python中邮件发送可以使用smtplib
模块,也可以使用第三方的yagmail
模块。
邮件收发简介
假如从xx@126.com
发送一份邮件至xx@sina.com
。首先使用Foxmail
等软件写好邮件发送,这些软件称为MUA(Mail User Agent,邮件用户代理)。
邮件从MUA发出去之后,先发到MTA(Mail Transfer Agent,邮件传输代理),也就是邮件服务提供商。我们的邮件是从126.com
发送的,所以先被投递到网易提供的MTA,再由网易的MTA发到对方服务商,也就是新浪的MTA。
邮件到达新浪的MTA后,由于对方使用的是新浪的邮箱,因此新浪的MTA会将邮件投递至最终的目的地MDA(Mail Delivery Agent,邮件投递代理)。
邮件到达MDA之后就会存放在某个服务器,我们将这个长期保存邮件的地方称为电子邮箱。
编写程序发送邮件本质就是编写MUA把邮件发送到MTA;收取邮件就是编写MUA从MDA收邮件。
发邮件时,MUA和MTA使用额协议就是SMTP
(Simple Mail Transfer Protocol),后面的MTA到另一个MTA也是使用SMTP协议。
收邮件时,MUA和MDA使用的协议有两种,POP
(Post Office Protocol),目前版本是3,称为POP3
。IMAP
(Internet Message Access Protocol)目前版本是4,优点是不但能收取邮件,还可以直接操作MDA上存储的邮件,比如从收件箱移动到垃圾箱等。
另外使用python发送邮件时需要注意:
- 大多数邮件服务商需要手动打开SMTP发信和POP收信功能。否则只能网页登录。
- 邮件客户端大多数要求使用客户端授权密码,而不是邮箱密码。需要网页登录设置。
smtplib
python对SMTP支持的有smtplib
和email
2个模块,其中email
负责构造邮件,smtplib
负责发送邮件。
email构造邮件
邮件构造主要使用email.mime
。
- 纯文本邮件
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22from email import encoders
from email.header import Header
from email.mime.text import MIMEText
from email.utils import parseaddr, formataddr
def _format_addr(s):
name, addr = parseaddr(s)
return formataddr((Header(name, 'utf-8').encode(), addr))
msg_from='XXXXX@163.com'
passwd='XXXXX'
msg_to='XXXXX@qq.com'
receivers = ['XXXXX@qq.com']
subject="python邮件测试"
content="hello, send by Python..."
msg = MIMEText(content,'plain','utf-8')
msg['Subject'] = Header(subject,'utf-8').encode()
msg['From'] = _format_addr('xiaohh <%s>' %msg_from) #此处xiaohh表示发件人的昵称
msg['To'] = msg_to
msg = MIMEText(content, 'plain', 'utf-8')
_format_addr()
用于格式化邮件地址。如果包含中文,需要通过Header
对象进行编码
构造MIMEText
对象时,第一个参数是邮件正文,第二个参数是MIME的subtype,传入plain
表示文本,最终的MIME就是text/plain
,最后使用utf-8
编码。msg['T0']
接受的是字符串而不是列表,若有多个地址可使用,
分隔。
HTML邮件
在构造MIMEText
对象时,把html字符串传进去,再把第二个参数由plain
变为html
。1
2
3
4content = ''<html><body><h1>Hello</h1>' +
'<p>send by <a href="http://www.python.org">Python</a>...</p>' +
'</body></html>''
msg = MIMEText(content, 'plain', 'utf-8')发送附件
带附件的邮件可以看做包含若干部分的邮件:文本和各个附件本身,可以构造一个MIMEMultipart
对象代表邮件本身,然后往里面添加MIMEText
作为邮件正文,再继续往里面加上表示附件的MIMEBase
对象即可。1
2
3
4
5
6
7
8
9
10msg = MIMEMultipart()
msg.attach(MIMEText('send with file...', 'plain', 'utf-8')) #邮件正文
with open('/Users/michael/Downloads/test.png', 'rb') as f:
mime = MIMEBase('image', 'png', filename='test.png') # 设置附件的MIME和文件名,这里是png类型
mime.add_header('Content-Disposition', 'attachment', filename='test.png') # 加上必要的头信息
mime.add_header('Content-ID', '<0>')
mime.add_header('X-Attachment-Id', '0')
mime.set_payload(f.read()) # 把附件的内容读进来
encoders.encode_base64(mime) # 用Base64编码
msg.attach(mime) # 添加到MIMEMultipart发送图片
要想把图片嵌入到邮件正文中,直接在HTML邮件中链接图片地址是不可行的,因为邮件服务商无法确定链接是否指向恶意网站。
要把图片嵌入到正文中,需要按照发送附件的方式,先把图片作为附件添加进去,然后在HTML中通过引用src="cid:0"
就可以把附件作为图片嵌入。如果有多个图片,给它们依次编号,然后引用不同的cid:x
即可。1
2
3msg.attach(MIMEText('<html><body><h1>Hello</h1>' +
'<p><img src="cid:0"></p>' +
'</body></html>', 'html', 'utf-8'))
关于email.mime
更多的说明可以点击email.mime: Creating email and MIME objects from scratch查看官方介绍。
关于email
邮件构造和解析更多的说明可以点击email — An email and MIME handling package查看官方介绍。
smtplib发送邮件
smtplib
发送邮件,实例化SMTP()
,指定smtp_server地址和端口号;
调用logine()
方法登录SMTP服务器;
调用sendmail()
方法发邮件。1
2
3
4
5
6import smtplib
server = smtplib.SMTP(smtp_server, 25) # SMTP协议默认端口是25
server.login(from_addr, password)
server.sendmail(from_addr, [to_addr], msg.as_string())
server.quit()
由于邮件正文是str
,所以msg.as_string()
是将MIMEText
对象变成str
。
- 加密SMTP
使用25端口连接SMTP服务器时使用的是明文传输,要更安全的发送邮件,可以加密SMTP会话。
starttls()
1
2
3
4
5server = smtplib.SMTP('smtp.gmail.com', 587) # gmail加密传输端口是587
server.starttls() #创建安全连接
server.login(from_addr, password)
server.sendmail(from_addr, [to_addr], msg.as_string())
server.quit()
调用starttls()
方式创建安全连接,其余代码和前面相同。smtp_ssl()
在连接建立的时候就需要SSL并且不适合使用starttls()
的情况下可以选择使用smtp_ssl()
。1
2
3
4server = smtplib.SMTP_SSL(smtp_server, 465) #使用smtp_ssl()方法
server.login(from_addr, password)
server.sendmail(from_addr, [to_addr], msg.as_string())
server.quit()
备注:starttls()
使用TLS,默认端口587;smtp_ssl()
使用SSL,默认端口为465。此处需要根据邮件服务商提供的加密方式选择。
关于smtplib
更多的说明可以点击smtplib — SMTP protocol client查看官方介绍。
实例
1 | from email import encoders |
yagmail
yagmail
是一个第三方模块,点击yagmail可以在github查看该项目使用说明及源码。
使用yagmail
发送邮件简单方便,免去了构建邮件内容的繁琐步骤。
安装
python2和python3的安装如下1
2pip install yagmail
pip3 install yagmail
使用
实例化SMTP()
类,然后调用send()方法即可。
更多使用可以参考github项目主页说明。
实例
1 | import yagmail |
to
:收件人,多个收件人可以通过列表方式传递。subject
:邮件主题。contents
:邮件正文。attachments
:附件,可以使用绝对路径。此处表示该文件夹和代码在同一目录。
另外,此处的contents
可以传递列表,它可以自动识别文件格式。例如:
上面发送修改为如下格式1
yag.send(to=emailList, subject="python邮件", contents=["Thanks for your python email!","__init__.py"])
最后收到邮件效果和上面的代码一致。可自动将__init__.py
识别为附件并添加。