email.policy: Policy 物件

3.3 版本新增。

原始碼: Lib/email/policy.py


email 包的主要重點是處理各種電子郵件和 MIME RFC 中描述的電子郵件訊息。然而,電子郵件訊息的一般格式(一個由名稱後跟冒號,後跟值的頭部欄位組成,整個塊後跟一個空行和一個任意的“主體”),是一種在電子郵件領域之外也很有用的格式。其中一些用法相當符合主要的電子郵件 RFC,有些則不然。即使在使用電子郵件時,有時也需要打破對 RFC 的嚴格遵守,例如生成與不遵循標準或以違反標準的方式實現您想要使用的擴充套件的電子郵件伺服器互操作的電子郵件。

Policy 物件為 email 包提供了處理所有這些不同用例的靈活性。

Policy 物件封裝了一組屬性和方法,這些屬性和方法控制 email 包在使用期間的各種元件的行為。Policy 例項可以傳遞給 email 包中的各種類和方法,以更改預設行為。下面描述了可設定的值及其預設值。

email 包中的所有類都使用預設的 policy。 對於所有 parser 類和相關的便捷函式,以及 Message 類,這是 Compat32 policy,透過其對應的預定義例項 compat32。此 policy 提供與 Python 3.3 之前的 email 包版本的完全向後相容性(在某些情況下,包括 bug 相容性)。

對於 EmailMessage,*policy* 關鍵字的此預設值為 EmailPolicy policy,透過其預定義例項 default

當建立 MessageEmailMessage 物件時,它會獲取 policy。 如果訊息是由 parser 建立的,則傳遞給解析器的 policy 將是其建立的訊息所使用的 policy。 如果訊息是由程式建立的,則可以在建立時指定 policy。 當將訊息傳遞給 generator 時,生成器預設使用訊息中的 policy,但您也可以將特定的 policy 傳遞給生成器,這將覆蓋儲存在訊息物件上的 policy。

對於 email.parser 類和解析器便捷函式,*policy* 關鍵字的預設值將在未來版本的 Python 中更改。 因此,在呼叫 parser 模組中描述的任何類和函式時,您應該始終明確指定您想要使用的 policy

本文件的第一部分介紹了 Policy 的特性,它是一個 抽象基類,定義了所有 policy 物件通用的特性,包括 compat32。這包括由 email 包在內部呼叫的某些鉤子方法,自定義 policy 可以覆蓋這些方法以獲得不同的行為。第二部分描述了具體類 EmailPolicyCompat32,它們分別實現提供標準行為和向後相容行為和特性的鉤子。

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 在建立要輸入到 sendmailstdin 的二進位制字串時使用符合 RFC 的行分隔符字元,其中預設 policy 將使用 \n 行分隔符。

某些 email 包方法接受 *policy* 關鍵字引數,允許為該方法覆蓋 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

也可以使用加法運算子組合 Policy 物件,生成一個 policy 物件,其設定是求和物件的非預設值的組合

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

這是所有 policy 類的 抽象基類。它為幾個瑣碎的方法提供預設實現,以及不可變屬性、clone() 方法和建構函式語義的實現。

可以將各種關鍵字引數傳遞給 policy 類的建構函式。可以指定的引數是此類上的任何非方法屬性,以及具體類上的任何其他非方法屬性。建構函式中指定的值將覆蓋相應屬性的預設值。

此類定義了以下屬性,因此可以將以下值傳遞給任何 policy 類的建構函式

max_line_length

序列化輸出中任何行的最大長度,不包括行尾字元。預設值為 78,根據 RFC 5322。值 0None 表示根本不應進行行換行。

linesep

用於終止序列化輸出中行的字串。預設值為 \n,因為這是 Python 使用的內部行尾規範,儘管 RFC 需要 \r\n

cte_type

控制可能使用或必須使用的內容傳輸編碼型別。可能的值為

7bit

所有資料必須是“7 位乾淨”(僅限 ASCII)。這意味著在必要時,資料將使用 quoted-printable 或 base64 編碼進行編碼。

8bit

資料不限於 7 位乾淨。標頭中的資料仍然必須是僅限 ASCII 的,因此會被編碼(請參閱下面的 fold_binary()utf8,瞭解例外情況),但主體部分可以使用 8bit CTE。

