Using Delegate Access with Exchange Web Services

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-07-23

By Michael Mainer, Programming Writer

Exchange Web Services in Microsoft Exchange Server 2007 provides the following two methods by which accounts can access the contents of other users' mailboxes:

  • Server-to-server authorization, also known as Exchange Impersonation
  • Delegate access

Exchange Impersonation enables one account to act as another account. In this manner, middle tier servers can act as clients that need access to Exchange 2007 mailbox information. For more information about Exchange Impersonation, see Server-to-Server Authorization. Delegate access differs from Exchange Impersonation in that accounts act on behalf of the account of a principal.

In this article, I will delve into delegate access in Exchange 2007. Delegate access in Exchange 2007 enables delegates to access the mailbox of a principal and perform search, create, delete, update, and copy operations.

Note

You can also use Microsoft Outlook or the Exchange Management Shell to set up delegate access. For information about how to use the Exchange Management Shell to set delegate access, see Add- MailboxPermission.

Using Exchange Web Services to Enable Delegate Access

Let's explore how you can use Exchange Web Services to enable delegate access.

Note

You must set delegate access permissions before delegate access attempts will succeed.

Using Delegate Access in a Request

Ad hoc FindItem and FindFolder operation searches are used as the entry point for delegate access to the mailbox of a principal. These operations identify parent folders that are searched. If the caller is using delegate access, the parent folders that are searched are located in the mailbox of the principal, instead of the mailbox of the caller.

Listing 1 shows a partial XML request to search the mailboxes of two principals.

Listing 1   Request to search user1's Junk E-mail folder and user2's Inbox folder

<FindItem Traversal="Shallow">
  <ItemShape>
    <t:BaseShape>IdOnly</t:BaseShape>
  </ItemShape>
  <ParentFolderIds>
    <t:DistinguishedFolderId Id="junkemail">
      <t:Mailbox>
        <t:EmailAddress>user1@example.com</t:EmailAddress>
      </t:Mailbox>
    </t:DistinguishedFolderId>
    <t:DistinguishedFolderId Id="inbox">
      <t:Mailbox>
        <t:EmailAddress>user2@example.com</t:EmailAddress>
      </t:Mailbox>
    </t:DistinguishedFolderId>
  </ParentFolderIds>
</FindItem>

The Mailbox child element of the DistinguishedFolderId element signifies that a delegate is performing the FindItem request. If the Mailbox elements were removed from this request, the FindItem search would be performed on the caller's Junk E-mail and Inbox folders. Because the Mailbox elements are included, the request represents an attempt by the caller to act as a delegate to search the mailboxes of the two principals, user1 and user2.

Listing 2 shows you how to perform this search by using the proxy objects.

Listing 2    Partial FindItem request for delegate access

FindItemType request = new FindItemType();
DistinguishedFolderIdType[] folders = new DistinguishedFolderIdType[2];
folders[0].Id = DistinguishedFolderIdNameType.junkemail;
folders[0].Mailbox = new EmailAddressType();
folders[0].Mailbox.EmailAddress = "user1@example.com";
folders[1].Id = DistinguishedFolderIdNameType.inbox;
folders[1].Mailbox = new EmailAddressType();
folders[1].Mailbox.EmailAddress = "user2@example.com";
request.ParentFolderIds = folders;

Handling Delegate Access in a Response

OK, so now you need to understand what is returned in a delegate access response. And more importantly, how delegate access is implemented.

Exchange Web Services interprets a request that contains the Mailbox element as a child element of the DistinguishedFolderId element as a request for delegate access. When it receives this kind of request, Exchange Web Services first determines whether the caller has act as owner permissions. If the caller has act as owner permissions, Exchange Web Services opens the mailbox as expected. Otherwise, it opens the mailbox as a delegate and the Exchange store performs access checks on each operation that the Exchange Web Services client performs.

Note

In Exchange Server 2007, each item and folder identifier that is returned in the delegate access FindItem response contains the Simple Mail Transfer Protocol (SMTP) address of the mailbox user, who owns the item, embedded in the identifier. If the SMTP address of a user is changed while an item or folder identifier is cached on a client, the cached identifiers will become invalid. In Exchange Server 2007 SP1, the SMTP address is no longer embedded in the identifier and is replaced by a mailbox identifier. Because the identity of the mailbox is included in the identifier, subsequent requests that use those identifiers are implicitly used for delegate access.

The proxy object response to a delegate access FindItem request will contain one FindItemResponseMessageType per folder searched. In Listing 3, two FindItemResponseMessageType objects are represented by the FindItemResponseMessage element. These two elements represent the two folders that are identified to be searched in the request. The FindItemResponseMessageType order is determined by the order in which the folders were serialized. In the previous example, we identified user1's Junk E-mail folder first, therefore it will be the first FindItemResponseMessageType in the response. This is important when the delegate has to distinguish item ownership. Listing 3 shows you the XML in the response. Notice that there are two folders that have a single item in each one.

Listing 3   The FindItemResponse for a delegate access search of two folders in two different mailboxes

