19.1.4. "email.policy": 策略对象
********************************

3.3 新版功能.

**源代码:** Lib/email/policy.py

======================================================================

"email" 的主要焦点是按照各种电子邮件和 MIME RFC 的描述来处理电子邮件消
息。 但是电子邮件消息的基本格式（一个由名称加冒号加值的标头字段构成的
区块，后面再加一个空白行和任意的‘消息体’）是在电子邮件领域以外也获得应
用的格式。 这些应用的规则有些与主要电子邮件 RFC 十分接近，有些则很不相
同。 即使是操作电子邮件，有时也可能需要打破严格的 RFC 规则，例如生成可
与某些并不遵循标准的电子邮件服务器互联的电子邮件，或者是实现希望应用某
些破坏标准的操作方式的扩展。

策略对象给予 email 包处理这些不同用例的灵活性。

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

在 email 包中的所有类会使用一个默认的策略。 对于所有 "parser" 类及相关
的便捷函数，还有对于 "Message" 类来说，它是 "Compat32" 策略，通过其对
应的预定义实例 "compat32" 来使用。 这个策略提供了与 Python3.3 版之前的
email 包的完全向下兼容性（在某些情况下，也包括对缺陷的兼容性）。

传给 "EmailMessage" 的 *policy* 关键字的默认值是 "EmailPolicy" 策略，
表示为其预定义的实例 "default"。

在创建 "Message" 或 "EmailMessage" 对象时，它需要一个策略。 如果消息是
由 "parser" 创建的，则传给该解析器的策略将是它所创建的消息所使用的策略
。 如果消息是由程序创建的，则该策略可以在创建它的时候指定。 当消息被传
递给 "generator" 时，生成器默认会使用来自该消息的策略，但你也可以将指
定的策略传递给生成器，这将覆盖存储在消息对象上的策略。

"email.parser" 类和解析器便捷函数的 *policy* 关键字的默认值在未来的
Python 版本中 **将会改变**。 因此在调用任何 "parser" 模块所描述的类和
函数时你应当 **总是显式地指定你想要使用的策略**。

本文档的第一部分介绍了 "Policy" 的特性，它是一个 *abstract base class*
，定义了所有策略对象包括 "compat32" 的共有特性。 这些特性包括一些由
email 包内部调用的特定钩子方法，自定义策略可以重载这些方法以获得不同行
为。 第二部分描述了实体类 "EmailPolicy" 和 "Compat32"，它们分别实现了
提供标准行为和向下兼容行为与特性的钩子。

"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" 行分隔符。

某些 email 包的方法接受一个 *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

