在 Python进阶教程m9b–网络通信–smtplib发送邮件 一文中桔子菌给大家介绍了怎么用Python发送邮件,俗话说“来而不往非礼也”,有发就要有收,这篇文章将带大家熟悉下怎么用poplib和email模块接收邮件。

先做好准备工作,仍以163邮箱为例,首先需要先设置好邮箱的授权码,并找到邮箱的pop3服务器地址:

1、创建POP3()实例、登录

首先手动输入接收邮箱的地址和授权码,这里我们用到了getpass模块接收键盘输入的密码,这样密码不会显示在屏幕上,对比input()函数更安全些。

#输入邮箱地址、密码
to_addr = input('输入收件人: ')
password = getpass.getpass('收件人邮箱密码: ')
==========运行结果:
-----欢迎来到www.juzicode.com
-----公众号: 桔子code/juzicode
输入收件人: xxx@163.com
收件人邮箱密码:       ####这里因为使用getpass.getpass()方法,密码不显示

和接收邮件一样,传入pop3服务器地址“pop.163.com”创建一个POP3()实例,为了方便查看通信过程设置好调试打印等级,一般设置到2。因为创建POP3()实例会和服务器发起连接,这里用try语句捕获可能的异常。

#连接邮箱,设置调试等级
try:pop3 = poplib.POP3('pop.163.com')pop3.set_debuglevel(1) print(pop3)
except:print('连接服务器失败')sys.exit(1)

使用pop3.user()传入邮箱地址 和 pop3.pass_()方法传入授权码或邮箱密码(注意pass_()方法有下划线!), user() 和 pass_()方法会发起连接,可能会登录失败,也用try语句捕获异常。

#登录邮箱
try:ret=pop3.user(to_addr) print(ret)ret=pop3.pass_(password)print(ret)
except :  print('登录邮箱失败')sys.exit(1)
print('登录邮箱成功')
==========运行结果:
*cmd* 'USER xxx@163.com'
b'+OK core mail'
*cmd* 'PASS xxx'
b'+OK 5 message(s) [17765 byte(s)]'
登录邮箱成功

2、解析邮件

前面的过程完成了邮箱登录,下面开始读取和解析邮件。

2.1、获取邮件列表

用pop3.list()方法获取邮件消息列表,返回的是一个三元组:(response, [‘mesg_num octets’, …], octets) :

#获取邮件清单
mail_list = response, listings, octets = pop3.list()
print(mail_list)
==========结果:
*cmd* 'LIST'
(b'+OK 5 17765', [b'1 3429', b'2 10596', b'3 879', b'4 1481', b'5 1380'], 40)

listings = [b’1 3429′, b’2 10596′, b’3 879′, b’4 1481′, b’5 1380′] 这个列表就是我们需要的关键信息,表示获取到的邮件列表,包含了5个元素表示有5封邮件,b’1 3429′ 表示第1封邮件有3429字节, b’2 10596′ 表示第2封邮件,以此类推。每个元素内部由空格分隔,前面的数字表示mesg_num,这个值就是后面解析时用来表示的邮件索引号。敲黑板,这个是关键变量!

接下来开始遍历邮件列表listings,对它的单个元素用split()方法切割出mesg_num。另外因为返回的是bytes类型的数据,为了方便后面的处理,我们将其转换为str类型:

for listing in listings:print('~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~')#提取邮箱列表信息mesg_num, size = listing.split()mesg_num = bytes.decode(mesg_num)size = bytes.decode(size)print(mesg_num,size)

有了这些邮件消息编号,接下来就可以利用这些编号提取邮件header和正文等内容。

2.2、获取邮件Header

首先用pop3.top()方法提取邮件Header,top()方法输入的是邮件列表里解析出来的mesg_num。返回结果也是一个三元组,中间的lines是关键信息,因为是bytes类型,所以也需要转换为str类型。

    #提取邮件头res = response, lines, octets = pop3.top(mesg_num, 0)#print(lines)lines_post=[]for l in lines:lines_post.append(bytes.decode(l))

