18.4. 邮箱-处理各种格式的邮箱

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

See also

  • Module email

  • 表示和处理消息。

18.4.1. 邮箱对象

  • 类别 mailbox. Mailbox
    • 一个邮箱,可以检查和修改。

Mailbox类定义一个接口,不能实例化。而是,特定于格式的子类应继承Mailbox,并且您的代码应实例化特定的子类。

Mailbox界面类似于字典,带有对应于消息的小键。密钥由将与它们一起使用的Mailbox实例发出,并且仅对该Mailbox实例有意义。即使修改了相应的消息(例如,pass将其替换为另一条消息),键也会 continue 标识消息。

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

Mailbox接口语义在某些方面与字典语义有所不同。每次请求消息时,都会根据邮箱的当前状态生成新的表示形式(通常为Message实例)。同样,将消息添加到Mailbox实例时,将复制提供的消息表示形式的内容。在任何情况下,都不会引用Mailbox实例保留的消息表示形式。

默认的Mailbox迭代器遍历消息表示形式,而不是键,而不是默认的字典迭代器。此外,在迭代过程中修改邮箱是安全且定义明确的。创建迭代器后,添加到邮箱的邮件将不会被迭代器看到。在迭代器生成之前从邮箱中删除的消息将被静默跳过,尽管如果随后删除了相应的消息,则使用来自迭代器的键可能会导致KeyError异常。

Warning

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

Mailbox个实例具有以下方法:

  • add(消息)
    • 将* 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 对应的消息替换为 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子类的实例。

Note

iter()的行为与字典不同,后者在键上进行迭代。

  • iteritems ( )

    • items ( )
      • 返回对(* key message )对的迭代器,其中 key 是密钥, message *是消息表示形式(如果称为iteritems()),或者返回此类对的列表(如果称为items())。除非将Mailbox实例初始化时指定了自定义消息工厂,否则消息将表示为特定于格式的Message子类的实例。
  • get(* key default = None *)

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

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

    • 返回与* key *对应的消息的字符串表示形式,如果不存在此类消息,则引发KeyError异常。
  • get_file(* key *)

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

Note

与其他消息表示不同,类似文件的表示不一定独立于创建它们的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 message 的 Map,或者是( key message )对的可迭代对象。更新邮箱,以便对于每个给定的 key message ,将与 key 对应的消息设置为 message ,就像使用setitem()一样。与setitem()一样,每个 key 必须已经对应于邮箱中的一条消息,否则会引发KeyError异常,因此通常来说 arg *是Mailbox实例是不正确的。

Note

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

  • flush ( )

    • 将所有挂起的更 Rewrite 入文件系统。对于某些Mailbox子类,更改总是立即写入,而flush()则不执行任何操作,但您仍应养成调用此方法的习惯。
  • 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实例,请将 factor **设置为None

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

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

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

Note

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

import mailbox
mailbox.Maildir.colon = '!'

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

Maildir实例除以下内容外,还具有Mailbox的所有方法:

  • list_folders ( )

    • 返回所有文件夹名称的列表。
  • get_folder(文件夹)

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

    • 创建一个名为* folder *的文件夹,并返回代表该文件夹的Maildir实例。
  • remove_folder(文件夹)

    • 删除名称为* folder *的文件夹。如果文件夹中包含任何消息,则会引发NotEmptyErrorexception,并且不会删除该文件夹。
  • clean ( )

    • 从邮箱中删除过去 36 小时内未访问的临时文件。 Maildir 规范说,邮件阅读程序应该偶尔执行此操作。

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

  • add(消息)

    • __setitem__(* key message *)

    update(* arg *)

    Warning

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

  • flush ( )

    • 对 Maildir 邮箱的所有更改都将立即应用,因此此方法不起作用。
  • lock ( )

    • unlock ( )
      • Maildir 邮箱不支持(或要求)锁定,因此这些方法不起作用。
  • close ( )

    • Maildir实例不保留任何打开的文件,并且基础邮箱不支持锁定,因此此方法不执行任何操作。
  • get_file(* key *)

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

See also

18.4.1.2. mbox

    • class * mailbox. mbox(* path factory = None create = True *)
    • mbox 格式的邮箱的Mailbox子类。参数* factory 是一个可调用对象,它接受类似文件的消息表示形式(其行为就像在二进制模式下打开一样)并返回自定义表示形式。如果 factory None,则mboxMessage用作默认消息表示形式。如果 create *为True,则创建邮箱(如果该邮箱不存在)。

