EWS Displays Emails very slow - c#

I am using Exchange Services in my Application Code to display list of emails on application UI. However, it is able to retrieve emails list. But it takes very very long to display all set. If I decrease number of emails to display it takes less time to display.
public static List<EmailMsg> GetEmailListInFolder(string folderName)
{
var folderId = GetFolderId(folderName);
var service = GetExchangeService();
if (folderId != null)
{
var emails = new List<EmailMsg>();
var count = 0;
var findResults = service.FindItems(folderId, new ItemView(100));
foreach (var item in findResults.Items)
{
var emailPropertySet = new PropertySet(
BasePropertySet.FirstClassProperties,
new PropertyDefinitionBase[]{
new ExtendedPropertyDefinition(4115, MapiPropertyType.Binary)
});
var message = EmailMessage.Bind(service, item.Id, emailPropertySet);
emails.Add(new EmailMsg(folderName, count++, item.Id.UniqueId, message.Subject, message.DateTimeReceived.ToString("yyyy-MMM-dd HH:mm:ss"), ""));
}
return emails;
}
return null;
}
When I debug code and found out that it takes few seconds on this line to before proceeding to next line.
var message = EmailMessage.Bind(service, item.Id, emailPropertySet);
Kindly, suggest me a way to decrease the loading time of my email items. Thanks

You are returning all the BasePropertySet.FirstClassProperties!
You might want to consider changing this to just return the properties you need.
List of FirstClassProperties from msdn:
Id
ParentFolderId
ItemClass
Subject
Sensitivity
Body
Attachments
DateTimeReceived
Size
Categories
Importance
InReplyTo
IsSubmitted
IsDraft
IsFromMe
IsResend
IsUnmodified
InternetMessageHeaders
DateTimeSent
DateTimeCreated
AllowedResponseActions
ReminderDueBy
IsReminderSet
ReminderMinutesBeforeStart
DisplayCc
DisplayTo
HasAttachments
Culture
EffectiveRights
LastModifiedName
LastModifiedTime
IsAssociated
WebClientReadFormQueryString
WebClientEditFormQueryString
ConversationId
Flag
InstanceKey
EntityExtractionResult
Sender
ToRecipients
CcRecipients
BccRecipients
IsReadReceiptRequested
IsDeliveryReceiptRequested
ConversationIndex
ConversationTopic
From
InternetMessageId
IsRead
IsResponseRequested
ReplyTo
References
ReceivedBy
ReceivedRepresenting
You are loading the Attachments. To avoid this big load you can either:
Load the attachement only when you are on a specific mail.
Load only the properties
with LoadPropertiesForItems
and getting the attachments name, extention, etc without getting the real attachement.
Then getting the real attachment can be done using ExchangeService.GetAttachments

Related

Trouble reading contact.addresses in EWS. All contacts read display "The given key was not present in the dictionary."

Can't get the first email address to display. All records display like this:
"The given key was not present in the dictionary". There are definately email addresses associated with the contacts. Here is the code
....
static void Reademail()
{
ExchangeService service = new ExchangeService(ExchangeVersion.Exchange2013);
service.UseDefaultCredentials = true;
service.AutodiscoverUrl("validaddress#ddd.com");
// Get the number of items in the contacts folder. To limit the size of the response, request only the TotalCount property.
ContactsFolder contactsfolder = ContactsFolder.Bind(service,WellKnownFolderName.Contacts,new PropertySet(BasePropertySet.IdOnly, FolderSchema.TotalCount));
// Set the number of items to the number of items in the Contacts folder or 50, whichever is smaller.
int numItems = contactsfolder.TotalCount < 50 ? contactsfolder.TotalCount : 50;
// Instantiate the item view with the number of items to retrieve from the Contacts folder.
ItemView view = new ItemView(numItems);
// To keep the request smaller, request only the display name property.
view.PropertySet = new PropertySet(BasePropertySet.IdOnly, ContactSchema.DisplayName);
// Retrieve the items in the Contacts folder that have the properties that you selected.
FindItemsResults<Item> contactItems = service.FindItems(WellKnownFolderName.Contacts, view);
// Display the list of contacts.
foreach (Item item in contactItems)
{
if (item is Contact)
{
Contact contact = item as Contact;
Console.Write(contact.DisplayName + " ");
try
{
Console.WriteLine(contact.EmailAddresses[EmailAddressKey.EmailAddress1].Name);
}
catch (Exception e)
{
Console.WriteLine(e.Message);
}
}
}
Console.ReadKey();
}
.....
the fix I found was to use the contact.Load statement. Although maybe not the most efficient as it mask a call back to EWS. Apparently this loads the primary class and the email addresses are then visible.

