email.policy: Policy 對象?

3.3 新版功能.

源代碼: Lib/email/policy.py


email 的主要焦點(diǎn)是按照各種電子郵件和 MIME RFC 的描述來(lái)處理電子郵件消息。 但是電子郵件消息的基本格式(一個(gè)由名稱(chēng)加冒號加值的標頭字段構成的區塊,后面再加一個(gè)空白行和任意的‘消息體’)是在電子郵件領(lǐng)域以外也獲得應用的格式。 這些應用的規則有些與主要電子郵件 RFC 十分接近,有些則很不相同。 即使是操作電子郵件,有時(shí)也可能需要打破嚴格的 RFC 規則,例如生成可與某些并不遵循標準的電子郵件服務(wù)器互聯(lián)的電子郵件,或者是實(shí)現希望應用某些破壞標準的操作方式的擴展。

Policy 對象給予 email 包處理這些不同用例的靈活性。

Policy 對象封裝了一組屬性和方法用來(lái)在使用期間控制 email 包中各個(gè)組件的行為。 Policy 實(shí)例可以被傳給 email 包中的多個(gè)類(lèi)和方法以更改它們的默認行為。 可設置的值及其默認值如下所述。

在 email 包中的所有類(lèi)會(huì )使用一個(gè)默認的策略。 對于所有 parser 類(lèi)及相關(guān)的便捷函數,還有對于 Message 類(lèi)來(lái)說(shuō),它是 Compat32 策略,通過(guò)其對應的預定義實(shí)例 compat32 來(lái)使用。 這個(gè)策略提供了與 Python3.3 版之前的 email 包的完全向下兼容性(在某些情況下,也包括對缺陷的兼容性)。

傳給 EmailMessagepolicy 關(guān)鍵字的默認值是 EmailPolicy 策略,表示為其預定義的實(shí)例 default。

在創(chuàng )建 MessageEmailMessage 對象時(shí),它需要一個(gè)策略。 如果消息是由 parser 創(chuàng )建的,則傳給該解析器的策略將是它所創(chuàng )建的消息所使用的策略。 如果消息是由程序創(chuàng )建的,則該策略可以在創(chuàng )建它的時(shí)候指定。 當消息被傳遞給 generator 時(shí),生成器默認會(huì )使用來(lái)自該消息的策略,但你也可以將指定的策略傳遞給生成器,這將覆蓋存儲在消息對象上的策略。

email.parser 類(lèi)和解析器便捷函數的 policy 關(guān)鍵字的默認值在未來(lái)的 Python 版本中 將會(huì )改變。 因此在調用任何 parser 模塊所描述的類(lèi)和函數時(shí)你應當 總是顯式地指定你想要使用的策略。

本文檔的第一部分介紹了 Policy 的特性,它是一個(gè) abstract base class,定義了所有策略對象包括 compat32 的共有特性。 這些特性包括一些由 email 包內部調用的特定鉤子方法,自定義策略可以重載這些方法以獲得不同行為。 第二部分描述了實(shí)體類(lèi) EmailPolicyCompat32,它們分別實(shí)現了提供標準行為和向下兼容行為與特性的鉤子。

Policy 實(shí)例是不可變的,但它們可以被克隆,接受與類(lèi)構造器一致的關(guān)鍵字參數并返回一個(gè)新的 Policy 實(shí)例,新實(shí)例是原實(shí)例的副本,但具有被改變的指定屬性。

例如,以下代碼可以被用來(lái)從一個(gè) Unix 系統的磁盤(pán)文件中讀取電子郵件消息并將其傳遞給系統的 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 在創(chuàng )建要送入 sendmail's stdin 的二進(jìn)制字串時(shí)使用符合 RFC 的行分隔字符,默認的策略將會(huì )使用 \n 行分隔符。

某些 email 包的方法接受一個(gè) policy 關(guān)鍵字參數,允許為該方法重載策略。 例如,以下代碼使用了來(lái)自之前示例的 msg 對象的 as_bytes() 方法并使用其運行所在平臺的本機行分隔符將消息寫(xiě)入一個(gè)文件:

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

Policy 對象也可使用加法運算符進(jìn)行組合來(lái)產(chǎn)生一個(gè)新策略對象,其設置是被加總對象的非默認值的組合:

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

此運算不滿(mǎn)足交換律;也就是說(shuō)對象的添加順序很重要。 見(jiàn)以下演示:

>>>
>>> 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)?

