18.4. 邮箱 — 操作各种格式的邮箱 — Python 文档
18.4. 邮箱 — 处理各种格式的邮箱
该模块定义了两个类,Mailbox 和 Message,用于访问和操作磁盘邮箱及其包含的消息。 Mailbox 提供了从键到消息的类似字典的映射。 Message 扩展了 email.message 模块的 Message 类,具有特定于格式的状态和行为。 支持的邮箱格式有 Maildir、mbox、MH、Babyl 和 MMDF。
18.4.1. 邮箱对象
- class mailbox.Mailbox
可以检查和修改的邮箱。
Mailbox 类定义了一个接口并且不打算被实例化。 相反,特定于格式的子类应该从 Mailbox 继承,并且您的代码应该实例化一个特定的子类。
Mailbox界面类似字典,小键对应消息。 密钥由 Mailbox 实例发布,它们将与它们一起使用,并且仅对 Mailbox 实例有意义。 即使相应的消息被修改,例如通过将其替换为另一条消息,密钥也会继续标识消息。
可以使用类似 set 的方法 add() 将消息添加到 Mailbox 实例,并使用
del
语句或类似 set 的方法 remove 删除() 和 discard()。Mailbox 接口语义在一些值得注意的方面不同于字典语义。 每次请求消息时,都会根据邮箱的当前状态生成一个新的表示(通常是 Message 实例)。 类似地,当将消息添加到 Mailbox 实例时,提供的消息表示的内容将被复制。 在这两种情况下,都不是对 Mailbox 实例保存的消息表示的引用。
默认的 Mailbox 迭代器迭代消息表示,而不是像默认字典迭代器那样迭代键。 此外,在迭代期间修改邮箱是安全且明确的。 迭代器创建后添加到邮箱的消息不会被迭代器看到。 在迭代器产生它们之前从邮箱中删除的消息将被静默跳过,但如果相应的消息随后被删除,则使用迭代器中的键可能会导致
KeyError
异常。警告
修改可能被其他进程同时更改的邮箱时要非常小心。 用于此类任务的最安全的邮箱格式是 Maildir; 尽量避免使用 mbox 等单文件格式进行并发写入。 如果您正在修改邮箱,则 必须 通过调用 lock() 和 unlock() 方法 before 来锁定它文件中的消息或通过添加或删除消息进行任何更改。 未能锁定邮箱会面临丢失邮件或损坏整个邮箱的风险。
Mailbox 实例有以下方法:
- add(message)
将message加入邮箱并返回分配给它的密钥。
参数 message 可以是 Message 实例、email.message.Message 实例、字符串或类似文件的对象(应该以文本形式打开)模式)。 如果 message 是特定格式的适当 Message 子类的实例(例如,如果它是 mboxMessage 实例并且这是一个 mbox实例),则使用其特定于格式的信息。 否则,将使用格式特定信息的合理默认值。
- remove(key)
__delitem__(key)
discard(key) 从邮箱中删除key对应的消息。
如果不存在这样的消息,如果该方法被调用为 remove() 或 __delitem__(),则会引发
KeyError
异常,但如果该方法是称为 discard()。 如果底层邮箱格式支持其他进程的并发修改,则 discard() 的行为可能是首选。
- __setitem__(key, message)
将key对应的消息替换为消息。 如果没有消息已经对应于 键 ,则引发
KeyError
异常。与 add() 一样,参数 message 可以是 Message 实例、email.message.Message 实例、字符串或一个类似文件的对象(应该在文本模式下打开)。 如果 message 是特定格式的适当 Message 子类的实例(例如,如果它是 mboxMessage 实例并且这是一个 mbox实例),则使用其特定于格式的信息。 否则,当前对应于 key 的消息的格式特定信息保持不变。
- iterkeys()
keys() 如果调用为 iterkeys(),则返回所有键的迭代器,如果调用为 keys(),则返回键列表。
- itervalues()
__iter__()
values() 如果被称为 itervalues() 或 __iter__(),则返回所有消息表示的迭代器,或者如果被称为 values(),则返回此类表示的列表。 除非在初始化 Mailbox 实例时指定了自定义消息工厂,否则消息表示为特定格式的适当 Message 子类的实例。
笔记
__iter__() 的行为与字典不同,字典遍历键。
- iteritems()
items() 在 (key, message) 对上返回一个迭代器,其中 key 是一个键,message 是一个消息表示,如果调用为iteritems() 或返回此类对的列表,如果调用为 items()。 除非在初始化 Mailbox 实例时指定了自定义消息工厂,否则消息表示为特定格式的适当 Message 子类的实例。
- get(key, default=None)
__getitem__(key) 返回对应于 key 的消息的表示。 如果不存在这样的消息,如果该方法被调用为 get(),则返回 default,如果该方法被调用为 ,则会引发
KeyError
异常__getitem__()。 除非在初始化 Mailbox 实例时指定了自定义消息工厂,否则消息表示为适当的特定格式 Message 子类的实例。
- get_message(key)
返回对应于 key 的消息的表示,作为适当的特定格式 Message 子类的实例,或者如果不存在此类消息,则引发
KeyError
异常。
- get_string(key)
返回对应于 key 的消息的字符串表示,如果不存在此类消息,则引发
KeyError
异常。
- get_file(key)
返回对应于 key 的消息的类似文件的表示,或者如果不存在此类消息则引发
KeyError
异常。 类文件对象的行为就像以二进制模式打开一样。 一旦不再需要该文件,应将其关闭。笔记
与其他消息表示不同,类文件表示不一定独立于创建它们的 Mailbox 实例或底层邮箱。 每个子类都提供了更具体的文档。
- has_key(key)
__contains__(key) 如果 key 对应一条消息,则返回
True
,否则返回False
。
- __len__()
返回邮箱中的邮件计数。
- clear()
从邮箱中删除所有邮件。
- pop(key[, default])
返回对应于 key 的消息的表示并删除该消息。 如果不存在此类消息,则返回 default(如果已提供),否则引发
KeyError
异常。 除非在初始化 Mailbox 实例时指定了自定义消息工厂,否则消息表示为适当的特定格式 Message 子类的实例。
- popitem()
返回任意的 (key, message) 对,其中 key 是密钥,message 是消息表示,并删除对应的信息。 如果邮箱为空,则引发
KeyError
异常。 除非在初始化 Mailbox 实例时指定了自定义消息工厂,否则消息表示为适当的特定格式 Message 子类的实例。
- update(arg)
参数 arg 应该是 key-to-message 映射或 (key, message) 的迭代对。 更新邮箱,对于每个给定的 key 和 message,对应于 key 的消息被设置为 message,就像使用__setitem__()。 与 __setitem__() 一样,每个 key 必须已经对应邮箱中的一条消息,否则将引发
KeyError
异常,因此通常不正确arg 是一个 Mailbox 实例。笔记
与字典不同,不支持关键字参数。
- lock()
获取对邮箱的独占咨询锁,以便其他进程知道不要修改它。 如果锁不可用,则会引发 ExternalClashError。 使用的特定锁定机制取决于邮箱格式。 在对其内容进行任何修改之前,您应该 始终 锁定邮箱。
- unlock()
解除对邮箱的锁定(如果有)。
- close()
刷新邮箱,必要时将其解锁,然后关闭所有打开的文件。 对于某些 Mailbox 子类,此方法不执行任何操作。
18.4.1.1. Maildir
- class mailbox.Maildir(dirname, factory=rfc822.Message, create=True)
Maildir 格式邮箱的 Mailbox 的子类。 参数 factory 是一个可调用对象,它接受类似文件的消息表示(其行为就像以二进制模式打开一样)并返回自定义表示。 如果 factory 是
None
,则 MaildirMessage 用作默认消息表示。 如果create为True
,则邮箱不存在则创建。由于历史原因,factory 默认为 rfc822.Message 并且 dirname 被命名为这样而不是 path。 对于行为类似于其他 Mailbox 子类的实例的 Maildir 实例,将 factory 设置为
None
。Maildir 是一种为 qmail 邮件传输代理发明的基于目录的邮箱格式,现在被其他程序广泛支持。 Maildir 邮箱中的邮件存储在公共目录结构内的单独文件中。 这种设计允许多个不相关的程序访问和修改 Maildir 邮箱而不会损坏数据,因此文件锁定是不必要的。
Maildir 邮箱包含三个子目录,分别是:
tmp
、new
和cur
。 消息在tmp
子目录中暂时创建,然后移动到new
子目录以完成传递。 邮件用户代理随后可以将消息移动到cur
子目录,并将有关消息状态的信息存储在附加到其文件名的特殊“信息”部分中。还支持由 Courier 邮件传输代理引入的样式的文件夹。 如果
'.'
是其名称中的第一个字符,则主邮箱的任何子目录都被视为文件夹。 文件夹名称由 Maildir 表示,没有前导'.'
。 每个文件夹本身就是一个 Maildir 邮箱,但不应包含其他文件夹。 相反,逻辑嵌套使用'.'
来表示级别,例如“Archived.2005.07”。笔记
Maildir 规范要求在某些消息文件名中使用冒号 (
':'
)。 但是,某些操作系统不允许在文件名中使用此字符,如果您希望在此类操作系统上使用类似 Maildir 的格式,则应指定另一个字符来代替。 感叹号 ('!'
) 是一种流行的选择。 例如:import mailbox mailbox.Maildir.colon = '!'
colon
属性也可以在每个实例的基础上设置。Maildir 实例除了以下之外还具有 Mailbox 的所有方法:
- list_folders()
返回所有文件夹名称的列表。
- get_folder(folder)
返回一个 Maildir 实例,表示名称为 folder 的文件夹。 如果文件夹不存在,则会引发 NoSuchMailboxError 异常。
- add_folder(folder)
创建一个名称为 folder 的文件夹,并返回一个表示它的 Maildir 实例。
- remove_folder(folder)
删除名称为 folder 的文件夹。 如果文件夹包含任何消息,则会引发 NotEmptyError 异常并且不会删除该文件夹。
- clean()
从邮箱中删除过去 36 小时内未被访问的临时文件。 Maildir 规范说邮件阅读程序应该偶尔这样做。
- add(message)
__setitem__(key, message)
update(arg) 警告
这些方法根据当前进程 ID 生成唯一的文件名。 使用多个线程时,可能会发生未检测到的名称冲突并导致邮箱损坏,除非协调线程以避免使用这些方法同时操作同一个邮箱。
- flush()
对 Maildir 邮箱的所有更改都会立即应用,因此此方法不执行任何操作。
- lock()
unlock() Maildir 邮箱不支持(或要求)锁定,因此这些方法什么都不做。
- close()
Maildir 实例不保留任何打开的文件,底层邮箱不支持锁定,因此该方法什么也不做。
- get_file(key)
根据主机平台,在返回的文件保持打开状态时,可能无法修改或删除基础消息。
也可以看看
- qmail 的 maildir 手册页
- 格式的原始规范。
- 使用maildir格式
- 其发明者对 Maildir 的注释。 包括更新的名称创建方案和“信息”语义的详细信息。
- 来自 Courier 的 maildir 手册页
- 格式的另一种规范。 描述支持文件夹的通用扩展。
18.4.1.2. mbox
- class mailbox.mbox(path, factory=None, create=True)
mbox 格式邮箱的 Mailbox 的子类。 参数 factory 是一个可调用对象,它接受类似文件的消息表示(其行为就像以二进制模式打开一样)并返回自定义表示。 如果 factory 是
None
,则 mboxMessage 用作默认消息表示。 如果create为True
,则邮箱不存在则创建。mbox 格式是在 Unix 系统上存储邮件的经典格式。 mbox 邮箱中的所有消息都存储在单个文件中,每条消息的开头由前五个字符为“From”的行指示。
mbox 格式存在多种变体,以解决原始格式中的明显缺陷。 为了兼容性,mbox 实现了原始格式,有时也称为 mboxo。 这意味着 Content-Length 标头(如果存在)将被忽略,并且在存储消息时,消息正文中任何行开头的“From”都将转换为“>From”,尽管在阅读消息时出现的“>From”不会转换为“From”。
- get_file(key)
在 mbox 实例上调用
flush()
或close()
后使用该文件可能会产生不可预测的结果或引发异常。
- lock()
unlock() 使用了三种锁定机制 — 点锁定以及
flock()
和lockf()
系统调用(如果可用)。
也可以看看
- qmail 中的 mbox 手册页
- 格式及其变体的规范。
- tin 中的 mbox 手册页
- 格式的另一个规范,包含有关锁定的详细信息。
- 在 Unix 上配置 Netscape Mail:为什么内容长度格式不好
- 使用原始 mbox 格式而不是变体的参数。
- “mbox”是几种互不兼容的邮箱格式的家族
- mbox 变体的历史。
18.4.1.3. MH
- class mailbox.MH(path, factory=None, create=True)
MH 格式邮箱的 Mailbox 的子类。 参数 factory 是一个可调用对象,它接受类似文件的消息表示(其行为就像以二进制模式打开一样)并返回自定义表示。 如果 factory 是
None
,则 MHMessage 用作默认消息表示。 如果create为True
,则邮箱不存在则创建。MH 是一种基于目录的邮箱格式,是为 MH 消息处理系统(一种邮件用户代理)发明的。 MH 邮箱中的每条消息都驻留在其自己的文件中。 除了消息之外,MH 邮箱可能包含其他 MH 邮箱(称为 文件夹 )。 文件夹可以无限嵌套。 MH 邮箱还支持 sequences,这是一种命名列表,用于对消息进行逻辑分组,而无需将它们移动到子文件夹中。 序列在每个文件夹中名为
.mh_sequences
的文件中定义。MH 类操作 MH 邮箱,但它不会尝试模拟 mh 的所有行为。 特别是,它不会修改
context
或.mh_profile
文件,mh 使用这些文件来存储其状态和配置,并且不受这些文件的影响。- list_folders()
返回所有文件夹名称的列表。
- get_folder(folder)
返回一个 MH 实例,表示名称为 folder 的文件夹。 如果文件夹不存在,则会引发 NoSuchMailboxError 异常。
- add_folder(folder)
创建一个名称为 folder 的文件夹,并返回一个表示它的 MH 实例。
- remove_folder(folder)
删除名称为 folder 的文件夹。 如果文件夹包含任何消息,则会引发 NotEmptyError 异常并且不会删除该文件夹。
- get_sequences()
返回映射到键列表的序列名称字典。 如果没有序列,则返回空字典。
- set_sequences(sequences)
根据 sequences 重新定义邮箱中存在的序列,这是一个映射到键列表的名称字典,如 get_sequences() 返回的。
- pack()
根据需要重命名邮箱中的邮件以消除编号差距。 序列列表中的条目会相应地更新。
笔记
已发出的密钥将通过此操作失效,以后不应再使用。
- remove(key)
__delitem__(key)
discard(key) 这些方法会立即删除消息。 不使用通过在其名称前添加逗号来标记要删除的消息的 MH 约定。
- lock()
unlock() 使用了三种锁定机制 — 点锁定以及
flock()
和lockf()
系统调用(如果可用)。 对于 MH 邮箱,锁定邮箱意味着锁定.mh_sequences
文件,并且仅在影响它们的任何操作期间锁定单个邮件文件。
- get_file(key)
根据主机平台,可能无法在返回的文件保持打开状态时删除基础消息。
- flush()
对 MH 邮箱的所有更改都会立即应用,因此此方法不执行任何操作。
18.4.1.4. Babyl
- class mailbox.Babyl(path, factory=None, create=True)
Babyl 格式邮箱的 Mailbox 子类。 参数 factory 是一个可调用对象,它接受类似文件的消息表示(其行为就像以二进制模式打开一样)并返回自定义表示。 如果 factory 是
None
,则 BabylMessage 用作默认消息表示。 如果create为True
,则邮箱不存在则创建。Babyl 是 Emacs 附带的 Rmail 邮件用户代理使用的单文件邮箱格式。 消息的开头由包含两个字符 Control-Underscore (
'\037'
) 和 Control-L ('\014'
) 的行指示。 一条消息的结束由下一条消息的开始指示,或者在最后一条消息的情况下,由包含控制下划线 ('\037'
) 字符的行指示。Babyl 邮箱中的邮件有两组标题,原始标题和所谓的可见标题。 可见标头通常是原始标头的子集,经过重新格式化或删节以使其更具吸引力。 Babyl 邮箱中的每条消息还有一个附带的 标签列表 ,或记录有关消息的额外信息的短字符串,并且在邮箱中找到的所有用户定义标签的列表保存在 Babyl 选项中部分。
Babyl 实例除了以下之外还具有 Mailbox 的所有方法:
- get_labels()
返回邮箱中使用的所有用户定义标签的名称列表。
笔记
检查实际邮件以确定邮箱中存在哪些标签,而不是查阅 Babyl 选项部分中的标签列表,但每当修改邮箱时都会更新 Babyl 部分。
- get_file(key)
在 Babyl 邮箱中,消息的标题不与消息的正文连续存储。 为了生成类似文件的表示,标题和正文一起复制到 StringIO 实例(来自 StringIO 模块),该实例具有与文件相同的 API。 因此,类文件对象真正独立于底层邮箱,但与字符串表示相比并不节省内存。
- lock()
unlock() 使用了三种锁定机制 — 点锁定以及
flock()
和lockf()
系统调用(如果可用)。
18.4.1.5. MMDF
- class mailbox.MMDF(path, factory=None, create=True)
MMDF 格式邮箱的 Mailbox 的子类。 参数 factory 是一个可调用对象,它接受类似文件的消息表示(其行为就像以二进制模式打开一样)并返回自定义表示。 如果 factory 是
None
,则 MMDFMessage 用作默认消息表示。 如果create为True
,则邮箱不存在则创建。MMDF 是一种单文件邮箱格式,是为多渠道备忘录分发工具(一种邮件传输代理)发明的。 每条消息的格式与 mbox 消息的格式相同,但在包含四个 Control-A (
'\001'
) 字符的行之前和之后用括号括起来。 与 mbox 格式一样,每条消息的开头由前五个字符为“From”的行指示,但在存储消息时,不会将额外出现的“From”转换为“>From”,因为额外的消息分隔行会阻止将此类事件误认为是后续消息的开始。一些由 MMDF 实现的 Mailbox 方法值得特别说明:
- get_file(key)
在 MMDF 实例上调用
flush()
或close()
后使用该文件可能会产生不可预测的结果或引发异常。
- lock()
unlock() 使用了三种锁定机制 — 点锁定以及
flock()
和lockf()
系统调用(如果可用)。
18.4.2. 信息对象
- class mailbox.Message([message])
email.message 模块的 Message 的子类。 mailbox.Message 的子类添加了邮箱格式特定的状态和行为。
如果省略 message,则在默认的空状态下创建新实例。 如果 message 是 email.message.Message 实例,则复制其内容; 此外,如果 message 是一个 Message 实例,则任何格式特定的信息都被尽可能地转换。 如果 message 是一个字符串或文件,它应该包含一个 RFC 2822 兼容的消息,该消息被读取和解析。
子类提供的特定于格式的状态和行为各不相同,但通常仅支持不特定于特定邮箱的属性(尽管可能这些属性特定于特定邮箱格式)。 例如,不保留单文件邮箱格式的文件偏移量和基于目录的邮箱格式的文件名,因为它们仅适用于原始邮箱。 但是诸如消息是否已被用户阅读或标记为重要的状态被保留,因为它适用于消息本身。
不要求使用 Message 实例来表示使用 Mailbox 实例检索的消息。 在某些情况下,生成 Message 表示所需的时间和内存可能无法接受。 对于这种情况,Mailbox 实例还提供字符串和类似文件的表示,并且可以在初始化 Mailbox 实例时指定自定义消息工厂。
18.4.2.1. MaildirMessage
- class mailbox.MaildirMessage([message])
具有 Maildir 特定行为的消息。 参数 message 与 Message 构造函数的含义相同。
通常,在用户第一次打开和关闭邮箱后,邮件用户代理应用程序将
new
子目录中的所有邮件移动到cur
子目录,记录邮件是否已旧不是他们实际上已经被阅读。cur
中的每条消息都有一个“信息”部分添加到其文件名中,以存储有关其状态的信息。 (一些邮件阅读器可能还会在new
中的消息中添加“信息”部分。)“信息”部分可能采用以下两种形式之一:它可能包含“2”,后跟标准化标志列表(例如,“2,FR”)或者它可能包含“1”,后跟所谓的实验信息。 Maildir 消息的标准标志如下:旗帜
意义
解释
D
草案
构图下
F
标记
标记为重要
P
通过
转发、重新发送或退回
R
回复
回复到
S
看过
读
T
垃圾
标记为后续删除
MaildirMessage 实例提供以下方法:
- get_subdir()
返回“new”(如果消息应该存储在
new
子目录中)或“cur”(如果消息应该存储在cur
子目录中)。笔记
邮件通常在其邮箱被访问后从
new
移动到cur
,无论该邮件是否已被阅读。 如果"S" in msg.get_flags()
为True
,则已读取消息msg
。
- set_subdir(subdir)
设置消息应存储在的子目录。 参数 subdir 必须是“new”或“cur”。
- get_flags()
返回一个字符串,指定当前设置的标志。 如果消息符合标准 Maildir 格式,则结果是按字母顺序连接
'D'
、'F'
、'P'
、'R'
、'S'
和'T'
。 如果未设置标志或“信息”包含实验语义,则返回空字符串。
- set_flags(flags)
设置由 flags 指定的标志并取消设置所有其他标志。
- add_flag(flag)
设置由 flag 指定的标志而不更改其他标志。 要一次添加多个标志,flag 可以是一个以上字符的字符串。 无论是否包含实验信息而不是标志,当前的“信息”都会被覆盖。
- remove_flag(flag)
取消设置 flag 指定的标志而不更改其他标志。 要一次删除多个标志,flag 可能是一个包含多个字符的字符串。 如果“info”包含实验信息而不是标志,则不会修改当前的“info”。
- get_date()
以浮点数形式返回消息的交付日期,表示自纪元以来的秒数。
- set_date(date)
将消息的交付日期设置为 date,这是一个浮点数,表示自纪元以来的秒数。
- get_info()
返回一个包含消息“信息”的字符串。 这对于访问和修改实验性的“信息”(即,不是标志列表)很有用。
- set_info(info)
将“info”设置为 info,它应该是一个字符串。
当基于 mboxMessage 或 MMDFMessage 实例创建 MaildirMessage 实例时,Status 和 X-Status标题被省略,并发生以下转换:
结果状态 | mboxMessage 或 MMDFMessage 状态 |
---|---|
“cur”子目录 | O 旗 |
F旗 | F旗 |
R标志 | 一只旗 |
S旗 | R标志 |
T旗 | D旗 |
当基于 MHMessage 实例创建 MaildirMessage 实例时,会发生以下转换:
结果状态 | MHMessage 状态 |
---|---|
“cur”子目录 | “看不见”的序列 |
“cur” 子目录和 S 标志 | 没有“看不见”的序列 |
F旗 | “标记”序列 |
R标志 | “回复”序列 |
当基于 BabylMessage 实例创建 MaildirMessage 实例时,会发生以下转换:
结果状态 | BabylMessage 状态 |
---|---|
“cur”子目录 | “看不见”的标签 |
“cur” 子目录和 S 标志 | 没有“看不见”的标签 |
P标志 | “转发”或“重新发送”标签 |
R标志 | “回答”标签 |
T旗 | “已删除”标签 |
18.4.2.2. mboxMessage
- class mailbox.mboxMessage([message])
具有特定于 mbox 的行为的消息。 参数 message 与 Message 构造函数的含义相同。
mbox 邮箱中的消息一起存储在一个文件中。 发件人的信封地址和递送时间通常存储在以“发件人”开头的一行中,该行用于指示消息的开始,尽管在 mbox 实现中此数据的确切格式存在相当大的差异。 指示消息状态的标志,例如它是否已被读取或标记为重要,通常存储在 Status 和 X-Status 标头中。
mbox 消息的常规标志如下:
旗帜
意义
解释
R
读
读
O
老的
之前被 MUA 检测到
D
已删除
标记为后续删除
F
标记
标记为重要
A
已回答
回复到
“R”和“O”标志存储在Status标头中,“D”、“F”和“A”标志存储在X-Status标题。 标志和标题通常按提到的顺序出现。
mboxMessage 实例提供以下方法:
- get_from()
返回一个字符串,表示“发件人”行,该行标记了 mbox 邮箱中邮件的开始。 不包括前导的“From”和尾随的换行符。
- set_from(from_, time_=None)
将“From”行设置为from_,指定时不应该使用前导“From”或尾随换行符。 为方便起见,可以指定 time_ 并将其适当格式化并附加到 from_。 如果指定了 time_,则应该是 time.struct_time 实例,适合传递给 time.strftime() 或
True
的元组](使用 time.gmtime())。
- get_flags()
返回一个字符串,指定当前设置的标志。 如果消息符合常规格式,则结果是按以下顺序串联
'R'
,'O'
,'D'
,'F'
和'A'
。
- set_flags(flags)
设置由 flags 指定的标志并取消设置所有其他标志。 参数 flags 应该是
'R'
、'O'
、'D'
、'F'
中每一个的零次或多次出现的任何顺序的串联, 和'A'
。
- add_flag(flag)
设置由 flag 指定的标志而不更改其他标志。 要一次添加多个标志,flag 可以是一个以上字符的字符串。
- remove_flag(flag)
取消设置 flag 指定的标志而不更改其他标志。 要一次删除多个标志,flag 可能是一个包含多个字符的字符串。
当基于 MaildirMessage 实例创建 mboxMessage 实例时,会根据 MaildirMessage 实例的交付日期生成“From”行,并进行以下转换地方:
结果状态 | MaildirMessage 状态 |
---|---|
R标志 | S旗 |
O 旗 | “cur”子目录 |
D旗 | T旗 |
F旗 | F旗 |
一只旗 | R标志 |
当基于 MHMessage 实例创建 mboxMessage 实例时,会发生以下转换:
结果状态 | MHMessage 状态 |
---|---|
R 标志和 O 标志 | 没有“看不见”的序列 |
O 旗 | “看不见”的序列 |
F旗 | “标记”序列 |
一只旗 | “回复”序列 |
当基于 BabylMessage 实例创建 mboxMessage 实例时,会发生以下转换:
结果状态 | BabylMessage 状态 |
---|---|
R 标志和 O 标志 | 没有“看不见”的标签 |
O 旗 | “看不见”的标签 |
D旗 | “已删除”标签 |
一只旗 | “回答”标签 |
当基于 MMDFMessage 实例创建 Message 实例时,复制“From”行,所有标志直接对应:
结果状态 | MMDFMessage 状态 |
---|---|
R标志 | R标志 |
O 旗 | O 旗 |
D旗 | D旗 |
F旗 | F旗 |
一只旗 | 一只旗 |
18.4.2.3. MHMessage
- class mailbox.MHMessage([message])
具有 MH 特定行为的消息。 参数 message 与 Message 构造函数的含义相同。
MH 消息不支持传统意义上的标记或标志,但它们确实支持序列,即任意消息的逻辑分组。 一些邮件阅读程序(尽管不是标准的 mh 和 nmh)使用序列的方式与其他格式使用标志的方式大致相同,如下所示:
顺序
解释
看不见
未读取,但之前已被 MUA 检测到
回复了
回复到
被标记的
标记为重要
MHMessage 实例提供以下方法:
- get_sequences()
返回包含此消息的序列名称列表。
- set_sequences(sequences)
设置包含此消息的序列列表。
- add_sequence(sequence)
将 sequence 添加到包含此消息的序列列表中。
- remove_sequence(sequence)
从包含此消息的序列列表中删除 sequence。
当基于 MaildirMessage 实例创建 MHMessage 实例时,会发生以下转换:
结果状态 | MaildirMessage 状态 |
---|---|
“看不见”的序列 | 没有 S 标志 |
“回复”序列 | R标志 |
“标记”序列 | F旗 |
当基于 mboxMessage 或 MMDFMessage 实例创建 MHMessage 实例时,Status 和 X-Status标题被省略,并发生以下转换:
结果状态 | mboxMessage 或 MMDFMessage 状态 |
---|---|
“看不见”的序列 | 没有 R 标志 |
“回复”序列 | 一只旗 |
“标记”序列 | F旗 |
当基于 BabylMessage 实例创建 MHMessage 实例时,会发生以下转换:
结果状态 | BabylMessage 状态 |
---|---|
“看不见”的序列 | “看不见”的标签 |
“回复”序列 | “回答”标签 |
18.4.2.4. BabylMessage
- class mailbox.BabylMessage([message])
带有 Babyl 特定行为的消息。 参数 message 与 Message 构造函数的含义相同。
某些消息标签,称为 属性 ,按惯例定义为具有特殊含义。 属性如下:
标签
解释
看不见
未读取,但之前已被 MUA 检测到
已删除
标记为后续删除
归档
复制到另一个文件或邮箱
回答
回复到
转发
转发
已编辑
由用户修改
怨恨
反感
默认情况下,Rmail 仅显示可见的标题。 然而,BabylMessage 类使用原始标题,因为它们更完整。 如果需要,可以显式访问可见标头。
BabylMessage 实例提供以下方法:
- get_labels()
返回消息上的标签列表。
- set_labels(labels)
将消息上的标签列表设置为 labels。
- add_label(label)
将 label 添加到邮件的标签列表中。
- remove_label(label)
从邮件的标签列表中删除 label。
- get_visible()
返回一个 Message 实例,其标题是消息的可见标题,正文为空。
- set_visible(visible)
将消息的可见标题设置为与 message 中的标题相同。 参数 visible 应为 Message 实例、email.message.Message 实例、字符串或类似文件的对象(应以文本形式打开)模式)。
- update_visible()
修改 BabylMessage 实例的原始标头时,不会自动修改可见标头以对应。 该方法更新可见头部如下:每个有对应原始头部的可见头部被设置为原始头部的值,每个没有对应原始头部的可见头部被移除,Date,[ X251X]From、Reply-To、To、CC和Subject,它们存在于原始标题中但不存在可见标题被添加到可见标题中。
当基于 MaildirMessage 实例创建 BabylMessage 实例时,会发生以下转换:
结果状态 | MaildirMessage 状态 |
---|---|
“看不见”的标签 | 没有 S 标志 |
“已删除”标签 | T旗 |
“回答”标签 | R标志 |
“转发”标签 | P标志 |
当基于 mboxMessage 或 MMDFMessage 实例创建 BabylMessage 实例时,Status 和 X-Status标题被省略,并发生以下转换:
结果状态 | mboxMessage 或 MMDFMessage 状态 |
---|---|
“看不见”的标签 | 没有 R 标志 |
“已删除”标签 | D旗 |
“回答”标签 | 一只旗 |
当基于 MHMessage 实例创建 BabylMessage 实例时,会发生以下转换:
结果状态 | MHMessage 状态 |
---|---|
“看不见”的标签 | “看不见”的序列 |
“回答”标签 | “回复”序列 |
18.4.2.5. MMDFMessage
- class mailbox.MMDFMessage([message])
具有 MMDF 特定行为的消息。 参数 message 与 Message 构造函数的含义相同。
与 mbox 邮箱中的消息一样,MMDF 消息与发件人地址和交付日期一起存储在以“From”开头的初始行中。 同样,指示消息状态的标志通常存储在 Status 和 X-Status 标头中。
MMDF 消息的常规标志与 mbox 消息的标志相同,如下所示:
旗帜
意义
解释
R
读
读
O
老的
之前被 MUA 检测到
D
已删除
标记为后续删除
F
标记
标记为重要
A
已回答
回复到
“R”和“O”标志存储在Status标头中,“D”、“F”和“A”标志存储在X-Status标题。 标志和标题通常按提到的顺序出现。
MMDFMessage 实例提供以下方法,这些方法与 mboxMessage 提供的方法相同:
- get_from()
返回一个字符串,表示“发件人”行,该行标记了 mbox 邮箱中邮件的开始。 不包括前导的“From”和尾随的换行符。
- set_from(from_, time_=None)
将“From”行设置为from_,指定时不应该使用前导“From”或尾随换行符。 为方便起见,可以指定 time_ 并将其适当格式化并附加到 from_。 如果指定了 time_,则应该是 time.struct_time 实例,适合传递给 time.strftime() 或
True
的元组](使用 time.gmtime())。
- get_flags()
返回一个字符串,指定当前设置的标志。 如果消息符合常规格式,则结果是按以下顺序串联
'R'
,'O'
,'D'
,'F'
和'A'
。
- set_flags(flags)
设置由 flags 指定的标志并取消设置所有其他标志。 参数 flags 应该是
'R'
、'O'
、'D'
、'F'
中每一个的零次或多次出现的任何顺序的串联, 和'A'
。
- add_flag(flag)
设置由 flag 指定的标志而不更改其他标志。 要一次添加多个标志,flag 可以是一个以上字符的字符串。
- remove_flag(flag)
取消设置 flag 指定的标志而不更改其他标志。 要一次删除多个标志,flag 可能是一个包含多个字符的字符串。
当基于 MaildirMessage 实例创建 MMDFMessage 实例时,会根据 MaildirMessage 实例的交付日期生成“From”行,并进行以下转换地方:
结果状态 | MaildirMessage 状态 |
---|---|
R标志 | S旗 |
O 旗 | “cur”子目录 |
D旗 | T旗 |
F旗 | F旗 |
一只旗 | R标志 |
当基于 MHMessage 实例创建 MMDFMessage 实例时,会发生以下转换:
结果状态 | MHMessage 状态 |
---|---|
R 标志和 O 标志 | 没有“看不见”的序列 |
O 旗 | “看不见”的序列 |
F旗 | “标记”序列 |
一只旗 | “回复”序列 |
当基于 BabylMessage 实例创建 MMDFMessage 实例时,会发生以下转换:
结果状态 | BabylMessage 状态 |
---|---|
R 标志和 O 标志 | 没有“看不见”的标签 |
O 旗 | “看不见”的标签 |
D旗 | “已删除”标签 |
一只旗 | “回答”标签 |
当基于 mboxMessage 实例创建 MMDFMessage 实例时,复制“From”行并且所有标志直接对应:
结果状态 | mboxMessage 状态 |
---|---|
R标志 | R标志 |
O 旗 | O 旗 |
D旗 | D旗 |
F旗 | F旗 |
一只旗 | 一只旗 |
18.4.3. 例外
mailbox 模块中定义了以下异常类:
- exception mailbox.Error
- 所有其他特定于模块的异常的基础类。
- exception mailbox.NoSuchMailboxError
- 在需要邮箱但未找到邮箱时引发,例如在使用不存在的路径实例化 Mailbox 子类时(并且将 create 参数设置为
False
]),或者打开不存在的文件夹时。
- exception mailbox.NotEmptyError
- 当邮箱不为空但预期为空时引发,例如删除包含邮件的文件夹时。
- exception mailbox.ExternalClashError
- 当某些超出程序控制的邮箱相关条件导致程序无法继续时引发,例如无法获取另一个程序已经持有锁的锁,或者当一个唯一生成的文件名已经存在时。
- exception mailbox.FormatError
- 当无法解析文件中的数据时引发,例如当 MH 实例尝试读取损坏的
.mh_sequences
文件时。
18.4.4. 弃用的类和方法
自 2.6 版起已弃用。
旧版本的 mailbox 模块不支持修改邮箱,例如添加或删除邮件,并且不提供表示特定格式的邮件属性的类。 为了向后兼容,较旧的邮箱类仍然可用,但应优先使用较新的类。 旧类已在 Python 3 中删除。
较旧的邮箱对象仅支持迭代并提供单个公共方法:
- oldmailbox.next()
- 返回邮箱中的下一条消息,创建时使用可选的 factory 参数传递给邮箱对象的构造函数。 默认情况下,这是一个 rfc822.Message 对象(请参阅 rfc822 模块)。 根据邮箱实现,此对象的 fp 属性可能是真实的文件对象或模拟文件对象的类实例,如果多个邮件消息包含在单个文件中,则会处理消息边界等问题,等等。 如果没有更多消息可用,则此方法返回
None
。
除了 Maildir,大多数旧邮箱类的名称与当前邮箱类名称不同。 为此,新的 Maildir 类定义了一个 next()
方法,其构造函数与其他新邮箱类的构造函数略有不同。
名称与其较新对应物不同的较旧邮箱类如下:
- class mailbox.UnixMailbox(fp[, factory])
访问经典的 Unix 风格邮箱,其中所有邮件都包含在一个文件中,并由
From
(又名From_
) 行。 文件对象 fp 指向邮箱文件。 可选的 factory 参数是一个应创建新消息对象的可调用对象。 factory 使用一个参数 fp 由邮箱对象的next()
方法调用。 默认是 rfc822.Message 类(参见 rfc822 模块 - 以及下面的注释)。笔记
由于该模块内部实现的原因,您可能希望以二进制模式打开 fp 对象。 这在 Windows 上尤其重要。
为了获得最大的可移植性,Unix 风格的邮箱中的消息被任何以字符串
'From '
(注意尾随空格)开头的行分隔,如果前面正好有两个换行符。 由于实践中的变化范围很广,因此不应考虑From_
行上的任何其他内容。 但是,当前的实现不检查前两个换行符。 这通常适用于大多数应用程序。UnixMailbox 类实现了更严格的
From_
行检查版本,使用通常正确匹配From_
分隔符的正则表达式。 它认为分隔线由From name time
行分隔。 为了获得最大的可移植性,请改用 PortableUnixMailbox 类。 此类与 UnixMailbox 相同,只是各个消息仅由From
行分隔。
- class mailbox.PortableUnixMailbox(fp[, factory])
- UnixMailbox 的不太严格的版本,它只考虑分隔消息的行开头的
From
。 From 行的“name time”部分被忽略,以防止在实践中观察到的一些变化。 这是有效的,因为邮件中以'From '
开头的行在传递时被邮件处理软件引用。
- class mailbox.MmdfMailbox(fp[, factory])
- 访问一个 MMDF 样式的邮箱,其中所有邮件都包含在一个文件中,并由由 4 个 control-A 字符组成的行分隔。 文件对象 fp 指向邮箱文件。 可选的 factory 与 UnixMailbox 类一样。
- class mailbox.MHMailbox(dirname[, factory])
- 访问一个 MH 邮箱,这是一个目录,每个邮件都在一个带有数字名称的单独文件中。 邮箱目录的名称在 dirname 中传递。 factory 与 UnixMailbox 类一样。
- class mailbox.BabylMailbox(fp[, factory])
- 访问类似于 MMDF 邮箱的 Babyl 邮箱。 在 Babyl 格式中,每条消息都有两组标题,original 标题和 visible 标题。 原始标题出现在仅包含
'*** EOOH ***'
(End-Of-Original-Headers)的行之前,可见标题出现在EOOH
行之后。 Babyl 兼容的邮件阅读器将只显示可见的标题,而 BabylMailbox 对象将返回仅包含可见标题的邮件。 您必须自己解析邮箱文件才能获得原始标题。 邮件消息以 EOOH 行开始,以仅包含'\037\014'
的行结束。 factory 与 UnixMailbox 类一样。
如果您希望将旧邮箱类与 email 模块一起使用,而不是使用已弃用的 rfc822 模块,您可以按如下方式进行:
import email
import email.Errors
import mailbox
def msgfactory(fp):
try:
return email.message_from_file(fp)
except email.Errors.MessageParseError:
# Don't return None since that will
# stop the mailbox iterator
return ''
mbox = mailbox.UnixMailbox(fp, msgfactory)
或者,如果您知道您的邮箱只包含格式正确的 MIME 消息,您可以将其简化为:
import email
import mailbox
mbox = mailbox.UnixMailbox(fp, email.message_from_file)
18.4.5. 例子
打印邮箱中所有邮件主题的简单示例:
import mailbox
for message in mailbox.mbox('~/mbox'):
subject = message['subject'] # Could possibly be None.
if subject and 'python' in subject.lower():
print subject
要将所有邮件从 Babyl 邮箱复制到 MH 邮箱,转换所有可以转换的特定格式信息:
import mailbox
destination = mailbox.MH('~/Mail')
destination.lock()
for message in mailbox.Babyl('~/RMAIL'):
destination.add(mailbox.MHMessage(message))
destination.flush()
destination.unlock()
本示例将来自多个邮件列表的邮件分类到不同的邮箱中,注意避免因其他程序并发修改而导致邮件损坏、因程序中断导致邮件丢失或因邮箱中的错误消息而过早终止:
import mailbox
import email.errors
list_names = ('python-list', 'python-dev', 'python-bugs')
boxes = dict((name, mailbox.mbox('~/email/%s' % name)) for name in list_names)
inbox = mailbox.Maildir('~/Maildir', factory=None)
for key in inbox.iterkeys():
try:
message = inbox[key]
except email.errors.MessageParseError:
continue # The message is malformed. Just leave it.
for name in list_names:
list_id = message['list-id']
if list_id and name in list_id:
# Get mailbox to use
box = boxes[name]
# Write copy to disk before removing original.
# If there's a crash, you might duplicate a message, but
# that's better than losing a message completely.
box.lock()
box.add(message)
box.flush()
box.unlock()
# Remove original message
inbox.lock()
inbox.discard(key)
inbox.flush()
inbox.unlock()
break # Found destination, so stop looking.
for box in boxes.itervalues():
box.close()