目的:将自动化测试的最新测试报告通过163邮箱发送邮件通知用户
网络上有很多相关资料,记录过程和调试过程中遇到的问题
目录
一、邮件传输协议基础
常见的电子邮件传输协议有:
POP3:接收全部邮件,是client/server协议
SMTP:Simple Mail Transfer Protocol 简单邮件传输协议,是一组用于由源地址到目的地址传送邮件的规则,由它来控制信件的中转方式,是一种邮件发送协议
IMAP4:仅接收邮件标题,仅接收离线邮件的标题,与pop3协议相比较节省了空间
MIME:由参数控制邮件内容的文件类型:如文本或HTML、附件等
PGP:邮件加密
python的smtplib提供了一种很方便的途径发送电子邮件,它对SMTP协议进行了简单的封装
二、发送文本类型邮件
#!/usr/bin/python3
import smtplib
from email.mime.text import MIMEText
from email.header import Header
# 第三方 SMTP 服务
mail_host = "smtp.163.com" # 设置服务器
mail_user = "xxx@163.com" # 邮箱用户名
mail_pass = "xxx" # 是邮箱授权口令,不是邮箱登录密码
sender = "xxx@163.com" # 发送邮件邮箱
receivers = ["xxx1@qq.com","xxx2@qq.com"] # 接收邮件,可添加多个邮箱
message = MIMEText('Python 邮件发送测试...', 'plain', 'utf-8') # 发送邮件的内容、类型
message['From'] = "xxx@163.com" # 邮件发信人,也可以自己定义,建议和发件人一致
message['To'] = "xxx@qq.com" # 邮件收件人,可自己定义,建议和收件人一致
subject = 'Python SMTP 邮件测试'
message['Subject'] = Header(subject, 'utf-8')
try:
smtpObj = smtplib.SMTP()
smtpObj.connect(mail_host, 25) # SMTP端口号25,pop3端口号110
smtpObj.login(mail_user, mail_pass)
smtpObj.sendmail(sender, receivers, message.as_string())
print("邮件发送成功")
except smtplib.SMTPException:
print("Error: 无法发送邮件")
运行程序,控制台输出发送成功,邮箱收到邮件
三、发送HTML和附件格式邮件
和文本类型相比,修改邮件内容和类型就可以
#!/usr/bin/python3
import smtplib
from email.mime.text import MIMEText
from email.mime.multipart import MIMEMultipart
from email.header import Header
import os
"""
发带附件的邮件
需要先创建MIMEMultipart()实例,然后构件附件,最后利用smtplib.smtp发送
@wei
2023-11-08
"""
# 第三方 SMTP 服务
mail_host = "smtp.163.com" # 设置服务器
mail_user = "xxx@163.com" # 用户名
mail_pass = "xxx" # 口令
sender = "xxx@163.com"
receivers = ["xxx@qq.com"] # 接收邮件,可设置为你的QQ邮箱或者其他邮箱
#创建一个带附件的实例
message = MIMEMultipart()
message['From'] = "xxx@163.com"
message['To'] = "xxx@qq.com"
subject = 'Python SMTP 邮件测试'
message['Subject'] = Header(subject, 'utf-8')
mail_msg = """
<p>Python 邮件发送测试...</p>
<p><a href="http://www.runoob.com">这是一个链接</a></p>
"""
# 邮件正文内容
message.attach(MIMEText(mail_msg, 'html', 'utf-8'))
# 获取文件的目录
cur_path = os.path.dirname(os.path.realpath(__file__))
report_file = os.path.join(cur_path, "report\\2023-10-18result.html")
# 构造附件1,传送目录下的report.html文件
att1 = MIMEText(open(report_file, 'rb').read(), 'base64', 'utf-8')
att1["Content-Type"] = 'application/octet-stream'
# 这里的filename可以任意写,写什么名字,邮件中显示什么名字
att1["Content-Disposition"] = 'attachment; filename="2023-10-18result.html"'
message.attach(att1)
# 构造附件2,传送目录下的report.html文件
att2 = MIMEText(open(report_file, 'rb').read(), 'base64', 'utf-8')
att2["Content-Type"] = 'application/octet-stream'
# 这里的filename可以任意写,邮件中显示什么名字,尽量不用中文
att2["Content-Disposition"] = 'attachment; filename="2023-10-18result.html"'
message.attach(att2)
try:
smtpObj = smtplib.SMTP()
smtpObj.connect(mail_host, 25) # 25 为 SMTP 端口号
smtpObj.login(mail_user, mail_pass)
smtpObj.sendmail(sender, receivers, message.as_string())
print("邮件发送成功")
except smtplib.SMTPException:
print("Error: 无法发送邮件")
四、发送带图片的邮件(部分代码)
# multipart类型主要有三种子类型:mixed、alternative、related。
# 创建一个带附件的实例
message = MIMEMultipart('related')
message['From'] = "@163.com"
message['To'] = "@qq.com"
subject = 'Python SMTP 邮件测试'
message['Subject'] = Header(subject, 'utf-8')
messageAlternative = MIMEMultipart('alternative')
message.attach(messageAlternative)
mail_msg = """
<p>Python 邮件发送测试...</p>
<p><a href="http://www.runoob.com">这是一个链接</a></p>
<p>图片测试</p>
<p><img decoding="async" src="cid:image1"></p>
"""
# 邮件正文内容
message.attach(MIMEText(mail_msg, 'html', 'utf-8')) #发送HTML格式邮件
#获取图片
with open("D:\\testdata\\apic41419_s.jpg", 'rb') as fp:
msgImage = MIMEImage(fp.read())
# 定义图片ID在HTML文本中引用
msgImage.add_header('Content-ID', '<image1>')
message.attach(msgImage)
五、优化:读取测试报告作为邮件内容发送
# 和图片类似,读取测试报告中的内容作为邮件的正文,但是没有添加对应样式,可能没有HTML中美观
with open(report_file, "rb") as f:
mail_body = f.read()
msg = MIMEMultipart()
body = MIMEText(mail_body, _subtype='html', _charset='utf-8')
msg.attach(body)
六、发送邮件功能封装
将邮件基本信息放在配置文件config.py中,添加readConfig.py 读取配置文件
将发送邮件封装为函数,参数为测试文档,在测试用例执行完成后调用
七、邮箱设置
邮箱平台-设置页面开启相应的协议,并设置授权码即可(授权码就是代码中对应的密码)
仅为163邮箱,其他邮箱设置可能有差异
八、注意事项
1、需提前确认邮箱客户端是可以正常发送和接收邮件的,如果收件箱没有找到,可以看一下垃圾箱里有没有
2、以上以163邮箱为例,使用其他邮箱(如:QQ 邮箱 SMTP 服务器地址:smtp.qq.com,ssl 端口:465)会根据具体的SMTP协议导致服务器信息和端口号不同,一般控制台会报错:邮件发送失败,无法连接到服务器;这时候可以先查看防火墙或者对应的服务器、端口号是否一致
3、最常见报错
AttributeError: 'tuple' object has no attribute 'encode'
一般问题是出现在邮件的标题,SMTP协议中有定义的格式,MIME类型的标题必须是字符串,可以尝试以下方法
# 修改前
msg["from"]=sender
msg["to"]=psw
# 修改后 join方法或直接输入整个字符串
msg["from"] = ','.join(sender)
msg["to"] = "xx1@qq.com,xx2@qq.com,"
本人也遇到了这个问题,在标题这里死磕了半天,怎么都不对;最后发现是在每个参数的后边加了逗号,于是字符串变成了元组。。。。。
4、注意邮件所在类的命名,不能为email,因为和包重名了,运行会报错没有找到这个包,修改类名就可以了
ImportError: The module name 'email.mime' could not be found. email is not a package
5、windows系统自动升级到11后,文件夹都默认设置成了只读权限,修改后再打开还是只读,尝试了网络上其他方法也没有解决,客服没有回复,社区看了一下好像当前就是这样,也没有修改的措施,所以发送附件时只能选择到具体的文件,如果想选择某个文件夹下的HTML格式的文件,程序会报错文件夹没有权限
6、添加附件中的filename尽量不用中文,否则邮箱实际接收到的HTML文件就会如下显示
参考网站:
smtplib,'tuple'对象没有属性'encode' | 那些遇到过的问题
python编程,排除163邮箱发送邮件报错(AttributeError: ‘tuple‘ object has no attribute ‘encode‘) - 代码先锋网python中发邮件时的 MIMEMultipart - 简书