email.policy:策略对象

在版本 3.3 中添加。

源代码: Lib/email/policy.py


email 包的主要重点是处理电子邮件和 MIME RFC 中描述的电子邮件消息。但是,电子邮件消息的一般格式(一个由头字段块组成,每个字段块由一个名称、一个冒号和一个值组成,整个块后跟一个空行和一个任意“正文”)是一种在电子邮件领域之外找到用途的格式。其中一些用途与主要的电子邮件 RFC 非常一致,而另一些则不一致。即使在使用电子邮件时,有时也希望打破对 RFC 的严格遵守,例如生成与不遵循标准的电子邮件服务器进行交互的电子邮件,或以违反标准的方式实现您想要使用的扩展。

策略对象使电子邮件包能够灵活地处理所有这些不同的用例。

Policy 对象封装了一组属性和方法,它们控制电子邮件包在使用期间的各个组件的行为。Policy 实例可以传递给电子邮件包中的各个类和方法,以更改默认行为。可设置的值及其默认值如下所述。

电子邮件包中所有类都使用默认策略。对于所有 parser 类和相关便捷函数,以及 Message 类,这是 Compat32 策略,通过其对应的预定义实例 compat32。此策略提供与电子邮件包的 Python3.3 之前版本(在某些情况下包括错误兼容性)的完全向后兼容性。

policy 关键字的 EmailMessage 的默认值为 EmailPolicy 策略,通过其预定义实例 default

创建 MessageEmailMessage 对象时,它会获取策略。如果消息是由 parser 创建的,传递给解析器的策略将是其创建的消息使用的策略。如果消息是由程序创建的,则可以在创建时指定策略。将消息传递给 generator 时,生成器默认使用消息中的策略,但你也可以将特定策略传递给生成器,该策略将覆盖存储在消息对象上的策略。

policy 关键字的 email.parser 类和解析器便捷函数的默认值将在 Python 的未来版本中发生更改。因此,在调用 parser 模块中描述的任何类和函数时,你应始终明确指定要使用的策略

本说明文档的第一部分涵盖了 Policy 的特性,抽象基类 定义了所有策略对象共有的特性,包括 compat32。这包括电子邮件包在内部调用的某些钩子方法,自定义策略可以覆盖这些方法以获取不同的行为。第二部分描述了具体类 EmailPolicyCompat32,它们分别实现了提供标准行为和向后兼容行为和特性的钩子。

Policy 实例是不可变的,但它们可以克隆,接受与类构造函数相同的关键字参数,并返回一个新的 Policy 实例,该实例是原始实例的副本,但指定了已更改的属性值。

例如,可以使用以下代码从磁盘上的文件中读取电子邮件,并将其传递给 Unix 系统上的系统 sendmail 程序

>>> from email import message_from_binary_file
>>> from email.generator import BytesGenerator
>>> from email import policy
>>> from subprocess import Popen, PIPE
>>> with open('mymsg.txt', 'rb') as f:
...     msg = message_from_binary_file(f, policy=policy.default)
...
>>> p = Popen(['sendmail', msg['To'].addresses[0]], stdin=PIPE)
>>> g = BytesGenerator(p.stdin, policy=msg.policy.clone(linesep='\r\n'))
>>> g.flatten(msg)
>>> p.stdin.close()
>>> rc = p.wait()

在这里,我们告诉 BytesGenerator 在创建要馈送到 sendmail's stdin 的二进制字符串时使用 RFC 正确的行分隔符字符,其中默认策略将使用 \n 行分隔符。

一些电子邮件包方法接受一个 策略 关键字参数,允许为该方法覆盖策略。例如,以下代码使用上一个示例中的 msg 对象的 as_bytes() 方法,并使用在其上运行的平台的本机行分隔符将消息写入文件

>>> import os
>>> with open('converted.txt', 'wb') as f:
...     f.write(msg.as_bytes(policy=msg.policy.clone(linesep=os.linesep)))
17

策略对象也可以使用加法运算符组合,生成一个策略对象,其设置是求和对象的非默认值的组合

>>> compat_SMTP = policy.compat32.clone(linesep='\r\n')
>>> compat_strict = policy.compat32.clone(raise_on_defect=True)
>>> compat_strict_SMTP = compat_SMTP + compat_strict

此操作不是可交换的;也就是说,添加对象的顺序很重要。举例来说

>>> policy100 = policy.compat32.clone(max_line_length=100)
>>> policy80 = policy.compat32.clone(max_line_length=80)
>>> apolicy = policy100 + policy80
>>> apolicy.max_line_length
80
>>> apolicy = policy80 + policy100
>>> apolicy.max_line_length
100
class email.policy.Policy(**kw)

