email.policy
:策略物件¶
在 3.3 版本加入。
原始碼: Lib/email/policy.py
email
包的主要關注點是處理各種電子郵件和 MIME RFCs 所描述的電子郵件訊息。然而,電子郵件訊息的通用格式(一個由多個標頭欄位組成的塊,每個欄位包含一個名稱後跟一個冒號,然後是一個值,整個塊後跟一個空行和一個任意的“正文”)這種格式在電子郵件領域之外也得到了應用。其中一些用法與主要的電子郵件 RFCs 相當接近,而另一些則不然。即使在處理電子郵件時,有時也需要打破對 RFCs 的嚴格遵守,例如生成與那些本身不遵循標準或以違反標準的方式實現您想使用的擴充套件的電子郵件伺服器互操作的電子郵件。
策略物件賦予 email 包處理所有這些不同用例的靈活性。
Policy
物件封裝了一組屬性和方法,用於在使用過程中控制 email 包中各種元件的行為。Policy
例項可以傳遞給 email 包中的各種類和方法,以改變預設行為。可設定的值及其預設值將在下面描述。
email 包中所有的類都使用一個預設策略。對於所有的 parser
類和相關的便利函式,以及 Message
類,預設策略是 Compat32
策略,透過其對應的預定義例項 compat32
來實現。這個策略提供了與 Python 3.3 之前的 email 包版本的完全向後相容性(在某些情況下,包括與 bug 的相容性)。
EmailMessage
的 policy 關鍵字的預設值是 EmailPolicy
策略,透過其預定義例項 default
實現。
當建立 Message
或 EmailMessage
物件時,它會獲得一個策略。如果訊息是由 parser
建立的,傳遞給解析器的策略將成為它建立的訊息所使用的策略。如果訊息是由程式建立的,那麼可以在建立時指定策略。當訊息被傳遞給 generator
時,生成器預設使用訊息的策略,但你也可以傳遞一個特定的策略給生成器,它將覆蓋儲存在訊息物件上的策略。
在 Python 的未來版本中,email.parser
類和解析器便利函式的 policy 關鍵字的預設值**將會改變**。因此,在呼叫 parser
模組中描述的任何類和函式時,你應該**總是顯式指定你想要使用的策略**。
本文件的第一部分涵蓋了 Policy
的特性,它是一個抽象基類,定義了所有策略物件(包括 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
的 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
策略物件也可以使用加法運算子進行組合,生成一個策略物件,其設定是相加物件非預設值的組合。
>>> 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)¶
這是所有策略類的抽象基類。它為一些簡單的方法提供了預設實現,以及不可變性屬性的實現、
clone()
方法和建構函式的語義。策略類的建構函式可以接受各種關鍵字引數。可以指定的引數是這個類上的任何非方法屬性,以及具體類上的任何額外的非方法屬性。在建構函式中指定的值將覆蓋相應屬性的預設值。
該類定義了以下屬性,因此以下屬性的值可以在任何策略類的建構函式中傳遞:
- linesep¶
用於在序列化輸出中終止行的字串。預設是
\n
,因為這是 Python 內部使用的行尾規則,儘管 RFCs 要求使用\r\n
。
- cte_type¶
控制可能或必須使用的內容傳輸編碼(Content Transfer Encodings)的型別。可能的值是:
7bit
所有資料必須是“7 位安全的”(僅 ASCII)。這意味著在必要時,資料將使用 quoted-printable 或 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 ”* 開頭的行會透過在它們前面加上一個>
來進行轉義。此引數在訊息由生成器序列化時使用。預設值:False
。在 3.5 版本加入。
- verify_generated_headers¶
如果為
True
(預設值),生成器將引發HeaderWriteError
,而不是寫入一個摺疊或分隔不當的標頭,這樣的標頭可能會被解析為多個標頭或與相鄰資料連線。這類標頭可能由自定義標頭類或email
模組中的錯誤生成。由於它是一項安全特性,即使在
Compat32
策略中,它也預設為True
。為了實現向後相容但行為不安全的模式,必須將其顯式設定為False
。在 3.13 版本加入。
以下
Policy
方法旨在由使用 email 庫的程式碼呼叫,以建立具有自定義設定的策略例項:其餘的
Policy
方法由 email 包的程式碼呼叫,不應由使用 email 包的應用程式呼叫。自定義策略必須實現所有這些方法。- handle_defect(obj, defect)¶
處理在 obj 上發現的 defect。當 email 包呼叫此方法時,defect 將始終是
MessageDefect
的子類。預設實現會檢查
raise_on_defect
標誌。如果為True
,defect 將作為異常被引發。如果為False
(預設值),obj 和 defect 將被傳遞給register_defect()
。
- register_defect(obj, defect)¶
在 obj 上註冊一個 defect。在 email 包中,defect 將始終是
MessageDefect
的子類。預設實現會呼叫 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 可能包含 surrogateescaped 編碼的二進位制資料。
沒有預設實現。
- 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 可能包含 surrogateescaped 編碼的二進位制資料。方法返回的值中不應包含 surrogateescaped 編碼的二進位制資料。
沒有預設實現。
- class email.policy.EmailPolicy(**kw)¶
這個具體的
Policy
提供了旨在完全符合當前電子郵件 RFC 的行為。這些 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_source_parse(sourcelines)¶
名稱被解析為直到“
:
”之前的所有內容並原樣返回。值是透過去除第一行剩餘部分的前導空格,將所有後續行連線在一起,並去除任何尾隨的回車或換行符來確定的。
- header_store_parse(name, value)¶
名稱原樣返回。如果輸入值具有一個
name
屬性且其與 name 忽略大小寫匹配,則該值原樣返回。否則,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 編碼。
以下 EmailPolicy
例項為特定應用領域提供了合適的預設值。請注意,將來這些例項的行為(特別是 HTTP
例項)可能會被調整,以更緊密地符合其相關領域的 RFC。
- email.policy.default¶
一個
EmailPolicy
的例項,所有預設值均未改變。此策略使用標準的 Python\n
換行符,而不是 RFC 規範的\r\n
。
- email.policy.SMTP¶
適用於按照電子郵件 RFCs 規範序列化訊息。與
default
類似,但linesep
設定為\r\n
,這符合 RFC 規範。
- 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
是向後相容策略。它複製了 email 包在 Python 3.2 中的行為。policy
模組也定義了這個類的一個例項compat32
,它被用作預設策略。因此,email 包的預設行為是保持與 Python 3.2 的相容性。以下屬性的值與
Policy
的預設值不同:- mangle_from_¶
預設值為
True
。
該類提供了
Policy
抽象方法的以下具體實現:- header_source_parse(sourcelines)¶
名稱被解析為直到“
:
”之前的所有內容並原樣返回。值是透過去除第一行剩餘部分的前導空格,將所有後續行連線在一起,並去除任何尾隨的回車或換行符來確定的。
- header_store_parse(name, value)¶
名稱和值將不加修改地返回。
腳註