cte_type 值為 8bit 僅適用於 BytesGenerator,而不適用於 Generator,因為字串不能包含二進位制資料。如果 Generator 在指定 cte_type=8bit 的策略下執行,它將表現得好像 cte_type7bit

raise_on_defect

如果為 True,則遇到的任何缺陷都將作為錯誤引發。如果為 False(預設值),缺陷將傳遞給 register_defect() 方法。

mangle_from_

如果為 True,則主體中以 “From “ 開頭的行將透過在其前面放置一個 > 來轉義。當訊息由生成器序列化時,將使用此引數。預設值:False

在 3.5 版本中新增。

message_factory

用於構造新的空訊息物件的工廠函式。由解析器在構建訊息時使用。預設為 None,在這種情況下,將使用 Message

在 3.6 版本中新增。

verify_generated_headers

如果為 True(預設值),生成器將引發 HeaderWriteError,而不是寫入不正確摺疊或分隔的標頭,以致它將被解析為多個標頭或與相鄰資料連線。此類標頭可以透過自定義標頭類或 email 模組中的錯誤生成。

由於它是一個安全功能,即使在 Compat32 策略中,此值也預設為 True。對於向後相容但存在不安全行為的情況,必須顯式將其設定為 False

在 3.13 版本中新增。

以下 Policy 方法旨在由使用 email 庫的程式碼呼叫,以建立具有自定義設定的策略例項

clone(**kw)

返回一個新的 Policy 例項,其屬性的值與當前例項相同,除非這些屬性透過關鍵字引數給出新值。

其餘的 Policy 方法由 email 包程式碼呼叫,不打算由使用 email 包的應用程式呼叫。自定義策略必須實現所有這些方法。

handle_defect(obj, defect)

處理在 obj 上找到的 defect。當 email 包呼叫此方法時,defect 將始終是 Defect 的子類。

預設實現檢查 raise_on_defect 標誌。如果為 True,則將 defect 作為異常引發。如果為 False(預設值),則將 objdefect 傳遞給 register_defect()

register_defect(obj, defect)

obj 上註冊一個 defect。在 email 包中,defect 將始終是 Defect 的子類。

預設實現呼叫 objdefects 屬性的 append 方法。當 email 包呼叫 handle_defect 時,obj 通常會有一個具有 append 方法的 defects 屬性。與 email 包一起使用的自定義物件型別(例如,自定義 Message 物件)也應提供這樣的屬性,否則解析訊息中的缺陷將引發意外錯誤。

header_max_count(name)

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

當將標頭新增到 EmailMessageMessage 物件時呼叫。如果返回的值不是 0None,並且已經存在多個名為 name 的標頭大於或等於返回的值,則會引發 ValueError

由於 Message.__setitem__ 的預設行為是將值附加到標頭列表,因此很容易在不知不覺中建立重複的標頭。此方法允許對某些標頭進行限制,以限制可以透過程式設計方式新增到 Message 的該標頭的例項數量。(解析器不會觀察此限制,它會忠實地生成訊息中存在的儘可能多的標頭。)

預設實現為所有標頭名稱返回 None

header_source_parse(sourcelines)

email 包使用一個字串列表呼叫此方法,每個字串都以在要解析的源中找到的行分隔符字元結尾。第一行包括欄位標頭名稱和分隔符。源中的所有空格都會被保留。該方法應返回要儲存在 Message 中以表示已解析標頭的 (name, value) 元組。

如果實現希望保留與現有 email 包策略的相容性,則 name 應該是保留大小寫的名稱(直到 ‘:’ 分隔符的所有字元),而 value 應該是不折疊的值(刪除了所有行分隔符字元,但保留了空格),並刪除了前導空格。

sourcelines 可能包含 surrogateescaped 二進位制資料。

沒有預設實現

header_store_parse(name, value)

當應用程式在以程式設計方式修改 Message(而不是由解析器建立的 Message)時,email 包使用應用程式提供的名稱和值呼叫此方法。該方法應返回要儲存在 Message 中以表示標頭的 (name, value) 元組。

如果實現希望保留與現有 email 包策略的相容性,則 namevalue 應該是字串或不更改傳入引數內容的字串子類。

沒有預設實現

header_fetch_parse(name, value)

當應用程式請求該標頭時,email 包會使用當前儲存在 Message 中的namevalue 呼叫此方法,並且該方法返回的任何內容都會作為檢索到的標頭值傳遞迴應用程式。請注意,Message 中可能儲存了多個具有相同名稱的標頭;該方法會傳遞特定標頭的名稱和值,該標頭註定要返回給應用程式。