接下来用email.message_from_string()构造结构化数据,再提取From,To,Subject,Date等信息:

    #构造messagemessage = email.message_from_string('\n'.join(lines_post))print('type(message):',type(message))print('From:',message['From'])print('To:',message['To'])print('Subject:',message['Subject'])print('Date:',message['Date'])
==========结果:
4 1481
*cmd* 'TOP 4 0'
type(message): <class 'email.message.Message'>
From: xxx <xxx@163.com>
To: xxx <xxx@163.com>
Subject: https://www.juzicode.com/  vx:juzicode
Date: Wed, 11 Nov 2020 20:08:18 +0800 (CST)

2.3、获取邮件正文

用pop3.retr()方法提取邮件正文, retr()方法输入的也是邮件列表里解析出来的mesg_num。返回结果也是一个三元组,中间的lines是关键信息,因为是bytes类型,所以也需要转换为str类型。

    #提取邮件内容res = response, lines, octets = pop3.retr(mesg_num)lines_post=[]for l in lines:lines_post.append(bytes.decode(l))

接下来用email.message_from_string()构造结构化数据,这里我们先不考虑复杂的情况,先只处理类型为multipart和text类型的内容。

根据get_content_maintype()方法获取到不同的类型,需要做分支处理。如果是multipart,需要再次遍历;如果是text类型,就可以直接用get_payload()获取邮件正文。

这个例子中邮件内容的解码mail_content.decode() 尝试了UTF8和GBK 2种方式,也可能是其他编码方式,需要根据实际情况作出变化。

    #构造messagemessage = email.message_from_string('\n'.join(lines_post))    maintype = message.get_content_maintype()    print('maintype:',maintype)    if maintype == 'multipart':for part in message.get_payload():print('multipart:',part.get_content_maintype())if part.get_content_maintype() == 'text':mail_content = part.get_payload(decode=True).strip()try:print('mail_content:',mail_content.decode('UTF8'))  except:try:print('mail_content:',mail_content.decode('GBK'))  except:continueelif maintype == 'text':mail_content = message.get_payload(decode=True).strip()try:print('mail_content:',mail_content.decode('UTF8'))  except:  try:print('mail_content:',mail_content.decode('GBK'))  except:continue 
==========提取第5封邮件的结果:
*******************
*cmd* 'RETR 5'
maintype: multipart
multipart: text
mail_content: www.juzicode.com   微信公众号:桔子code
multipart: text
mail_content: &lt;div style="line-height:1.7;color:#000000;font-size:14px;font-family:Arial">&lt;p style="margin:0;">www.juzicode.com&amp;nbsp; &amp;nbsp;微信公众号:桔子code&lt;/p>&lt;/div>&lt;br>&lt;br>&lt;span title="neteasefooter">&lt;p>&amp;nbsp;&lt;/p>&lt;/span>

从网页进入邮箱看到的邮件内容是下图这样的,正好和前面第一次取到的text内容是一样的:“mail_content: www.juzicode.com 微信公众号:桔子code”

第2次取到的text内容则是html格式的邮件正文,我们可以创建一个文本文件,输入这段内容:<div style …… /p>,改后缀为html,然后用浏览器打开,看到的效果和第1次取得的text内容是一致的:

2.4 处理附件和复杂的邮件正文

上一节中处理邮件内容作了简化操作,比如解析文本内容的时候采用的是尝试按照UTF8和GBK 2种方式解码,不能完全自适应解析;如果邮件中有附件,也没有实现接收附件的功能 ;当message的主类型为multipart,只处理了2层,实际情况可能更复杂。接下来继续改造解析消息方式,因为multipart可能有多层,需要用递归来实现,我们定义一个parse_msg()的函数。

如果邮件带有附件,首先利用get_filename()方法获取附件文件名称,如果这个名称非空,则说明该段message是个附件,通过get_payload()方法可以提取出数据,并将该数据写入到文件中:

    #如果get_filename()返回非None,表示有附件filename = message.get_filename()if filename:print('找到1个附件,文件名:',filename)data=message.get_payload(decode=True)with open(filename,'wb') as pf:pf.write(data)        return filename