mbox 格式是在 Unix 系统上存储邮件的经典格式。 mbox 邮箱中的所有邮件都存储在一个文件中,每封邮件的开头由一行表示,其前五个字符为“发件人”。

存在 mbox 格式的几种变体,以解决原始版本中的感知缺陷。出于兼容性考虑,mbox实现了原始格式,有时称为* mboxo 。这意味着 Content-Length *Headers(如果存在)将被忽略,并且在存储消息时,在消息正文行的开头出现的所有“ From”都将转换为“> From”,尽管出现“阅读消息时,> From“不会转换为” From“。

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

  • get_file(* key *)

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

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

See also

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 邮箱(称为* folders )。文件夹可能无限期嵌套。 MH 邮箱还支持 sequences *,这是命名列表,用于对消息进行逻辑分组而不将其移动到子文件夹。序列在每个文件夹中的名为.mh_sequences的文件中定义。

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

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

  • list_folders ( )

    • 返回所有文件夹名称的列表。
  • get_folder(文件夹)

    • 返回一个MH实例,该实例代表名称为* folder *的文件夹。如果该文件夹不存在,则会引发NoSuchMailboxError异常。
  • add_folder(文件夹)

    • 创建一个名为* folder *的文件夹,并返回代表该文件夹的MH实例。
  • remove_folder(文件夹)

    • 删除名称为* folder *的文件夹。如果文件夹中包含任何消息,则会引发NotEmptyErrorexception,并且不会删除该文件夹。
  • get_sequences ( )

    • 返回 Map 到键列表的序列名称的字典。如果没有序列,则返回空字典。
  • set_sequences(序列)

    • 根据* sequences 重新定义邮箱中存在的序列, sequences *是 Map 到键列表的名称的字典,如get_sequences()返回。
  • pack ( )

    • 根据需要重命名邮箱中的邮件,以消除编号上的空白。序列列表中的条目会相应更新。

Note

此操作已使已发布的密钥无效,因此以后不应使用。

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

  • remove(* key *)

    • __delitem__(* key *)
    • discard(* key *)
      • 这些方法会立即删除该消息。未使用pass在消息名称前添加逗号来标记要删除的消息的 MH 约定。
  • lock ( )

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

    • 根据主机平台的不同,返回的文件保持打开状态时,可能无法删除基础消息。
  • flush ( )

    • 对 MH 邮箱的所有更改都将立即应用,因此此方法无效。
  • close ( )

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

See also

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')的行指示。消息的结尾由下一条消息的开头或在最后一条消息的情况下由包含 Control-Underscore('\037')字符的行指示。

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

Babyl实例除以下内容外,还具有Mailbox的所有方法:

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

Note

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

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

  • get_file(* key *)

    • 在 Babyl 邮箱中,邮件的标题不与邮件的正文连续存储。为了生成类似文件的表示形式,将 Headers 和正文一起复制到StringIO实例(来自StringIO模块),该实例的 API 与文件的 API 相同。结果,类似于文件的对象实际上独立于基础邮箱,但是与字符串表示形式相比,不节省内存。
  • lock ( )

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

See also

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()系统调用(如果可用)。

See also

  • 锡的 mmdf 手册页

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

  • MMDF

  • Wikipedia 上描述多 Channel 备忘录分发工具的文章。

18.4.2. 讯息对象

如果Ellipsis* message ,则新实例以默认的空状态创建。如果 message email.message.Message实例,则复制其内容;此外,如果 message Message实例,则将尽可能转换任何特定于格式的信息。如果 message *是字符串或文件,则它应包含 RFC 2822兼容的消息,该消息将被读取和解析。

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

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

18.4.2.1. MaildirMessage

  • 类别 mailbox. MaildirMessage([消息])
    • 带有 Maildir 特定行为的消息。参数* message *具有与Message构造函数相同的含义。

通常,邮件用户代理应用程序在用户第一次打开和关闭邮箱之后,将new子目录中的所有消息移至cur子目录,记录该消息是否旧,无论是否已被实际读取。 cur中的每个消息都有一个“ info”部分添加到其文件名中,以存储有关其状态的信息。 (某些邮件阅读器可能还会在new中的消息中添加“信息”部分.)“信息”部分可能采用以下两种形式之一:它可能包含“ 2”,后跟标准化标志列表(例如,“ 2” FR”),也可以包含“ 1”,后跟所谓的实验信息。 Maildir 消息的标准标志如下:

