email.headerregistry: 自定義標頭物件

原始碼: Lib/email/headerregistry.py


在 3.6 版本加入: [1]

標頭由 str 的自定義子類來表示。用於表示給定標頭的特定類由建立標頭時生效的 policyheader_factory 決定。本節文件介紹了 email 包為處理符合 RFC 5322 的電子郵件訊息而實現的特定 header_factory,它不僅為各種標頭型別提供了自定義標頭物件,還為應用程式提供了一種擴充套件機制,以新增自己的自定義標頭型別。

當使用任何派生自 EmailPolicy 的策略物件時,所有標頭都由 HeaderRegistry 生成,並以 BaseHeader 作為它們的最後一個基類。每個標頭類都有一個額外的基類,該基類由標頭的型別決定。例如,許多標頭以 UnstructuredHeader 類作為它們的另一個基類。標頭的專用第二個類由標頭的名稱決定,使用儲存在 HeaderRegistry 中的查詢表。所有這些對於典型的應用程式都是透明管理的,但提供了介面來修改預設行為,以供更復雜的應用程式使用。

以下各節首先介紹標頭基類及其屬性,然後是用於修改 HeaderRegistry 行為的 API,最後是從結構化標頭中解析出的資料所使用的支援類。

class email.headerregistry.BaseHeader(name, value)

namevalue 是透過呼叫 header_factory 傳遞給 BaseHeader 的。任何標頭物件的字串值都是完全解碼為 Unicode 的 value

這個基類定義了以下只讀屬性:

name

標頭的名稱(欄位中“:”之前的部分)。這與在 header_factory 呼叫中為 name 傳遞的值完全相同;也就是說,大小寫被保留。

defects

一個 HeaderDefect 例項的元組,報告在解析期間發現的任何 RFC 合規性問題。email 包試圖完整地檢測合規性問題。有關可能報告的缺陷型別的討論,請參見 errors 模組。

max_count

具有相同 name 的此類標頭的最大數量。值為 None 意味著無限制。BaseHeader 對此屬性的值為 None;專門的標頭類會根據需要覆蓋此值。

BaseHeader 還提供了以下方法,該方法由 email 庫程式碼呼叫,通常不應由應用程式呼叫:

fold(*, policy)

返回一個字串,其中包含根據 policy 正確摺疊標頭所需的 linesep 字元。cte_type8bit 將被視為 7bit,因為標頭不能包含任意二進位制資料。如果 utf8False,非 ASCII 資料將被 RFC 2047 編碼。

BaseHeader 本身不能用於建立標頭物件。它定義了一個協議,每個專門的標頭都與之協作以生成標頭物件。具體來說,BaseHeader 要求專門的類提供一個名為 parseclassmethod()。該方法按如下方式呼叫:

parse(string, kwds)

kwds 是一個包含一個預初始化鍵 defects 的字典。defects 是一個空列表。parse 方法應將任何檢測到的缺陷附加到此列表中。返回時,kwds 字典*必須*包含至少 decodeddefects 鍵的值。decoded 應該是標頭的字串值(即,完全解碼為 Unicode 的標頭值)。parse 方法應假定 string 可能包含內容傳輸編碼的部分,但也應正確處理所有有效的 Unicode 字元,以便它可以解析未編碼的標頭值。

BaseHeader__new__ 然後建立標頭例項,並呼叫其 init 方法。專門的類只有在希望設定 BaseHeader 本身提供的屬性之外的其他屬性時,才需要提供 init 方法。這樣的 init 方法應該如下所示:

def init(self, /, *args, **kw):
    self._myattr = kw.pop('myattr')
    super().init(*args, **kw)

也就是說,專門類放入 kwds 字典中的任何額外內容都應該被移除和處理,然後將 kw 的剩餘內容(以及 args)傳遞給 BaseHeaderinit 方法。

class email.headerregistry.UnstructuredHeader

“非結構化”標頭是 RFC 5322 中的預設標頭型別。任何沒有指定語法的標頭都被視為非結構化。非結構化標頭的經典示例是 Subject 標頭。

RFC 5322 中,非結構化標頭是一段 ASCII 字元集中的任意文字。然而,RFC 2047 有一個與 RFC 5322 相容的機制,用於在標頭值中將非 ASCII 文字編碼為 ASCII 字元。當一個包含編碼詞的 value 傳遞給建構函式時,UnstructuredHeader 解析器會根據 RFC 2047 的非結構化文字規則將這些編碼詞轉換為 Unicode。解析器使用啟發式方法嘗試解碼某些不合規的編碼詞。在這種情況下會註冊缺陷,同時也會為編碼詞或未編碼文字中的無效字元等問題註冊缺陷。

