Skip to content
Advertisement

Exchangelib Scan All Folders – Efficiency

I am using exchangelib to connect to my exchange mailbox. Currently the code is scanning through all folders since the target email message can be in any of the folders for my task.

Is there a more efficient way for looping/scanning the folders here? (Looking for emails greater than a target start date)

all_folders = account.root.glob('**/*')
for folder in all_folders:
    # Messages can only exist in 'IPF.Note' folder classes
    if folder.folder_class == 'IPF.Note':
        # For all emails that are newer than the target date
        for email in folder.filter(datetime_received__gt=ews_bfr):
            # Do something

Edit: Thanks for the help, Erik. This worked and made the run time decrease dramatically:

target_folders = (f for f in account.root.walk() if f.name in ['xxxxxx'])
folder_coll = FolderCollection(account=account, folders=target_folders)
for email in folder_coll.filter(datetime_received__gt=ews_bfr):
    # Do something

Advertisement

Answer

A normal .filter() works on just the folder you call it on. EWS does not support searching items within all folders, but only the folders explicitly mentioned in the FindItems service call.

In exchangelib, the way to filter on multiple folders in one go is to use a FolderCollection:

from exchangelib import FolderCollection
FolderCollection(account=account, folders=[...]).filter(some_field='foo')

The folders argument can be any iterable of folders, e.g. [account.inbox, account.sent], account.root.walk() or (f for f in account.root.walk() if f.CONTAINER_CLASS == 'IPF.Note')

.glob(), .walk(), .children and other subfolder access methods also support calling .filter() on them:

account.root.glob('**/*').filter(datetime_received__gt=ews_bfr)
account.root.walk().filter(datetime_received__gt=ews_bfr)
Advertisement