Python爱好者

使用 python 发送电子邮件

2019-02-14  本文已影响1人  远飞的大雁2010

使用 python 发送电子邮件

使用 Python 来发送邮件是一件很方便的事,有两个模块可以帮助我们完成这项任务。一个是 smtp 模块,用来发送邮件,另一个是 email 模块,用来构造邮件。

一、构造邮件

一封电子邮件,一般来说需要包含以下三部分内容:

  1. 邮件头:包括发件人、收件人、抄送、标题等内容。
  2. 正文:有两种形式,文本或超文本。
  3. 附件:附件有两种形式,一种嵌入超文本正文,另一种出现在附件列表中。

构造一封邮件我们可以按以下的步骤来操作:

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 来构建,超级简单。不过要注意的是类型有两种,一种是超文本,其 subtypehtml,还有一种是纯文本,subtypeplain。具体代码如下:

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)

参数说明:

  1. type_ 是合并类型,可以有以下几种:
    1. related:用来合并邮件正文和内嵌附件。
    2. alternative:用来合并两种纯文本和超文本两种。一般来说,我们的邮件正文要么用超文本,要么用纯文本,所以这种方式基本上用不到。
    3. mixed:用来合并邮件正文和附件。
  2. subparts是需要合并的各个部分。

合并的顺序:

  1. 先合并超文本和内嵌附件,使用 related来合并。
  2. 合并超文本和纯文本,使用 alternative来合并。
  3. 合并邮件正文和附件,使用 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 来发送电子邮件,网上的教程很多,但有少存在错误。主要是邮件的客户端太多,不同的邮件客户端的兼容性也不一样,如果不按规范来构造邮件有的客户端也会正确显示。在测试不充分的情况下,就会造成一些误解。

主要注意的事项有以下几个方面:

  1. 收件人及发件人的地址都需要格式化,否则存在中文时会显示不正确。
  2. 列表中的附件如果文件名是中文的,需要对文件名进行转码处理。
  3. 内嵌附件要有 cidContent-Disposition要设置成 inline ,并且和超文本正文合并时,要使用 related来合并。如果不这样操作,有的客户端,比如 outlook 可以在附件列表中隐藏附件,其他的客户端就很难说了。
  4. 合并各个部件的时候,注意顺序不要弄错。
上一篇 下一篇

猜你喜欢

热点阅读