当前位置:嗨网首页>书籍在线阅读

20-搜索电子邮件

  
选择背景色: 黄橙 洋红 淡粉 水蓝 草绿 白色 选择字体: 宋体 黑体 微软雅黑 楷体 选择字体大小: 恢复默认

18.5.3 搜索电子邮件

登录后,实际获取你感兴趣的电子邮件分为两步。首先,必须选择要搜索的文件夹。然后,必须调用 IMAPClient 对象的 search() 方法,向其传入IMAP搜索关键词字符串。

选择文件夹

几乎每个账户默认有一个INBOX文件夹, 但也可以调用 IMAPClient 对象的 list_folders() 方法来获取文件夹列表。这将返回一个元组的列表。每个元组包含一个文件夹的信息。输入以下代码,继续演示交互式环境的例子:

>>> import pprint
>>> pprint.pprint(imapObj.list_folders())
[(('\\HasNoChildren',), '/', 'Drafts'),
 (('\\HasNoChildren',), '/', 'Filler'),
 (('\\HasNoChildren',), '/', 'INBOX'),
 (('\\HasNoChildren',), '/', 'Sent'),
--snip--
 (('\\HasNoChildren', '\\Flagged'), '/', 'Starred'),
 (('\\HasNoChildren', '\\Trash'), '/', 'Trash')]

每个元组的3个值,例如 (('\\HasNoChildren',), '/', 'INBOX') ,其解释如下。

  • 该文件夹的标志的元组(这些标志代表到底是什么超出了本书的讨论范围,你可以放心地忽略该字段)。
  • 名称字符串中用于分隔父文件夹和子文件夹的分隔符。
  • 该文件夹的全名。

要选择一个文件夹进行搜索,就调用 IMAPClient 对象的 select_folder() 方法,传入该文件夹的名称字符串:

>>> imapObj.select_folder('INBOX', readonly=True)

可以忽略 select_folder() 的返回值。如果所选文件夹不存在,Python会抛出 imaplib.error 异常。

readonly=True 关键字参数可以防止你在随后的方法调用中,不小心更改或删除该文件夹中的任何电子邮件。除非你想删除电子邮件,否则将 readonly 设置为 True 总是个好主意。

执行搜索

文件夹选中后,就可以用 IMAPClient 对象的 search() 方法搜索电子邮件。 search() 的参数是一个字符串列表,每一个被格式化为IMAP搜索键。表18-3介绍了IMAP的各种搜索键。

请注意,在处理标志和搜索键方面,某些IMAP服务器的实现可能稍有不同。可能需要在交互式环境中试验一下,看看它们实际的行为如何。

在传入 search() 方法的列表参数中,可以有多个IMAP搜索键字符串。返回的消息将匹配所有的搜索键。如果想匹配任何一个搜索键,使用OR搜索键。对于NOT和OR搜索键,它们后边分别跟着一个和两个完整的搜索键。

表18-3 IMAP搜索键

