如何发送带附件的Email邮件?

2019年7月27日 / 33次阅读 / Last Modified 2019年7月27日
Email

发送带附件的Email是一个很常用的功能,比如将定期导出的MySQL数据库,压缩后再用Email附件的形式发给特定的维护人员备份存档。本文介绍如何用Python实现这个功能。

本文重点在于介绍发送带附件的Email,更多关于用Python发送邮件的细节,比如抄送,密送,发给多人等等,请参考:用Python发送Email的技术

引入发送附件需要的对象

带附件的Email,需要一个MIMEMultipart对象来作为容器,里面装一个MIMEText对象代表邮件中的文字内容,再装一个MIMEBase对象来代表邮件的附件。

>>> import smtplib
>>> from email.header import Header
>>> from email.mime.text import MIMEText
>>> from email.mime.multipart import MIMEMultipart
>>> from email.mime.base import MIMEBase
>>> from email import encoders

发送一张图片附件

发送一个图片附件的示例代码如下:

>>> msg = MIMEMultipart('mixed')
>>> msg.attach(MIMEText('send email with attachment.','plain','utf-8'))
>>> attach = MIMEBase('image','jpg')  # MIME type
>>> attach.add_header('Content-Disposition','attachment',filename='logo.jpg')
>>> attach.add_header('Content-ID','<0>')
>>> attach.add_header('X-Attachment-Id','0')
>>> with open('logo.jpg','rb') as f:
...     attach.set_payload(f.read())
...
>>> encoders.encode_base64(attach)
>>> msg.attach(attach)
>>>
>>> msg['From'] = 'from@qq.com'
>>> msg['To'] = 'to@qq.com'
>>> msg['Subject'] = Header('jpeg attachment','utf-8').encode()
>>>
>>> smtp = smtplib.SMTP_SSL('smtp.qq.com')
>>> smtp.login('from@qq.com', 'password')
(235, b'Authentication successful')
>>> smtp.sendmail('from@qq.com',['to@qq.com'],msg.as_string())
{}
>>> smtp.quit()
(221, b'Bye')

先创建一个MIMEMultipart('mixed')混合对象msg,然后将一个plain的MIMEText对象添加到msg中,然后再将一个包含一张jpg图片信息的MIMEBase对象添加到msg中。此图片是同目录下的logo.jpg,ID设为0,采用rb的方式读取图片内容,然后转换成Base64编码,最后添加到msg对象。然后按常规发送Email。整个过程就是这样。

有一张图片作为附件的Email
有一张图片作为附件的Email

发送多张图片附件的Email

多个附件,就是要讲多个MIMEBase对象attach到msg。

>>> msg = MIMEMultipart('mixed')
>>> msg.attach(MIMEText('send email with more jpg attachments.','plain','utf-8')
)
>>> jpg1 = MIMEBase('image','jpg')
>>> jpg1.add_header('Content-Disposition','attachment',filename='logo.jpg')
>>> jpg1.add_header('Content-ID','<0>')
>>> jpg1.add_header('X-Attachment-Id','0')
>>> with open('logo.jpg','rb') as f:
...     jpg1.set_payload(f.read())
...
>>> encoders.encode_base64(jpg1)
>>> msg.attach(jpg1)
>>> jpg2 = MIMEBase('image','jpg')
>>> jpg2.add_header('Content-Disposition','attachment',filename='pynote.jpg')
>>> jpg2.add_header('Content-ID','<1>')
>>> jpg2.add_header('X-Attachment-Id','1')
>>> with open('pynote.jpg','rb') as f:
...     jpg2.set_payload(f.read())
...
>>> encoders.encode_base64(jpg2)
>>> msg.attach(jpg2)
>>>
>>> msg['From'] = 'from@qq.com'
>>> msg['To'] = 'to@qq.com'
>>> msg['Subject'] = Header('jpeg attachment','utf-8').encode()
>>>
>>> smtp = smtplib.SMTP_SSL('smtp.qq.com')
>>> smtp.login('from@qq.com', 'password')
(235, b'Authentication successful')
>>> smtp.sendmail('from@qq.com',['to@qq.com'],msg.as_string())
{}
>>> smtp.quit()
(221, b'Bye')

两张图片,jpg1和jpg2,注意他们的ID不一样。亲测成功:

多张图片作为附件的Email
多张图片作为附件的Email

add_header('Content-Disposition','attachment',filename='logo.jpg'),Content-disposition 是 MIME 协议的扩展,指示Email客户端如何显示附加的文件。

发送任意类型的附件

图片的MIME类型是image/jpg或image/png,如果不是图片作为附件,怎么处理呢?有哪么多不同的类型,怎么办?

>>> import mimetypes

我们用mimetypes模块提供的工具,来自动判断MIME类型。

下面这段代码,不太方便在Python解释器中调试,就放到test_email.py文件中,通过python3 test_email.py执行。这段代码,将相同目录下一大推不同类型的文件,都作为Email的附件,发送出去。

import smtplib
from email.header import Header
from email.mime.text import MIMEText
from email.mime.multipart import MIMEMultipart
from email.mime.base import MIMEBase
from email import encoders
import mimetypes

file = ['logo.jpg', 'pig.ico', 'Auto10G.zip', 'MySQL学习.pdf', 
    'Book1.xlsx', 'filelist.dat', 'setupssh.exe', 'test_url.html', 
    '程序员之软件架构.epub']

msg = MIMEMultipart('mixed')
msg.attach(MIMEText('send email with different types of attachments.',
            'plain','utf-8'))
for i in range(len(file)):
    contype, encoding = mimetypes.guess_type(file[i])
    if contype is None or encoding is not None:
        contype = 'application/octet-stream'  # default MIME type
    maintype, subtype = contype.split('/')
    att = MIMEBase(maintype,subtype)
    att.add_header('Content-Disposition','attachment',filename=file[i])
    att.add_header('Content-ID',f'<{i}>')
    att.add_header('X-Attachment-Id',f'{i}')
    with open(file[i],'rb') as f:
        att.set_payload(f.read())
    encoders.encode_base64(att)
    msg.attach(att)

msg['From'] = 'from@qq.com'
msg['To'] = 'to@qq.com'
msg['Subject'] = Header('Email with different types of attachments',
            'utf-8').encode()

smtp = smtplib.SMTP_SSL('smtp.qq.com')
smtp.login('from@qq.com','password')
smtp.sendmail('from@qq.com', 'to@qq.com', msg.as_string())
smtp.quit()

高亮那一段for循环是关键,用mimetype.guess_type来判断MIME类型,无法判断就是用默认类型,然后与之前一样的处理,最后添加到msg对象中。以上代码所发送的附件都在当前工作路径下,亲测成功:

发送带任意类型附件的Email
发送带任意类型附件的Email

特别注意附件的大小,如果太大超过了你的邮件服务商的限制,在发送时,可能会出这样的错误:smtplib.SMTPDataError: (451, b'Error: queue file write error')

以上基本上把使用Python发送带附件的Email的各种情况都介绍到了。

-- EOF --

本文链接:https://www.pynote.net/archives/669

留言区

电子邮件地址不会被公开。 必填项已用*标注


前一篇:
后一篇:

More

麦新杰的Python笔记

Ctrl+D 收藏本页


©Copyright 麦新杰 Since 2019 Python笔记

go to top