email.headerregistry: пользовательские объекты заголовков


Добавлено в версии 3.6: [1]

Заголовки представлены настраиваемыми str подклассами. Используемый для представления заголовка класс, определяется header_factory policy, действующим при создании заголовков. В этом разделе рассматривается header_factory, реализованный пакетом email для обработки сообщений электронной почты, совместимых с RFC 5322, который не только предоставляет настраиваемые объекты заголовков для различных типов заголовков, но также предоставляет механизм расширения для приложений, позволяющий добавлять свои настраиваемые типы заголовков.

При использовании любого из объектов политики, производных от EmailPolicy, все заголовки создаются HeaderRegistry и содержат BaseHeader в качестве последнего базового класса. Каждый класс заголовка содержит дополнительный базовый класс, определяемый типом заголовка. Например, у многих заголовков есть класс UnstructuredHeader в качестве другого базового класса. Специализированный второй класс для заголовка определяется именем заголовка с использованием таблицы поиска, хранящейся в HeaderRegistry. Все это управляется прозрачно для типичной прикладной программы, но предусмотрены интерфейсы для изменения поведения по умолчанию для использования более сложными приложениями.

В разделах ниже сначала описаны базовые классы заголовков и их атрибуты, затем API для изменения поведения HeaderRegistry и классы поддержки, используемые для представления данных, распарсенных из структурированных заголовков.

class email.headerregistry.BaseHeader(name, value)

name и value передаются в BaseHeader из вызова header_factory. Строковое значение любого объекта заголовка — value, полностью декодированное в Юникод.

Данный базовый класс определяет следующие свойства только для чтения:

name

Имя заголовка (часть поля перед «:»). Это именно то значение, которое было передано в вызове header_factory для name; т. е. регистр сохраняется.

defects

Кортеж из экземпляров HeaderDefect, сообщающих о любых проблемах с соответствием RFC, обнаруженных во время парсинга. Пакет email пытается завершить обнаружение проблем соответствия. См. модуль errors для обсуждения типов дефектов, о которых можно сообщать.

max_count

Максимальное количество заголовков данного типа, у которых может быть один и тот же name. Значение None означает неограниченное количество. Значение BaseHeader для этого атрибута — None; ожидается, что специализированные классы заголовков будут переопределять это значение по мере необходимости.

BaseHeader также предоставляет следующий метод, который вызывается кодом библиотеки email и обычно не должен вызываться прикладными программами:

fold(*, policy)

Возвращает строку, содержащую linesep символов, необходимую для правильного сворачивания заголовка в соответствии с policy. cte_type из 8bit будет рассматриваться как 7bit, поскольку заголовки не могут содержать произвольные двоичные данные. Если utf8 равен False, отличные от ASCII данные, будут закодированы как RFC 2047.

BaseHeader сам по себе не может использоваться для создания объекта заголовка. Он определяет протокол, с которым взаимодействует каждый специализированный заголовок для создания объекта заголовка. В частности, BaseHeader требует, чтобы специализированный класс предоставлял classmethod() с именем parse. Данный метод называется следующим образом:

parse(string, kwds)

kwds — это словарь, содержащий один предварительно инициализированный ключ defects. defects — пустой список. Метод парсинга должен добавлять в данный список все обнаруженные дефекты. По возвращении словарь kwds должен содержать значения как минимум для ключей decoded и defects. decoded должно быть строковым значением для заголовка (т. е. полностью декодированным в Юникод значением заголовка). Метод парсинга должен предполагать, что string может содержать части, закодированные при передаче содержимого, но также должен правильно обрабатывать все допустимые символы Юникода, чтобы он мог парсить незакодированные значения заголовков.

Затем BaseHeader __new__ создаёт экземпляр заголовка и вызывает его метод init. Специализированный класс должен предоставить метод init только в том случае, если он хочет установить дополнительные атрибуты помимо тех, которые предоставляются самим BaseHeader. Такой метод init должен выглядеть так:

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

Т. е. все лишнее, что специализированный класс помещает в словарь kwds, должно быть удалено и обработано, а оставшееся содержимое kwargs) передано в метод BaseHeader init.

class email.headerregistry.UnstructuredHeader

«Неструктурированный» заголовок — это тип заголовка по умолчанию в RFC 5322. Любой заголовок, не имеющий указанного синтаксиса, считается неструктурированным. Классический пример неструктурированного заголовка — заголовок Subject.

В RFC 5322 неструктурированный заголовок представляет собой множество произвольного текста в множестве ASCII символов. Однако у RFC 2047 есть совместимый с RFC 5322 механизм, для кодирования отличного от ASCII текста, в виде символов ASCII в значении заголовка. Когда содержащий закодированные слова value, передаётся конструктору, парсер UnstructuredHeader преобразует закодированные слова в Юникод, следуя правилам RFC 2047 для неструктурированного текста. Парсер использует эвристику, чтобы попытаться декодировать определённые несовместимые закодированные слова. В таких случаях регистрируются дефекты, а также дефекты по таким вопросам, как недопустимые символы в закодированных словах или незакодированный текст.

Данный тип заголовка не предоставляет никаких дополнительных атрибутов.

class email.headerregistry.DateHeader

RFC 5322 указывает очень специфический формат для дат в заголовках электронной почты. Парсер DateHeader распознает данный формат даты, а также распознает ряд вариантов форм, которые иногда встречаются «в дикой природе».

Данный тип заголовка предоставляет следующие дополнительные атрибуты:

datetime

