Searching for items in a mailbox by using the EWS Managed API 2.0

Last modified: October 13, 2012

Applies to: EWS Managed API | Exchange Server 2007 Service Pack 1 (SP1) | Exchange Server 2010

Note: This content applies to the EWS Managed API 2.0 and earlier versions. For the latest information about the EWS Managed API, see Web services in Exchange.

You can use the Microsoft Exchange Web Services (EWS) Managed API 1.0 to search for items in a mailbox.

To search for items in a mailbox

  1. Create a search filter collection.

    List<SearchFilter> searchFilterCollection = new List<SearchFilter>();
    
  2. Add search filters to the search filter collection. The following code shows how to create a logical OR search filter on the substring "Test" for the Subject property and on the substring "homecoming" for the Body property.

    searchFilterCollection.Add(new SearchFilter.ContainsSubstring(ItemSchema.Subject, "Test"));
    searchFilterCollection.Add(new SearchFilter.ContainsSubstring(ItemSchema.Body, "homecoming"));
    SearchFilter searchFilter = new SearchFilter.SearchFilterCollection(LogicalOperator.Or, searchFilterCollection.ToArray());
    

    For more information about how to build search filters, see Working with search filters by using the EWS Managed API 2.0.

  3. Create an ItemView. The following code shows an ItemView with a page size of 50.

    ItemView view = new ItemView(50); 
    

    The ItemView named view will have a page size of 50 items. If there are more search results than the view page size, subsequent calls that use ItemView offsets must be performed to return the rest of the results.

  4. Identify the properties to return in the result set and the additional properties that are returned for each item.

    view.PropertySet = new PropertySet(BasePropertySet.IdOnly, ItemSchema.Subject, ItemSchema.DateTimeReceived);
    

    The base property set that is returned can be expanded by using the BasePropertySet.FirstClassProperties enumeration for the BasePropertySet property. Additional properties, such as properties identified by the ItemSchema and MAPI properties, can be returned by adding the properties to the property set.

  5. Order the search results by the DateTimeReceived property. The sort direction is in descending order.

    view.OrderBy.Add(ItemSchema.DateTimeReceived, SortDirection.Descending);
    
  6. Set the manner by which the search filter traverses the target folder. In the following example, the search filter performs a shallow traversal. Shallow is the default option; other traversal options are Associated and SoftDeleted.

    view.Traversal = ItemTraversal.Shallow;
    
  7. Send the request to search the mailbox that is associated with the service binding. The request is to search the Inbox by using the view defined in the previous steps.

    FindItemsResults<Item> findResults = service.FindItems(WellKnownFolderName.Inbox, searchFilter, view);
    

    If the FindItems method used the overload for grouped search, the returned type would be a GroupedFindItemsResults.

  8. Process each item that is returned in the result set.

    foreach (Item myItem in findResults.Items)
    {
        if (myItem is EmailMessage)
        {
            Console.WriteLine((myItem as EmailMessage).Subject);
        }
    
        else if (myItem is MeetingRequest)
        {
            Console.WriteLine((myItem as MeetingRequest).Subject);
        }
    
        else
        {
            // Else handle other item types. 
        }
    }
    

    Important

    Make sure that the code that handles the items in the result set can handle the many different types of items that can be stored in the Exchange database.

Example

The following code example shows how to search the Inbox for any type of item that contains either the substring "Test" in the subject or the substring "homecoming" in the body. The search results are returned in a set of 50 items. Only the item identifier, the subject, and the date/time when the item was received are returned in the search results for each item. The search results are returned in descending order based on the DateTimeReceived property.

// Add a search filter that searches on the body or subject.
List<SearchFilter> searchFilterCollection = new List<SearchFilter>();
searchFilterCollection.Add(new SearchFilter.ContainsSubstring(ItemSchema.Subject, "Test"));
searchFilterCollection.Add(new SearchFilter.ContainsSubstring(ItemSchema.Body, "homecoming"));

// Create the search filter.
SearchFilter searchFilter = new SearchFilter.SearchFilterCollection(LogicalOperator.Or, searchFilterCollection.ToArray());

// Create a view with a page size of 50.
ItemView view = new ItemView(50);

