1. IMAP
IMAP:Internet Mail Access Protocol,Internet邮件访问协议。规定了如何与邮件提供商的服务器通信,取回发送到你的邮箱的的电子邮件。Python自带一个imaplib模块,但是第三方的imapclient更易用。然后使用pyzmail模块对邮件进行解析。
2. 用 IMAP 获取和删除电子邮件
1) 连接到 IMAP 服务器
就像你需要一个 SMTP 对象连接到 SMTP 服务器并发送电子邮件一样,你需要一个 IMAPClient 对象,连接到 IMAP 服务器并接收电子邮件。使用imapclient.IMAPClient()函数,创建一个IMAPClient对象。同时,大多数电子邮件提供商要求 SSL 加密,传入 SSL= TRUE 关键字参数。示例:
>>>import imapclient >>>imapObj = imapclient.IMAPClient('imap.qq.com', ssl=True)
2) 登录到 IMAP 服务器
取得IMAP对象后,调用它的login()方法,传入用户名和密码进行登陆。示例:
>>> imapObj.login('XXX@qq.com','QQ邮箱授权码') b'Success login ok'
3) 搜索电子邮件
登录后,实际获取你感兴趣的电子邮件分为两步。首先,必须选择要搜索的文件夹。然后,必须调用 IMAPClient 对象的search()方法,传入 IMAP 搜索关键词字符串。
4) 选择文件夹
几乎每个账户默认都有一个INBOX 文件夹,但也可以调用 IMAPClient 对象的list_folders()方法,获取文件夹列表。这将返回一个元组的列表。每个元组包含一个文件夹的信息。
>>>import pprint >>>pprint.pprint(imapObj.list_ _folders()) [((b'\\NoSelect',b'\\HasChildren'), b'/', '其他文件夹'), ((b'\\HasNoChildren',), b'/', 'INBOX'), ((b'\\HasNoChildren',), b'/', 'SentMessages'), ((b'\\HasNoChildren',), b'/', 'Drafts'), ((b'\\HasNoChildren',), b'/', 'DeletedMessages'), ((b'\\HasNoChildren',), b'/', 'Junk'), ((b'\\HasNoChildren',), b'/', '其他文件夹/QQ邮件订阅')]
要选择一个文件夹进行搜索,就调用 IMAPClient 对象的select_folder()方法,传入该文件夹的名称字符串。示例:
imapObj.select_folder('INBOX', readonly=True)
5) 执行搜索
文件夹选中后,就可以用IMAPClient 对象的 search()方法搜索电子邮件。search()的参数是一个字符串列表,每一个格式化为 IMAP 搜索键。示例:
>>>imapObj.search(['ALL']) [380, 381, 382, 383, 384, 385, 400, 519,539, 540, 541, 542, 543, 544]
search()函数返回邮件的唯一ID(UID),然后,可以将这些 UID传入 fetch()方法,获得邮件内容。
6) 大小限制
如果你的搜索匹配大量的电子邮件,Python可能抛出异常 imaplib.error: got more than 10000 bytes。如果发生这种情况,必须断开并重连 IMAP 服务器,然后再试。这个限制是防止Python 程序消耗太多内存。遗憾的是,默认大小限制往往太小。可以执行下面的代码,将限制从 10000 字节改为 10000000 字节:
>>> import imaplib >>> imaplib._ _MAXLINE = 10000000
这应该能避免该错误消息再次出现。也许要在你写的每一个 IMAP 程序中加上这两行。
7) 取邮件并标记为已读
得到UID的列表后,可以调用imapclient.fetch()方法获得实际的电子邮件内容。UID 列表是 fetch()的第一个参数。第二个参数应该是['BODY[]'],它告诉 fetch()下载 UID 列表中指定电子邮件的所有正文内容。示例:
>>>rawMessages = imapObj.fetch(UIDs, ['BODY[]']) >>>import pprint >>>pprint.pprint(rawMessages) defaultdict(<class'dict'>, {519: {b'BODY[]': b'Received: frommail.paymentwall.com (unknown' b'[216.127.71.105])\r\n\tby newmx1000.qq.com (Ne' ...... b'olor:#333;">=E6=9C=8D=E5=8A=A1=\r\n=E6=9D=A1=' b'E6=AC=BE</a></td></tr></tbody></table></td><' b'/tr></tbody></tabl=\r\ne></td></tr></tbody></t' b'able></body></html>\r\n', b'SEQ': 1}})
如果希望在获取邮件的时候,就需要将 readonly=False 传入 select_folder()。示例:
>>>imapObj.select_folder(‘INBOX’,readonly= False)
8) 从原始消息中获取电子邮件地址
调用pyzmail.PeekMessage.factory()函数,传入原始邮件的'BODY[]'部分可以获得PyzMessage对象。示例:
>>>message.get_ _subject() 'Hello!' >>>message.get_ _addresses('from') [('EdwardSnowden', 'esnowden@nsa.gov')] >>>message.get_ _addresses('to') [(Jane Doe','my_email_address@gmail.com')] >>>message.get_ _addresses('cc') [] >>>message.get_ _addresses('bcc') []
在这里,‘cc’表示抄送,‘bcc’表示密送。
9) 从原始消息中获取正文
如果电子邮件仅仅是纯文本,它的PyzMessage对象会将html_part 属性设为None。同样,如果电子邮件只是HTML,它的PyzMessage 对象会将text_part 属性设为None。
text_part 或 html_part 将有一个 get_payload()方法,将电子邮件的正文返回为 bytes 数据类型。对 get_payload()返回的 bytes 值调用 decode()方法。decode()方法接受一个参数:这条消息的字符编码,保存在 text_part.charset或 html_part.charset 属性中。最后,这返回了邮件正文的字符串。示例:
>>>message.text_ _part != None True >>>message.text_ _part.get_ _payload().decode(message.text_ _part.charset) 'So long, andthanks for all the fish!\r\n\r\n-Al\r\n' >>>message.html_ _part != None True >>>message.html_ _part.get_ _payload().decode(message.html_ _part.charset) '<divdir="ltr"><div>So long, and thanks for all thefish!<br><br></div>-Al <br></div>\r\n'
10)删除电子邮件
向 IMAPClient.delete_messages()方法传入一个消息UID 的列表。这为电子邮件加上\Deleted 标志。调用 expunge()方法,将永久删除当前选中的文件夹中带\Deleted 标志的所有电子邮件。示例:
>>>imapObj.select_ _folder('INBOX', readonly=False) >>>UIDs = imapObj.search(['ON 09-Jul-2015']) >>>UIDs [40066] >>>imapObj.delete_ _messages(UIDs) {40066:('\\Seen', '\\Deleted')} >>>imapObj.expunge() ('Success',[(5452, 'EXISTS')])
11) 从 IMAP 服务器断开
如果程序已经完成了获取和删除电子邮件,就调用 IMAPClient 的 logout()方法,从 IMAP 服务器断开连接。示例:
>>> imapObj.logout()