自动化运维之使用Python3收发电子邮件~~~附源码

 

一、背景介绍

 

1.1  一些专业名称的解释

 

MUA——Mail User Agent,邮件用户代理。是用户与电子邮件系统的交互接口,一般来说它就是我们PC机上的一个程序,提供一个好的用户界面,它提取用户在其界面填写的各项信息,生成一封符合SMTP等邮件标准的邮件,然后采用SMTP协议将邮件发送到发送端邮件服务器。常见的通用型代理有OutLook Express、FoxMail、网易闪电邮等

MTA——Mail Transfer Agent,邮件传输代理。负责邮件的传输,它采用端到端的传输的传输方式,源端主机参与邮件传输的全过程,也可称之为SMTP服务器。其实就是那些Email服务提供商,比如网易、新浪等等。比如我使用的电子邮件是163.com,所以,发Email首先被投递到网易提供的MTA,再由网易的MTA发到对方服务商,可能是sina、qq或者其他的MTA,这个过程中间可能还会经过别的MTA

MDA——Mail Deliver Agent,邮件投递代理。Email到达收件人(比如使用的是新浪的邮箱)的MTA后,新浪的MTA会把Email投递到邮件的最终目的地MDA。Email到达MDA后,就静静地躺在新浪的某个服务器上,存放在某个文件或特殊的数据库里。Email不会直接到达对方的电脑,对方要取到邮件,必须通过MUA从MDA上把邮件取到自己的电脑上。

SMTP——Simple Mail Transfer Protocol,简单邮件传输协议 。是Internet上基于TCP/IP的应用层协议,定义了邮件发送方和接收方之间的连接传输,默认端口号TCP 25。SMTP有其一定的局限性,它只能传送ASCII文本文件,而对于一些二进制数据文件需要进行编码后才能传送。

MIME——Multipose Internet Mail Extensions,多途径Internet邮件扩展协议。是一种编码标准,它解决了SMTP只能传送ASCII文本的限制。MIME定义了各种类型数据,如声音、图像、表格、二进制数据等的编码格式,通过对这些类型的数据编码并将它们作为邮件中的附件进行处理,以保证这些部分内容完整、正确地传输。因此,MIME增强了SMTP的传输功能,统一了编码规范。

POP3——Post Office Protocol Version 3,邮局协议的第三版本。主要用于支持使用客户端远程管理在服务器上的电子邮件。,它规定怎样将个人计算机连接到Internet的邮件服务器和下载电子邮件的电子协议。它是因特网电子邮件的第一个离线协议标准,POP3允许用户从服务器上把邮件存储到本地主机(即自己的计算机)上,同时删除保存在邮件服务器上的邮件

IMAP——Internet Message Access Protocol,因特网报文存取协议。它是跟POP3类似邮件访问标准协议之一。不同的是,开启了IMAP后,您在电子邮件客户端收取的邮件仍然保留在服务器上,同时在客户端上的操作都会反馈到服务器上,如:删除邮件,标记已读等,服务器上的邮件也会做相应的动作。所以无论从浏览器登录邮箱或者客户端软件登录邮箱,看到的邮件以及状态都是一致的。

 

1.2  电子邮件收发原理

有了上述基本概念,要编写程序来发送和接收邮件,本质上就是:

编写MUA把邮件发到MTA;

编写MUA从MDA上收邮件。

发邮件时,MUA和MTA使用的协议就是SMTP,后面的MTA到另一个MTA也是用SMTP协议。

收邮件时,MUA和MDA使用的协议有两种:POP3和IMAP。

邮件客户端软件在发邮件时,会让你先配置SMTP服务器,也就是你要发到哪个MTA上。假设你正在使用163的邮箱,你就不能直接发到新浪的MTA上,因为它只服务新浪的用户,所以,你得填163提供的SMTP服务器地址:smtp.163.com,为了证明你是163的用户,SMTP服务器还要求你填写邮箱地址和邮箱口令,这样,MUA才能正常地把Email通过SMTP协议发送到MTA。

类似的,从MDA收邮件时,MDA服务器也要求验证你的邮箱口令,确保不会有人冒充你收取你的邮件,所以,Outlook之类的邮件客户端会要求你填写POP3或IMAP服务器地址、邮箱地址和口令,这样,MUA才能顺利地通过POP或IMAP协议从MDA取到邮件。

自动化运维之使用Python3收发电子邮件~~~附源码_第1张图片

 

1.3  编码前的准备工作

 

使用Python收发邮件前,请先准备好至少两个电子邮件,如[email protected][email protected][email protected]等,注意两个邮箱不要用同一家邮件服务商。

