mailbox — 以各种格式操作邮箱

源代码: Lib/mailbox.py


此模块定义了两个类,MailboxMessage,用于访问和操作磁盘上的邮箱以及它们包含的消息。Mailbox 提供从键到消息的类似字典的映射。Message 使用特定于格式的状态和行为扩展了 email.message 模块的 Message 类。支持的邮箱格式有 Maildir、mbox、MH、Babyl 和 MMDF。

参见

模块 email

表示和操作消息。

Mailbox 对象

class mailbox.Mailbox

一个可以检查和修改的邮箱。

Mailbox 类定义了一个接口,不打算实例化。相反,特定于格式的子类应该继承自 Mailbox,您的代码应该实例化特定的子类。

Mailbox 接口类似于字典,具有对应于消息的小键。键由将使用它们的 Mailbox 实例发出,并且仅对该 Mailbox 实例有意义。即使修改了相应的消息(例如通过将其替换为另一条消息),键也继续标识消息。

可以使用类似集合的方法 add() 将消息添加到 Mailbox 实例,并使用 del 语句或类似集合的方法 remove()discard() 删除消息。

Mailbox 接口语义在某些方面与字典语义不同。每次请求消息时,都会基于邮箱的当前状态生成新的表示(通常是 Message 实例)。同样,当将消息添加到 Mailbox 实例时,将复制提供的消息表示的内容。在这两种情况下,Mailbox 实例都不会保留对消息表示的引用。

默认的 Mailbox 迭代器 迭代消息表示,而不是像默认的 dictionary 迭代器那样迭代键。此外,在迭代期间修改邮箱是安全且明确定义的。迭代器创建后添加到邮箱的消息将不会被迭代器看到。在迭代器生成之前从邮箱中删除的消息将被静默跳过,但如果随后删除了相应的消息,则使用迭代器中的键可能会导致 KeyError 异常。

警告

在修改可能同时被其他进程更改的邮箱时,请务必小心。用于此类任务的最安全的邮箱格式是 Maildir;尽量避免使用诸如 mbox 之类的单文件格式进行并发写入。如果要修改邮箱,则在读取文件中的任何消息或通过添加或删除消息进行任何更改之前必须通过调用 lock()unlock() 方法来锁定它。如果未能锁定邮箱,则可能会丢失消息或损坏整个邮箱。

Mailbox 实例具有以下方法

add(message)

message 添加到邮箱并返回已分配给它的键。

参数 message 可以是 Message 实例、 email.message.Message 实例、字符串、字节串或类文件对象(应以二进制模式打开)。如果 message 是适当的特定格式的 Message 子类实例(例如,如果它是 mboxMessage 实例,并且这是一个 mbox 实例),则会使用其特定格式的信息。否则,将使用特定格式的合理默认值。

在 3.2 版本中变更: 增加了对二进制输入的支持。

remove(key)
__delitem__(key)
discard(key)

从邮箱中删除与 key 对应的消息。

如果不存在这样的消息,如果该方法以 remove()__delitem__() 的形式调用,则会引发 KeyError 异常,但如果该方法以 discard() 的形式调用,则不会引发异常。如果底层邮箱格式支持其他进程的并发修改,则可能首选 discard() 的行为。

__setitem__(key, message)

使用 message 替换与 key 对应的消息。如果不存在与 key 对应的消息,则引发 KeyError 异常。

add() 一样,参数 message 可以是 Message 实例、 email.message.Message 实例、字符串、字节串或类文件对象(应以二进制模式打开)。如果 message 是适当的特定格式的 Message 子类实例(例如,如果它是 mboxMessage 实例,并且这是一个 mbox 实例),则会使用其特定格式的信息。否则,当前与 key 对应的消息的特定格式信息保持不变。

iterkeys()

返回所有键的 迭代器

keys()

iterkeys() 相同,只是返回的是 list 而不是 迭代器

itervalues()
__iter__()

返回所有消息表示形式的 迭代器。 除非在初始化 Mailbox 实例时指定了自定义消息工厂,否则这些消息将表示为适当的特定格式的 Message 子类的实例。

注意

__iter__() 的行为与字典的行为不同,字典是对键进行迭代。

values()

itervalues() 相同,只是返回的是 list 而不是 迭代器

iteritems()

