18.1.1. email.message:代表电子邮件

email包中的中心类是Message类,从email.message模块导入。它是email对象模型的 Base Class。 Message提供了用于设置和查询头字段以及访问消息正文的核心Function。

从概念上讲,Message对象由* headers payloads *组成。Headers 是 RFC 2822样式的字段名称和值,其中字段名称和值之间用冒号分隔。冒号既不是字段名也不是字段值的一部分。

Headers 以保留大小写的形式存储和返回,但不区分大小写。也可能只有一个信封 Headers,也称为* Unix-From Headers 或From_Headers。对于简单的邮件对象,有效负载可以是字符串,也可以是 MIME 容器文档的Message对象列表(例如 multipart/* message/rfc822 *)。

Message对象提供用于访问消息头的 Map 样式接口,以及用于访问头和有效负载的显式接口。它提供了方便的方法来生成消息对象树的纯文本表示形式,访问常用的头参数以及递归遍历对象树。

以下是Message类的方法:

  • 类别 email.message. Message

    • 构造函数不带任何参数。
  • as_string([* unixfrom *])

    • 返回整平为字符串的整个消息。当可选的* unixfrom *为True时,信封头包含在返回的字符串中。 * unixfrom *默认为False。如果需要填写默认值以完成对字符串的转换(例如,可能会生成或修改 MIME 边界),则拼合消息可能会触发对Message的更改。

请注意,此方法是为方便起见而提供的,不一定总是按照您想要的方式格式化消息。例如,默认情况下,它会粉碎以From开头的行。为了获得更大的灵 Active,请实例化一个Generator实例并直接使用其flatten()方法。例如:

from cStringIO import StringIO
from email.generator import Generator
fp = StringIO()
g = Generator(fp, mangle_from_=False, maxheaderlen=60)
g.flatten(msg)
text = fp.getvalue()
  • __str__ ( )

    • 等效于as_string(unixfrom=True)
  • is_multipart ( )

    • 如果消息的有效负载是子Message对象的列表,则返回True,否则返回False。当is_multipart()返回False时,有效负载应为字符串对象。
  • set_unixfrom(* unixfrom *)

    • 将邮件的信封 Headers 设置为* unixfrom *,它应该是一个字符串。
  • get_unixfrom ( )

    • 返回邮件的信封头。如果从未设置信封头,则默认为None
  • attach(有效负载)

    • 将给定的* payload *添加到当前有效负载中,该有效负载必须为None或调用之前的Message对象列表。调用之后,有效负载将始终是Message个对象的列表。如果要将有效负载设置为标量对象(例如字符串),请改用set_payload()
  • get_payload([* i * [,* decode *]])

    • 返回当前有效负载,当is_multipart()True时将为Message对象的列表,或当is_multipart()False时为字符串。如果有效负载是列表,并且您对列表对象进行了突变,则可以在适当位置修改消息的有效负载。

使用可选参数* i ,如果is_multipart()True,则get_payload()将返回有效载荷的第 i 个元素,从零开始计数。如果 i 小于 0 或大于或等于有效载荷中的项目数,则将引发IndexError。如果有效载荷是字符串(即is_multipart()False)并且给出了 i *,则引发TypeError

可选的* decode 是根据 Content-Transfer-Encoding Headers 指示是否应解码有效载荷的标志。当True并且消息不是 Multipart 时,如果此 Headers 的值为quoted-printablebase64,则将对有效负载进行解码。如果使用其他某种编码,或者缺少 Content-Transfer-Encoding Headers,或者有效负载包含伪造的 base64 数据,则有效负载将按原样返回(未编码)。如果消息是 Multipart 消息,并且 decode *标志是True,则返回None。 * decode *的默认值为False

  • set_payload(有效负载 [,字符集])
    • 将整个消息对象的有效负载设置为* payload 。确保有效载荷不变是 Client 的责任。可选的 charset *设置消息的默认字符集;有关详情,请参见set_charset()

在版本 2.2.2 中更改:添加了* charset *参数。

  • set_charset(字符集)
    • 将有效负载的字符集设置为* charset ,它可以是Charset实例(请参见email.charset),命名字符集的字符串或None。如果是字符串,它将被转换为Charset实例。如果 charset None,则charset参数将从 Content-Type *Headers 中删除(该消息将不会进行其他修改)。其他任何东西都会生成TypeError

如果不存在* MIME-Version Headers,则将添加一个。如果不存在 Content-Type Headers,则会添加一个 text/plain 值。无论 Content-Type Headers 已经存在,其charset参数都将设置为 charset.output_charset 。如果 charset.input_charset charset.output_charset 不同,则有效负载将重新编码为 output_charset 。如果不存在 Content-Transfer-Encoding Headers,则有效载荷将根据需要使用指定的Charset进行传输编码,并添加具有适当值的 Headers。如果 Content-Transfer-Encoding Headers 已经存在,则假定已经使用该 Content-Transfer-Encoding *对有效负载进行了正确编码,并且未对其进行修改。

该消息将被假定为* text/*类型,其有效负载采用 unicode 或 charset.input_charset 编码。在生成消息的纯文本表示形式时,它将被编码或转换为 charset.output_charset 并进行适当的传输编码。 MIMEHeaders( MIME-Version Content-Type Content-Transfer-Encoding *)将根据需要添加。

版本 2.2.2 中的新Function。

  • get_charset ( )
    • 返回与消息的有效负载关联的Charset实例。

版本 2.2.2 中的新Function。

下列方法实现了一个类似于 Map 的接口,用于访问消息的 RFC 2822Headers。请注意,这些方法与常规 Map(即字典)接口之间在语义上有所不同。例如,在词典中没有重复的键,但是这里可能有重复的消息头。同样,在字典中并没有保证keys()返回的键的 Sequences,但是在Message对象中,Headers 总是按照它们在原始消息中出现的 Sequences 返回,或者在以后添加到消息中。删除然后重新添加的任何 Headers 始终附加在 Headers 列表的末尾。

这些语义上的差异是故意的,并且倾向于最大的便利性。

请注意,在所有情况下,消息中存在的任何信封头都不会包含在 Map 接口中。

  • __len__ ( )

    • 返回标题总数,包括重复项。
  • __contains__(* name *)

    • 如果消息对象具有一个名为* name 的字段,则返回 true。匹配不区分大小写,并且 name *不应包含结尾的冒号。用于in运算符,例如:
if 'message-id' in myMessage:
    print 'Message-ID:', myMessage['message-id']
  • __getitem__(* name *)
    • 返回命名标题字段的值。 * name *不应包含冒号分隔符。如果缺少标题,则返回None;否则,返回_。永远不会提出KeyError

请注意,如果命名字段在消息的标题中多次出现,则将不确定返回哪个字段值。使用get_all()方法获取所有现存命名报头的值。

  • __setitem__(* name val *)
    • 向消息添加 Headers,其字段名称为* name ,值为 val *。该字段将附加到邮件现有字段的末尾。

请注意,这不会覆盖或删除任何具有相同名称的现有 Headers。如果要确保新标题是消息中字段名称为* name *的唯一字段,请首先删除该字段,例如:

del msg['subject']
msg['subject'] = 'Python roolz!'
  • __delitem__(* name *)

    • 从邮件标题中删除所有出现的名称为* name *的字段。如果标题字段中不存在命名字段,则不会引发异常。
  • has_key(* name *)

    • 如果消息包含名为* name *的头字段,则返回 true,否则返回 false。
  • keys ( )

    • 返回所有消息标题字段名称的列表。
  • values ( )

    • 返回所有消息字段值的列表。
  • items ( )

    • 返回一个包含所有消息字段标题和值的 2Tuples 列表。
  • get(* name * [,* failobj *])

    • 返回命名标题字段的值。这与getitem()相同,除了如果缺少指定的 Headers(默认为None),则返回可选的* failobj *。

以下是一些其他有用的方法:

  • get_all(* name * [,* failobj *])

    • 返回名为* name 的字段的所有值的列表。如果消息中没有这样的命名头,则返回 failobj *(默认为None)。
  • add_header(* _name _value ** _ params *)

    • 扩展头设置。此方法与setitem()相似,不同之处在于可以提供其他 Headers 参数作为关键字参数。 * _name 是要添加的标题字段, _ value 是标题的 primary *值。

对于关键字参数字典* _params *中的每个项目,都将键作为参数名称,并将下划线转换为破折号(因为破折号在 Python 标识符中是非法的)。通常,除非值是None,否则参数将作为key="value"添加,在这种情况下,仅会添加键。如果值包含非 ASCII 字符,则必须以(CHARSET, LANGUAGE, VALUE)格式将其指定为三个 Tuples,其中CHARSET是一个字符串,用于命名用于对值进行编码的字符集,通常LANGUAGE可以设置为None或空字符串(请参见 RFC 2231(其他可能性),而VALUE是包含非 ASCII 代码点的字符串值。

这是一个例子:

msg.add_header('Content-Disposition', 'attachment', filename='bud.gif')

这将添加一个看起来像

Content-Disposition: attachment; filename="bud.gif"

具有非 ASCII 字符的示例:

msg.add_header('Content-Disposition', 'attachment',
               filename=('iso-8859-1', '', 'Fußballer.ppt'))

Which produces

Content-Disposition: attachment; filename*="iso-8859-1''Fu%DFballer.ppt"
  • replace_header(* _name _value *)
    • 替换标题。替换在与* _name *匹配的消息中找到的第一个 Headers,并保留 HeadersSequences 和字段名大小写。如果找不到匹配的 Headers,则引发KeyError

版本 2.2.2 中的新Function。

  • get_content_type ( )
    • 返回消息的 Content Type。返回的字符串被强制转换为小写形式* maintype/subtype 。如果消息中没有 Content-Type *Headers,则将返回get_default_type()给出的默认类型。由于根据 RFC 2045,消息始终具有默认类型,因此get_content_type()将始终返回值。

RFC 2045将消息的默认类型定义为* text/plain ,除非它出现在 multipart/digest 容器内,在这种情况下它将是 message/rfc822 。如果 Content-Type Headers 具有无效的类型规范,则 RFC 2045要求默认类型为 text/plain *。

版本 2.2.2 中的新Function。

  • get_content_maintype ( )
    • 返回消息的主要 Content Type。这是get_content_type()返回的字符串的* maintype *部分。

版本 2.2.2 中的新Function。

  • get_content_subtype ( )
    • 返回消息的子 Content Type。这是get_content_type()返回的字符串的* subtype *部分。

版本 2.2.2 中的新Function。

  • get_default_type ( )
    • 返回默认的 Content Type。大多数消息的默认 Content Type 为* text/plain ,但作为 multipart/digest 容器的子部分的消息除外。这些子部分的默认 Content Type 为 message/rfc822 *。

版本 2.2.2 中的新Function。

  • set_default_type(* ctype *)
    • 设置默认的 Content Type。 * ctype 应该是 text/plain message/rfc822 ,尽管这不是强制性的。默认 Content Type 未存储在 Content-Type *Headers 中。

版本 2.2.2 中的新Function。

  • get_params([* failobj * [,* header * [,* unquote *]]])
    • 以列表形式返回消息的* Content-Type 参数。返回列表的元素是键/值对的 2Tuples,在'='符号上拆分。 '='的左侧是键,而右侧是值。如果参数中没有'='符号,则该值为空字符串,否则该值如get_param()中所述,并且如果可选的 unquote *为True(默认值),则该值不加引号。

可选的* failobj 是没有 Content-Type 头时要返回的对象。可选的 header 是要搜索的标题,而不是 Content-Type *。

在版本 2.2.2 中更改:添加了* unquote *参数。

  • get_param(* param * [,* failobj * [,* header * [,* unquote *]]])
    • 以字符串形式返回* Content-Type Headers 参数 param 的值。如果消息没有 Content-Type 头,或者没有这样的参数,则返回 failobj *(默认为None)。

如果提供了可选的* header ,则指定要使用的消息头,而不是 Content-Type *。

参数键始终不区分大小写地进行比较。返回值可以是字符串,也可以是 3Tuples(如果参数是 RFC 2231编码)。当它是一个三 Tuples 时,该值的元素的格式为(CHARSET, LANGUAGE, VALUE)。请注意CHARSETLANGUAGE都可以是None,在这种情况下,您应该考虑将VALUE编码为us-ascii字符集。您通常可以忽略LANGUAGE

如果您的应用程序不关心参数是否按照 RFC 2231进行编码,则可以pass调用email.utils.collapse_rfc2231_value()并从get_param()传入返回值来折叠参数值。当该值是一个 Tuples 时,它将返回经过适当解码的 Unicode 字符串;如果不是,则返回未引用的原始字符串。例如:

rawparam = msg.get_param('foo')
param = email.utils.collapse_rfc2231_value(rawparam)

在任何情况下,除非* unquote *设置为False,否则参数值(返回的字符串或三 Tuples 中的VALUE项)始终不加引号。

在版本 2.2.2 中进行了更改:添加了* unquote *参数,并且可能有 3Tuples 的返回值。

  • set_param((* param value * [,* header * [,* requote * [,* charset * [,* language *]]]])
    • 在* Content-Type Headers 中设置一个参数。如果参数已存在于标题中,则其值将替换为 value 。如果尚未为该消息定义 Content-Type Headers,则将其设置为 text/plain *,并将按照 RFC 2045附加新的参数值。

可选的* header 指定 Content-Type 的备用标题,除非可选的 requote *为False(默认为True),否则所有参数都将被引用。

如果指定了可选的* charset ,则该参数将根据 RFC 2231进行编码。可选的 language *指定 RFC 2231 语言,默认为空字符串。 * charset language *都应为字符串。

版本 2.2.2 中的新Function。

  • del_param(* param * [,* header * [,* requote *]])
    • 从* Content-Type Headers 中完全删除给定的参数。Headers 将在没有参数或其值的情况下被重写。除非 requote False(默认值为True),否则所有值都将根据需要加上引号。可选的 header 指定 Content-Type *的替代形式。

版本 2.2.2 中的新Function。

  • set_type(* type [,Headers] [,重新引用] *)
    • 设置* Content-Type *Headers 的主要类型和子类型。 * type 必须是形式为 maintype/subtype *的字符串,否则引发ValueError

此方法替换* Content-Type Headers,将所有参数保留在适当的位置。如果 requote *为False,则保留现有 Headers 的引用不变,否则参数将被引用(默认)。

可以在* header 参数中指定备用标题。设置 Content-Type Headers 后,还将添加 MIME-Version *Headers。

版本 2.2.2 中的新Function。

  • get_filename([* failobj *])

    • 返回消息的* Content-Disposition Headers 的filename参数的值。如果标题没有filename参数,则此方法将退回到在 Content-Type 标题上寻找name参数。如果两者均未找到,或者标题丢失,则返回 failobj *。返回的字符串将始终按照email.utils.unquote()取消引用。
  • get_boundary([* failobj *])

    • 返回消息的* Content-Type Headers 的boundary参数的值,如果 Headers 丢失或没有boundary参数,则返回 failobj *。返回的字符串将始终按照email.utils.unquote()取消引用。
  • set_boundary(* boundary *)

    • 将* Content-Type Headers 的boundary参数设置为 boundary 。如有必要,set_boundary()将始终引用 boundary 。如果消息对象没有 Content-Type *Headers,则引发HeaderParseError

请注意,使用此方法与passadd_header()删除旧的* Content-Type Headers 并添加具有新边界的新方法有一点不同,因为set_boundary()保留了 Content-Type *Headers 在 Headers 列表中的 Sequences。但是,它不会保留原始的 Content-TypeHeaders 中可能存在的任何连续行。

  • get_content_charset([* failobj *])
    • 返回* Content-Type Headers 的charset参数(强制小写)。如果没有 Content-Type 头,或者该头没有charset参数,则返回 failobj *。

请注意,此方法不同于get_charset(),后者返回Charset实例以获取消息正文的默认编码。

版本 2.2.2 中的新Function。

  • get_charsets([* failobj *])
    • 返回包含消息中字符集名称的列表。如果消息是* multipart *,则列表将为有效负载中的每个子部分包含一个元素,否则,它将为长度为 1 的列表。

列表中的每个项目都是一个字符串,它是表示子部分的* Content-Type 标题中charset参数的值。但是,如果子部分没有 Content-Type Headers,没有charset参数或者不是 text 主 MIME 类型,则返回列表中的该项将是 failobj *。

  • walk ( )
    • walk()方法是一种通用生成器,可用于按深度优先的遍历 Sequences 遍历消息对象树的所有部分和子部分。通常,您将在for循环中使用walk()作为迭代器;每次迭代都会返回下一个子部分。

这是一个打印 Multipart 消息结构的每个部分的 MIME 类型的示例:

>>> for part in msg.walk():
...     print part.get_content_type()
multipart/report
text/plain
message/delivery-status
text/plain
text/plain
message/rfc822

在版本 2.5 中进行了更改:先前弃用的方法get_type()get_main_type()get_subtype()已删除。

Message对象还可以选择包含两个实例属性,可以在生成 MIME 消息的纯文本时使用它们。

  • preamble
    • MIME 文档的格式允许在标题后的空白行和第一个 Multipart 边界字符串之间添加一些文本。通常,此文本在支持 MIME 的邮件阅读器中永远不可见,因为它不在标准 MIME 防护范围内。但是,在查看邮件的原始文本时,或在不支持 MIME 的阅读器中查看邮件时,此文本可能会变得可见。
  • preamble 属性包含 MIME 文档的前导多余的装甲文本。当Parser在标题之后但在第一个边界字符串之前发现一些文本时,它将将此文本分配给消息的 preamble 属性。当Generator写出 MIME 消息的纯文本表示形式时,如果发现该消息具有 preamble *属性,它将在 Headers 和第一个边界之间的区域中写入此文本。有关详细信息,请参见email.parseremail.generator

请注意,如果消息对象没有前导,则* preamble *属性将为None

  • epilogue
      • epilogue 属性的作用方式与 preamble *属性相同,不同之处在于它包含出现在消息的最后边界和末尾之间的文本。

在版本 2.5 中进行了更改:您无需将结尾部分设置为空字符串,即可使Generator在文件末尾打印换行符。

  • defects
      • defects *属性包含解析此消息时发现的所有问题的列表。有关可能的解析缺陷的详细说明,请参见email.errors

2.4 版的新Function。