InfiniTec - Henning Krauses Blog

Don't adjust your mind - it's reality that is malfunctioning

Getting the body of an Email with a FindItems request

The FindItem operation (or the corresponding ExchangeService.FindItems method) does not return the body of an email by default. And when trying to explicitly request them via a custom propertyset, the call fails. Consider this method, which uses the EWS Managed API to execute a FindItems method to get every message from the inbox folder of a mailbox, fetching only the item id and the body:

   1: private static void GetAllItems(ExchangeService exchangeService)
   2: {
   3:     var offset = 0;
   4:     const int pageSize = 100;
   5:  
   6:     FindItemsResults<Item> result;
   7:     do
   8:     {
   9:         var view = new ItemView(pageSize, offset)
  10:                        {
  11:                            PropertySet = new PropertySet(BasePropertySet.IdOnly)
  12:                                              {
  13:                                                  ItemSchema.Body
  14:                                              }
  15:                        };
  16:  
  17:         result = exchangeService.FindItems(WellKnownFolderName.Inbox, view);
  18:  
  19:         foreach (var item in result)
  20:         {
  21:             ProcessItem(item);
  22:         }
  23:         offset += pageSize;
  24:     } while (result.MoreAvailable);
  25: }

When executed, the ExchangeService instance throws a ServiceValidationException stating “The property Body cannot be used in FindItem requests”. The official workaround proposed by Microsoft is to use a FindItem request to get the item ids of the items in a folder and afterward issue a GetItem request containing all the item ids and request the body property. However, there is another solution: The body properties can be fetched by requesting the MAPI properties containing the body:

   1: private static ExtendedPropertyDefinition TextBodyProperty = new ExtendedPropertyDefinition(0x1000, MapiPropertyType.String);
   2: private static ExtendedPropertyDefinition HtmlBodyProperty = new ExtendedPropertyDefinition(0x1013, MapiPropertyType.Binary);

The first property definition can be used to fetch the text body of a mail. The second one fetches the Html body. The new GetAllItemsMethod now looks like this:

   1: private static void GetAllItems(ExchangeService exchangeService)
   2: {
   3:     var offset = 0;
   4:     const int pageSize = 100;
   5:  
   6:     FindItemsResults<Item> result;
   7:     do
   8:     {
   9:         var view = new ItemView(pageSize, offset)
  10:                        {
  11:                            PropertySet = new PropertySet(BasePropertySet.IdOnly)
  12:                                              {
  13:                                                  HtmlBodyProperty
  14:                                              }
  15:                        };
  16:  
  17:         result = exchangeService.FindItems(WellKnownFolderName.Inbox, view);
  18:  
  19:         foreach (var item in result)
  20:         {
  21:             object body;
  22:             if (item.ExtendedProperties.TryGetValue(HtmlBodyProperty, out body))
  23:             {
  24:                 Console.Out.WriteLine("item.Body = {0}", Encoding.UTF8.GetString(Convert.FromBase64String((string)body)));
  25:             }
  26:         }
  27:         offset += pageSize;
  28:     } while (result.MoreAvailable);
  29: }

The HtmlBody is requested with the addtion of the HtmlBodyProperty to the ItemView in line 13. Since the Html body is stored in binary form and returned in Base64 encoded format, it needs to be decoded before it can be displayed. This is done in line 24. If the plaintext body is requested, the value of the body property in line 24 can simply be converted to a string.


Posted by Henning Krause on Tuesday, June 9, 2009 9:00 PM, last modified on Wednesday, April 20, 2011 6:19 PM
Permalink | Post RSSRSS comment feed

Comments (10) -

On 7/31/2009 4:17:39 PM Lee Feagin United States wrote:

Lee Feagin

Just wanted to say that I appreciate this post so much.  It really saved me a lot of googling in getting a quick tasked coded and done.  Thanks again!

On 4/20/2011 6:19:45 PM LW United States wrote:

LW

Thanks for the post.  I tried this but it returned only the first 255 characters of the body.  Is there a way to get the rest of the email body using extended properties?

On 8/2/2009 9:30:52 PM jdmd United States wrote:

jdmd

Hello Henning - Is there a simple EWS soap request I can POST to see of an Exchange Server has EWS enabled?  For example, should this work from a web browser:


&amp;amp;amp;amp;amp;amp;amp;amp;amp;lt;html&amp;amp;amp;amp;amp;amp;amp;amp;amp;gt;
&amp;amp;amp;amp;amp;amp;amp;amp;amp;lt;body&amp;amp;amp;amp;amp;amp;amp;amp;amp;gt;
&amp;amp;amp;amp;amp;amp;amp;amp;amp;lt;form method=&amp;amp;amp;amp;amp;amp;amp;amp;amp;quot;post&amp;amp;amp;amp;amp;amp;amp;amp;amp;quot; action=&amp;amp;amp;amp;amp;amp;amp;amp;amp;quot;myexchangeserver.mycompany.com/.../Exchange.asmx&amp;amp;amp;amp;amp;amp;amp;amp;amp;quot;&amp;amp;amp;amp;amp;amp;amp;amp;amp;gt;
&amp;amp;amp;amp;amp;amp;amp;amp;amp;lt;input type=&amp;amp;amp;amp;amp;amp;amp;amp;amp;quot;submit&amp;amp;amp;amp;amp;amp;amp;amp;amp;quot; value=&amp;amp;amp;amp;amp;amp;amp;amp;amp;quot;submit&amp;amp;amp;amp;amp;amp;amp;amp;amp;quot;/&amp;amp;amp;amp;amp;amp;amp;amp;amp;gt;
&amp;amp;amp;amp;amp;amp;amp;amp;amp;lt;br/&amp;amp;amp;amp;amp;amp;amp;amp;amp;gt;
&amp;amp;amp;amp;amp;amp;amp;amp;amp;lt;textarea name=&amp;amp;amp;amp;amp;amp;amp;amp;amp;quot;data&amp;amp;amp;amp;amp;amp;amp;amp;amp;quot; rows=&amp;amp;amp;amp;amp;amp;amp;amp;amp;quot;30&amp;amp;amp;amp;amp;amp;amp;amp;amp;quot; cols=&amp;amp;amp;amp;amp;amp;amp;amp;amp;quot;120&amp;amp;amp;amp;amp;amp;amp;amp;amp;quot;&amp;amp;amp;amp;amp;amp;amp;amp;amp;gt;
&amp;amp;amp;amp;amp;amp;amp;amp;amp;lt;?xml version=&amp;amp;amp;amp;amp;amp;amp;amp;amp;quot;1.0&amp;amp;amp;amp;amp;amp;amp;amp;amp;quot; encoding=&amp;amp;amp;amp;amp;amp;amp;amp;amp;quot;utf-8&amp;amp;amp;amp;amp;amp;amp;amp;amp;quot;?&amp;amp;amp;amp;amp;amp;amp;amp;amp;gt;
&amp;amp;amp;amp;amp;amp;amp;amp;amp;lt;soap:Envelope xmlns:xsi=&amp;amp;amp;amp;amp;amp;amp;amp;amp;quot;www.w3.org/.../XMLSchema-instance&amp;amp;amp;amp;amp;amp;amp;amp;amp;quot;
               xmlns:xsd=&amp;amp;amp;amp;amp;amp;amp;amp;amp;quot;www.w3.org/.../XMLSchema&amp;amp;amp;amp;amp;amp;amp;amp;amp;quot;
               xmlns:soap=&amp;amp;amp;amp;amp;amp;amp;amp;amp;quot;schemas.xmlsoap.org/.../&amp;amp;amp;amp;amp;amp;amp;amp;amp;quot;
         xmlns:t=&amp;amp;amp;amp;amp;amp;amp;amp;amp;quot;schemas.microsoft.com/.../types&amp;amp;amp;amp;amp;amp;amp;amp;amp;quot;&amp;amp;amp;amp;amp;amp;amp;amp;amp;gt;
  &amp;amp;amp;amp;amp;amp;amp;amp;amp;lt;soap:Body&amp;amp;amp;amp;amp;amp;amp;amp;amp;gt;
    &amp;amp;amp;amp;amp;amp;amp;amp;amp;lt;ResolveNames xmlns=&amp;amp;amp;amp;amp;amp;amp;amp;amp;quot;schemas.microsoft.com/.../messages&amp;amp;amp;amp;amp;amp;amp;amp;amp;quot;
                  xmlns:t=&amp;amp;amp;amp;amp;amp;amp;amp;amp;quot;schemas.microsoft.com/.../types&amp;amp;amp;amp;amp;amp;amp;amp;amp;quot;
                  ReturnFullContactData=&amp;amp;amp;amp;amp;amp;amp;amp;amp;quot;true&amp;amp;amp;amp;amp;amp;amp;amp;amp;quot;&amp;amp;amp;amp;amp;amp;amp;amp;amp;gt;
      &amp;amp;amp;amp;amp;amp;amp;amp;amp;lt;UnresolvedEntry&amp;amp;amp;amp;amp;amp;amp;amp;amp;gt;John&amp;amp;amp;amp;amp;amp;amp;amp;amp;lt;/UnresolvedEntry&amp;amp;amp;amp;amp;amp;amp;amp;amp;gt;
    &amp;amp;amp;amp;amp;amp;amp;amp;amp;lt;/ResolveNames&amp;amp;amp;amp;amp;amp;amp;amp;amp;gt;
  &amp;amp;amp;amp;amp;amp;amp;amp;amp;lt;/soap:Body&amp;amp;amp;amp;amp;amp;amp;amp;amp;gt;