EWS Extended Properties between accounts

we have encountered a problem with recognizing and setting ExtendedProperties by EWS. Right now, we have the functionality to import emails, which can be done either manually by user or a separate service. There seems to be inconsistency with how Exchange searches through ExtendedProperties and how they are set.
To clarify, I have three mailboxes attached to Outlook application. One is mine and two are the test accounts, which are linked to my AD account. The test accounts contain emails which are imported by the automatic service(when a mail is sent to one of them, it is imported to our application and there is set and ExtendedProperty on the email, providing the information that the email was imported).
What is strange, on my side, in Outlook Add-in, on one account the emails are properly marked and on the other it is not happening as it should, despite that the mechanism is the same.
These are the codes of our add-in.
This is the code of retrieving emails:
private static IEnumerable<EmailMessage> GetEmails(Microsoft.Exchange.WebServices.Data.Folder folder, int pageSize, DateTime lastImport)
{
SearchFilter filter = PrepareFilter(lastImport);
List<Item> foundItems = new List<Item>();
Guid propertySetId = new Guid("F723C954-3F83-46AA-A783-FDEAC90AE512");
ExtendedPropertyDefinition registered = new ExtendedPropertyDefinition(propertySetId, "Registered", MapiPropertyType.Boolean);
ItemView view = new ItemView(pageSize);
view.PropertySet = new PropertySet(BasePropertySet.FirstClassProperties, registered);
foundItems = service.FindItems(folder.Id, filter, view).Items.ToList();
List<EmailMessage> results = new List<EmailMessage>();
foreach (EmailMessage message in foundItems)
{
results.Add(message);
}
return results;
}
private static SearchFilter PrepareFilter(DateTime lastImport)
{
Guid propertySetId = new Guid("F723C954-3F83-46AA-A783-FDEAC90AE512");
ExtendedPropertyDefinition Registered= new ExtendedPropertyDefinition(propertySetId, "Registered", MapiPropertyType.Boolean);
SearchFilter isRegistered = new SearchFilter.IsEqualTo(registered, true);
return isRegistered;
}
And this is the flag setting method written by my colleague:
public static bool SetExchangeRegistered(List<MailItem> mailsToRegister)
{
try
{
var service = new Exchange.ExchangeService(Exchange.ExchangeVersion.Exchange2010)
{
UseDefaultCredentials = true
};
var emailAddress = new Application().ActiveExplorer().Session.CurrentUser.AddressEntry.GetExchangeUser().PrimarySmtpAddress;
service.AutodiscoverUrl(emailAddress);
foreach (var mail in mailsToRegister)
{
string itemId = ConvertHexEntryIdToEwsId(service, mail.EntryID, emailAddress);
Exchange.EmailMessage message = Exchange.EmailMessage.Bind(service, new Exchange.ItemId(itemId));
bool propertyRegisteredExists =
message.ExtendedProperties.FirstOrDefault(x => x.PropertyDefinition.Name == "Registered") != null;
if (!propertyRegisteredExists)
{
Guid propertySetId = new Guid("F723C954-3F83-46AA-A783-FDEAC90AE512");
Exchange.ExtendedPropertyDefinition registered =
new Exchange.ExtendedPropertyDefinition(propertySetId, "Re", Exchange.MapiPropertyType.Boolean);
message.SetExtendedProperty(registered, true);
}
else
{
message.ExtendedProperties.First(x => x.PropertyDefinition.Name == "Registered").Value = true;
}
message.Update(Exchange.ConflictResolutionMode.AlwaysOverwrite);
}
}
catch (Exception ex)
{
grmtAddInBase.Logger.Trace(string.Format("Registered update failed: {0}", ex.Message));
return false;
}
grmtAddInBase.Logger.Trace("Email property 'Registered' updated successfully");
return true;
}
Generally, the method above seems to be identical in control flow to the method which is implemented in the separate service, and it seems that it actually does set the ExtendedProperty of the email correctly.
Another clue, which, to be honest, leaves me clueless, is that even when I tried to get all the emails greedily, load it and then separate the correct ones by their ExtendedProperty which we set... The problem then is that for some emails(i.e. inside one of the mailboxes which are treated by the autoimport service) it sees the Properties correctly and for the rest(i.e. my own mailbox) it doesn't even load and ExtProps, which means that it probably does not see them at all.
I have also tried to use DefaultExtendedPropertySet.PublicStrings, but then it didn't work at all.
I am a little bit puzzled and nobody in close proximity or EWS docs/MS Forums could provide the answer. I am aware that there may be no help, I am aware of the possibility that we are just hopelessly stupid and made some mistake which we cannot find.
After a while, the emails on Exchange mailboxes are just copies - that would be reasonable reason why we cannot access the ExtendedProperties of the email that we received, when it's "flag" was set by another user. But, maybe there is a way to synchronize those properties between those mailboxes? Because there are some alternatives already that we will discuss, but it would be nice if at least part of the current solution could be reused.

