email.policy: Policy 對象?

3.3 新版功能.

源代碼: Lib/email/policy.py


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

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

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

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

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

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

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

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

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

例如,以下代碼可以被用來從一個 Unix 系統(tǒng)的磁盤文件中讀取電子郵件消息并將其傳遞給系統(tǒng)的 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 的二進制字串時使用符合 RFC 的行分隔字符,默認的策略將會使用 \n 行分隔符。

某些 email 包的方法接受一個 policy 關(guān)鍵字參數(shù),允許為該方法重載策略。 例如,以下代碼使用了來自之前示例的 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 對象也可使用加法運算符進行組合來產(chǎn)生一個新策略對象,其設(shè)置是被加總對象的非默認值的組合:

>>>
>>> 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。 它提供了一些簡單方法的默認實現(xiàn),以及不可變特征屬性,clone() 方法以及構(gòu)造器語義的實現(xiàn)。

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

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

max_line_length?

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

linesep?

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

cte_type?

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

7bit

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

8bit

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

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

raise_on_defect?

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

mangle_from_?

如為 True,則消息體中以 "From " 開頭的行會通過在其前面放一個 > 來進行轉(zhuǎn)義。 當(dāng)消息被生成器執(zhí)行序列化時會使用此形參。 默認值t: False。

3.5 新版功能: mangle_from_ 形參。

message_factory?

用來構(gòu)造新的空消息對象的工廠函數(shù)。 在構(gòu)建消息時由解析器使用。 默認為 None,在此情況下會使用 Message。

3.6 新版功能.

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

clone(**kw)?

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

其余的 Policy 方法是由 email 包代碼來調(diào)用的,而不應(yīng)當(dāng)被使用 email 包的應(yīng)用程序所調(diào)用。 自定義的策略必須實現(xiàn)所有這些方法。

handle_defect(obj, defect)?

處理在 obj 上發(fā)現(xiàn)的 defect。 當(dāng) email 包調(diào)用此方法時,defect 將總是 Defect 的一個子類。

默認實現(xiàn)會檢查 raise_on_defect 旗標(biāo)。 如果其為 True,則 defect 會被作為異常來引發(fā)。 如果其為 False (默認值),則 objdefect 會被傳遞給 register_defect()

register_defect(obj, defect)?

obj 上注冊一個 defect。 在 email 包中,defect 將總是 Defect 的一個子類。

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

header_max_count(name)?

返回名為 name 的標(biāo)頭的最大允許數(shù)量。

當(dāng)添加一個標(biāo)頭到 EmailMessageMessage 對象時被調(diào)用。 如果返回值不為 0None,并且已有的名稱為 name 的標(biāo)頭數(shù)量大于等于所返回的值,則會引發(fā) ValueError。

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

默認實現(xiàn)對于所有標(biāo)頭名稱都返回 None。

header_source_parse(sourcelines)?

email 包調(diào)用此方法時將傳入一個字符串列表,其中每個字符串以在被解析源中找到的行分隔符結(jié)束。 第一行包括字段標(biāo)頭名稱和分隔符。 源中的所有空白符都會被保留。 此方法應(yīng)當(dāng)返回 (name, value) 元組以保存至 Message 中來代表被解析的標(biāo)頭。

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

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

此方法沒有默認實現(xiàn)

header_store_parse(name, value)?

當(dāng)一個應(yīng)用通過程序代碼修改 Message (而不是由解析器創(chuàng)建 Message) 時,email 包會調(diào)用此方法并附帶應(yīng)用程序所提供的名稱和值。 此方法應(yīng)當(dāng)返回 (name, value) 元組以保存至 Message 中用來表示標(biāo)頭。

如果一個實現(xiàn)希望保持與現(xiàn)有 email 包策略的兼容性,則 namevalue 應(yīng)當(dāng)為字符串或字符串的子類,它們不會修改在參數(shù)中傳入的內(nèi)容。

此方法沒有默認實現(xiàn)

header_fetch_parse(name, value)?

當(dāng)標(biāo)頭被應(yīng)用程序所請求時,email 包會調(diào)用此方法并附帶當(dāng)前保存在 Message 中的 namevalue,并且無論此方法返回什么它都會被回傳給應(yīng)用程序作為被提取標(biāo)頭的值。 請注意可能會有多個相同名稱的標(biāo)頭被保存在 Message 中;此方法會將指定標(biāo)頭的名稱和值返回給應(yīng)用程序。

