email.policy
: Policy 對象?
3.3 新版功能.
源代碼: Lib/email/policy.py
email
的主要焦點是按照各種電子郵件和 MIME RFC 的描述來處理電子郵件消息。 但是電子郵件消息的基本格式(一個由名稱加冒號加值的標頭字段構(gòu)成的區(qū)塊,后面再加一個空白行和任意的‘消息體’)是在電子郵件領(lǐng)域以外也獲得應(yīng)用的格式。 這些應(yīng)用的規(guī)則有些與主要電子郵件 RFC 十分接近,有些則很不相同。 即使是操作電子郵件,有時也可能需要打破嚴格的 RFC 規(guī)則,例如生成可與某些并不遵循標準的電子郵件服務(wù)器互聯(lián)的電子郵件,或者是實現(xiàn)希望應(yīng)用某些破壞標準的操作方式的擴展。
Policy 對象給予 email 包處理這些不同用例的靈活性。
Policy
對象封裝了一組屬性和方法用來在使用期間控制 email 包中各個組件的行為。 Policy
實例可以被傳給 email 包中的多個類和方法以更改它們的默認行為。 可設(shè)置的值及其默認值如下所述。
在 email 包中的所有類會使用一個默認的策略。 對于所有 parser
類及相關(guān)的便捷函數(shù),還有對于 Message
類來說,它是 Compat32
策略,通過其對應(yīng)的預(yù)定義實例 compat32
來使用。 這個策略提供了與 Python3.3 版之前的 email 包的完全向下兼容性(在某些情況下,也包括對缺陷的兼容性)。
傳給 EmailMessage
的 policy 關(guān)鍵字的默認值是 EmailPolicy
策略,表示為其預(yù)定義的實例 default
。
在創(chuàng)建 Message
或 EmailMessage
對象時,它需要一個策略。 如果消息是由 parser
創(chuàng)建的,則傳給該解析器的策略將是它所創(chuàng)建的消息所使用的策略。 如果消息是由程序創(chuàng)建的,則該策略可以在創(chuàng)建它的時候指定。 當消息被傳遞給 generator
時,生成器默認會使用來自該消息的策略,但你也可以將指定的策略傳遞給生成器,這將覆蓋存儲在消息對象上的策略。
email.parser
類和解析器便捷函數(shù)的 policy 關(guān)鍵字的默認值在未來的 Python 版本中 將會改變。 因此在調(diào)用任何 parser
模塊所描述的類和函數(shù)時你應(yīng)當 總是顯式地指定你想要使用的策略。
本文檔的第一部分介紹了 Policy
的特性,它是一個 abstract base class,定義了所有策略對象包括 compat32
的共有特性。 這些特性包括一些由 email 包內(nèi)部調(diào)用的特定鉤子方法,自定義策略可以重載這些方法以獲得不同行為。 第二部分描述了實體類 EmailPolicy
和 Compat32
,它們分別實現(xià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)造器:
- 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 比特位。 標頭中的數(shù)據(jù)仍要求僅 ASCII 因此將被編碼(參閱下文的
fold_binary()
和utf8
了解例外情況),但消息體部分可能使用8bit
CTE。cte_type
值為8bit
僅適用于BytesGenerator
而非Generator
,因為字符串不能包含二進制數(shù)據(jù)。 如果Generator
運行于指定了cte_type=8bit
的策略,它的行為將與cte_type
為7bit
相同。
- raise_on_defect?
如為
True
,則遇到的任何缺陷都將引發(fā)錯誤。 如為False
(默認值),則缺陷將被傳遞給register_defect()
方法。
- mangle_from_?
如為
True
,則消息體中以 "From " 開頭的行會通過在其前面放一個>
來進行轉(zhuǎn)義。 當消息被生成器執(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è)置的策略實例:其余的
Policy
方法是由 email 包代碼來調(diào)用的,而不應(yīng)當被使用 email 包的應(yīng)用程序所調(diào)用。 自定義的策略必須實現(xiàn)所有這些方法。- handle_defect(obj, defect)?
處理在 obj 上發(fā)現(xiàn)的 defect。 當 email 包調(diào)用此方法時,defect 將總是
Defect
的一個子類。默認實現(xiàn)會檢查
raise_on_defect
旗標。 如果其為True
,則 defect 會被作為異常來引發(fā)。 如果其為False
(默認值),則 obj 和 defect 會被傳遞給register_defect()
。
- register_defect(obj, defect)?
在 obj 上注冊一個 defect。 在 email 包中,defect 將總是
Defect
的一個子類。默認實現(xiàn)會調(diào)用 obj 的
defects
屬性的append
方法。 當 email 包調(diào)用handle_defect
時,obj 通常將具有一個帶append
方法的defects
屬性。 配合 email 包使用的自定義對象類型(例如自定義的Message
對象)也應(yīng)當提供這樣的屬性,否則在被解析消息中的缺陷將引發(fā)非預(yù)期的錯誤。
- header_max_count(name)?
返回名為 name 的標頭的最大允許數(shù)量。
當添加一個標頭到
EmailMessage
或Message
對象時被調(diào)用。 如果返回值不為0
或None
,并且已有的名稱為 name 的標頭數(shù)量大于等于所返回的值,則會引發(fā)ValueError
。由于
Message.__setitem__
的默認行為是將值添加到標頭列表,因此很容易不知情地創(chuàng)建重復(fù)的標頭。 此方法允許在程序中限制可以被添加到Message
中的特定標頭的實例數(shù)量。 (解析器不會考慮此限制,它將忠實地產(chǎn)生被解析消息中存在的任意數(shù)量的標頭。)默認實現(xiàn)對于所有標頭名稱都返回
None
。
- header_source_parse(sourcelines)?
email 包調(diào)用此方法時將傳入一個字符串列表,其中每個字符串以在被解析源中找到的行分隔符結(jié)束。 第一行包括字段標頭名稱和分隔符。 源中的所有空白符都會被保留。 此方法應(yīng)當返回
(name, value)
元組以保存至Message
中來代表被解析的標頭。如果一個實現(xiàn)希望保持與現(xiàn)有 email 包策略的兼容性,則 name 應(yīng)當為保留大小寫形式的名稱(所有字符直至 '
:
' 分隔符),而 value 應(yīng)當為展開后的值(移除所有行分隔符,但空白符保持不變),并移除開頭的空白符。sourcelines 可以包含經(jīng)替代轉(zhuǎn)義的二進制數(shù)據(jù)。
此方法沒有默認實現(xiàn)
- header_store_parse(name, value)?
當一個應(yīng)用通過程序代碼修改
Message
(而不是由解析器創(chuàng)建Message
) 時,email 包會調(diào)用此方法并附帶應(yīng)用程序所提供的名稱和值。 此方法應(yīng)當返回(name, value)
元組以保存至Message
中用來表示標頭。如果一個實現(xiàn)希望保持與現(xiàn)有 email 包策略的兼容性,則 name 和 value 應(yīng)當為字符串或字符串的子類,它們不會修改在參數(shù)中傳入的內(nèi)容。
此方法沒有默認實現(xiàn)
- header_fetch_parse(name, value)?
當標頭被應(yīng)用程序所請求時,email 包會調(diào)用此方法并附帶當前保存在
Message
中的 name 和 value,并且無論此方法返回什么它都會被回傳給應(yīng)用程序作為被提取標頭的值。 請注意可能會有多個相同名稱的標頭被保存在Message
中;此方法會將指定標頭的名稱和值返回給應(yīng)用程序。value 可能包含經(jīng)替代轉(zhuǎn)義的二進制數(shù)據(jù)。 此方法所返回的值應(yīng)當沒有經(jīng)替代轉(zhuǎn)義的二進制數(shù)據(jù)。
此方法沒有默認實現(xiàn)
- fold(name, value)?
email 包調(diào)用此方法時會附帶當前保存在
Message
中的給定標頭的 name 和 value。 此方法應(yīng)當返回一個代表該標頭的(根據(jù)策略設(shè)置)通過處理 name 和 value 并在適當位置插入linesep
字符來正確地“折疊”的字符串。 請參閱 RFC 5322 了解有關(guān)折疊電子郵件標頭的規(guī)則的討論。value 可能包含經(jīng)替代轉(zhuǎn)義的二進制數(shù)據(jù)。 此方法所返回的字符串應(yīng)當沒有經(jīng)替代轉(zhuǎn)義的二進制數(shù)據(jù)。
- class email.policy.EmailPolicy(**kw)?
這個實體
Policy
提供了完全遵循當前電子郵件 RFC 的行為。 這包括 (但不限于) RFC 5322, RFC 2047 以及當前的各種 MIME RFC。此策略添加了新的標頭解析和折疊算法。 標頭不是簡單的字符串,而是帶有依賴于字段類型的屬性的
str
的子類。 這個解析和折疊算法完整實現(xiàn)了 RFC 2047 和 RFC 5322。message_factory
屬性的默認值為EmailMessage
。除了上面列出的適用于所有策略的可設(shè)置屬性,此策略還添加了下列額外屬性:
3.6 新版功能: 1
- utf8?
如為
False
,則遵循 RFC 5322,通過編碼為“已編碼字”來支持標頭中的非 ASCII 字符。 如為True
,則遵循 RFC 6532 并對標頭使用utf-8
編碼格式。 以此方式格式化的消息可被傳遞給支持SMTPUTF8
擴展 (RFC 6531) 的 SMTP 服務(wù)器。
- refold_source?
如果
Message
對象中標頭的值源自parser
(而非由程序設(shè)置),此屬性會表明當將消息轉(zhuǎn)換回序列化形式時是否應(yīng)當由生成器來重新折疊該值。 可能的值如下:none
所有源值使用原始折疊
long
具有任何長度超過
max_line_length
的行的源值將被折疊all
所有值會被重新折疊。
默認值為
long
。
- header_factory?
該可調(diào)用對象接受兩個參數(shù),
name
和value
,其中name
為標頭字段名而value
為展開后的標頭字段值,并返回一個表示該標頭的字符串子類。 已提供的默認header_factory
(參見headerregistry
) 支持對各種地址和日期 RFC 5322 標頭字段類型及主要 MIME 標頭字段類型的自定義解析。 未來還將添加對其他自定義解析的支持。
- content_manager?
此對象至少有兩個方法: get_content 和 set_content。 當一個
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_source_parse(sourcelines)?
此名稱會被作為到 '
:
' 止的所有內(nèi)容來解析。 該值是通過從第一行的剩余部分去除前導空格,再將所有后續(xù)行連接到一起,并去除所有末尾回車符或換行符來確定的。
- header_store_parse(name, value)?
name 將會被原樣返回。 如果輸入值具有
name
屬性并可在忽略大小寫的情況下匹配 name,則 value 也會被原樣返回。 在其他情況下 name 和 value 會被傳遞給header_factory
,并將結(jié)果標頭對象作為值返回。 在此情況下如果輸入值包含 CR 或 LF 字符則會引發(fā)ValueError
。
- header_fetch_parse(name, value)?
如果值具有
name
屬性,它會被原樣返回。 在其他情況下 name 和移除了所有 CR 和 LF 字符的 value 會被傳遞給header_factory
,并返回結(jié)果標頭對象。 任何經(jīng)替代轉(zhuǎn)義的字節(jié)串會被轉(zhuǎn)換為 unicode 未知字符字形。
- fold(name, value)?
標頭折疊是由
refold_source
策略設(shè)置來控制的。 當且僅當一個值沒有name
屬性(具有name
屬性就意味著它是某種標頭對象)它才會被當作是“源值”。 如果一個原值需要按照策略來重新折疊,則會通過將 name 和去除了所有 CR 和 LF 字符的 value 傳遞給header_factory
來將其轉(zhuǎn)換為標頭對象。 標頭對象的折疊是通過調(diào)用其fold
方法并附帶當前策略來完成的。源值會使用
splitlines()
來拆分成多行。 如果該值不被重新折疊,則會使用策略中的linesep
重新合并這些行并將其返回。 例外的是包含非 ascii 二進制數(shù)據(jù)的行。 在此情況下無論refold_source
如何設(shè)置該值都會被重新折疊,這會導致二進制數(shù)據(jù)使用unknown-8bit
字符集進行 CTE 編碼。
以下 EmailPolicy
的實例提供了適用于特定應(yīng)用領(lǐng)域的默認值。 請注意在未來這些實例(特別是 HTTP
實例)的行為可能會被調(diào)整以便更嚴格地遵循與其領(lǐng)域相關(guān)的 RFC。
- email.policy.default?
一個未改變?nèi)魏文J值的
EmailPolicy
實例。 此策略使用標準的 Python\n
行結(jié)束符而非遵循 RFC 的\r\n
。
- email.policy.SMTP?
適用于按照符合電子郵件 RFC 的方式來序列化消息。 與
default
類似,但linesep
被設(shè)為遵循 RFC 的\r\n
。
- email.policy.SMTPUTF8?
與
SMTP
類似但是utf8
為True
。 適用于在不使用標頭內(nèi)已編碼字的情況下對消息進行序列化。 如果發(fā)送方或接收方地址具有非 ASCII 字符則應(yīng)當只被用于 SMTP 傳輸 (smtplib.SMTP.send_message()
方法會自動如此處理)。
- email.policy.HTTP?
適用于序列化標頭以在 HTTP 通信中使用。 與
SMTP
類似但是max_line_length
被設(shè)為None
(無限制)。
- email.policy.strict?
便捷實例。 與
default
類似但是raise_on_defect
被設(shè)為True
。 這樣可以允許通過以下寫法來嚴格地設(shè)置任何策略:somepolicy + policy.strict
因為所有這些 EmailPolicies
,email 包的高效 API 相比 Python 3.2 API 發(fā)生了以下幾方面變化:
從應(yīng)用程序的視角來看,這意味著任何通過 EmailMessage
獲得的標頭都是具有附加屬性的標頭對象,其字符串值都是該標頭的完全解碼后的 unicode 值。 類似地,可以使用 unicode 對象為一個標頭賦予新的值,或創(chuàng)建一個新的標頭對象,并且該策略將負責把該 unicode 字符串轉(zhuǎn)換為正確的 RFC 已編碼形式。
標頭對象及其屬性的描述見 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)容來解析。 該值是通過從第一行的剩余部分去除前導空格,再將所有后續(xù)行連接到一起,并去除所有末尾回車符或換行符來確定的。
- header_store_parse(name, value)?
name 和 value 會被原樣返回。
- header_fetch_parse(name, value)?
如果 value 包含二進制數(shù)據(jù),則會使用
unknown-8bit
字符集來將其轉(zhuǎn)換為Header
對象。 在其他情況下它會被原樣返回。
備注