在 Exchange 中使用 EWS 处理隐藏文件夹

了解如何在 Exchange 中使用 EWS 托管 API 或 EWS 隐藏文件夹并查找隐藏的文件夹。

除了一个例外,Exchange 邮箱根目录中的文件夹 (非 IPM 子树) 对用户隐藏。 相反, MsgFolderRoot 中的所有文件夹 (IPM 子树) 对用户可见。 那么,如何在 MsgFolderRoot 下隐藏文件夹? 这不是那么棘手 - 它归结为一个属性, PidTagAttributeHidden (0x10F4000B) 扩展属性。 当此属性设置为 true 时,Outlook 或使用 属性确定文件夹可见性的另一个客户端将从用户视图中隐藏该文件夹。 由于这是一个扩展属性,因此使用起来比平均文件夹属性更复杂,因此本文将指导你完成主要方案。

表 1. 用于处理隐藏文件夹的 EWS 托管 API 方法和 EWS 操作

任务 EWS 托管的 API 方法 EWS 操作
隐藏文件夹
Folder.Bind 后跟 Folder.Update
GetFolder 后跟 UpdateFolder
查找隐藏的文件夹
FindFolders
FindFolder

你想知道一个例外是什么 — 即根目录中的哪个文件夹对用户可见? 它是 Finder 文件夹 (也称为 SearchFoldersWellKnownFolder 枚举值,或 searchfoldersDistinguishedFolderId 元素值) ,其中包含用户的搜索文件夹。 在 Finder 文件夹中创建的搜索文件夹对 Outlook 用户可见。 如果需要创建对用户不可见的搜索文件夹,请将其移动到根文件夹下以将其隐藏。 与其他文件夹不同,将 PidTagAttributeHidden 属性设置为 true 不会隐藏 Finder 文件夹中的搜索文件夹。

使用 EWS 托管 API 隐藏文件夹

可以通过将 PidTagAttributeHidden 扩展属性更改为 true使现有文件夹成为隐藏文件夹。 首先, 为 属性创建扩展属性定义。 接下来,使用 Bind 方法访问 文件夹,然后将 PidTagAttributeHidden 属性的值更新为 true,并使用 Update 方法保存更改。

此示例假定 服务 是邮箱所有者的有效 ExchangeService 对象,用户已向 Exchange 服务器进行身份验证,并且 folderId 是标识要隐藏的文件夹的有效 Folder.Id

private static void MakeHidden(FolderId folderId, ExchangeService service)
{
    // Create an extended property definition for the PidTagAttributeHidden property.
    ExtendedPropertyDefinition isHiddenProp = new ExtendedPropertyDefinition(0x10f4, MapiPropertyType.Boolean);
    PropertySet propSet = new PropertySet(isHiddenProp);
    // Bind to a folder and retrieve the PidTagAttributeHidden property.
    Folder folder = Folder.Bind(service, folderId, propSet);
    // Set the PidTagAttributeHidden property to true.
    folder.SetExtendedProperty(isHiddenProp, true);
    // Save the changes.
    folder.Update();
}

使用 EWS 隐藏文件夹

可以通过将 PidTagAttributeHidden 扩展属性更改为 true,使用 EWS 将现有文件夹设置为隐藏文件夹。 首先,使用 GetFolder 操作访问文件夹,然后通过包括 ExtendedFieldURI 元素并将 PropertyTag 值设置为 4340 并将 PropertyType 值设置为 Boolean 来检索 PidTagAttributeHidden 属性。

这也是 EWS 托管 API 在将文件夹设置为隐藏文件夹之前使用 Bind 方法获取文件夹时发送的 XML 请求。

为提高可读性, 将缩短 FolderId 值。

<?xml version="1.0" encoding="utf-8"?>
<soap:Envelope xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
               xmlns:m="http://schemas.microsoft.com/exchange/services/2006/messages"
               xmlns:t="http://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:GetFolder>
      <m:FolderShape>
        <t:BaseShape>IdOnly</t:BaseShape>
        <t:AdditionalProperties>
          <t:ExtendedFieldURI PropertyTag="4340"
                              PropertyType="Boolean" />
        </t:AdditionalProperties>
      </m:FolderShape>
      <m:FolderIds>
        <t:FolderId Id="IQywAAAA==" />
      </m:FolderIds>
    </m:GetFolder>
  </soap:Body>
