用Python中Pywin32 win32com操作outlook总结 | 读-查-发-存邮件

目录

1. 简介

2. 用win32com操作outlook

1.读邮件

2. 根据条件查邮件

3. 保存邮件附件或邮件

4. 发邮件

5. 获取邮件的发件人,收件人和copy人的邮件地址

3. 问题总结

1.发件人邮件地址取不到

4. 其它


1. 简介

Pywin32是最受欢迎的软件包之一,可以自动化Microsoft Outlook/Excel等的日常工作。 本文主要通过Python Pywin32软件包从Outlook中读邮件,查邮件,发邮件和保存邮件。

2. 用win32com操作outlook

1.读邮件

安装pywin32包

python -m pip install pypiwin32

就像与其他系统或应用程序通信一样,您需要首先启动会话。 通过调用getNamespace函数,您可以获取后续操作的Outlook会话。

import win32com.client as win32
outlook = win32.Dispatch('outlook.application')
mapi = outlook.GetNamespace('MAPI')

当使用以下代码迭代帐户属性时,您将看到您在Outlook中配置的任何帐户:

for account in mapi.Accounts:
    print(account.DeliveryStore.DisplayName)

执行结果如下:

abc@company.com
xxx@gmail.com

为了访问特定电子邮件帐户下的子文件夹,您可以继续使用文件夹方法来指定文件夹的子文件夹名称或索引。 在此之前,您可能需要检查什么是可用的子文件夹,并且根据以下内容的索引值:

for idx, folder in enumerate(mapi.Folders("abc@company.com").Folders):
    print(idx+1, folder)
# or using index to access the folder
for idx, folder in enumerate(mapi.Folders(1).Folders): 
    print(idx+1, folder)

执行结果如下:

1 Deleted Items
2 Inbox
3 Outbox
4 Sent Items
5 Tasks
6 RSS Subscriptions
7 Contacts
8 Calendar
9 Yammer Root
10 Sync Issues
11 Quick Step Settings
12 Suggested Contacts
13 News Feed
14 Junk Email
15 Drafts
16 Conversation Action Settings
17 Conversation History
18 Notes
19 ExternalContacts
20 Journal
21 Files

访问inbox文件夹

# access inbox folder with GetDefaultFolder(6) method
for idx, folder in enumerate(mapi.GetDefaultFolder(6).Folders):
    print(idx + 1, folder)

读Inbox文件夹下的邮件,

messages = mapi.Folders("abc@company.com").Folders("Inbox").Items
# or
messages = mapi.Folders("abc@company.com").GetDefaultFolder(6).Items
# or
messages = mapi.Folders(1).Folders(2).Items
for msg in list(messages):
    print(msg.Subject)

读inbox文件夹下的最后一份邮件或第一份邮件, 并且打印邮件的标题,发件人邮箱地址和邮件内容

message = messages.GetLast()
#message = messages.GetFirst()

print(message.Subject)
print(message.SenderEmailAddress)
print(message.Body)

读前5份邮件

len_items = len(messages)
last5Messages = []
for i in range(5):
    # print(i)
    last5Messages.append(messages[len_items - i - 1])

for message in last5Messages:
    print(message)

或者

messages.Sort("[ReceivedTime]", Descending=True)

#read only the first 5 messages
for message in list(messages)[:5]:
    print(message.Subject, message.ReceivedTime, message.SenderEmailAddress)

2. 根据条件查邮件

使用限制功能来过滤您的电子邮件。 例如,我们可以在过去24小时内接收时间来过滤。

from datetime import datetime, timedelta

received_dt = datetime.now() - timedelta(days=1)
received_dt = received_dt.strftime('%m/%d/%Y %H:%M %p')
messages = messages.Restrict("[ReceivedTime] >= '" + received_dt + "'")
messages = messages.Restrict("[SenderEmailAddress] = 'contact@codeforests.com'")
messages = messages.Restrict("[Subject] = 'Sample Report'")

过滤的通配符匹配

使用限制方法,您无法进行通配符匹配,例如搜索电子邮件主体或身体是否包含某些关键字。 为了实现这一目标,您需要使用ADSL查询。

例如,使用以下DASL查询语法,您可以过滤包含“Sample Report”关键字的电子邮件主题:

messages = messages.Restrict("@SQL=(urn:schemas:httpmail:subject LIKE '%Sample Report%')")

要仅从特定域过滤电子邮件,您可以使用类似于上一个示例的ADSL查询:

messages = messages.Restrict("@SQL=(urn:schemas:httpmail:SenderEmailAddress LIKE '%company.com')")

为了将电子邮件从几个域中排除,您可以使用多个条件与逻辑运营商:

messages = messages.Restrict("@SQL=(Not(urn:schemas:httpmail:senderemail LIKE '%@abc%') \
And Not(urn:schemas:httpmail:senderemail LIKE '%@123%') \
And Not(urn:schemas:httpmail:senderemail LIKE '%@xyz%'))")