FlagMeaningExplanation
DDraftUnder composition
FFlagged标记为重要
PPassed转发,重新发送或退回
RRepliedReplied to
SSeenRead
TTrashed标记为以后删除

MaildirMessage个实例提供以下方法:

  • get_subdir ( )
    • 返回“ new”(如果消息应存储在new子目录中)或“ cur”(如果消息应存储在cur子目录中)。

Note

无论是否已读取邮件,访问邮件后,通常会将邮件从new移到cur。如果"S" in msg.get_flags()True,则已读取消息msg

  • set_subdir(* subdir *)

    • 设置消息应存储在的子目录。参数* subdir *必须为“ new”或“ cur”。
  • get_flags ( )

    • 返回一个字符串,指定当前设置的标志。如果邮件符合标准 Maildir 格式,则结果是按字母 Sequences 的级联,即'D''F''P''R''S''T'的出现 Sequences 为零或一次。如果未设置标志或“ info”包含实验性语义,则返回空字符串。
  • set_flags(* flags *)

    • 设置由* flags *指定的标志,并取消设置所有其他标志。
  • add_flag(* flag *)

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

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

    • 以浮点数返回消息的传递日期,该浮点数表示自该纪元以来的秒数。
  • set_date(日期)

    • 将消息的传递日期设置为* date *,这是一个代表自纪元以来的秒数的浮点数。
  • get_info ( )

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

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

当基于mboxMessageMMDFMessage实例创建MaildirMessage实例时,将Ellipsis* Status X-Status *Headers,并进行以下转换:

Resulting statemboxMessageMMDFMessage状态
"cur" subdirectoryO flag
F flagF flag
R flagA flag
S flagR flag
T flagD flag

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

Resulting stateMHMessage state
"cur" subdirectory"unseen" sequence
“ cur”子目录和 S 标志没有“看不见”的序列
F flag"flagged" sequence
R flag"replied" sequence

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

Resulting stateBabylMessage state
"cur" subdirectory"unseen" label
“ cur”子目录和 S 标志没有“看不见”的标签
P flag“转发”或“重新发送”标签
R flag"answered" label
T flag"deleted" label

18.4.2.2. mboxMessage

  • 类别 mailbox. mboxMessage([消息])
    • 具有特定于 mbox 行为的消息。参数* message *具有与Message构造函数相同的含义。

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

mbox 消息的常规标志如下:

FlagMeaningExplanation
RReadRead
OOld以前由 MUA 检测到
DDeleted标记为以后删除
FFlagged标记为重要
AAnsweredReplied to

“ R”和“ O”标志存储在* Status Headers 中,而“ D”,“ F”和“ A”标志存储在 X-Status *Headers 中。标志和 Headers 通常按提到的 Sequences 出现。

mboxMessage个实例提供以下方法:

  • get_from ( )

    • 返回一个字符串,该字符串表示 mbox 邮箱中消息的开始处的“发件人”行。开头的“ From”和结尾的换行符不包括在内。
  • set_from(* from_ time_ = None *)

    • 将“ From”行设置为* from_ ,应在不使用前导“ From”或尾随换行符的情况下进行指定。为了方便起见,可以指定 time_ 并将其适当地格式化并附加到 from_ 。如果指定了 time_ *,则它应该是time.struct_time实例,适合传递给time.strftime()True(使用time.gmtime())的 Tuples。
  • get_flags ( )

    • 返回一个字符串,指定当前设置的标志。如果消息符合常规格式,则结果是按照以下 Sequences 从零开始串联,即'R''O''D''F''A'中的每一个出现一次。
  • set_flags(* flags *)

    • 设置由* flags 指定的标志,并取消设置所有其他标志。参数 flags 应该是'R''O''D''F''A'中的每个零次或多次出现的任意 Sequences 的串联。
  • add_flag(* flag *)

    • 设置* flag 指定的标志,而不更改其他标志。要一次添加多个标志, flag *可以是一个以上字符的字符串。
  • remove_flag(* flag *)

    • 取消设置* flag 指定的标志,而不更改其他标志。要一次删除多个标志, flag *可能是一串以上的字符。

当基于MaildirMessage实例创建mboxMessage实例时,将根据MaildirMessage实例的交付日期生成“发件人”行,并进行以下转换:

