I am trying using exchangelib to read emails with certain conversation_id and only read 2 attributes: eid and datetime_received. I don't know why the following code doesn't work:
from exchangelib import Credentials, Account, Configuration, DELEGATE, EWSDateTime, EWSTimeZone, ExtendedProperty, Message
from exchangelib.properties import ConversationId
def read_latest_eid(conversation_id_, email_address_, password):
convert_ID_to_entryID = lambda x: ''.join('{:02x}'.format(i) for i in x).upper().strip()
class EntryID(ExtendedProperty):
property_tag = 4095
property_type = 'Binary'
try:
Message.register('eid', EntryID)
except:
Message.deregister('eid')
Message.register('eid', EntryID)
credentials = Credentials(email_address_, password)
config = Configuration(server='outlook.office365.com', credentials=credentials)
account = Account("xxx@abc.eu", config=config, access_type=DELEGATE,
autodiscover=False)
result = []
conversationid_to_search = ConversationId(conversation_id_)
print('*** Search following conversation id:', conversationid_to_search, type(conversationid_to_search))
print('*** id:', conversationid_to_search.id, type(conversationid_to_search.id))
for i in account.inbox.filter(conversation_id=conversationid_to_search).only("datetime_received", "eid"):
print('*** i:', i, type(i))
result.append(list((i.datetime_received.astimezone().strftime("%d/%m/%Y, %H:%M:%S"),
convert_ID_to_entryID(i.eid))))
Message.deregister('eid')
return result
# For testing read_latest_id
if __name__ == "__main__":
conversation_id = '7FD7341602EE405193F1F996D7DD8D6A'
print(read_latest_eid(conversation_id))
Currently the error is:
*** Search following conversation id: ConversationId(id='7FD7341602EE405193F1F996D7DD8D6A') <class 'exchangelib.properties.ConversationId'>
*** id: 7FD7341602EE405193F1F996D7DD8D6A <class 'str'>
*** i: Id is malformed. <class 'exchangelib.errors.ErrorInvalidIdMalformed'>
Traceback (most recent call last):
File "h:\Codes\Subscribe_Email\Read_Open_Mail.py", line 171, in <module>
print(read_latest_eid(conversation_id))
File "h:\Codes\Subscribe_Email\Read_Open_Mail.py", line 149, in read_latest_eid
result.append(list((i.datetime_received.astimezone().strftime("%d/%m/%Y, %H:%M:%S"),
AttributeError: 'ErrorInvalidIdMalformed' object has no attribute 'datetime_received'
Any pointer how to solve it would be much appreciated.
Updated: I got the conversation_id from the locally running outlook programm. The following code outputs the currently selected email from my outlook. Refer to "return" line below.
def read_selected_email(outlook):
# This function reads the properties of selected Outlook-Email.
try:
messages = outlook.ActiveExplorer().Selection
message = messages(1)
# print('Sender:', message.Sender)
# print('Date:', message.ReceivedTime)
# print('Titel:', message.subject)
# print('Sender:', message.Sender)
# print('Recipient:', message.To)
# print('ConversationID', message.ConversationID)
# received_time = str(datetime.strptime(str(message.ReceivedTime).rstrip(
# "+00:00"), '%Y-%m-%d %H:%M:%S').date())
received_time = str(message.ReceivedTime).rstrip("+00:00")
print(received_time)
try:
received_time = datetime.strptime(received_time, '%Y-%m-%d %H:%M:%S')
# print('+1')
except:
try:
received_time = datetime.strptime(received_time, '%Y-%m-%d %H:%M')
# print('+2')
except:
received_time = datetime.strptime(received_time, '%Y-%m-%d %H:%M:%S.%f')
received_time = str(received_time.date())
# print('***', message)
return [{'Datum': received_time, 'Titel': message.subject,
'Sender': message.SenderName.split("(")[0], 'Recipient':
message.To, 'Kommentar': '',
'ConversationID': message.ConversationID}]
except AttributeError:
print('*** No Email selected')
pass
except Exception as e:
print(e)
pass
# For testing read_selected_email
if __name__ == "__main__":
outlook = win32com.client.Dispatch("Outlook.Application")
outlook_mapi = outlook.GetNamespace("MAPI")
print(read_selected_email(outlook))
Actually, I just want to reproduce the solution in https://github.com/ecederstrand/exchangelib/issues/261 by filtering the search based on conversation_id I am not sure, why it doesn't work on me.
Your exchange server does not like the format of your conversation ID. You're getting an ErrorInvalidIdMalformed error from the server.
Did you get the conversation ID directly from the server? If not, you may be able to convert the ID to the correct format using the ConvertID service, available via the account.protocol.convert_ids()
method.
If you don't know the original format of the conversation ID, you can just try with all formats:
from exchangelib.properties import ID_FORMATS, EWS_ID, AlternateId
i = '7FD7341602EE405193F1F996D7DD8D6A'
for fmt in ID_FORMATS:
res = list(account.protocol.convert_ids([
AlternateId(
id=i, format=fmt,
mailbox=account.primary_smtp_address)
], destination_format=EWS_ID))[0]
if isinstance(res, Exception):
print(f'Error converting from {fmt} to {EWS_ID}: {res}')
else:
print(f'Sucessfully converted from {fmt} to {EWS_ID}: {res}')
It's also possible that you need to search using the MAPI property for the ConversationID field. Something like this should do (based on https://social.msdn.microsoft.com/Forums/office/en-US/5551df43-d833-4352-b27a-70e18ef71576/how-can-i-compare-conversation-id-from-exchange-web-services-with-outlook-conversation-id-?forum=outlookdev and https://github.com/ecederstrand/exchangelib/issues/146):
class MAPIConverstationID(ExtendedProperty):
property_tag = 0x3013
property_type = 'Binary'
Message.register('mapi_cid', MAPIConverstationID)
for m in account.filter(mapi_cid=my_win32com_cid):
print(m.mapi_cid)