Get user photos by using EWS in Exchange

Learn how to get user photos that are associated with a mailbox or contact by using the EWS Managed API or EWS in Exchange.

It's nice to put a face to a name. If your users like to put names to faces, your application can request an image, typically a photo, from Exchange that represents an email account. You can get a user photo stored on an Exchange server for a mailbox, or you can get a contact photo from contacts stored in your mailbox.

You can use several different technologies to get photos from mailboxes or Active Directory Domain Services (AD DS). The best way to get a photo depends on the type of contact that you want to get a photo from.

Table 1. Technologies to use to get user photos based on contact type

Contact type Technologies to use
Mailbox user photo
Get a mailbox user photo by using REST

Get a user photo by using EWS
Contact user photo
Get a contact user photo by using EWS Managed API

Get a user photo by using EWS

Get a mailbox user photo by using REST

You can request user photos from an Exchange server by using a standard HTTPS GET request. In the request, specify the email account address and a size code for the image, as shown in the following example.

https://Exchange Server/ews/Exchange.asmx/s/GetUserPhoto?email=email address&size=size code

Use the Autodiscover service GetUserSettings operation to retrieve the ExternalEwsUrl setting, which contains the URL of the Exchange Web Services (EWS) endpoint and the location of the Exchange.asmx HTTP handler that returns the user photos.

Each size code indicates the height and width of the image in pixels. For example, the size code HR48x48 returns an image that is 48 pixels high by 48 pixels wide. The possible values for the size code parameter are the same as the possible values for the SizeRequested element. If the request specifies a size that is not available, the largest available photo will be returned. If no photo is stored on the Exchange server, the thumbnail image stored in AD DS for the account will be returned.

Note

The HR48x48 size code always returns the AD DS thumbnail image if it is available.

The following example shows how you can use the GET request to retrieve the user photo for Sadie and save it to your local computer.

// Create the web request with the REST URL.
HttpWebRequest request = 
   WebRequest.Create("https://www.contoso.com/ews/exchange.asmx/s/GetUserPhoto?email=sadie@contoso.com&size=HR240x240") 
   as HttpWebRequest;
// Submit the request.
using (HttpWebResponse resp = request.GetResponse() as HttpWebResponse)
{
   // Take the response and save it as an image.
   Bitmap image = new Bitmap(resp.GetResponseStream());
   image.Save("Sadie.jpg");
}

The request will return an HTTP response.

Table 2. Response codes for a GetUserPhoto request

Response code Description
200
An image is available for the specified email account and the binary image is contained in the response.
304
The image has not changed since the last time the ETag was returned to the application.
404
No image is available for the specified email account.

Cache user photos

Exchange returns the data with a content type of image/jpeg, along with a collection of header values. The ETag header is similar to a change key. The value is a string that represents the last time the photo was updated. The ETag remains the same for the user photo until the photo is changed. You can send this ETag value to the server in the HTTPS GET request in an If-None-Match header. If the photo hasn't changed since the last request, the server will respond with an HTTP 304 response that indicates as such. This means that you can use the user photo that you previously requested and saved rather than processing a new one.

Get a contact user photo by using EWS Managed API

Your application can use the EWS Managed API to retrieve photos for contacts, if the contact is stored in a contact folder in the user's mailbox. To do this, first, find the ItemId for the contact you want use. Then, after you bind to that contact, load it to the attachments collection. If the contact has a photo, the photo will be one of the attachments. Loop through the attachments collection, checking the value of the IsContactPhoto property. When you find the contact photo, you can save it to your local computer, and your application can access it.

The following example shows this process. This example assumes that service is a valid ExchangeService object and that the user has been authenticated to an Exchange server.

