1.关于SMTP
SMTP是发送邮件的协议,Python内置对SMTP的支持,可以发送纯文本邮件、HTML邮件以及带附件的邮件。
Python对SMTP支持有smtplib和email两个模块,email负责构造邮件,smtplib负责发送邮件。
1.1关于smtplib
使用Python的smtplib发送邮件十分简单,只要掌握了各种邮件类型的构造方法,正确设置好邮件头,就可以顺利发出。
构造一个邮件对象就是一个Messag对象,如果构造一个MIMEText对象,就表示一个文本邮件对象,如果构造一个MIMEImage对象,就表示一个作为附件的图片,要把多个对象组合起来,就用MIMEMultipart对象,而MIMEBase可以表示任何对象。它们的继承关系如下:
Message
± MIMEBase
± MIMEMultipart
± MIMENonMultipart
± MIMEMessage
± MIMEText
± MIMEImage
这种嵌套关系就可以构造出任意复杂的邮件。你可以通过email.mime文档查看它们所在的包以及详细的用法。
2.关于qq邮箱授权码
我使用的qq邮箱,是要开启qq授权码等功能才能登陆以及发送邮件。其它邮箱也应该是差不多的。这个自己直接百度一下就有详细教程了。
3.代码编写
3.1纯文本邮件
# -*- coding: utf-8 -*-
# @Time : 2020/3/9 上午 10:36
# @Author : lh
# @Email : xx@lh.com
# @File : test2.py
# @Software: PyCharm
import smtplib
from email.mime.text import MIMEText
from email.header import Header
qqAccout = 'XX@qq.com' # 邮箱账号
qqCode = '**********' # 授权码
smtp_server = 'smtp.qq.com' # SMTP服务器地址:
smtp_port = 465 # 服务器端口
# 配置服务器以及登录(login()方法用来登录SMTP服务器,)
stmp = smtplib.SMTP_SSL(smtp_server, smtp_port)
stmp.set_debuglevel(1) # 我们用set_debuglevel(1)就可以打印出和SMTP服务器交互的所有信息。
stmp.login(qqAccout, qqCode)
# 组装发送纯文本内容
message = MIMEText('33333没有什么实质作用的内容3333', 'plain', 'utf-8') # 注意到构造MIMEText对象时,第一个参数就是邮件正文,第二个参数是MIME的subtype,传入'plain'表示纯文本,最终的MIME就是'text/plain',最后一定要用utf-8编码保证多语言兼容性。
message['From'] = Header("Python自动化监控系统", 'utf-8') # 发件人
message['To'] = Header("有缘人", 'utf-8') # 收件人
subject = 'Python SMTP 发送邮件测试'
message['Subject'] = Header(subject, 'utf-8') # 邮件标题
try:
# sendmail()方法就是发邮件,由于可以一次发给多个人,所以传入一个list,邮件正文是一个str,as_string()把MIMEText对象变成str
stmp.sendmail(qqAccout, [qqAccout, ], message.as_string()) # 发件人,收件人,
print('邮件发送成功')
except Exception as e:
print('邮件发送失败--' + str(e))
注意到构造MIMEText对象时,第一个参数就是邮件正文,第二个参数是MIME的subtype,传入’plain’表示纯文本,最终的MIME就是’text/plain’,最后一定要用utf-8编码保证多语言兼容性。
运行程序:
这是一个自己发给自己的邮件。
3.2 HTML邮件
在构造MIMEText对象时,把HTML字符串传进去,再把第二个参数由plain变为html就可以了:
msg = MIMEText('<html><body><p>这是一个HTML邮件</p><a href="www.baidu.com">百度一下</a></body></html>', 'html', 'utf-8')
3.3 附件邮件
带附件的邮件可以看做包含若干部分的邮件:文本和各个附件本身,所以,可以构造一个MIMEMultipart对象代表邮件本身,然后往里面加上一个MIMEText作为邮件正文,再继续往里面加上表示附件的MIMEBase对象
# -*- coding: utf-8 -*-
# @Time : 2020/3/12 上午 10:21
# @Author : lh
# @Email : xx@lh.com
# @File : test5.py
# @Software: PyCharm
import smtplib
from email import encoders
from email.header import Header
from email.mime.base import MIMEBase
from email.mime.text import MIMEText
from email.mime.multipart import MIMEMultipart
from email.utils import parseaddr, formataddr
def _format_addr(s):
name, addr = parseaddr(s)
return formataddr((Header(name, 'utf-8').encode(), addr))
from_addr = input('From: ')
password = input('Password: ')
to_addr = input('To: ')
smtp_server = input('SMTP server: ')
# 邮件对象
msg = MIMEMultipart()
msg['From'] = _format_addr('Python邮件测试<%s>' % from_addr)
msg['To'] = _format_addr('管理员 <%s>' % to_addr)
msg['Subject'] = Header('你是美团的吗,那么能送', 'utf-8').encode()
# 邮件正文是 MIMEText
msg.attach(MIMEText('发送文本邮件...', 'plain', 'utf-8'))
# 添加附件就是加上一个MIMEBase, 从本地读取一个图片
with open('test.html', 'rb') as f:
# 设置附件的MIME和文件名, 这是一个html文件呢
m = MIMEBase('file', 'html', filename='test.html')
# 加上头信息
m.add_header('Content-Disposition', 'attachment', filename='test.html')
m.add_header('Content-ID', '<0>')
m.add_header('X-Attachment-Id', '0')
# 把附件的内容读取进来
m.set_payload(f.read())
# 使用Base64进行编码
encoders.encode_base64(m)
msg.attach(m)
server = smtplib.SMTP(smtp_server, 25)
server.set_debuglevel(1)
server.login(from_addr, password)
server.sendmail(from_addr, [to_addr], msg.as_string())
server.quit()
3.4邮件中带图片
想要直接嵌套图片到邮件中的话需要,设置一下,因为一般邮件都会屏蔽掉我们带的外链的图片的。
按照发送附件的方式,先把邮件作为附件添加进去,然后,在HTML中通过引用src="cid:0"就可以把附件作为图片嵌入了。如果有多个图片,给它们依次编号,然后引用不同的cid:x即可。
上面代码加入MIMEMultipart的MIMEText从plain改为html,然后在适当的位置引用图片
# -*- coding: utf-8 -*-
# @Time : 2020/3/12 上午 11:19
# @Author : lh
# @Email : xx@lh.com
# @File : test6.py
# @Software: PyCharm
import smtplib
from email import encoders
from email.header import Header
from email.mime.base import MIMEBase
from email.mime.text import MIMEText
from email.mime.multipart import MIMEMultipart
from email.utils import parseaddr, formataddr
def _format_addr(s):
name, addr = parseaddr(s)
return formataddr((Header(name, 'utf-8').encode(), addr))
from_addr = input('From: ')
password = input('Password: ')
to_addr = input('To: ')
smtp_server = input('SMTP server: ')
# 邮件对象
msg = MIMEMultipart()
msg['From'] = _format_addr('Python邮件测试<%s>' % from_addr)
msg['To'] = _format_addr('管理员 <%s>' % to_addr)
msg['Subject'] = Header('你是美团的吗,那么能送', 'utf-8').encode()
# 邮件正文是 MIMEText
msg.attach(MIMEText('<html><body><h1>Hello</h1>' +
'<p><img src="cid:0"></p>' +
'</body></html>', 'html', 'utf-8'))
# 添加附件就是加上一个MIMEBase, 从本地读取一个图片
with open('test.jpg', 'rb') as f:
# 设置附件的MIME和文件名, 这是一个html文件呢
m = MIMEBase('image', 'jpg', filename='test.jpg')
# 加上头信息
m.add_header('Content-Disposition', 'attachment', filename='test.jpg')
m.add_header('Content-ID', '<0>')
m.add_header('X-Attachment-Id', '0')
# 把附件的内容读取进来
m.set_payload(f.read())
# 使用Base64进行编码
encoders.encode_base64(m)
msg.attach(m)
server = smtplib.SMTP(smtp_server, 25)
server.set_debuglevel(1)
server.login(from_addr, password)
server.sendmail(from_addr, [to_addr], msg.as_string())
server.quit()
3.5降级查看邮件
收件人通过浏览器或者Outlook之类的软件是可以正常浏览邮件内容的,但是,如果收件人使用的设备太古老,查看不了HTML邮件的话,办法是在发送HTML的同时再附加一个纯文本,如果收件人无法查看HTML格式的邮件,就可以自动降级查看纯文本邮件。
利用MIMEMultipart就可以组合一个HTML和Plain,要注意指定subtype是alternative:
msg = MIMEMultipart('alternative')
msg['From'] = ...
msg['To'] = ...
msg['Subject'] = ...
msg.attach(MIMEText('hello', 'plain', 'utf-8'))
msg.attach(MIMEText('<html><body><h1>Hello</h1></body></html>', 'html', 'utf-8'))
# 正常发送msg对象...