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 包的完全向下兼容性(在某些情況下,也包括對缺陷的兼容性)。
傳給 EmailMessage
的 policy 關(guān)鍵字的默認值是 EmailPolicy
策略,表示為其預定義的實(shí)例 default
。
在創(chuàng )建 Message
或 EmailMessage
對象時(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) EmailPolicy
和 Compat32
,它們分別實(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)的構造器:
- 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_type
為7bit
相同。
- 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í)例:其余的
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
(默認值),則 obj 和 defect 會(huì )被傳遞給register_defect()
。
- register_defect(obj, defect)?
在 obj 上注冊一個(gè) defect。 在 email 包中,defect 將總是
Defect
的一個(gè)子類(lèi)。默認實(shí)現會(huì )調用 obj 的
defects
屬性的append
方法。 當 email 包調用handle_defect
時(shí),obj 通常將具有一個(gè)帶append
方法的defects
屬性。 配合 email 包使用的自定義對象類(lèi)型(例如自定義的Message
對象)也應當提供這樣的屬性,否則在被解析消息中的缺陷將引發(fā)非預期的錯誤。
- header_max_count(name)?
返回名為 name 的標頭的最大允許數量。
當添加一個(gè)標頭到
EmailMessage
或Message
對象時(shí)被調用。 如果返回值不為0
或None
,并且已有的名稱(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 包策略的兼容性,則 name 和 value 應當為字符串或字符串的子類(lèi),它們不會(huì )修改在參數中傳入的內容。
此方法沒(méi)有默認實(shí)現
- header_fetch_parse(name, value)?
當標頭被應用程序所請求時(shí),email 包會(huì )調用此方法并附帶當前保存在
Message
中的 name 和 value,并且無(wú)論此方法返回什么它都會(huì )被回傳給應用程序作為被提取標頭的值。 請注意可能會(huì )有多個(gè)相同名稱(chēng)的標頭被保存在Message
中;此方法會(huì )將指定標頭的名稱(chēng)和值返回給應用程序。value 可能包含經(jīng)替代轉義的二進(jìn)制數據。 此方法所返回的值應當沒(méi)有經(jīng)替代轉義的二進(jìn)制數據。
此方法沒(méi)有默認實(shí)現
- 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 2047 和 RFC 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è)參數,
name
和value
,其中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_source_parse(sourcelines)?
此名稱(chēng)會(huì )被作為到 '
:
' 止的所有內容來(lái)解析。 該值是通過(guò)從第一行的剩余部分去除前導空格,再將所有后續行連接到一起,并去除所有末尾回車(chē)符或換行符來(lái)確定的。
- header_store_parse(name, value)?
name 將會(huì )被原樣返回。 如果輸入值具有
name
屬性并可在忽略大小寫(xiě)的情況下匹配 name,則 value 也會(huì )被原樣返回。 在其他情況下 name 和 value 會(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 編碼。
以下 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)似但是utf8
為True
。 適用于在不使用標頭內已編碼字的情況下對消息進(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ā)生了以下幾方面變化:
從應用程序的視角來(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ì )被原樣返回。
備注