</soap:Envelope>

服务器使用 GetFolderResponse 消息响应 GetFolder 请求,该邮件包含 NoError的 ResponseCode 元素值,指示已成功检索文件夹。 响应还包括 ExtendedProperty的值。 在此示例中, 设置为 false,这意味着文件夹当前未隐藏。

<?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="898"
                         MinorBuildNumber="23"
                         Version="V2_10"
                         xmlns:h="http://schemas.microsoft.com/exchange/services/2006/types"
                         xmlns="http://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:GetFolderResponse xmlns:m="http://schemas.microsoft.com/exchange/services/2006/messages"
                         xmlns:t="http://schemas.microsoft.com/exchange/services/2006/types">
      <m:ResponseMessages>
        <m:GetFolderResponseMessage ResponseClass="Success">
          <m:ResponseCode>NoError</m:ResponseCode>
          <m:Folders>
            <t:Folder>
              <t:FolderId Id="IQywAAAA=="
                          ChangeKey="AQAAABYAAAD32nSTjepyT63rYH17n9THAAAAABED" />
              <t:ExtendedProperty>
                <t:ExtendedFieldURI PropertyTag="0x10f4"
                                    PropertyType="Boolean" />
                <t:Value>false</t:Value>
              </t:ExtendedProperty>
            </t:Folder>
          </m:Folders>
        </m:GetFolderResponseMessage>
      </m:ResponseMessages>
    </m:GetFolderResponse>
  </s:Body>
</s:Envelope>

若要将 ExtendedProperty 的值更改为 true,请使用 UpdateFolder 操作。 包括 PidTagAttributeHidden 扩展属性的 ExtendedPropertyExtendedFieldURIValue 元素,并将 Value 元素设置为 true 以隐藏文件夹。

这也是使用 Update 方法更新文件夹以 使其成为隐藏文件夹时 EWS 托管 API 发送的 XML 请求。

<?xml version="1.0" encoding="utf-8"?>
<soap:Envelope xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
               xmlns:m="http://schemas.microsoft.com/exchange/services/2006/messages"
               xmlns:t="http://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:UpdateFolder>
      <m:FolderChanges>
        <t:FolderChange>
          <t:FolderId Id="IQywAAAA=="
                      ChangeKey="AQAAABYAAAD32nSTjepyT63rYH17n9THAAAAABED" />
          <t:Updates>
            <t:SetFolderField>
              <t:ExtendedFieldURI PropertyTag="4340"
                                  PropertyType="Boolean" />
              <t:Folder>
                <t:ExtendedProperty>
                  <t:ExtendedFieldURI PropertyTag="4340"
                                      PropertyType="Boolean" />
                  <t:Value>true</t:Value>
                </t:ExtendedProperty>
              </t:Folder>
            </t:SetFolderField>
          </t:Updates>
        </t:FolderChange>
      </m:FolderChanges>
    </m:UpdateFolder>
  </soap:Body>
</soap:Envelope>

服务器使用 UpdateFolderResponse 消息响应 UpdateFolder 请求,该邮件包含一个 ResponseCode 元素值 NoError,指示文件夹已成功更新,现在已隐藏。

使用 EWS 托管 API 查找所有隐藏的文件夹

可以通过为 PidTagAttributeHidden扩展属性创建扩展属性定义,然后使用 FindFolders 方法查找具有设置为 true的 PidTagAttributeHidden 值的文件夹,从而查找父文件夹下的所有隐藏文件夹。 此示例使用 MsgFolderRoot(也称为信息存储的顶部)或 IPM 子树作为要搜索的父文件夹。

此示例假定 服务 是邮箱所有者的有效 ExchangeService 对象,并且用户已向 Exchange 服务器进行身份验证。

