发送电子邮件模块 smtplib

电子邮件是最流行的互联网应用之一。在系统管理领域,我们常常使用邮件来发送告警信息、业务质量报表等,方便运维人员第一时间了解业务的服务状态。本节通过 Python 的 smtplib 模块来实现邮件的发送功能,模拟一个 smtp 客户端,通过与 smtp 服务器交互来实现邮件发送的功能,这可以理解成 Foxmail 的发邮件功能,在第一次使用之前我们需要配置 smtp 主机地址、邮箱账号及密码等信息,Python 2.3 或更高版本默认自带 smtplib 模块,无需额外安装。下面详细进行介绍。

smtplib 模块的常用类与方法

SMTP 类定义:smtplib.SMTP([host[, port[, local_hostname[, timeout]]]]),作为 SMTP 的构造函数,功能是与 smtp 服务器建立连接,在连接成功后,就可以向服务器发送相关请求,比如登录、校验、发送、退出等。host 参数为远程 smtp 主机地址,比如 smtp.163.com;port 为连接端口,默认为 25;local_hostname 的作用是在本地主机的 FQDN(完整的域名)发送 HELO/EHLO(标识用户身份)指令,timeout 为连接或尝试在多少秒超时。SMTP 类具有如下方法:

  • SMTP.connect([host[, port]]) 方法,连接远程 smtp 主机方法,host 为远程主机地址,port 为远程主机 smtp 端口,默认 25,也可以直接使用 host:port 形式来表示,例如:SMTP.connect("smtp.163.com","25")。

  • SMTP.login(user, password) 方法,远程 smtp 主机的校验方法,参数为用户名与密码,如 SMTP.login("python_2014@163.com","sdjkg358")。

  • SMTP.sendmail(from_addr, to_addrs, msg[, mail_options,rcpt_options]) 方法,实现邮件的发送功能,参数依次为是发件人、收件人、邮件内容,例如:SMTP.sendmail("python_2014@163.com","demo@domail.com",body),其中 body 内容定义如下:

"""From: python_2014@163.com
To: demo@domail.com
Subject: test mail
test mail body"""
  • SMTP.starttls([keyfile[, certfile]]) 方法,启用 TLS(安全传输)模式,所有 SMTP 指令都将加密传输,例如使用 gmail 的 smtp 服务时需要启动此项才能正常发送邮件,如 SMTP.starttls()。

  • SMTP.quit() 方法,断开 smtp 服务器的连接。

下面通过一个简单示例帮助大家理解,目的是使用 gmail 向 QQ 邮箱发送测试邮件,代码如下:

#!/usr/bin/python
import smtplib

HOST = "smtp.gmail.com"  # 定义smtp主机
SUBJECT = "Test email from Python"  # 定义邮件主题
TO = "testmail@qq.com"  # 定义邮件收件人
FROM = "mymail@gmail.com"  # 定义邮件发件人
text = "Python rules them all!"  # 邮件内容
BODY = str.join("\r\n", (  # 组装sendmail方法的邮件主体内容,各段以"\r\n"进行分隔
    "From: %s" % FROM,
    "To: %s" % TO,
    "Subject: %s" % SUBJECT,
    "",
    text
))

server = smtplib.SMTP()  # 创建一个SMTP()对象
server.connect(HOST, "25")  # 通过connect方法连接smtp主机
server.starttls()  # 启动安全传输模式
server.login("mymail@gmail.com", "mypassword")  # 邮箱账号登录校验
server.sendmail(FROM, [TO], BODY)  # 邮件发送
server.quit()  # 断开smtp连接

我们将收到一封这样的邮件,如图 2-5 所示。

image 2023 12 07 14 20 52 210
Figure 1. 图2-5 收到的邮件

定制个性化的邮件格式方法

