email.headerregistry
: 自定義標頭對象?
源代碼: Lib/email/headerregistry.py
3.6 新版功能: 1
標頭是由 str
的自定義子類(lèi)來(lái)表示的。 用于表示給定標頭的特定類(lèi)則由創(chuàng )建標頭時(shí)生效的 policy
的 header_factory
確定。 這一節記錄了 email 包為處理兼容 RFC 5322 的電子郵件消息所實(shí)現的特定 header_factory
,它不僅為各種標頭類(lèi)型提供了自定義的標頭對象,還為應用程序提供了添加其自定義標頭類(lèi)型的擴展機制。
當使用派生自 EmailPolicy
的任何策略對象時(shí),所有標頭都通過(guò) HeaderRegistry
產(chǎn)生并且以 BaseHeader
作為其最后一個(gè)基類(lèi)。 每個(gè)標頭類(lèi)都有一個(gè)由該標頭類(lèi)型確定的附加基類(lèi)。 例如,許多標頭都以 UnstructuredHeader
類(lèi)作為其另一個(gè)基類(lèi)。 一個(gè)標頭專(zhuān)用的第二個(gè)類(lèi)是由標頭名稱(chēng)使用存儲在 HeaderRegistry
中的查找表來(lái)確定的。 所有這些都針對典型應用程序進(jìn)行透明的管理,但也為修改默認行為提供了接口,以便由更復雜的應用使用。
以下各節首先記錄了標頭基類(lèi)及其屬性,然后是用于修改 HeaderRegistry
行為的 API,最后是用于表示從結構化標頭解析的數據的支持類(lèi)。
- class email.headerregistry.BaseHeader(name, value)?
name 和 value 會(huì )從
header_factory
調用傳遞給BaseHeader
。 任何標頭對象的字符串值都是完成解碼為 unicode 的 value。這個(gè)基類(lèi)定義了下列只讀屬性:
- name?
標頭的名稱(chēng)(字段在 ':' 之前的部分)。 這就是 name 的
header_factory
調用所傳遞的值;也就是說(shuō)會(huì )保持大小寫(xiě)形式。
- defects?
一個(gè)包含
HeaderDefect
實(shí)例的元組,這些實(shí)例報告了在解析期間發(fā)現的任何 RFC 合規性問(wèn)題。 email 包會(huì )嘗試盡可能地檢測合規性問(wèn)題。 請參閱errors
模塊了解可能被報告的缺陷類(lèi)型的相關(guān)討論。
- max_count?
此類(lèi)型標頭可具有相同
name
的最大數量。None
值表示無(wú)限制。 此屬性的BaseHeader
值為None
;專(zhuān)用的標頭類(lèi)預期將根據需要重載這個(gè)值。
BaseHeader
還提供了以下方法,它由 email 庫代碼調用,通常不應當由應用程序來(lái)調用。- fold(*, policy)?
返回一個(gè)字符串,其中包含用來(lái)根據 policy 正確地折疊標頭的
linesep
字符。cte_type
為8bit
時(shí)將被作為7bit
來(lái)處理,因為標頭不能包含任意二進(jìn)制數據。 如果utf8
為False
,則非 ASCII 數據將根據 RFC 2047 來(lái)編碼。
BaseHeader
本身不能被用于創(chuàng )建標頭對象。 它定義了一個(gè)與每個(gè)專(zhuān)用標頭相配合的協(xié)議以便生成標頭對象。 具體來(lái)說(shuō),BaseHeader
要求專(zhuān)用類(lèi)提供一個(gè)名為parse
的classmethod()
。 此方法的調用形式如下:parse(string, kwds)
kwds
是包含了一個(gè)預初始化鍵defects
的字典。defects
是一個(gè)空列表。 parse 方法應當將任何已檢測到的缺陷添加到此列表中。 在返回時(shí),kwds
字典 必須 至少包含decoded
和defects
等鍵的值。decoded
應當是標頭的字符串值(即完全解碼為 unicode 的標頭值)。 parse 方法應當假定 string 可能包含 content-transfer-encoded 部分,但也應當正確地處理全部有效的 unicode 字符以便它能解析未經(jīng)編碼的標頭值。隨后
BaseHeader
的__new__
會(huì )創(chuàng )建標頭實(shí)例,并調用其init
方法。 專(zhuān)屬類(lèi)如果想要設置BaseHeader
自身所提供的屬性之外的附加屬性,只需提供一個(gè)init
方法。 這樣的init
看起來(lái)應該是這樣:def init(self, /, *args, **kw): self._myattr = kw.pop('myattr') super().init(*args, **kw)
也就是說(shuō),專(zhuān)屬類(lèi)放入
kwds
字典的任何額外內容都應當被移除和處理,并且kw
(和args
) 的剩余內容會(huì )被傳遞給BaseHeader
init
方法。
- class email.headerregistry.UnstructuredHeader?
"非結構化" 標頭是 RFC 5322 中默認的標頭類(lèi)型。 任何沒(méi)有指定語(yǔ)法的標頭都會(huì )被視為是非結構化的。 非結構化標頭的經(jīng)典例子是 Subject 標頭。
在 RFC 5322 中,非結構化標頭是指一段以 ASCII 字符集表示的任意文本。 但是 RFC 2047 具有一個(gè) RFC 5322 兼容機制用來(lái)將標頭值中的非 ASCII 文本編碼為 ASCII 字符。 當包含已編碼字的 value 被傳遞給構造器時(shí),
UnstructuredHeader
解析器會(huì )按照非結構化文本的 RFC 2047 規則將此類(lèi)已編碼字轉換為 unicode。 解析器會(huì )使用啟發(fā)式機制來(lái)嘗試解碼一些不合規的已編碼字。 在此種情況下各類(lèi)缺陷,例如已編碼字或未編碼文本中的無(wú)效字符問(wèn)題等缺陷將會(huì )被注冊。此標頭類(lèi)型未提供附加屬性。
- class email.headerregistry.DateHeader?
RFC 5322 為電子郵件標頭內的日期指定了非常明確的格式。
DateHeader
解析器會(huì )識別該日期格式,并且也能識別間或出現的一些“不規范”變種形式。這個(gè)標頭類(lèi)型提供了以下附加屬性。
- datetime?
如果標頭值能被識別為某一種有效的日期形式,此屬性將包含一個(gè)代表該日期的
datetime
實(shí)例。 如果輸入日期的時(shí)區被指定為-0000
(表示為 UTC 但不包含源時(shí)區的相關(guān)信息),則datetime
將為簡(jiǎn)單型datetime
。 如果找到了特定的時(shí)區時(shí)差值 (包括 +0000),則datetime
將包含使用datetime.timezone
來(lái)記錄時(shí)區時(shí)差時(shí)的感知型datetime
。
標頭的
decoded
值是由按照 RFC 5322 對datetime
進(jìn)行格式化來(lái)確定的;也就是說(shuō),它會(huì )被設為:email.utils.format_datetime(self.datetime)
當創(chuàng )建
DateHeader
時(shí),value 可以為datetime
實(shí)例。 例如這意味著(zhù)以下代碼是有效的并能實(shí)現人們預期的行為:msg['Date'] = datetime(2011, 7, 15, 21)
因為這是個(gè)簡(jiǎn)單型
datetime
它將被解讀為 UTC 時(shí)間戳,并且結果值的時(shí)區將為-0000
。 使用來(lái)自utils
模塊的localtime()
函數會(huì )更有用:msg['Date'] = utils.localtime()
這個(gè)例子將日期標頭設為使用當前時(shí)區時(shí)差值的當前時(shí)間和日期。
- class email.headerregistry.AddressHeader?
地址標頭是最復雜的結構化標頭類(lèi)型之一。
AddressHeader
類(lèi)提供了適合任何地址標頭的泛用型接口。這個(gè)標頭類(lèi)型提供了以下附加屬性。
- groups?
編碼了在標頭值中找到的地址和分組的
Group
對象的元組。 非分組成員的地址在此列表中表示為display_name
為None
的單地址Groups
。
- addresses?
編碼了來(lái)自標頭值的所有單獨地址的
Address
對象的元組。 如果標頭值包含任何分組,則來(lái)自分組的單個(gè)地址將包含在該分組出現在值中的點(diǎn)上列出(也就是說(shuō),地址列表會(huì )被“展平”為一維列表)。
The
decoded
value of the header will have all encoded words decoded to unicode.idna
encoded domain names are also decoded to unicode. Thedecoded
value is set by joining thestr
value of the elements of thegroups
attribute with', '
.可以使用
Address
與Group
對象的任意組合的列表來(lái)設置一個(gè)地址標頭的值。display_name
為None
的Group
對象將被解讀為單獨地址,這允許一個(gè)地址列表可以附帶通過(guò)使用從源標頭的groups
屬性獲取的列表而保留原分組。
- class email.headerregistry.SingleAddressHeader?
AddressHeader
的子類(lèi),添加了一個(gè)額外的屬性:- address?
由標頭值編碼的單個(gè)地址。 如果標頭值實(shí)際上包含一個(gè)以上的地址(這在默認
policy
下將違反 RFC),則訪(fǎng)問(wèn)此屬性將導致ValueError
。
上述類(lèi)中許多還具有一個(gè) Unique
變體 (例如 UniqueUnstructuredHeader
)。 其唯一差別是在 Unique
變體中 max_count
被設為 1。
- class email.headerregistry.MIMEVersionHeader?
實(shí)際上 MIME-Version 標頭只有一個(gè)有效的值,即
1.0
。 為了將來(lái)的擴展,這個(gè)標頭類(lèi)還支持其他的有效版本號。 如果一個(gè)版本號是 RFC 2045 的有效值,則標頭對象的以下屬性將具有不為None
的值:- version?
字符串形式的版本號。 任何空格和/或注釋都會(huì )被移除。
- major?
整數形式的主版本號
- minor?
整數形式的次版本號
- class email.headerregistry.ParameterizedMIMEHeader?
MIME 標頭都以前綴 'Content-' 打頭。 每個(gè)特定標頭都具有特定的值,其描述在該標頭的類(lèi)之中。 有些也可以接受一個(gè)具有通用格式的補充形參形表。 這個(gè)類(lèi)被用作所有接受形參的 MIME 標頭的基類(lèi)。
- params?
一個(gè)將形參名映射到形參值的字典。
- class email.headerregistry.ContentTypeHeader?
處理 Content-Type 標頭的
ParameterizedMIMEHeader
類(lèi)。- content_type?
maintype/subtype
形式的內容類(lèi)型字符串。
- maintype?
- subtype?
- class email.headerregistry.ContentDispositionHeader?
處理 Content-Disposition 標頭的
ParameterizedMIMEHeader
類(lèi)。- content_disposition?
inline
和attachment
是僅有的常用有效值。
- class email.headerregistry.ContentTransferEncoding?
處理 Content-Transfer-Encoding 標頭。
- class email.headerregistry.HeaderRegistry(base_class=BaseHeader, default_class=UnstructuredHeader, use_default_map=True)?
這是由
EmailPolicy
在默認情況下使用的工廠(chǎng)函數。HeaderRegistry
會(huì )使用 base_class 和從它所保存的注冊表中獲取的專(zhuān)用類(lèi)來(lái)構建用于動(dòng)態(tài)地創(chuàng )建標頭實(shí)例的類(lèi)。 當給定的標頭名稱(chēng)未在注冊表中出現時(shí),則會(huì )使用由 default_class 所指定的類(lèi)作為專(zhuān)用類(lèi)。 當 use_default_map 為True
(默認值) 時(shí),則會(huì )在初始化期間把將標頭名稱(chēng)與類(lèi)的標準映射拷貝到注冊表中。 base_class 始終會(huì )是所生成類(lèi)的__bases__
列表中的最后一個(gè)類(lèi)。默認的映射有:
- subject
UniqueUnstructuredHeader
- date
UniqueDateHeader
- resent-date
DateHeader
- orig-date
UniqueDateHeader
- sender
UniqueSingleAddressHeader
- resent-sender
SingleAddressHeader
- 到
UniqueAddressHeader
- resent-to
AddressHeader
- cc
UniqueAddressHeader
- resent-cc
AddressHeader
- bcc
UniqueAddressHeader
- resent-bcc
AddressHeader
- 從
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 是要映射的標頭名稱(chēng)。 它將在注冊表中被轉換為小寫(xiě)形式。 cls 是要與 base_class 一起被用來(lái)創(chuàng )建用于實(shí)例化與 name 相匹配的標頭的類(lèi)的專(zhuān)用類(lèi)。
- __getitem__(name)?
構造并返回一個(gè)類(lèi)來(lái)處理 name 標頭的創(chuàng )建。
- __call__(name, value)?
從注冊表獲得與 name 相關(guān)聯(lián)的專(zhuān)用標頭 (如果 name 未在注冊表中出現則使用 default_class) 并將其與 base_class 相組合以產(chǎn)生類(lèi),調用被構造類(lèi)的構造器,傳入相同的參數列表,并最終返回由此創(chuàng )建的類(lèi)實(shí)例。
以下的類(lèi)是用于表示從結構化標頭解析的數據的類(lèi),并且通常會(huì )由應用程序使用以構造結構化的值并賦給特定的標頭。
- class email.headerregistry.Address(display_name='', username='', domain='', addr_spec=None)?
用于表示電子郵件地址的類(lèi)。 地址的一般形式為:
[display_name] <username@domain>
或者:
username@domain
其中每個(gè)部分都必須符合在 RFC 5322 中闡述的特定語(yǔ)法規則。
為了方便起見(jiàn)可以指定 addr_spec 來(lái)替代 username 和 domain,在此情況下 username 和 domain 將從 addr_spec 中解析。 addr_spec 應當是一個(gè)正確地引用了 RFC 的字符串;如果它不是
Address
則將引發(fā)錯誤。 Unicode 字符也允許使用并將在序列化時(shí)被正確地編碼。 但是,根據 RFC,地址的 username 部分 不允許 有 unicode。- display_name?
地址的顯示名稱(chēng)部分(如果有的話(huà))并去除所有引用項。 如果地址沒(méi)有顯示名稱(chēng),則此屬性將為空字符串。
- username?
地址的
username
部分,去除所有引用項。
- domain?
地址的
domain
部分。
- addr_spec?
地址的
username@domain
部分,經(jīng)過(guò)正確引用處理以作為純地址使用(上面顯示的第二種形式)。 此屬性不可變。
為了支持 SMTP (RFC 5321),
Address
會(huì )處理一種特殊情況:如果username
和domain
均為空字符串 (或為None
),則Address
的字符串值為<>
。
- class email.headerregistry.Group(display_name=None, addresses=None)?
用于表示地址組的類(lèi)。 地址組的一般形式為:
display_name: [address-list];
作為處理由組和單個(gè)地址混合構成的列表的便捷方式,
Group
也可以通過(guò)將 display_name 設為None
以用來(lái)表示不是某個(gè)組的一部分的單獨地址并提供單獨地址的列表作為 addresses。- display_name?
組的
display_name
。 如果其為None
并且恰好有一個(gè)Address
在addresses
中,則Group
表示一個(gè)不在某個(gè)組中的單獨地址。
備注