通过放开调试打印,我们可以看到邮件正文使用的字符集(编码方式): b’Content-Type: text/plain; charset=GBK\r\n’,利用get_content_charset()方法就能获取到邮件正文的编码方式 ,如果是消息主类型为text,则可以用该编码方式解析:

    #如果主类型为text,根据编码方式解析content_charset = message.get_content_charset()print('content_charset:',content_charset)          if maintype == 'text':mail_content = message.get_payload(decode=True).strip()try:print('mail_content:\n',mail_content.decode(content_charset))  except:  print('解码邮件错误') 

如果主类型是multipart,则调用自己,实现递归解析消息:

    elif maintype == 'multipart':for message_part in message.get_payload():parse_msg(message_part)        

完整的消息解析函数:

def parse_msg(message):type = message.get_content_type() maintype = message.get_content_maintype()    subtype = message.get_content_subtype()print('type:',type)        print('maintype:',maintype)    print('subtype:',subtype)  boundary = message.get_boundary()print('boundary:',boundary) #如果get_filename()返回非None,表示有附件filename = message.get_filename()if filename:print('找到1个附件,文件名:',filename)data=message.get_payload(decode=True)with open(filename,'wb') as pf:pf.write(data)        return filename#如果主类型为text,根据编码方式解析content_charset = message.get_content_charset()print('content_charset:',content_charset)          if maintype == 'text':mail_content = message.get_payload(decode=True).strip()try:print('mail_content:\n',mail_content.decode(content_charset))  except:  print('解码邮件错误')  #如果主类型为multipart,递归elif maintype == 'multipart':for message_part in message.get_payload():parse_msg(message_part)            return 

这是解析其中一封邮件的过程:

*cmd* 'RETR 5'
type: multipart/mixed
maintype: multipart
subtype: mixed
boundary: ----=_Part_70354_1982485947.1605182620221
content_charset: None
type: multipart/alternative
maintype: multipart
subtype: alternative
boundary: ----=_Part_70356_1595858516.1605182620221
content_charset: None
type: text/plain
maintype: text
subtype: plain
boundary: None
content_charset: gbk
mail_content:微信公众号:桔子code  ,这是一个包含二进制附件的邮件
type: text/html
maintype: text
subtype: html
boundary: None
content_charset: gbk
mail_content:<div style="line-height:1.7;color:#000000;font-size:14px;font-family:Arial"><p>微信公众号:桔子code&nbsp;&nbsp;,这是一个包含二进制附件的邮件<br></p></div><br><br><span title="neteasefooter"><p>&nbsp;</p></span>
type: application/vnd.ms-excel
maintype: application
subtype: vnd.ms-excel
boundary: None
找到1个附件,文件名: attached1.xls

进入邮箱看到的邮件正文、附件和前面解析到结果是一样的:

总结:到这里整个接收邮件的过程就介绍完了,主要是2大步骤:第一步poplib模块接收邮件:创建连接实例、登录、获取邮件头、获取邮件正文;第二步用email模块进行邮件内容的解析。


推荐阅读:
Python进阶教程m9–网络通信–socket通信
Python进阶教程m9b–网络通信–smtplib发送邮件 

关注微信公众“桔子code”,在后台回复“python教程”,可以获得Python桔子教程的全套源码。