这是所有策略类的抽象基类。它为几个平凡方法提供了默认实现,以及不变性属性的实现、clone() 方法和构造函数语义。

可以将各种关键字参数传递给策略类的构造函数。可以指定的参数是此类上的任何非方法属性,以及具体类上的任何其他非方法属性。构造函数中指定的值将覆盖相应属性的默认值。

此类定义以下属性,因此可以在任何策略类的构造函数中传递以下值

max_line_length

序列化输出中任何行的最大长度,不包括行尾字符。默认值为 78,根据 RFC 5322。值为 0None 表示根本不应进行任何换行。

linesep

用于终止序列化输出中行的字符串。默认值为 \n,因为这是 Python 使用的内部行尾规则,尽管 RFC 需要 \r\n

cte_type

控制可能或必须使用的内容传输编码的类型。可能的值是

7bit

所有数据都必须是“7 位干净”(仅限 ASCII)。这意味着在必要时,数据将使用 quoted-printable 或 base64 编码进行编码。

8bit

数据不受 7 位干净的约束。标头中的数据仍然需要仅限 ASCII,因此将被编码(有关例外,请参见下面的 fold_binary()utf8),但正文部分可以使用 8bit CTE。

cte_type8bit 仅适用于 BytesGenerator,不适用于 Generator,因为字符串不能包含二进制数据。如果 Generator 在指定 cte_type=8bit 的策略下运行,它将表现得好像 cte_type7bit

raise_on_defect

如果 True,遇到的任何缺陷都将作为错误提出。如果 False(默认),缺陷将传递到 register_defect() 方法。

mangle_from_

如果 True,正文中以“From “开头的行将通过在它们前面放置一个 > 来转义。此参数在生成器序列化消息时使用。默认值:False

在版本 3.5 中添加。

message_factory

用于构建新空消息对象的工厂函数。构建消息时,解析器使用它。默认为 None,在这种情况下,将使用 Message

在版本 3.6 中添加。

以下 Policy 方法旨在由使用电子邮件库的代码调用,以创建具有自定义设置的策略实例

clone(**kw)

返回一个新的 Policy 实例,其属性具有与当前实例相同的值,但这些属性由关键字参数赋予新值的情况除外。

其余 Policy 方法由电子邮件包代码调用,并且不打算由使用电子邮件包的应用程序调用。自定义策略必须实现所有这些方法。

handle_defect(obj, defect)

处理在 obj 上发现的缺陷。当电子邮件包调用此方法时,缺陷将始终是 Defect 的子类。

默认实现检查 raise_on_defect 标志。如果为 True,则将 defect 作为异常引发。如果为 False(默认值),则将 objdefect 传递给 register_defect()

register_defect(obj, defect)

obj 上注册 defect。在电子邮件包中,defect 始终是 Defect 的子类。

默认实现调用 objdefects 属性的 append 方法。当电子邮件包调用 handle_defect 时,obj 通常具有一个具有 append 方法的 defects 属性。与电子邮件包一起使用的自定义对象类型(例如,自定义 Message 对象)也应提供此类属性,否则已解析消息中的缺陷将引发意外错误。

header_max_count(name)

返回允许的最大数量,名为 name 的头。

当头被添加到 EmailMessageMessage 对象时调用。如果返回值不是 0None,并且已经存在数量大于或等于返回值的名称为 name 的头,则会引发 ValueError

由于 Message.__setitem__ 的默认行为是将值附加到头列表中,因此很容易在没有意识到这一点的情况下创建重复头。此方法允许对 Message 中可以添加的特定头实例的数量进行限制(通过编程方式)。(解析器不会遵守此限制,它将忠实地生成与正在解析的消息中存在的一样多的头。)

默认实现为所有头名称返回 None

header_source_parse(sourcelines)

电子邮件包使用一组字符串调用此方法,每个字符串以解析的源中找到的行分隔符结尾。第一行包括字段头名称和分隔符。保留源中的所有空格。该方法应返回要存储在 Message 中以表示已解析头的 (name, value) 元组。

如果某个实现希望与现有的电子邮件包策略保持兼容,则name 应为保留大小写的名称(直到“:”分隔符的所有字符),而value 应为展开的值(删除所有行分隔符,但保留空格),并删除前导空格。

sourcelines 可能包含代理转义的二进制数据。

没有默认实现

header_store_parse(name, value)

当应用程序通过编程方式修改 Message(而不是由解析器创建的 Message)时,电子邮件包使用应用程序提供的名称和值调用此方法。该方法应返回要存储在 Message 中以表示头的 (name, value) 元组。

