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 值。字典的值是带有某些额外方法的字符串。标头以保留大小写形式存储和返回,但字段名匹配不区分大小写。键是有序的,但与真正的字典不同,可以有重复的键。提供了额外的方法来处理具有重复键的标头。

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

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*为真时,信封头会包含在返回的字符串中。*unixfrom* 默认为 False。为了向后兼容基类 Message,*maxheaderlen* 参数被接受,但默认为 None,这意味着默认情况下行长由策略的 max_line_length 控制。*policy* 参数可用于覆盖从消息实例获取的默认策略。这可以用来控制该方法产生的一些格式,因为指定的 *policy* 将被传递给 Generator

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

请注意,此方法是为方便起见而提供的,在您的应用程序中可能不是序列化消息的最有用方式,特别是当您处理多个消息时。请参阅 email.generator.Generator 以获取更灵活的消息序列化 API。另请注意,当 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*为真时,信封头会包含在返回的字符串中。*unixfrom*默认为False。*policy*参数可用于覆盖从消息实例获取的默认策略。这可以用来控制该方法产生的一些格式,因为指定的*policy*将被传递给BytesGenerator

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

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

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

返回一个包含所有消息字段头和值的二元组列表。

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-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'))
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*。当 *header* 是 Content-Type(默认值)且消息中尚不存在该标头时,会添加该标头,将其值设置为 text/plain,并附加新的参数值。可选的 *header* 指定了除 Content-Type 之外的备用标头。

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

如果*replace*为False(默认值),标头会被移动到标头列表的末尾。如果*replace*为True,标头将在原地更新。

不推荐在 EmailMessage 对象中使用 *requote* 参数。

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

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

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

Content-Type 标头中完全移除给定的参数。标头将在原地重写,不包含该参数及其值。可选的 *header* 指定了除 Content-Type 之外的备选标头。

不推荐在 EmailMessage 对象中使用 *requote* 参数。

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 参数设置为 *boundary*。set_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。如果消息遵循 RFC 2183,则此方法的可能值为 *inline*、*attachment* 或 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部分不是multipart,但它们确实包含子部分。is_multipart()返回Truewalk会深入到子部分。

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的对象开始,所以在multipart/related上调用get_body将返回对象本身,除非*preferencelist*具有非默认值。(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_manager*的get_content()方法,将 self 作为消息对象传递,并将任何其他参数或关键字作为附加参数传递。如果未指定*content_manager*,则使用当前policy指定的content_manager

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

调用*content_manager*的set_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)

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

如果消息是 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* 属性将为 None

epilogue

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

defects

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

class email.message.MIMEPart(policy=default)

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

脚注