這是所有策略類(lèi)的 abstract base class。 它提供了一些簡(jiǎn)單方法的默認實(shí)現,以及不可變特征屬性,clone() 方法以及構造器語(yǔ)義的實(shí)現。

可以向策略類(lèi)的構造器傳入各種關(guān)鍵字參數。 可以指定的參數是該類(lèi)的任何非方法特征屬性,以及實(shí)體類(lèi)的任何額外非方法特征屬性。 在構造器中指定的值將覆蓋相應屬性的默認值。

這個(gè)類(lèi)定義了下列特征屬性,因此下列值可以被傳給任何策略類(lèi)的構造器:

max_line_length?

序列化輸出中任何行的最大長(cháng)度,不計入行字符的末尾。 默認值為 78,基于 RFC 5322。 值為 0None 表示完全沒(méi)有行包裝。

linesep?

用來(lái)在序列化輸出中確定行的字符串。 默認值為 \n 因為這是 Python 所使用的內部行結束符規范,但 RFC 的要求是 \r\n。

cte_type?

控制可能要求使用的內容傳輸編碼格式類(lèi)型。 可能的值包括:

7bit

所有數據必須為 "純 7 比特位" (僅 ASCII)。 這意味著(zhù)在必要情況下數據將使用可打印引用形式或 base64 編碼格式進(jìn)行編碼。

8bit

數據不會(huì )被限制為純 7 比特位。 標頭中的數據仍要求僅 ASCII 因此將被編碼(參閱下文的 fold_binary()utf8 了解例外情況),但消息體部分可能使用 8bit CTE。

cte_type 值為 8bit 僅適用于 BytesGenerator 而非 Generator,因為字符串不能包含二進(jìn)制數據。 如果 Generator 運行于指定了 cte_type=8bit 的策略,它的行為將與 cte_type7bit 相同。

raise_on_defect?

如為 True,則遇到的任何缺陷都將引發(fā)錯誤。 如為 False (默認值),則缺陷將被傳遞給 register_defect() 方法。

mangle_from_?

如為 True,則消息體中以 "From " 開(kāi)頭的行會(huì )通過(guò)在其前面放一個(gè) > 來(lái)進(jìn)行轉義。 當消息被生成器執行序列化時(shí)會(huì )使用此形參。 默認值t: False。

3.5 新版功能: mangle_from_ 形參。

message_factory?

用來(lái)構造新的空消息對象的工廠(chǎng)函數。 在構建消息時(shí)由解析器使用。 默認為 None,在此情況下會(huì )使用 Message。

3.6 新版功能.

下列 Policy 方法是由使用 email 庫的代碼來(lái)調用以創(chuàng )建具有自室外設置的策略實(shí)例:

clone(**kw)?

返回一個(gè)新的 Policy 實(shí)例,其屬性與當前實(shí)例具有相同的值,除非是那些由關(guān)鍵字參數給出了新值的屬性。

其余的 Policy 方法是由 email 包代碼來(lái)調用的,而不應當被使用 email 包的應用程序所調用。 自定義的策略必須實(shí)現所有這些方法。

handle_defect(obj, defect)?

處理在 obj 上發(fā)現的 defect。 當 email 包調用此方法時(shí),defect 將總是 Defect 的一個(gè)子類(lèi)。

默認實(shí)現會(huì )檢查 raise_on_defect 旗標。 如果其為 True,則 defect 會(huì )被作為異常來(lái)引發(fā)。 如果其為 False (默認值),則 objdefect 會(huì )被傳遞給 register_defect()。

register_defect(obj, defect)?

obj 上注冊一個(gè) defect。 在 email 包中,defect 將總是 Defect 的一個(gè)子類(lèi)。

默認實(shí)現會(huì )調用 objdefects 屬性的 append 方法。 當 email 包調用 handle_defect 時(shí),obj 通常將具有一個(gè)帶 append 方法的 defects 屬性。 配合 email 包使用的自定義對象類(lèi)型(例如自定義的 Message 對象)也應當提供這樣的屬性,否則在被解析消息中的缺陷將引發(fā)非預期的錯誤。

header_max_count(name)?

返回名為 name 的標頭的最大允許數量。

當添加一個(gè)標頭到 EmailMessageMessage 對象時(shí)被調用。 如果返回值不為 0None,并且已有的名稱(chēng)為 name 的標頭數量大于等于所返回的值,則會(huì )引發(fā) ValueError。

由于 Message.__setitem__ 的默認行為是將值添加到標頭列表,因此很容易不知情地創(chuàng )建重復的標頭。 此方法允許在程序中限制可以被添加到 Message 中的特定標頭的實(shí)例數量。 (解析器不會(huì )考慮此限制,它將忠實(shí)地產(chǎn)生被解析消息中存在的任意數量的標頭。)

