`ErrorNonExistentMailbox` in version 5.2.1 but not in 5.2.0
seanslma opened this issue · 6 comments
Describe the bug
My code works as expected in version 5.2.0 but got this error in 5.2.1:
exchangelib.errors.ErrorNonExistentMailbox: No mailbox with such guid.
To Reproduce
from exchangelib import (
Account,
Configuration,
Credentials,
DELEGATE,
Message,
NTLM,
)
server = 'owa.example.com'
sender = 'sender@example.com'
recipients = ['recipient_1@example.com']
username = 'username@example.com'
password = 'my-password'
config = Configuration(
server=server,
credentials=Credentials(username=username, password=password),
auth_type=NTLM,
version=None,
)
account = Account(sender, config=config, access_type=DELEGATE)
message = Message(
account=account,
subject='Test Email',
body='Test OK',
to_recipients=recipients,
)
message.send()
Expected behavior
The 5.2.1 should work as well
Log output
ErrorNonExistentMailbox Traceback (most recent call last)
Cell In[41], line 32
24 account = Account(sender, config=config, access_type=DELEGATE)
26 message = Message(
27 account=account,
28 subject='Test Email',
29 body='Test OK',
30 to_recipients=recipients,
31 )
---> 32 message.send()
File ~\conda-envs\env_py39\lib\site-packages\exchangelib\util.py:39, in require_account.<locals>.wrapper(self, *args, **kwargs)
37 if not self.account:
38 raise ValueError(f"{self.__class__.__name__} must have an account")
---> 39 return f(self, *args, **kwargs)
File ~\conda-envs\env_py39\lib\site-packages\exchangelib\items\message.py:81, in Message.send(self, save_copy, copy_to_folder, conflict_resolution, send_meeting_invitations)
78 if copy_to_folder:
79 # This would better be done via send_and_save() but let's just support it here
80 self.folder = copy_to_folder
---> 81 return self.send_and_save(
82 conflict_resolution=conflict_resolution, send_meeting_invitations=send_meeting_invitations
83 )
85 if self.account.version.build < EXCHANGE_2013 and self.attachments:
86 # At least some versions prior to Exchange 2013 can't send attachments immediately. You need to first save,
87 # then attach, then send. This is done in send_and_save(). send() will delete the item again.
88 self.send_and_save(
89 conflict_resolution=conflict_resolution, send_meeting_invitations=send_meeting_invitations
90 )
File ~\conda-envs\env_py39\lib\site-packages\exchangelib\items\message.py:120, in Message.send_and_save(self, update_fields, conflict_resolution, send_meeting_invitations)
110 self.save(
111 update_fields=update_fields,
112 conflict_resolution=conflict_resolution,
113 send_meeting_invitations=send_meeting_invitations,
114 )
115 return self.send(
116 save_copy=False,
117 conflict_resolution=conflict_resolution,
118 send_meeting_invitations=send_meeting_invitations,
119 )
--> 120 return self._create(message_disposition=SEND_AND_SAVE_COPY, send_meeting_invitations=send_meeting_invitations)
File ~\conda-envs\env_py39\lib\site-packages\exchangelib\util.py:39, in require_account.<locals>.wrapper(self, *args, **kwargs)
37 if not self.account:
38 raise ValueError(f"{self.__class__.__name__} must have an account")
---> 39 return f(self, *args, **kwargs)
File ~\conda-envs\env_py39\lib\site-packages\exchangelib\items\item.py:185, in Item._create(self, message_disposition, send_meeting_invitations)
179 @require_account
180 def _create(self, message_disposition, send_meeting_invitations):
181 # Return a BulkCreateResult because we want to return the ID of both the main item *and* attachments. In send
182 # and send-and-save-copy mode, the server does not return an ID, so we just return True.
183 from ..services import CreateItem
--> 185 return CreateItem(account=self.account).get(
186 items=[self],
187 folder=self.folder,
188 message_disposition=message_disposition,
189 send_meeting_invitations=send_meeting_invitations,
190 )
File ~\conda-envs\env_py39\lib\site-packages\exchangelib\services\common.py:164, in EWSService.get(self, expect_result, **kwargs)
156 def get(self, expect_result=True, **kwargs):
157 """Like .call(), but expects exactly one result from the server, or zero when expect_result=False, or either
158 zero or one when expect_result=None. Returns either one object or None.
159
(...)
162 :return: Same as .call(), but returns either None or exactly one item
163 """
--> 164 res = list(self.call(**kwargs))
165 # Raise any errors
166 for r in res:
File ~\conda-envs\env_py39\lib\site-packages\exchangelib\services\common.py:225, in EWSService._elems_to_objs(self, elems)
223 def _elems_to_objs(self, elems):
224 """Takes a generator of XML elements and exceptions. Returns the equivalent Python objects (or exceptions)."""
--> 225 for elem in elems:
226 # Allow None here. Some services don't return an ID if the target folder is outside the mailbox.
227 if isinstance(elem, (Exception, type(None))):
228 yield elem
File ~\conda-envs\env_py39\lib\site-packages\exchangelib\services\common.py:287, in EWSService._chunked_get_elements(self, payload_func, items, **kwargs)
285 for i, chunk in enumerate(chunkify(filtered_items, self.chunk_size), start=1):
286 log.debug("Processing chunk %s containing %s items", i, len(chunk))
--> 287 yield from self._get_elements(payload=payload_func(chunk, **kwargs))
File ~\conda-envs\env_py39\lib\site-packages\exchangelib\services\common.py:308, in EWSService._get_elements(self, payload)
304 while True:
305 try:
306 # Create a generator over the response elements so exceptions in response elements are also raised
307 # here and can be handled.
--> 308 yield from self._response_generator(payload=payload)
309 # TODO: Restore session pool size on succeeding request?
310 return
File ~\conda-envs\env_py39\lib\site-packages\exchangelib\services\common.py:684, in EWSService._get_elements_in_response(self, response)
659 """Take a list of 'SomeServiceResponseMessage' elements and return the elements in each response message that
660 we want the service to return. With e.g. 'CreateItem', we get a list of 'CreateItemResponseMessage' elements
661 and return the 'Message' elements.
(...)
681 :return: a generator of items as returned by '_get_elements_in_container()
682 """
683 for msg in response:
--> 684 container_or_exc = self._get_element_container(message=msg, name=self.element_container_name)
685 if isinstance(container_or_exc, (bool, Exception)):
686 yield container_or_exc
File ~\conda-envs\env_py39\lib\site-packages\exchangelib\services\common.py:606, in EWSService._get_element_container(self, message, name)
604 # response_class == 'Error', or 'Success' and not 'NoError'
605 try:
--> 606 raise self._get_exception(code=response_code, text=msg_text, msg_xml=msg_xml)
607 except self.ERRORS_TO_CATCH_IN_RESPONSE as e:
608 return e
ErrorNonExistentMailbox: No mailbox with such guid.
Additional context
For example, Python and exchangelib versions.
- Python: 3.9
- exchangelib: 5.2.1
This is covered by the test suite, so there must be something else going on.
Your best bet is to enable debug logging and comparing the XML requests and responses for a working 5.2.0 and a non-working exchangelib 5.2.1 version, to see how the new version queries the server differently.
I encountered that the 5.2.1 version does not work with SingleFolderQuerySet(), with 5.2.0 works perfect.
@seanslma Did you get a chance to debug this?
@ecederstrand Thanks. Was occupied by other things and pinned the version to 5.2.0.
The only difference in Request XML:
Version 5.2.1
<t:DistinguishedFolderId Id="sentitems"/>
Version 5.2.0
<t:DistinguishedFolderId Id="sentitems">
<t:Mailbox>
<t:EmailAddress>sender@example.com</t:EmailAddress>
<t:RoutingType>SMTP</t:RoutingType>
<t:MailboxType>Mailbox</t:MailboxType>
</t:Mailbox>
</t:DistinguishedFolderId>
Thanks for the debug info! I believe d9035d0 may fix this for you. Can you try it out?