此標頭型別不提供其他屬性。

class email.headerregistry.DateHeader

RFC 5322 為電子郵件標頭中的日期指定了非常特定的格式。DateHeader 解析器可以識別該日期格式,以及一些有時在“野外”發現的變體形式。

此標頭型別提供了以下附加屬性:

datetime

如果標頭值能被識別為某種形式的有效日期,則此屬性將包含一個表示該日期的 datetime 例項。如果輸入日期的時區指定為 -0000(表示它在 UTC,但不包含有關源時區的資訊),則 datetime 將是一個 naive datetime。如果找到特定的時區偏移量(包括 +0000),則 datetime 將包含一個 aware datetime,它使用 datetime.timezone 來記錄時區偏移量。

標頭的 decoded 值是透過根據 RFC 5322 規則格式化 datetime 來確定的;也就是說,它被設定為:

email.utils.format_datetime(self.datetime)

建立 DateHeader 時,value 可以是 datetime 例項。這意味著,例如,以下程式碼是有效的並且會按預期工作:

msg['Date'] = datetime(2011, 7, 15, 21)

由於這是一個 naive datetime,它將被解釋為 UTC 時間戳,並且結果值將具有 -0000 的時區。更有用的是使用 utils 模組中的 localtime() 函式:

msg['Date'] = utils.localtime()

此示例將日期標頭設定為當前時間和日期,使用當前時區偏移量。

class email.headerregistry.AddressHeader

地址標頭是最複雜的結構化標頭型別之一。AddressHeader 類為任何地址標頭提供了通用介面。

此標頭型別提供了以下附加屬性:

groups

一個 Group 物件的元組,編碼了在標頭值中找到的地址和組。不屬於組的地址在此列表中表示為單個地址的 Group,其 display_nameNone

addresses

一個 Address 物件的元組,編碼了標頭值中的所有單個地址。如果標頭值包含任何組,則組中的單個地址將包含在列表中,位置是組在值中出現的位置(也就是說,地址列表被“扁平化”為一維列表)。

標頭的 decoded 值將所有編碼詞解碼為 Unicode。idna 編碼的域名也被解碼為 Unicode。decoded 值透過將 groups 屬性元素的 str 值用 ', ' 連線起來設定。

可以使用 AddressGroup 物件的任意組合列表來設定地址標頭的值。其 display_nameNoneGroup 物件將被解釋為單個地址,這允許透過使用從源標頭的 groups 屬性獲得的列表來完整地複製地址列表(包括組)。

class email.headerregistry.SingleAddressHeader

AddressHeader 的子類,增加了一個額外的屬性:

address

由標頭值編碼的單個地址。如果標頭值實際上包含多個地址(在預設 policy 下會違反 RFC),訪問此屬性將導致 ValueError

許多上述類還有一個 Unique 變體(例如,UniqueUnstructuredHeader)。唯一的區別是,在 Unique 變體中,max_count 被設定為 1。

class email.headerregistry.MIMEVersionHeader

MIME-Version 標頭實際上只有一個有效值,那就是 1.0。為了將來的相容性,此標頭類支援其他有效的版本號。如果一個版本號根據 RFC 2045 是有效值,則標頭物件將對以下屬性具有非 None 的值:

version

版本號,為字串,去除了任何空白和/或註釋。

major

主版本號,為整數

minor

次版本號,為整數

class email.headerregistry.ParameterizedMIMEHeader

MIME 標頭都以字首“Content-”開頭。每個特定的標頭都有一個特定的值,在該標頭的類下有描述。有些還可以帶有一系列補充引數,這些引數具有通用格式。此類作為所有帶有引數的 MIME 標頭的基類。

params

一個將引數名稱對映到引數值的字典。

class email.headerregistry.ContentTypeHeader

一個 ParameterizedMIMEHeader 類,用於處理 Content-Type 標頭。

content_type

內容型別字串,格式為 maintype/subtype

maintype
subtype
class email.headerregistry.ContentDispositionHeader

一個 ParameterizedMIMEHeader 類,用於處理 Content-Disposition 標頭。

content_disposition

inlineattachment 是唯一常用且有效的值。

class email.headerregistry.ContentTransferEncoding

處理 Content-Transfer-Encoding 標頭。