最后特别注意,目前大多数邮件服务商都需要手动打开SMTP发信和POP收信的功能,否则只允许在网页登录,以163邮箱为例配置步骤如下:

 

(1)登陆自己的163邮箱,在设置中选择“POP3/SMTP/IMAP”,配置如下图,并记住SMTP服务器地址,后续会用到

自动化运维之使用Python3收发电子邮件~~~附源码_第2张图片

 

 (2)找到设置中的“客户端授权码”,开启这项功能并设置授权码,系统会提示不允许与登陆密码相同

自动化运维之使用Python3收发电子邮件~~~附源码_第3张图片

 

 

二、用python3发邮件

 

SMTP是发送邮件的协议,Python对SMTP支持有smtplibemail两个模块,email负责构造邮件,smtplib负责发送邮件

2.1. 最简单的示例,发送纯文本邮件(无附件、正文里无图片和html语句)

需要导入的包如下:(关于第一个包后续展开讲,在这个最简单的例子中使用这个)

from email.mime.text import MIMEText
import smtplib

"""
发送频繁的话会被当做垃圾邮件,运行程序显示554错误
"""

from email.mime.text import MIMEText
from email.utils import formataddr
import smtplib
# 输入发送人地址和口令:
from_addr = '***@163.com'
password = '***'#授权码而非登陆密码
# 输入收件人地址:
to_addr = '***@qq.com'
# 输入发件人SMTP服务器地址:
smtp_server = 'smtp.163.com'
#构造邮件
msg = MIMEText('这里写正文的内容……','plain','utf-8') #构造MIMEText对象
msg['From'] = formataddr(["发件人的昵称",from_addr])  #括号里的对应发件人邮箱昵称、发件人邮箱账号
msg['To'] = formataddr(["收件人的昵称",to_addr]) #括号里的对应收件人邮箱昵称、收件人邮箱账号
msg['Subject'] = "这里写主题" #邮件的主题,也可以说是标题
server = smtplib.SMTP(smtp_server, 25) # SMTP协议默认端口是25
#server.set_debuglevel(1)#打印出和SMTP服务器交互的所有信息
server.login(from_addr, password)#登录SMTP服务器
#sendmail()方法就是发邮件,由于可以一次发给多个人,所以传入一个list,邮件正文是一个str,as_string()把MIMEText对象变成str
server.sendmail(from_addr, [to_addr], msg.as_string())
server.quit()#退出SMTP服务器

 

tips1:

from email.utils import formataddr中的formataddr使用help(formataddr)查看

可以看到formataddr和parseaddr是互逆的两个过程

自动化运维之使用Python3收发电子邮件~~~附源码_第4张图片

举个例子:

formataddr(['我', '[email protected]'])的结果是:=?utf-8?b?5oiR?= 
parseaddr('"我"')的结果是:'我', '[email protected]'

tips2:
password要填写授权码(也就是自己设置的),而不是邮箱登陆密码

tips3:
构造MIMEText对象时,第一个参数就是邮件正文,第二个参数是MIME的subtype,传入'plain'表示纯文本,最终的MIME就是'text/plain',最后一定要用utf-8编码保证多语言兼容性

tips4:
SMTP协议就是简单的文本命令和响应。
login()方法用来登录SMTP服务器
sendmail()方法就是发邮件,由于可以一次发给多个人(用“,”隔开),所以传入一个list

邮件正文是一个stras_string()MIMEText对象变成str



查看收件箱的结果如下:

自动化运维之使用Python3收发电子邮件~~~附源码_第5张图片

 为什么没有显示昵称我也不太清楚……只试验了自己的邮箱,并没有进行大范围的测试

 

 


 

 

2.2 第二个示例——邮件正文中包含html语句(当然也可以包含纯文本文字)

在构造MIMEText对象时,把HTML字符串传进去,再把第二个参数由plain变为html就可以了

