在 Exchange 中使用 EWS 获取用户照片

了解如何使用 Exchange 中的 EWS 托管 API 或 EWS 获取与邮箱或联系人关联的用户照片。

把脸贴在名字上真好。 如果用户希望将姓名写在人脸上,应用程序可以从 Exchange 请求一张表示电子邮件帐户的图像(通常是照片)。 您可以获取邮箱的 Exchange 服务器上存储的用户照片,也可以从邮箱中存储的联系人中获取联系人照片。

可以使用多种不同的技术从邮箱获取照片,或Active Directory 域服务 (AD DS) 。 获取照片的最佳方式取决于要从中获取照片的联系人类型。

表 1. 用于根据联系人类型获取用户照片的技术

联系人类型 要使用的技术
邮箱用户照片
使用 REST 获取邮箱用户照片

使用 EWS 获取用户照片
联系人用户照片
使用 EWS 托管 API 获取联系人用户照片

使用 EWS 获取用户照片

使用 REST 获取邮箱用户照片

可以使用标准 HTTPS GET 请求从 Exchange 服务器请求用户照片。 在请求中,指定图像的电子邮件帐户地址和大小代码,如以下示例所示。

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

使用自动发现服务 GetUserSettings 操作检索 ExternalEwsUrl 设置,该设置包含 Exchange Web Services (EWS) 终结点的 URL 以及返回用户照片的 Exchange.asmx HTTP 处理程序的位置。

每个大小代码指示图像的高度和宽度(以像素为单位)。 例如,大小代码 HR48x48 返回高 48 像素 x 48 像素宽的图像。 大小代码参数的可能值与 SizeRequested 元素的可能值相同。 如果请求指定的大小不可用,则将返回最大的可用照片。 如果 Exchange 服务器上未存储任何照片,则会返回帐户 AD DS 中存储的缩略图图像。

注意

HR48x48 大小代码始终返回 AD DS 缩略图图像(如果可用)。

以下示例演示如何使用 GET 请求检索 Sadie 的用户照片并将其保存到本地计算机。

// 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");
}

请求将返回 HTTP 响应。

表 2. GetUserPhoto 请求的响应代码

响应代码 说明
200
图像可用于指定的电子邮件帐户,二进制图像包含在响应中。
304
自上次 将 ETag 返回到应用程序以来,映像未更改。
404
没有可用于指定电子邮件帐户的映像。

缓存用户照片

Exchange 返回内容类型为 image/jpeg 的数据,以及标头值的集合。 ETag 标头类似于更改键。 该值是一个字符串,表示上次更新照片的时间。 在更改照片之前,用户照片的 ETag 保持不变。 可以在 If-None-Match 标头中的 HTTPS GET 请求中将此 ETag 值发送到服务器。 如果照片自上次请求以来一直没有更改,则服务器将使用 HTTP 304 响应进行响应,以指示此类响应。 这意味着你可以使用之前请求和保存的用户照片,而不是处理新照片。

使用 EWS 托管 API 获取联系人用户照片

如果联系人存储在用户邮箱中的联系人文件夹中,则应用程序可以使用 EWS 托管 API 检索联系人的照片。 为此,请先找到要使用的联系人的 ItemId 。 然后,在绑定到该联系人后,将其加载到附件集合。 如果联系人有照片,则照片将是附件之一。 循环访问附件集合,检查 IsContactPhoto 属性的值。 找到联系人照片后,可以将其保存到本地计算机,应用程序可以访问它。

以下示例演示此过程。 此示例假定 service 是有效的 ExchangeService 对象,且用户已通过 Exchange 服务器的身份验证。

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);
   }
}

使用 EWS 获取用户照片

如果要从 AD DS 获取用户照片,则可以使用 GetUserPhoto 操作 ((如果知道电子邮件地址) )或 ResolveNames 操作 ((如果不知道电子邮件地址) )。 如果要从邮箱中的联系人文件夹获取用户照片,请使用 GetItem 操作,然后使用 GetAttachment 操作。 在任一情况下,照片将在 XML 响应中作为 Base64 编码字符串返回。

使用 GetUserPhoto 操作获取邮箱用户照片

使用 GetUserPhoto 操作非常简单。 在 XML 请求中,在 SizeRequested 元素) 中指定要返回 (的用户电子邮件地址和照片的大小。 下面的 XML 请求示例演示如何为 Sadie Daniels 获取 360 像素宽 x 360 像素高的照片。

<?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="http://schemas.microsoft.com/exchange/services/2006/types"
               xmlns:m="http://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>

下面是 XML 响应。 Base64 编码的照片包含在 PictureData 元素中, (内容已缩短,以便) 可读性。

<?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="http://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>

使用 ResolveNames 操作获取邮箱用户照片

如果不知道要为其获取照片的用户的电子邮件地址,可以使用 ResolveNames 操作 获取可能的匹配项。 如果为 ResolveNames 元素的 ContactDataShape 属性指定“AllProperties”,则会为每个候选项返回大量数据,包括用户照片。 以下示例演示解析名称“Sadie”并返回每个候选项的所有属性的 XML 请求。

<?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="http://schemas.microsoft.com/exchange/services/2006/messages"
               xmlns:soap="https://schemas.xmlsoap.org/soap/envelope/"
               xmlns:t="http://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>

响应中将返回大量数据。 以下示例仅显示与用户照片相关的数据。 Photo 元素包含 Base64 编码的用户照片, (内容已缩短,以便) 可读性。

<?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="http://schemas.microsoft.com/exchange/services/2006/messages" 
         xmlns:t="http://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>

使用 GetAttachment 操作获取联系人用户照片

可以使用 EWS 从邮箱中存储的联系人获取照片。 首先,使用 GetItem 操作返回所有属性,以便查找照片。 以下示例演示获取联系人项的 XML 请求。 为了提高可读性,项目 ID 已缩短。

<?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="http://schemas.microsoft.com/exchange/services/2006/types">
  <soap:Body>
    <GetItem xmlns='http://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>

查找 HasPicture 元素以验证联系人是否具有关联的照片。 然后浏览附件集合,了解 IsContactPhoto 元素的值为 true 的附件。 以下响应示例仅显示相关数据。 为了提高可读性,将缩短 ID 值。

<?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="http://schemas.microsoft.com/exchange/services/2006/messages" 
         xmlns:t="http://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>

接下来,将 GetAttachment 操作与 AttachmentId 配合使用,请求具有联系人照片的附件。 以下示例演示获取附件的 XML 请求。 为了提高可读性,ID 会缩短。

<?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="http://schemas.microsoft.com/exchange/services/2006/types">
  <soap:Body>
    <GetAttachment xmlns="http://schemas.microsoft.com/exchange/services/2006/messages"
    xmlns:t="http://schemas.microsoft.com/exchange/services/2006/types">
      <AttachmentShape/>
      <AttachmentIds>
         <t:AttachmentId Id="1LGlhgpgoA="/>
      </AttachmentIds>
    </GetAttachment>
  </soap:Body>
</soap:Envelope>

以下示例显示包含所请求附件相关信息的 XML 响应。 Content 元素包含用户照片的 Base64 编码字符串,为了提高可读性,在本示例中进行了缩短。

<?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="http://schemas.microsoft.com/exchange/services/2006/messages" 
         xmlns:t="http://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>

解码 Base64 编码的字符串

无论使用何种操作获取用户照片,都需要解码该字符串,以便在应用程序中使用它。 以下示例演示如何解码字符串,然后将其保存到本地计算机,以便应用程序稍后可以访问它。

// 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();
}

另请参阅