使用EWS查找收件箱文件夹的所有子文件夹

我有以下收件箱文件夹结构:

Inbox --ABC ----ABC 2 ----ABC 3 --XYZ ----XYZ 2 --123 ----123 A ----123 B ----123 C 

我使用Exchange Web服务和以下代码来查找收件箱文件夹的子文件夹:

 ExchangeService service = new ExchangeService(ExchangeVersion.Exchange2010); service.AutodiscoverUrl("MyName@MyDomain.com"); Mailbox mb = new Mailbox("MyName@MyDomain.com"); FindFoldersResults findResults = service.FindFolders( WellKnownFolderName.Inbox, new FolderView(int.MaxValue)); foreach (Folder folder in findResults.Folders) { Console.WriteLine(folder.DisplayName); } 

这部分有效,因为它返回ABC,XYZ和123文件夹; 不幸的是,它没有返回每个文件夹内的文件夹(ABC 2,ABC 3,XYZ 2,123 A,123 B,123 C)。

此外,文件夹可能在其中包含多个子文件夹级别。

如何编写此代码,以便它将返回所有子文件夹,无论它们的嵌套程度如何?

您可以告诉EWS在搜索文件夹时进行深度遍历。 您可以使用FolderView.Traversal属性执行此操作。 然后,您的代码将更改为类似于以下内容:

 FindFoldersResults findResults = service.FindFolders( WellKnownFolderName.Inbox, new FolderView(int.MaxValue) { Traversal = FolderTraversal.Deep }); 

您可以在几次调用中分页您的请求并从服务器获取整个文件夹层次结构。 关键是FolderView.Traversal属性,正如Jacob指出的那样。

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

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

 using Microsoft.VisualBasic; using System; using System.Collections; using System.Collections.Generic; using System.Data; using System.Diagnostics; using Exchange = Microsoft.Exchange.WebServices.Data; static internal class Main { public static void Main() { Exchange.ExchangeService oService = default(Exchange.ExchangeService); Dictionary oUsers = default(Dictionary); oUsers = new Dictionary(); 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((KeyValuePair Credential) => { File.Delete(LOG_FILE_PATH.ToFormat(Credential.Key)); }); oUsers.ToList.ForEach((KeyValuePair Credential) => { 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(); }); Console.WriteLine(); Console.Write("Press any key to exit..."); Console.ReadKey(); } private static void GetAllFolders(Exchange.ExchangeService Service, string LogFilePath) { Exchange.ExtendedPropertyDefinition oIsHidden = default(Exchange.ExtendedPropertyDefinition); List oFolders = default(List); Exchange.FindFoldersResults oResults = default(Exchange.FindFoldersResults); bool lHasMore = false; Exchange.Folder oChild = default(Exchange.Folder); Exchange.FolderView oView = default(Exchange.FolderView); short nPageSize = 0; short nOffSet = 0; List oPaths = default(List); List oPath = default(List); oIsHidden = new Exchange.ExtendedPropertyDefinition(0x10f4, Exchange.MapiPropertyType.Boolean); nPageSize = 1000; oFolders = new List(); lHasMore = true; nOffSet = 0; 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) { nOffSet += nPageSize; } } oFolders.RemoveAll(Folder => Folder.ExtendedProperties(0).Value == true); oFolders.RemoveAll(Folder => Folder.FolderClass != "IPF.Note"); oPaths = new List(); oFolders.ForEach(Folder => { oChild = Folder; oPath = new List(); do { oPath.Add(oChild.DisplayName); oChild = oFolders.SingleOrDefault(Parent => Parent.Id.UniqueId == oChild.ParentFolderId.UniqueId); } while (oChild != null); oPath.Reverse(); oPaths.Add("{0}{1}{2}".ToFormat(Strings.Join(oPath.ToArray, DELIMITER), Constants.vbTab, Folder.TotalCount)); }); oPaths.RemoveAll(Path => Path.StartsWith("Sync Issues")); File.WriteAllText(LogFilePath, Strings.Join(oPaths.ToArray, Constants.vbCrLf)); } private static string LogFileName; private const string LOG_FILE_PATH = "D:\\Emails\\Remote{0}.txt"; private const string DELIMITER = "\\"; } internal class Service { public static Exchange.ExchangeService ConnectToService(User User) { return Service.ConnectToService(User, null); } public static Exchange.ExchangeService ConnectToService(User User, Exchange.ITraceListener Listener) { Exchange.ExchangeService oService = default(Exchange.ExchangeService); oService = new Exchange.ExchangeService(Exchange.ExchangeVersion.Exchange2013_SP1); oService.Credentials = new NetworkCredential(User.EmailAddress, User.Password); oService.AutodiscoverUrl(User.EmailAddress, RedirectionUrlValidationCallback); if (Listener != null) { oService.TraceListener = Listener; oService.TraceEnabled = true; oService.TraceFlags = Exchange.TraceFlags.All; } return oService; } private static bool RedirectionUrlValidationCallback(string RedirectionUrl) { var _with1 = new Uri(RedirectionUrl); return _with1.Scheme.ToLower == "https"; } } internal class User { public User(string EmailAddress) { _EmailAddress = EmailAddress; _Password = new SecureString(); } public User(string EmailAddress, string Password) { _EmailAddress = EmailAddress; _Password = new SecureString(); Password.ToList.ForEach((char Chr) => { this.Password.AppendChar(Chr); }); Password.MakeReadOnly(); } public static User GetUser() { User functionReturnValue = null; string sEmailAddress = null; ConsoleKeyInfo oUserInput = default(ConsoleKeyInfo); Console.Write("Enter email address: "); sEmailAddress = Console.ReadLine; Console.Write("Enter password: "); functionReturnValue = new User(sEmailAddress); while (true) { oUserInput = Console.ReadKey(true); if (oUserInput.Key == ConsoleKey.Enter) { break; // TODO: might not be correct. Was : Exit While } else if (oUserInput.Key == ConsoleKey.Escape) { functionReturnValue.Password.Clear(); } else if (oUserInput.Key == ConsoleKey.Backspace) { if (functionReturnValue.Password.Length != 0) { functionReturnValue.Password.RemoveAt(functionReturnValue.Password.Length - 1); } } else { functionReturnValue.Password.AppendChar(oUserInput.KeyChar); Console.Write("*"); } } if (functionReturnValue.Password.Length == 0) { functionReturnValue = null; } else { functionReturnValue.Password.MakeReadOnly(); Console.WriteLine(); } return functionReturnValue; } public string EmailAddress { get; } public SecureString Password { get; } } internal class TraceListener : Exchange.ITraceListener { public void Trace(string TraceType, string TraceMessage) { File.AppendAllText("{0}.txt".ToFormat(Path.Combine("D:\\Emails\\TraceOutput", Guid.NewGuid.ToString("D"))), TraceMessage); } } //======================================================= //Service provided by Telerik (www.telerik.com) //Conversion powered by NRefactory. //Twitter: @telerik //Facebook: facebook.com/telerik //=======================================================