Policy 对象也可使用附加运算符进行组合来产生一个新策略对象，其设置是被
加总对象的非默认值的组合:

   >>> 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*。 它提供了一些简单方法的默认
   实现，以及不可变特征属性，"clone()" 方法以及构造器语义的实现。

   可以向策略类的构造器传入各种关键字参数。 可以指定的参数是该类的任何
   非方法特征属性，以及实体类的任何额外非方法特征属性。 在构造器中指定
   的值将覆盖相应属性的默认值。

   这个类定义了下列特征属性，因此下列值可以被传给任何策略类的构造器:

   max_line_length

      序列化输出中任何行的最大长度，不计入行字符的末尾。 默认值为 78，
      基于 **RFC 5322**。 值为 "0" 或 "None" 表示完全没有行包装。

   linesep

      用来在序列化输出中确定行的字符串。 默认值为 "\n" 因为这是 Python
      所使用的内部行结束符规范，但 RFC 的要求是 "\r\n"。

   cte_type

      控制可能要求使用的内容传输编码格式类型。 可能的值包括:

      +----------+-----------------------------------------------------------------+
      | "7bit"   | 所有数据必须为 "纯 7 比特位" (仅 ASCII)。 这意味着在必要情况下  |
      |          | 数 据将使用可打印引用形式或 base64 编码格式进行编码。           |
      +----------+-----------------------------------------------------------------+
      | "8bit"   | 数据不会被限制为纯 7 比特位。 标头中的数据仍要求仅 ASCII 因此将 |
      |          | 被编码（参阅下文的 "fold_binary()" 和 "utf8" 了解例外情况），但 |
      |          | 消息体部分可能使用 "8bit" CTE。                                 |
      +----------+-----------------------------------------------------------------+

      "cte_type" 值为 "8bit" 仅适用于 "BytesGenerator" 而非
      "Generator"，因为字符串不能包含二进制数据。 如果 "Generator" 运
      行于指定了 "cte_type=8bit" 的策略，它的行为将与 "cte_type" 为
      "7bit" 相同。

   raise_on_defect

      如为 "True"，则遇到的任何缺陷都将引发错误。 如为 "False" (默认值
      )，则缺陷将被传递给 "register_defect()" 方法。

   mangle_from_

      如为 "True"，则消息体中以 *"From "* 开头的行会通过在其前面放一个
      ">" 来进行转义。 当消息被生成器执行序列化时会使用此形参。 默认值
      t: "False"。

      3.5 新版功能: *mangle_from_* 形参。

   message_factory

      用来构造新的空消息对象的工厂函数。 在构建消息时由解析器使用。 默
      认为 "None"，在此情况下会使用 "Message"。

      3.6 新版功能.

   下列 "Policy" 方法是由使用 email 库的代码来调用以创建具有自室外设置
   的策略实例:

   clone(**kw)

      返回一个新的 "Policy" 实例，其属性与当前实例具有相同的值，除非是
      那些由关键字参数给出了新值的属性。

   其余的 "Policy" 方法是由 email 包代码来调用的，而不应当被使用 email
   包的应用程序所调用。 自定义的策略必须实现所有这些方法。

   handle_defect(obj, defect)

      处理在 *obj* 上发现的 *defect*。 当 email 包调用此方法时，
      *defect* 将总是 "Defect" 的一个子类。

      默认实现会检查 "raise_on_defect" 旗标。 如果其为 "True"，则
      *defect* 会被作为异常来引发。 如果其为 "False" (默认值)，则
      *obj* 和 *defect* 会被传递给 "register_defect()"。

   register_defect(obj, defect)

      在 *obj* 上注册一个 *defect*。 在 email 包中，*defect* 将总是
      "Defect" 的一个子类。

      默认实现会调用 *obj* 的 "defects" 属性的 "append" 方法。 当
      email 包调用 "handle_defect" 时，*obj* 通常将具有一个带 "append"
      方法的 "defects" 属性。 配合 email 包使用的自定义对象类型（例如
      自定义的 "Message" 对象）也应当提供这样的属性，否则在被解析消息
      中的缺陷将引发非预期的错误。

   header_max_count(name)

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

      当添加一个标头到 "EmailMessage" 或 "Message" 对象时被调用。 如果
      返回值不为 "0" 或 "None"，并且已有的名称为 *name* 的标头数量大于
      等于所返回的值，则会引发 "ValueError"。

      由于 "Message.__setitem__" 的默认行为是将值添加到标头列表，因此
      很容易不知情地创建重复的标头。 此方法允许在程序中限制可以被添加
      到 "Message" 中的特定标头的实例数量。 （解析器不会考虑此限制，它
      将忠实地产生被解析消息中存在的任意数量的标头。）

      默认实现对于所有标头名称都返回 "None"。

   header_source_parse(sourcelines)

      email 包调用此方法时将传入一个字符串列表，其中每个字符串以在被解
      析源中找到的行分隔符结束。 第一行包括字段标头名称和分隔符。 源中
      的所有空白符都会被保留。 此方法应当返回 "(name, value)" 元组以保
      存至 "Message" 中来代表被解析的标头。

      如果一个实现希望保持与现有 email 包策略的兼容性，则 *name* 应当
      为保留大小写形式的名称（所有字符直至 '":"' 分隔符），而 *value*
      应当为展开后的值（移除所有行分隔符，但空白符保持不变），并移除开
      头的空白符。

      *sourcelines* 可以包含经替代转义的二进制数据。

      此方法没有默认实现

   header_store_parse(name, value)

      当一个应用通过程序代码修改 "Message" (而不是由解析器创建
      "Message") 时，email 包会调用此方法时并附带应用程序所提供的名称
      和值。 此方法应当返回 "(name, value)" 元组以保存至 "Message" 中
      用来表示标头。

      如果一个实现希望保持与现有 email 包策略的兼容性，则 *name* 和
      *value* 应当为字符串或字符串的子类，它们不会修改在参数中传入的内
      容。

      此方法没有默认实现

   header_fetch_parse(name, value)

      当标头被应用程序所请求时，email 包会调用此方法并附带当前保存在
      "Message" 中的 *name* 和 *value*，并且无论此方法返回什么它都会被
      回传给应用程序作为被提取标头的值。 请注意可能会有多个相同名称的
      标头被保存在 "Message" 中；此方法会将指定标头的名称和值返回给应
      用程序。

      *value* 可能包含经替代转义的二进制数据。 此方法所返回的值应当没
      有经替代转义的二进制数据。

      此方法没有默认实现

   fold(name, value)

      email 包调用此方法时会附带当前保存在 "Message" 中的给定标头的
      *name* 和 *value*。 此方法应当返回一个代表该标头的（根据策略设置
      ）通过处理 *name* 和 *value* 并在适当位置插入 "linesep" 字符来正
      确地“折叠”的字符串。 请参阅 **RFC 5322** 了解有关折叠电子邮件标
      头的规则的讨论。

      *value* 可能包含经替代转义的二进制数据。 此方法所返回的字符串应
      当没有经替代转义的二进制数据。

   fold_binary(name, value)

      与 "fold()" 类似，不同之处在于返回的值应当为字节串对象而非字符串
      。

      *value* 可能包含经替代转义的二进制数据。 这些数据可以在被返回的
      字节串对象中被转换回二进制数据。