Resulting stateMaildirMessage state
R flagS flag
O flag"cur" subdirectory
D flagT flag
F flagF flag
A flagR flag

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

Resulting stateMHMessage state
R 标志和 O 标志没有“看不见”的序列
O flag"unseen" sequence
F flag"flagged" sequence
A flag"replied" sequence

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

Resulting stateBabylMessage state
R 标志和 O 标志没有“看不见”的标签
O flag"unseen" label
D flag"deleted" label
A flag"answered" label

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

Resulting stateMMDFMessage state
R flagR flag
O flagO flag
D flagD flag
F flagF flag
A flagA flag

18.4.2.3. MHMessage

  • 类别 mailbox. MHMessage([消息])
    • 带有 MH 特定行为的消息。参数* message *具有与Message构造函数相同的含义。

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

SequenceExplanation
unseen未读取,但先前被 MUA 检测到
repliedReplied to
flagged标记为重要

MHMessage个实例提供以下方法:

  • get_sequences ( )

    • 返回包含此消息的序列名称的列表。
  • set_sequences(序列)

    • 设置包含此消息的序列列表。
  • add_sequence(序列)

    • 在包含此消息的序列列表中添加* sequence *。
  • remove_sequence(序列)

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

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

Resulting stateMaildirMessage state
"unseen" sequence没有 S 标志
"replied" sequenceR flag
"flagged" sequenceF flag

当基于mboxMessageMMDFMessage实例创建MHMessage实例时,将Ellipsis* Status X-Status *Headers,并进行以下转换:

Resulting statemboxMessageMMDFMessage状态
"unseen" sequence没有 R 标志
"replied" sequenceA flag
"flagged" sequenceF flag

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

Resulting stateBabylMessage state
"unseen" sequence"unseen" label
"replied" sequence"answered" label

18.4.2.4. BabylMessage

  • 类别 mailbox. BabylMessage([消息])
    • 带有 Babyl 特定行为的消息。参数* message *具有与Message构造函数相同的含义。

某些称为* attributes *的消息标签由约定定义为具有特殊含义。属性如下:

LabelExplanation
unseen未读取,但先前被 MUA 检测到
deleted标记为以后删除
filed复制到另一个文件或邮箱
answeredReplied to
forwardedForwarded
edited由用户修改
resentResent

默认情况下,Rmail 仅显示可见的标题。但是,BabylMessage类使用原始 Headers,因为它们更完整。如果需要,可以显式访问可见的 Headers。

BabylMessage个实例提供以下方法:

  • get_labels ( )

    • 返回邮件上的标签列表。
  • set_labels(* labels *)

    • 将消息上的标签列表设置为* labels *。
  • add_label(* label *)

    • 将* label *添加到邮件上的标签列表。
  • remove_label(* label *)

    • 从邮件上的标签列表中删除* label *。
  • get_visible ( )

    • 返回一个Message实例,其标题是消息的可见标题,并且其主体为空。
  • set_visible(可见)

    • 将消息的可见 Headers 设置为与* message 中的 Headers 相同。参数 visible *应该是Message实例,email.message.Message实例,字符串或类似文件的对象(应在文本模式下打开)。
  • update_visible ( )

    • 修改BabylMessage实例的原始 Headers 后,可见 Headers 不会自动修改为与之对应。此方法如下更新可见 Headers:将具有相应原始 Headers 的每个可见 Headers 设置为原始 Headers 的值,删除不具有相应原始 Headers 的每个可见 Headers,以及* Date From *,*原始 Headers 中存在但不包含可见 Headers 的 Reply-To To CC Subject *被添加到可见 Headers 中。

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

Resulting stateMaildirMessage state
"unseen" label没有 S 标志
"deleted" labelT flag
"answered" labelR flag
"forwarded" labelP flag

当基于mboxMessageMMDFMessage实例创建BabylMessage实例时,将Ellipsis* Status X-Status *Headers,并进行以下转换:

Resulting statemboxMessageMMDFMessage状态
"unseen" label没有 R 标志
"deleted" labelD flag
"answered" labelA flag

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

Resulting stateMHMessage state
"unseen" label"unseen" sequence
"answered" label"replied" sequence

18.4.2.5. MMDFMessage

  • 类别 mailbox. MMDFMessage([消息])
    • 带有 MMDF 特定行为的消息。参数* message *具有与Message构造函数相同的含义。

