通过在 Exchange 中使用 EWS 以代理身份访问日历

了解如何通过使用 EWS 托管 API 或在 Exchange 中的 EWS 以代理身份访问日历。

可以使用 EWS 托管 API 或 EWS 向用户代理授予对邮箱所有者日历文件夹的访问权限。 然后,代理可以代表邮箱所有者创建会议请求、创建约会、响应会议请求,并根据其权限从邮箱所有者的日历文件夹中检索、更新和删除会议。

作为代理人,可以使用相同的方法和操作来访问邮箱所有者的日历文件夹,就像你用来访问你自己的日历文件夹一样。 主要区别在于,必须使用 显式访问 来查找或创建日历项或日历子文件夹,然后在标识项目 ID 或文件夹 ID 后,可以使用 隐式访问 来获取、更新或删除该项。

表 1. 用于以代理人身份访问日历的 EWS 托管 API 方法和 EWS 操作

若要… 使用此 EWS 托管 API 方法… 使用此 EWS 操作…
以代理身份创建会议或约会
Appointment.Save,其中 FolderId 参数向邮箱所有者日历文件夹提供 显式访问
CreateItem,其中 邮箱 元素指定邮箱所有者的 EmailAddress
以代理身份创建多个会议或约会
ExchangeService.CreateItems,其中 FolderId 参数提供对邮箱所有者日历文件夹的 显式访问
CreateItem,其中 邮箱 元素指定邮箱所有者的 EmailAddress
以代理身份搜索或查找约会或会议
ExchangeService.FindItems,其中 FolderId 参数提供对邮箱所有者日历文件夹的 显式访问
FindItem,其中 邮箱 元素指定邮箱所有者的 EmailAddress
以代理身份获取约会或会议
Appointment.Bind
GetItem
以代理身份更新约会或会议
Appointment.Bind,然后是 Appointment.Update
GetItem,然后是 UpdateItem
以代理身份删除约会或会议
Appointment.Bind,然后是 Appointment.Delete
GetItem,然后是 DeleteItem

注意

在本文的代码示例中, primary@contoso.com 是邮箱所有者。

先决条件任务

在用户可以以代理身份访问邮箱所有者日历文件夹之前,必须将该用户 添加为具有邮箱所有者日历文件夹权限的代理

代理人必须拥有附加在其帐户上的邮箱,才能更新邮箱所有者日历。

如果代理仅需处理会议请求和答复,则可以将委托添加到日历文件夹中, 并使用默认 MeetingRequestsDeliveryScope.DelegatesAndSendInformationToMe EWS 托管 API 枚举值或 DelegatesAndSendInformationToMeDeliverMeetingRequests EWS 元素值,用于向代理发送请求,并向邮箱所有者委派发送信息性邮件。 然后,不需要向代理授予对邮箱所有者收件箱文件夹的访问权限。

通过使用 EWS 托管 API 以代理身份创建会议或约会

EWS 托管 API 可以使你使用委托用户的服务对象为邮箱所有者创建日历项。 此示例演示了如何使用 保存 方法创建会议并向与会者发送会议请求。

此示例假定 服务 是一个有效的 ExchangeService 对象,并且已授予该代理邮箱所有者日历文件夹的相应权限。

private static void DelegateAccessCreateMeeting(ExchangeService service)
{
    Appointment meeting = new Appointment(service);
    // Set the properties on the meeting object to create the meeting.
    meeting.Subject = "Team building exercise";
    meeting.Body = "Let's learn to really work as a team and then have lunch!";
    meeting.Start = DateTime.Now.AddDays(2);
    meeting.End = meeting.Start.AddHours(4);
    meeting.Location = "Conference Room 12";
    meeting.RequiredAttendees.Add("sadie@contoso.com");
    meeting.ReminderMinutesBeforeStart = 60;
    // Save the meeting to the Calendar folder for 
    // the mailbox owner and send the meeting request.
    // This method call results in a CreateItem call to EWS.
    meeting.Save(new FolderId(WellKnownFolderName.Calendar, 
        "primary@contoso.com"), 
        SendInvitationsMode.SendToAllAndSaveCopy);
    // Verify that the meeting was created.
    Item item = Item.Bind(service, meeting.Id, new PropertySet(ItemSchema.Subject));
    Console.WriteLine("\nMeeting created: " + item.Subject + "\n");
}

请注意,保存项目时,保存 方法调用必须标识邮箱所有者的日历文件夹。 如果未指定邮箱所有者的日历文件夹,则会将会议请求保存到代理的日历中,而不是邮箱所有者的日历文件夹中。 可以通过两种方式在 保存 方法调用中包含邮箱所有者的日历文件夹。 建议使用 WellKnownFolderName 和邮箱所有者的 SMTP 地址实例化 FolderId 对象的新实例。

