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. Flask初级(六)flash模板渲染

    Project name :Flask_Plan templates:templates static:static 继续上篇的模板 我们已经可以静态调用模板,包括继承模板,保证了页面的一致性,但是我 ...

  2. JS将日期转化为unix时间戳

    var str = '2008-10-09 21:35:28';//PHP中对应的UNIX时间戳为1223559328 var new_str = str.replace(/:/g,'-'); new ...

  3. <NET CLR via c# 第4版>笔记 第12章 泛型

    泛型优势: 源代码保护 使用泛型算法的开发人员不需要访问算法的源代码.(使用c++模板的泛型技术,算法的源代码必须提供给使用算法的用户) 类型安全 向List<DateTime>实例添加一 ...

  4. L233

    Betty was offended because she felt that her friends had ignored her purposefully(deliberately) at t ...

  5. Ubuntu使用Remastersys封装制作系统ISO镜像

    首先下载Remastersys的Deb软件包 链接:http://pan.baidu.com/s/1i3tYPKT 密码:qvyd 使用命令强制安装 dpkg --force-all -i remas ...

  6. Android RIL结构分析与移植

    介绍 本文档对Android RIL部分的内容进行了介绍,其重点放在了Android RIL的原生代码部分. 包括四个主题: 1.Android RIL框架介绍 2.Android RIL与 Wind ...

  7. C++ 多线程中使用cout还是printf

    在多线程的设计模式下,如果多个线程都使用cout打印信息,那么很容易出现内容交替的现象,例如下图: 代码如下: 如果把cout替换成printf,那么就不会出现这个问题,运行结果如下图: 对应代码如下 ...

  8. JQuery - Tab Control

    http://jqueryui.com/tabs/ <!doctype html> <html lang="en"> <head> <me ...

  9. 20155310 2016-2017-2 《Java程序设计》第八周学习总结

    20155310 2016-2017-2 <Java程序设计>第八周学习总结 教材学习内容总结 第十五章 通用API 通用API •日志:日志对信息安全意义重大,审计.取证.入侵检验等都会 ...

  10. 虚拟机lamp环境下,Apache配置虚拟主机

    1.在Apache配置文件中开启虚拟主机功能:即:Include etc//extra/httpd-vhosts.conf把前面的#去掉: 2.在extra目录下找到文件httpd-vhosts.co ...