Fetching all mails in Inbox from Exchange Web Services Managed API and storing them as a .eml files

Mahesha999 picture Mahesha999 · Dec 18, 2013 · Viewed 26.5k times · Source

I want to fetch all mails in the Inbox folder using EWS Managed API and store them as .eml. The problem is in fetching (1) all mails with (2) all headers (like from, to, subject) (I am keeping information of those values of from, to and other properties somewhere else, so I need them too) and (3)byte[] EmailMessage.MimeContent.Content. Actually I am lacking understanding of

  • Microsoft.Exchange.WebServices.Data.ItemView,
  • Microsoft.Exchange.WebServices.Data.BasePropertySet and
  • Microsoft.Exchange.WebServices.Data.ItemSchema

thats why I am finding it difficult.

My primary code is:

When I create PropertySet as follows:

PropertySet properties = new PropertySet(BasePropertySet.FirstClassProperties, ItemSchema.MimeContent);

I get following exception:

The property MimeContent can't be used in FindItem requests.

I dont understand

(1) What these ItemSchema and BasePropertySet are

(2) And how we are supposed to use them

So I removed ItemSchema.MimeContent:

PropertySet properties = new PropertySet(BasePropertySet.FirstClassProperties);

I wrote simple following code to get all mails in inbox:

ItemView view = new ItemView(50);
view.PropertySet = properties;
FindItemsResults<Item> findResults; 
List<EmailMessage> emails = new List<EmailMessage>();

do
{    
    findResults = service.FindItems(WellKnownFolderName.Inbox, view);
    foreach (var item in findResults.Items)
    {
        emails.Add((EmailMessage)item);
    }
    Console.WriteLine("Loop");
    view.Offset = 50;
}
while (findResults.MoreAvailable);

Above I kept page size of ItemView to 50, to retrieve no more than 50 mails at a time, and then offsetting it by 50 to get next 50 mails if there are any. However it goes in infinite loop and continuously prints Loop on console. So I must be understanding pagesize and offset wrong. I want to understand

(3) what pagesize, offset and offsetbasepoint in ItemView constructor means

(4) how they behave and

(5) how to use them to retrieve all mails in the inbox

I didnt found any article online nicely explaining these but just giving code samples. Will appreciate question-wise explanation despite it may turn long.

Answer

user1017413 picture user1017413 · Dec 19, 2013

EWS is a bit inconsistent with the properties returned from various operations. An Item.Bind will not return the exact same properties as a FindItem. You're using PropertySets properly as far as defining what you want from the server, but you have to use them in the right place. What you need to do is find the items, then load the properties into them. It's not ideal, but that's the way EWS works. With your loop, you're constantly assigning 50 to your offset when you need to increment it by 50. Off the top of my head, something like this would do:

int offset = 0;
int pageSize = 50;
bool more = true;
ItemView view = new ItemView(pageSize, offset, OffsetBasePoint.Beginning);

view.PropertySet = PropertySet.IdOnly;
FindItemsResults<Item> findResults;
List<EmailMessage> emails = new List<EmailMessage>();

while(more){
    findResults = service.FindItems(WellKnownFolderName.Inbox, view);
    foreach (var item in findResults.Items){
        emails.Add((EmailMessage)item);
    }
    more = findResults.MoreAvailable;
    if (more){
        view.Offset += pageSize;
    }
}
PropertySet properties = (BasePropertySet.FirstClassProperties); //A PropertySet with the explicit properties you want goes here
service.LoadPropertiesForItems(emails, properties);

Now you have all of the items with all of the properties that you requested. FindItems often doesn't return all of the properties you want even if you ask for them, so loading only the Id initially and then loading up the properties you want is generally the way to go. You may also want to batch the loading of properties in some way depending on how many emails you're retrieving, perhaps in the loop prior to adding them to the List of EmailMessages. You could also consider other methods of getting items, such as a service.SyncFolder action.