Finding the Message Body
This content is no longer actively maintained. It is provided as is, for anyone who may still be using these technologies, with no warranties or claims of accuracy with regard to the most recent product version or service release.
Topic Last Modified: 2007-08-24
By Mark Taylor
Where is that darn message body anyway? I have seen this question (or variations on it) many times. Someone writes code to use the Exchange Web Services proxy objects to enumerate through all the items in a mailbox folder to get the message body content for each item. Even though the code they write retrieves the items, the message body content is nowhere to be found. The code required to get the message body content isn't as obvious as you might think. To learn the secret, read on!
Why doesn't FindItem return the message body?
The process for getting the message body is not intuitive because of how the Exchange Web Services proxy objects are created. The naming conventions don't help, either. Most developers use FindItem with an AllProperties BaseShape to return all the items in the folder, then enumerate through the items returned, expecting the message body to be one of the properties.
That process would work very well if FindItem with an AllProperties BaseShape actually returned the message body — but, to minimize the resource usage of FindItem, it doesn’t. AllProperties in a FindItem call does not return all the properties attached to an item. Large binary objects or text properties such as the Body, and calculated properties (those whose value depends on other properties), are not returned in a FindItem call.
Actually, the AllProperties BodyShape in a GetItem call doesn’t return all the properties set on an item, either. It returns all the properties that we have mapped in our schema. Believe me — we’re beginning to regret our choice of naming there!
But don’t worry, there is a way to retrieve the message body — it just involves a few extra steps. See the code example that follows for the inside scoop!
You can also retrieve the body summary in a GetItem call. An interesting post (Accessing Web service URL) on the Exchange Server Development TechNet Forum discussed this.
What properties are returned by GetItem versus FindItem?
The following table lists the properties that are returned by GetItem, but are not returned by FindItem.
Properties Returned Only by GetItem |
---|
Attachments |
Body |
Categories |
CcRecipients |
InternetMessageHeaders |
ReplyTo |
ResponseObjects |
ToRecipients |
BccRecipients |
The following table lists the properties that are returned by both GetItem and FindItem.
Properties Returned by Both FindItem and GetItem |
---|
ConversationIndex |
ConversationTopic |
Culture |
DateTimeCreated |
DateTimeReceived |
DateTimeSent |
DisplayCc |
DisplayTo |
From |
HasAttachments |
Importance |
InReplyTo |
InternetMessageId |
IsDeliveryReceiptRequested |
IsDraft |
IsFromMe |
IsRead |
IsReadReceiptRequested |
IsResend |
IsResponseRequested |
IsSubmitted |
IsUnmodified |
ItemClass |
ItemId |
ParentFolderId |
References |
ReminderDueBy |
ReminderIsSet |
ReminderMinutesBeforeStart |
Sender |
Sensitivity |
Size |
Subject |
Retrieving the message body and attachments
Many times you'll want to enumerate through mailbox items and retrieve the Body, and you'll also want the attachments. To do this, you call FindItem to get the list of items, and then call GetItem to retrieve the item and its properties, including the Body. To get the attachment content, you call GetAttachment and pass in the AttachmentId.
The following code shows you how to retrieve any attachments on the item, by using the following process:
- Calling FindItem on the mailbox folder to retrieve the list of ItemIds for the items.
- Calling GetItem on each mailbox item to retrieve the Body property and AttachmentIds for the item.
- If the mailbox item has any attachments, calling GetAttachment to retrieve each one.
// First, set up the binding to Exchange Web Services.
ExchangeServiceBinding binding = new ExchangeServiceBinding();
binding.Credentials = new NetworkCredential("fred", "Pa$$word", "contoso");
binding.Url = @"https://exchange.contoso.com/EWS/Exchange.asmx";
//
// Next, call FindItem for the Inbox folder.
// Form the FindItem request.
FindItemType findItemRequest = new FindItemType();
findItemRequest.Traversal = ItemQueryTraversalType.Shallow;
//
// Define which item properties are returned in the response.
// We only need the ItemIds.
ItemResponseShapeType itemProperties = new ItemResponseShapeType();
itemProperties.BaseShape = DefaultShapeNamesType.IdOnly;
//
// Add the properties shape to request.
findItemRequest.ItemShape = itemProperties;
//
// Identify which folders to search to find items.
DistinguishedFolderIdType[] folderIDArray = new DistinguishedFolderIdType[2];
folderIDArray[0] = new DistinguishedFolderIdType();
folderIDArray[0].Id = DistinguishedFolderIdNameType.inbox;
//
// Add folders to the request.
findItemRequest.ParentFolderIds = folderIDArray;
//
// Send the request and get the response.
FindItemResponseType findItemResponse = binding.FindItem(findItemRequest);
//
// Next, enumerate through the Items returned by FindItem.
foreach (FindItemResponseMessageType responseMessage in findItemResponse.ResponseMessages.Items)
{
if (responseMessage.ResponseClass == ResponseClassType.Success)
{
ArrayOfRealItemsType mailboxItems =
(ArrayOfRealItemsType)responseMessage.RootFolder.Item;
for (int itemCount = 0; itemCount <
mailboxItems.Items.Length; itemCount++)
{
ItemType inboxItem = mailboxItems.Items[itemCount];
// Call GetItem on each ItemId to retrieve the
// item's Body property and any AttachmentIds.
//
// Form the GetItem request.
GetItemType getItemRequest = new GetItemType();
getItemRequest.ItemShape =
new ItemResponseShapeType();
// AllProperties on a GetItem request WILL return
// the message body.
getItemRequest.ItemShape.BaseShape =
DefaultShapeNamesType.AllProperties;
getItemRequest.ItemIds = new ItemIdType[1];
getItemRequest.ItemIds[0] =
(BaseItemIdType)inboxItem.ItemId;
GetItemResponseType getItemResponse =
binding.GetItem(getItemRequest);
// We only passed in one ItemId to the GetItem
// request. Therefore, we can assume that
// we got at most one Item back.
ItemInfoResponseMessageType getItemResponseMessage =
getItemResponse.ResponseMessages.Items[0] as
ItemInfoResponseMessageType;
if (getItemResponseMessage != null)
{
if (getItemResponseMessage.ResponseClass ==
ResponseClassType.Success &&
getItemResponseMessage.Items.Items !=
null &&
getItemResponseMessage.Items.Items.Length
> 0)
{
inboxItem =
getItemResponseMessage.Items.Items[0];
}
else
{
return;
}
}
else
{
return;
}
// Now the message Body is there.
BodyType messageBody = inboxItem.Body;
//
// You now have the mailbox item's Body property
// and you can use it as needed.
//
// Check for attachments.
if (inboxItem.HasAttachments)
{
AttachmentType[] attachments =
inboxItem.Attachments;
//
// Enumerate through the attachments.
for (int attachmentCount = 0;
attachmentCount < attachments.Length;
attachmentCount++)
{
// Form the GetAttachment request.
GetAttachmentType getAttachmentRequest =
new GetAttachmentType();
//
// Add the attachment to retrieve.
RequestAttachmentIdType[]
attachmentIDArray =
new RequestAttachmentIdType[1];
attachmentIDArray[0] =
new RequestAttachmentIdType();
attachmentIDArray[0].Id =
attachments[attachmentCount].AttachmentId.Id;
getAttachmentRequest.AttachmentIds =
attachmentIDArray;
//
// Make the GetAttachment request.
GetAttachmentResponseType
getAttachmentResponse =
binding.GetAttachment(getAttachmentRequest);
//
// We then parse through the
// GetAttachment response to get the
//attachment object itself
//
// We only passed in one AttachmentId.
// Therefore, we can assume that we
// got at most one attachment back.
AttachmentInfoResponseMessageType
attachmentResponseMessage =
getAttachmentResponse.ResponseMessages.Items[0]
as AttachmentInfoResponseMessageType;
if (attachmentResponseMessage != null)
{
if
(attachmentResponseMessage.ResponseClass
== ResponseClassType.Success &&
attachmentResponseMessage.Attachments !=
null &&
attachmentResponseMessage.Attachments.Length
> 0)
{
AttachmentType attachment =
attachmentResponseMessage.Attachments[0];
}
else
{
return;
}
}
else
{
return;
}
}
}
}
}
}
Now you have the message body and the attachments and you can do whatever you want to with them!
And that is that! Maybe not as easy as you may have hoped, but not too bad, either!