默認實(shí)現對于所有標頭名稱(chēng)都返回 None。

header_source_parse(sourcelines)?

email 包調用此方法時(shí)將傳入一個(gè)字符串列表,其中每個(gè)字符串以在被解析源中找到的行分隔符結束。 第一行包括字段標頭名稱(chēng)和分隔符。 源中的所有空白符都會(huì )被保留。 此方法應當返回 (name, value) 元組以保存至 Message 中來(lái)代表被解析的標頭。

如果一個(gè)實(shí)現希望保持與現有 email 包策略的兼容性,則 name 應當為保留大小寫(xiě)形式的名稱(chēng)(所有字符直至 ':' 分隔符),而 value 應當為展開(kāi)后的值(移除所有行分隔符,但空白符保持不變),并移除開(kāi)頭的空白符。

sourcelines 可以包含經(jīng)替代轉義的二進(jìn)制數據。

此方法沒(méi)有默認實(shí)現

header_store_parse(name, value)?

當一個(gè)應用通過(guò)程序代碼修改 Message (而不是由解析器創(chuàng )建 Message) 時(shí),email 包會(huì )調用此方法并附帶應用程序所提供的名稱(chēng)和值。 此方法應當返回 (name, value) 元組以保存至 Message 中用來(lái)表示標頭。

如果一個(gè)實(shí)現希望保持與現有 email 包策略的兼容性,則 namevalue 應當為字符串或字符串的子類(lèi),它們不會(huì )修改在參數中傳入的內容。

此方法沒(méi)有默認實(shí)現

header_fetch_parse(name, value)?

當標頭被應用程序所請求時(shí),email 包會(huì )調用此方法并附帶當前保存在 Message 中的 namevalue,并且無(wú)論此方法返回什么它都會(huì )被回傳給應用程序作為被提取標頭的值。 請注意可能會(huì )有多個(gè)相同名稱(chēng)的標頭被保存在 Message 中;此方法會(huì )將指定標頭的名稱(chēng)和值返回給應用程序。

value 可能包含經(jīng)替代轉義的二進(jìn)制數據。 此方法所返回的值應當沒(méi)有經(jīng)替代轉義的二進(jìn)制數據。

此方法沒(méi)有默認實(shí)現

fold(name, value)?

email 包調用此方法時(shí)會(huì )附帶當前保存在 Message 中的給定標頭的 namevalue。 此方法應當返回一個(gè)代表該標頭的(根據策略設置)通過(guò)處理 namevalue 并在適當位置插入 linesep 字符來(lái)正確地“折疊”的字符串。 請參閱 RFC 5322 了解有關(guān)折疊電子郵件標頭的規則的討論。

value 可能包含經(jīng)替代轉義的二進(jìn)制數據。 此方法所返回的字符串應當沒(méi)有經(jīng)替代轉義的二進(jìn)制數據。

fold_binary(name, value)?

fold() 類(lèi)似,不同之處在于返回的值應當為字節串對象而非字符串。

value 可能包含經(jīng)替代轉義的二進(jìn)制數據。 這些數據可以在被返回的字節串對象中被轉換回二進(jìn)制數據。

class email.policy.EmailPolicy(**kw)?

這個(gè)實(shí)體 Policy 提供了完全遵循當前電子郵件 RFC 的行為。 這包括 (但不限于) RFC 5322, RFC 2047 以及當前的各種 MIME RFC。

此策略添加了新的標頭解析和折疊算法。 標頭不是簡(jiǎn)單的字符串,而是帶有依賴(lài)于字段類(lèi)型的屬性的 str 的子類(lèi)。 這個(gè)解析和折疊算法完整實(shí)現了 RFC 2047RFC 5322。

message_factory 屬性的默認值為 EmailMessage。

除了上面列出的適用于所有策略的可設置屬性,此策略還添加了下列額外屬性:

3.6 新版功能: 1

utf8?

如為 False,則遵循 RFC 5322,通過(guò)編碼為“已編碼字”來(lái)支持標頭中的非 ASCII 字符。 如為 True,則遵循 RFC 6532 并對標頭使用 utf-8 編碼格式。 以此方式格式化的消息可被傳遞給支持 SMTPUTF8 擴展 (RFC 6531) 的 SMTP 服務(wù)器。

refold_source?