cte

有效值為 7bit8bitbase64quoted-printable。更多資訊請參見 RFC 2045

class email.headerregistry.HeaderRegistry(base_class=BaseHeader, default_class=UnstructuredHeader, use_default_map=True)

這是 EmailPolicy 預設使用的工廠。HeaderRegistry 動態地構建用於建立標頭例項的類,它使用 base_class 和從其持有的登錄檔中檢索的專門類。當給定的標頭名稱未出現在登錄檔中時,使用 default_class 指定的類作為專門類。當 use_default_mapTrue(預設值)時,在初始化期間將標頭名稱到類的標準映射覆制到登錄檔中。base_class 始終是生成的類的 __bases__ 列表中的最後一個類。

預設對映如下:

subject:

UniqueUnstructuredHeader

date:

UniqueDateHeader

resent-date:

DateHeader

orig-date:

UniqueDateHeader

sender:

UniqueSingleAddressHeader

resent-sender:

SingleAddressHeader

to:

UniqueAddressHeader

resent-to:

AddressHeader

cc:

UniqueAddressHeader

resent-cc:

AddressHeader

bcc:

UniqueAddressHeader

resent-bcc:

AddressHeader

from:

UniqueAddressHeader

resent-from:

AddressHeader

reply-to:

UniqueAddressHeader

mime-version:

MIMEVersionHeader

content-type:

ContentTypeHeader

content-disposition:

ContentDispositionHeader

content-transfer-encoding:

ContentTransferEncodingHeader

message-id:

MessageIDHeader

HeaderRegistry 具有以下方法:

map_to_type(self, name, cls)

name 是要對映的標頭的名稱。它將在登錄檔中轉換為小寫。cls 是要與 base_class 一起使用的專門類,用於建立例項化匹配 name 的標頭時所使用的類。

__getitem__(name)

構造並返回一個用於處理建立 name 標頭的類。

__call__(name, value)

從登錄檔中檢索與 name 關聯的專門標頭(如果 name 未出現在登錄檔中,則使用 default_class),並將其與 base_class 組合以生成一個類,呼叫構造的類的建構函式,並向其傳遞相同的引數列表,最後返回由此建立的類例項。

以下類是用於表示從結構化標頭解析的資料的類,通常可以由應用程式用於構造結構化值以分配給特定的標頭。

class email.headerregistry.Address(display_name='', username='', domain='', addr_spec=None)

用於表示電子郵件地址的類。地址的一般形式是:

[display_name] <username@domain>

username@domain

其中每個部分都必須符合 RFC 5322 中詳細說明的特定語法規則。

為方便起見,可以指定 addr_spec 代替 usernamedomain,在這種情況下,usernamedomain 將從 addr_spec 中解析出來。addr_spec 必須是符合 RFC 規範的帶引號字串;否則 Address 將引發錯誤。允許使用 Unicode 字元,並且在序列化時會被正確編碼。但是,根據 RFC,地址的使用者名稱部分*不允許*使用 Unicode。

display_name

地址的顯示名稱部分(如果有的話),去除了所有引號。如果地址沒有顯示名稱,此屬性將為空字串。

username

地址的 username 部分,去除了所有引號。

domain

地址的 domain 部分。

addr_spec

地址的 username@domain 部分,被正確引用以用作裸地址(上面顯示的第二種形式)。此屬性不可變。

__str__()

物件的 str 值是根據 RFC 5322 規則引用的地址,但不對任何非 ASCII 字元進行內容傳輸編碼。

為了支援 SMTP (RFC 5321), Address 處理一種特殊情況:如果 usernamedomain 都是空字串(或 None),則 Address 的字串值為 <>

class email.headerregistry.Group(display_name=None, addresses=None)

用於表示地址組的類。地址組的一般形式是:

display_name: [address-list];

為了方便處理由組和單個地址混合組成的地址列表,Group 也可以用於表示不屬於組的單個地址,方法是將 display_name 設定為 None,並提供單個地址的列表作為 addresses

display_name

組的 display_name。如果為 Noneaddresses 中只有一個 Address,則 Group 表示一個不在組中的單個地址。

addresses

一個可能為空的 Address 物件元組,表示組中的地址。

__str__()

Groupstr 值根據 RFC 5322 格式化,但不對任何非 ASCII 字元進行內容傳輸編碼。如果 display_name 為 none 且 addresses 列表中只有一個 Address,則 str 值將與該單個 Addressstr 相同。

腳註