private static void FindHiddenFolders(ExchangeService service)
{
    // Create an extended property definition for the PidTagAttributeHidden property.
    ExtendedPropertyDefinition isHiddenProp = new ExtendedPropertyDefinition(0x10f4, MapiPropertyType.Boolean);
    // Create a folder view to retrieve up to 100 folders and 
    // retrieve only the PidTagAttributeHidden and the display name.
    FolderView folderView = new FolderView(100);
    folderView.PropertySet = new PropertySet(isHiddenProp, FolderSchema.DisplayName);
    // Indicate a Traversal value of Deep, so that all subfolders are retrieved.
    folderView.Traversal = FolderTraversal.Deep;
    // Find all hidden folders under the MsgFolderRoot.
    // This call results in a FindFolder call to EWS.
    FindFoldersResults findFolder = service.FindFolders(WellKnownFolderName.MsgFolderRoot,
            new SearchFilter.IsEqualTo(isHiddenProp, true), folderView);
    // Display the folder ID and display name of each hidden folder.
    foreach (Folder folder in findFolder)
    {
        Console.WriteLine("FolderId: {0}", folder.Id);
        Console.WriteLine("DisplayName: {0}", folder.DisplayName);
        Console.WriteLine("\r\n");
    }
}

使用 EWS 查找所有隐藏的文件夹

可以通过调用 FindFolder 操作并搜索 PidTagAttributeHidden 扩展属性设置为 true 的文件夹,使用 EWS 查找现有文件夹下的所有隐藏文件夹。 为此,请包括一个 IsEqualToRestriction,该限制在 PidTagAttributeHidden 属性的 ExtendedFieldURI 元素 ( PropertyTag 值到 4243,将 PropertyType 值搜索为布尔值) ,如以下请求中所示。 此示例使用 MsgFolderRoot(也称为信息存储的顶部)或 IPM 子树作为要搜索的父文件夹。

这也是使用 FindFolders 方法 查找所有隐藏文件夹时 EWS 托管 API 发送的 XML 请求。

<?xml version="1.0" encoding="utf-8"?>
<soap:Envelope xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
               xmlns:m="http://schemas.microsoft.com/exchange/services/2006/messages"
               xmlns:t="http://schemas.microsoft.com/exchange/services/2006/types"
               xmlns:soap="https://schemas.xmlsoap.org/soap/envelope/">
  <soap:Header>
    <t:RequestServerVersion Version="Exchange2007_SP1" />
    <t:TimeZoneContext>
      <t:TimeZoneDefinition Id="Central Standard Time" />
    </t:TimeZoneContext>
  </soap:Header>
  <soap:Body>
    <m:FindFolder Traversal="Deep">
      <m:FolderShape>
        <t:BaseShape>IdOnly</t:BaseShape>
        <t:AdditionalProperties>
          <t:ExtendedFieldURI PropertyTag="4340"
                              PropertyType="Boolean" />
          <t:FieldURI FieldURI="folder:DisplayName" />
        </t:AdditionalProperties>
      </m:FolderShape>
      <m:IndexedPageFolderView MaxEntriesReturned="100"
                               Offset="0"
                               BasePoint="Beginning" />
      <m:Restriction>
        <t:IsEqualTo>
          <t:ExtendedFieldURI PropertyTag="4340"
                              PropertyType="Boolean" />
          <t:FieldURIOrConstant>
            <t:Constant Value="true" />
          </t:FieldURIOrConstant>
        </t:IsEqualTo>
      </m:Restriction>
      <m:ParentFolderIds>
        <t:DistinguishedFolderId Id="msgfolderroot" />
      </m:ParentFolderIds>
    </m:FindFolder>
  </soap:Body>
</soap:Envelope>

服务器使用 FindFolderResponse 邮件响应 FindFolder 请求,该邮件包含 NoErrorResponseCode 元素值,该值指示文件夹搜索成功,以及根邮件文件夹下的所有隐藏文件夹。

为提高可读性, 将缩短 FolderId 值。