Exchange 2013 API - Get Room Properties

I am trying to get the room details from Exchange using EWS API.
Here is the example given for getting room list.
So as per the code I am trying to get the room details like location, city, state etc., but with code example's code block, I am only getting Id, MailboxType, Name & RoutingType.
Code snippet I have tried:
// Initialize service object here
EmailAddressCollection myRoomLists = service.GetRoomLists();
foreach (EmailAddress address in myRoomLists)
{
EmailAddress myRoomList = address.Address;
Console.WriteLine("Email Address: {0}", address.Address);
}
Really appreciate if some can help me in getting the room property (Location, City, State etc.) with Exchange API in C#?
The RoomList operation will only return the EmailAddresses of the Room Mailboxes in the list. To get further information on these you will need to use an operation like ResolveName and return the ContactInformation eg
EmailAddressCollection myRoomLists = service.GetRoomLists();
foreach (EmailAddress address in myRoomLists)
{
EmailAddress myRoomList = address.Address;
PropertySet AllProps = new PropertySet(BasePropertySet.FirstClassProperties);
NameResolutionCollection ncCol = service.ResolveName(address.Address, ResolveNameSearchLocation.DirectoryOnly, true, AllProps);
foreach (NameResolution nr in ncCol)
{
Console.WriteLine(nr.Contact.DisplayName);
Console.WriteLine(nr.Contact.Notes);
}
}
Room Capacity is not a property that is exposed by EWS so you need to use a workaround to get it https://social.technet.microsoft.com/Forums/office/en-US/9eef45a5-dd1d-4912-9beb-bded7b40cb9e/ews-managed-api-using-c?forum=exchangesvrdevelopment
Cheers
Glen

casting objects in c# (Exchange Web Services Item to Email)

I cannot work out how I can do what I need to do.
I have a method called 'MarkAsRead' that takes an ItemID and should mark the mail item as read.
But it seems that the Item doesn't have an 'IsRead' proeprty, only an email does, so I need to cast my Exchange WebServices mail item to an email message.
here is the code:
try
{
System.Diagnostics.Debugger.Break();
//creates an object that will represent the desired mailbox
Mailbox mb = new Mailbox(common.strInboxURL);
//creates a folder object that will point to inbox fold
FolderId fid = new FolderId(WellKnownFolderName.Inbox, mb);
//this will bind the mailbox you're looking for using your service instance
Microsoft.Exchange.WebServices.Data.Folder inbox = Microsoft.Exchange.WebServices.Data.Folder.Bind(service, fid);
//// if the property is not loaded yet, first load it
//mail.Load(PropertySet(BasePropertySet.IdOnly, EmailMessageSchema.IsRead));
//if (!mail.IsRead) // check that you don't update and create unneeded traffic
//{
// mail.IsRead = true; // mark as read
// mail.Update(ConflictResolutionMode.AutoResolve); // persist changes
//}
// As a best practice, limit the properties returned to only those that are required.
PropertySet propSet = new PropertySet(BasePropertySet.IdOnly, ItemSchema.Subject);
// Bind to the existing item by using the ItemId.
// This method call results in a GetItem call to EWS.
Item item = Item.Bind(service, itemId, propSet);
EmailMessage mail = Item.Bind(service, itemId, propSet);
item.Load(new PropertySet(BasePropertySet.IdOnly,EmailMessageSchema.IsRead));
item.IsRead = true;
item.Update(ConflictResolutionMode.AlwaysOverwrite);
return true;
}
I am trying to do something like this:
// if the property is not loaded yet, first load it
mail.Load(PropertySet(BasePropertySet.IdOnly, EmailMessageSchema.IsRead));
if (!mail.IsRead) // check that you don't update and create unneeded traffic
{
mail.IsRead = true; // mark as read
mail.Update(ConflictResolutionMode.AutoResolve); // persist changes
}
unfortunately I need to be able to get a unique email message from the item.
how can I do that please?
Philip-
You can add EmailMessageSchema.IsRead to your property set, so that you can get it in your Bind call, and then you don't have to call Load at all.
PropertySet propSet = new PropertySet(BasePropertySet.IdOnly,
ItemSchema.Subject, EmailMessageSchema.IsRead);
The EmailClass derives from the Item class, so Bind works on both. So you can do the following:
EmailMessage mail = EmailMessage.Bind(service, itemId, propSet);
Put that together and you've got this:
PropertySet propSet = new PropertySet(BasePropertySet.IdOnly, ItemSchema.Subject, EmailMessageSchema.IsRead);
EmailMessage mail = EmailMessage.Bind(service, itemId, propSet);
if (!mail.IsRead) // check that you don't update and create unneeded traffic
{
mail.IsRead = true; // mark as read
mail.Update(ConflictResolutionMode.AutoResolve); // persist changes
}
Philip,
When testing my code I added just a little bit to the Item.Bind() from your code to make this work:
EmailMessage mail = Item.Bind(service, itemId, propSet) as EmailMessage;
The as EmailMessage will cast it to the appropriate type for you. After that I was able to see the isRead property.
I hope this helps. If this does resolve your problem, please mark the post as answered.
Thanks,
--- Bob ---