Python网络通信~pop3接收邮件相关推荐

  1. python使用POP3获取邮件信息

    一. 前言 曾经写过一篇利用python库SMTP发送邮箱以控制电脑的文章, 文章链接点击这里 现在回头看, 有很多做的不完美的地方, 其中最重要的点是无法主动控制电脑, 只能被动地等待程序触发某个条 ...

  2. Qt pop3接收邮件并下载附件程序

    功能简介:帮朋友做的自动登陆邮箱接收邮件,并把邮件保存到数据库,附件下载到工程目录. 环境:qtcreator5.4,MSVC2013-Opengl,数据库:mysql 用到的第三方库https:// ...

  3. Powershell 通过POP3接收邮件

     ################################################################################ #POP3接收邮件代码 func ...

  4. python学习——POP3收取邮件

    SMTP用于发送邮件,如果要收取邮件呢? 收取邮件就是编写一个MUA作为客户端,从MDA把邮件获取到用户的电脑或者手机上.收取邮件最常用的协议是POP协议,目前版本号是3,俗称POP3. Python ...

  5. 使用python发送邮件和接收邮件

    发邮件是大家工作中最常用到的.今天来看一下怎么用python来发送和接收邮件. python实现发送和接收邮件功能主要用到poplib和smtplib模块. poplib用于接收邮件,而smtplib ...

  6. 用python发邮件为什么接收不了_使用python发送邮件和接收邮件

    发邮件是大家工作中最常用到的.今天来看一下怎么用python来发送和接收邮件. python实现发送和接收邮件功能主要用到poplib和smtplib模块. poplib用于接收邮件,而smtplib ...

  7. java imap 乱码_php imap/pop3 接收邮件类,解决中文乱码

    小弟目的想在嵌入式开发板上实现接收邮件,当然谷歌了一下,发现还是有很多实现方法的:php最简单,C socket实现效率最高(我是这么感觉),当然也少不了python实现(不过还没动手测试)等等. 今 ...

  8. java pop3 接收邮件_JavaMail POP3接收邮件示例

    /** * CrazyItTest * 使用JavaMail 编写接收邮件示例 */ package com.labci.javamail.test; import java.io.BufferedR ...

  9. java pop3 接收邮件_JavaMail使用POP3协议接收并解析电子邮件

    JavaMail使用POP3协议接收并解析电子邮件 代码片段:public static void main(String[] args) throws Exception { receive(); ...

最新文章

  1. python实训心得2000_实训总结万能版2000字五篇
  2. .NET(C#)时间日期字符串(String)格式化转换成Datetime异常报错问题
  3. 算法导论之图的基本算法
  4. CentOS中通过NAT连接网络
  5. 沉淀再出发:关于java中的AQS理解
  6. java 排序 1和1_新手入门-冒泡排序和选择排序第一节排序1.1排序概述排序(
  7. ffmpeg编译的静态链接库问题
  8. python遥感影像分类代码_Python 实现遥感影像波段组合的示例代码
  9. java oop6_JavaOOP_03 构造方法
  10. 文件的记录c语言程序,急求如何将下列C语言程序数据存储到文件中?
  11. 比较完善的手写数组reduce方法
  12. js模拟ps吸管吸取颜色功能
  13. redis配置文件redis.conf中bind详解
  14. 51单片机电路原理图_51单片机入门(第1篇):纯干货,单片机最小系统
  15. hysys动态模拟教程_(转载)HYSYS-过程模拟软件-稳态模拟-第一部分(一)
  16. S7-1200PLC CPU集成模拟量输入通道接线和编程
  17. Description: A component required a bean of type ‘com.jia.dao.UserDao‘ that
  18. gerrit 邮箱配置 及 验证问题
  19. python在使用绝对路径时出现OSError: [Errno 22] Invalid argument: ‘E:\python\python扩展\text_file\pi_digits.txt
  20. 从零开始再造打爆李世石的AlphaGo:创造能下围棋的机器人

热门文章

  1. H264视频传输、编解码----RTP协议对H264数据帧拆包、打包、解包过程
  2. 抖音很火的设备性能在线测试
  3. 利用d3.js对大数据资料进行可视化分析
  4. java txt替换内容_使用Java替换文件中的文本
  5. R语言与马克维茨资产组合理论学习笔记(fportfolio包简介)
  6. JAVA 用Steam求和
  7. 刷脸支付技术引领产业链加速冲刺正在上演
  8. 英特尔频频收购,意欲何为?
  9. NGUI PK UGUI
  10. 支付宝小程序商品加入购物车动画