Skip to main content

19.1.4. 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 时,生成器默认使用消息中的策略,但是您也可以向生成器传递特定的策略,该策略将覆盖存储在消息对象上的策略。

email.parser 类的 policy 关键字的默认值以及Python未来版本中的解析器方便函数 将会改变。因此,在调用 parser 模块中描述的任何类和函数时,您应该使用 总是明确指定要使用的策略

本文档的第一部分涵盖了 Policy 的功能,abstract base class 定义了所有策略对象(包括 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 行分隔符。

一些电子邮件包方法接受 policy 关键字参数,允许为该方法覆盖策略。例如,以下代码使用上一个示例中的 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)

这是所有策略类的 abstract base class。它提供了几个平凡方法的默认实现,以及immutability属性,clone() 方法和构造方法语义的实现。

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

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

max_line_length

序列化输出中任何行的最大长度,不计算行结束字符。默认值为78,每个 RFC 5322。值为 0None 表示根本不应进行换行。

linesep

用于终止序列化输出中的行的字符串。默认值是 \n,因为这是Python使用的内部结束规则,虽然 \r\n 是RFC要求的。

cte_type

控制可能需要或需要使用的内容传输编码的类型。可能的值为:

7bit

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

8bit

数据不限于7位清理。头部中的数据仍然需要为仅ASCII,因此将被编码(例外见下面的 fold_binary()utf8),但身体部分可以使用 8bit CTE。

8bitcte_type 值仅适用于 BytesGenerator,而不适用于 Generator,因为字符串不能包含二进制数据。如果 Generator 在指定 cte_type=8bit 的策略下操作,则其将表现为 cte_type7bit

raise_on_defect

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

mangle_from_

如果 True,在身体中以 “从” 开头的行通过在它们前面放置 > 而被转义。当消息由生成器序列化时使用此参数。默认值:False

3.5 新版功能: mangle_from_ 参数。

message_factory

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

3.6 新版功能.

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

clone(**kw)

返回一个新的 Policy 实例,其属性具有与当前实例相同的值,除非这些属性通过关键字参数被赋予新值。

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

handle_defect(obj, defect)

处理在 obj 上发现的 defect。当电子邮件包调用此方法时,defect 将始终是 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)

当应用程序请求该标题时,电子邮件包使用当前存储在 Message 中的 namevalue 来调用该方法,并且该方法返回的是作为被检索的标题的值被传递回应用的什么。注意,在 Message 中可以存储具有相同名称的多于一个报头;该方法将传递要返回给应用程序的头的特定名称和值。

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

没有默认实现

fold(name, value)

电子邮件包使用当前存储在 Message 中的 namevalue 为给定的标题调用此方法。该方法应通过将 namevalue 组合并在适当的位置插入 linesep 字符来正确返回表示标题“折叠”的字符串(根据策略设置)。有关折叠电子邮件标头的规则的讨论,请参阅 RFC 5322

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

fold_binary(name, value)

fold() 相同,除了返回的值应该是一个字节对象而不是一个字符串。

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

class email.policy.EmailPolicy(**kw)

这个具体的 Policy 提供了旨在完全符合当前电子邮件RFC的行为。这些包括(但不限于) RFC 5322RFC 2047 和当前的MIME RFC。

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

message_factory 属性的默认值为 EmailMessage

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

3.6 新版功能: [1]

utf8

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

refold_source

如果 Message 对象中的头的值来源于 parser (而不是由程序设置),则该属性指示当将消息转换回序列化形式时,生成器是否应重新折叠该值。可能的值为:

none

所有源值使用原始折叠

long

具有任何长于 max_line_length 的行的源值将被重新折叠

all

所有值都重新折叠。

默认值为 long

header_factory

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

content_manager

具有至少两个方法的对象:get_content和set_content。当 EmailMessage 对象的 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 属性意味着它是某种类型的头对象)时,该值被认为是“源值”。如果源值需要根据策略重新折叠,则通过将具有去除的任何CR和LF字符的 namevalue 传递给 header_factory,将其转换为头部对象。头对象的折叠通过使用当前策略调用其 fold 方法来完成。

源值使用 splitlines() 分割成行。如果值不重新折叠,则使用 linesep 从策略重新加入线并返回。异常是包含非ascii二进制数据的行。在这种情况下,无论 refold_source 设置如何,都将重新折叠值,这会导致二进制数据使用 unknown-8bit 字符集进行CTE编码。

fold_binary(name, value)

如果 cte_type7bit,与 fold() 相同,除了返回的值是字节。

如果 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字符(smtplib.SMTP.send_message() 方法自动处理此字符),则应仅用于SMTP传输。

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)

如果值包含二进制数据,则使用 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中的电子邮件包的行为的向后兼容性。

脚注

[1]

最初添加在3.3作为 临时特征