Python邮件发送
邮件是互联网上应用非常广泛的服务,几乎所有的编程语言都支持发送和接收电子邮件,使用Python发送邮件和接收邮件也是非常简单易学的。现在几乎每个人的手机上都自带邮件客户端,多数邮箱都支持短信提醒.
因此,在运维场景中将程序报错的信息发送到相应人员的邮箱可以及时感知程序的报错,尽早处理从而避免更多的损失。当然,使用程序发送邮件还有许多应用场景,如网站的密码重置等,在此不再一一列举。
目录
邮箱设置
win10系统下网易邮箱怎样设置SMTP服务:http://www.xitongcheng.com/jiaocheng/win10_article_30498.html
邮件发送和接受的原理
关于如何写代码发送邮件,我们应首先想到发送邮件使用什么协议。目前发送邮件的协议是SMTP(Simple Mail Transfer Protocol,简单邮件传输协议),是一组用于由源地址到目的地址传送邮件的规则,由它来控制信件的中转方式。我们编写代码,实际上就是将待发送的消息使用SMTP协议的格式进行封装,再提交SMTP服务器进行发送的过程。
秒懂百科:https://baike.baidu.com/item/SMTP/175887?fr=aladdin
SMTP
SMTP 的全称是“Simple Mail Transfer Protocol”,即简单邮件传输协议。它是一组用于从源地址到目的地址传输邮件的规范,通过它来控制邮件的中转方式。SMTP 协议属于 TCP/IP 协议簇,它帮助每台计算机在发送或中转信件时找到下一个目的地。SMTP 服务器就是遵循 SMTP 协议的发送邮件服务器。
POP3
POP3是Post Office Protocol 3的简称,即邮局协议的第3个版本,它规定怎样将个人计算机连接到Internet的邮件服务器和下载电子邮件的电子协议。它是因特网电子邮件的第一个离线协议标准,POP3允许用户从服务器上把邮件存储到本地主机(即自己的计算机)上,同时删除保存在邮件服务器上的邮件,而POP3服务器则是遵循POP3协议的接收邮件服务器,用来接收电子邮件的。(与IMAP有什么区别?)
IMAP
IMAP全称是Internet Mail Access Protocol,即交互式邮件存取协议,它是跟POP3类似邮件访问标准协议之一。不同的是,开启了IMAP后,您在电子邮件客户端收取的邮件仍然保留在服务器上,同时在客户端上的操作都会反馈到服务器上,如:删除邮件,标记已读等,服务器上的邮件也会做相应的动作。所以无论从浏览器登录邮箱或者客户端软件登录邮箱,看到的邮件以及状态都是一致的。
Python如何处理邮件
Python内置的smtplib提供了一种很方便的途径发送电子邮件,可以发送纯文本邮件、HTML邮件及带附件的邮件。Python对SMTP支持有smtplib和email两个模块,email负责构造邮件,smtplib负责发送邮件。
发送纯文本邮件
设置第三方SMTP服务
# -*- coding: UTF-8 -*- import smtplib from email.mime.text import MIMEText from email.header import Header # 第三方 SMTP 服务 mail_host = "smtp.qq.com" # 设置服务器 mail_user = "maxin5452@qq.com" # 用户名 mail_pass = "aaaaaaaaaaaaaa" # 口令
构造发件人、收件人、主题和正文
sender = "maxin5452@qq.com" receivers = ["458976849@qq.com", "2831036889@qq.com"] # 接收邮件,可设置为你的QQ邮箱或者其他邮箱 message = MIMEText( '您好,欢迎收看自动化运维课', "plain", "utf-8", ) # 构造正文 message["From"] = sender # 发件人,必须构造,也可以使用Header构造 message["To"] = ";".join(receivers) # 收件人列表,不是必须的 message["Subject"] = "这是主题:马欣 SMTP 邮件测试"
发送邮件
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 as e: print(f"发送失败,错误原因:{e}")
发送HTML格式的邮件
把messge 改写一下,其他内容不变
邮件正文即可改成HTML格式。
message = MIMEText( '<html><body><h1>这是正文标题</h1>\ <p>正文内容 <a href="#">超链接</a>...</p>\ </body></html>', "html", "utf-8", ) # 构造正文
发送带附件的邮件
import smtplib #import chardet from email.mime.text import MIMEText from email.mime.multipart import MIMEMultipart from email.mime.image import MIMEImage from email.header import Header # 第三方 SMTP 服务 mail_host = "smtp.qq.com" # 设置服务器 mail_user = "maxin5452@qq.com" # 用户名 mail_pass = "qqqqqqqqqqqq" # 口令 sender = "maxin5452@qq.com" receivers = ["458976849@qq.com", "2831036889@qq.com"] # 接收邮件,可设置为你的QQ邮箱或者其他邮箱 message = MIMEMultipart() message["From"] = sender # 构造发件人,也可以使用Header构造 message["To"] = ";".join(receivers) # 收件人列表,不是必须的 message["Subject"] = "这是主题:SMTP 邮件测试" # 邮件正文内容 message.attach(MIMEText('<p>这是正文:图片及附件发送测试</p><p>图片演示:</p>', 'html', 'utf-8')) #添加附件1,传送当前目录下的 test.txt 文件 att1 = MIMEText(open("test.txt", "rb").read(), "base64", "utf-8") att1["Content-Type"] = "application/octet-stream" # 这里的filename可以任意写,写什么名字,邮件中显示什么名字 att1["Content-Disposition"] = 'attachment; filename="test.txt"' message.attach(att1) # 添加附件2,传送当前目录下的 测试.txt 文件 att2 = MIMEText(open("测试.txt", "rb").read(), "base64", "utf-8") att2["Content-Type"] = "application/octet-stream" # 这里的filename可以任意写,写什么名字,邮件中显示什么名字 att2.add_header("Content-Disposition", "attachment", filename=("gbk", "", "测试.txt")) 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 as e: print(f"发送失败,错误原因:{e}")
jpg类型的附件
jpgpart = MIMEApplication(open('2.jpg', 'rb').read()) jpgpart.add_header('Content-Disposition', 'attachment', filename='beauty.jpg') message.attach(jpgpart)
xlsx类型的附件
# xlsx类型的附件 xlsxpart = MIMEApplication(open('3.xlsx', 'rb').read()) xlsxpart.add_header('Content-Disposition', 'attachment', filename='test.xlsx') message.attach(xlsxpart)
rar类型附件
# rar类型附件 part = MIMEApplication(open('test.rar', 'rb').read()) part.add_header('Content-Disposition', 'attachment', filename="test.rar") message.attach(part)
完整代码:
import smtplib from email.mime.text import MIMEText from email.header import Header from email.mime.text import MIMEText from email.mime.multipart import MIMEMultipart from email.mime.application import MIMEApplication from email.mime.image import MIMEImage from email.header import Header # 第三方 SMTP 服务 mail_host = "smtp.qq.com" # 设置服务器 mail_user = "maxin5452@qq.com" # 用户名 mail_pass = "aaaaaa" # 口令 sender = "maxin5452@qq.com" receivers = ["458976849@qq.com", "2831036889@qq.com"] # 接收邮件,可设置为你的QQ邮箱或者其他邮箱 message = MIMEMultipart() message["From"] = sender # 构造发件人,也可以使用Header构造 message["To"] = ";".join(receivers) # 收件人列表,不是必须的 message["Subject"] = "这是主题:SMTP 邮件测试" # 邮件正文内容 message.attach(MIMEText('<p>这是正文:图片及附件发送测试</p><p>图片演示:</p>', 'html', 'utf-8')) part = MIMEApplication(open('test.rar', 'rb').read()) part.add_header('Content-Disposition', 'attachment', filename="test.rar") message.attach(part) 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 as e: print(f"发送失败,错误原因:{e}")
接收邮件
连接POP3服务器
# -*- encoding:utf-8 -*- import poplib from email.parser import Parser from email.header import decode_header from email.utils import parseaddr # 输入邮件地址, 口令和POP3服务器地址 email = "maxin5452@163.com" password = "******" pop3_server = "pop.163.com" # 连接到POP3服务器,如果开启ssl请使用poplib.POP3_SSL server = poplib.POP3_SSL(pop3_server) # 可以打开或关闭调试信息 # server.set_debuglevel(1) # 可选:打印POP3服务器的欢迎文字 print(server.getwelcome().decode("utf-8")) # 身份认证: server.user(email) server.pass_(password)
输出邮箱总体信息
# stat()返回邮件数量和占用空间: print("邮件数量: %s个. 大小: %.2fMB" % (server.stat()[0], server.stat()[1] / 1024 / 1024)) # list()返回所有邮件的编号: resp, mails, octets = server.list() # 可以查看返回的列表类似[b'1 82923', b'2 2184', ...]
获取特定邮件信息
# 获取最新一封邮件, 注意索引号从1开始,最新的邮件索引即为邮件的总个数 index = len(mails) resp, lines, octets = server.retr(index) # lines存储了邮件的原始文本的每一行可以获得整个邮件的原始文本 msg_content = b"\r\n".join(lines).decode("utf-8") #print(msg_content)
解析特定邮件信息
# 稍后解析出邮件 msg = Parser().parsestr(msg_content) def decode_str(s): value, charset = decode_header(s)[0] if charset: value = value.decode(charset) return value print("解析获取到的邮件内容如下:\n----------begin------------") # 打印发件人信息 print( f"{ decode_str(parseaddr(msg.get('From',''))[0])}<{decode_str(parseaddr( msg.get('From',''))[1])}>" ) # 打印收件人信息 print( f"{ decode_str(parseaddr(msg.get('To',''))[0])}<{decode_str(parseaddr( msg.get('To',''))[1])}>" ) # 打印主题信息 print(decode_str(msg["Subject"])) # 打印第一条正文信息 part0 = msg.get_payload()[0] content = msg.get_payload(decode=True) print(content.decode(msg.get_content_charset())) print("----------end------------")
删除特定邮件
# 可以根据邮件索引号直接从服务器删除邮件 # server.dele(index) # 关闭连接: server.quit()
完整代码
# -*- encoding:utf-8 -*- import poplib from email.parser import Parser from email.header import decode_header from email.utils import parseaddr # 输入邮件地址, 口令和POP3服务器地址 email = "maxin5452@163.com" password = "******" pop3_server = "pop.163.com" # 连接到POP3服务器,如果开启ssl请使用poplib.POP3_SSL server = poplib.POP3_SSL(pop3_server) # 可以打开或关闭调试信息 # server.set_debuglevel(1) # 可选:打印POP3服务器的欢迎文字 print(server.getwelcome().decode("utf-8")) # 身份认证: server.user(email) server.pass_(password) # stat()返回邮件数量和占用空间: print("邮件数量: %s个. 大小: %.2fMB" % (server.stat()[0], server.stat()[1] / 1024 / 1024)) # list()返回所有邮件的编号: resp, mails, octets = server.list() # 可以查看返回的列表类似[b'1 82923', b'2 2184', ...] # 获取最新一封邮件, 注意索引号从1开始,最新的邮件索引即为邮件的总个数 index = len(mails) resp, lines, octets = server.retr(index) # lines存储了邮件的原始文本的每一行可以获得整个邮件的原始文本 msg_content = b"\r\n".join(lines).decode("utf-8") # 稍后解析出邮件 msg = Parser().parsestr(msg_content) def decode_str(s): value, charset = decode_header(s)[0] if charset: value = value.decode(charset) return value print("解析获取到的邮件内容如下:\n----------begin------------") # 打印发件人信息 print( f"{ decode_str(parseaddr(msg.get('From',''))[0])}<{decode_str(parseaddr( msg.get('From',''))[1])}>" ) # 打印收件人信息 print( f"{ decode_str(parseaddr(msg.get('To',''))[0])}<{decode_str(parseaddr( msg.get('To',''))[1])}>" ) # 打印主题信息 print(decode_str(msg["Subject"])) # 打印第一条正文信息 part0 = msg.get_payload()[0] #content = part0.get_payload(decode=True) #print(content.decode(part0.get_content_charset())) print("----------end------------") # 可以根据邮件索引号直接从服务器删除邮件 # server.dele(index) # 关闭连接: server.quit()