如果 Message 對象中標頭的值源自 parser (而非由程序設置),此屬性會(huì )表明當將消息轉換回序列化形式時(shí)是否應當由生成器來(lái)重新折疊該值。 可能的值如下:

none

所有源值使用原始折疊

long

具有任何長(cháng)度超過(guò) max_line_length 的行的源值將被折疊

all

所有值會(huì )被重新折疊。

默認值為 long。

header_factory?

該可調用對象接受兩個(gè)參數,namevalue,其中 name 為標頭字段名而 value 為展開(kāi)后的標頭字段值,并返回一個(gè)表示該標頭的字符串子類(lèi)。 已提供的默認 header_factory (參見(jiàn) headerregistry) 支持對各種地址和日期 RFC 5322 標頭字段類(lèi)型及主要 MIME 標頭字段類(lèi)型的自定義解析。 未來(lái)還將添加對其他自定義解析的支持。

content_manager?

此對象至少有兩個(gè)方法: get_content 和 set_content。 當一個(gè) EmailMessage 對象的 get_content()set_content() 方法被調用時(shí),它會(huì )調用此對象的相應方法,將消息對象作為其第一個(gè)參數,并將傳給它的任何參數或關(guān)鍵字作為附加參數傳入。 默認情況下 content_manager 會(huì )被設為 raw_data_manager。

3.4 新版功能.

這個(gè)類(lèi)提供了下列對 Policy 的抽象方法的具體實(shí)現:

header_max_count(name)?

返回用來(lái)表示具有給定名稱(chēng)的標頭的專(zhuān)用類(lèi)的 max_count 屬性的值。

header_source_parse(sourcelines)?

此名稱(chēng)會(huì )被作為到 ':' 止的所有內容來(lái)解析。 該值是通過(guò)從第一行的剩余部分去除前導空格,再將所有后續行連接到一起,并去除所有末尾回車(chē)符或換行符來(lái)確定的。

header_store_parse(name, value)?

name 將會(huì )被原樣返回。 如果輸入值具有 name 屬性并可在忽略大小寫(xiě)的情況下匹配 name,則 value 也會(huì )被原樣返回。 在其他情況下 namevalue 會(huì )被傳遞給 header_factory,并將結果標頭對象作為值返回。 在此情況下如果輸入值包含 CR 或 LF 字符則會(huì )引發(fā) ValueError。

header_fetch_parse(name, value)?

如果值具有 name 屬性,它會(huì )被原樣返回。 在其他情況下 name 和移除了所有 CR 和 LF 字符的 value 會(huì )被傳遞給 header_factory,并返回結果標頭對象。 任何經(jīng)替代轉義的字節串會(huì )被轉換為 unicode 未知字符字形。

fold(name, value)?

標頭折疊是由 refold_source 策略設置來(lái)控制的。 當且僅當一個(gè)值沒(méi)有 name 屬性(具有 name 屬性就意味著(zhù)它是某種標頭對象)它才會(huì )被當作是“源值”。 如果一個(gè)原值需要按照策略來(lái)重新折疊,則會(huì )通過(guò)將 name 和去除了所有 CR 和 LF 字符的 value 傳遞給 header_factory 來(lái)將其轉換為標頭對象。 標頭對象的折疊是通過(guò)調用其 fold 方法并附帶當前策略來(lái)完成的。

源值會(huì )使用 splitlines() 來(lái)拆分成多行。 如果該值不被重新折疊,則會(huì )使用策略中的 linesep 重新合并這些行并將其返回。 例外的是包含非 ascii 二進(jìn)制數據的行。 在此情況下無(wú)論 refold_source 如何設置該值都會(huì )被重新折疊,這會(huì )導致二進(jìn)制數據使用 unknown-8bit 字符集進(jìn)行 CTE 編碼。

fold_binary(name, value)?

如果 cte_type7bit 則與 fold() 類(lèi)似,不同之處在于返回的值是字節串。

如果 cte_type8bit,則將非 ASCII 二進(jìn)制數據轉換回字節串。 帶有二進(jìn)制數據的標頭不會(huì )被重新折疊,無(wú)論 refold_header 設置如何,因為無(wú)法知曉該二進(jìn)制數據是由單字節字符還是多字節字符組成的。

以下 EmailPolicy 的實(shí)例提供了適用于特定應用領(lǐng)域的默認值。 請注意在未來(lái)這些實(shí)例(特別是 HTTP 實(shí)例)的行為可能會(huì )被調整以便更嚴格地遵循與其領(lǐng)域相關(guān)的 RFC。

email.policy.default?

