Use search filters with EWS in Exchange

Find out how to use search filters with the EWS Managed API or EWS in Exchange.

Search filters are the primary tool for expressing search criteria in your EWS Managed API or EWS application. We recommend that you use search filters, as opposed to query strings, to do the following:

  • Search on a specific property or set of properties.
  • Search using multiple search criteria.

Search filters are your only option if you are doing any of the following:

  • Searching custom properties.
  • Performing case-sensitive string searches.
  • Performing prefix or exact match string searches.
  • Performing bitmask searches.
  • Searching for items that have a specific property set, regardless of value.
  • Searching for folders.
  • Creating search folders.

Determine what type of search filter you need

Before you create a search filter, first determine which type of filter you need. The filter types are implemented as descendant classes of the SearchFilter class in the EWS Managed API, and as child elements of the Restriction element in EWS.

Table 1. Types of search filters

Filter type EWS Managed API class EWS element Description
Contains filter
ContainsSubstring
Contains
The best filter type to use for string comparisons. It allows you to control case sensitivity, whether to ignore whitespace, and set the containment mode.
Bitmask filter
ExcludesBitmask
Excludes
Allows you to search integer properties as bitmasks and only return results that have bits corresponding to the specified bitmask unset.
Exists filter
Exists
Exists
Returns all items that have the specified property present, regardless of value.
Equality filter
IsEqualTo
IsNotEqualTo
IsEqualTo
IsNotEqualTo
Compares the value of the specified property with either a specified constant value or the value of another property and return all items that have an equal value (in the case of an IsEqualTo filter) or a non-equal value (in the case of an IsNotEqualTo filter).
Relational testing filter
IsGreaterThan
IsGreaterThanOrEqualTo
IsLessThan
IsLessThanOrEqualTo
IsGreaterThan
IsGreaterThanOrEqualTo
IsLessThan
IsLessThanOrEqualTo
Returns all items that have a value for the specified property in the appropriate relation to either a specified constant value or another property. For example, an IsGreaterThan filter returns all items that have a value that is greater than the specified value in the specified property.
Negating filter
Not
Not
Negates the result of the other filters.
Compound filter
SearchFilterCollection
And
Or
Combines multiple filters, allowing for more complex search criteria.

Contains filter

A contains filter is the best choice for searching string properties. With a contains filter, you can control aspects of string matching, like case sensitivity and how whitespace is treated, by setting the containment mode and the comparison mode.

Contains filter in the EWS Managed API

If you're using the EWS Managed API, you set the containment mode by using the ContainmentMode property of the ContainsSubstring class, and you set the comparison mode by using the ComparisonMode property of the ContainsSubstring class. The following example shows you how to create a search filter that searches the subject field of items for the substring "meeting notes". This example ignores case, but does not ignore whitespace.

// Find all items with a subject that contain the substring
// "meeting notes", regardless of case.
// Matches include:
//   - meeting notes
//   - Meeting Notes
//   - Here are my meeting notes
SearchFilter.ContainsSubstring subjectFilter = new SearchFilter.ContainsSubstring(ItemSchema.Subject,
    "meeting notes", ContainmentMode.Substring, ComparisonMode.IgnoreCase);

Contains filter in EWS

In EWS, you set the containment mode by using the ContainmentMode attribute on the Contains element, and you set the comparison mode by using the ContainmentComparison attribute on the Contains element. The following example shows you how to create a search filter to search the subject field of items for the substring "meeting notes". This example ignores case, but does not ignore whitespace.

<t:Contains ContainmentMode="Substring" ContainmentComparison="IgnoreCase">
  <t:FieldURI FieldURI="item:Subject" />
  <t:Constant Value="meeting notes" />
</t:Contains>

Bitmask filter

A bitmask filter enables you to search integer properties as bitmasks, and return results where specific bits are not set in the value of the specified property.

Bitmask filter in the EWS Managed API

The following example shows you how to use the EWS Managed API to create a search filter to return all items that have a value in the ItemIndex custom property (defined in the Example: Find items by using a search filter and the EWS Managed API section of this article) that do not have the second bit (10 in binary) set.