| 搜索键 | 含义 | | :----- | :----- | :----- | :----- | | 'ALL' | 返回该文件夹中的所有邮件。如果你请求一个大文件夹中的所有消息,可能会遇到 imaplib 的大小限制。参见本小节“大小限制”部分 | | 'BEFORE date', 'ON date', 'SINCE date' | 这3个搜索键分别返回给定date之前、当天和之后IMAP服务器接收的消息。日期的格式必须为05-Jul-2015。此外,虽然 'SINCE 05-Jul-2015' 将匹配7月5日当天和之后的消息,但 'BEFORE 05-Jul-2015' 仅匹配7月5日之前的消息,不包括7月5日当天 | | 'SUBJECT string', 'BODY string', 'TEXT string' | 分别返回 string 出现在主题、正文、主题或正文中的消息。如果 string 中有空格,就使用双引号: 'TEXT "search with spaces"' | | 'FROM string', 'TO string', 'CC string', 'BCC string' | 返回所有消息,其中 string 分别出现在“ from ”邮件地址、“ to ”邮件地址、“ cc ”(抄送)地址或“ bcc ”(密件抄送)地址中。如果 string 中有多个电子邮件地址,就用空格将它们分开,并使用双引号: 'CC "[email protected] [email protected]"' | | 'SEEN', 'UNSEEN' | 分别返回包含和不包含 \Seen 标记的所有信息。如果电子邮件已经被 fetch() 方法调用访问(稍后描述),或者你曾在电子邮件程序或网络浏览器中单击过它,就会有 \Seen 标记。比较常用的说法是电子邮件“已读”,而不是“已看”,但它们的意思一样 | | 'ANSWERED', 'UNANSWERED' | 分别返回包含和不包含 \Answered 标记的所有消息。如果消息已答复,就会有\ Answered 标记 | | 'DELETED', 'UNDELETED' | 分别返回包含和不包含 \Deleted 标记的所有信息。用 delete_messages() 方法删除的邮件就会有 \Deleted 标记,直到调用 expunge() 方法才会永久删除(请参阅18.5.7小节“删除电子邮件”)。请注意,一些电子邮件提供商,例如Gmail,会自动清除邮件 | | 'DRAFT', 'UNDRAFT' | 分别返回包含和不包含 \Draft 标记的所有消息。草稿邮件通常保存在单独的草稿文件夹中,而不是在收件箱中 | | 'FLAGGED', 'UNFLAGGED' | 分别返回包含和不包含 \Flagged 标记的所有消息。这个标记通常用来标记电子邮件为“重要”或“紧急” | | 'LARGER N', 'SMALLER N' | 分别返回大于或小于N个字节的所有消息 | | 'NOT search-key ' | 返回搜索键不会返回的那些消息 | | 'OR search-key1 search-key2' | 返回符合第一个或第二个搜索键的消息 |

下面是 search() 方法调用的一些例子,以及它们的含义。

imapObj.search(['ALL']) 返回当前选定的文件夹中的每一个消息。

imapObj.search(['ON 05-Jul-2019']) 返回在2019年7月5日发送的每个消息。

imapObj.search(['SINCE 01-Jan-2019', 'BEFORE 01-Feb-2019', 'UNSEEN']) 返回2019年1月发送的所有未读消息(注意,这意味着从1月1日直到2月1日,但不包括2月1日)。

imapObj.search(['SINCE 01-Jan-2019', 'FROM alice@example. com']) 返回自2019年开始以来,发自[email protected]的消息。

imapObj.search(['SINCE 01-Jan-2019', 'NOT FROM alice@example. com']) 返回自2019年开始以来,除[email protected]外,其他所有人发来的消息。

imapObj.search(['OR FROM [email protected] FROM bob@example. com']) 返回发自[email protected][email protected]的所有信息。

imapObj.search(['FROM [email protected]', 'FROM bob@example. com']) 为恶作剧例子。该搜索不会返回任何消息,因为消息必须匹配所有搜索关键词。因为只能有一个“ from ”地址,所以一条消息不可能既来自[email protected],又来自[email protected]

search() 方法不返回电子邮件本身,而是返回邮件的唯一ID(UID)。然后,可以将这些UID传入 fetch() 方法,获得邮件内容。

输入以下代码,继续演示交互式环境的例子:

>>> UIDs = imapObj.search(['SINCE 05-Jul-2019'])
>>> UIDs
[40032, 40033, 40034, 40035, 40036, 40037, 40038, 40039, 40040, 40041]

这里, search() 返回的消息ID列表(针对7月5日以来接收的消息)保存在UIDs中。计算机上返回的UIDs列表与这里显示的不同,它们对于特定的电子邮件账户是唯一的。如果你稍后将UID传递给其他函数调用,请用你收到的UID值,而不是本书例子中输出的。

大小限制

如果你的搜索匹配大量的电子邮件,Python可能抛出异常 imaplib.error: got more than 10000 bytes 。如果发生这种情况,必须断开并重连IMAP服务器,然后再试。

这个限制是防止Python程序消耗太多内存。遗憾的是,默认大小限制往往太小。可以执行下面的代码,将限制从10 000字节改为10 000 000字节:

>>> import imaplib
>>> imaplib._MAXLINE = 10000000

这能避免该异常再次出现。也许要在你写的每一个IMAP程序中加上这两行。