返回 (key, message) 对的 迭代器,其中 key 是一个键,message 是消息的表示形式。除非在初始化 Mailbox 实例时指定了自定义消息工厂,否则这些消息将表示为适当的特定格式的 Message 子类的实例。

items()

iteritems() 相同,只是返回的是成对的 list 而不是成对的 迭代器

get(key, default=None)
__getitem__(key)

返回与 key 对应的消息的表示形式。 如果不存在这样的消息,如果该方法以 get() 的形式调用,则返回 default,如果该方法以 __getitem__() 的形式调用,则引发 KeyError 异常。 除非在初始化 Mailbox 实例时指定了自定义消息工厂,否则该消息将表示为适当的特定格式的 Message 子类的实例。

get_message(key)

返回与 key 对应的消息的表示形式,作为适当的特定格式的 Message 子类的实例;如果不存在这样的消息,则引发 KeyError 异常。

get_bytes(key)

返回与 key 对应的消息的字节表示形式,如果不存在此消息,则引发 KeyError 异常。

在版本 3.2 中添加。

get_string(key)

返回与 key 对应的消息的字符串表示形式,如果不存在此消息,则引发 KeyError 异常。该消息会通过 email.message.Message 进行处理,将其转换为 7 位干净的表示形式。

get_file(key)

返回与 key 对应的消息的 类文件 表示形式,如果不存在此消息,则引发 KeyError 异常。此类文件对象的行为就像以二进制模式打开一样。此文件一旦不再需要,应将其关闭。

在版本 3.2 中更改: 此文件对象实际上是一个 二进制文件;之前错误地以文本模式返回。此外,类文件对象 现在支持 上下文管理器 协议:您可以使用 with 语句自动关闭它。

注意

与其他消息表示形式不同,类文件 表示形式不一定独立于创建它们的 Mailbox 实例或底层邮箱。每个子类都提供了更具体的文档。

__contains__(key)

如果 key 对应于一条消息,则返回 True,否则返回 False

__len__()

返回邮箱中消息的计数。

clear()

删除邮箱中的所有消息。

pop(key, default=None)

返回与 key 对应的消息的表示形式并删除该消息。如果不存在此类消息,则返回 default。该消息表示为适当的特定格式的 Message 子类的实例,除非在初始化 Mailbox 实例时指定了自定义消息工厂。

popitem()

返回一个任意的 (key, message) 对,其中 key 是一个键,message 是消息的表示形式,并删除对应的消息。如果邮箱为空,则引发 KeyError 异常。该消息表示为适当的特定格式的 Message 子类的实例,除非在初始化 Mailbox 实例时指定了自定义消息工厂。

update(arg)

参数 arg 应该是一个 keymessage 的映射或一个 (key, message) 对的可迭代对象。更新邮箱,以便对于每个给定的 keymessage,与 key 对应的消息设置为 message,就像使用 __setitem__() 一样。与 __setitem__() 一样,每个 key 必须已经对应于邮箱中的一条消息,否则会引发 KeyError 异常,因此通常 arg 不应该是一个 Mailbox 实例。

注意

与字典不同,不支持关键字参数。

flush()

将所有挂起的更改写入文件系统。对于某些 Mailbox 子类,更改始终会立即写入,flush() 不执行任何操作,但您仍然应该养成调用此方法的习惯。

lock()

获取对邮箱的独占咨询锁,以便其他进程知道不要修改它。如果锁不可用,则引发 ExternalClashError。使用的特定锁定机制取决于邮箱格式。在对邮箱的内容进行任何修改之前,您应该始终锁定邮箱。

unlock()

释放邮箱上的锁(如果有)。

close()

刷新邮箱,如有必要则解锁,并关闭所有打开的文件。对于某些 Mailbox 子类,此方法不执行任何操作。

Maildir 对象

class mailbox.Maildir(dirname, factory=None, create=True)

Mailbox 的子类,用于 Maildir 格式的邮箱。参数 factory 是一个可调用对象,它接受类文件的消息表示形式(其行为就像以二进制模式打开一样)并返回自定义表示形式。如果 factoryNone,则使用 MaildirMessage 作为默认消息表示形式。如果 createTrue,则在邮箱不存在时创建邮箱。

如果 createTrue 并且 dirname 路径存在,则会将其视为现有 maildir,而不会尝试验证其目录布局。

出于历史原因,dirname 被命名为这样而不是 path