// Identify the Subject and DateTimeReceived properties to return.
// Indicate that the base property will be the item identifier
view.PropertySet = new PropertySet(BasePropertySet.IdOnly, ItemSchema.Subject, ItemSchema.DateTimeReceived);

// Order the search results by the DateTimeReceived in descending order.
view.OrderBy.Add(ItemSchema.DateTimeReceived, SortDirection.Descending);

// Set the traversal to shallow. (Shallow is the default option; other options are Associated and SoftDeleted.)
view.Traversal = ItemTraversal.Shallow;

// Send the request to search the Inbox and get the results.
FindItemsResults<Item> findResults = service.FindItems(WellKnownFolderName.Inbox, searchFilter, view);

// Process each item.
foreach (Item myItem in findResults.Items)
{
    if (myItem is EmailMessage)
    {
        Console.WriteLine((myItem as EmailMessage).Subject);
    }

    else if (myItem is MeetingRequest)
    {
        Console.WriteLine((myItem as MeetingRequest).Subject);
    }
    else
    {
        // Else handle other item types.
    }
}
' Add a search filter that searches on the body or subject.
Dim SearchFilterCollection As New List(Of SearchFilter)
SearchFilterCollection.Add(New SearchFilter.ContainsSubstring(ItemSchema.Subject, "Test"))
SearchFilterCollection.Add(New SearchFilter.ContainsSubstring(ItemSchema.Body, "homecoming"))

' Create the search filter.
Dim searchFilter As SearchFilter = New SearchFilter.SearchFilterCollection(LogicalOperator.Or, SearchFilterCollection.ToArray())

' Create a view with a page size of 50.
Dim view As New ItemView(50)

'Identify the Subject and DateTimeReceived properties to return.
'Indicate that the base property will be the item identifier
view.PropertySet = (New PropertySet(BasePropertySet.IdOnly, ItemSchema.Subject, ItemSchema.DateTimeReceived))

' Order the search results by the DateTimeReceived in descending order.
view.OrderBy.Add(ItemSchema.DateTimeReceived, SortDirection.Descending)

' Set the traversal to shallow. (Shallow is the default option; other options are Associated and SoftDeleted.)
view.Traversal = ItemTraversal.Shallow

' Send the request to search the Inbox and get the results.
Dim findResults As FindItemsResults(Of Item) = service.FindItems(WellKnownFolderName.Inbox, searchFilter, view)

' Process each item.
For Each item As Item In findResults.Items
    If TypeOf item Is EmailMessage Then
        Console.WriteLine(TryCast(item, EmailMessage).Subject)
    ElseIf TypeOf item Is MeetingRequest Then
        Console.WriteLine(TryCast(item, MeetingRequest).Subject)
    Else
        ' Else handle other item types.
    End If
Next

The following example shows the XML that is sent by the FindItems method.

<soap:Envelope xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"      
     xmlns:m="https://schemas.microsoft.com/exchange/services/2006/messages"
     xmlns:t="https://schemas.microsoft.com/exchange/services/2006/types"
     xmlns:soap="http://schemas.xml
     soap.org/soap/envelope/">
  <soap:Header>
    <t:RequestServerVersion Version="Exchange2010" />
  </soap:Header>
  <soap:Body>
    <m:FindItem Traversal="Shallow">
      <m:ItemShape>
        <t:BaseShape>IdOnly</t:BaseShape>
        <t:AdditionalProperties>
          <t:FieldURI FieldURI="item:Subject" />
          <t:FieldURI FieldURI="item:DateTimeReceived" />
        </t:AdditionalProperties>
      </m:ItemShape>
      <m:IndexedPageItemView MaxEntriesReturned="50" Offset="0" BasePoint="Beginning" />
      <m:Restriction>
        <t:Or>
          <t:Contains ContainmentMode="Substring" ContainmentComparison="IgnoreCase">
            <t:FieldURI FieldURI="item:Subject" />
            <t:Constant Value="Test" />
          </t:Contains>
          <t:Contains ContainmentMode="Substring" ContainmentComparison="IgnoreCase">
            <t:FieldURI FieldURI="item:Body" />
            <t:Constant Value="homecoming" />
          </t:Contains>
        </t:Or>
      </m:Restriction>
      <m:SortOrder>
        <t:FieldOrder Order="Descending">
          <t:FieldURI FieldURI="item:DateTimeReceived" />
        </t:FieldOrder>
      </m:SortOrder>
      <m:ParentFolderIds>
        <t:DistinguishedFolderId Id="inbox" />
      </m:ParentFolderIds>
    </m:FindItem>
  </soap:Body>