// Find all items with a value of the custom property that does not
// have the second bit (0010) set.
// Matches include:
//   - Property not set
//   - 1 (0001)
//   - 4 (0100)
//   - 5 (0101)
//   - 8 (1000)
SearchFilter.ExcludesBitmask bit2NotSetFilter = 
    new SearchFilter.ExcludesBitmask(customPropDefinition, 2);

Bitmask filter in EWS

The following example shows you how to use EWS to create a search filter to return all items that have a value in the ItemIndex custom property (defined in the Example: Find items by using a search filter and the EWS Managed API section of this article) that do not have the second bit (10 in binary) set.

<t:Excludes>
  <t:ExtendedFieldURI PropertySetId="aa3df801-4fc7-401f-bbc1-7c93d6498c2e" PropertyName="ItemIndex" PropertyType="Integer" />
  <t:Bitmask Value="2" />
</t:Excludes>

Exists filter

An exists filter enables you to search for items that have a specific property set on them, regardless of the value.

Exists filter in the EWS Managed API

The following example shows you how to create a search filter to return all items that have the ItemIndex custom property set.

// Find all items that have the custom property set.
SearchFilter.Exists customPropSetFilter =
    new SearchFilter.Exists(customPropDefinition);

Exists filter in EWS

The following example shows you how to create a search filter to return all items that have the ItemIndex custom property set.

<t:Exists>
  <t:ExtendedFieldURI PropertySetId="aa3df801-4fc7-401f-bbc1-7c93d6498c2e" PropertyName="ItemIndex" PropertyType="Integer" />
</t:Exists>

Equality filter

Equality filters enable you to search for all items that have a value for the specified property that either equals a specific value or does not equal a specific value. The value to compare with can be either a constant value or the value of another property on each item.

Equality filter in the EWS Managed API

The following example shows you how to use the EWS Managed API to create a search filter to return all items that have not been read.

// Find all items that are not marked as read.
SearchFilter.IsEqualTo unreadFilter =
    new SearchFilter.IsEqualTo(EmailMessageSchema.IsRead, false);

The following example shows you how to create a search filter to return all items that have a value in the ItemIndex property that is not equal to the size of the item.

// Find all items that are marked as read.
SearchFilter.IsNotEqualTo indexNotEqualToSizeFilter =
    new SearchFilter.IsNotEqualTo(customPropDefinition, ItemSchema.Size);

Equality filter in EWS

The following example shows you how to use EWS to create a search filter to return all items that have not been read.

<t:IsEqualTo>
  <t:FieldURI FieldURI="message:IsRead" />
  <t:FieldURIOrConstant>
    <t:Constant Value="false" />
  </t:FieldURIOrConstant>
</t:IsEqualTo>

The following example shows you how to create a search filter to return all items that have a value in the ItemIndex property that is not equal to the size of the item.

<t:IsNotEqualTo>
  <t:ExtendedFieldURI PropertySetId="aa3df801-4fc7-401f-bbc1-7c93d6498c2e" PropertyName="ItemIndex" PropertyType="Integer" />
  <t:FieldURIOrConstant>
    <t:FieldURI FieldURI="item:Size" />
  </t:FieldURIOrConstant>
</t:IsNotEqualTo>

Relational testing filter

Relational testing filters enable you to search for all items that have a value in the specified property that is either greater than (>), greater than or equal to (>=), less than (<), or less than or equal to (<=) a specified value. The value to compare with can be either a constant value or the value of another property on each item.

Relational testing filter in the EWS Managed API

The following example shows you how to use the EWS Managed API to create search filters to return all items with a value in the ItemIndex property that has the specified relationship to the constant value 3.

// Find all items where the custom property value is > 3.
SearchFilter.IsGreaterThan greaterThanFilter =
    new SearchFilter.IsGreaterThan(customPropDefinition, 3);
// Find all items where the custom property value is >= 3.
SearchFilter.IsGreaterThanOrEqualTo greaterThanOrEqualFilter =
    new SearchFilter.IsGreaterThanOrEqualTo(customPropDefinition, ItemSchema.Size);
// Find all items where the custom property value is < 3.
SearchFilter.IsLessThan lessThanFilter =
    new SearchFilter.IsLessThan(customPropDefinition, 3);