value 可能包含經(jīng)替代轉(zhuǎn)義的二進制數(shù)據(jù)。 此方法所返回的值應(yīng)當(dāng)沒有經(jīng)替代轉(zhuǎn)義的二進制數(shù)據(jù)。

此方法沒有默認實現(xiàn)

fold(name, value)?

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

value 可能包含經(jīng)替代轉(zhuǎn)義的二進制數(shù)據(jù)。 此方法所返回的字符串應(yīng)當(dāng)沒有經(jīng)替代轉(zhuǎn)義的二進制數(shù)據(jù)。

fold_binary(name, value)?

fold() 類似,不同之處在于返回的值應(yīng)當(dāng)為字節(jié)串對象而非字符串。

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

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

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

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

message_factory 屬性的默認值為 EmailMessage

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

3.6 新版功能: 1

utf8?

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

refold_source?

如果 Message 對象中標(biāo)頭的值源自 parser (而非由程序設(shè)置),此屬性會表明當(dāng)將消息轉(zhuǎn)換回序列化形式時是否應(yīng)當(dāng)由生成器來重新折疊該值。 可能的值如下:

none

所有源值使用原始折疊

long

具有任何長度超過 max_line_length 的行的源值將被折疊

all

所有值會被重新折疊。

默認值為 long

header_factory?

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

content_manager?

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

3.4 新版功能.

這個類提供了下列對 Policy 的抽象方法的具體實現(xiàn):

header_max_count(name)?

返回用來表示具有給定名稱的標(biāo)頭的專用類的 max_count 屬性的值。

header_source_parse(sourcelines)?

此名稱會被作為到 ':' 止的所有內(nèi)容來解析。 該值是通過從第一行的剩余部分去除前導(dǎo)空格,再將所有后續(xù)行連接到一起,并去除所有末尾回車符或換行符來確定的。

header_store_parse(name, value)?

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

header_fetch_parse(name, value)?

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

fold(name, value)?

標(biāo)頭折疊是由 refold_source 策略設(shè)置來控制的。 當(dāng)且僅當(dāng)一個值沒有 name 屬性(具有 name 屬性就意味著它是某種標(biāo)頭對象)它才會被當(dāng)作是“源值”。 如果一個原值需要按照策略來重新折疊,則會通過將 name 和去除了所有 CR 和 LF 字符的 value 傳遞給 header_factory 來將其轉(zhuǎn)換為標(biāo)頭對象。 標(biāo)頭對象的折疊是通過調(diào)用其 fold 方法并附帶當(dāng)前策略來完成的。

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

fold_binary(name, value)?

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

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

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

email.policy.default?

一個未改變?nèi)魏文J值的 EmailPolicy 實例。 此策略使用標(biāo)準(zhǔn)的 Python \n 行結(jié)束符而非遵循 RFC 的 \r\n。

email.policy.SMTP?

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

email.policy.SMTPUTF8?

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

email.policy.HTTP?

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

email.policy.strict?

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

somepolicy + policy.strict

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

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

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

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

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

標(biāo)頭對象及其屬性的描述見 headerregistry。

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

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

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

mangle_from_?

默認值為 True。

這個類提供了下列對 Policy 的抽象方法的具體實現(xiàn):

header_source_parse(sourcelines)?

此名稱會被作為到 ':' 止的所有內(nèi)容來解析。 該值是通過從第一行的剩余部分去除前導(dǎo)空格,再將所有后續(xù)行連接到一起,并去除所有末尾回車符或換行符來確定的。

header_store_parse(name, value)?

name 和 value 會被原樣返回。

header_fetch_parse(name, value)?

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

fold(name, value)?

標(biāo)頭會使用 Header 折疊算法進行折疊,該算法保留 value 中現(xiàn)有的換行,并將每個結(jié)果行的長度折疊至 max_line_length。 非 ASCII 二進制數(shù)據(jù)會使用 unknown-8bit 字符串進行 CTE 編碼。

fold_binary(name, value)?

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

email.policy.compat32?

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

備注

1

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