email.message:表示电子邮件

源代码: Lib/email/message.py


3.6 版本新增: [1]

email 包中的核心类是 EmailMessage 类,它从 email.message 模块导入。它是 email 对象模型的基础类。EmailMessage 提供了设置和查询头部字段、访问消息正文以及创建或修改结构化消息的核心功能。

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

EmailMessage 对象提供的概念模型是一个有序的头部字典,以及表示消息 RFC 5322 正文的 有效负载,它可能是一个 EmailMessage 子对象列表。除了用于访问头部名称和值的普通字典方法外,还有一些方法用于访问头部中的专门信息(例如 MIME 内容类型)、操作有效负载、生成消息的序列化版本以及递归遍历对象树。

EmailMessage 类字典式接口由头部名称索引,头部名称必须是 ASCII 值。字典的值是带有附加方法的一些字符串。头部以保留大小写形式存储和返回,但字段名称匹配不区分大小写。键是有序的,但与真正的字典不同,可以有重复项。还提供了其他方法用于处理具有重复键的头部。

有效负载 可以是字符串或字节对象(对于简单的消息对象),也可以是 EmailMessage 对象列表(对于 MIME 容器文档,如 multipart/*message/rfc822 消息对象)。

class email.message.EmailMessage(policy=default)

如果指定了 policy,则使用它指定的规则来更新和序列化消息的表示形式。如果未设置 policy,则使用 default 策略,该策略遵循电子邮件 RFC 的规则,但行尾符除外(它使用 Python 标准的 \n 行尾符,而不是 RFC 规定的 \r\n)。有关详细信息,请参阅 policy 文档。

as_string(unixfrom=False, maxheaderlen=None, policy=None)

返回整个消息,将其展平为字符串。当可选的 unixfrom 为 true 时,返回的字符串中包含信封头。unixfrom 默认为 False。为了向后兼容基本的 Message 类,接受 maxheaderlen,但默认为 None,这意味着默认情况下,行长由策略的 max_line_length 控制。可以使用 policy 参数覆盖从消息实例获得的默认策略。这可以用来控制该方法生成的一些格式,因为指定的 policy 将传递给 Generator

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

请注意,提供此方法是为了方便起见,并且可能不是在应用程序中序列化消息的最有用的方法,尤其是在处理多个消息时。有关用于序列化消息的更灵活的 API,请参阅 email.generator.Generator。另请注意,当 utf8False(默认值)时,此方法仅限于生成序列化为 “7 位干净” 的消息。

在 3.6 版本中更改: 当未指定 maxheaderlen 时,默认行为从默认为 0 更改为默认为策略中的 max_line_length 的值。

__str__()

等效于 as_string(policy=self.policy.clone(utf8=True))。允许 str(msg) 生成一个包含以可读格式序列化消息的字符串。

3.4 版本更改: 该方法已更改为使用 utf8=True,从而生成类似 RFC 6531 的消息表示形式,而不是作为 as_string() 的直接别名。

as_bytes(unixfrom=False, policy=None)

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

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

请注意,此方法是为了方便而提供的,可能不是在应用程序中序列化消息的最有效方法,特别是当您处理多个消息时。有关序列化消息的更灵活的 API,请参阅 email.generator.BytesGenerator

__bytes__()

等效于 as_bytes()。允许 bytes(msg) 生成一个包含序列化消息的字节对象。

is_multipart()

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

set_unixfrom(unixfrom)

将消息的信封头设置为 unixfrom,它应该是一个字符串。(有关此标头的简要说明,请参阅 mboxMessage。)

get_unixfrom()

返回消息的信封头。如果从未设置信封头,则默认为 None

以下方法实现了用于访问消息标头的类似映射的接口。请注意,这些方法与普通映射(即字典)接口之间存在一些语义差异。例如,在字典中,没有重复的键,但是在这里,可能存在重复的消息头。此外,在字典中,keys() 返回的键的顺序没有保证,但是在 EmailMessage 对象中,标头始终以它们在原始消息中出现的顺序返回,或者以它们稍后添加到消息中的顺序返回。任何删除然后重新添加的标头始终附加到标头列表的末尾。

这些语义差异是有意的,并且偏向于在最常见的用例中提供便利。

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

__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() 方法获取所有名为 name 的现有标头的值。

使用标准(非 compat32)策略,返回的值是 email.headerregistry.BaseHeader 的子类的实例。

__setitem__(name, val)

向消息添加一个标头,字段名称为 name,值为 val。该字段将附加到消息的现有标头的末尾。

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

del msg['subject']
msg['subject'] = 'Python roolz!'

如果 policy 将某些标头定义为唯一(标准策略也是如此),则当尝试为已存在的此类标头赋值时,此方法可能会引发 ValueError。为了保持一致性,此行为是故意的,但是不要依赖它,因为我们可能会选择将来使此类赋值自动删除现有标头。

__delitem__(name)

从消息的标头中删除所有名称为 name 的字段。如果标头中不存在命名字段,则不会引发异常。

keys()

返回所有消息的标头字段名称的列表。

values()

返回所有消息的字段值的列表。

items()

返回包含所有消息的字段标头和值的 2 元组的列表。

get(name, failobj=None)

返回命名标头字段的值。这与 __getitem__() 相同,只是如果缺少命名标头,则返回可选的 failobj (failobj 默认为 None)。

以下是一些其他有用的与标头相关的方法

get_all(name, failobj=None)

返回名为 name 的字段的所有值的列表。如果消息中没有此类命名的标头,则返回 failobj (默认为 None)。

add_header(_name, _value, **_params)

扩展标头设置。此方法类似于 __setitem__(),不同之处在于可以提供额外的标头参数作为关键字参数。_name 是要添加的标头字段,_value 是标头的主要值。

对于关键字参数字典 _params 中的每个项目,键被视为参数名称,下划线转换为破折号(因为破折号在 Python 标识符中是非法的)。通常,参数将添加为 key="value",除非值是 None,在这种情况下,只会添加键。

如果值包含非 ASCII 字符,可以通过将值指定为 (CHARSET, LANGUAGE, VALUE) 格式的三元组来显式控制字符集和语言,其中 CHARSET 是一个字符串,用于命名用于编码该值的字符集, LANGUAGE 通常可以设置为 None 或空字符串(有关其他可能性,请参见 RFC 2231), VALUE 是包含非 ASCII 代码点的字符串值。如果未传递三元组,并且值包含非 ASCII 字符,则会使用 utf-8CHARSETNoneLANGUAGERFC 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'))
replace_header(_name, _value)

替换标头。替换消息中与 _name 匹配的第一个标头,保留原始标头的标头顺序和字段名称大小写。如果没有找到匹配的标头,则引发 KeyError

get_content_type()

返回消息的内容类型,强制转换为小写形式的 maintype/subtype。如果消息中没有 Content-Type 标头,则返回 get_default_type() 返回的值。如果 Content-Type 标头无效,则返回 text/plain

(根据 RFC 2045,消息始终具有默认类型,get_content_type() 将始终返回一个值。RFC 2045 定义消息的默认类型为 text/plain,除非它出现在 multipart/digest 容器内,在这种情况下它将是 message/rfc822。如果 Content-Type 标头具有无效的类型规范,则 RFC 2045 要求默认类型为 text/plain。)

get_content_maintype()

返回消息的主要内容类型。这是 get_content_type() 返回的字符串的 maintype 部分。

get_content_subtype()

返回消息的子内容类型。这是 get_content_type() 返回的字符串的 subtype 部分。

get_default_type()

返回默认内容类型。大多数消息的默认内容类型为 text/plain,但作为 multipart/digest 容器子部分的消息除外。此类子部分的默认内容类型为 message/rfc822

set_default_type(ctype)

设置默认内容类型。ctype 应该是 text/plainmessage/rfc822,尽管这不是强制的。默认内容类型不存储在 Content-Type 标头中,因此它仅在消息中不存在 Content-Type 标头时影响 get_content_type 方法的返回值。

set_param(param, value, header='Content-Type', requote=True, charset=None, language='', replace=False)

Content-Type 标头中设置参数。如果参数已存在于标头中,则将其值替换为 value。当 headerContent-Type (默认值)并且标头尚未存在于消息中时,添加该标头,将其值设置为 text/plain,并追加新的参数值。可选的 header 指定 Content-Type 的替代标头。

如果值包含非 ASCII 字符,可以使用可选的 charsetlanguage 参数显式指定字符集和语言。可选的 language 指定 RFC 2231 语言,默认为空字符串。charsetlanguage 都应该是字符串。默认情况下,charset 使用 utf8language 使用 None

如果 replaceFalse (默认值),则标头将移动到标头列表的末尾。如果 replaceTrue,则将在适当的位置更新标头。

不建议将 requote 参数与 EmailMessage 对象一起使用。

请注意,可以通过标头值的 params 属性访问标头的现有参数值(例如,msg['Content-Type'].params['charset'])。

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

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

Content-Type 标头中完全删除给定的参数。标头将在适当的位置重写,不包含参数或其值。可选的 header 指定 Content-Type 的替代标头。

不建议将 requote 参数与 EmailMessage 对象一起使用。

get_filename(failobj=None)

返回消息的 Content-Disposition 标头的 filename 参数的值。如果标头没有 filename 参数,则此方法将回退到查找 Content-Type 标头上的 name 参数。如果找不到任何一个,或者标头丢失,则返回 failobj。返回的字符串将始终根据 email.utils.unquote() 进行取消引用。

get_boundary(failobj=None)

返回消息的 Content-Type 标头的 boundary 参数的值,如果缺少标头或没有 boundary 参数,则返回 failobj。返回的字符串将始终按照 email.utils.unquote() 进行非引用。

set_boundary(boundary)

Content-Type 标头的 boundary 参数设置为 boundaryset_boundary() 如果需要,将始终引用 boundary。如果消息对象没有 Content-Type 标头,则会引发 HeaderParseError

请注意,使用此方法与删除旧的 Content-Type 标头,并通过 add_header() 添加具有新边界的新标头略有不同,因为 set_boundary() 会保留标头列表中 Content-Type 标头的顺序。

get_content_charset(failobj=None)

返回 Content-Type 标头的 charset 参数,强制转换为小写。 如果没有 Content-Type 标头,或者该标头没有 charset 参数,则返回 failobj

get_charsets(failobj=None)

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

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

is_attachment()

如果存在 Content-Disposition 标头,并且其(不区分大小写)的值为 attachment,则返回 True,否则返回 False

在 3.4.2 版本中更改: 为了与 is_multipart() 保持一致,is_attachment 现在是一个方法而不是属性。

get_content_disposition()

如果消息有 Content-Disposition 标头,则返回该标头的(不带参数)小写值,否则返回 None。此方法的可能值为 *inline*、*attachment*,如果消息遵循 RFC 2183,则返回 None

在 3.5 版本中添加。

以下方法与查询和操作消息的内容(有效负载)有关。

walk()

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

以下是一个示例,该示例打印多部分消息结构的每个部分的 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。我们可以在示例中通过使用 _structure 调试助手函数来看到这一点

>>> from email.iterators import _structure
>>> 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() 返回 True,并且 walk 会下降到子部分中。

get_body(preferencelist=('related', 'html', 'plain'))

返回最适合作为消息“正文”的 MIME 部分。

preferencelist 必须是字符串序列,来自集合 relatedhtmlplain,并指示返回的部分的内容类型的首选顺序。

开始查找与调用 get_body 方法的对象匹配的候选对象。

如果 preferencelist 中未包含 related,则当(子)部分与首选项匹配时,将遇到的任何相关部分的根部分(或根部分的子部分)视为候选对象。

当遇到 multipart/related 时,请检查 start 参数,如果找到具有匹配 Content-ID 的部分,则在查找候选匹配项时仅考虑它。否则,仅考虑 multipart/related 的第一个(默认根)部分。

如果某个部分具有 Content-Disposition 标头,则仅当该标头的值为 inline 时才将该部分视为候选匹配项。

如果候选对象均不匹配 preferencelist 中的任何首选项,则返回 None

注意:(1)对于大多数应用程序,真正有意义的 preferencelist 组合只有 ('plain',)('html', 'plain') 和默认的 ('related', 'html', 'plain')。(2) 由于匹配从调用 get_body 的对象开始,因此除非 preferencelist 具有非默认值,否则在 multipart/related 上调用 get_body 将返回对象本身。(3) 未指定 Content-Type 或其 Content-Type 标头无效的消息(或消息部分)将被视为 text/plain 类型,这偶尔可能导致 get_body 返回意外结果。

iter_attachments()

返回消息的所有直接子部分的迭代器,这些子部分不是候选“正文”部分。也就是说,跳过 text/plaintext/htmlmultipart/relatedmultipart/alternative 的首次出现(除非它们通过 Content-Disposition: attachment 显式标记为附件),并返回所有剩余部分。当直接应用于 multipart/related 时,返回除根部分之外的所有相关部分的迭代器(即:start 参数指向的部分,或者如果没有 start 参数或 start 参数与任何部分的 Content-ID 不匹配时的第一部分)。当直接应用于 multipart/alternative 或非 multipart 时,返回一个空迭代器。

iter_parts()

返回消息的所有直接子部分的迭代器,对于非 multipart,该迭代器将为空。(另请参见 walk()。)

get_content(*args, content_manager=None, **kw)

调用 content_managerget_content() 方法,将 self 作为消息对象传递,并将任何其他参数或关键字作为附加参数传递。如果未指定 content_manager,则使用当前 policy 指定的 content_manager

set_content(*args, content_manager=None, **kw)

调用 content_managerset_content() 方法,将 self 作为消息对象传递,并将任何其他参数或关键字作为附加参数传递。如果未指定 content_manager,则使用当前 policy 指定的 content_manager

将非 multipart 消息转换为 multipart/related 消息,将任何现有的 Content- 标头和有效负载移动到 multipart 的(新的)第一部分。如果指定了 boundary,则将其用作 multipart 中的边界字符串,否则将边界留到需要时自动创建(例如,当消息被序列化时)。

make_alternative(boundary=None)

将非 multipartmultipart/related 消息转换为 multipart/alternative 消息,将任何现有的 Content- 标头和有效负载移动到 multipart 的(新的)第一部分。如果指定了 boundary,则将其用作 multipart 中的边界字符串,否则将边界留到需要时自动创建(例如,当消息被序列化时)。

make_mixed(boundary=None)

将非 multipartmultipart/relatedmultipart-alternative 消息转换为 multipart/mixed 消息,将任何现有的 Content- 标头和有效负载移动到 multipart 的(新的)第一部分。如果指定了 boundary,则将其用作 multipart 中的边界字符串,否则将边界留到需要时自动创建(例如,当消息被序列化时)。

如果消息是 multipart/related,则创建一个新的消息对象,将其所有参数传递给其 set_content() 方法,并将其 attach()multipart。如果消息是非 multipart,则调用 make_related(),然后按上述步骤进行。如果消息是任何其他类型的 multipart,则引发 TypeError。如果未指定 content_manager,则使用当前 policy 指定的 content_manager。如果添加的部分没有 Content-Disposition 标头,则添加一个值为 inline 的标头。

add_alternative(*args, content_manager=None, **kw)

如果消息是 multipart/alternative,则创建一个新的消息对象,将其所有参数传递给其 set_content() 方法,并将其 attach()multipart。如果消息是非 multipartmultipart/related,则调用 make_alternative(),然后按上述步骤进行。如果消息是任何其他类型的 multipart,则引发 TypeError。如果未指定 content_manager,则使用当前 policy 指定的 content_manager

add_attachment(*args, content_manager=None, **kw)

如果消息是 multipart/mixed,则创建一个新的消息对象,将其所有参数传递给其 set_content() 方法,并将其 attach()multipart。如果消息是非 multipartmultipart/relatedmultipart/alternative,则调用 make_mixed(),然后按上述步骤进行。如果未指定 content_manager,则使用当前 policy 指定的 content_manager。如果添加的部分没有 Content-Disposition 标头,则添加一个值为 attachment 的标头。此方法可用于显式附件(Content-Disposition: attachment)和 inline 附件(Content-Disposition: inline),通过将适当的选项传递给 content_manager

clear()

删除有效负载和所有标头。

clear_content()

移除载荷和所有 !Content- 标头,保持所有其他标头完整且顺序不变。

EmailMessage 对象具有以下实例属性

preamble

MIME 文档的格式允许在标头后的空行和第一个多部分边界字符串之间存在一些文本。通常,此文本在支持 MIME 的邮件阅读器中是不可见的,因为它位于标准 MIME 封装之外。但是,在查看邮件的原始文本或在不支持 MIME 的阅读器中查看邮件时,此文本可能会变得可见。

preamble 属性包含 MIME 文档的此引导式额外封装文本。当 Parser 在标头之后但在第一个边界字符串之前发现一些文本时,它会将此文本分配给消息的 preamble 属性。当 Generator 正在写出 MIME 消息的纯文本表示形式,并且发现该消息具有 preamble 属性时,它会将此文本写入标头和第一个边界之间的区域。有关详细信息,请参阅 email.parseremail.generator

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

epilogue

epilogue 属性的作用与 preamble 属性相同,只是它包含出现在最后一个边界和消息末尾之间的文本。与 preamble 一样,如果没有 epilogue 文本,此属性将为 None

defects

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

class email.message.MIMEPart(policy=default)

此类表示 MIME 消息的子部分。它与 EmailMessage 相同,只是当调用 set_content() 时不会添加 MIME-Version 标头,因为子部分不需要自己的 MIME-Version 标头。

脚注