</soap:Envelope>

The following example shows the XML that is returned by using the FindItems method. The ItemId and ChangeKey attributes have been shortened to preserve readability.

<s:Envelope xmlns:s="https://schemas.xmlsoap.org/soap/envelope/">
  <s:Header>
    <h:ServerVersionInfo MajorVersion="14" 
           MinorVersion="0" 
           MajorBuildNumber="639" 
           MinorBuildNumber="20" 
           Version="Exchange2010" 
           xmlns:h="https://schemas.microsoft.com/exchange/services/2006/types"
           xmlns="https://schemas.microsoft.com/exchange/services/2006/types"
           xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" 
           xm=""lns:xsd="http://www.w3.org/2001/XMLSchema" />
  </s:Header>
  <s:Body xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:xsd="http://www.w3.org/2001/XMLSchema">
    <m:FindItemResponse xmlns:m="https://schemas.microsoft.com/exchange/service
s/2006/messages" xmlns:t="https://schemas.microsoft.com/exchange/services/2006/types">
      <m:ResponseMessages>
        <m:FindItemResponseMessage ResponseClass="Success">
          <m:ResponseCode>NoError</m:ResponseCode>
          <m:RootFolder IndexedPagingOffset="3" TotalItemsInView="3" IncludesLastItemInRange="true">
            <t:Items>
              <t:MeetingRequest>
                <t:ItemId Id="AQMkAGEyYzQ" ChangeKey="CwAAABYAAA " />
                <t:Subject>Lets have a meeting.</t:Subject>
                <t:DateTimeReceived>2009-10-12T16:12:37Z</t:DateTimeReceived>
              </t:MeetingRequest>
              <t:MeetingRequest>
                <t:ItemId Id="AQMkAGEyYzQ" ChangeKey="CwAAABYAAA " />
                <t:Subject>Over there</t:Subject>
                <t:DateTimeReceived>2009-10-08T22:22:46Z</t:DateTimeReceived>
              </t:MeetingRequest>
             <t:MeetingRequest>
                <t:ItemId Id="AQMkAGEyYzQ" ChangeKey="CwAAABYAAA " />
                <t:Subject>test</t:Subject>
                <t:DateTimeReceived>2009-10-08T22:21:15Z</t:DateTimeReceived>
              </t:MeetingRequest>
            </t:Items>
          </m:RootFolder>
        </m:FindItemResponseMessage>
      </m:ResponseMessages>
    </m:FindItemResponse>
  </s:Body>
</s:Envelope>

This example assumes that the ExchangeService object named service is correctly configured for connecting to the user’s Client Access server.

Compiling the code

For information about compiling this code, see Getting started with the EWS Managed API 2.0.

Robust programming

  • Write appropriate error handling code for common search errors.

  • Review the client request XML that is sent to the Exchange server.

  • Review the server response XML that is sent from the Exchange server.

  • Set the service binding as shown in Setting the Exchange service URL by using the EWS Managed API 2.0. Do not hard code URLs because if mailboxes move, they might be serviced by a different Client Access server. If the client cannot connect to the service, retry setting the binding by using the AutodiscoverUrl(String) method.

  • Set the target Exchange Web Services schema version by setting the requestedServerVersion parameter of the ExchangeService constructor. For more information, see Versioning EWS requests by using the EWS Managed API 2.0.

Security

  • Use HTTP with SSL for all communication between client and server.

  • Always validate the server certificate that is used for establishing the SSL connections. For more information, see Validating X509 certificates by using the EWS Managed API 2.0.

  • Do not include user names and passwords in trace files.

  • Verify that Autodiscover lookups that use HTTP GET to find an endpoint always prompt for user confirmation; otherwise, they should be blocked.