// Find all items where the custom property value is <= 3.
SearchFilter.IsLessThanOrEqualTo lessThanOrEqualFilter =
    new SearchFilter.IsLessThanOrEqualTo(customPropDefinition, 3);

Relational testing filter in EWS

The following example shows you how to use EWS to create a search filter to return all items with a value in the ItemIndex property that is greater than the constant value 3.

<t:IsGreaterThan>
  <t:ExtendedFieldURI PropertySetId="aa3df801-4fc7-401f-bbc1-7c93d6498c2e" PropertyName="ItemIndex" PropertyType="Integer" />
  <t:FieldURIOrConstant>
    <t:Constant Value="3" />
  </t:FieldURIOrConstant>
</t:IsGreaterThan>

The following example shows you how to create a search filter to return all items with a value in the ItemIndex property that is greater than or equal to the constant value 3.

<t:IsGreaterThanOrEqualTo>
  <t:ExtendedFieldURI PropertySetId="aa3df801-4fc7-401f-bbc1-7c93d6498c2e" PropertyName="ItemIndex" PropertyType="Integer" />
  <t:FieldURIOrConstant>
    <t:Constant Value="3" />
  </t:FieldURIOrConstant>
</t:IsGreaterThanOrEqualTo>

The following example shows you how to create a search filter to return all items with a value in the ItemIndex property that is less than the constant value 3.

<t:IsLessThan>
  <t:ExtendedFieldURI PropertySetId="aa3df801-4fc7-401f-bbc1-7c93d6498c2e" PropertyName="ItemIndex" PropertyType="Integer" />
  <t:FieldURIOrConstant>
    <t:Constant Value="3" />
  </t:FieldURIOrConstant>
</t:IsLessThan>

The following example shows you how to create a search filter to return all items with a value in the ItemIndex property that is less than or equal to the constant value 3.

<t:IsLessThanOrEqualTo>
  <t:ExtendedFieldURI PropertySetId="aa3df801-4fc7-401f-bbc1-7c93d6498c2e" PropertyName="ItemIndex" PropertyType="Integer" />
  <t:FieldURIOrConstant>
    <t:Constant Value="3" />
  </t:FieldURIOrConstant>
</t:IsLessThanOrEqualTo>

Negating filter

A negating filter enables you to negate another filter and get the opposite search results. While other filters return results that match specific criteria, a negating filter returns results that do not match the criteria specified by the filter it is applied to.

Negating filter in the EWS Managed API

The following example shows you how to use the EWS Managed API to create a search filter to return all items that do not have the substring "meeting notes" in the subject.

SearchFilter.ContainsSubstring subjectFilter = new SearchFilter.ContainsSubstring(ItemSchema.Subject,
    "meeting notes", ContainmentMode.Substring, ComparisonMode.IgnoreCase);
SearchFilter.Not subjectNotFilter =
    new SearchFilter.Not(subjectFilter);

Negating filter in EWS

The following example shows you how to create a search filter to return all items that do not have the substring "meeting notes" in the subject.

<t:Not>
  <t:Contains ContainmentMode="ExactPhrase" ContainmentComparison="IgnoreCase">
    <t:FieldURI FieldURI="item:Subject" />
    <t:Constant Value="meeting notes" />
  </t:Contains>
</t:Not>

Compound filter

A compound filter enables you to combine multiple filters to create more complex search criteria. You can combine criteria by using the logical operators AND or OR. In this way, you can perform searches like "all mail from Sadie Daniels that contains 'meeting notes' in the subject".

Compound filter in the EWS Managed API

The following example shows you how to use the EWS Managed API to create a search filter that returns all items that are sent from Sadie Daniels and contain "meeting notes" in the subject.

SearchFilter.ContainsSubstring subjectFilter = new SearchFilter.ContainsSubstring(ItemSchema.Subject,
    "meeting notes", ContainmentMode.Substring, ComparisonMode.IgnoreCase);
EmailAddress manager = new EmailAddress("sadie@contoso.com");
SearchFilter.IsEqualTo fromManagerFilter =
    new SearchFilter.IsEqualTo(EmailMessageSchema.Sender, manager);
