在我们的工作中,基本都用过邮件客户端,比如OutLook、Foxmail。从配置项我们可以知道,发送邮件使用SMTP协议,接收邮件使用POP3和IMAP协议。其实很多编程语言都有此类协议的实现,Python也不例外。标准库smtplib、poplib和imaplib是相应协议的实现。至于发送邮件,初学者不建议使用smtplib,推荐使用djangomail。详情见上面最简单的发送邮件的方式,这样程序就可以在出错的时候自动发送邮件。今天分享一下如何使用poplib和imaplib来接收邮件。你说这两个都可以用来收邮件,你应该用哪个?我们先来看看它们的区别。POP3和IMAP的区别POP3协议是PostOfficeProtocol3的缩写,即第三版邮局协议,是TCP/IP协议族的一员,默认端口为110。这协议主要用于支持使用客户端远程管理服务器上的电子邮件。IMAP的全称是InternetMailAccessProtocol,即InteractiveMailAccessProtocol,是一种应用层协议,端口为143。用于从本地邮件客户端访问远程服务器上的邮件。POP3工作在传输层,而IMAP工作在应用层。从这个角度来看,IMAP更先进,事实上也确实如此。虽然这两种协议都是从邮件服务器下载邮件到本地,但不同的是IMAP提供双向通信,即在客户端所做的修改会反馈到服务器端,并与服务器端同步,这样如删除邮件,创建文件夹等。但是POP3是一种单向通信,即把邮件下载到本地就可以了,所做的修改只是在客户端,不会反映到客户端服务器端。所以使用IMAP协议会更方便、体验更好、更可靠。因此,如果要将邮件的更改同步到服务器,则使用IMAP,否则使用POP3POP3发送邮件以下面的代码为例,我们获取最新的邮件内容:server=poplib.POP3(settings.pop3_server)#Authentication:server.user(settings.email)server.pass_(settings.password)#stat()返回邮件数量和占用空间:print('Messages:%s.size:%s'%server.stat())#list()返回所有邮件的数量:resp,mails,octets=server.list()#可以查看返回的列表如[b'182923',b'22184',...]#获取最新邮件,注意索引号从1开始:latest_mail_index=len(mails)resp,lines,octets=server.retr(latest_mail_index)#lines存放邮件原文的每一行,#可以得到整封邮件的原文:msg_content=b'\r\n'.join(lines).decode('utf-8')#稍后解析邮件:msg=Parser().parsestr(msg_content)print_info(msg)#邮件索引号直接从服务器删除邮件#server.dele(index)#关闭连接:server.quit()执行结果如下:poplib分两步收集邮件:第一步获取邮件列表,第二步是使用email模块将原始邮件解析为Message对象,然后以合适的形式显示邮件内容。print_info函数的逻辑比较复杂,放在utils.py中。完整代码见文末链接。基于poplib的三方库使用过标准库poplib和三方库zmail。只想说,三方库用起来还是爽的。zmailZmail在Python3中使发送和接收电子邮件更容易。您不需要手动添加服务器地址、端口和适当的协议,zmail会为您完成。此外,使用字典来表示电子邮件内容更直观。Zmail只支持Python3,不依赖任何第三方库。安装方式:pipinstallzmail特点:自动查找服务器地址和端口自动使用可靠的链接协议自动将python字典映射到MIME对象(带附件)自动添加头文件和本地主机名以防止服务器拒绝您的电子邮件轻松自定义您的标题文件仅支持使用HTML作为邮件内容python>=3.5,您可以将其嵌入到您的项目中,无需其他依赖示例代码:importzmailserver=zmail.server('yourmail@example.com','yourpassword')#Sendmailserver.send_mail('yourfriend@example.com',{'subject':'Hello!','content_text':'Byzmail.'})#Ortoalistoffriends.server.send_mail(['friend1@example.com','friend2@example.com'],{'subject':'Hello!','content_text':'Byzmail.'})#Retrievemaillatest_mail=server.get_latest()zmail.show(latest_mail)可见接收最新的Mail只需要两行代码:latest_mail=server.get_latest()zmail.show(latest_mail)执行结果are如下:非常简洁易用。文档:https://github.com/zhangyunhao116/zmail/blob/master/README-cn.mdimap接收163等很多主流邮箱的邮件,qq邮箱默认关闭了imap服务,可以手动去邮箱打开账户设置页面,生成一个授权码,就是代码中登录的密码。获取最新邮件并显示:importimaplibimportemail#导入两个库importsettingsfromutilsimportprint_infoM=imaplib.IMAP4_SSL(host=settings.imap_server)print('连接到服务器')M.login(settings.email,settings.password)print('登录')print(M.noop())M.select()typ,data=M.search(None,'ALL')fornumindata[0].split():typ,data=M.fetch(num,'(RFC822)')#print('Message%s\n%s\n'%(num,data[0][1]))#print(data[0][1].decode('utf-8'))msg=email.message_from_string(data[0][1].decode('utf-8'))print_info(msg)breakM.close()M.logout()结果如下:基于三方imaplib库,您可能会问:为什么要为Python创建另一个IMAP客户端库?Python标准库不是已经有imaplib了吗?imaplib的问题在于它的级别非常低。它使用起来相当复杂,您可能不得不处理很多细节,而且由于IMAP服务器响应可能非常复杂,这意味着每个使用imaplib的人最终都会编写自己脆弱的解析器。此外,imaplib没有很好地利用异常。这意味着您需要检查每次调用imaplib的返回值,以查看请求是否成功。下面推荐两个常用的三方库。imapclientimapclient在内部使用的imaplib,但比imaplib好用的多,示例代码如下:importsslfromimapclientimportIMAPClientimportsettings#contextmanagerensuresthesessioniscleanedupssl_context=ssl.create_default_context()#don'tcheckifcertificatehostnamedoesn'tmatchtargethostnamessl_context.check_hostname=False#don'tcheckifthecertificateistrustedbyacertificateauthorityssl_context.verify_mode=ssl.CERT_NONEwithIMAPClient(host=settings.imap_server,ssl_context=ssl_context)asclient:client.login(settings.account,settings.password)select_info=client.select_folder('INBOX')print('%dmessagesinINBOX'%select_info[b'EXISTS'])#searchcriteriaarepassedinastraightforwardway#(nestingissupported)messages=client.search(['FROM','xxxx@163.com'])#`response`iskeyedbymessageidandcontainsparsed,#convertedresponseitems.formessage_id,datainclient.fetch(消息,['信封']).items():envelope=data[b'ENVELOPE']print('{id}:subject:{subject}date:{date}'.format(id=message_id,subject=envelope.subject.decode(),date=envelope.date))文档:https://github.com/mjs/imapclientimap_tools通过IMAP处理电子邮件和邮箱,支持以下功能:解析电子邮件消息属性以生成用于搜索电子邮件的查询使用文件夹的操作:copy,delete,mark,move,see,append使用文件夹的操作:list,set,get,create,exist,rename,delete,statustest@mail.com','pwd')asmailbox:subjects=[msg.subjectformsginmailbox.fetch()]#getlistofemailsubjectsfromINBOXfolder-equivalentverbosversionmailbox=Mailimap.mail.com')mailbox.login('test@mail.com','pwd',initial_folder='INBOX')#ormailbox.folder.setinstead3dargsubjects=[msg.subjectformsginmailbox.fetch(AND(all=True))]mailbox.logout()文档:https://github.com/ikvk/imap_toolsFinalwords完整示例代码:https://github.com/somenzz/tutorial/tree/master/email使用标准库帮助我们加深了对邮件协议细节的理解,但是第三方库可以直接使用,不用考虑太多细节。标准库相当于手动传输,第三方库相当于自动传输。使用哪一种,选择最适合自己的