Если значение заголовка может быть распознано как допустимая дата той или иной формы, данный атрибут будет содержать экземпляр datetime, представляющий эту дату. Если часовой пояс входной даты указан как -0000 (указывая, что он указан в формате UTC, но не содержит информации об исходном часовом поясе), тогда datetime будет наивным datetime. Если найдено определённое смещение часового пояса (включая +0000), то datetime будет содержать осведомленный datetime, который использует datetime.timezone для записи смещения часового пояса.

Значение заголовка decoded определяется путём форматирования datetime в соответствии с правилами RFC 5322; т. е. установлено:

email.utils.format_datetime(self.datetime)

При создании DateHeader value может быть экземпляром datetime. Это означает, например, что следующий код действителен и делает то, что можно было бы ожидать:

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

Поскольку это наивный datetime, он будет интерпретирован как временная метка UTC, а результирующее значение будет в часовом поясе -0000. Гораздо полезнее использовать функцию localtime() из модуля utils:

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

В этом примере заголовок даты задается текущим временем и датой, используя текущее смещение часового пояса.

class email.headerregistry.AddressHeader

Заголовки адресов являются одним из наиболее сложных структурированных типов заголовков. Класс AddressHeader предоставляет общий интерфейс для любого заголовка адреса.

Данный тип заголовка предоставляет следующие дополнительные атрибуты:

groups

Кортеж из объектов Group, кодирующих адреса и группы, найденные в значении заголовка. Адреса, не входящие в группу, представлены в этом списке как одноадресный Groups, display_name который None.

addresses

Кортеж из объектов Address, кодирующих все отдельные адреса из значения заголовка. Если значение заголовка содержит какие-либо группы, отдельные адреса из группы включаются в список в той точке, где группа встречается в значении (т. е. список адресов «сглаживается» до одномерного списка).

Значение заголовка decoded будет иметь все закодированные слова, декодированные в Юникод. Доменные имена в кодировке idna также декодируются в Юникод. Значение decoded задается join значением str элементов атрибута groups с ', '.

Список объектов Address и Group в любой комбинации может использоваться для установки значения заголовка адреса. Объекты Group, чей display_name равен None, будут интерпретироваться как одиночные адреса, что позволяет копировать список адресов с целыми группами, используя список, полученный из атрибута groups исходного заголовка.

class email.headerregistry.SingleAddressHeader

Подкласс AddressHeader, добавляющий один дополнительный атрибут:

address

Единственный адрес, закодированный значением заголовка. Если значение заголовка на самом деле содержит более одного адреса (что было бы нарушением RFC по умолчанию policy), доступ к этому атрибуту приведёт к ValueError.

Многие из вышеперечисленных классов также содержат вариант Unique (например, UniqueUnstructuredHeader). Единственное отличие состоит в том, что в варианте Unique для max_count установлено значение 1.

class email.headerregistry.MIMEVersionHeader

На самом деле существует только одно допустимое значение для заголовка MIME-Version1.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

inline и attachment являются единственными общепринятыми допустимыми значениями.

class email.headerregistry.ContentTransferEncoding

Обрабатывает заголовок Content-Transfer-Encoding.

cte

Допустимые значения: 7bit, 8bit, base64 и quoted- 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_map равен True (по умолчанию), стандартное сопоставление имён заголовков с классами копируется в реестр во время инициализации. 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 (используя default_class, если name не отображается в реестре) и объединяет его с base_class для создания класса, вызывает конструктор созданного класса, передавая ему тот же список аргументов и возвращает класс созданный таким образом экземпляр.

Следующие классы — это классы, используемые для представления данных, распарсенных из структурированных заголовков, и, как правило, могут использоваться прикладной программой для создания структурированных значений для назначения определенным заголовкам.

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

Класс, используемый для представления адреса электронной почты. Общая форма адреса такова:

[display_name] <username@domain>

или:

username@domain

где каждая часть должна соответствовать определенным правилам синтаксиса, изложенным в RFC 5322.

Для удобства можно указать addr_spec вместо username и domain, и в этом случае username и domain будут распарсенны из addr_spec. Строка addr_spec должна быть правильно заключена в RFC кавычки; если это не Address, возникнет ошибка. Разрешены символы Юникода, и они будут закодированы свойством при сериализации. Тем не менее, в соответствии с документами RFC, в части имени пользователя в адресе не разрешен Юникод.

display_name

Часть отображаемого имени адреса, если таковая имеется, с удаленными кавычками. Если адрес не имеет отображаемого имени, данный атрибут будет пустой строкой.

username

Часть адреса username с удаленными кавычками.

domain

Часть адреса domain.

addr_spec

Часть адреса username@domain, правильно указанная для использования в качестве простого адреса (вторая форма показана выше). Данный атрибут не является изменяемым.

__str__()

Значение str объекта — это адрес, указанный в соответствии с правилами RFC 5322, но без кодирования передачи содержимого любых символов, отличных от ASCII.

Для поддержки SMTP (RFC 5321) Address обрабатывает один особый случай: если username и domain являются пустой строкой (или None), то строковое значение Address равно <>.

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

Класс, используемый для представления группы адресов. Общая форма адресной группы такова:

display_name: [address-list];

Для удобства обработки списков адресов, состоящих из смеси групп и отдельных адресов, Group также можно использовать для представления отдельных адресов, не входящих в группу, установив display_name на None и предоставив список одного адреса как addresses.

display_name

display_name группы. Если это None и в addresses есть ровно один Address, то Group представляет собой один адрес, не входящий в группу.

addresses

Возможно, пустой кортеж объектов Address, представляющих адреса в группе.

__str__()

Значение str Group отформатировано в соответствии с RFC 5322, но без кодирования передачи содержимого любых символов, отличных от ASCII. Если display_name отсутствует и в списке addresses есть один Address, значение str будет таким же, как str данного Address.

Сноски

[1]Первоначально добавлен в 3.3 как предварительный модуль