python使用smtplib发送邮件
- 1、下载文档前请自行甄别文档内容的完整性,平台不提供额外的编辑、内容补充、找答案等附加服务。
- 2、"仅部分预览"的文档,不可在线预览部分如存在完整性等问题,可反馈申请退款(可完整预览的文档不适用该条件!)。
- 3、如文档侵犯您的权益,请联系客服反馈,我们会尽快为您处理(人工客服工作时间:9:00-18:30)。
python使⽤smtplib发送邮件
python要实现发送邮件的功能,需要使⽤smtplib库。
1. 过程⼤致如下:
1. 建⽴和SMTP邮件服务器的连接
# 默认端⼝25
smtp = smtplib.SMTP(host, port)
# 或者
smtp = smtplib.SMTP()
smtp.connect(host, port)
# 带SSL,默认端⼝465
smtp = smtp.SMTP_SSL()
smtp.connect(host, port)
2. 完成⾝份认证
# 对于163⽽⾔,第三⽅客户端登陆使⽤的是授权码⽽不是密码
smtp.login(username, password)
3. 发送邮件(必须明确发件⼈、收件⼈、主题、内容,⽽抄送⼈、密送⼈、附件、内嵌式图⽚等资源是可选的)
smtp.sendmail(from_addr, to_addrs, msg, mail_options=[], rcpt_options=[])
4. 结束会话
smtp.quit()
2. MIME相关知识介绍
MIME全称Multipurpose Internet Mail Extensions(多⽤途互联⽹邮件扩展)。
是⼀个互联⽹标准,它扩展了电⼦邮件标准,使其能够⽀持:
⾮ASCII字符⽂本;
⾮⽂本格式附件(⼆进制、声⾳、图像等);
由多部分(multiple parts)组成的消息体;
包含⾮ASCII字符的头信息(Header information)
此外,web中使⽤的HTTP协议也使⽤了MIMIE的框架,标准被扩展为。
MIME头部信息:
MIME版本: ⽬前版本1.0
MIME-Version: 1.0
内容类型(Content-Type),⽤于指定消息类型。
形式如下:
Content-Type: [type]/[subtype]; parameter
type有以下形式:
Text: ⽂本消息,可以使⽤charset参数指定字符集;
Multipart: ⽤于连接消息体的多个部分构成⼀个消息,这些部分可以是不同类型的数据;
Application:⽤于传输应⽤程序数据或者⼆进制数据;
Message:⽤于包装⼀个E-mail消息;
Image:⽤于传输静态图⽚数据;
Audio:⽤于传输⾳频数据;
Video:⽤于传输动态影像数据,可以是与⾳频编辑在⼀起的视频数据格式
常见的⽂件扩展名与Content-Type对应关系如下:
⽂件扩展名Content-Type
.txt text/plain
.html text/html
.xhtml application/xhtml+xml
.css text/css
.js application/javascript
.xml application/atom+xml
.json application/json
.jpg image/jpeg
.png image/png
.gif image/gif
.mp3audio/mpeg3
.mp4video/mp4
.wav audio/wav
.avi video/avi
.doc application/msword
.docx application/vnd.openxmlformats-officedocument.wordprocessingml.document
.xls application/vnd.ms-excel
.xlsx application/vnd.openxmlformats-officedocument.spreadsheetml.sheet
.ppt application/vnd.ms-powerpoint
.pptx application/vnd.openxmlformats-officedocument.presentationml.presentation
.pdf application/pdf
.rar application/x-rar-compressed
.zip application/x-compressed
.tar application/x-tar
.gz application/x-compressed
.bz2application/x-bzip2
表⽰任意⼆进制数据application/octet-stream
使⽤HTTP的POST⽅法提交表单application/x-www-form-urlencoded
主要⽤于表单提交时伴随⽂件上传的场合multipart/form-data
Text默认是text/plain,Application默认是application/octet-stream⽽Multipart默认情况下被看作multipart/mixed。
内容传输编码(Content-Transfer-Encoding)
Content-Transfer-Encoding: [mechanism]
其中,mechanism的值可以指定为“7bit”,“8bit”,“binary”,“quoted-printable”,“base64”
MIME信息剖析
⼀封普通的⽂本邮件的信息包含⼀个头部分(例如:From、To、Subject 等等)和⼀个体部分。
体部分通常为单体类型(例如:text、image、audio、video、application 等等)或是复合类型(即:multipart)。
头部分和体部分之间⽤⼀个空⾏进⾏分隔,并且体部分的类型由信头内容类型字段Content-Type 描述。
信头含义 (Headers)
域名含义
Content-Type内容的类型
MIME-Version MIME 版本
域名含义
Content-Transfer-Encoding内容的传输编码⽅式
From发件⼈地址
To收件⼈地址
Cc抄送地址
Bcc暗送地址
Date⽇期和时间
Subject主题
Received传输路径
Return-Path回复地址
Delivered-To发送地址
Reply-To回复地址
Message-ID消息 ID
信体部分
邮件中常见的简单类型有 text/plain(纯⽂本)和 text/html(超⽂本)。
复杂的邮件内容格式采⽤ multipart 类型,可以包括纯⽂本/超⽂本(alternative)、内嵌资源(图⽚)(related)、附件类型(mixed)等等。
multipart 类型的邮件体被分为多个段,每个段⼜包含段头和段体两部分,这两部分之间也以空⾏分隔。
信体头含义
域名含义
Content-Type段体的类型
Content-Transfer-Encoding段体的传输编码⽅式
Content-Disposition段体的位置,内嵌(inline)或附件(attachment)
Content-ID段体的 ID, 唯⼀标识
Content-Location段体的位置(路径)
Content-Base段体的基位置
常见的 multipart 类型有三种:multipart/mixed, multipart/related 和 multipart/alternative。
复合类型层次关系⽰例图:
multipart 诸类型的共同特征是,在段头指定 boundary 参数字符串,段体内的每个⼦段以此字符串定界。
所有的⼦段都以 --boundary ⾏开始,⽗段则以 --boundary-- ⾏结束。
段与段之间也以空⾏分隔。
例⼦:
1) 发送纯⽂本⽂件:
Content-Type: text/plain; charset="UTF-8"
Content-Transfer-Encoding: base64
aGVsbG8gd29ybGQK5L2g5aW95LiW55WM
2)发送包含富⽂本的邮件:
Content-Type: multipart/alternative;
boundary="----=ALIBOUNDARY_14343_4f941940_5a9a0b10_90106"
------=ALIBOUNDARY_14343_4f941940_5a9a0b10_90106
Content-Type: text/plain; charset="UTF-8"
Content-Transfer-Encoding: base64
aGVsbG8gd29ybGTkvaDlpb3kuJbnlYw=
------=ALIBOUNDARY_14343_4f941940_5a9a0b10_90106
Content-Type: text/html; charset="UTF-8"
Content-Transfer-Encoding: base64
PGRpdiBjbGFzcz0iX19hbGl5dW5fZW1haWxfYm9keV9ibG9jayI+PGRpdiAgc3R5bGU9ImNsZWFy
OmJvdGg7Ij48c3BhbiAgc3R5bGU9ImZvbnQtZmFtaWx5OlRhaG9tYSxBcmlhbCxTVEhlaXRpLFNp
bVN1bjtmb250LXNpemU6MTQuMHB4O2NvbG9yOiMwMDAwMDA7Ij5oZWxsbyB3b3JsZDwvc3Bhbj48
L2Rpdj48ZGl2ICBzdHlsZT0iY2xlYXI6Ym90aDsiPjxzcGFuICBzdHlsZT0iZm9udC1mYW1pbHk6
VGFob21hLEFyaWFsLFNUSGVpdGksU2ltU3VuO2NvbG9yOiMwMDAwMDA7YmFja2dyb3VuZC1jb2xv
cjojZmYwMDAwO2ZvbnQtc2l6ZTozMi4wcHg7Ij7kvaDlpb3kuJbnlYw8L3NwYW4+PC9kaXY+PC9k
aXY+
------=ALIBOUNDARY_14343_4f941940_5a9a0b10_90106--
”aGVsbG8gd29ybGTkvaDlpb3kuJbnlYw=" base64前明⽂:
hello world你好世界
"
PGRpdiBjbGFzcz0iX19hbGl5dW5fZW1haWxfYm9keV9ibG9jayI+PGRpdiAgc3R5bGU9ImNsZWFy
OmJvdGg7Ij48c3BhbiAgc3R5bGU9ImZvbnQtZmFtaWx5OlRhaG9tYSxBcmlhbCxTVEhlaXRpLFNp
bVN1bjtmb250LXNpemU6MTQuMHB4O2NvbG9yOiMwMDAwMDA7Ij5oZWxsbyB3b3JsZDwvc3Bhbj48
L2Rpdj48ZGl2ICBzdHlsZT0iY2xlYXI6Ym90aDsiPjxzcGFuICBzdHlsZT0iZm9udC1mYW1pbHk6
VGFob21hLEFyaWFsLFNUSGVpdGksU2ltU3VuO2NvbG9yOiMwMDAwMDA7YmFja2dyb3VuZC1jb2xv
cjojZmYwMDAwO2ZvbnQtc2l6ZTozMi4wcHg7Ij7kvaDlpb3kuJbnlYw8L3NwYW4+PC9kaXY+PC9k
aXY+" 明⽂:
<div class="__aliyun_email_body_block"><div style="clear:both;"><span style="font-family:Tahoma,Arial,STHeiti,SimSun;font-size:14.0px;color:#000000;">hello world</span></div> <div style="clear:both;"><span style="font-family:Tahoma,Arial,STHeiti,SimSun;color:#000000;background-color:#ff0000;font-size:32.0px;">你好世界</span></div></div>
3) 将图⽚内嵌:
Content-Type: multipart/related;
boundary="----=ALIBOUNDARY_25467_4f851940_5a9a032e_8ff9d"
------=ALIBOUNDARY_25467_4f851940_5a9a032e_8ff9d
Content-Type: multipart/alternative;
boundary="----=ALIBOUNDARY_25467_4f851940_5a9a032e_8ff9e"
------=ALIBOUNDARY_25467_4f851940_5a9a032e_8ff9e
Content-Type: text/plain; charset="UTF-8"
Content-Transfer-Encoding: base64
6L+Z5pivcHl0aG9u55qEbG9nb8KgCg==
------=ALIBOUNDARY_25467_4f851940_5a9a032e_8ff9e
Content-Type: text/html; charset="UTF-8"
Content-Transfer-Encoding: base64
PGRpdiBjbGFzcz0iX19hbGl5dW5fZW1haWxfYm9keV9ibG9jayI+PGRpdiAgc3R5bGU9ImNsZWFy
OmJvdGg7Ij48c3BhbiAgc3R5bGU9ImZvbnQtZmFtaWx5OlRhaG9tYSxBcmlhbCxTVEhlaXRpLFNp
bVN1bjtmb250LXNpemU6MTQuMHB4O2NvbG9yOiMwMDAwMDA7Ij7ov5nmmK9weXRob27nmoRsb2dv
PC9zcGFuPjwvZGl2PjxkaXYgIHN0eWxlPSJjbGVhcjpib3RoOyI+PHNwYW4gIHN0eWxlPSJmb250
LWZhbWlseTpUYWhvbWEsQXJpYWwsU1RIZWl0aSxTaW1TdW47Zm9udC1zaXplOjE0LjBweDtjb2xv
cjojMDAwMDAwOyI+PGltZyAgc3JjPSJjaWQ6X19hbGl5dW4xNTIwMDQyNzk4MjEzOTg3MjEiPiZu
YnNwOzxiciA+PC9zcGFuPjwvZGl2PjwvZGl2Pg==
------=ALIBOUNDARY_25467_4f851940_5a9a032e_8ff9e--
------=ALIBOUNDARY_25467_4f851940_5a9a032e_8ff9d
Content-Type: application/octet-stream
Content-ID: <__aliyun152004279821398721>
Content-Disposition: inline; filename="=?UTF-8?B?cHl0aG9uLWxvZ28ucG5n?="
Content-Transfer-Encoding: base64
下⾯多⾏是图⽚⼆进制数据base64编码后的数据
xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx
------=ALIBOUNDARY_25467_4f851940_5a9a032e_8ff9d--
"6L+Z5pivcHl0aG9u55qEbG9nb8KgCg==" 是经过base64编码后的数据,明⽂为:
这是python的logo
"
PGRpdiBjbGFzcz0iX19hbGl5dW5fZW1haWxfYm9keV9ibG9jayI+PGRpdiAgc3R5bGU9ImNsZWFy
OmJvdGg7Ij48c3BhbiAgc3R5bGU9ImZvbnQtZmFtaWx5OlRhaG9tYSxBcmlhbCxTVEhlaXRpLFNp
bVN1bjtmb250LXNpemU6MTQuMHB4O2NvbG9yOiMwMDAwMDA7Ij7ov5nmmK9weXRob27nmoRsb2dv
PC9zcGFuPjwvZGl2PjxkaXYgIHN0eWxlPSJjbGVhcjpib3RoOyI+PHNwYW4gIHN0eWxlPSJmb250 LWZhbWlseTpUYWhvbWEsQXJpYWwsU1RIZWl0aSxTaW1TdW47Zm9udC1zaXplOjE0LjBweDtjb2xv
cjojMDAwMDAwOyI+PGltZyAgc3JjPSJjaWQ6X19hbGl5dW4xNTIwMDQyNzk4MjEzOTg3MjEiPiZu
YnNwOzxiciA+PC9zcGFuPjwvZGl2PjwvZGl2Pg==" 明⽂为:
<div class="__aliyun_email_body_block"><div style="clear:both;"><span style="font-family:Tahoma,Arial,STHeiti,SimSun;font-size:14.0px;color:#000000;">
这是python的logo</span></div><div style="clear:both;"><span style="font-family:Tahoma,Arial,STHeiti,SimSun;font-size:14.0px;color:#000000;">
<img src="cid:__aliyun152004279821398721"> <br ></span></div></div>
4) 发送带附件的邮件
Content-Type: multipart/mixed;
boundary="----=ALIBOUNDARY_68661_4cbc5940_5a9a0f2a_90709"
This is a multi-part message in MIME format.
------=ALIBOUNDARY_68661_4cbc5940_5a9a0f2a_90709
Content-Type: multipart/alternative;
boundary="----=ALIBOUNDARY_68661_4cbc5940_5a9a0f2a_9070a"
------=ALIBOUNDARY_68661_4cbc5940_5a9a0f2a_9070a
Content-Type: text/plain; charset="UTF-8"
Content-Transfer-Encoding: base64
5Y+R6YCB6ZmE5Lu25rWL6K+V
------=ALIBOUNDARY_68661_4cbc5940_5a9a0f2a_9070a
Content-Type: text/html; charset="UTF-8"
Content-Transfer-Encoding: base64
PGRpdiBjbGFzcz0iX19hbGl5dW5fZW1haWxfYm9keV9ibG9jayI+PGRpdiAgc3R5bGU9ImNsZWFy
OmJvdGg7Ij48c3BhbiAgc3R5bGU9ImZvbnQtZmFtaWx5OlRhaG9tYSxBcmlhbCxTVEhlaXRpLFNp
bVN1bjtmb250LXNpemU6MTQuMHB4O2NvbG9yOiMwMDAwMDA7Ij7lj5HpgIHpmYTku7Y8c3BhbiAg
c3R5bGU9ImNvbG9yOiMwMDAwMDA7Zm9udC1mYW1pbHk6VGFob21hLEFyaWFsLFNUSGVpdGksU2lt
U3VuO2ZvbnQtc2l6ZToxNC4wcHg7Zm9udC1zdHlsZTpub3JtYWw7Zm9udC12YXJpYW50LWxpZ2F0
dXJlczpub3JtYWw7Zm9udC12YXJpYW50LWNhcHM6bm9ybWFsO2ZvbnQtd2VpZ2h0OjQwMDt0ZXh0
LWFsaWduOnN0YXJ0O3RleHQtaW5kZW50Oi4wcHg7dGV4dC10cmFuc2Zvcm06bm9uZTt3aWRvd3M6
MjtiYWNrZ3JvdW5kLWNvbG9yOiNmZmZmZmY7dGV4dC1kZWNvcmF0aW9uLXN0eWxlOmluaXRpYWw7
dGV4dC1kZWNvcmF0aW9uLWNvbG9yOmluaXRpYWw7ZmxvYXQ6bm9uZTtkaXNwbGF5OmlubGluZTsi
Pua1i+ivlTwvc3Bhbj48L3NwYW4+PC9kaXY+PC9kaXY+
------=ALIBOUNDARY_68661_4cbc5940_5a9a0f2a_9070a--
------=ALIBOUNDARY_68661_4cbc5940_5a9a0f2a_90709
Content-Type: application/octet-stream
Content-Disposition: attachment; filename="=?UTF-8?B?5L2g5aW9d29ybGQudHh0?="
Content-Transfer-Encoding: base64
aGVsbG8gd29ybGQNCsTjusPKwL3n
------=ALIBOUNDARY_68661_4cbc5940_5a9a0f2a_90709--
multipart/alternative:
在同时提供多种消息格式,这些消息格式间是相互可替换的,如提供同⼀消息的多语⾔版本。
multipart/related:
添加内嵌资源时必须指定的Content-Type类型,通常配合Content-ID使⽤。
Content-ID头字段⽤于为“multipart/related” 组合消息中的内嵌资源指定⼀个唯⼀的标识符。
在html格式的正⽂中使⽤这个唯⼀标识号来引⽤该内嵌资源。
格式如下:
<img src="cid:CONTENTID" />
# CONTENTID⽤具体的数值替换
multipart/mixed:
添加附件时必须指定的Content-Type类型, 配合Content-Disposition来获取上⽂⽂件的名称。
Content-Disposition: attachment; filename=”上传⽂件的⽂件名"
# ⼀般中⽂⽂件名都需要base64编码
# 以python_logo.png为例,base64编码后变为: cHl0aG9uX2xvZ28ucG5n
# 最后结果为: =?UTF-8?B?cHl0aG9uLWxvZ28ucG5n?=
3. python中的MIME
参考:
MIMENonMultipart 作为中间类,主要⽤途是防⽌调⽤attach()⽅法
MIMEMultipart 与Conent-Type中的multipart对应,默认类型为multipart/mixed
MIMEApplication与Content-Type中的application对应,默认类型为application/octed-stream,默认编码类型为base64
MIMEText与Content-Type中的text对应,默认类型为text/plain。
⾝份认证发⽣错误:
smtplib.SMTPAuthenticationError: (535, 'Error: authentication failed')
原因分析:⽹易163邮箱需要启⽤授权码,并且使⽤授权码登录,⽽不是密码登录
1. 发送纯⽂本
import smtplib
from email.mime.text import MIMEText
from email.header import Header
host = ""
username = "u1@"
# 对于163邮箱使⽤授权码⽽不是密码登录
password = "xxxxxxxxxxxx"
# 接收⼈列表
receivers = ['q1@']
# 抄送⼈列表
cc_list = ['q2@']
# 密送⼈列表
bcc_list = ['q3@']
# 主题
subject = "阿⾥邮箱给qq邮箱发信"
# 正⽂
body = "Python 发送邮件测试"
sender = username
# 邮件正⽂
message = MIMEText(body, 'plain', 'utf-8')
# 发件⼈
message['From'] = sender
# 收件⼈
message['To'] = ",".join(receivers) # 多个接收⼈之间要⽤逗号隔开
# 抄送⼈
message['Cc'] = ','.join(cc_list)
# 密送⼈
message['Bcc'] = ','.join(bcc_list)
# 主题
message['Subject'] = Header(subject, "utf-8")
try:
smtp = smtplib.SMTP()
smtp.set_debuglevel(1) # 开启调试,⽅便观察和邮件服务器通信全过程
smtp.connect(host) # 默认端⼝是25
# 登陆
smtp.login(username, password)
# 发送邮件
# 邮件服务器在转发邮件的过程中,省略了Bcc项
# To: Cc: Bcc: 只是⼀种表现形式,归根结底都是邮件的接收者,都需要服务器发送RCPT TO:来告知邮件服务器发送给谁。
# 因此接收者列表应该是收件⼈、抄送⼈、密送⼈的集合。
smtp.sendmail(sender, receivers + cc_list + bcc_list, message.as_string())
smtp.quit()
except smtplib.SMTPException as e:
print("error: ", e)
案例: 将磁盘使⽤情况以邮件的形式发送
# coding=utf-8
import smtplib
import subprocess
def send_email(smtp_server, sender, passwd, receiver_list, subject, content):
receiver = receiver_list
if isinstance(receiver_list, list):
receiver = ",".join(receiver_list) # 多个收件⼈之间⽤,隔开
# 注意主题和正⽂中有⼀个空⾏
msg = '\r\n'.join([
'From: %s' % sender,
'To: %s' % receiver,
'Subject: %s' % subject,
'',
content
])
try:
s = smtplib.SMTP()
# 连接smtp服务器
s.connect(smtp_server)
# 登陆 对于163邮箱,使⽤授权码⽽不是密码登陆第三⽅邮件客户端
s.login(sender, passwd)
# 发送邮件
s.sendmail(sender, receiver_list, msg)
print'success'
s.quit()
except Exception as e:
print e
# 发送邮件测试
def send_email_test():
smtp_server = ''
sender = 'sender@'# 发件⼈
password = 'authorized_code'# 163邮箱的登陆授权码
# 收件⼈
receiver = ['qq1@', 'qq2@']
# 邮件主题
subject = 'Disk Usage Report'
p = subprocess.Popen('df -h', shell=True, stdout=subprocess.PIPE)
content = p.stdout.read() # 获取磁盘使⽤情况
send_email(smtp_server, sender, password, receiver, subject, content)
2. 发送富⽂本邮件
host = ""
username = "u1@"
password = “password"
receivers = ['q1@']
subject = "python发送html"
sender = username
# 类型为alternative
message = MIMEMultipart("alternative")
message['From'] = sender
message['To'] = ",".join(receivers) # 多个接收⼈之间要⽤逗号隔开
message['Subject'] = Header(subject, "utf-8")
# 正⽂有两部分
part1 = MIMEText("<h1>使⽤python发送邮件</h1>", "html", "utf-8")
part2 = MIMEText('<a href="">python官⽹</a>', "html", "utf-8") message.attach(part1)
message.attach(part2)
3. 发送带附件的邮件
import os
import smtplib
from email.mime.text import MIMEText
from email.mime.multipart import MIMEMultipart
from email.header import Header
from email.mime.application import MIMEApplication
def add_attchment(message, file):
"""添加附件
:param message: MIMEMultipart对象
:param file: file为⽂件的路径
:return: None
"""
filename = os.path.basename(file) # 获取⽂件名
with open(file, "rb") as f:
attachment = MIMEApplication(f.read())
attachment.add_header(
"Content-Disposition",
"attachment",
filename=(
"gbk", # 指定编码格式, qq邮箱对邮件使⽤gbk编码,否则可能会出现⽂件名乱码
"",
filename))
message.attach(attachment)
host = ""
username = "u1@"
password = “password"
receivers = ['q1@']
subject = "python发送附件"
sender = username
# 发送附件,Content-Type必须为multipart/mixed
message = MIMEMultipart("mixed")
message['From'] = sender
message['To'] = ",".join(receivers) # 多个接收⼈之间要⽤逗号隔开
message['Subject'] = Header(subject, "utf-8")
# 添加正⽂
body = MIMEText("测试发送附件", "html", "utf-8")
message.attach(body)
# 添加附件
add_attchment(message, "百度logo.jpg")
add_attchment(message, "测试.txt")
add_attchment(message, "测试.xlsx")
4. 发送带内嵌图⽚的邮件
def get_base64name(file):
"""
:param file: ⽂件路径
:return: 返回base64编码的⽂件名
"""
filename = os.path.basename(file)
base64name = base64.b64encode(filename.encode('utf-8'))
filename = (str(base64name))[2:-1]
return filename
def add_nested_picture(message, msgalternative, file):
"""
向邮件中嵌⼊图⽚
"""
# 将base64编码的⽂件名作为cid
cid = get_base64name(file)
link = MIMEText('<img src="cid:%s" />' % cid, "html", "utf-8")
msgalternative.attach(link)
with open(file, "rb") as f:
nested_picture = MIMEApplication(f.read())
nested_picture.add_header("Content-ID", cid)
# 下⾯这⼀⾏可以省略
nested_picture.add_header("Content-Disposition", "inline", filename=("gbk", "", os.path.basename(file)))
message.attach(nested_picture)
sender = username
# 指定类型为multipart/related
message = MIMEMultipart("related")
message['From'] = sender
message['To'] = ",".join(receivers) # 多个接收⼈之间要⽤逗号隔开
message['Subject'] = Header(subject, "utf-8")
msgalternative = MIMEMultipart("alternative")
message.attach(msgalternative)
# 添加正⽂
body = MIMEText("测试发送含有内嵌图⽚的邮件", "html", "utf-8")
msgalternative.attach(body)
add_nested_picture(message, msgalternative, "C:/users/hupeng/pictures/lena.jpg")
层次结果:
⾥层: 类型为multipart/alternative的MIMEMultipart对象attach 装载html⽂本的MIMEText对象。
外层: 类型为multipart/related的MIMEMultipart对象 attach 表⽰内嵌资源的MIMEApplication对象和表⽰⽂本信息类型为mulitpart/alternative的MIMEMultipart对象。
当然也可以直接使⽤类型为multipart/mixed类型的对象attach 表⽰html⽂本的MIME对象和表⽰内嵌资源的MIMEApplication对象
代码如下:
def get_base64name(file):
"""
:param file: ⽂件路径
:return: 返回base64编码的⽂件名
"""
filename = os.path.basename(file)
base64name = base64.b64encode(filename.encode('utf-8'))
filename = (str(base64name))[2:-1]
return filename
def add_nested_picture(message, file):
"""
向邮件中嵌⼊图⽚
"""
# 将base64编码的⽂件名作为cid
cid = get_base64name(file)
link = MIMEText('<img src="cid:%s" />' % cid, "html", "utf-8")
message.attach(link)
with open(file, "rb") as f:
nested_picture = MIMEApplication(f.read())
nested_picture.add_header("Content-ID", cid)
message.attach(nested_picture)
sender = username
# 指定最外层信息段类型为multipart/mixed
message = MIMEMultipart("mixed")
message['From'] = sender
message['To'] = ",".join(receivers) # 多个接收⼈之间要⽤逗号隔开
message['Subject'] = Header(subject, "utf-8")
# 添加正⽂
body = MIMEText("测试发送含有内嵌图⽚的邮件", "html", "utf-8")
message.attach(body)
# 添加嵌⼊式图⽚
add_nested_picture(message, "百度logo.jpg")
备注: 邮件客户端(web端)包含查看邮件原⽂的功能,使⽤该功能可以很好的帮助学习。