EWS managed API. IsNew Always return false and can't use TextBody

I am a newbie developer and I have been stuck with EWS for hours now. I need to read through the most recent emails, get all the unread emails and use the data from them to do some stuff.
At this moment My code looks like this.
static void Main(string[] args)
{
ServicePointManager.ServerCertificateValidationCallback = CertificateValidationCallBack;
ExchangeService service = new ExchangeService(ExchangeVersion.Exchange2013);
service.Credentials = new WebCredentials("support#mycompany.com", "mysupersuperdupersecretpassword");
service.AutodiscoverUrl("support#mycompany.com", RedirectionUrlValidationCallback);
FindItemsResults<Item> findResults = service.FindItems(WellKnownFolderName.Inbox,new ItemView(2));
foreach (Item item in findResults.Items)
{
// works perfectly until here
Console.WriteLine(item.Subject);
Console.WriteLine('\n');
item.Load();
string temp = item.Body.Text;
// I can't seem to get TextBody to work. so I used a RegEx Match match = Regex.Match(temp, "<body>.*?</body>", RegexOptions.Singleline);
string result = match.Value;
result = result.Replace("<body>", "");
result = result.Replace("</body>", "");
Console.Write(result);
Console.WriteLine('\n');
//Now the email boddy is fine but IsNew always returns false.
if (item.IsNew)
{
Console.WriteLine("This message is unread!");
}
else
{
Console.WriteLine("This message is read!");
}
}
}
I have googled and tried and googled some more and I am stuck. How do I now which emails are read, is there a way to get the email body text that's more effective than what I have done ? Any help would be super appreciated.
The MSDN article for usage is pretty good if you haven't already read it.
For your issue, cast your item to an EmailMessage
foreach (Item item in findResults.Items)
{
var mailItem = (EmailMessage)item;
// works perfectly until here
Console.WriteLine(mailItem.Subject);
}
I did notice you are not using Property Sets, but having only used EWS for event notifications and not going through existing mails, it may be different.
UPDATE Additions in light of your changes
use this for your Property Set
new PropertySet(BasePropertySet.FirstClassProperties) {
RequestedBodyType = BodyType.Text
};
Also this reads a little nicer and uses the Body.Text property
foreach (Item myItem in findResults.Items.Where(i=>i is EmailMessage))
{
var mailItem = myItem as EmailMessage;
Console.WriteLine(mailItem.Subject);
mailItem.Load(new PropertySet(BasePropertySet.FirstClassProperties) {
RequestedBodyType = BodyType.Text
}); // Adding this parameter does the trick :)
Console.WriteLine(mailItem.Body.Text);
if(! mailItem.IsRead)
Console.WriteLine("Who is Your Daddy!!!!");
}

Categories

Resources