使用 python 发送电子邮件
使用 python 发送电子邮件
使用 Python 来发送邮件是一件很方便的事,有两个模块可以帮助我们完成这项任务。一个是 smtp
模块,用来发送邮件,另一个是 email
模块,用来构造邮件。
一、构造邮件
一封电子邮件,一般来说需要包含以下三部分内容:
- 邮件头:包括发件人、收件人、抄送、标题等内容。
- 正文:有两种形式,文本或超文本。
- 附件:附件有两种形式,一种嵌入超文本正文,另一种出现在附件列表中。
构造一封邮件我们可以按以下的步骤来操作:
1.处理附件
1.1 添加附件列表中的附件。附件可以有各种各样的格式,我们可以根据附件的不同,使用不用的 MIME 来进行包装。如图片可以使用 MIMEImage
来包装,音频文件可以使用 MIMEAudio
来进行包装,当然也可以全部使用 MIMEApplication
来进行包装。
在添加附件的时候,我们为这个 MIME 通过添加Content-Disposition
来指定附件的类型以及文件名。
msg.add_header('Content-Disposition','attachment',filename=encode(file.name))
需要注意的是:文件名是中文件的话需要进行转码。转码的方法如下:
def encode(filename):
return Charset('utf8').header_encode(filename) \
if any(map(lambda x: ord(x) > 127, filename))else filename
1.2 添加内嵌附件的方法和上面一样,只不过每个文件需要指定一个 cid
,以便在超文邮件正文中使用。具体代码如下:
msg.add_header('Content-Disposition', 'inline',filename=encode(file.name))
msg.add_header('Content-ID', f'<{cid}>')
msg.add_header('X-Attachment-Id', cid)
2.构建邮件正文
邮件正文使用 MIMEText
来构建,超级简单。不过要注意的是类型有两种,一种是超文本,其 subtype
为html
,还有一种是纯文本,subtype
为 plain
。具体代码如下:
subtype = 'html' if body.startswith('<html>') else 'plain'
msg = MIMEText(body, subtype, 'utf-8')
3.邮件合并
通过上面的步骤,邮件的各个部分都已经构建好了,接下来我们要对邮件的各个部分进行合并。合并是通过 MIMEMultipart
来实现的。为了简化处理,我们可以先定义一个合并函数来完成。
def combine(type_='mixed', *subparts):
return MIMEMultipart(type_, _subparts=subparts)
参数说明:
-
type_ 是合并类型,可以有以下几种:
- related:用来合并邮件正文和内嵌附件。
- alternative:用来合并两种纯文本和超文本两种。一般来说,我们的邮件正文要么用超文本,要么用纯文本,所以这种方式基本上用不到。
- mixed:用来合并邮件正文和附件。
- subparts是需要合并的各个部分。
合并的顺序:
- 先合并超文本和内嵌附件,使用
related
来合并。 - 合并超文本和纯文本,使用
alternative
来合并。 - 合并邮件正文和附件,使用
mixed
来合并。
具体代码如下:
body = self.body
subtype = 'html' if body.startswith('<html>') else 'plain'
msg = MIMEText(body, subtype, 'utf-8')
if self.inline_attachments:
msg = combine('related', msg, *self.inline_attachments)
if self.attachments:
msg = combine('fixed', msg, *self.attachments)
4. 添加邮件头
邮件的各部分合并完成后,就需要添加邮件头了。需要注意的是,邮件头的各种地址列表都需要格式化。格式化的方法如下:
from email.utils import getaddresses, formataddr
def fmtaddr(addrs):
return ';'.join(map(formataddr, getaddresses([addrs])))
完整设置邮件头的代码如下:
msg.add_header('Subject', self.subject)
for name in ('sender', 'to', 'cc', 'bcc'):
val = getattr(self, name)
if val:
msg.add_header(name.capitalize(), fmtaddr(val))
通过上面的步骤,一封完整的邮件就构造好了。
二、发送邮件
发送邮件就超级简单了。连接邮件服务器后进行登录,然后就可以发邮件了。
其代码如下:
import smtplib
with smtplib.SMTP(host)as smtp:
smtp.login(user,passwd)
smtp.send_message(msg)
三、要点提示
用 Python 来发送电子邮件,网上的教程很多,但有少存在错误。主要是邮件的客户端太多,不同的邮件客户端的兼容性也不一样,如果不按规范来构造邮件有的客户端也会正确显示。在测试不充分的情况下,就会造成一些误解。
主要注意的事项有以下几个方面:
- 收件人及发件人的地址都需要格式化,否则存在中文时会显示不正确。
- 列表中的附件如果文件名是中文的,需要对文件名进行转码处理。
- 内嵌附件要有
cid
,Content-Disposition
要设置成inline
,并且和超文本正文合并时,要使用related
来合并。如果不这样操作,有的客户端,比如 outlook 可以在附件列表中隐藏附件,其他的客户端就很难说了。 - 合并各个部件的时候,注意顺序不要弄错。