<?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="898"
                         MinorBuildNumber="23"
                         Version="V2_10"
                         xmlns:h="http://schemas.microsoft.com/exchange/services/2006/types"
                         xmlns="http://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:FindFolderResponse xmlns:m="http://schemas.microsoft.com/exchange/services/2006/messages"
                          xmlns:t="http://schemas.microsoft.com/exchange/services/2006/types">
      <m:ResponseMessages>
        <m:FindFolderResponseMessage ResponseClass="Success">
          <m:ResponseCode>NoError</m:ResponseCode>
          <m:RootFolder IndexedPagingOffset="6"
                        TotalItemsInView="6"
                        IncludesLastItemInRange="true">
            <t:Folders>
              <t:ContactsFolder>
                <t:FolderId Id="IBHgAAAA=="
                            ChangeKey="AwAAABYAAAD32nSTjepyT63rYH17n9THAAAAAACz" />
                <t:DisplayName>{06967759-274D-40B2-A3EB-D7F9E73727D7}</t:DisplayName>
                <t:ExtendedProperty>
                  <t:ExtendedFieldURI PropertyTag="0x10f4"
                                      PropertyType="Boolean" />
                  <t:Value>true</t:Value>
                </t:ExtendedProperty>
              </t:ContactsFolder>
              <t:ContactsFolder>
                <t:FolderId Id="IBHwAAAA=="
                            ChangeKey="AwAAABYAAAD32nSTjepyT63rYH17n9THAAAAAAC7" />
                <t:DisplayName>{A9E2BC46-B3A0-4243-B315-60D991004455}</t:DisplayName>
                <t:ExtendedProperty>
                  <t:ExtendedFieldURI PropertyTag="0x10f4"
                                      PropertyType="Boolean" />
                  <t:Value>true</t:Value>
                </t:ExtendedProperty>
              </t:ContactsFolder>
              <t:ContactsFolder>
                <t:FolderId Id="IBIQAAAA=="
                            ChangeKey="AwAAABYAAAD32nSTjepyT63rYH17n9THAAAAAADO" />
                <t:DisplayName>GAL Contacts</t:DisplayName>
                <t:ExtendedProperty>
                  <t:ExtendedFieldURI PropertyTag="0x10f4"
                                      PropertyType="Boolean" />
                  <t:Value>true</t:Value>
                </t:ExtendedProperty>
              </t:ContactsFolder>
              <t:ContactsFolder>
                <t:FolderId Id="IBHQAAAA=="
                            ChangeKey="AwAAABYAAAD32nSTjepyT63rYH17n9THAAAAAACa" />
                <t:DisplayName>Recipient Cache</t:DisplayName>
                <t:ExtendedProperty>
                  <t:ExtendedFieldURI PropertyTag="0x10f4"
                                      PropertyType="Boolean" />
                  <t:Value>true</t:Value>
                </t:ExtendedProperty>
              </t:ContactsFolder>
              <t:Folder>
                <t:FolderId Id="HAAAAA=="
                            ChangeKey="AQAAABYAAAD32nSTjepyT63rYH17n9THAAAAAACS" />
                <t:DisplayName>Conversation Action Settings</t:DisplayName>
                <t:ExtendedProperty>
                  <t:ExtendedFieldURI PropertyTag="0x10f4"
                                      PropertyType="Boolean" />
                  <t:Value>true</t:Value>
                </t:ExtendedProperty>
              </t:Folder>
              <t:Folder>
                <t:FolderId Id="IQywAAAA=="
                            ChangeKey="AQAAABYAAAD32nSTjepyT63rYH17n9THAAAeZIBf" />
                <t:DisplayName>TestFolder</t:DisplayName>
                <t:ExtendedProperty>
                  <t:ExtendedFieldURI PropertyTag="0x10f4"
                                      PropertyType="Boolean" />
                  <t:Value>true</t:Value>
                </t:ExtendedProperty>
              </t:Folder>
            </t:Folders>
          </m:RootFolder>
        </m:FindFolderResponseMessage>
      </m:ResponseMessages>
    </m:FindFolderResponse>
  </s:Body>
</s:Envelope>

隐藏或取消隐藏文件夹后,可能需要获取文件夹层次结构或 同步文件夹层次结构。 演示如何 使用 EWS 托管 API 获取文件夹层次结构 或使用 EWS 获取文件夹层次结构 的示例还指示隐藏了层次结构中的哪些文件夹。

另请参阅