Python 调用 Outlook 发送邮件

微软 Office 提供基于 COM 接口的编程。Python 通过 pywin32 可以方便地调用各组件。如果下载和安装 pywin32 有困难,可以到 Sourceforge 的镜像网摘查找合适的版本。

单一账号

import win32com.client as win32

def send_mail():
    outlook = win32.Dispatch('Outlook.Application')

    mail_item = outlook.CreateItem(0) # 0: olMailItem

    mail_item.Recipients.Add('someone@qq.com')
    mail_item.Subject = 'Mail Test'

    mail_item.BodyFormat = 2          # 2: Html format
    mail_item.HTMLBody  = '''
        <H2>Hello, This is a test mail.</H2>
        Hello Guys. 
        '''
    mail_item.Send()

if __name__ == '__main__':
    send_mail()

多账号发送邮件

如果 Outlook 有多个账号,需要选择账号发送邮件,需要在代码中对账号进行判断,代码如下:

def send_mail():
    outlook_app = win32.Dispatch('Outlook.Application')

    # choose sender account
    send_account = None
    for account in outlook_app.Session.Accounts:
        if account.DisplayName == 'sender@hotmail.com':
            send_account = account
            break

    mail_item = outlook_app.CreateItem(0)   # 0: olMailItem

    # mail_item.SendUsingAccount = send_account not working
    # the following statement performs the function instead
    mail_item._oleobj_.Invoke(*(64209, 0, 8, 0, send_account))

    mail_item.Recipients.Add('receipient@qq.com')
    mail_item.Subject = 'Test sending using particular account'
    mail_item.BodyFormat = 2   # 2: Html format
    mail_item.HTMLBody = '''
        <H2>Hello, This is a test mail.</H2>
        Hello Guys. 
        '''

    mail_item.Send()


if __name__ == '__main__':
    send_mail()

这里有点黑魔法,直接设置 mail_item.SendUsingAccount 不会起作用,返回值是 None, 永远从第一个邮箱账号发送邮件,我使用的是 Office 365 版。需要调用 _oleobj_.Invoke() 方法。后面列出了参考链接。

本质上,这种方法是调用 COM 组件,可以查询微软的开发帮助了解相关对象的属性和方法,比如我想知道 Account 的细节,就特意参考了下面这篇帮助:https://docs.microsoft.com/zh-cn/office/vba/api/outlook.account 。COM 编程与语言无关。另外可以在 Outlook 中 ALT + F11,进入 VBE 环境,然后 F2 进入对象浏览器界面查看比如下面的界面显示了 Account 的属性和方法:

image

关于调试

python 作为动态语言,通过 Debug 获取 COM 对象信息并不是很方便,比如下面代码:

import win32com.client as win32

def print_outlook_accounts():
    outlook_app = win32.Dispatch('Outlook.Application')

    for account in outlook_app.Session.Accounts:
        print (account.DeliveryStore.DisplayName)

if __name__ == '__main__':
    send_mail()

设置断点的调试界面:


image

我们只知道 account 是一个 COM Object,account 包含的信息很多都是 unknown 的。碰到这种情况,我一般用 C# 或者 VBA 编写代码进行调试。如果我需要详细了解 account 的属性和方法,在 Office 的任何组件中,比如 Excel,写一段下面的代码:

Public Sub Print_Outlook_Accounts()

    ' 工具 -> 引用:添加 Microsoft Outook Object Library 引用
    
    Dim outlookApp As New Outlook.Application
    Dim accounts As Outlook.accounts
    
    Set accounts = outlookApp.Session.accounts
    
    Dim account As Outlook.account
    For Each account In accounts
        Debug.Print account.DisplayName
    Next
End Sub

显示出监视窗口,设置断点,获取 accounts 信息:

image

在监视窗口添加变量 accounts:

image

展开:

image

Item 1 和 Item 2 表示有两个账号,现在我们想看到 Item 2 的账号信息,将 Item 2 展开:

image

DeliveryStore 属性也包含 account 的信息,可以展开查看。

参考

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
平台声明:文章内容(如有图片或视频亦包括在内)由作者上传并发布,文章内容仅代表作者本人观点,简书系信息发布平台,仅提供信息存储服务。

推荐阅读更多精彩内容

  • # Python 资源大全中文版 我想很多程序员应该记得 GitHub 上有一个 Awesome - XXX 系列...
    小迈克阅读 8,162评论 1 3
  • Python资源大全中文版,包括:Web框架、网络爬虫、模板引擎、数据库、数据可视化、图片处理等,由伯乐在线持续更...
    dxl1236阅读 10,146评论 2 33
  • Python 资源 我想很多程序员应该记得 GitHub 上有一个 Awesome - XXX 系列的资源整理。a...
    叶冷随记阅读 12,343评论 1 225
  • Python 资源大全中文版 awesome-python[https://github.com/vinta/aw...
    万色星辰阅读 13,270评论 0 255
  • Python 资源大全中文版 我想很多程序员应该记得 GitHub 上有一个 Awesome - XXX 系列的资...
    叶同学阅读 13,828评论 0 73