value 可能包含 surrogateescaped 二進位制資料。該方法返回的值中不應包含 surrogateescaped 二進位制資料。

沒有預設實現

fold(name, value)

對於給定的標頭,email 包會使用當前儲存在 Message 中的namevalue 呼叫此方法。該方法應返回一個字串,該字串透過將 namevalue 組合並在適當的位置插入 linesep 字元,來正確地“摺疊”(根據策略設定)該標頭。有關摺疊電子郵件標頭的規則的討論,請參閱 RFC 5322

value 可能包含 surrogateescaped 二進位制資料。該方法返回的字串中不應包含 surrogateescaped 二進位制資料。

fold_binary(name, value)

fold() 相同,只是返回的值應為 bytes 物件而不是字串。

value 可能包含 surrogateescaped 二進位制資料。這些資料可以在返回的 bytes 物件中轉換回二進位制資料。

class email.policy.EmailPolicy(**kw)

這個具體的 Policy 提供了旨在完全符合當前電子郵件 RFC 的行為。這些包括(但不限於)RFC 5322RFC 2047 和當前的 MIME RFC。

此策略添加了新的標頭解析和摺疊演算法。標頭不再是簡單的字串,而是 str 子類,其屬性取決於欄位的型別。解析和摺疊演算法完全實現了 RFC 2047RFC 5322

message_factory 屬性的預設值是 EmailMessage

除了上面列出的適用於所有策略的可設定屬性之外,此策略還添加了以下附加屬性

在 3.6 版本中新增: [1]

utf8

如果為 False,則遵循 RFC 5322,透過將非 ASCII 字元編碼為“編碼字”來支援它們。如果為 True,則遵循 RFC 6532,並對標頭使用 utf-8 編碼。以這種方式格式化的訊息可能會傳遞給支援 SMTPUTF8 擴充套件的 SMTP 伺服器 (RFC 6531)。

refold_source

如果 Message 物件中標頭的值來自 parser (而不是由程式設定),則此屬性指示在將訊息轉換回序列化形式時,生成器是否應重新摺疊該值。可能的值為

none

所有源值都使用原始摺疊

long

任何行長度超過 max_line_length 的源值將被重新摺疊

all

所有值都將被重新摺疊。

預設值為 long

header_factory

一個可呼叫物件,它接受兩個引數,namevalue,其中 name 是標頭欄位名稱,value 是未摺疊的標頭欄位值,並返回表示該標頭的字串子類。提供了一個預設的 header_factory(請參閱 headerregistry),該工廠支援對各種地址和日期 RFC 5322 標頭欄位型別以及主要的 MIME 標頭欄位型別進行自定義解析。將來將新增對其他自定義解析的支援。

content_manager

一個物件,至少具有兩個方法:get_content 和 set_content。當呼叫 get_content()set_content() 方法時,EmailMessage 物件會呼叫此物件的相應方法,並將其作為第一個引數傳遞給訊息物件,並將傳遞給它的任何引數或關鍵字作為附加引數。預設情況下,content_manager 設定為 raw_data_manager

在 3.4 版本中新增。

該類提供了 Policy 的抽象方法的以下具體實現

header_max_count(name)

返回用於表示具有給定名稱的標頭的專門類的 max_count 屬性的值。

header_source_parse(sourcelines)

名稱被解析為直到“:”的所有內容,並按原樣返回。該值透過剝離第一行的開頭空格、將所有後續行連線在一起並剝離任何尾隨回車符或換行符來確定。

header_store_parse(name, value)

名稱保持不變地返回。如果輸入值具有 name 屬性並且它與 name (忽略大小寫)匹配,則該值保持不變地返回。否則,會將 namevalue 傳遞給 header_factory,並將生成的標頭物件作為值返回。在這種情況下,如果輸入值包含 CR 或 LF 字元,則會引發 ValueError

header_fetch_parse(name, value)

如果值具有 name 屬性,則將其原樣返回。否則,將刪除任何 CR 或 LF 字元的 _name_ 和 _value_ 傳遞給 header_factory,並返回生成的標頭物件。任何被代理轉義的位元組都會轉換為 Unicode 的未知字元字形。

fold(name, value)

