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
.mp3 audio/mpeg3
.mp4 video/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
.bz2 application/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">&nbsp;<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

参考: email.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 = "smtp.aliyun.com"
username = "u1@aliyun.com"
# 对于163邮箱使用授权码而不是密码登录
password = "xxxxxxxxxxxx" # 接收人列表
receivers = ['q1@qq.com']
# 抄送人列表
cc_list = ['q2@qq.com']
# 密送人列表
bcc_list = ['q3@qq.com']
# 主题
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 = 'smtp.163.com'
sender = 'sender@163.com' # 发件人
password = 'authorized_code' # 163邮箱的登陆授权码 # 收件人
receiver = ['qq1@qq.com', 'qq2@qq.com']
# 邮件主题
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 = "smtp.aliyun.com"
username = "u1@aliyun.com"
password = “password"
receivers = ['q1@qq.com']
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="http://www.python.org">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 = "smtp.aliyun.com"
username = "u1@aliyun.com"
password = “password"
receivers = ['q1@qq.com']
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端)包含查看邮件原文的功能,使用该功能可以很好的帮助学习。

python使用smtplib发送邮件的更多相关文章

  1. python:利用smtplib发送邮件详解

    本文转自:https://www.cnblogs.com/insane-Mr-Li/p/9121619.html 自动化测试中,测试报告一般都需要发送给相关的人员,比较有效的一个方法是每次执行完测试用 ...

  2. Python用smtplib发送邮件

    参照了下面: 1. 先随便照着试试这个: http://blog.csdn.net/zhaoweikid/article/details/1638349 2. 这个写了一个很简洁的代码,看过NO.1就 ...

  3. python smtplib发送邮件遇到的认证问题

    python的smtplib模块主要是用来发送邮件的,使用起来比较方便. 使用程序发送邮件只需要写以下几行代码就OK了: #!/usr/bin/env python import smtplib s ...

  4. python email ==> send 发送邮件 :) [smtplib, email 模块]

    关于Email的预备知识: 原贴地址:http://www.cnblogs.com/lonelycatcher/archive/2012/02/09/2343480.html ############ ...

  5. python smtplib 发送邮件简单介绍

    SMTP(Simple Mail Transfer Protocol)即简单邮件传输协议,它是一组用于由源地址到目的地址传送邮件的规则,由它来控制信件的中转方式python的smtplib提供了一种很 ...

  6. python ftplib,smtplib,poplib学习

    一.ftplib from ftplib import FTP ftpobj = FTP(IP或域名)     #实例化对象 ftpobj.login('username','passwd')  ## ...

  7. python简单的发送邮件

    python 利用smtplib来发送邮件,具体的代码如下 一. 编辑smtp_v2.py vim /home/python/smtp_v2.py #!/usr/bin/env python # -* ...

  8. Python使用SMTP发送邮件[HTML格式、送带附件]

    SMTP(Simple Mail Transfer Protocol)即简单邮件传输协议,它是一组用于由源地址到目的地址传送邮件的规则,由它来控制信件的中转方式. python的smtplib提供了一 ...

  9. python通过SMTP发送邮件失败,报错505/535

    python通过SMTP发送邮件失败:错误1:smtplib.SMTPAuthenticationError: (550, b'User has no permission')    我们使用pyth ...

随机推荐

  1. ECharts报表的使用

    知道你们懒得手打网址,给你们贴上:http://echarts.baidu.com/echarts2/ 1.下载并解压之后,找到echarts-2.2.7\build\dist\echarts-all ...

  2. Triangles 正多边形分割锐角三角形

    题目描述 已知一个圆的圆周被N个点分成了N段等长圆弧,求任意取三个点,组成锐角三角形的个数. 输入 多组数据,每组数据一个N(N <= 1000000) 输出 对于每组数据,输出不同锐角三角形的 ...

  3. localstorage检测

    localstorage检测 初来乍到,刚刚接触一个从零开始的移动wap项目,希望内容根据策略(正在思考中)在浏览器中缓存,appcache.localstorage都作为泛化知识进行了解和练习,知道 ...

  4. CUDA ---- Dynamic Parallelism

    Dynamic Parallelism 到目前为止,所有kernel都是在host端调用,GPU的工作完全在CPU的控制下.CUDA Dynamic Parallelism允许GPU kernel在d ...

  5. L224 词汇题

    Elaborate 精心的 preparations were being made for the Prime Minister’s official visit to the four forei ...

  6. koa 微信小程序 项目

    这个微信号入门, 应该能自己模仿做一个微信公众号了 另外 微信小程序开发 和 微信公众号h5嵌入 还是有区别的 h5嵌入在体验上和 微信小程序 差距还是比较大, 因为小程序直接调用了微信的原生组件, ...

  7. js 压缩 预览 上传图片

    com.js export const compressImage=function (files,fn,preCallbackFn,i) { let newfile = files.files[0] ...

  8. URL的应用

    1.对于Android来说,开发应用都会去访问服务器地址,那么就要连网,需要通过URL. 先new一个URL来获取路径,然后利用HttpURLConnection来连接并打开url,并通过get 请求 ...

  9. SUST OJ 1671: 数字拼图

    1671: 数字拼图 时间限制: 1 Sec  内存限制: 16 MB提交: 34  解决: 19[提交][状态][讨论版] 题目描述 拼图游戏即在任意一个N*N(N>1)的拼图中,会把一张完整 ...

  10. php-fpm简介

    What is PHP-FPM? PHP-FPM (FastCGI Process Manager) is an alternative PHP FastCGI implementation with ...