Python学习笔记(四十八)POP3收取邮件
2017-09-17 00:01
531 查看
收取邮件就是编写一个MUA作为客户端,从MDA把邮件获取到用户的电脑或者手机上。收取邮件最常用的协议是POP协议,目前版本号是3,俗称POP3。
Python内置一个
注意到POP3协议收取的不是一个已经可以阅读的邮件本身,而是邮件的原始文本,这和SMTP协议很像,SMTP发送的也是经过编码后的一大段文本。
要把POP3收取的文本变成可以阅读的邮件,还需要用
所以,收取邮件分两步:
第一步:用poplib把邮件的原始文本下载到本地;
第二部:用email解析原始文本,还原为邮件对象。
用POP3获取邮件其实很简单,要获取所有邮件,只需要循环使用
只需要一行代码就可以把邮件内容解析为
但是这个
所以我们要递归地打印出
邮件的Subject或者Email中包含的名字都是经过编码后的str,要正常显示,就必须decode:
文本邮件的内容也是str,还需要检测编码,否则,非UTF-8编码的邮件都无法正常显示:
把上面的代码整理好,我们就可以来试试收取一封邮件。先往自己的邮箱发一封邮件,然后用浏览器登录邮箱,看看邮件收到没,如果收到了,我们就来用Python程序把它收到本地:
我们从打印的结构可以看出,这封邮件是一个
注意:用qq邮箱(修改这段代码)
Python内置一个
poplib模块,实现了POP3协议,可以直接用来收邮件。
注意到POP3协议收取的不是一个已经可以阅读的邮件本身,而是邮件的原始文本,这和SMTP协议很像,SMTP发送的也是经过编码后的一大段文本。
要把POP3收取的文本变成可以阅读的邮件,还需要用
所以,收取邮件分两步:
通过POP3下载邮件
POP3协议本身很简单,以下面的代码为例,我们来获取最新的一封邮件内容:importpoplib #输入邮件地址,口令和POP3服务器地址: fromemail.parserimportParser email=input('Email:') password=input('Password:') pop3_server=input('POP3server:') #连接到POP3服务器 server=poplib.POP3(pop3_server) #可以打开或关闭调试信息: server.set_debuglevel(1) #可选:打印POP3服务器的欢迎文字: print(server.getwelcome().decode('utf-8')) #身份认证: server.user(email) server.pass_(password) #stat()返回邮件数量和占用空间: print('Message:%s.Size:%s'%server.stat()) #list()返回所有邮件的编号: resp,mails,octets=server.list() #可以查看返回的列表类似[b'182923',b'22184',....] print(mails) #获取最新一封邮件,注意索引号从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) #可以根据邮件索引号直接从服务器删除邮件: #server.dele(index) #关闭连接: server.quit()
用POP3获取邮件其实很简单,要获取所有邮件,只需要循环使用
retr()把每一封邮件内容拿到即可。真正麻烦的是把邮件的原始内容解析为可以阅读的邮件对象。
解析邮件
解析邮件的过程和上一节构造邮件正好相反,因此,先导入必要的模块:fromemail.parserimportParser fromemail.headerimportdecode_header fromemail.utilsimportparseaddr importpoplib
只需要一行代码就可以把邮件内容解析为
Message对象:
msg=Parser().parsestr(msg_content)
但是这个
Message对象本身可能是一个
MIMEMultipart对象,即包含嵌套的其他
MIMEBase对象,嵌套可能还不止一层。
所以我们要递归地打印出
Message对象的层次结构:
#递归地打印出Message对象的层次结构: #indent用于缩进显示: defprint_info(msg,indent=0): ifindent==0: forheaderin['From','To','Subject']: value=msg.get(header,'') ifvalue: ifheader=='Subject': value=decode_str(value) else: hdr,addr=parseaddr(value) name=decode_str(hdr) value=u'%s<%s>'%(name,addr) print('%s%s:%s'%(''*indent,header,value)) if(msg.is_multipart()): parts=msg.get_payload() forn,partinenumerate(parts): print('%spart%s'%(''*indent,n)) print('%s-------------------'%(''*indent)) print_info(part,indent+1) else: content_type=msg.get_content_type() ifcontent_type=='text/plain'orcontent_type=='text/html': content=msg.get_payload(decode=True) charset=guess_charset(msg) ifcharset: content=content.decode(charset) print('%sText:%s'%(''*indent,content+'...')) else: print('%sAttachment:%s'%(''*indent,content_type))
邮件的Subject或者Email中包含的名字都是经过编码后的str,要正常显示,就必须decode:
defdecode_str(s): value,charset=decode_header(s)[0] ifcharset: value=value.decode(charset) returnvalue
decode_header()返回一个list,因为像
Cc、
Bcc这样的字段可能包含多个邮件地址,所以解析出来的会有多个元素。上面的代码我们偷了个懒,只取了第一个元素。
文本邮件的内容也是str,还需要检测编码,否则,非UTF-8编码的邮件都无法正常显示:
defguess_charset(msg): charset=msg.get_charset() ifcharsetisNone: content_type=msg.get('Content-Type','').lower() pos=content_type.find('charset=') ifpos>=0: charset=content_type[pos+8:].strip() returncharset
把上面的代码整理好,我们就可以来试试收取一封邮件。先往自己的邮箱发一封邮件,然后用浏览器登录邮箱,看看邮件收到没,如果收到了,我们就来用Python程序把它收到本地:
Email:17805054367@163.com Password:************** POP3server:pop3.163.com +OKWelcometocoremailMailPop3Server(163coms[726cd87d72d896a1ac393507346040fas]) *cmd*'USER17805054367@163.com' *cmd*'PASS************' *cmd*'STAT' *stat*[b'+OK',b'4',b'108715'] Message:4.Size:108715 *cmd*'LIST' [b'13418',b'28115',b'394797',b'42385'] *cmd*'RETR4' *cmd*'QUIT' From:淮豆居士<jdouzi@qq.com> To:17805054367<17805054367@163.com> Subject:17805054367<17805054367@163.com> part0 ------------------- part1 -------------------
我们从打印的结构可以看出,这封邮件是一个
MIMEMultipart,它包含两部分:第一部分又是一个
MIMEMultipart,第二部分是一个附件。而内嵌的
MIMEMultipart是一个
alternative类型,它包含一个纯文本格式的
MIMEText和一个HTML格式的
MIMEText。
小结
用Python的poplib模块收取邮件分两步:第一步是用POP3协议把邮件获取到本地,第二步是用
Message对象,然后,用适当的形式把邮件内容展示给用户即可。
全部代码:
importpoplib #输入邮件地址,口令和POP3服务器地址: fromemail.parserimportParser #先导入模块,用于解析邮件 fromemail.headerimportdecode_header fromemail.utilsimportparseaddr email=input('Email:') password=input('Password:') pop3_server=input('POP3server:') #连接到POP3服务器 server=poplib.POP3(pop3_server) #可以打开或关闭调试信息: server.set_debuglevel(1) #可选:打印POP3服务器的欢迎文字: print(server.getwelcome().decode('utf-8')) #身份认证: server.user(email) server.pass_(password) #stat()返回邮件数量和占用空间: print('Message:%s.Size:%s'%server.stat()) #list()返回所有邮件的编号: resp,mails,octets=server.list() #可以查看返回的列表类似[b'182923',b'22184',....] print(mails) #获取最新一封邮件,注意索引号从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) #可以根据邮件索引号直接从服务器删除邮件: #server.dele(index) #关闭连接: server.quit() #把邮件内容解析为Message对象: msg=Parser().parsestr(msg_content) #递归地打印出Message对象的层次结构: #indent用于缩进显示: defprint_info(msg,indent=0): ifindent==0: forheaderin['From','To','Subject']: value=msg.get(header,'') ifvalue: ifheader=='Subject': value=decode_str(value) else: hdr,addr=parseaddr(value) name=decode_str(hdr) value=u'%s<%s>'%(name,addr) print('%s%s:%s'%(''*indent,header,value)) if(msg.is_multipart()): parts=msg.get_payload() forn,partinenumerate(parts): print('%spart%s'%(''*indent,n)) print('%s-------------------'%(''*indent)) print_info(part,indent+1) else: content_type=msg.get_content_type() ifcontent_type=='text/plain'orcontent_type=='text/html': content=msg.get_payload(decode=True) charset=guess_charset(msg) ifcharset: content=content.decode(charset) print('%sText:%s'%(''*indent,content+'...')) else: print('%sAttachment:%s'%(''*indent,content_type)) defdecode_str(s): value,charset=decode_header(s)[0] ifcharset: value=value.decode(charset) returnvalue defguess_charset(msg): charset=msg.get_charset() ifcharsetisNone: content_type=msg.get('Content-Type','').lower() pos=content_type.find('charset=') ifpos>=0: charset=content_type[pos+8:].strip() returncharset print_info(msg)
注意:用qq邮箱(修改这段代码)
server=poplib.POP3_SSL(pop3_server,port=995)
相关文章推荐
- python学习——POP3收取邮件
- python学习笔记------发送邮件(文本和html)
- Python学习笔记18-发送邮件
- python学习笔记(SMTP邮件发送:带附件)
- python模块之poplib: 用pop3收取邮件
- python模块之poplib: 用pop3收取邮件
- Python 学习笔记 发送邮件
- 【Python学习笔记】-自动发送邮件脚本
- python模块之poplib: 用pop3收取邮件
- Python POP3 收取邮件
- python模块之poplib: 用pop3收取邮件
- python学习笔记[3]-邮件的发送
- python小例子之6 -- pop3协议收取邮件
- Python学习笔记-邮件模块SMTP
- Python学习笔记(四十七)SMTP发送邮件
- Python基础 POP3 收取邮件
- Python学习:用POP3接受邮件
- Python学习笔记 --- 利用STMP协议发送邮件
- 8.python学习笔记:python发送邮件
- python学习笔记(十二):发送邮件