Exchangelib:按 conversation_id 过滤电子邮件

Exchangelib: Filtering email by conversation_id

我正在尝试使用 exchangelib 阅读带有某些 conversation_id 的电子邮件,并且只阅读 2 个属性:eid 和 datetime_received。 我不知道为什么下面的代码不起作用:

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))

当前错误是:

*** 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'

任何解决方法的指针将不胜感激。

更新: 我从本地 运行 outlook 程序中得到了 conversation_id。 以下代码从我的 outlook 中输出当前选择的电子邮件。 请参阅下面的“return”行。

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))

其实我只是想重现https://github.com/ecederstrand/exchangelib/issues/261中的解决方案 通过根据 conversation_id 过滤搜索 我不确定,为什么它对我不起作用。

您的交换服务器不喜欢您对话 ID 的格式。您从服务器收到 ErrorInvalidIdMalformed 错误。

您是直接从服务器获取对话 ID 吗?如果没有,您可以使用 ConvertID 服务将 ID 转换为正确的格式,该服务可通过 account.protocol.convert_ids() 方法获得。

如果您不知道对话 ID 的原始格式,您可以尝试所有格式:

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}')

您也可能需要使用 MAPI 属性 搜索 ConversationID 字段。应该这样做(基于 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)