Maildir 是一种基于目录的邮箱格式,为 qmail 邮件传输代理发明,现在被其他程序广泛支持。Maildir 邮箱中的消息存储在公共目录结构中的单独文件中。这种设计允许多个不相关的程序访问和修改 Maildir 邮箱而不会发生数据损坏,因此不需要文件锁定。

Maildir 邮箱包含三个子目录,即:tmpnewcur。消息在 tmp 子目录中临时创建,然后移动到 new 子目录以完成传递。邮件用户代理随后可以将消息移动到 cur 子目录,并将有关消息状态的信息存储在其文件名的特殊“info”部分中。

还支持 Courier 邮件传输代理引入的样式的文件夹。如果 '.' 是其名称的第一个字符,则主邮箱的任何子目录都被视为文件夹。文件夹名称由 Maildir 表示,不带前导 '.'。每个文件夹本身都是一个 Maildir 邮箱,但不应包含其他文件夹。相反,逻辑嵌套使用 '.' 来分隔级别,例如,“Archived.2005.07”。

colon

Maildir 规范要求在某些消息文件名中使用冒号(':')。但是,某些操作系统不允许在文件名中使用此字符。如果希望在此类操作系统上使用类似 Maildir 的格式,则应指定要使用的另一个字符。感叹号('!')是一种流行的选择。例如

import mailbox
mailbox.Maildir.colon = '!'

colon 属性也可以按实例设置。

3.13 版本更改: Maildir 现在会忽略以点号开头的的文件。

Maildir 实例拥有 Mailbox 的所有方法,此外还有以下方法:

list_folders()

返回所有文件夹名称的列表。

get_folder(folder)

返回一个 Maildir 实例,表示名称为 folder 的文件夹。如果该文件夹不存在,则会引发 NoSuchMailboxError 异常。

add_folder(folder)

创建一个名为 folder 的文件夹,并返回一个表示该文件夹的 Maildir 实例。

remove_folder(folder)

删除名称为 folder 的文件夹。如果该文件夹包含任何消息,则会引发 NotEmptyError 异常,并且不会删除该文件夹。

clean()

删除邮箱中最近 36 小时内未被访问的临时文件。Maildir 规范规定邮件读取程序应偶尔执行此操作。

get_flags(key)

以字符串形式返回与 key 对应的消息上设置的标志。这与 get_message(key).get_flags() 相同,但速度快得多,因为它不会打开消息文件。在遍历键以确定哪些消息值得获取时,请使用此方法。

如果您有一个 MaildirMessage 对象,请改用其 get_flags() 方法,因为消息的 set_flags()add_flag()remove_flag() 方法所做的更改不会在此处反映,直到调用邮箱的 __setitem__() 方法。

3.13 版本中新增。

set_flags(key, flags)

在与 key 对应的消息上,设置由 flags 指定的标志,并取消设置所有其他标志。调用 some_mailbox.set_flags(key, flags) 类似于

one_message = some_mailbox.get_message(key)
one_message.set_flags(flags)
some_mailbox[key] = one_message

但速度更快,因为它不会打开消息文件。

如果您有一个 MaildirMessage 对象,请改用其 set_flags() 方法,因为使用此邮箱方法所做的更改对于消息对象的方法 get_flags() 不可见。

3.13 版本中新增。

add_flag(key, flag)

在与 key 对应的消息上,设置由 flag 指定的标志,而不更改其他标志。要一次添加多个标志,flag 可以是包含多个字符的字符串。

使用此方法与消息对象的 add_flag() 方法的注意事项类似于 set_flags();请参阅那里的讨论。

3.13 版本中新增。

remove_flag(key, flag)

在与 key 对应的消息上,取消设置由 flag 指定的标志,而不更改其他标志。要一次删除多个标志,flag 可以是包含多个字符的字符串。

使用此方法与消息对象的 remove_flag() 方法的注意事项类似于 set_flags();请参阅那里的讨论。

3.13 版本中新增。

get_info(key)

返回包含与 key 对应的消息信息的字符串。这与 get_message(key).get_info() 相同,但速度快得多,因为它不会打开消息文件。在遍历键以确定哪些消息值得获取时,请使用此方法。

如果您有一个 MaildirMessage 对象,请改用其 get_info() 方法,因为消息的 set_info() 方法所做的更改不会在此处反映,直到调用邮箱的 __setitem__() 方法。

3.13 版本中新增。

set_info(key, info)

