Hobby Chef
FindItem is one of the very useful & powerful functions available in EWS. You can use it on any folder to find any type of item with as complex restrictions as you can think of.
But wait… before you assume you can get everything that you would get from GetItem, It is not truth!
FindItem only returns summary information & following fields are returned ONLY by GetItem and never by FindItem.
Attachments, Body, Categories, CcRecipients, InternetMessageHeaders, ReplyTo, ResponseObjects, ToRecipients, BccRecipients
I have also discovered that although Sender is returned by FindItem, but you only get display name for sender and EmailAddressType & RoutingType are set to null. I asked myself why not… and following is the response I got from people who decided to design it that way.
"Returning the e-mail address to clients would not add much network traffic from the client to the CAS server, it would be a tremendous performance problem for the server itself. FindItem's whole point is to be an extremely efficient operation for the server – because it's potentially returning very large tables of data. The data returned by a FindItem call is often used to display a view (such as a list of items, like in Outlook). Returning the e-mail address as part of FindItem would require one Active Directory (AD) lookup per recipient, which would result in insufficient performance for FindItem. Beyond that, applications that display a table of information would typically only show the display name of a recipient (as Outlook does in the item listing). So, all that put together is why we require clients to call GetItem to find full recipient information."
References:
http://msdn2.microsoft.com/en-us/library/bb508824.aspx
This is an attempt to extend my previous code sample Getting into a folder by path using EWS
With this code sample I have demonstrated HOWTO find items under a folder.
I have used Restriction to list down all the "IPM.Note" items falling under a specified date/time span.
class EWS_SAMPLE { static void Main(string[] args) { ExchangeServiceBinding esb = new ExchangeServiceBinding(); esb.Credentials = new System.Net.NetworkCredential("Username", "Password"); esb.Url = "https://server-name-here/EWS/Exchange.asmx"; BaseFolderType bft = GetFolderByPath(esb, "/Inbox/myFolder"); if (null == bft) Console.WriteLine("Folder not found."); else { Console.WriteLine("Folder Found: " + bft.DisplayName); ItemType[] its = FindAllItems(esb, bft.FolderId.Id, DateTime.Parse("07/25/2007 00:00"), DateTime.Parse("07/30/2007 00:00")); if (null == its) return; foreach (ItemType it in its) { MessageType mt; mt = GetItem(esb, it.ItemId.Id) as MessageType; if (null == mt) Console.WriteLine("Item not found"); else Console.WriteLine(mt.DateTimeSent + " >> " + mt.Subject + " >> " + mt.Sender.Item.EmailAddress); } } return; } static public BaseFolderType GetFolderByPath(ExchangeServiceBinding esb, string szFolderPath) { if (null == szFolderPath) return null; if (szFolderPath.IndexOf("/") == -1) return null; if (szFolderPath.Substring(0, 1).CompareTo("/") == 0) szFolderPath = szFolderPath.Substring(1); string[] Path = szFolderPath.Split('/'); string szParentFolderId = null; BaseFolderType bft = null; for (int i = 0; i < Path.GetLength(0); i++) { if (null == szParentFolderId) szParentFolderId = GetRootFolderId(esb); bft = GetFolder(esb, szParentFolderId, Path[i]); if (null == bft) return null; else szParentFolderId = bft.FolderId.Id; } return bft; } static public BaseFolderType GetFolder(ExchangeServiceBinding esb, string szParentFolderId, string szFolderName) { if (null == esb || null == szFolderName) return null; //get the root folder ID FolderIdType[] fit = new FolderIdType[1]; fit[0] = new FolderIdType(); fit[0].Id = szParentFolderId; //set the props that we want to retrieve FolderResponseShapeType frst = new FolderResponseShapeType(); frst.BaseShape = DefaultShapeNamesType.AllProperties; //restrict the search on the folder name PathToUnindexedFieldType ftFolderName = new PathToUnindexedFieldType(); ftFolderName.FieldURI = UnindexedFieldURIType.folderDisplayName; ConstantValueType cvt = new ConstantValueType(); cvt.Value = szFolderName; FieldURIOrConstantType ctFolderName = new FieldURIOrConstantType(); ctFolderName.Item = cvt; ContainsExpressionType cet = new ContainsExpressionType(); cet.Constant = cvt; cet.Item = ftFolderName; cet.ContainmentComparison = ContainmentComparisonType.IgnoreCase; cet.ContainmentComparisonSpecified = true; cet.ContainmentMode = ContainmentModeType.FullString; cet.ContainmentModeSpecified = true; RestrictionType rt = new RestrictionType(); rt.Item = cet; //find the folder FindFolderType fft = new FindFolderType(); fft.Traversal = FolderQueryTraversalType.Deep; fft.ParentFolderIds = fit; fft.FolderShape = frst; fft.Restriction = rt; FindFolderResponseType ffrt = esb.FindFolder(fft); ResponseMessageType rmt = ((ResponseMessageType)ffrt.ResponseMessages.Items[0]); if (rmt.ResponseClass == ResponseClassType.Success) { BaseFolderType[] bfts = ((FindFolderResponseMessageType)ffrt.ResponseMessages.Items[0]).RootFolder.Folders; if (bfts.GetLength(0) > 0) return bfts[0]; else return null; } else return null; } static public ItemType GetItem(ExchangeServiceBinding esb, string szItemId) { if (null == esb || null == szItemId) return null; //specify the content that we want to retrieve, we are retrieving AllProperties ItemResponseShapeType irst = new ItemResponseShapeType(); irst.BaseShape = DefaultShapeNamesType.AllProperties; irst.IncludeMimeContent = true; irst.IncludeMimeContentSpecified = true; ItemIdType iit = new ItemIdType(); iit.Id = szItemId; BaseItemIdType[] biit = new BaseItemIdType[1]; biit[0] = iit; //get the item GetItemType git = new GetItemType(); git.ItemShape = irst; git.ItemIds = biit; GetItemResponseType girt = esb.GetItem(git); if (girt.ResponseMessages.Items[0].ResponseClass == ResponseClassType.Success) return ((ItemType)(((ItemInfoResponseMessageType)girt.ResponseMessages.Items[0]).Items.Items[0])); else return null; } static public string GetRootFolderId(ExchangeServiceBinding esb) { if (null == esb) return null; DistinguishedFolderIdType[] dfit = new DistinguishedFolderIdType[1]; //get the root folder ID dfit[0] = new DistinguishedFolderIdType(); dfit[0].Id = DistinguishedFolderIdNameType.root; //set the props that we want to retrieve FolderResponseShapeType frst = new FolderResponseShapeType(); frst.BaseShape = DefaultShapeNamesType.AllProperties; //get the folder GetFolderType gftRoot = new GetFolderType(); gftRoot.FolderIds = dfit; gftRoot.FolderShape = frst; GetFolderResponseType gfrt = esb.GetFolder(gftRoot); FolderInfoResponseMessageType firmt = ((FolderInfoResponseMessageType)gfrt.ResponseMessages.Items[0]); if (firmt.ResponseClass == ResponseClassType.Success) return ((FolderInfoResponseMessageType)gfrt.ResponseMessages.Items[0]).Folders[0].FolderId.Id; else return null; } static public ItemType[] FindAllItems(ExchangeServiceBinding esb, string strFolderID, DateTime StartDate, DateTime EndDate) { if (null == esb || null == strFolderID || "" == strFolderID) return null; //get the inbox folder ID FolderIdType[] fita = new FolderIdType[1]; fita[0] = new FolderIdType(); fita[0].Id = strFolderID; //request AllProperties PathToUnindexedFieldType[] ptufta = new PathToUnindexedFieldType[1]; ptufta[0] = new PathToUnindexedFieldType(); ptufta[0].FieldURI = UnindexedFieldURIType.itemItemClass; ItemResponseShapeType irst = new ItemResponseShapeType(); irst.BaseShape = DefaultShapeNamesType.AllProperties; irst.IncludeMimeContent = false; irst.AdditionalProperties = ptufta; //restrict the returned items to just items of a specific message class PathToUnindexedFieldType MsgClassField = new PathToUnindexedFieldType(); MsgClassField.FieldURI = UnindexedFieldURIType.itemItemClass; ConstantValueType MsgClassToGet = new ConstantValueType(); MsgClassToGet.Value = "IPM.NOTE"; FieldURIOrConstantType MsgClassConstant = new FieldURIOrConstantType(); MsgClassConstant.Item = MsgClassToGet; IsEqualToType iett = new IsEqualToType(); iett.FieldURIOrConstant = MsgClassConstant; iett.Item = MsgClassField; //restrict the returned items greater than a specified date PathToUnindexedFieldType StartDateReceivedField = new PathToUnindexedFieldType(); StartDateReceivedField.FieldURI = UnindexedFieldURIType.itemDateTimeReceived; ConstantValueType StartDateReceivedToGet = new ConstantValueType(); StartDateReceivedToGet.Value = StartDate.ToUniversalTime().ToString(); FieldURIOrConstantType StartDateReceivedConstant = new FieldURIOrConstantType(); StartDateReceivedConstant.Item = StartDateReceivedToGet; IsGreaterThanOrEqualToType igtett = new IsGreaterThanOrEqualToType(); igtett.FieldURIOrConstant = StartDateReceivedConstant; igtett.Item = StartDateReceivedField; //restrict the returned items less than a specified date PathToUnindexedFieldType EndDateReceivedField = new PathToUnindexedFieldType(); EndDateReceivedField.FieldURI = UnindexedFieldURIType.itemDateTimeReceived; ConstantValueType EndDateReceivedToGet = new ConstantValueType(); EndDateReceivedToGet.Value = EndDate.ToUniversalTime().ToString(); FieldURIOrConstantType EndDateReceivedConstant = new FieldURIOrConstantType(); EndDateReceivedConstant.Item = EndDateReceivedToGet; IsLessThanOrEqualToType iltett = new IsLessThanOrEqualToType(); iltett.FieldURIOrConstant = EndDateReceivedConstant; iltett.Item = EndDateReceivedField; AndType at = new AndType(); at.Items = new SearchExpressionType[3]; at.Items[0] = igtett; at.Items[1] = iltett; //TODO: Uncomment the following line if you want to display only email items from folder // If the following line is commented then all items would be returned from folder, // for e.g. Reports, Appointment, Meeting Requests, Contacts etc. //at.Items[2] = iett; RestrictionType rt = new RestrictionType(); rt.Item = at; //find the items FindItemType fit = new FindItemType(); fit.ItemShape = irst; fit.ParentFolderIds = fita; fit.Restriction = rt; FindItemResponseType firt = esb.FindItem(fit); return ((ArrayOfRealItemsType)((FindItemResponseMessageType)firt.ResponseMessages .Items[0]).RootFolder.Item).Items; } }
Exchange Web Service is very powerful but everything has some limitations.
I've been struggling with one limitation that you cannot access any folder in Mailbox using its path like
/Inbox/MyFolder1/MyAnotherFolder/ThisIsTheFolderIWant
Client is not aware of the folder hierarchy on server side so you cannot access any folder directly, you need to create your own mechanism for that.
I am sharing the sample code I have created to Traverse down to the Folder path one by one and finally return the last folder.
Approach
- Suppose you want to get into “/Inbox/First/Second/Final” folder
- Get root folder’s ID
- Find Inbox using root folder’s ID
- Find First using Inbox folder’s ID
- and so on till Final folder
- Remember you should call FindFolder with FullString ContainmentModeType to get the desired result, otherwise you might get wrong folder
Code
Note: I have tested this code on Exchange 2007 RTM with Visual Studio 2005 , and it should work fine
class Program { static void Main(string[] args) { ExchangeServiceBinding esb = new ExchangeServiceBinding(); esb.Credentials = new System.Net.NetworkCredential("UserName", "Password"); esb.Url = "http://YourExchangeServerHere/ews/exchange.asmx"; BaseFolderType bft = GetFolderByPath(esb, "/Inbox/Folder1/Folder2/Folder3/FinalFolder"); if (null == bft) Console.WriteLine("Folder not found."); else Console.WriteLine("Folder Found: " + bft.DisplayName); return; } static public BaseFolderType GetFolderByPath(ExchangeServiceBinding esb, string szFolderPath) { if (null == szFolderPath) return null; if (szFolderPath.IndexOf("/") == -1) return null; if (szFolderPath.Substring(0, 1).CompareTo("/") == 0) szFolderPath = szFolderPath.Substring(1); string[] Path = szFolderPath.Split('/'); string szParentFolderId = null; BaseFolderType bft = null; for (int i = 0; i < Path.GetLength(0); i++) { if (null == szParentFolderId) szParentFolderId = GetRootFolderId(esb); bft = GetFolder(esb, szParentFolderId, Path[i]); if (null == bft) return null; else szParentFolderId = bft.FolderId.Id; } return bft; } static public BaseFolderType GetFolder(ExchangeServiceBinding esb, string szParentFolderId, string szFolderName) { if (null == esb || null == szFolderName) return null; //get the root folder ID FolderIdType[] fit = new FolderIdType[1]; fit[0] = new FolderIdType(); fit[0].Id = szParentFolderId; //set the props that we want to retrieve FolderResponseShapeType frst = new FolderResponseShapeType(); frst.BaseShape = DefaultShapeNamesType.AllProperties; //restrict the search on the folder name PathToUnindexedFieldType ftFolderName = new PathToUnindexedFieldType(); ftFolderName.FieldURI = UnindexedFieldURIType.folderDisplayName; ConstantValueType cvt = new ConstantValueType(); cvt.Value = szFolderName; FieldURIOrConstantType ctFolderName = new FieldURIOrConstantType(); ctFolderName.Item = cvt; ContainsExpressionType cet = new ContainsExpressionType(); cet.Constant = cvt; cet.Item = ftFolderName; cet.ContainmentComparison = ContainmentComparisonType.IgnoreCase; cet.ContainmentComparisonSpecified = true; cet.ContainmentMode = ContainmentModeType.FullString; cet.ContainmentModeSpecified = true; RestrictionType rt = new RestrictionType(); rt.Item = cet; //find the folder FindFolderType fft = new FindFolderType(); fft.Traversal = FolderQueryTraversalType.Deep; fft.ParentFolderIds = fit; fft.FolderShape = frst; fft.Restriction = rt; FindFolderResponseType ffrt = esb.FindFolder(fft); ResponseMessageType rmt = ((ResponseMessageType)ffrt.ResponseMessages.Items[0]); if (rmt.ResponseClass == ResponseClassType.Success) { BaseFolderType[] bfts = ((FindFolderResponseMessageType)ffrt.ResponseMessages.Items[0]).RootFolder.Folders; if (bfts.GetLength(0) > 0) return bfts[0]; else return null; } else return null; } static public string GetRootFolderId(ExchangeServiceBinding esb) { if (null == esb) return null; DistinguishedFolderIdType[] dfit = new DistinguishedFolderIdType[1]; //get the root folder ID dfit[0] = new DistinguishedFolderIdType(); dfit[0].Id = DistinguishedFolderIdNameType.root; //set the props that we want to retrieve FolderResponseShapeType frst = new FolderResponseShapeType(); frst.BaseShape = DefaultShapeNamesType.AllProperties; //get the folder GetFolderType gftRoot = new GetFolderType(); gftRoot.FolderIds = dfit; gftRoot.FolderShape = frst; GetFolderResponseType gfrt = esb.GetFolder(gftRoot); FolderInfoResponseMessageType firmt = ((FolderInfoResponseMessageType)gfrt.ResponseMessages.Items[0]); if (firmt.ResponseClass == ResponseClassType.Success) return ((FolderInfoResponseMessageType)gfrt.ResponseMessages.Items[0]).Folders[0].FolderId.Id; else return null; } }