private static void GetContactPhoto(ExchangeService service, string ItemId)
{
   // Bind to an existing contact by using the ItemId passed into this function.
   Contact contact = Contact.Bind(service, ItemId);
   // Load the contact to get access to the collection of attachments.
   contact.Load(new PropertySet(ContactSchema.Attachments));
   // Loop through the attachments looking for a contact photo.
   foreach (Attachment attachment in contact.Attachments)
   {
      if ((attachment as FileAttachment).IsContactPhoto)
      {
         // Load the attachment to access the content.
         attachment.Load();
      }
   }
   FileAttachment photo = contact.GetContactPictureAttachment();
   // Create a file stream and save the contact photo to your computer.
   using (FileStream file = new FileStream(photo.Name, FileMode.Create, System.IO.FileAccess.Write))
   {
      photo.Load(file);
   }
}

Get a user photo by using EWS

If you're getting a user photo from AD DS, you can use the GetUserPhoto operation (if you know the email address) or the ResolveNames operation (if you don't know the email address). If you're getting a user photo from a contacts folder in the mailbox, use the GetItem operation followed by the GetAttachment operation. In either case, the photo is returned as a Base64-encoded string in the XML response.

Get a mailbox user photo by using the GetUserPhoto operation

Using the GetUserPhoto operation is straightforward. In the XML request, specify the email address of the user, and the size of the photo to return (in the SizeRequested element). The following XML request example shows how to get a photo for Sadie Daniels that's 360 pixels wide by 360 pixels high.

<?xml version="1.0" encoding="utf-8" ?>
<soap:Envelope xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
               xmlns:xsd="http://www.w3.org/2001/XMLSchema"
               xmlns:soap="https://schemas.xmlsoap.org/soap/envelope/"
               xmlns:t="https://schemas.microsoft.com/exchange/services/2006/types"
               xmlns:m="https://schemas.microsoft.com/exchange/services/2006/messages">
   <soap:Header>
      <t:RequestServerVersion Version="Exchange2013 "/>
   </soap:Header>
   <soap:Body>
      <m:GetUserPhoto>
         <m:Email>sadie@contoso.com</m:Email>
         <m:SizeRequested>HR360x360</m:SizeRequested>
      </m:GetUserPhoto>
   </soap:Body>
</soap:Envelope>

The following is the XML response. The Base64-encoded photo is contained in the PictureData element (the content has been shortened for readability).

<?xml version="1.0" encoding="utf-8"?>
<s:Envelope xmlns:s="https://schemas.xmlsoap.org/soap/envelope/">
  <s:Body xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" 
         xmlns:xsd="http://www.w3.org/2001/XMLSchema">
    <GetUserPhotoResponse ResponseClass="Success" 
         xmlns="https://schemas.microsoft.com/exchange/services/2006/messages">
      <ResponseCode>NoError</ResponseCode>
      <HasChanged>true</HasChanged>
      <PictureData>/9j/4AAQSkZJRgABAQEAYABgAAD/2wBDAAg... wATRRRSuB//2Q==</PictureData>
    </GetUserPhotoResponse>
  </s:Body>
</s:Envelope>

Get a mailbox user photo by using the ResolveNames operation

If you don't know the email address of the user for whom you are getting a photo, you can use the ResolveNames operation to get candidates for a possible match. If you specify "AllProperties" for the ContactDataShape attribute of the ResolveNames element, a lot of data, including user photos, will be returned for each candidate. The following example shows the XML request to resolve the name "Sadie" and return all the properties for each candidate.

<?xml version="1.0" encoding="utf-8"?>
<soap:Envelope xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
               xmlns:xsd="http://www.w3.org/2001/XMLSchema"
xmlns:m="https://schemas.microsoft.com/exchange/services/2006/messages"
               xmlns:soap="https://schemas.xmlsoap.org/soap/envelope/"
               xmlns:t="https://schemas.microsoft.com/exchange/services/2006/types">
<soap:Header>
    <t:RequestServerVersion Version="Exchange2013" />
  </soap:Header>  
<soap:Body>
  <m:ResolveNames ReturnFullContactData="true" ContactDataShape="AllProperties">
      <m:UnresolvedEntry>sadie</m:UnresolvedEntry>
    </m:ResolveNames>
  </soap:Body>
</soap:Envelope>