将与 key 对应的消息的信息设置为 info。调用 some_mailbox.set_info(key, flags) 类似于

one_message = some_mailbox.get_message(key)
one_message.set_info(info)
some_mailbox[key] = one_message

但速度更快,因为它不会打开消息文件。

如果您有一个 MaildirMessage 对象,请改用其 set_info() 方法,因为使用此邮箱方法所做的更改对于消息对象的方法 get_info() 不可见。

3.13 版本中新增。

Maildir 实现的一些 Mailbox 方法值得特别说明

add(message)
__setitem__(key, message)
update(arg)

警告

这些方法基于当前进程 ID 生成唯一的文件名。当使用多个线程时,可能会发生未检测到的名称冲突,除非协调线程以避免使用这些方法同时操作同一邮箱,否则可能导致邮箱损坏。

flush()

对 Maildir 邮箱的所有更改都会立即应用,因此此方法不执行任何操作。

lock()
unlock()

Maildir 邮箱不支持(或不需要)锁定,因此这些方法不会执行任何操作。

close()

Maildir 实例不保留任何打开的文件,并且底层邮箱不支持锁定,因此此方法不会执行任何操作。

get_file(key)

根据主机平台的不同,在返回的文件保持打开状态时,可能无法修改或删除底层消息。

参见

来自 Courier 的 maildir 手册页

格式的规范。描述了用于支持文件夹的常见扩展。

使用 maildir 格式

关于 Maildir 的发明者的说明。包括更新的名称创建方案和关于“info”语义的详细信息。

mbox 对象

class mailbox.mbox(path, factory=None, create=True)

用于 mbox 格式邮箱的 Mailbox 的子类。参数 factory 是一个可调用对象,它接受类文件消息表示(其行为如同以二进制模式打开),并返回自定义表示。如果 factoryNone,则使用 mboxMessage 作为默认消息表示。如果 createTrue,则在邮箱不存在时创建邮箱。

mbox 格式是用于在 Unix 系统上存储邮件的经典格式。mbox 邮箱中的所有消息都存储在单个文件中,每条消息的开头都由一行以“From ”开头的行表示。

存在几种 mbox 格式的变体,以解决原始格式中被认为的缺点。为了兼容性,mbox 实现了原始格式,有时被称为 mboxo。这意味着如果存在 Content-Length 标头,则会被忽略,并且消息正文中任何以“From ”开头的行在存储消息时都会转换为“>From ”,尽管读取消息时“>From ”的出现不会转换为“From ”。

mbox 实现的某些 Mailbox 方法值得特别说明

get_file(key)

mbox 实例上调用 flush()close() 之后使用该文件可能会产生不可预测的结果或引发异常。

lock()
unlock()

使用了三种锁定机制 - 点锁定,以及如果可用,则使用 flock()lockf() 系统调用。

参见

来自 tin 的 mbox 手册页

格式的规范,其中包含有关锁定的详细信息。

在 Unix 上配置 Netscape Mail:为什么 Content-Length 格式不好

使用原始 mbox 格式而不是变体的论据。

“mbox”是几种相互不兼容的邮箱格式的系列

mbox 变体的历史。

MH 对象

class mailbox.MH(path, factory=None, create=True)

用于 MH 格式邮箱的 Mailbox 的子类。参数 factory 是一个可调用对象,它接受类文件消息表示(其行为如同以二进制模式打开),并返回自定义表示。如果 factoryNone,则使用 MHMessage 作为默认消息表示。如果 createTrue,则在邮箱不存在时创建邮箱。

MH 是一种基于目录的邮箱格式,为邮件用户代理 MH 消息处理系统发明。MH 邮箱中的每条消息都驻留在其自己的文件中。除了消息之外,MH 邮箱可能包含其他 MH 邮箱(称为 文件夹)。文件夹可以无限嵌套。MH 邮箱还支持 序列,这些序列是用于在逻辑上对消息进行分组而无需将其移动到子文件夹的命名列表。序列在每个文件夹中名为 .mh_sequences 的文件中定义。

MH 类操作 MH 邮箱,但它不会尝试模拟所有 mh 的行为。特别是,它不会修改也不受 mh 用来存储其状态和配置的 context.mh_profile 文件的影响。

MH 实例除了以下方法外,还具有 Mailbox 的所有方法

在 3.13 版本中更改: 支持不包含 .mh_sequences 文件的文件夹。