&amp;amp;amp;amp;amp;amp;amp;amp;amp;lt;/soap:Envelope&amp;amp;amp;amp;amp;amp;amp;amp;amp;gt;&amp;amp;amp;amp;amp;amp;amp;amp;amp;lt;/textarea&amp;amp;amp;amp;amp;amp;amp;amp;amp;gt;
&amp;amp;amp;amp;amp;amp;amp;amp;amp;lt;/form&amp;amp;amp;amp;amp;amp;amp;amp;amp;gt;
&amp;amp;amp;amp;amp;amp;amp;amp;amp;lt;/body&amp;amp;amp;amp;amp;amp;amp;amp;amp;gt;
&amp;amp;amp;amp;amp;amp;amp;amp;amp;lt;/html&amp;amp;amp;amp;amp;amp;amp;amp;amp;gt;

On 5/11/2011 1:48:26 PM PW United Kingdom wrote:

PW

Just wanted to say a huge thank-you for this post it been key to helping us speed up the request we were running from 2 minutes to under 10 seconds.

On 8/22/2011 5:53:14 PM PaulE wrote:

PaulE

In lines 22-25 of GetAllItems, you could also simply put:

item.Load();
Console.Out.WriteLine(&amp;amp;amp;amp;amp;amp;amp;amp;amp;quot;item.Body = {0}&amp;amp;amp;amp;amp;amp;amp;amp;amp;quot;, item.Body.Text);

This may take a little longer than desired since Load() loads the first-class properties, but there is an overload for Load which takes a PropertySet parameter.

   ---PaulE---

On 9/1/2011 5:31:19 PM hkrause wrote:

hkrause

Of course you could do that. But that would require several requests to the server instead of one.

On 9/13/2011 1:22:34 PM Luke wrote:

Luke

Thank you for this this has saved me heaps of time!  Do you have any idea how you can search All Mail Items and not just the Inbox folder.  I would like to retrieve all emails that are from a certain user even if they are within sub-folders.  I can&amp;amp;amp;amp;amp;amp;amp;#39;t seem to find a solution anywhere.

On 12/13/2011 9:01:55 PM vp wrote:

vp

Hi Henning, I have uncovered a bug with this code when used for instances of recurring appointments. It affects both EWS on Exchange 2007 and 2010.
1. Create a recurring appointment using EWS (Managed API). Set the body text to &amp;amp;amp;amp;amp;amp;quot;X&amp;amp;amp;amp;amp;amp;quot;.
2. Change one of the occurrences *** Using Outlook *** - Set the body text to &amp;amp;amp;amp;amp;amp;quot;Y&amp;amp;amp;amp;amp;amp;quot;.
3. Get the occurrence using EWS - if you use the 0x1000 property, you will get the body of the recurring master and not the exception.

On 3/20/2012 4:52:33 PM Petr Snobelt wrote:

Petr Snobelt

Sample code returns only first 255 characters. After some googling I find article which show how to retrive whole body as text
blogs.dotnetkicks.com/.../

On 3/15/2013 7:36:55 PM George wrote:

George

This code still throws an error when the email message body is null. I&amp;amp;amp;amp;#39;ve discovered a few emails like this coming from gmail. Any suggestions on how to check for a null message body?