A lot of data will be returned in the response. The following example shows only the data that is relevant to the user photo. The Photo element contains the Base64-encoded user photo (the content has been shortened for readability).

<?xml version="1.0" encoding="utf-8"?>
<s:Envelope xmlns:s="https://schemas.xmlsoap.org/soap/envelope/">
  <s:Body xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" 
         xmlns:xsd="http://www.w3.org/2001/XMLSchema">
    <m:ResolveNamesResponse xmlns:m="https://schemas.microsoft.com/exchange/services/2006/messages" 
         xmlns:t="https://schemas.microsoft.com/exchange/services/2006/types">
      <m:ResponseMessages>
        <m:ResolveNamesResponseMessage ResponseClass="Success">
          <m:ResponseCode>NoError</m:ResponseCode>
          <m:ResolutionSet TotalItemsInView="1" IncludesLastItemInRange="true">
            <t:Resolution>
              <t:Mailbox>
                <t:Name>Sadie Daniels</t:Name>
                <t:EmailAddress>sadie@contoso.com</t:EmailAddress>
                <t:RoutingType>SMTP</t:RoutingType>
                <t:MailboxType>Mailbox</t:MailboxType>
              </t:Mailbox>
              <t:Contact>
                <t:DisplayName>Sadie Daniels</t:DisplayName>
                <t:GivenName>Sadie</t:GivenName>
                <t:Initials/>
                <t:CompanyName>CONTOSO</t:CompanyName>
......
                <t:Photo>/9j/4AAQSkZJRgABAQE...qKKKAP/2Q==</t:Photo>
......
              </t:Contact>
            </t:Resolution>
          </m:ResolutionSet>
        </m:ResolveNamesResponseMessage>
      </m:ResponseMessages>
    </m:ResolveNamesResponse>
  </s:Body>
</s:Envelope>

Get a contact user photo by using the GetAttachment operation

You can use EWS to get photos from contacts stored in your mailbox. First, you use the GetItem operation to return all properties so you can look for photos. The following example shows an XML request to get a contact item. The item ID has been shortened for readability.

<?xml version="1.0" encoding="utf-8"?>
<soap:Envelope xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
               xmlns:xsd="http://www.w3.org/2001/XMLSchema"
               xmlns:soap="https://schemas.xmlsoap.org/soap/envelope/"
               xmlns:t="https://schemas.microsoft.com/exchange/services/2006/types">
  <soap:Body>
    <GetItem xmlns='https://schemas.microsoft.com/exchange/services/2006/messages'>
      <ItemShape>
        <t:BaseShape>AllProperties</t:BaseShape>
      </ItemShape>
      <ItemIds>
        <t:ItemId Id="AAAAGECXAAA=" ChangeKey="EQAAABYAAAD2WuN+TpqwSrNP9JCCMKC0AABLzXRv"/>
      </ItemIds>
    </GetItem>
  </soap:Body>
</soap:Envelope>

Look for the HasPicture element to verify that the contact has an associated photo. Then look through the collection of attachments for one that has a value of true for the IsContactPhoto element. The following response example shows only the relevant data. The ID values are shortened for readability.

<?xml version="1.0" encoding="utf-8"?>
<s:Envelope xmlns:s="https://schemas.xmlsoap.org/soap/envelope/">
  <s:Body xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" 
         xmlns:xsd="http://www.w3.org/2001/XMLSchema">
    <m:GetItemResponse xmlns:m="https://schemas.microsoft.com/exchange/services/2006/messages" 
         xmlns:t="https://schemas.microsoft.com/exchange/services/2006/types">
      <m:ResponseMessages>
        <m:GetItemResponseMessage ResponseClass="Success">
          <m:ResponseCode>NoError</m:ResponseCode>
          <m:Items>
            <t:Contact>
              <t:ItemId Id="AAAAGECXAAA=" ChangeKey="EQAAABYAAAD2WuN+TpqwSrNP9JCCMKC0AABLzXRv"/>
              <t:ParentFolderId Id="nIxIAAA=" ChangeKey="AQAAAA=="/>
              <t:ItemClass>IPM.Contact</t:ItemClass>
              <t:Subject>Hope Gross</t:Subject>
              <t:Sensitivity>Normal</t:Sensitivity>