与 mbox 邮箱中的邮件一样,MMDF 邮件与发件人的地址和传递日期一起存储在以“ From”开头的首行中。同样,指示消息状态的标志通常存储在* Status X-Status *Headers 中。

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

FlagMeaningExplanation
RReadRead
OOld以前由 MUA 检测到
DDeleted标记为以后删除
FFlagged标记为重要
AAnsweredReplied to

“ R”和“ O”标志存储在* Status Headers 中,而“ D”,“ F”和“ A”标志存储在 X-Status *Headers 中。标志和 Headers 通常按提到的 Sequences 出现。

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())的 Tuples。
  • get_flags ( )

    • 返回一个字符串,指定当前设置的标志。如果消息符合常规格式,则结果是按照以下 Sequences 从零开始串联,即'R''O''D''F''A'中的每一个出现一次。
  • set_flags(* flags *)

    • 设置由* flags 指定的标志,并取消设置所有其他标志。参数 flags 应该是'R''O''D''F''A'中的每个零次或多次出现的任意 Sequences 的串联。
  • add_flag(* flag *)

    • 设置* flag 指定的标志,而不更改其他标志。要一次添加多个标志, flag *可以是一个以上字符的字符串。
  • remove_flag(* flag *)

    • 取消设置* flag 指定的标志,而不更改其他标志。要一次删除多个标志, flag *可能是一串以上的字符。

当基于MaildirMessage实例创建MMDFMessage实例时,将根据MaildirMessage实例的交付日期生成“发件人”行,并进行以下转换:

Resulting stateMaildirMessage state
R flagS flag
O flag"cur" subdirectory
D flagT flag
F flagF flag
A flagR flag

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

Resulting stateMHMessage state
R 标志和 O 标志没有“看不见”的序列
O flag"unseen" sequence
F flag"flagged" sequence
A flag"replied" sequence

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

Resulting stateBabylMessage state
R 标志和 O 标志没有“看不见”的标签
O flag"unseen" label
D flag"deleted" label
A flag"answered" label

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

Resulting statemboxMessage state
R flagR flag
O flagO flag
D flagD flag
F flagF flag
A flagA flag

18.4.3. Exceptions

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

  • exception mailbox. Error

    • 所有其他模块特定异常的 Base Class。
  • exception mailbox. NoSuchMailboxError

    • 在需要邮箱但未找到邮箱时引发,例如在使用不存在的路径实例化Mailbox子类(并且将* create *参数设置为False)或打开不存在的文件夹时引发。
  • exception mailbox. NotEmptyError

    • 在邮箱不为空但预期为空白时引发,例如在删除包含邮件的文件夹时。
  • exception mailbox. ExternalClashError

    • 当程序无法控制的某些与邮箱相关的条件导致该程序无法 continue 运行时(例如,无法获取另一个程序已经持有该锁的锁,或者当一个唯一生成的文件名已经存在时)引发。
  • exception mailbox. FormatError

    • 在无法解析文件中的数据时引发,例如当MH实例try读取损坏的.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 参数是可调用的,应创建新的消息对象。邮箱对象的next()方法使用一个参数 fp 调用 factory *。默认值为rfc822.Message类(请参见rfc822模块–和下面的 Comments)。

Note

出于本模块内部实现的原因,您可能希望以二进制模式打开* 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 *中传递。 工厂UnixMailbox类相同。
    • class * mailbox. BabylMailbox(* fp * [,* factory *])
    • 访问 Babyl 邮箱,该邮箱类似于 MMDF 邮箱。以 Babyl 格式,每封邮件都有两组 Headers,即原始Headers 和* visible *Headers。原始 Headers 出现在仅包含'*** EOOH ***'(原始 Headers 的结尾)的行之前,而可见 Headers 出现在EOOH行之后。与 Babyl 兼容的邮件阅读器将仅向您显示可见的 Headers,而BabylMailbox对象将返回仅包含可见 Headers 的邮件。您必须对邮箱文件进行自己的解析才能获得原始标题。邮件消息以 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. Examples

一个简单的示例,显示邮箱中所有邮件的主题,这些主题看起来很有趣:

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

本示例将邮件从多个邮件列表中分类到不同的邮箱中,请注意避免由于其他程序的并发修改而导致的邮件损坏,由于程序break而导致的邮件丢失或由于邮箱中的邮件格式错误而导致的过早终止:

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