標頭摺疊由 refold_source 策略設定控制。如果值不具有 name 屬性,則認為它是“源值”(具有 name 屬性意味著它某種形式的標頭物件)。如果根據策略需要重新摺疊源值,則透過將刪除任何 CR 和 LF 字元的 _name_ 和 _value_ 傳遞給 header_factory 將其轉換為標頭物件。標頭物件的摺疊是透過使用當前策略呼叫其 fold 方法來完成的。

使用 splitlines() 將源值拆分為多行。如果該值不重新摺疊,則使用策略中的 linesep 重新連線這些行並返回。例外情況是包含非 ASCII 二進位制資料的行。在這種情況下,無論 refold_source 設定如何,該值都會被重新摺疊,這會導致使用 unknown-8bit 字元集對二進位制資料進行 CTE 編碼。

fold_binary(name, value)

如果 cte_type7bit,則與 fold() 相同,只是返回的值是位元組。

如果 cte_type8bit,則非 ASCII 二進位制資料會被轉換回位元組。無論 refold_header 設定如何,包含二進位制資料的標頭都不會被重新摺疊,因為無法知道二進位制資料是由單位元組字元還是多位元組字元組成的。

以下 EmailPolicy 例項提供了適用於特定應用領域的預設值。請注意,在將來,這些例項(特別是 HTTP 例項)的行為可能會被調整,以更加符合與其領域相關的 RFC。

email.policy.default

所有預設值均未更改的 EmailPolicy 例項。此策略使用標準的 Python \n 行尾符,而不是 RFC 正確的 \r\n

email.policy.SMTP

適用於根據電子郵件 RFC 序列化訊息。與 default 類似,但 linesep 設定為符合 RFC 的 \r\n

email.policy.SMTPUTF8

SMTP 相同,只是 utf8True。在不使用標頭中的編碼詞的情況下序列化訊息到訊息儲存很有用。僅當發件人或收件人地址包含非 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,電子郵件包的有效 API 從 Python 3.2 API 更改為以下方式

  • Message 上設定標頭會導致解析該標頭並建立標頭物件。

  • Message 獲取標頭值會導致解析該標頭並建立並返回標頭物件。

  • 任何標頭物件或由於策略設定而重新摺疊的任何標頭都使用完全實現 RFC 摺疊演算法的演算法進行摺疊,包括知道在何處需要和允許編碼詞。

從應用程式檢視來看,這意味著透過 EmailMessage 獲得的任何標頭都是具有額外屬性的標頭物件,其字串值是標頭的完全解碼的 Unicode 值。同樣,可以使用 Unicode 字串為標頭分配新值或建立新標頭,並且策略將負責將 Unicode 字串轉換為正確的 RFC 編碼形式。

標頭物件及其屬性在 headerregistry 中進行了描述。

class email.policy.Compat32(**kw)

此具體 Policy 是向後相容性策略。它複製了 Python 3.2 中電子郵件包的行為。policy 模組還定義了此類的例項 compat32,該例項用作預設策略。因此,電子郵件包的預設行為是保持與 Python 3.2 的相容性。

以下屬性的值與 Policy 預設值不同

mangle_from_

預設值為 True

該類提供了 Policy 的抽象方法的以下具體實現

header_source_parse(sourcelines)

名稱被解析為直到“:”的所有內容,並按原樣返回。該值透過剝離第一行的開頭空格、將所有後續行連線在一起並剝離任何尾隨回車符或換行符來確定。

header_store_parse(name, value)

名稱和值原樣返回。

header_fetch_parse(name, value)

如果值包含二進位制資料,它會使用 unknown-8bit 字元集轉換為 Header 物件。否則,它將保持不變返回。

fold(name, value)

標頭使用 Header 摺疊演算法進行摺疊,該演算法保留值中現有的換行符,並將每行結果包裹到 max_line_length。非 ASCII 二進位制資料使用 unknown-8bit 字元集進行 CTE 編碼。

fold_binary(name, value)

標頭使用 Header 摺疊演算法進行摺疊,該演算法保留值中現有的換行符,並將每行結果包裹到 max_line_length。如果 cte_type7bit,則非 ASCII 二進位制資料會使用 unknown-8bit 字元集進行 CTE 編碼。否則,將使用原始源標頭,包含其現有的換行符以及可能包含的任何(RFC 無效的)二進位制資料。

email.policy.compat32

Compat32 的一個例項,提供與 Python 3.2 中 email 包的行為的向後相容性。

腳註