list_folders()

返回所有文件夹名称的列表。

get_folder(folder)

返回一个 MH 实例,表示名称为 folder 的文件夹。如果该文件夹不存在,则引发 NoSuchMailboxError 异常。

add_folder(folder)

创建一个名称为 folder 的文件夹,并返回一个表示它的 MH 实例。

remove_folder(folder)

删除名称为 folder 的文件夹。如果该文件夹包含任何消息,则会引发 NotEmptyError 异常,并且不会删除该文件夹。

get_sequences()

返回一个将序列名称映射到键列表的字典。如果没有序列,则返回空字典。

set_sequences(sequences)

根据 sequences 重新定义邮箱中存在的序列,sequences 是一个将名称映射到键列表的字典,类似于 get_sequences() 返回的字典。

pack()

根据需要在邮箱中重命名消息,以消除编号中的间隙。相应地更新序列列表中的条目。

注意

此操作会使已发布的键无效,因此不应随后使用。

MH 实现的某些 Mailbox 方法值得特别说明

remove(key)
__delitem__(key)
discard(key)

这些方法会立即删除消息。不会使用 MH 约定,即通过在消息名称前添加逗号来标记要删除的消息。

lock()
unlock()

使用了三种锁定机制 - 点锁定,以及(如果可用)flock()lockf() 系统调用。对于 MH 邮箱,锁定邮箱意味着锁定 .mh_sequences 文件,并且仅在影响它们的任何操作期间锁定单个消息文件。

get_file(key)

根据主机平台的不同,当返回的文件保持打开状态时,可能无法删除底层消息。

flush()

对 MH 邮箱的所有更改都会立即应用,因此此方法不执行任何操作。

close()

MH 实例不保留任何打开的文件,因此此方法等效于 unlock()

参见

nmh - 消息处理系统

nmh 的主页,它是原始 mh 的更新版本。

MH & nmh:用户和程序员的电子邮件

一本关于 mhnmh 的 GPL 许可书籍,其中包含一些关于邮箱格式的信息。

Babyl 对象

class mailbox.Babyl(path, factory=None, create=True)

用于 Babyl 格式邮箱的 Mailbox 的子类。参数 factory 是一个可调用对象,它接受一个类似文件的消息表示(其行为类似于以二进制模式打开),并返回一个自定义表示。如果 factoryNone,则 BabylMessage 将用作默认消息表示。如果 createTrue,则如果邮箱不存在,则会创建该邮箱。

Babyl 是 Emacs 附带的 Rmail 邮件用户代理使用的一种单文件邮箱格式。消息的开头由包含两个字符 Control-Underscore ('\037') 和 Control-L ('\014') 的行指示。消息的结尾由下一条消息的开头指示,或者在最后一条消息的情况下,由包含 Control-Underscore ('\037') 字符的行指示。

Babyl 邮箱中的消息有两组标头:原始标头和所谓的可见标头。可见标头通常是原始标头的子集,这些标头已被重新格式化或缩写,使其更具吸引力。Babyl 邮箱中的每条消息还附带一个 标签列表,或者记录有关消息的额外信息的短字符串,并且在 Babyl 选项部分中保留了邮箱中找到的所有用户定义标签的列表。

Babyl 实例除了以下方法外,还具有 Mailbox 的所有方法。

get_labels()

返回邮箱中使用的所有用户定义标签的名称列表。

注意

检查实际消息以确定邮箱中存在哪些标签,而不是查阅 Babyl 选项部分中的标签列表,但是每当修改邮箱时,都会更新 Babyl 部分。

Babyl 实现的一些 Mailbox 方法值得特别说明。

get_file(key)

在 Babyl 邮箱中,消息的标头不会与消息的正文连续存储。要生成类似文件的表示形式,标头和正文会一起复制到 io.BytesIO 实例中,该实例具有与文件相同的 API。因此,类似文件的对象真正独立于底层邮箱,但与字符串表示形式相比,不会节省内存。

lock()
unlock()

使用了三种锁定机制 - 点锁定,以及如果可用,则使用 flock()lockf() 系统调用。

参见

第 5 版 Babyl 文件格式

Babyl 格式的规范。

使用 Rmail 读取邮件

Rmail 手册,其中包含一些关于 Babyl 语义的信息。

MMDF 对象

class mailbox.MMDF(path, factory=None, create=True)

