EWS: deep folder listing with ParentFolderId path reconstruction + result cache
Brought to you by:
mguessan
With the O365EWS mode, LIST "" "*" (recursive folder listing) walks the folder tree one level at a time: appendSubFolders() issues a separate FindFolder request per folder that has children. For mailboxes with large shared-folder trees (e.g. a team mailbox with 38,000+ folders), this generates tens of thousands of EWS round trips, takes ~60 seconds, and triggers server throttling ("The server cannot service this request right now") — which breaks clients like Thunderbird during startup.
On top of that, EWS's FindFolder with Traversal=Deep does not return ParentFolderId unless it is explicitly requested, so a single deep request could not be used to rebuild folder paths.
appendSubFolders() now dispatches to appendSubFoldersShallow() (unchanged per-level behavior) or the new appendSubFoldersDeep().appendSubFoldersDeep() performs one paged FindFolder(Traversal=Deep) over the whole subtree, requesting folder:ParentFolderId as an additional property (new parentfolderid alias in Field.java), then reconstructs each folder's full path by walking ParentFolderId up to the root. Well-known top-level folder names (folderIdMap) are preserved.getSubFolders() caches the recursive listing per session (60 s TTL, synchronized) so concurrent IMAP LIST connections share one walk instead of repeating it; callers get a defensive copy.For a mailbox with 38,334 folders:
LIST "" "*" dropped from ~59 s (cold) to ~0.5 s (cached)Pub/Comp/Customers/A - E/ABC/Offers)sendSubFolders only reads folder flags/paths). If you prefer, the cache part can be dropped and only the deep-traversal change kept.O365EWS) path is touched; the WebDAV path is untouched.src/java/davmail/exchange/ews/EwsExchangeSession.javasrc/java/davmail/exchange/ews/Field.java
I made a typo in the Problem section: the round trips took over 600 seconds (thus triggering several "limited connection" flags in Thunderbird, eventually failing)