如果某个实现希望与现有的电子邮件包策略保持兼容,则namevalue 应为字符串或字符串子类,它们不会更改传入参数的内容。

没有默认实现

header_fetch_parse(name, value)

当应用程序程序请求该头时,电子邮件包会使用当前存储在 消息 中的名称调用此方法,并且该方法返回的任何内容都将作为要检索的头部的值传递回应用程序。请注意,消息 中可能存储了多个具有相同名称的头;该方法会传递要返回给应用程序的头部的特定名称和值。

可能包含代理转义的二进制数据。该方法返回的值中不应包含代理转义的二进制数据。

没有默认实现

折叠(名称, )

电子邮件包使用给定头的当前存储在 消息 中的名称调用此方法。该方法应返回一个字符串,该字符串通过将名称组合并插入 行分隔符 字符在适当的位置来正确“折叠”该头(根据策略设置)。有关折叠电子邮件头的规则的讨论,请参见 RFC 5322

可能包含代理转义的二进制数据。该方法返回的字符串中不应包含代理转义的二进制数据。

折叠_二进制(名称, )

折叠() 相同,除了返回的值应为字节对象而不是字符串。

可能包含代理转义的二进制数据。这些可以在返回的字节对象中转换回二进制数据。

电子邮件.电子邮件策略(**千瓦)

此具体 策略 提供的行为旨在完全符合当前的电子邮件 RFC。其中包括(但不限于) RFC 5322RFC 2047 和当前的 MIME RFC。

此策略添加了新的标头解析和折叠算法。标头不是简单的字符串,而是 str 子类,其属性取决于字段的类型。解析和折叠算法完全实现了 RFC 2047RFC 5322

message_factory 属性的默认值为 EmailMessage

除了上述适用于所有策略的可设置属性外,此策略还添加了以下附加属性

3.6 版中添加: [1]

utf8

如果 False,则遵循 RFC 5322,通过将非 ASCII 字符编码为“编码字”来支持标头中的非 ASCII 字符。如果 True,则遵循 RFC 6532,并对标头使用 utf-8 编码。以这种方式格式化的邮件可以传递给支持 SMTPUTF8 扩展的 SMTP 服务器(RFC 6531)。

refold_source

如果 Message 对象中标头的值源自 parser(而不是由程序设置),则此属性指示生成器在将邮件转换回序列化形式时是否应该折叠该值。可能的值是

none

所有源值都使用原始折叠

long

任何一行长度大于 max_line_length 的源值都将被折叠

all

所有值都将被折叠。

默认值为 long

header_factory

一个可调用的函数,它接收两个参数,namevalue,其中 name 是一个头字段名称,value 是一个未展开的头字段值,并返回一个表示该头的字符串子类。提供了一个默认的 header_factory(参见 headerregistry),它支持对各种地址和日期 RFC 5322 头字段类型以及主要的 MIME 头字段类型进行自定义解析。未来将添加对其他自定义解析的支持。

content_manager

一个至少具有两个方法的对象:get_content 和 set_content。当调用 get_content()set_content() 方法时,它调用此对象的相应方法,并将其作为第一个参数传递给消息对象,以及作为附加参数传递给它的任何参数或关键字。默认情况下,content_manager 设置为 raw_data_manager

在版本 3.4 中添加。

该类提供了 Policy 抽象方法的以下具体实现

header_max_count(name)

返回使用给定名称表示头的专用类的 max_count 属性的值。

header_source_parse(sourcelines)

名称被解析为直到 ‘:’ 之前的所有内容,并原样返回。值通过去除第一行开头的空白,将所有后续行连接在一起,并去除任何尾随的回车或换行符来确定。

header_store_parse(name, value)

名称将保持不变。如果输入值具有 name 属性,并且它忽略大小写与 name 匹配,则该值将保持不变。否则,将 namevalue 传递给 header_factory,并将结果标头对象作为值返回。在这种情况下,如果输入值包含 CR 或 LF 字符,则会引发 ValueError

header_fetch_parse(name, value)

如果该值具有 name 属性,则将其返回为未修改状态。否则,将 name 和删除任何 CR 或 LF 字符的 value 传递给 header_factory,并将结果标头对象返回。任何代理转义字节都会变成 Unicode 未知字符字形。

fold(name, value)