......
              <t:Attachments>
                <t:FileAttachment>
                  <t:AttachmentId Id="1LGlhgpgoA="/>
                  <t:Name>ContactPicture.jpg</t:Name>
                  <t:Size>6260</t:Size>
                  <t:LastModifiedTime>2011-03-09T16:55:55</t:LastModifiedTime>
                  <t:IsInline>false</t:IsInline>
                  <t:IsContactPhoto>true</t:IsContactPhoto>
                </t:FileAttachment>
              </t:Attachments>
......
              <t:HasPicture>true</t:HasPicture>
            </t:Contact>
          </m:Items>
        </m:GetItemResponseMessage>
      </m:ResponseMessages>
    </m:GetItemResponse>
  </s:Body>
</s:Envelope>

Next, use the GetAttachment operation with the AttachmentId to request the attachment that has the contact photo. The following example shows the XML request to get the attachment. The ID is shortened for readability.

<?xml version="1.0" encoding="utf-8"?>
<soap:Envelope xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:xsd="http://www.w3.org/2001/XMLSchema"
xmlns:soap="https://schemas.xmlsoap.org/soap/envelope/"
xmlns:t="https://schemas.microsoft.com/exchange/services/2006/types">
  <soap:Body>
    <GetAttachment xmlns="https://schemas.microsoft.com/exchange/services/2006/messages"
    xmlns:t="https://schemas.microsoft.com/exchange/services/2006/types">
      <AttachmentShape/>
      <AttachmentIds>
         <t:AttachmentId Id="1LGlhgpgoA="/>
      </AttachmentIds>
    </GetAttachment>
  </soap:Body>
</soap:Envelope>

The following example shows the XML response with the information about the attachment you requested. The Content element contains the Base64-encoded string for the user photo, shortened in this example for readability.

<?xml version="1.0" encoding="utf-8"?>
<s:Envelope xmlns:s="https://schemas.xmlsoap.org/soap/envelope/">
  <s:Body xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" 
         xmlns:xsd="http://www.w3.org/2001/XMLSchema">
    <m:GetAttachmentResponse xmlns:m="https://schemas.microsoft.com/exchange/services/2006/messages" 
         xmlns:t="https://schemas.microsoft.com/exchange/services/2006/types">
      <m:ResponseMessages>
        <m:GetAttachmentResponseMessage ResponseClass="Success">
          <m:ResponseCode>NoError</m:ResponseCode>
          <m:Attachments>
            <t:FileAttachment>
              <t:AttachmentId Id="+KsDBEr1LGlhgpgoA="/>
              <t:Name>ContactPicture.jpg</t:Name>
              <t:Content>/9j/4AAQSkZJRgABAQEAYABgAAD/2wBDAAg...D//2Q==</t:Content>
            </t:FileAttachment>
          </m:Attachments>
        </m:GetAttachmentResponseMessage>
      </m:ResponseMessages>
    </m:GetAttachmentResponse>
  </s:Body>
</s:Envelope>

Decode a Base64-encoded string

Regardless of the operation you use to get a user photo, you'll need to decode that string so you can use it in your application. The following example shows how to decode the string, and then save it to your local computer so you application can access it later.

// Convert the encoded string into a byte array.
byte[] data = System.Convert.FromBase64String(Photo);
// Create a memory stream to read the data.
MemoryStream ms = new MemoryStream(data);
// Save the data on your local computer as a JPG image.
using (FileStream file = new FileStream(ContactName + ".jpg", FileMode.Create, System.IO.FileAccess.Write))
{
   byte[] bytes = new byte[ms.Length];
   ms.Read(bytes, 0, (int)ms.Length);
   file.Write(bytes, 0, bytes.Length);
   ms.Close();
}

See also