이메일의 여정은 다음과 같습니다.
메일 사용자 에이전트(MUA)는 사용자가 이메일 계정에 액세스하는 데 사용하는 이메일 클라이언트 또는 소프트웨어를 말합니다. (예: Outlook과 유사한 이메일 소프트웨어)
MTA: 메일 전송 에이전트 - 메일 전송 에이전트는 NetEase, Sina 등과 같은 이메일 서비스 제공업체입니다.
MDA: 메일 배달 대행자——메일 배달 대행자입니다. 이메일 서비스 제공업체의 서버
Sender-> MTA -> MTA -> 여러 MTA -> MUA <- 수신자
이메일은 기본적으로 다음과 같습니다.
MUA를 작성하여 MTA로 이메일을 보냅니다.
MUA를 작성하여 MDA로부터 이메일을 받습니다.
이메일을 보낼 때 MUA와 MTA에서 사용하는 프로토콜은 SMTP: Simple Mail Transfer Protocol입니다. 후속 MTA도 다른 MTA에 SMTP 프로토콜을 사용합니다.
이메일을 받을 때 MUA와 MDA는 두 가지 프로토콜을 사용합니다. POP: Post Office Protocol, 현재 버전은 3이며 일반적으로 POP3로 알려져 있습니다: Internet Message Access Protocol, 현재 버전은 4입니다. 이메일을 검색할 뿐 아니라 받은 편지함에서 휴지통으로 이동하는 등 MDA에 저장된 이메일을 직접 조작할 수도 있습니다.
는 단순 메일 전송 프로토콜로, 편지 전송 방법을 제어하는 원본 주소에서 대상 주소로 이메일을 전송하는 규칙 집합입니다.
Python의 smtplib는 이메일을 보내는 매우 편리한 방법을 제공합니다. 이는 단순히 SMTP 프로토콜을 캡슐화합니다.
Python은 smtplib
와 email
의 두 가지 모듈로 SMTP를 지원합니다. email
은 이메일 구성을 담당하고 smtplib
는 메일 발송을 담당합니다. smtplib
和email
两个模块,email
负责构造邮件,smtplib
负责发送邮件。
构造一个邮件对象就是一个Messag
对象,如果构造一个MIMEText
对象,就表示一个文本邮件对象,如果构造一个MIMEImage
对象,就表示一个作为附件的图片,要把多个对象组合起来,就用MIMEMultipart
对象,而MIMEBase
可以表示任何对象。它们的继承关系如下:
Message +- MIMEBase +- MIMEMultipart +- MIMENonMultipart +- MIMEMessage +- MIMEText +- MIMEImage
首先,我们来构造一个最简单的纯文本邮件,然后,通过SMTP发出去。
from email.mime.text import MIMEText msg = MIMEText('hello, send by Python...', 'plain', 'utf-8')
注意到构造MIMEText
对象时,第一个参数就是邮件正文,第二个参数是MIME的subtype,传入'plain'
,最终的MIME就是'text/plain'
,最后一定要用utf-8
编码保证多语言兼容性。
语法如下:
import smtplib smtpObj = smtplib.SMTP( [host [, port [, local_hostname]]] )
参数说明:
host: SMTP 服务器主机。这个参数可选,你可以根据需要指定主机的IP地址或者域名,例如:runoob.com。
port: 如果你提供了 host 参数, 你需要指定 SMTP 服务使用的端口号,一般情况下 SMTP 端口号为25。
local_hostname: 如果 SMTP 在你的本机上,你只需要指定服务器地址为 localhost 即可。
语法如下:
SMTP.sendmail(from_addr, to_addrs, msg[, mail_options, rcpt_options])
参数说明:
from_addr: 邮件发送者地址。
to_addrs: 字符串列表,邮件发送地址。
msg: 发送消息
这里要注意一下第三个参数,msg 是字符串,表示邮件。要发送邮件,就必须注意信息的格式,因为邮件通常包括标题、发件人、收件人、邮件内容和附件等。这个格式就是 smtp 协议中定义的格式。
以下执行实例需要你本机已安装了支持 SMTP 的服务。
sendmail()
方法就是发邮件,由于可以一次发给多个人,所以传入一个list
,邮件正文是一个str
,as_string()
把MIMEText
对象变成str
。
经过Header
对象编码的文本,包含utf-8编码信息和Base64编码的文本。
以下是一个使用 Python 发送邮件简单的实例:
import smtplib from email.mime.text import MIMEText from email.header import Header sender = 'from@runoob.com' receivers = ['429240967@qq.com'] # 接收邮件,可设置为你的QQ邮箱或者其他邮箱 # 三个参数:第一个为文本内容,第二个 plain 设置文本格式,第三个 utf-8 设置编码 message = MIMEText('Python 邮件发送测试内容...', 'plain', 'utf-8') message['From'] = Header("菜鸟教程", 'utf-8') # 发送者 message['To'] = Header("测试", 'utf-8') # 接收者 message['Subject'] = Header('Python SMTP 邮件测试主题', 'utf-8') try: smtpObj = smtplib.SMTP('localhost') smtpObj.sendmail(sender, receivers, message.as_string()) print "邮件发送成功" except smtplib.SMTPException: print "Error: 无法发送邮件"
如果我们本机没有 sendmail 访问,也可以使用其他邮件服务商的 SMTP 访问(QQ、网易、Google等)。
login()
方法用来登录SMTP服务器
发收件件人的名字没有显示为友好的名字,比如Mr Green
;
使用 formataddr方法来格式化一个邮件地址。如果包含中文,需要通过Header
对象进行编码。
msg['To']
接收的是字符串而不是list,如果有多个邮件地址,用,
MIMEText
개체를 구성한다는 의미입니다. 텍스트 메일 개체 MIMEImage
개체를 생성하면 그림이 첨부 파일로 표시됩니다. 여러 개체를 결합하려면 MIMEMultipart
개체와 MIMEBase 는 모든 객체를 나타낼 수 있습니다. 그들의 상속 관계는 다음과 같습니다: 🎜<pre class="brush:py;">import smtplib
from email.mime.text import MIMEText
from email.utils import formataddr
# 第三方 SMTP 服务
mail_host = "mail.sss.com" # 设置服务器
mail_user = "it_system@sss.com" # 用户名
mail_pass = "Ssss201709#" # 口令
sender = &#39;it_system@tcl.com&#39;
receivers = &#39;sss.yang@tcsssl.com&#39; # 接收邮件,可设置为你的QQ邮箱或者其他邮箱
message = MIMEText(&#39;Python 邮件内容测试...&#39;, &#39;plain&#39;, &#39;utf-8&#39;)
message[&#39;From&#39;] = formataddr((&#39;SCBC-啊iT&#39;, sender))
message[&#39;To&#39;] = formataddr((&#39;杨生&#39;, receivers))
message[&#39;Subject&#39;] = &#39;Python SMTP 邮件测试&#39;
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: 无法发送邮件")</pre>🎜먼저 가장 간단한 일반 텍스트 이메일을 구성한 다음 SMTP를 통해 보냅니다. 🎜<pre class="brush:py;">mail_msg = """
Python 邮件内容测试...
这是一个链接
"""
message = MIMEText(mail_msg, &#39;html&#39;, &#39;utf-8&#39;)</pre>🎜 <code>MIMEText
객체를 구성할 때 첫 번째 매개변수는 이메일 본문이고 두 번째 매개변수는 'plain'
의 MIME 전달 하위 유형이라는 점에 주목하세요. final MIME 'text/plain'
입니다. 마지막으로 다국어 호환성을 보장하려면 utf-8
인코딩을 사용해야 합니다. 🎜from email.mime.multipart import MIMEMultipart # 创建一个带附件的实例 message = MIMEMultipart() message['From'] = formataddr(('SCBC-啊iT', sender)) message['To'] = formataddr(('杨生', receivers)) message['Subject'] = 'Python SMTP 邮件测试' mail_msg = """ Python 邮件内容测试... 这是一个链接 """ # 邮件正文内容 message.attach(MIMEText(mail_msg, 'html', 'utf-8')) # 构造附件1,传送当前目录下的 test.txt 文件 att = MIMEText(open('32.txt', 'rb').read(), 'base64', 'utf-8') att["Content-Type"] = 'application/octet-stream' # 这里的filename可以任意写,写什么名字,邮件中显示什么名字 att["Content-Disposition"] = 'attachment; filename="32.txt"' message.attach(att)🎜매개변수 설명: 🎜🎜🎜🎜host: SMTP 서버 호스트. 이 매개변수는 선택사항입니다. 필요에 따라 호스트의 IP 주소 또는 도메인 이름을 지정할 수 있습니다(예: runoob.com). 🎜🎜🎜🎜port: 호스트 매개변수를 제공하는 경우 SMTP 서비스에서 사용하는 포트 번호를 지정해야 합니다. 일반적으로 SMTP 포트 번호는 25입니다. 🎜🎜🎜🎜local_hostname: SMTP가 로컬 컴퓨터에 있는 경우 서버 주소를 localhost로 지정하기만 하면 됩니다. 🎜🎜🎜
from email.mime.multipart import MIMEMultipart from email.mime.image import MIMEImage # 创建一个带附件的实例 message = MIMEMultipart() message['From'] = formataddr(('SCBC-啊iT', sender)) message['To'] = formataddr(('杨生', receivers)) message['Subject'] = 'Python SMTP 邮件测试' mail_msg = """ Python 邮件内容测试... 这是一个链接 图片演示: """ # 邮件正文内容 message.attach(MIMEText(mail_msg, 'html', 'utf-8')) # 指定图片为当前目录 with open('a.jpg', 'rb') as fp: msgImage = MIMEImage(fp.read()) # 定义图片 ID,在 HTML 文本中引用 msgImage.add_header('Content-ID', '') message.attach(msgImage)🎜매개변수 설명: 🎜🎜🎜🎜from_addr: 이메일 보낸 사람 주소. 🎜🎜🎜🎜to_addrs: 문자열 목록, 이메일 전송 주소. 🎜🎜🎜🎜msg: 메시지 보내기 🎜🎜🎜🎜 여기서 세 번째 매개변수인 msg는 이메일을 나타내는 문자열입니다. 이메일을 보내려면 정보 형식에 주의해야 합니다. 이메일에는 일반적으로 제목, 보낸 사람, 받는 사람, 이메일 내용, 첨부 파일 등이 포함되기 때문입니다. 이 형식은 smtp 프로토콜에 정의된 형식입니다. 🎜🎜2. 예제🎜
sendmail()
메소드는 동시에 여러 사람에게 보낼 수 있으므로 목록
을 전달하고 이메일 본문은 다음과 같습니다. str
, as_string()
은 MIMEText
개체를 str
로 바꿉니다. 🎜🎜UTF-8 인코딩 정보 및 Base64 인코딩 텍스트를 포함하여 Header
개체로 인코딩된 텍스트입니다. 🎜🎜다음은 Python을 사용하여 이메일을 보내는 간단한 예입니다. 🎜# 指定图片为当前目录 with open('a.jpg', 'rb') as fp: # 设置附件的MIME和文件名,这里是png类型: mime = MIMEBase('image', 'jpg', filename='a.jpg') # 加上必要的头信息: mime.add_header('Content-Disposition', 'attachment', filename='附件显示名称.jpg') mime.add_header('Content-ID', '') # 如果有多个文件需要使用.format(index) mime.add_header('X-Attachment-Id', '0') # 如果有多个文件需要使用.format(index) # 把附件的内容读进来: mime.set_payload(fp.read()) # 用Base64编码: encoders.encode_base64(mime) # 添加到MIMEMultipart: message.attach(mime)
login()
메소드는 SMTP 서버에 로그인하는 데 사용됩니다. 🎜🎜수신자의 이름은 Mr Green
과 같은 친숙한 이름으로 표시되지 않습니다. 이메일 주소의 형식을 지정하는 formataddr 메소드. 중국어가 포함된 경우 Header
개체를 통해 인코딩해야 합니다. 🎜🎜msg['To']
는 목록 대신 문자열을 받습니다. 이메일 주소가 여러 개인 경우 ,
를 사용하여 구분하세요. 🎜import smtplib from email.mime.text import MIMEText from email.utils import formataddr # 第三方 SMTP 服务 mail_host = "mail.sss.com" # 设置服务器 mail_user = "it_system@sss.com" # 用户名 mail_pass = "Ssss201709#" # 口令 sender = 'it_system@tcl.com' receivers = 'sss.yang@tcsssl.com' # 接收邮件,可设置为你的QQ邮箱或者其他邮箱 message = MIMEText('Python 邮件内容测试...', 'plain', 'utf-8') message['From'] = formataddr(('SCBC-啊iT', sender)) message['To'] = formataddr(('杨生', receivers)) message['Subject'] = 'Python 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: print("Error: 无法发送邮件")
Python在构造MIMEText
对象时,把HTML字符串传进去,再把第二个参数由plain
变为html
就可以了:
具体代码如下:
mail_msg = """ Python 邮件内容测试... 这是一个链接 """ message = MIMEText(mail_msg, 'html', 'utf-8')
带附件的邮件可以看做包含若干部分的邮件:文本和各个附件本身,所以,可以构造一个MIMEMultipart
对象代表邮件本身,然后往里面加上一个MIMEText
作为邮件正文,再继续往里面加上表示附件的MIMEBase
对象即可。
发送带附件的邮件,首先要创建MIMEMultipart()实例,然后构造附件,如果有多个附件,可依次构造,最后利用smtplib.smtp发送。
from email.mime.multipart import MIMEMultipart # 创建一个带附件的实例 message = MIMEMultipart() message['From'] = formataddr(('SCBC-啊iT', sender)) message['To'] = formataddr(('杨生', receivers)) message['Subject'] = 'Python SMTP 邮件测试' mail_msg = """ Python 邮件内容测试... 这是一个链接 """ # 邮件正文内容 message.attach(MIMEText(mail_msg, 'html', 'utf-8')) # 构造附件1,传送当前目录下的 test.txt 文件 att = MIMEText(open('32.txt', 'rb').read(), 'base64', 'utf-8') att["Content-Type"] = 'application/octet-stream' # 这里的filename可以任意写,写什么名字,邮件中显示什么名字 att["Content-Disposition"] = 'attachment; filename="32.txt"' message.attach(att)
要把图片嵌入到邮件正文中,我们只需按照发送附件的方式,先把邮件作为附件添加进去,然后,在HTML中通过引用src="cid:0"
就可以把附件作为图片嵌入了。如果有多个图片,给它们依次编号,然后引用不同的cid:x
即可。
邮件的 HTML 文本中一般邮件服务商添加外链是无效的,正确添加图片的实例如下所示:
from email.mime.multipart import MIMEMultipart from email.mime.image import MIMEImage # 创建一个带附件的实例 message = MIMEMultipart() message['From'] = formataddr(('SCBC-啊iT', sender)) message['To'] = formataddr(('杨生', receivers)) message['Subject'] = 'Python SMTP 邮件测试' mail_msg = """ Python 邮件内容测试... 这是一个链接 图片演示: """ # 邮件正文内容 message.attach(MIMEText(mail_msg, 'html', 'utf-8')) # 指定图片为当前目录 with open('a.jpg', 'rb') as fp: msgImage = MIMEImage(fp.read()) # 定义图片 ID,在 HTML 文本中引用 msgImage.add_header('Content-ID', '') message.attach(msgImage)
或者通过MIMEBase来添加图片
# 指定图片为当前目录 with open('a.jpg', 'rb') as fp: # 设置附件的MIME和文件名,这里是png类型: mime = MIMEBase('image', 'jpg', filename='a.jpg') # 加上必要的头信息: mime.add_header('Content-Disposition', 'attachment', filename='附件显示名称.jpg') mime.add_header('Content-ID', '') # 如果有多个文件需要使用.format(index) mime.add_header('X-Attachment-Id', '0') # 如果有多个文件需要使用.format(index) # 把附件的内容读进来: mime.set_payload(fp.read()) # 用Base64编码: encoders.encode_base64(mime) # 添加到MIMEMultipart: message.attach(mime)
如果我们发送HTML邮件,收件人通过浏览器或者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('Hello', 'html', 'utf-8')) # 正常发送msg对象...
如果使用标准的25端口连接SMTP服务器发送邮件,即使身份验证成功,因为明文传输的缘故,整个邮件发送过程都有可能被窃听。要更安全地发送邮件,可以加密SMTP会话,实际上就是先创建SSL安全连接,然后再使用SMTP协议发送邮件。
在某些邮件服务提供商(例如Gmail)中,SMTP服务必须使用加密传输。我们来看看如何通过Gmail提供的安全SMTP发送邮件。
只需要在创建SMTP
对象后,立刻调用starttls()
方法,就创建了安全连接。后面的代码和前面的发送邮件代码完全一样。
必须知道,Gmail的SMTP端口是587,因此,修改代码如下:
smtp_server = 'smtp.gmail.com' smtp_port = 587 server = smtplib.SMTP(smtp_server, smtp_port) server.starttls() # 剩下的代码和前面的一模一样: server.set_debuglevel(1)
收取邮件就是编写一个MUA作为客户端,从MDA把邮件获取到用户的电脑或者手机上。收取邮件最常用的协议是POP协议,目前版本号是3,俗称POP3。
Python内置一个poplib
模块,实现了POP3协议,可以直接用来收邮件。
POP3 的命令和响应数据都是基于 ASCII 文本的,并以 CR 和 LF(/r/n) 作为行结束符,响应数据包括一个表示返回状态的符号(+/)和描述信息。
请求和响应的标准格式如下:
请求标准格式:命令 [参数] CRLF
响应标准格式:+OK /[-ERR] description CRLF
POP3 协议客户端的命令和服务器端对应的响应数据如下:
user name:向 POP 服务器发送登录的用户名。
pass string:向 POP 服务器发送登录的密码。
quit:退出 POP 服务器。
stat:统计邮件服务器状态,包括邮件数和总大小。
list [msg_no]:列出全部邮件或指定邮件。返回邮件编号和对应大小。
retr msg_no:获取指定邮件的内容(根据邮件编号来获取,编号从 1 开始)。
dele msg_no:删除指定邮件(根据邮件编号来删除,编号从 1 开始)。
noop:空操作。仅用于与服务器保持连接。
rset:用于撤销 dele 命令。
poplib 模块完全模拟了上面命令,poplib.POP3 或 poplib.POP3_SSL 为上面命令提供了相应的方法,开发者只要依次使用上面命令即可从服务器端下载对应的邮件
注意到POP3协议收取的不是一个已经可以阅读的邮件本身,而是邮件的原始文本,这和SMTP协议很像,SMTP发送的也是经过编码后的一大段文本。
要把POP3收取的文本变成可以阅读的邮件,还需要用email
模块提供的各种类来解析原始文本,变成可阅读的邮件对象。
所以,收取邮件分两步:
用POP3获取邮件其实很简单,要获取所有邮件,只需要循环使用retr()
把每一封邮件内容拿到即可。真正麻烦的是把邮件的原始内容解析为可以阅读的邮件对象。
import poplib from email.parser import Parser # email.parser 解析电子邮件,返回这个对象的email.message.Message实例 from email.header import decode_header from email.utils import parseaddr # 服务器及用户信息 host = 'mail.tcl.com' username = 'bobin.yang@tcl.com' password = 'Ybb7654321' # 连接到POP3服务器 conn = poplib.POP3_SSL(host) # 注意qq邮箱使用SSL连接 # 设置调试模式,可以看到与服务器的交互信息 conn.set_debuglevel(1) # 打印POP3服务器的欢迎文字 print(conn.getwelcome().decode("utf-8")) # 身份认证 conn.user(username) conn.pass_(password) # 获取服务器上信件信息,返回一个列表,第一项是一共有多少封邮件,第二项是共有多少字节 # stat()返回邮件数量和占用空间 mail_total, total_size = conn.stat() print('message: %s.Size:%s' % (mail_total, total_size)) # list()返回(response, ['mesg_num octets', ...], octets),第二项是编号 resp, mails, octets = conn.list() print(mails) # 返回的列表类似[b'1 82923', b'2 2184', ...] # 获取最新一封邮件,注意索引号从1开始 # POP3.retr(which) 检索序号which的这个邮件,然后设置他的出现标志 返回(response, ['line', ...], octets)这个三元组 resp, lines, ocetes = conn.retr(len(mails)) print('lines:', len(lines)) # lines 存储了邮件的原始文本的每一行 # 可以获得整个邮件的原始文本 print("-------------------")
消息
对象,然后,用适当的形式把邮件内容展示给用户即可。解析邮件的过程和上一节构造邮件正好相反。
程序在创建 BytesParser(解析字节串格式的邮件数据)或 Parser(解析字符串格式的邮件数据)时,必须指定 policy=default
;否则,BytesParse 或 Parser 解析邮件数据得到的就是过时的 Message 对象,,不是新的 EmailMessage,处理起来非常不方便。
msg = b'\r\n'.join(lines).decode('utf-8') # 解析出邮件 msg = Parser().parsestr(msg) # email.Parser.parsestr(text, headersonly=False) # 与parser()方法类似,不同的是他接受一个字符串对象而不是一个类似文件的对象 # 可选的headersonly表示是否在解析玩标题后停止解析,默认为否 # 返回根消息对象 # 编码处理,文本邮件的内容也是str,还需要检测编码,否则,非UTF-8编码的邮件都无法正常显示 def guess_charset(msg): charset = msg.get_charset() # 从msg对象获取编码 if charset is None: content_type = msg.get('Content-Type', '').lower() # 如果获取不到,再从content—type字段获取 if 'charset' in content_type: charset = content_type.split('charset=')[1].strip() return charset return charset # 数据解码,邮件的Subject或者Email中包含的名字都是经过编码后的str,要正常显示,就必须decode def decode_str(s): value, charset = decode_header(s)[0] # 数据,数据编码方式,from email.header import decode_header # decode_header()返回一个list,因为像Cc、Bcc这样的字段可能包含多个邮件地址,所以解析出来的会有多个元素。上面的代码我们偷了个懒,只取了第一个元素。 if charset: value = value.decode(charset) return value # print_ingo函数:解析邮件与构造邮件的步骤正好相反 def print_info(msg, indent=0): # indent用于缩进显示 if indent == 0: for header in ['From', 'To', 'Subject']: # 邮件的from、to、subject存在于根对象上 value = msg.get(header, '') if value: if header == 'Subject': value = decode_str(value) # 需要解码subject字符串 else: # 解码mail地址 hdr, addr = parseaddr(value) name = decode_str(hdr) value = '%s' % addr print('%s: %s %s' % (header, value, name)) print('-*-' * 20) if msg.is_multipart(): # 如果邮件对象是一个is_multipart,get_payload()返回一个list,包含所有子对象 parts = msg.get_payload() # 循环获得列表项 for n, part in enumerate(parts): # print('%spart %s' % (' ' * indent, n)) # print('%s------------' % (' ' * indent)) # 递归打印没一个子对象 print_info(part, indent + 1) else: # 邮件对象不是一个is_multipart,就根据content_type判断 content_type = msg.get_content_type() # 数据类型 if content_type == 'text/plain' or content_type == 'text/html': # 纯文本 html文本 # 纯文本或html内容 content = msg.get_payload(decode=True) # 获得文本对象的字符串而非对象本身 charset = guess_charset(msg) # 要检测文本编码 if charset: content = content.decode(charset) content = '%s' % (content) print(content) # 获取邮件文本内容,如果只有文本,打印显示的结果和邮件中看的效果一模一样 else: print(content_type+'不是文本') print_info(msg, 0) # 退出 conn.quit()
如果程序要获取邮件的发件人、收件人和主题,直接通过 EmailMessage 的相应属性来获取即可,与前面为 EmailMessage 设置发件人、收件人和主题的方式是对应的。
如果程序要读取 EmailMessage 的各部分,则需要调用该对象的 walk() 方法,该方法返回一个可迭代对象,程序使用 for 循环遍历 walk() 方法的返回值,对邮件内容进行逐项处理:
如果邮件某项的 maintype 是 'multipart',则说明这一项是容器,用于包含邮件内容、附件等其他项。
如果邮件某项的 maintype 是 'text',则说明这一项的内容是文本,通常就是邮件正文或文本附件。对于这种文本内容,程序直接将其输出到控制台中。
如果邮件中某个项的 maintype 属性是“其他”,那么这一项的内容就是作为附件的,程序会将附件内容保存到本地文件中。
import os import poplib import mimetypes from email.parser import Parser, BytesParser from email.policy import default msg_data = b'\r\n'.join(lines) # 将字符串内容解析成邮件,此处一定要指定policy=default msg = BytesParser(policy=default).parsebytes(msg_data) print(type(msg)) print('发件人:' + msg['from']) print('收件人:' + msg['to']) print('主题:' + msg['subject']) print('第一个收件人名字:' + msg['to'].addresses[0].username) print('第一个发件人名字:' + msg['from'].addresses[0].username) for part in msg.walk(): counter = 1 # 如果maintype是multipart,说明是容器(用于包含正文、附件等) if part.get_content_maintype() == 'multipart': continue # 如果maintype是multipart,说明是邮件正文部分 elif part.get_content_maintype() == 'text': print(part.get_content()) # 处理附件 else: # 获取附件的文件名 filename = part.get_filename() # 如果没有文件名,程序要负责为附件生成文件名 if not filename: # 根据附件的contnet_type来推测它的后缀名 ext = mimetypes.guess_extension(part.get_content_type()) # 如果推测不出后缀名 if not ext: # 使用.bin作为后缀名 ext = '.bin' # 程序为附件来生成文件名 filename = 'part-%03d%s' % (counter, ext) counter += 1 # 将附件写入的本地文件 with open(os.path.join('.', filename), 'wb') as fp: fp.write(part.get_payload(decode=True)) # 退出服务器,相当于发送POP 3的quit命令 conn.quit()
通过IMAP协议来管理邮箱用的,称作交互邮件访问协议。
! encoding:utf8 ''' 环境: Win10 64位 Python 2.7.5 参考: http://www.pythonclub.org/python-network-application/email-format http://blog.sina.com.cn/s/blog_4deeda2501016eyf.html ''' import imaplib import email def parseHeader(message): """ 解析邮件首部 """ subject = message.get('subject') h = email.Header.Header(subject) dh = email.Header.decode_header(h) subject = unicode(dh[0][0], dh[0][1]).encode('gb2312') # 主题 print subject print ' ' # 发件人 print 'From:', email.utils.parseaddr(message.get('from'))[1] print ' ' # 收件人 print 'To:', email.utils.parseaddr(message.get('to'))[1] print ' ' # 抄送人 print 'Cc:',email.utils.parseaddr(message.get_all('cc'))[1] def parseBody(message): """ 解析邮件/信体 """ # 循环信件中的每一个mime的数据块 for part in message.walk(): # 这里要判断是否是multipart,是的话,里面的数据是一个message 列表 if not part.is_multipart(): charset = part.get_charset() # print 'charset: ', charset contenttype = part.get_content_type() # print 'content-type', contenttype name = part.get_param("name") #如果是附件,这里就会取出附件的文件名 if name: # 有附件 # 下面的三行代码只是为了解码象=?gbk?Q?=CF=E0=C6=AC.rar?=这样的文件名 fh = email.Header.Header(name) fdh = email.Header.decode_header(fh) fname = dh[0][0] print '附件名:', fname # attach_data = par.get_payload(decode=True) # 解码出附件数据,然后存储到文件中 # try: # f = open(fname, 'wb') #注意一定要用wb来打开文件,因为附件一般都是二进制文件 # except: # print '附件名有非法字符,自动换一个' # f = open('aaaa', 'wb') # f.write(attach_data) # f.close() else: #不是附件,是文本内容 print part.get_payload(decode=True) # 解码出文本内容,直接输出来就可以了。 # pass # print '+'*60 # 用来区别各个部分的输出 def getMail(host, username, password, port=993): try: serv = imaplib.IMAP4_SSL(host, port) except Exception, e: serv = imaplib.IMAP4(host, port) serv.login(username, password) serv.select() # 搜索邮件内容 typ, data = serv.search(None, '(FROM "xx@xxx.com")') count = 1 pcount = 1 for num in data[0].split()[::-1]: typ, data = serv.fetch(num, '(RFC822)') text = data[0][1] message = email.message_from_string(text) # 转换为email.message对象 parseHeader(message) print ' ' parseBody(message) pcount += 1 if pcount > count: break serv.close() serv.logout() if __name__ == '__main__': host = "imap.mail_serv.com" # "pop.mail_serv.com" username = "Trevor@mail_serv.com" password = "your_password" getMail(host, username, password)
위 내용은 이메일, smtplib, poplib, imaplib 모듈을 사용하여 Python에서 이메일을 보내고 받는 방법의 상세 내용입니다. 자세한 내용은 PHP 중국어 웹사이트의 기타 관련 기사를 참조하세요!