meeting.Save(new FolderId(WellKnownFolderName.Calendar,
    "primary@contoso.com"), SendInvitationsMode.SendToAllAndSaveCopy);

然而,也可以先 绑定 到日历文件夹,然后在 保存 方法调用中使用该文件夹的 ID。 但是,请注意,这将产生额外的 EWS 调用。

    // Identify the mailbox owner's SMTP address
    // and bind to their Calendar folder.
    Mailbox primary = new Mailbox("primary@contoso.com"); 
    Folder primaryCalendar = Folder.Bind(service, 
        new FolderId(WellKnownFolderName.Calendar, primary)); 
…
    // Save the meeting to the Calendar folder for the mailbox owner and send the meeting request.
    meeting.Save(primaryCalendar.Id, 
        SendInvitationsMode.SendToAllAndSaveCopy);

通过使用 EWS 以代理身份创建会议或约会

EWS 可以使你使用委托用户的服务对象为邮箱所有者创建日历项。 此示例演示了如何使用 CreateItem 操作创建会议并向与会者发送会议请求。

当你使用 保存 方法 以代理身份创建会议或约会 时,这也是 EWS 托管 API 发送的 XML 请求。

为了简洁起见,已从以下示例中删除 SOAP 标头。

<?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:Body>
    <m:CreateItem SendMeetingInvitations="SendToAllAndSaveCopy">
      <m:SavedItemFolderId>
        <t:DistinguishedFolderId Id="calendar">
          <t:Mailbox>
            <t:EmailAddress>primary@contoso.com</t:EmailAddress>
          </t:Mailbox>
        </t:DistinguishedFolderId>
      </m:SavedItemFolderId>
      <m:Items>
        <t:CalendarItem>
          <t:Subject>Team building exercise</t:Subject>
          <t:Body BodyType="HTML">Let's learn to really work as a 
              team and then have lunch!</t:Body>
          <t:ReminderMinutesBeforeStart>60</t:ReminderMinutesBeforeStart>
          <t:Start>2014-03-09T23:26:33.756-05:00</t:Start>
          <t:End>2014-03-10T03:26:33.756-05:00</t:End>
          <t:Location>Conference Room 12</t:Location>
          <t:RequiredAttendees>
            <t:Attendee>
              <t:Mailbox>
                <t:EmailAddress>sadie@contoso.com</t:EmailAddress>
              </t:Mailbox>
            </t:Attendee>
          </t:RequiredAttendees>
        </t:CalendarItem>
      </m:Items>
    </m:CreateItem>
  </soap:Body>
</soap:Envelope>

服务器使用 CreateItemResponse 消息响应 CreateItem 请求,该消息包含 NoErrorResponseCode 元素值,指示已成功创建会议。 响应还包含新创建的会议的项 ID。

通过使用 EWS 托管 API 以代理身份搜索会议或约会

若要搜索会议,必须使用 ExchangeService.FindItems 方法之一,其中包括 FolderId 参数,以便可以指定邮箱所有者的日历文件夹。