通过邮件传输简单的文本已经无法满足我们的需求,比如我们时常会定制业务质量报表,在邮件主体中会包含 HTML、图像、声音以及附件格式等,MIME(Multipurpose Internet Mail Extensions,多用途互联网邮件扩展)作为一种新的扩展邮件格式很好地补充了这一点,更多 MIME 知识见 http://zh.wikipedia.org/wiki/MIME 。下面介绍几个 Python 中常用的 MIME 实现类:

  • email.mime.multipart.MIMEMultipart([_subtype[,boundary[, _subparts[, _params]]]]),作用是生成包含多个部分的邮件体的 MIME 对象,参数 _subtype 指定要添加到 "Content-type:multipart/subtype" 报头的可选的三种子类型,分别为 mixed、related、alternative,默认值为 mixed。定义 mixed 实现构建一个带附件的邮件体;定义 related 实现构建内嵌资源的邮件体;定义 alternative 则实现构建纯文本与超文本共存的邮件体。

  • email.mime.audio.MIMEAudio (_audiodata[,_subtype[, _encoder[, **_params]]]),创建包含音频数据的邮件体,_audiodata 包含原始二进制音频数据的字节字符串。

  • email.mime.image.MIMEImage(_imagedata[,_subtype[, _encoder[, **_params]]]),创建包含图片数据的邮件体,_imagedata 是包含原始图片数据的字节字符串。

  • email.mime.text.MIMEText (_text[, _subtype[,_charset]]),创建包含文本数据的邮件体,_text 是包含消息负载的字符串,_subtype 指定文本类型,支持 plain(默认值)或 html 类型的字符串。

定制常用邮件格式示例详解

前面两小节介绍了 Python 的 smtplib 及 email 模块的常用方法,那么两者在邮件定制到发送过程中是如何分工的?我们可以将 email.mime 理解成 smtplib 模块邮件内容主体的扩展,从原先默认只支持纯文本格式扩展到 HTML,同时支持附件、音频、图像等格式,smtplib 只负责邮件的投递即可。下面介绍在日常运营工作中邮件应用的几个示例。

示例1:实现HTML格式的数据报表邮件。

纯文本的邮件内容已经不能满足我们多样化的需求,本示例通过引入 email.mime 的 MIMEText 类来实现支持 HTML 格式的邮件,支持所有 HTML 元素,包含表格、图片、动画、CSS 样式、表单等。本示例使用 HTML 的表格定制美观的业务流量报表,实现代码如下:

smtplib/simple2.py
Unresolved include directive in modules/ROOT/pages/section01/ch02/ch2-03.adoc - include::example$/第二章/smtplib/simple2.py[]

代码运行结果如图2-6所示,我们将业务日志分析结果定期推送给管理员,以方便管理员了解业务的服务情况。

image 2023 12 07 14 32 04 617
Figure 2. 图2-6 示例1运行结果

示例2:实现图文格式的服务器性能报表邮件。

示例 1 通过 MIMEText 类来实现 HTML 格式的邮件,当要求包含图片数据的邮件内容时,需要引用 MIMEImage 类,若邮件主体由多个 MIME 对象组成,则同时需引用 MIMEMultipart 类来进行组装。本示例通过 MIMEText 与 MIMEImage 类的组合来实现图文格式的服务器性能报表邮件的定制,实现代码如下:

smtplib/simple3.py
Unresolved include directive in modules/ROOT/pages/section01/ch02/ch2-03.adoc - include::example$第二章/smtplib/simple3.py[]

代码运行结果如图2-7所示,我们将业务服务器性能数据定期推送给管理员,以方便管理员了解业务的服务情况。

image 2023 12 07 15 01 26 835
Figure 3. 图2-7 示例2运行结果

示例3:实现带附件格式的业务服务质量周报邮件。

本示例通过 MIMEText 与 MIMEImage 类的组合,实现图文邮件格式。另通过 MIMEText 类再定义 Content-Disposition 属性来实现带附件的邮件。我们可以利用这些丰富的特性来定制周报邮件,如业务服务质量周报。实现代码如下:

Unresolved include directive in modules/ROOT/pages/section01/ch02/ch2-03.adoc - include::example$第二章/smtplib/simple4.py[]

代码运行结果如图2-8所示,实现了发送业务服务质量周报的邮件功能。

image 2023 12 07 15 02 58 302
Figure 4. 图2-8 示例3的运行结果

参考提示