msg = MIMEText('

Hello

' + '

send by Python...

' + '', 'html', 'utf-8')#发送html

 查看邮件结果:

自动化运维之使用Python3收发电子邮件~~~附源码_第6张图片

 

 


 

 

2.3 发送不同格式的附件(当然也可以包含纯文本)

基本思路就是,使用MIMEMultipart来标示这个邮件是多个部分组成的,然后attach各个部分。如果是附件,则add_header加入附件的声明。
在python中,MIME的这些对象的继承关系如下:

官方参考:https://docs.python.org/3/library/email.mime.html

 自动化运维之使用Python3收发电子邮件~~~附源码_第7张图片

一般来说,不会用到MIMEBase,而是直接使用它的继承类。MIMEMultipart有attach方法,而MIMENonMultipart没有,只能被attach。
MIME有很多种类型,这个略麻烦,如果附件是图片格式,要用MIMEImage,如果是音频,要用MIMEAudio等等……但是可以作为附件的文件类型实在是太多了,记起来又很麻烦,这里有一个懒人方法就是,不管什么类型的附件,都用MIMEApplication,MIMEApplication默认子类型是application/octet-stream。
application/octet-stream表明“这是个二进制的文件,希望你们那边知道怎么处理”,然后客户端,比如qq邮箱,收到这个声明后,会根据文件扩展名来猜测。

 

from email.mime.multipart import MIMEMultipart
from email.mime.application import MIMEApplication
from email.mime.image import MIMEImage
#from email.mime.image import MIMEAudio #并没有找到MIMEAudio这个库

# 如名字所示Multipart就是分多个部分 # 构造一个MIMEMultipart对象代表邮件本身
msg = MIMEMultipart()

# ---这是文字部分---
part1 = MIMEText("纯文本内容")
msg.attach(part1)

# xlsx类型附件
part2 = MIMEApplication(open('痒痒鼠.xlsx', 'rb').read())
part2.add_header('Content-Disposition', 'attachment', filename="痒痒鼠.xlsx")
msg.attach(part2)

#图片作为附件的时候,有时会出现图片不完整的情况
# jpg类型附件
part3 = MIMEApplication(open('qqq.jpg', 'rb').read())
part3.add_header('Content-Disposition', 'attachment', filename="qqq.jpg")
msg.attach(part3)
# jpg类型附件另一种方法
part33 = MIMEImage(open('qqq.jpg', 'rb').read())
part33.add_header('Content-Disposition', 'attachment', filename="qqq.jpg")
msg.attach(part33)

# pdf类型附件
part4 = MIMEApplication(open('马蜂窝庐山.pdf', 'rb').read())
part4.add_header('Content-Disposition', 'attachment', filename="马蜂窝庐山.pdf")
msg.attach(part4)

# mp3类型附件
part5 = MIMEApplication(open('天哪.mp3', 'rb').read())
part5.add_header('Content-Disposition', 'attachment', filename="天哪.mp3")
msg.attach(part5)
# mp3类型附件另一种方法,因为无法导入MIMEAudio这个库,失败

 

总结一下用法,可直接套用以下模板:

from email.mime.multipart import MIMEMultipart
from email.mime.application import MIMEApplication

msg = MIMEMultipart()

#纯文本内容 part1 = MIMEText("纯文本内容") msg.attach(part1)
# 添加附件
part2 = MIMEApplication(open('附件***.类型', 'rb').read())
part2.add_header('Content-Disposition', 'attachment', filename="附件***.类型")
msg.attach(part2)

查看邮件结果:

自动化运维之使用Python3收发电子邮件~~~附源码_第8张图片

 

 tips1:可以添加多个附件

tips2:附件为图片的时候有可能不完整

 

2.4 加密传输

使用标准的25端口连接SMTP服务器时,使用的是明文传输,发送邮件的整个过程可能会被窃听。要更安全地发送邮件,可以加密SMTP会话,实际上就是先创建SSL安全连接,然后再使用SMTP协议发送邮件。

某些邮件服务商,例如Gmail,提供的SMTP服务必须要加密传输。我们来看看如何通过Gmail提供的安全SMTP发送邮件。

必须知道,Gmail的SMTP端口是587,因此,修改代码如下:

smtp_server = 'smtp.gmail.com'
smtp_port = 587
server = smtplib.SMTP(smtp_server, smtp_port)
server.starttls()
# 剩下的代码和前面的一模一样:
server.set_debuglevel(1)

只需要在创建SMTP对象后,立刻调用starttls()方法,就创建了安全连接。后面的代码和前面的发送邮件代码完全一样。

 

三、用python3收邮件

 讲完了发送邮件,现在讲解收取邮件

 

 

收取邮件就是编写一个MUA作为客户端,从MDA把邮件获取到用户的电脑或者手机上。收取邮件最常用的协议是POP协议,目前版本号是3,俗称POP3

Python内置一个poplib模块,实现了POP3协议,可以直接用来收邮件。

注意到POP3协议收取的不是一个已经可以阅读的邮件本身,而是邮件的原始文本,这和SMTP协议很像,SMTP发送的也是经过编码后的一大段文本。

要把POP3收取的文本变成可以阅读的邮件,还需要用email模块提供的各种类来解析原始文本,变成可阅读的邮件对象。

所以,收取邮件分两步:

第一步:用poplib把邮件的原始文本下载到本地;

第二部:用email解析原始文本,还原为邮件对象。

 

转载于:https://www.cnblogs.com/aby321/p/10366205.html

你可能感兴趣的:(自动化运维之使用Python3收发电子邮件~~~附源码)