【问题标题】:Exchange Web Services (EWS) FindItems within All Folders所有文件夹中的 Exchange Web 服务 (EWS) FindItems
【发布时间】:2011-11-16 02:18:36
【问题描述】:

我正在使用以下代码查找用户发送的所有电子邮件,但这仅搜索主收件箱文件夹,不检查任何子文件夹。我想搜索所有邮件项目,包括任何子文件夹。

我尝试了WellKnownFolderName.RootWellKnownFolderName.Inbox,它们只搜索那些文件夹,而不是子文件夹。

private static void SearchItems(string email)
{
    ItemView iv = new ItemView(10);
    FindItemsResults<Item> fiitems = _service.FindItems(WellKnownFolderName.Inbox, "from:username@example.com", iv);

    foreach (Item item in fiitems)
    {
        Console.WriteLine("Subject:\t" + item.Subject);
        Console.WriteLine("Received At:\t\t" + item.DateTimeReceived.ToString("dd MMMM yyyy"));
        Console.WriteLine();
    }

    Console.WriteLine("Press Enter to continue");
    Console.ReadLine();
}

【问题讨论】:

    标签: c# exchange-server exchangewebservices


    【解决方案1】:

    我在 Exchange over at Glen's blog 中的 AllItems 文件夹中找到了一些信息。我已将 PowerShell 脚本移植到 C#,如下所示。

    private static void SearchItems()
    {
        ExtendedPropertyDefinition allFoldersType = 
            new ExtendedPropertyDefinition(13825, MapiPropertyType.Integer);
    
        FolderId rootFolderId = new FolderId(WellKnownFolderName.Root);
        FolderView folderView = new FolderView(1000);
        folderView.Traversal = FolderTraversal.Shallow;
    
        SearchFilter searchFilter1 = new SearchFilter.IsEqualTo(allFoldersType, "2");
        SearchFilter searchFilter2 = new SearchFilter.IsEqualTo(FolderSchema.DisplayName, "allitems");
    
        SearchFilter.SearchFilterCollection searchFilterCollection = 
            new SearchFilter.SearchFilterCollection(LogicalOperator.And);
        searchFilterCollection.Add(searchFilter1);
        searchFilterCollection.Add(searchFilter2);
    
        FindFoldersResults findFoldersResults = 
            _service.FindFolders(rootFolderId, searchFilterCollection, folderView);
    
        if (findFoldersResults.Folders.Count > 0)
        {
            Folder allItemsFolder = findFoldersResults.Folders[0];
            Console.WriteLine("Folder:\t" + allItemsFolder.DisplayName);
    
            ItemView iv = new ItemView(1000);
            FindItemsResults<Item> findResults = 
                allItemsFolder.FindItems("System.Message.DateReceived:01/01/2011..01/31/2011", iv);
    
            foreach (Item item in findResults)
            {
                Console.WriteLine("Subject:\t" + item.Subject);
                Console.WriteLine("Received At:\t\t" + item.DateTimeReceived.ToString("dd MMMM yyyy"));
                Console.WriteLine("Is New:\t\t" + item.IsNew.ToString());
                Console.WriteLine("Has Attachments:\t\t" + item.HasAttachments.ToString());
                Console.WriteLine();
            }
        }
    
        Console.WriteLine("Press Enter to continue");
        Console.ReadLine();
    }
    

    【讨论】:

    • @Kiquenet 不,我没有,它不会被大量使用
    【解决方案2】:
    【解决方案3】:

    如果您只需要服务器上所有文件夹和子文件夹的集合,您可以分页请求并通过几次调用从服务器获取整个文件夹层次结构。关键是FolderView.Traversal 属性。

    例如,对于包含约 1,300 个文件夹的 Exchange 邮箱,以下代码仅发出 2 个请求。您可以将页面大小设置为您喜欢的任何大小,只要您保持在或低于服务器限制即可。

    仅供参考:Exchange Online (Office365) 在响应中最多包含 1,000 个项目。我没有测试过,所以在查询本地 Exchange Server 时,我无法说出任何类似的限制。

    Imports Exchange = Microsoft.Exchange.WebServices.Data
    
    Friend Module Main
      Public Sub Main()
        Dim oService As Exchange.ExchangeService
        Dim oUsers As Dictionary(Of String, User)
    
        oUsers = New Dictionary(Of String, User)
        oUsers.Add("User1", New User("write.to.me1@my.address.com", "Some-Fancy-Password1"))
        oUsers.Add("User2", New User("write.to.me2@my.address.com", "Some-Fancy-Password2"))
    
        oUsers.ToList.ForEach(Sub(Credential As KeyValuePair(Of String, User))
                                File.Delete(LOG_FILE_PATH.ToFormat(Credential.Key))
                              End Sub)
    
        oUsers.ToList.ForEach(Sub(Credential As KeyValuePair(Of String, User))
                                LogFileName = Credential.Key
    
                                Console.WriteLine("Getting message counts for mailbox [{0}]...", LogFileName)
                                Console.WriteLine()
    
                                oService = Service.ConnectToService(Credential.Value)
    
                                GetAllFolders(oService, LOG_FILE_PATH.ToFormat(Credential.Key))
    
                                Console.Clear()
                              End Sub)
    
        Console.WriteLine()
        Console.Write("Press any key to exit...")
        Console.ReadKey()
      End Sub
    
    
    
      Private Sub GetAllFolders(Service As Exchange.ExchangeService, LogFilePath As String)
        Dim oIsHidden As Exchange.ExtendedPropertyDefinition
        Dim oFolders As List(Of Exchange.Folder)
        Dim oResults As Exchange.FindFoldersResults
        Dim lHasMore As Boolean
        Dim oChild As Exchange.Folder
        Dim oView As Exchange.FolderView
    
        Dim _
          nPageSize,
          nOffSet As Short
    
        Dim _
          oPaths,
          oPath As List(Of String)
    
        oIsHidden = New Exchange.ExtendedPropertyDefinition(&H10F4, Exchange.MapiPropertyType.Boolean)
        nPageSize = 1000
        oFolders = New List(Of Exchange.Folder)
        lHasMore = True
        nOffSet = 0
    
        Do While lHasMore
          oView = New Exchange.FolderView(nPageSize, nOffSet, Exchange.OffsetBasePoint.Beginning)
          oView.PropertySet = New Exchange.PropertySet(Exchange.BasePropertySet.IdOnly)
          oView.PropertySet.Add(oIsHidden)
          oView.PropertySet.Add(Exchange.FolderSchema.ParentFolderId)
          oView.PropertySet.Add(Exchange.FolderSchema.DisplayName)
          oView.PropertySet.Add(Exchange.FolderSchema.FolderClass)
          oView.PropertySet.Add(Exchange.FolderSchema.TotalCount)
          oView.Traversal = Exchange.FolderTraversal.Deep
    
          oResults = Service.FindFolders(Exchange.WellKnownFolderName.MsgFolderRoot, oView)
          oFolders.AddRange(oResults.Folders)
    
          lHasMore = oResults.MoreAvailable
    
          If lHasMore Then
            nOffSet += nPageSize
          End If
        Loop
    
        oFolders.RemoveAll(Function(Folder) Folder.ExtendedProperties(0).Value = True)
        oFolders.RemoveAll(Function(Folder) Folder.FolderClass <> "IPF.Note")
    
        oPaths = New List(Of String)
    
        oFolders.ForEach(Sub(Folder)
                           oChild = Folder
                           oPath = New List(Of String)
    
                           Do
                             oPath.Add(oChild.DisplayName)
                             oChild = oFolders.SingleOrDefault(Function(Parent) Parent.Id.UniqueId = oChild.ParentFolderId.UniqueId)
                           Loop While oChild IsNot Nothing
    
                           oPath.Reverse()
                           oPaths.Add("{0}{1}{2}".ToFormat(Join(oPath.ToArray, DELIMITER), vbTab, Folder.TotalCount))
                         End Sub)
    
        oPaths.RemoveAll(Function(Path) Path.StartsWith("Sync Issues"))
    
        File.WriteAllText(LogFilePath, Join(oPaths.ToArray, vbCrLf))
      End Sub
    
    
    
      Private LogFileName As String
    
      Private Const LOG_FILE_PATH As String = "D:\Emails\Remote{0}.txt"
      Private Const DELIMITER As String = "\"
    End Module
    
    
    
    Friend Class Service
      Public Shared Function ConnectToService(User As User) As Exchange.ExchangeService
        Return Service.ConnectToService(User, Nothing)
      End Function
    
    
    
      Public Shared Function ConnectToService(User As User, Listener As Exchange.ITraceListener) As Exchange.ExchangeService
        Dim oService As Exchange.ExchangeService
    
        oService = New Exchange.ExchangeService(Exchange.ExchangeVersion.Exchange2013_SP1)
        oService.Credentials = New NetworkCredential(User.EmailAddress, User.Password)
        oService.AutodiscoverUrl(User.EmailAddress, AddressOf RedirectionUrlValidationCallback)
    
        If Listener IsNot Nothing Then
          oService.TraceListener = Listener
          oService.TraceEnabled = True
          oService.TraceFlags = Exchange.TraceFlags.All
        End If
    
        Return oService
      End Function
    
    
    
      Private Shared Function RedirectionUrlValidationCallback(RedirectionUrl As String) As Boolean
        With New Uri(RedirectionUrl)
          Return .Scheme.ToLower = "https"
        End With
      End Function
    End Class
    
    
    
    Friend Class User
      Public Sub New(EmailAddress As String)
        _EmailAddress = EmailAddress
        _Password = New SecureString
      End Sub
    
    
    
      Public Sub New(EmailAddress As String, Password As String)
        _EmailAddress = EmailAddress
        _Password = New SecureString
    
        Password.ToList.ForEach(Sub(Chr As Char)
                                  Me.Password.AppendChar(Chr)
                                End Sub)
    
        Password.MakeReadOnly()
      End Sub
    
    
    
      Public Shared Function GetUser() As User
        Dim sEmailAddress As String
        Dim oUserInput As ConsoleKeyInfo
    
        Console.Write("Enter email address: ")
        sEmailAddress = Console.ReadLine
        Console.Write("Enter password: ")
    
        GetUser = New User(sEmailAddress)
    
        While True
          oUserInput = Console.ReadKey(True)
    
          If oUserInput.Key = ConsoleKey.Enter Then
            Exit While
    
          ElseIf oUserInput.Key = ConsoleKey.Escape Then
            GetUser.Password.Clear()
    
          ElseIf oUserInput.Key = ConsoleKey.Backspace Then
            If GetUser.Password.Length <> 0 Then
              GetUser.Password.RemoveAt(GetUser.Password.Length - 1)
            End If
    
          Else
            GetUser.Password.AppendChar(oUserInput.KeyChar)
            Console.Write("*")
    
          End If
        End While
    
        If GetUser.Password.Length = 0 Then
          GetUser = Nothing
        Else
          GetUser.Password.MakeReadOnly()
          Console.WriteLine()
        End If
      End Function
    
    
    
      Public ReadOnly Property EmailAddress As String
    
      Public ReadOnly Property Password As SecureString
    End Class
    
    
    
    Friend Class TraceListener
      Implements Exchange.ITraceListener
    
      Public Sub Trace(TraceType As String, TraceMessage As String) Implements Exchange.ITraceListener.Trace
        File.AppendAllText("{0}.txt".ToFormat(Path.Combine("D:\Emails\TraceOutput", Guid.NewGuid.ToString("D"))), TraceMessage)
      End Sub
    End Class
    

    【讨论】:

    • 你试过性能测试吗? 对于巨大的收件箱
    • @Kiquenet — 我必须测试的最大邮箱是 1.2GB。代码在大约 30 秒或更短的时间内运行完毕。我既没有计时也没有基准测试。 YMMV
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2016-10-14
    • 1970-01-01
    • 1970-01-01
    • 2014-03-20
    • 2016-02-13
    相关资源
    最近更新 更多