email.message.Message:使用 compat32 API 表示电子邮件

Message类与EmailMessage类非常相似,没有该类添加的方法,并且某些其他方法的默认行为略有不同。我们还在此处记录了EmailMessage类支持的一些方法,除非您要处理旧代码,否则建议不要使用这些方法。

这两类的哲学和结构在其他方面是相同的。

本文档介绍了默认(针对Message)策略Compat32的行为。如果要使用其他策略,则应改用EmailMessage类。

电子邮件由* header payload 组成。Headers 必须为 RFC 5233个样式名称和值,其中字段名称和值之间用冒号分隔。冒号既不是字段名也不是字段值的一部分。有效负载可以是简单的文本消息,也可以是二进制对象,也可以是子消息的结构化序列,每个子消息都具有自己的 Headers 集和自己的有效负载。有效负载的后一种类型由具有 MIME 类型的消息(例如 multipart/* message/rfc822 *)指示。

Message对象提供的概念模型是标题的有序字典,其中包含用于从标题访问专用信息,访问有效负载,生成消息的序列化版本以及递归遍历对象树的其他方法。请注意,支持重复的 Headers,但必须使用特殊的方法来访问它们。

Message伪词典由 Headers 名称索引,Headers 名称必须为 ASCII 值。字典的值是应该仅包含 ASCII 字符的字符串;非 ASCIIImporting 有一些特殊的处理方法,但它并不总是产生正确的结果。Headers 以保留大小写的形式存储和返回,但是字段名称不区分大小写。也可能只有一个信封 Headers,也称为* Unix-From Headers 或From_Headers。如果是简单的邮件对象,则 payload 可以是字符串或字节,对于 MIME 容器文档(例如 multipart/* message/rfc822 ), payload 可以是字符串,也可以是Message对象的列表。

以下是Message类的方法:

  • 类别 email.message. Message(* policy = compat32 *)
    • 如果指定了* policy (它必须是policy类的实例),请使用它指定的规则来更新和序列化消息的表示形式。如果未设置 policy *,请使用compat32策略,该策略与电子邮件包的 Python 3.2 版本保持向后兼容性。有关更多信息,请参见policy文档。

在版本 3.3 中更改:添加了* policy *关键字参数。

  • as_string(* unixfrom = False maxheaderlen = 0 policy = None *)
    • 返回整平为字符串的整个消息。当可选的* unixfrom *为 true 时,信封头包含在返回的字符串中。 * unixfrom 默认为False。出于向后兼容的原因, maxheaderlen 默认为0,因此,如果要使用其他值,则必须显式覆盖它(此方法将忽略策略中为 max_line_length *指定的值)。 * policy 参数可用于覆盖从消息实例获得的默认策略。由于指定的 policy *将传递给Generator,因此可以用来控制该方法产生的某些格式。

如果需要填写默认值以完成对字符串的转换(例如,可能会生成或修改 MIME 边界),则拼合消息可能会触发对Message的更改。

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

from io import StringIO
from email.generator import Generator
fp = StringIO()
g = Generator(fp, mangle_from_=True, maxheaderlen=60)
g.flatten(msg)
text = fp.getvalue()

如果消息对象包含未根据 RFC 标准编码的二进制数据,则不兼容的数据将被 unicode“未知字符”代码点代替。 (另请参见as_bytes()BytesGenerator。)

在版本 3.4 中更改:添加了* policy *关键字参数。

  • __str__ ( )

    • 等效于as_string()。允许str(msg)生成包含格式化消息的字符串。
  • as_bytes(* unixfrom = False policy = None *)

    • 返回展平为字节对象的整个消息。当可选的* unixfrom *为 true 时,信封头包含在返回的字符串中。 * unixfrom *默认为False。 * policy 参数可用于覆盖从消息实例获得的默认策略。由于指定的 policy *将传递给BytesGenerator,因此可以用来控制该方法产生的某些格式。

如果需要填写默认值以完成对字符串的转换(例如,可能会生成或修改 MIME 边界),则拼合消息可能会触发对Message的更改。

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

from io import BytesIO
from email.generator import BytesGenerator
fp = BytesIO()
g = BytesGenerator(fp, mangle_from_=True, maxheaderlen=60)
g.flatten(msg)
text = fp.getvalue()

3.4 版的新Function。

  • __bytes__ ( )
    • 等效于as_bytes()。允许bytes(msg)产生一个包含格式化消息的字节对象。

3.4 版的新Function。

  • is_multipart ( )

    • 如果消息的有效负载是子Message对象的列表,则返回True,否则返回False。当is_multipart()返回False时,有效负载应为字符串对象(可能是 CTE 编码的二进制有效负载)。 (请注意,is_multipart()返回True并不一定意味着“ msg.get_content_maintype()=='multipart'”将返回True。例如,当Message类型为message/rfc822时,is_multipart将返回True。)
  • set_unixfrom(* unixfrom *)

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

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

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

这是传统方法。在EmailMessage类上,其Function由set_content()以及相关的makeadd方法代替。

  • get_payload(* i = None decode = False *)
    • 返回当前有效负载,当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,则将按原样返回有效负载(未编码)。在所有情况下,返回值都是二进制数据。如果消息是 Multipart 消息,并且 decode *标志是True,则返回None。如果有效载荷是 base64 且格式不正确(缺少填充,base64 字母之外的字符),则会将适当的缺陷添加到消息的缺陷属性(分别为InvalidBase64PaddingDefectInvalidBase64CharactersDefect)。

当* decode False(默认值)时,主体将作为字符串返回,而不对 Content-Transfer-Encoding 进行解码。但是,对于 8 位的 Content-Transfer-Encoding ,try使用replace错误处理程序,使用 Content-Type *Headers 指定的charset解码原始字节。如果未指定charset,或者电子邮件包无法识别给定的charset,则使用默认的 ASCII 字符集对正文进行解码。

这是传统方法。在EmailMessage类上,其Function由get_content()iter_parts()代替。

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

这是传统方法。在EmailMessage类上,其Function由set_content()代替。

  • 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 *对有效负载进行了正确编码,并且未对其进行修改。

这是传统方法。在EmailMessage类上,其Function由email.emailmessage.EmailMessage.set_content()方法的* charset *参数代替。

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

这是传统方法。在EmailMessage类上,它总是返回None

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

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

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

在从字节生成的模型中,任何pass非接口(与 RFC 违背)包含非 ASCII 字节的 Headers 值,当pass此接口检索时,都将被表示为Header对象,其字符集为 unknown-8bit。

  • __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 *的字段。如果标题字段中不存在命名字段,则不会引发异常。
  • keys ( )

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

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

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

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

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

  • get_all(* name failobj = None *)

    • 返回名为* 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 代码点的字符串值。如果未传递三个 Tuples,并且该值包含非 ASCII 字符,则会使用utf-8CHARSETNoneLANGUAGE自动以 RFC 2231格式进行编码。

这是一个例子:

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
  • 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 *。

  • get_content_maintype ( )

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

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

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

    • 设置默认的 Content Type。 * ctype 应该是 text/plain message/rfc822 ,尽管这不是强制性的。默认 Content Type 未存储在 Content-Type *Headers 中。
  • get_params(* failobj = None header ='content-type' unquote = True *)

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

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

这是传统方法。在EmailMessage类上,其Function由 Headers 访问方法返回的各个 Headers 对象的* params *属性代替。

  • get_param(* param failobj = None header ='content-type' unquote = True *)
    • 以字符串形式返回* 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项)始终不加引号。

这是传统方法。在EmailMessage类上,其Function由 Headers 访问方法返回的各个 Headers 对象的* params *属性代替。

  • set_param((param value header ='Content-Type' requote = True charset = None language ='' replace = False *)
    • 在* 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 *都应为字符串。

如果* replace False(默认值),则标题将移动到标题列表的末尾。如果 replace *为True,则标题将被适当更新。

在版本 3.4 中更改:添加了replace关键字。

  • del_param(* param header ='content-type' requote = True *)

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

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

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

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

这是传统方法。在EmailMessage类上,其Function由make_add_方法代替。

  • get_filename(* failobj = None *)

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

    • 返回消息的* 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 = None *)
    • 返回* Content-Type Headers 的charset参数(强制小写)。如果没有 Content-Type 头,或者该头没有charset参数,则返回 failobj *。

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

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

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

  • get_content_disposition ( )
    • 返回消息的* Content-Disposition Headers 的小写值(不带参数)(如果有的话)或None。如果消息遵循 RFC 2183,则此方法的可能值为 inline attachment *或None

3.5 版中的新Function。

  • 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
text/plain

walk迭代is_multipart()返回True的任何部分的子部分,即使msg.get_content_maintype() == 'multipart'可能返回False。我们可以pass使用_structure debug helper 函数在示例中看到这一点:

>>> for part in msg.walk():
...     print(part.get_content_maintype() == 'multipart',
...           part.is_multipart())
True True
False False
False True
False False
False False
False True
False False
>>> _structure(msg)
multipart/report
    text/plain
    message/delivery-status
        text/plain
        text/plain
    message/rfc822
        text/plain

这里的message部分不是multiparts,但它们确实包含子部分。 is_multipart()返回Truewalk下降到子部分。

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

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

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

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

您无需将结尾部分设置为空字符串,即可使Generator在文件末尾打印换行符。

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