SearchFilter.SearchFilterCollection compoundFilter =
    new SearchFilter.SearchFilterCollection(LogicalOperator.And, subjectFilter, fromManagerFilter);

Compound filter in EWS

The following example shows you how to use EWS to create a search filter that returns all items that are sent from Sadie Daniels and contain "meeting notes" in the subject.

<t:And>
  <t:Contains ContainmentMode="Substring" ContainmentComparison="IgnoreCase">
    <t:FieldURI FieldURI="item:Subject" />
    <t:Constant Value="meeting notes" />
  </t:Contains>
  <t:IsEqualTo>
    <t:FieldURI FieldURI="message:Sender" />
    <t:FieldURIOrConstant>
      <t:Constant Value="sadie@fourthcoffee.com" />
    </t:FieldURIOrConstant>
  </t:IsEqualTo>
</t:And>

Example: Find items by using a search filter and the EWS Managed API

The following EWS Managed API methods use search filters:

The following example uses the ExchangeService.FindItems method; however, the same rules and concepts apply to all the methods. In this example, a method called SearchWithFilter is defined. It takes an ExchangeService object, a WellKnownFolderName object, and a SearchFilter object as parameters. This example assumes that the ExchangeService object has been initialized with valid values in the Credentials and Url properties. The SearchFilter class is the base class for all the different search filters.

using Microsoft.Exchange.WebServices.Data
private static Guid SearchTestGUID = new Guid("{AA3DF801-4FC7-401F-BBC1-7C93D6498C2E}");
private static ExtendedPropertyDefinition customPropDefinition =
        new ExtendedPropertyDefinition(SearchTestGUID, "ItemIndex", MapiPropertyType.Integer);
static void SearchWithFilter(ExchangeService service, WellKnownFolderName folder, SearchFilter filter)
{
    // Limit the result set to 10 items.
    ItemView view = new ItemView(10);
    view.PropertySet = new PropertySet(ItemSchema.Subject, 
                                       ItemSchema.DateTimeReceived,
                                       EmailMessageSchema.IsRead,
                                       customPropDefinition);
    // Item searches do not support Deep traversal.
    view.Traversal = ItemTraversal.Shallow;
    // Sorting.
    view.OrderBy.Add(ItemSchema.DateTimeReceived, SortDirection.Descending);
    try
    {
        FindItemsResults<Item> results = service.FindItems(folder, filter, view);
        foreach (Item item in results.Items)
        {
            Console.WriteLine("Subject: {0}", item.Subject);
            Console.WriteLine("Id: {0}", item.Id.ToString());
            if (item.ExtendedProperties.Count > 0 &&
                 item.ExtendedProperties[0].PropertyDefinition == customPropDefinition)
            {
                Console.WriteLine("Search Index: {0}", item.ExtendedProperties[0].Value);
            }
            if (item is EmailMessage)
            {
                EmailMessage message = item as EmailMessage;
                Console.WriteLine("Read: {0}", message.IsRead.ToString());
            }
        }
    }
    catch (Exception ex)
    {
        Console.WriteLine("Exception while enumerating results: {0}", ex.Message);
    }
}

You can use this function with any of the search filters shown in the examples in this article. This example uses a compound filter to return all items in the Inbox from Sadie Daniels with "meeting notes" in the subject.

SearchFilter.ContainsSubstring subjectFilter = new SearchFilter.ContainsSubstring(ItemSchema.Subject,
    "meeting notes", ContainmentMode.Substring, ComparisonMode.IgnoreCase);
EmailAddress manager = new EmailAddress("sadie@contoso.com");
SearchFilter.IsEqualTo fromManagerFilter =
    new SearchFilter.IsEqualTo(EmailMessageSchema.Sender, manager);
SearchFilter.SearchFilterCollection compoundFilter =
    new SearchFilter.SearchFilterCollection(LogicalOperator.And, subjectFilter, greaterThanFilter);
SearchWithFilter(service, WellKnownFolderName.Inbox, compoundFilter);

Example: Find an item by using a search filter and EWS

The following EWS operations use search filters:

