2019年7月27日 / 546次阅读 / 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。整个过程就是这样。
多个附件,就是要讲多个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不一样。亲测成功:
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对象中。以上代码所发送的附件都在当前工作路径下,亲测成功:
特别注意附件的大小,如果太大超过了你的邮件服务商的限制,在发送时,可能会出这样的错误:smtplib.SMTPDataError: (451, b'Error: queue file write error')
以上基本上把使用Python发送带附件的Email的各种情况都介绍到了。
-- EOF --
本文链接:https://www.pynote.net/archives/669
©Copyright 麦新杰 Since 2019 Python笔记