<FindItemResponse>
  <ResponseMessages xmlns="https://schemas.microsoft.com/exchange/services/2006/messages">
    <FindItemResponseMessage ResponseClass="Success">
      <ResponseCode>NoError</ResponseCode>
      <RootFolder IncludesLastItemInRange="true" TotalItemsInView="1">
        <Items xmlns="https://schemas.microsoft.com/exchange/services/2006/types">
          <MeetingRequest>
            <ItemId Id="AAArAG1za2lgAA" ChangeKey="CwAAABYAAAAMoHzy8/" />
          </MeetingRequest>
        </Items>
      </RootFolder>
    </FindItemResponseMessage>
    <FindItemResponseMessage ResponseClass="Success">
      <ResponseCode>NoError</ResponseCode>
      <RootFolder IncludesLastItemInRange="true" TotalItemsInView="1">
        <Items xmlns="https://schemas.microsoft.com/exchange/services/2006/types">
          <MeetingRequest>
            <ItemId Id="AAAnAHJheWRAbW" ChangeKey="CwAAABYZAG6tPNDn" />
          </MeetingRequest>
        </Items>
      </RootFolder>
    </FindItemResponseMessage>
  </ResponseMessages>
</FindItemResponse>

Delegate Access and the Proxy Objects

We have seen the XML for the request and the XML deserialized from the response. But how does this all work when you are using the proxy objects? (For information about proxy objects, see Introduction to Exchange Web Services in Exchange 2007, Part 3).

Let's take a look at Listing 4. The code example in Listing 4 performs the same delegate access operation that is performed in Listing 1 and Listing 3. It shows an attempt to search the mailboxes of two principals.

Listing 4   An attempt to perform a delegate access search of two mailboxes

static void FindItems(ExchangeServiceBinding esb)
{
    // Form the FindItem request.
    FindItemType findItemRequest = new FindItemType();

    // Define which item properties are returned in the response.
    ItemResponseShapeType itemProperties = new ItemResponseShapeType();
    // Use the Default shape for the response. 
    itemProperties.BaseShape = DefaultShapeNamesType.IdOnly;
    findItemRequest.ItemShape = itemProperties;

    DistinguishedFolderIdType[] folderIDArray = new DistinguishedFolderIdType[2];
    folderIDArray[0] = new DistinguishedFolderIdType();
    folderIDArray[0].Id = DistinguishedFolderIdNameType.junkemail;
    folderIDArray[0].Mailbox = new EmailAddressType();
    folderIDArray[0].Mailbox.EmailAddress = " user1@example.com ";
    folderIDArray[1] = new DistinguishedFolderIdType();
    folderIDArray[1].Id = DistinguishedFolderIdNameType.inbox;
    folderIDArray[1].Mailbox = new EmailAddressType();
    folderIDArray[1].Mailbox.EmailAddress = " user2@example.com ";

    findItemRequest.ParentFolderIds = folderIDArray;

    // Define the traversal type.
    findItemRequest.Traversal = ItemQueryTraversalType.Shallow;

    try
    {
        // Send the FindItem request and get the response.
        FindItemResponseType findItemResponse = esb.FindItem(findItemRequest);

        // Access the response message.
        ArrayOfResponseMessagesType responseMessages = findItemResponse.ResponseMessages;
        ResponseMessageType[] rmta = responseMessages.Items;

        int folderNumber = 0;

        foreach (ResponseMessageType rmt in rmta)
        {
            // One FindItemResponseMessageType per folder searched.
            FindItemResponseMessageType firmt = rmt as FindItemResponseMessageType;

            FindItemParentType fipt = firmt.RootFolder;
            object obj = fipt.Item;

            // FindItem contains an array of items.
            if (obj is ArrayOfRealItemsType)
            {
                ArrayOfRealItemsType items = (obj as ArrayOfRealItemsType);
                if (items.Items == null)
                {
                    Console.WriteLine("Folder {0}: No items in folder", folderNumber);
                    folderNumber++;
                }
                else
                {
                    foreach (ItemType it in items.Items)
                    { 
                        Console.WriteLine("Folder {0}: Item identifier: {1}", folderNumber, it.ItemId.Id);

                    }
                    
                    folderNumber++;
                }
            }
        }
        Console.ReadLine();
    }
    catch (Exception e)
    {
        Console.WriteLine(e.Message);
    }
}

Delegate Access and Security

Before you use delegate access in a production environment, you should consider the security implications of delegating access. Delegates are given rights to act on behalf of the principal who grants the rights. Therefore, an implicit trust relationship must exist between the delegate and the principal. Depending on the rights assigned, the delegate may have access to items marked as private or may be able to delete items. If you use delegate access, make sure that you are using it in compliance with the security requirements of your organization.

Looking Ahead

This article describes the delegate access functionality that is available in Exchange Server 2007. Exchange Server 2007 Service Pack 1 (SP1) introduces new operations that improve the delegate access story. For starters, Exchange Web Services in Exchange 2007 SP1 exposes a set of new delegate management operations that can be used to set up delegate access from a client. In addition, the following delegate access functionality is available in Exchange 2007 SP1:

  • You can enable delegate access to items based on folder-level permissions that are set by using the delegate management operations. This provides for a more granular level of control.
  • Delegates can create and send meeting messages on behalf of the principal.
  • Delegates can receive meeting messages that are forwarded by the principal and respond to them for the principal.
  • Users who have owner rights on a shared mailbox can open the mailbox and act as the owner. Yep, as they should.
  • Delegates can create notification subscriptions on folders in the mailbox of the principal. This one can be very useful.

Now that you have a better understanding of how to use delegate access with Exchange Web Services, stay tuned for an upcoming article that describes Exchange Impersonation and how to use it.

Summary

Exchange Web Services provides a powerful tool for accessing other users' mailboxes. Delegate access provides a convenient way for Exchange Web Services clients to act on behalf of other user accounts and opens the door for you to create client applications that can work across mailboxes. Exchange Server 2007 SP1 will introduce enhancements to the delegate access story. So gear up and start adding delegate access functionality to your Exchange Web Services client applications.