static void DelegateAccessSearchWithFilter
    (ExchangeService service, SearchFilter filter)
{
    // Limit the result set to 10 items.
    ItemView view = new ItemView(10);
    view.PropertySet = new PropertySet(ItemSchema.Subject,
                                       ItemSchema.DateTimeReceived,
                                       EmailMessageSchema.IsRead);
    // Item searches do not support deep traversal.
    view.Traversal = ItemTraversal.Shallow;
    // Define the sort order.
    view.OrderBy.Add(ItemSchema.DateTimeReceived, SortDirection.Descending);
    try
    {
        // Call FindItems to find matching calendar items. 
        // The FindItems parameters must denote the mailbox owner,
        // mailbox, and Calendar folder.
        // This method call results in a FindItem call to EWS.
        FindItemsResults<Item> results = service.FindItems(
        new FolderId(WellKnownFolderName.Calendar, 
            "primary@contoso.com"), 
            filter, 
            view);
        foreach (Item item in results.Items)
        {
            Console.WriteLine("Subject: {0}", item.Subject);
            Console.WriteLine("Id: {0}", item.Id.ToString());
        }
    }
    catch (Exception ex)
    {
        Console.WriteLine("Exception while 
            enumerating results: {0}", ex.Message);
    }
}

FindItems 调用返回带有 ID 的响应后,可以通过使用 ID 和 隐式访问 获取、更新或删除该会议,并且无需指定邮箱所有者的 SMTP 地址。

通过使用 EWS 以代理身份搜索会议或约会

EWS 使你能够使用代理用户的服务对象来搜索符合一组搜索条件的约会和会议。 此示例演示了如何使用 FindItem 操作在邮箱所有者的日历文件夹中查找主题中包含“创建”一词的会议。

当你使用 FindItem 方法 以代理身份搜索会议或约会 时,这也是 EWS 托管 API 发送的 XML 请求。

<?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="Exchange2007_SP1" />
  </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:AdditionalProperties>
      </m:ItemShape>
      <m:IndexedPageItemView MaxEntriesReturned="10"
                             Offset="0"
                             BasePoint="Beginning" />
      <m:Restriction>
        <t:Contains ContainmentMode="Substring"
                    ContainmentComparison="IgnoreCase">
          <t:FieldURI FieldURI="item:Subject" />
          <t:Constant Value="building" />
        </t:Contains>
      </m:Restriction>
      <m:SortOrder>
        <t:FieldOrder Order="Descending">
          <t:FieldURI FieldURI="item:DateTimeReceived" />
        </t:FieldOrder>
      </m:SortOrder>
      <m:ParentFolderIds>
        <t:DistinguishedFolderId Id="calendar">
          <t:Mailbox>
            <t:EmailAddress>primary@contoso.com</t:EmailAddress>
          </t:Mailbox>
        </t:DistinguishedFolderId>
      </m:ParentFolderIds>
    </m:FindItem>
  </soap:Body>
</soap:Envelope>

服务器使用 FindItemResponse 消息来响应 FindItem 请求,其中包含 NoErrorResponseCode 元素值,指示已成功完成搜索。 响应包含满足搜索条件的任何约会或会议的 CalendarItem。 在这种情况下,仅发现一个会议。

为了便于阅读,已缩短 ItemId 元素的值。

<?xml version="1.0" encoding="utf-8"?>
<s:Envelope xmlns:s="https://schemas.xmlsoap.org/soap/envelope/">
  <s:Header>
    <h:ServerVersionInfo MajorVersion="15"
                         MinorVersion="0"
                         MajorBuildNumber="893"
                         MinorBuildNumber="10"
                         Version="V2_10"
                         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>
    <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="1"
                        TotalItemsInView="1"
                        IncludesLastItemInRange="true">
            <t:Items>
              <t:CalendarItem>
                <t:ItemId Id="IJpUAAA="
                          ChangeKey="DwAAABYAAADOilbYa8KaT7ZgMoTz2P+hAAAAIKhS" />
                <t:Subject>Team building exercise</t:Subject>
                <t:DateTimeReceived>2014-03-04T21:27:22Z</t:DateTimeReceived>
              </t:CalendarItem>
            </t:Items>
          </m:RootFolder>
        </m:FindItemResponseMessage>
      </m:ResponseMessages>
    </m:FindItemResponse>
  </s:Body>
</s:Envelope>

现在,你已拥有满足条件的会议的 ItemId,可以使用 ItemId隐式访问 以获取、更新或删除该会议 — 并且无需指定邮箱所有者的 SMTP 地址。

通过使用 EWS 托管 API 以代理身份获取、更新或删除日历项

可以使用 EWS 托管 API 以获取、更新或删除会议或约会,其方式与在不使用委派访问权限时执行这些操作的方式相同。 唯一的区别是服务对象适用于代理用户。 绑定 方法调用中包含的项目 ID 唯一地标识了邮箱所有者日历文件夹中邮箱存储里的项。

表 2. 用于以代理人身份处理约会和会议的 EWS 托管 API 方法

任务 EWS 托管的 API 方法 代码示例
获取约会或会议
绑定
使用 EWS 托管 API 获取项
更新约会或会议
绑定,然后是 更新
使用 EWS 托管 API 更新文件夹
删除约会或会议
绑定,然后是 删除
使用 EWS 托管 API 删除会议

通过使用 EWS 以代理身份获取、更新或删除日历项

可以使用 EWS 以获取、更新或删除会议或约会,其方式与在不使用委派访问权限时执行这些操作的方式相同。 唯一的区别是服务对象适用于代理用户。 GetItem 方法调用中包含的项目 ID 唯一地标识了邮箱所有者日历文件夹中邮箱存储里的项。

表 3. 用于以代理人身份处理约会和会议的 EWS 操作

任务 EWS 操作 代码示例
获取约会或会议
GetItem
使用 EWS 获取项
更新约会或会议
GetItem,然后是 UpdateItem
使用 EWS 更新文件夹
删除约会或会议
GetItem,然后是 DeleteItem
使用 EWS 删除会议

另请参阅