标头折叠由 refold_source 策略设置控制。当且仅当值没有 name 属性时,才将该值视为“源值”(具有 name 属性意味着它某种类型的标头对象)。如果根据策略需要对源值进行重新折叠,则通过将 name 和删除任何 CR 和 LF 字符的 value 传递给 header_factory,将其转换为标头对象。标头对象的折叠是通过使用当前策略调用其 fold 方法来完成的。

使用 splitlines() 将源值拆分为多行。如果不需要对值进行重新折叠,则使用策略中的 linesep 重新连接这些行并返回。例外情况是包含非 ASCII 二进制数据的行。在这种情况下,无论 refold_source 设置如何,都将重新折叠该值,这会导致使用 unknown-8bit 字符集对二进制数据进行 CTE 编码。

fold_binary(name, value)

如果 fold()cte_type7bit 相同,则返回的值为字节,否则相同。

如果 cte_type8bit,则非 ASCII 二进制数据将转换回字节。无论 refold_header 设置如何,都将不重新折叠包含二进制数据的标头,因为无法知道二进制数据是由单字节字符还是多字节字符组成的。

以下 EmailPolicy 实例为特定的应用程序域提供了合适的默认值。请注意,将来这些实例(尤其是 HTTP 实例)的行为可能会进行调整,以更加符合与各自域相关的 RFC。

email.policy.default

所有默认值均未更改的 EmailPolicy 实例。此策略使用标准 Python \n 换行符,而不是符合 RFC 规范的 \r\n

email.policy.SMTP

适用于序列化符合电子邮件 RFC 的邮件。与 default 相同,但将 linesep 设置为 \r\n,这是符合 RFC 规范的。

email.policy.SMTPUTF8

SMTP 相同,但 utf8True。适用于在标头中不使用编码字将邮件序列化到邮件存储中。仅当发件人或收件人地址包含非 ASCII 字符时,才应将其用于 SMTP 传输(smtplib.SMTP.send_message() 方法会自动处理此问题)。

email.policy.HTTP

适用于使用 HTTP 流量序列化标头。与 SMTP 相似,但 max_line_length 设置为 None(无限制)。

email.policy.strict

便捷实例。与 default 相同,但 raise_on_defect 设置为 True。这允许通过编写将任何策略设为严格

somepolicy + policy.strict

使用所有这些 EmailPolicies,电子邮件包的有效 API 会通过以下方式从 Python 3.2 API 中更改

  • Message 上设置标头会导致解析该标头并创建标头对象。

  • Message 中获取标头值会导致解析该标头并创建和返回标头对象。

  • 任何标头对象或由于策略设置而重新折叠的任何标头都使用完全实现 RFC 折叠算法的算法进行折叠,包括知道需要和允许编码单词的位置。

从应用程序视图来看,这意味着通过 EmailMessage 获得的任何标头都是具有额外属性的标头对象,其字符串值是标头的完全解码的 unicode 值。同样,可以使用 unicode 字符串分配标头新值或创建新标头,并且该策略将负责将 unicode 字符串转换为正确的 RFC 编码形式。

标头对象及其属性在 headerregistry 中进行了描述。

class email.policy.Compat32(**kw)

此具体 Policy 是向后兼容性策略。它复制了 Python 3.2 中电子邮件包的行为。 policy 模块还定义了此类的实例, compat32,用作默认策略。因此,电子邮件包的默认行为是保持与 Python 3.2 的兼容性。

以下属性的值与 Policy 默认值不同

mangle_from_

默认值为 True

该类提供了 Policy 抽象方法的以下具体实现

header_source_parse(sourcelines)

名称被解析为直到 ‘:’ 之前的所有内容,并原样返回。值通过去除第一行开头的空白,将所有后续行连接在一起,并去除任何尾随的回车或换行符来确定。

header_store_parse(name, value)

名称和值返回时未经修改。

header_fetch_parse(name, value)

如果值包含二进制数据,它将使用 Header 对象和 unknown-8bit 字符集转换为 Header 对象。否则它将返回时未经修改。

fold(name, value)

使用 Header 折叠算法折叠标题,该算法保留值中的现有换行符,并将每行结果换行到 max_line_length。非 ASCII 二进制数据使用 unknown-8bit 字符集进行 CTE 编码。

fold_binary(name, value)

使用 Header 折叠算法折叠标题,该算法保留值中的现有换行符,并将每行结果换行到 max_line_length。如果 cte_type7bit,则使用 unknown-8bit 字符集对非 ASCII 二进制数据进行 CTE 编码。否则,将使用原始源标题,保留其现有换行符和可能包含的任何(RFC 无效)二进制数据。

email.policy.compat32

Compat32 的一个实例,提供与 Python 3.2 中电子邮件包行为的向后兼容性。

脚注