1

I am trying to use exchangelib to retrieve messages from a account that match\starts with a particular subject. This must include messages from all folders and not just the 'inbox' folder. I went through a couple of similar questions here

How can I get the latest emails from all folders with exchangelib?

which led me to use FolderCollection. However, I am not clear how create and pass a list of all folders to the 'folders' parameter.

Currently I tried the below:

conf = Configuration(server=ex_srv, credentials=cred)
acct = Account(primary_smtp_address=email, 
                            config=conf, 
                            autodiscover=False, 
                            credentials=cred, 
                            access_type=IMPERSONATION
                        )

from exchangelib.folders import Messages, FolderCollection
all_folder_list = acct.folders[Messages]
all_folder_collection = FolderCollection(account=acct, folders=all_folder_list)

all_folder_collection.filter(subject__startswith='test')

I seem to be making a silly error here, but cannot get around to catching it.

Could someone please let me know the most optimal way of achieving this use case?

Edit:

The error I see is

Traceback (most recent call last):

  File "queryset.py", line 298, in __iter__
    for val in self._format_items(items=self._query(), return_format=self.return_format):
  File "queryset.py", line 375, in _item_yielder
    for i in iterable:
  File "account.py", line 580, in fetch
    shape=ID_ONLY,
  File "account.py", line 302, in _consume_item_service
    is_empty, items = peek(items)
  File "util.py", line 118, in peek
    first = next(iterable)
  File "folders.py", line 250, in find_items
    for i in items:
  File "services.py", line 432, in _paged_call
    parsed_pages = [self._get_page(message) for message in response]
  File "services.py", line 432, in <listcomp>
    parsed_pages = [self._get_page(message) for message in response]
  File "services.py", line 481, in _get_page
    rootfolder = self._get_element_container(message=message, name='{%s}RootFolder' % MNS)
  File "services.py", line 345, in _get_element_container
    raise self._get_exception(code=response_code, text=msg_text, msg_xml=msg_xml)
exchangelib.errors.ErrorInvalidOperation: Shared folder search cannot be performed on multiple folders.
codeoverflow
  • 71
  • 1
  • 5
  • What is the error you are seeing? Recent versions of exchangelib doesn't have a `Account.folders` dict but you can `walk()` or `glob()` a folder to include subfolders. See https://github.com/ecederstrand/exchangelib#folders You can even filter directly on that, e.g. `root.walk().filter(subject__startswith='test')`. `FolderCollection` accepts a list or generator of folders so your code looks about right. – Erik Cederstrand Jan 17 '19 at 07:53
  • Erik, thanks for the response. The error I get is "Shared folder search cannot be performed on multiple folders". I could not find enough information as to why this happens, but given that I was searching a collection of folders, I got confused with the error. I assume I am not passing in the right list of folders. This is when I used root.walk().filter() – codeoverflow Jan 17 '19 at 14:16
  • Can you please attach the full stack trace to the original post? – Erik Cederstrand Jan 17 '19 at 18:35
  • Thanks Erik. I have added the stacktrace. – codeoverflow Jan 19 '19 at 09:43

1 Answers1

2

The problem is that your FolderCollection contains multiple shared folders. EWS does not allow querying more than one shared folder at a time. You'll either have to exclude shared folders from the search, if you don't need to search them, or search the shared folders one at a time.

Erik Cederstrand
  • 9,643
  • 8
  • 39
  • 63
  • Thanks Erik for helping with this. I took some time to figure out how to filter this out. I replaced the all_folder_list = acct.folders[Messages] with account.root.walk() and add each folder to the all_folder_list. But I could not figure out what attribute on the folder says that it is a shared folder. I see a couple of fields such as effective_rights etc but I am not sure which one to use. Alternatively, since I know I want to search only emails and not look at other types like Notes, Contacts etc, is there a way to initially filter out folder that contain only messages? – codeoverflow Jan 28 '19 at 06:44
  • I believe shared folders are stored under `account.public_folders_root` but I don't have a lot of experience with shared folders. A folder instance has a `supported_item_models` attribute stating the item types it supports. See: https://github.com/ecederstrand/exchangelib/blob/f0b1909c71f6167701aa7e7a939a03f8291f8045/exchangelib/folders.py#L319 – Erik Cederstrand Jan 29 '19 at 09:03