3. 保存邮件附件或邮件

保存邮件的附件

#Let's assume we want to save the email attachment to the below directory
outputDir = r"C:\attachment"
try:
    for message in list(messages):
	try:
	    s = message.sender
	    for attachment in message.Attachments:
	        attachment.SaveASFile(os.path.join(outputDir, attachment.FileName))
	        print(f"attachment {attachment.FileName} from {s} saved")
	except Exception as e:
		print("error when saving the attachment:" + str(e))
except Exception as e:
		print("error when processing emails messages:" + str(e))

保存整个邮件

base_dir = 'C:\email'
import os
import uuid
for message in last5Messages:
    mail_name = str(uuid.uuid4()) + '.msg'
    temp_file_path = os.path.join(base_dir, mail_name)
    message.SaveAs(temp_file_path)

如果要保存邮件到数据库

# convert email to binary file
def convert_file_to_binary( file_path):
    with open(file_path, 'rb') as file:
        binary_file=file.read()
        return binary_file

base_dir = 'C:\email'
import os
import uuid
for message in last5Messages:
    mail_name = str(uuid.uuid4()) + '.msg'
    temp_file_path = os.path.join(base_dir, mail_name)
    binary_file = convert_file_to_binary(temp_file_path)
    # save binary file of email to DB directly
    

4. 发邮件

回复邮件

def reply_mail(mail,  content , to_address='abc@company.com'):
    signature = "
thanks
yourname" reply = mail.Reply() reply_message = """ """ + content + """
""" + signature + """
""" reply.HTMLBody = reply_message + reply.HTMLBody reply.To = to_address reply.CC = 'abc@company.com' reply.Send()

发邮件

mail = outlook.CreateItem(0)
replymail(mail , "myfirstEmail")

5. 获取邮件的发件人,收件人和copy人的邮件地址

def get_cc_to_email_address(message):
    CC_list = []
    TO_list = []
    recipients = message.Recipients
    for recipient in recipients:
        addressEntry = recipient.AddressEntry
        if (addressEntry.Type == "EX"):
            if addressEntry.GetExchangeUser() is None:
                email_address = addressEntry.GetExchangeDistributionList().PrimarySmtpAddress
            else:
                email_address = addressEntry.GetExchangeUser().PrimarySmtpAddress
        else:
            email_address = addressEntry.Address
    # 1: TO , 2 : CC
        if recipient.Type == 1:
            TO_list.append(email_address)
        elif recipient.Type == 2:
            CC_list.append(email_address)
        else:
            print('recipient.Type is not in (1, 2)', recipient.Type)
    recipients_dict = {'TO': TO_list, 'CC': CC_list}
    return recipients_dict

def get_sender_email_address(email_object):
    if email_object.SenderEmailType == "EX":
        try:
            email_sender =  email_object.Sender
            print(email_sender)
        except AttributeError:
            print('no sender attribute,')
            sender_email_address = email_object.SenderEmailAddress
        else:
            if email_object.Sender.GetExchangeUser() is None:
                sender_email_address = email_object.Sender.GetExchangeDistributionList().PrimarySmtpAddress
            else:
                sender_email_address = email_object.Sender.GetExchangeUser().PrimarySmtpAddress
    else:
        sender_email_address = email_object.SenderEmailAddress
    return sender_email_address

3. 问题总结

1.发件人邮件地址取不到

发件人邮件地址用SenderEmailAddress来取的话取出的不对,因为发件人的邮件地址类型是EX, 用下面的方法来取。

def get_sender_email_address(email_object):
    if email_object.SenderEmailType == "EX":
        try:
            email_sender =  email_object.Sender
            print(email_sender)
        except AttributeError:
            print('no sender attribute,')
            sender_email_address = email_object.SenderEmailAddress
        else:
            if email_object.Sender.GetExchangeUser() is None:
                sender_email_address = email_object.Sender.GetExchangeDistributionList().PrimarySmtpAddress
            else:
                sender_email_address = email_object.Sender.GetExchangeUser().PrimarySmtpAddress

    else:
        sender_email_address = email_object.SenderEmailAddress
    return sender_email_address

4. 其它

关于outlook文档的一些链接
(1)非官方,接口不全,可速查
http://www.snb-vba.eu/VBA_Outlook_external_en.html#L_2.0
(2)微软官方.NET接口文档(英文)
https://docs.microsoft.com/en-us/dotnet/api/microsoft.office.interop.outlook?view=outlook-pia
(3)微软官方.NET接口文档(中文)
https://docs.microsoft.com/zh-cn/dotnet/api/microsoft.office.interop.outlook?view=outlook-pia
(4)微软官方VBA文档
https://docs.microsoft.com/zh-cn/office/vba/api/overview/outloo

https://docs.microsoft.com/en-us/previous-versions/office/developer/exchange-server-2007/aa581347(v=exchg.80)

你可能感兴趣的