class email.policy.EmailPolicy(**kw)

   这个实体 "Policy" 提供了完全遵循当前电子邮件 RFC 的行为。 这包括 (
   但不限于) **RFC 5322**, **RFC 2047** 以及当前的各种 MIME RFC。

   此策略添加了新的标头解析和折叠算法。 标头不是简单的字符串，而是带有
   依赖于字段类型的属性的 "str" 的子类。 这个解析和折叠算法完整实现了
   **RFC 2047** 和 **RFC 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

      该可调用对象接受两个参数，"name" 和 "value"，其中 "name" 为标头
      字段名而 "value" 为展开后的标头字段值，并返回一个表示该标头的字
      符串子类。 已提供的默认 "header_factory" (参见 "headerregistry")
      支持对各种地址和日期 **RFC 5322** 标头字段类型及主要 MIME 标头字
      段类型的自定义解析。 未来还将添加对其他自定义解析的支持。

   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" 属性并可在忽略大小写
      的情况下匹配 *name*，则 value 也会被原样返回。 在其他情况下
      *name* 和 *value* 会被传递给 "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)

      如果 "cte_type" 为 "7bit" 则与 "fold()" 类似，不同之处在于返回的
      值是字节串。

      如果 "cte_type" 为 "8bit"，则将非 ASCII 二进制数据转换回字节串。
      带有二进制数据的标头不会被重新折叠，无论 "refold_header" 设置如
      何，因为无法知晓该二进制数据是由单字节字符还是多字节字符组成的。

以下 "EmailPolicy" 的实例提供了适用于特定应用领域的默认值。 请注意在未
来这些实例（特别是 "HTTP" 实例）的行为可能会被调整以便更严格地遵循与其
领域相关的 RFC。

email.policy.default

   一个未改变任何默认值的 "EmailPolicy" 实例。 此策略使用标准的 Python
   "\n" 行结束符而非遵循 RFC 的 "\r\n"。

email.policy.SMTP

   适用于按照符合电子邮件 RFC 的方式来序列化消息。 与 "default" 类似，
   但 "linesep" 被设为遵循 RFC 的 "\r\n"。

email.policy.SMTPUTF8

   与 "SMTP" 类似但是 "utf8" 为 "True"。 适用于在不使用标头内已编码字
   的情况下对消息进行序列化。 如果发送方或接收方地址具有非 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"，email 包的高效 API 相比 Python 3.2 API
发生了以下几方面变化:

   * 在 "Message" 中设置标头将使得该标头被解析并创建一个标头对象。

   * 从 "Message" 提取标头将使得该标头被解析并创建和返回一个标头对象。

   * 任何标头对象或任何由于策略设置而被重新折叠的标头都会使用一种完全
     实现了 RFC 折叠算法的算法来进行折叠，包括知道在休息需要并允许已编
     码字。

从应用程序的视角来看，这意味着任何通过 "EmailMessage" 获得的标头都是具
有附加属性的标头对象，其字符串值都是该标头的完全解码后的 unicode 值。
类似地，可以使用 unicode 对象为一个标头赋予新的值，或创建一个新的标头
对象，并且该策略将负责把该 unicode 字符串转换为正确的 RFC 已编码形式。

标头对象及其属性的描述见 "headerregistry"。

class email.policy.Compat32(**kw)

   这个实体 "Policy" 为向下兼容策略。 它复制了 Python 3.2 中 email 包
   的行为。 "policy" 模块还定义了该类的一个实例 "compat32"，用来作为默
   认策略。 因此 email 包的默认行为会保持与 Python 3.2 的兼容性。

   下列属性具有与 "Policy" 默认值不同的值:

   mangle_from_

      默认值为 "True"。

   这个类提供了下列对 "Policy" 的抽象方法的具体实现:

   header_source_parse(sourcelines)

      此名称会被作为到 '":"' 止的所有内容来解析。 该值是通过从第一行的
      剩余部分去除前导空格，再将所有后续行连接到一起，并去除所有末尾回
      车符或换行符来确定的。

   header_store_parse(name, value)

      name 和 value 会被原样返回。

   header_fetch_parse(name, value)

      如果 value 包含二进制数据，则会使用 "unknown-8bit" 字符集来将其
      转换为 "Header" 对象。 在其他情况下它会被原样返回。

   fold(name, value)

      标头会使用 "Header" 折叠算法进行折叠，该算法保留 value 中现有的
      换行，并将结果行长度折叠至 "max_line_length"。 非 ASCII 二进制数
      据会使用 "unknown-8bit" 字符串进行 CTE 编码。

   fold_binary(name, value)

      标头会使用 "Header" 折叠算法进行折叠，该算法保留 value 中现有的
      换行，并将每个结果行的长度折叠至 "max_line_length"。 如果
      "cte_type" 为 "7bit"，则非 ascii 二进制数据会使用 "unknown-8bit"
      字符集进行 CTE 编码。 在其他情况下则会使用原始的源标头，这将保留
      其现有的换行和所包含的任何（不符合 RFC 的）二进制数据。

email.policy.compat32

   "Compat32" 的实例，提供与 Python 3.2 中的 email 包行为的向下兼容性
   。

-[ 备注 ]-

[1] 最初在 3.3 中作为 *暂定特性* 添加。