The following example uses the FindItem operation; however, the same rules and concepts apply to both operations. Search filters are contained in the Restriction element in SOAP requests. This example sends a SOAP request that is equivalent to the search that is shown in the preceding EWS Managed API example.

<?xml version="1.0" encoding="utf-8"?>
<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="https://schemas.xmlsoap.org/soap/envelope/">
  <soap:Header>
    <t:RequestServerVersion Version="Exchange2013" />
  </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:FieldURI FieldURI="message:IsRead" />
          <t:ExtendedFieldURI PropertySetId="aa3df801-4fc7-401f-bbc1-7c93d6498c2e" PropertyName="ItemIndex" PropertyType="Integer" />
        </t:AdditionalProperties>
      </m:ItemShape>
      <m:IndexedPageItemView MaxEntriesReturned="10" Offset="0" BasePoint="Beginning" />
      <m:Restriction>
        <t:And>
          <t:Contains ContainmentMode="Substring" ContainmentComparison="IgnoreCase">
            <t:FieldURI FieldURI="item:Subject" />
            <t:Constant Value="meeting notes" />
          </t:Contains>
          <t:IsEqualTo>
            <t:FieldURI FieldURI="message:Sender" />
            <t:FieldURIOrConstant>
              <t:Constant Value="sadie@contoso.com" />
            </t:FieldURIOrConstant>
          </t:IsEqualTo>
        </t:And>
      </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 response from the server, including the search results.

<s:Envelope xmlns:s="https://schemas.xmlsoap.org/soap/envelope/">
  <s:Header>
    <h:ServerVersionInfo MajorVersion="15" MinorVersion="0" MajorBuildNumber="712" MinorBuildNumber="22" Version="V2_3" 
        xmlns:h="https://schemas.microsoft.com/exchange/services/2006/types" 
        xmlns="https://schemas.microsoft.com/exchange/services/2006/types" 
        xmlns:xsd="http://www.w3.org/2001/XMLSchema" 
        xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" />
  </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/services/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:Message>
                <t:ItemId Id="AAMkAGM2..." ChangeKey="CQAAABYA..." />
                <t:Subject>meeting notes</t:Subject>
                <t:DateTimeReceived>2013-11-20T21:18:51Z</t:DateTimeReceived>
                <t:ExtendedProperty>
                  <t:ExtendedFieldURI PropertySetId="aa3df801-4fc7-401f-bbc1-7c93d6498c2e" PropertyName="ItemIndex" PropertyType="Integer" />
                  <t:Value>5</t:Value>
                </t:ExtendedProperty>
                <t:IsRead>true</t:IsRead>
              </t:Message>
              <t:Message>
                <t:ItemId Id="AAMkAGM2..." ChangeKey="CQAAABYA..." />
                <t:Subject>Meeting Notes</t:Subject>
                <t:DateTimeReceived>2013-11-20T21:18:51Z</t:DateTimeReceived>
                <t:ExtendedProperty>
                  <t:ExtendedFieldURI PropertySetId="aa3df801-4fc7-401f-bbc1-7c93d6498c2e" PropertyName="ItemIndex" PropertyType="Integer" />
                  <t:Value>6</t:Value>
                </t:ExtendedProperty>
                <t:IsRead>true</t:IsRead>
              </t:Message>
              <t:Message>
                <t:ItemId Id="AAMkAGM2..." ChangeKey="CQAAABYA..." />
                <t:Subject>Meeting notes</t:Subject>
                <t:DateTimeReceived>2013-11-20T21:18:51Z</t:DateTimeReceived>
                <t:ExtendedProperty>
                  <t:ExtendedFieldURI PropertySetId="aa3df801-4fc7-401f-bbc1-7c93d6498c2e" PropertyName="ItemIndex" PropertyType="Integer" />
                  <t:Value>7</t:Value>
                </t:ExtendedProperty>
                <t:IsRead>true</t:IsRead>
              </t:Message>
            </t:Items>
          </m:RootFolder>
        </m:FindItemResponseMessage>
      </m:ResponseMessages>
    </m:FindItemResponse>
  </s:Body>
</s:Envelope>

Next steps

Now that you're familiar with using search filters in basic searches, you can move on to more advanced search techniques.

See also