一個(gè)未改變任何默認值的 EmailPolicy 實(shí)例。 此策略使用標準的 Python \n 行結束符而非遵循 RFC 的 \r\n。

email.policy.SMTP?

適用于按照符合電子郵件 RFC 的方式來(lái)序列化消息。 與 default 類(lèi)似,但 linesep 被設為遵循 RFC 的 \r\n。

email.policy.SMTPUTF8?

SMTP 類(lèi)似但是 utf8True。 適用于在不使用標頭內已編碼字的情況下對消息進(jìn)行序列化。 如果發(fā)送方或接收方地址具有非 ASCII 字符則應當只被用于 SMTP 傳輸 (smtplib.SMTP.send_message() 方法會(huì )自動(dòng)如此處理)。

email.policy.HTTP?

適用于序列化標頭以在 HTTP 通信中使用。 與 SMTP 類(lèi)似但是 max_line_length 被設為 None (無(wú)限制)。

email.policy.strict?

便捷實(shí)例。 與 default 類(lèi)似但是 raise_on_defect 被設為 True。 這樣可以允許通過(guò)以下寫(xiě)法來(lái)嚴格地設置任何策略:

somepolicy + policy.strict

因為所有這些 EmailPolicies,email 包的高效 API 相比 Python 3.2 API 發(fā)生了以下幾方面變化:

  • Message 中設置標頭將使得該標頭被解析并創(chuàng )建一個(gè)標頭對象。

  • Message 提取標頭將使得該標頭被解析并創(chuàng )建和返回一個(gè)標頭對象。

  • 任何標頭對象或任何由于策略設置而被重新折疊的標頭都會(huì )使用一種完全實(shí)現了 RFC 折疊算法的算法來(lái)進(jìn)行折疊,包括知道在休息需要并允許已編碼字。

從應用程序的視角來(lái)看,這意味著(zhù)任何通過(guò) EmailMessage 獲得的標頭都是具有附加屬性的標頭對象,其字符串值都是該標頭的完全解碼后的 unicode 值。 類(lèi)似地,可以使用 unicode 對象為一個(gè)標頭賦予新的值,或創(chuàng )建一個(gè)新的標頭對象,并且該策略將負責把該 unicode 字符串轉換為正確的 RFC 已編碼形式。

標頭對象及其屬性的描述見(jiàn) headerregistry。

class email.policy.Compat32(**kw)?

這個(gè)實(shí)體 Policy 為向下兼容策略。 它復制了 Python 3.2 中 email 包的行為。 policy 模塊還定義了該類(lèi)的一個(gè)實(shí)例 compat32,用來(lái)作為默認策略。 因此 email 包的默認行為會(huì )保持與 Python 3.2 的兼容性。

下列屬性具有與 Policy 默認值不同的值:

mangle_from_?

默認值為 True。

這個(gè)類(lèi)提供了下列對 Policy 的抽象方法的具體實(shí)現:

header_source_parse(sourcelines)?

此名稱(chēng)會(huì )被作為到 ':' 止的所有內容來(lái)解析。 該值是通過(guò)從第一行的剩余部分去除前導空格,再將所有后續行連接到一起,并去除所有末尾回車(chē)符或換行符來(lái)確定的。

header_store_parse(name, value)?

name 和 value 會(huì )被原樣返回。

header_fetch_parse(name, value)?

如果 value 包含二進(jìn)制數據,則會(huì )使用 unknown-8bit 字符集來(lái)將其轉換為 Header 對象。 在其他情況下它會(huì )被原樣返回。

fold(name, value)?

標頭會(huì )使用 Header 折疊算法進(jìn)行折疊,該算法保留 value 中現有的換行,并將每個(gè)結果行的長(cháng)度折疊至 max_line_length。 非 ASCII 二進(jìn)制數據會(huì )使用 unknown-8bit 字符串進(jìn)行 CTE 編碼。

fold_binary(name, value)?

標頭會(huì )使用 Header 折疊算法進(jìn)行折疊,該算法保留 value 中現有的換行,并將每個(gè)結果行的長(cháng)度折疊至 max_line_length。 如果 cte_type7bit,則非 ascii 二進(jìn)制數據會(huì )使用 unknown-8bit 字符集進(jìn)行 CTE 編碼。 在其他情況下則會(huì )使用原始的源標頭,這將保留其現有的換行和所包含的任何(不符合 RFC 的)二進(jìn)制數據。

email.policy.compat32?

Compat32 的實(shí)例,提供與 Python 3.2 中的 email 包行為的向下兼容性。

備注

1

最初在 3.3 中作為 暫定特性 添加。