用于 MMDF 格式邮箱的 Mailbox 的子类。参数 factory 是一个可调用对象,它接受一个类似文件的消息表示(其行为类似于以二进制模式打开),并返回一个自定义表示。如果 factoryNone,则 MMDFMessage 将用作默认消息表示。如果 createTrue,则如果邮箱不存在,则会创建该邮箱。

MMDF 是一种为多通道备忘录分发设施(一种邮件传输代理)发明的单文件邮箱格式。每条消息的格式与 mbox 消息相同,但在前后都用包含四个 Control-A ('\001') 字符的行括起来。与 mbox 格式一样,每条消息的开头由一行开头五个字符为 “From “ 的行表示,但是当存储消息时,额外的 “From “ 不会被转换为 “>From “,因为额外的消息分隔符行可以防止将此类出现误认为是后续消息的开头。

MMDF 实现的一些 Mailbox 方法值得特别说明。

get_file(key)

MMDF 实例上调用 flush()close() 之后使用该文件可能会产生不可预测的结果或引发异常。

lock()
unlock()

使用了三种锁定机制 - 点锁定,以及如果可用,则使用 flock()lockf() 系统调用。

参见

来自 tin 的 mmdf 手册页

来自新闻阅读器 tin 的文档中的 MMDF 格式规范。

MMDF

一篇描述多通道备忘录分发设施的维基百科文章。

Message 对象

class mailbox.Message(message=None)

模块 email.messageMessage 的子类。 mailbox.Message 的子类添加了特定于邮箱格式的状态和行为。

如果省略 message,则会在默认的空状态下创建新实例。如果 message 是一个 email.message.Message 实例,则会复制其内容;此外,如果 message 是一个 Message 实例,则会尽可能转换任何特定于格式的信息。如果 message 是字符串、字节串或文件,则它应该包含符合 RFC 2822 的消息,该消息会被读取和解析。文件应该以二进制模式打开,但是为了向后兼容,也接受文本模式的文件。

子类提供的特定于格式的状态和行为各不相同,但总的来说,只支持不特定于特定邮箱的属性(尽管这些属性可能特定于特定的邮箱格式)。例如,单文件邮箱格式的文件偏移量和基于目录的邮箱格式的文件名不会被保留,因为它们仅适用于原始邮箱。但是,消息是否已被用户读取或标记为重要等状态会被保留,因为它适用于消息本身。

不要求使用 Message 实例来表示使用 Mailbox 实例检索的消息。在某些情况下,生成 Message 表示形式所需的时间和内存可能不可接受。对于这种情况,Mailbox 实例还提供字符串和类似文件的表示形式,并且在初始化 Mailbox 实例时可以指定自定义消息工厂。

MaildirMessage 对象

class mailbox.MaildirMessage(message=None)

具有 Maildir 特定行为的消息。参数 message 的含义与 Message 构造函数相同。

通常,邮件用户代理应用程序在用户第一次打开和关闭邮箱后,会将 new 子目录中的所有邮件移动到 cur 子目录,记录这些邮件是旧的,无论它们是否真的已被读取。 cur 中的每条消息的文件名都会添加一个 “info” 部分,用于存储有关其状态的信息。(某些邮件阅读器也可能会在 new 中的消息中添加 “info” 部分。)“info” 部分可以采用两种形式:它可以包含 “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' 中的零个或一个的按字母顺序排列的串联。如果未设置任何标志或 “info” 包含实验语义,则返回空字符串。

set_flags(flags)

设置由 flags 指定的标志,并取消设置所有其他标志。

add_flag(flag)

设置由 flag 指定的标志,而不更改其他标志。要一次添加多个标志,flag 可以是包含多个字符的字符串。无论当前的 “info” 是否包含实验信息而不是标志,都会被覆盖。

remove_flag(flag)

取消设置由 flag 指定的标志,而不更改其他标志。要一次删除多个标志,flag 可以是包含多个字符的字符串。如果 “info” 包含实验信息而不是标志,则不会修改当前的 “info”。

get_date()

将消息的传递日期作为表示自 epoch 以来的秒数的浮点数返回。

set_date(date)

将消息的传递日期设置为 date,一个表示自 epoch 以来的秒数的浮点数。

get_info()

返回一个包含消息 “info” 的字符串。这对于访问和修改实验性的 “info”(即,不是标志列表)非常有用。

set_info(info)

将 “info” 设置为 info,它应该是一个字符串。

当基于 mboxMessageMMDFMessage 实例创建 MaildirMessage 实例时,将省略 StatusX-Status 标头,并进行以下转换

结果状态

mboxMessageMMDFMessage 状态

“cur” 子目录

O 标志

F 标志

F 标志

R 标志

A 标志

S 标志

R 标志

T 标志

D 标志

当基于 MHMessage 实例创建 MaildirMessage 实例时,会进行以下转换

结果状态

MHMessage 状态

“cur” 子目录

“unseen” 序列

“cur” 子目录和 S 标志

没有 “unseen” 序列

F 标志

“flagged” 序列

R 标志

“replied” 序列

当基于 BabylMessage 实例创建 MaildirMessage 实例时,会发生以下转换:

结果状态

BabylMessage 状态

“cur” 子目录

“unseen” 标签

“cur” 子目录和 S 标志

没有 “unseen” 标签

P 标志

“forwarded” 或 “resent” 标签

R 标志

“answered” 标签

T 标志

“deleted” 标签

mboxMessage 对象

class mailbox.mboxMessage(message=None)

具有 mbox 特定行为的消息。参数 message 的含义与 Message 构造函数中的含义相同。

mbox 邮箱中的消息存储在单个文件中。发件人的信封地址和发送时间通常存储在以 “From “ 开头的行中,该行用于指示消息的开始,尽管在不同的 mbox 实现中,此数据的确切格式存在很大差异。指示消息状态的标志,例如是否已读取或标记为重要,通常存储在 StatusX-Status 标头中。

mbox 消息的传统标志如下:

标志

含义

解释

R

已读

已读

O

旧的

先前被 MUA 检测到

D

已删除

标记为后续删除

F

已标记

标记为重要

A

已回复

已回复

“R” 和 “O” 标志存储在 Status 标头中,而 “D”、“F” 和 “A” 标志存储在 X-Status 标头中。这些标志和标头通常按上述顺序出现。

mboxMessage 实例提供以下方法:

get_from()

返回一个字符串,表示标记 mbox 邮箱中消息开始的 “From “ 行。不包括开头的 “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 标志

A 标志

R 标志

当基于 MHMessage 实例创建 mboxMessage 实例时,会发生以下转换:

结果状态

MHMessage 状态

R 标志和 O 标志

没有 “unseen” 序列

O 标志

“unseen” 序列

F 标志

“flagged” 序列

A 标志

“replied” 序列

当基于 BabylMessage 实例创建 mboxMessage 实例时,会发生以下转换:

结果状态

BabylMessage 状态

R 标志和 O 标志

没有 “unseen” 标签

O 标志

“unseen” 标签

D 标志

“deleted” 标签

A 标志

“answered” 标签

当基于 MMDFMessage 实例创建 mboxMessage 实例时,“From “ 行被复制,并且所有标志都直接对应。

结果状态

MMDFMessage 状态

R 标志

R 标志

O 标志

O 标志

D 标志

D 标志

F 标志

F 标志

A 标志

A 标志

MHMessage 对象

class mailbox.MHMessage(message=None)

具有 MH 特定行为的消息。参数 message 的含义与 Message 构造函数中的含义相同。

MH 消息不支持传统意义上的标记或标志,但它们支持序列,这是任意消息的逻辑分组。一些邮件阅读程序(尽管不是标准的 mhnmh)以与其他格式使用标志非常相似的方式使用序列,如下所示:

序列

解释

未见

未读,但先前被 MUA 检测到

已回复

已回复

已标记

标记为重要

MHMessage 实例提供以下方法:

get_sequences()

返回包含此消息的序列名称列表。

set_sequences(sequences)

设置包含此消息的序列列表。

add_sequence(sequence)

sequence 添加到包含此消息的序列列表中。

remove_sequence(sequence)

从包含此消息的序列列表中删除 sequence

当基于 MaildirMessage 实例创建 MHMessage 实例时,会发生以下转换:

结果状态

MaildirMessage 状态

“unseen” 序列

没有 S 标志

“replied” 序列

R 标志

“flagged” 序列

F 标志

当基于 mboxMessageMMDFMessage 实例创建 MHMessage 实例时,会省略 StatusX-Status 标头,并发生以下转换:

结果状态

mboxMessageMMDFMessage 状态

“unseen” 序列

没有 R 标志

“replied” 序列

A 标志

“flagged” 序列

F 标志

当基于 BabylMessage 实例创建 MHMessage 实例时,会发生以下转换:

结果状态

BabylMessage 状态

“unseen” 序列

“unseen” 标签

“replied” 序列

“answered” 标签

BabylMessage 对象

class mailbox.BabylMessage(message=None)

具有 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 实例的原始标头被修改时,可见标头不会自动修改以对应。此方法更新可见标头如下:每个具有相应原始标头的可见标头都设置为原始标头的值,每个没有相应原始标头的可见标头都将被删除,并且原始标头中存在但可见标头中不存在的任何 DateFromReply-ToToCCSubject 都将添加到可见标头中。

当基于 MaildirMessage 实例创建 BabylMessage 实例时,会发生以下转换:

结果状态

MaildirMessage 状态

“unseen” 标签

没有 S 标志

“deleted” 标签

T 标志

“answered” 标签

R 标志

“已转发” 标签

P 标志

当基于 mboxMessageMMDFMessage 实例创建 BabylMessage 实例时,会省略 StatusX-Status 标头,并发生以下转换:

结果状态

mboxMessageMMDFMessage 状态

“unseen” 标签

没有 R 标志

“deleted” 标签

D 标志

“answered” 标签

A 标志

当基于 MHMessage 实例创建 BabylMessage 实例时,会发生以下转换:

结果状态

MHMessage 状态

“unseen” 标签

“unseen” 序列

“answered” 标签

“replied” 序列

MMDFMessage 对象

class mailbox.MMDFMessage(message=None)

具有 MMDF 特定行为的消息。参数 message 的含义与 Message 构造函数相同。

与 mbox 邮箱中的消息一样,MMDF 消息存储时,发送者的地址和发送日期在以“From ”开头的初始行中。同样,指示消息状态的标志通常存储在 StatusX-Status 标头中。

MMDF 消息的传统标志与 mbox 消息的标志相同,如下所示:

标志

含义

解释

R

已读

已读

O

旧的

先前被 MUA 检测到

D

已删除

标记为后续删除

F

已标记

标记为重要

A

已回复

已回复

“R” 和 “O” 标志存储在 Status 标头中,而 “D”、“F” 和 “A” 标志存储在 X-Status 标头中。这些标志和标头通常按上述顺序出现。

MMDFMessage 实例提供以下方法,这些方法与 mboxMessage 提供的方法相同:

get_from()

返回一个字符串,表示标记 mbox 邮箱中消息开始的 “From “ 行。不包括开头的 “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 标志

A 标志

R 标志

当基于 MHMessage 实例创建 MMDFMessage 实例时,会发生以下转换:

结果状态

MHMessage 状态

R 标志和 O 标志

没有 “unseen” 序列

O 标志

“unseen” 序列

F 标志

“flagged” 序列

A 标志

“replied” 序列

当基于 BabylMessage 实例创建 MMDFMessage 实例时,会发生以下转换:

结果状态

BabylMessage 状态

R 标志和 O 标志

没有 “unseen” 标签

O 标志

“unseen” 标签

D 标志

“deleted” 标签

A 标志

“answered” 标签

当基于 mboxMessage 实例创建 MMDFMessage 实例时,将复制“From ”行,并且所有标志直接对应

结果状态

mboxMessage 状态

R 标志

R 标志

O 标志

O 标志

D 标志

D 标志

F 标志

F 标志

A 标志

A 标志

异常

以下异常类在 mailbox 模块中定义:

exception mailbox.Error

所有其他模块特定异常的基类。

exception mailbox.NoSuchMailboxError

当期望邮箱但未找到时引发,例如当使用不存在的路径(且 create 参数设置为 False)实例化 Mailbox 子类时,或者当打开不存在的文件夹时。

exception mailbox.NotEmptyError

当邮箱不为空但预期为空时引发此错误,例如删除包含消息的文件夹时。

异常 mailbox.ExternalClashError

当某些超出程序控制范围的邮箱相关条件导致程序无法继续时引发此错误,例如无法获取另一个程序已持有的锁,或者当唯一生成的文件名已存在时。

异常 mailbox.FormatError

当无法解析文件中的数据时引发此错误,例如当 MH 实例尝试读取损坏的 .mh_sequences 文件时。

示例

一个简单的示例,打印邮箱中所有看起来有趣的消息的主题

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 = {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()