> **Источник:** https://python-all.ru/3.3/library/email.headerregistry.html
>
> «Документация Python на русском» – неофициальный перевод официальной документации Python: версии от 2.6 до 3.16, полнотекстовый поиск, английский оригинал рядом с переводом. Эта Markdown-версия страницы предназначена для работы с LLM: вставьте её в ChatGPT, Claude или Cursor.

---

# 19.1.5. [`email.headerregistry`](https://python-all.ru/3.3/library/email.headerregistry.html#module-email.headerregistry): Пользовательские объекты заголовков

> **Примечание**
>
> Модуль headerregistry был включён в стандартную библиотеку на [*временной основе*](https://python-all.ru/3.3/glossary.html#term-provisional-package). Обратно несовместимые изменения (вплоть до удаления модуля) могут произойти, если основные разработчики сочтут это необходимым.

Новое в версии 3.3: в качестве [*временного модуля*](https://python-all.ru/3.3/glossary.html#term-provisional-package).

Headers are represented by customized subclasses of [`str`](https://python-all.ru/3.3/library/stdtypes.html#str). The particular class used to represent a given header is determined by the [`header_factory`](https://python-all.ru/3.3/library/email.policy.html#email.policy.EmailPolicy.header_factory) of the [`policy`](https://python-all.ru/3.3/library/email.policy.html#module-email.policy) in effect when the headers are created. This section documents the particular `header_factory` implemented by the email package for handling [**RFC 5322**](https://python-all.ru/3.3/library/email.headerregistry.html) compliant email messages, which not only provides customized header objects for various header types, but also provides an extension mechanism for applications to add their own custom header types.

При использовании любого из объектов политики, производных от [`EmailPolicy`](https://python-all.ru/3.3/library/email.policy.html#email.policy.EmailPolicy), все заголовки создаются через [`HeaderRegistry`](https://python-all.ru/3.3/library/email.headerregistry.html#email.headerregistry.HeaderRegistry) и имеют [`BaseHeader`](https://python-all.ru/3.3/library/email.headerregistry.html#email.headerregistry.BaseHeader) в качестве своего последнего базового класса. Каждый класс заголовка имеет дополнительный базовый класс, который определяется типом заголовка. Например, многие заголовки имеют класс [`UnstructuredHeader`](https://python-all.ru/3.3/library/email.headerregistry.html#email.headerregistry.UnstructuredHeader) в качестве второго базового класса. Специализированный второй класс для заголовка определяется его именем с помощью таблицы поиска, хранящейся в [`HeaderRegistry`](https://python-all.ru/3.3/library/email.headerregistry.html#email.headerregistry.HeaderRegistry). Все это прозрачно для типичного приложения, однако предоставляются интерфейсы для изменения поведения по умолчанию для использования более сложными приложениями.

В приведенных ниже разделах сначала документируются базовые классы заголовков и их атрибуты, затем описывается API для изменения поведения [`HeaderRegistry`](https://python-all.ru/3.3/library/email.headerregistry.html#email.headerregistry.HeaderRegistry), и, наконец, вспомогательные классы, используемые для представления данных, извлеченных из структурированных заголовков.

#### `class email.headerregistry.BaseHeader(name, value)`

*name* и *value* передаются в `BaseHeader` из вызова [`header_factory`](https://python-all.ru/3.3/library/email.policy.html#email.policy.EmailPolicy.header_factory). Строковое значение любого объекта заголовка – это *value*, полностью декодированное в Unicode.

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

#### `name`

Имя заголовка (часть поля до двоеточия). Это в точности то значение, которое передается в вызове [`header_factory`](https://python-all.ru/3.3/library/email.policy.html#email.policy.EmailPolicy.header_factory) для *name*; при этом регистр сохраняется.

#### `defects`

Кортеж экземпляров `HeaderDefect`, сообщающих о любых проблемах соответствия RFC, обнаруженных при разборе. Пакет email старается максимально полно выявлять проблемы с соответствием. См. модуль [`errors`](https://python-all.ru/3.3/library/email.errors.html#module-email.errors) для обсуждения типов дефектов, которые могут быть зарегистрированы.

#### `max_count`

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

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

#### `fold(*, policy)`

Возвращает строку, содержащую символы [`linesep`](https://python-all.ru/3.3/library/email.policy.html#email.policy.Policy.linesep), необходимые для корректного сворачивания заголовка в соответствии с *policy*. Значение [`cte_type`](https://python-all.ru/3.3/library/email.policy.html#email.policy.Policy.cte_type) равное `8bit` будет обрабатываться так, как если бы оно было `7bit`, поскольку строки не могут содержать двоичные данные.

`BaseHeader` сам по себе не может быть использован для создания объекта заголовка. Он определяет протокол, с которым взаимодействует каждый специализированный заголовок для создания объекта заголовка. В частности, `BaseHeader` требует, чтобы специализированный класс предоставлял [`classmethod()`](https://python-all.ru/3.3/library/functions.html#classmethod) с именем `parse`. Этот метод вызывается следующим образом:

```python
parse(string, kwds)
```

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

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

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

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

#### `class email.headerregistry.UnstructuredHeader`

«Неструктурированный» заголовок – это тип заголовка по умолчанию в [**RFC 5322**](https://python-all.ru/3.3/library/email.headerregistry.html). Любой заголовок, не имеющий заданного синтаксиса, считается неструктурированным. Классический пример неструктурированного заголовка – *Subject*.

В [**RFC 5322**](https://python-all.ru/3.3/library/email.headerregistry.html) неструктурированный заголовок представляет собой последовательность произвольных текстовых символов из набора ASCII. Однако [**RFC 2047**](https://python-all.ru/3.3/library/email.headerregistry.html) предоставляет совместимый с [**RFC 5322**](https://python-all.ru/3.3/library/email.headerregistry.html) механизм кодирования не-ASCII текста в виде ASCII символов внутри значения заголовка. Когда *value*, содержащее закодированные слова, передается конструктору, анализатор `UnstructuredHeader` преобразует такие закодированные слова обратно в исходный Unicode в соответствии с правилами [**RFC 2047**](https://python-all.ru/3.3/library/email.headerregistry.html) для неструктурированного текста. Анализатор использует эвристики для попытки декодирования некоторых некорректных закодированных слов. В таких случаях регистрируются дефекты, а также дефекты для таких проблем, как недопустимые символы внутри закодированных слов или незакодированного текста.

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

#### `class email.headerregistry.DateHeader`

[**RFC 5322**](https://python-all.ru/3.3/library/email.headerregistry.html) определяет очень конкретный формат для дат в заголовках электронной почты. Анализатор `DateHeader` распознает этот формат даты, а также ряд вариантов, которые иногда встречаются «в дикой природе».

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

#### `datetime`

Если значение заголовка может быть распознано как допустимая дата в той или иной форме, этот атрибут будет содержать экземпляр [`datetime`](https://python-all.ru/3.3/library/datetime.html#datetime.datetime), представляющий эту дату. Если часовой пояс входной даты указан как `-0000` (что означает, что дата указана в UTC, но не содержит информации об исходном часовом поясе), то [`datetime`](https://python-all.ru/3.3/library/email.headerregistry.html#email.headerregistry.DateHeader.datetime) будет наивным [`datetime`](https://python-all.ru/3.3/library/datetime.html#datetime.datetime). Если найден конкретный сдвиг часового пояса (включая *+0000*), то [`datetime`](https://python-all.ru/3.3/library/email.headerregistry.html#email.headerregistry.DateHeader.datetime) будет содержать осведомленный `datetime`, который использует [`datetime.timezone`](https://python-all.ru/3.3/library/datetime.html#datetime.timezone) для записи сдвига часового пояса.

Значение `decoded` заголовка определяется путем форматирования `datetime` в соответствии с правилами [**RFC 5322**](https://python-all.ru/3.3/library/email.headerregistry.html); то есть оно устанавливается в:

```python
email.utils.format_datetime(self.datetime)
```

При создании `DateHeader` *value* может быть экземпляром [`datetime`](https://python-all.ru/3.3/library/datetime.html#datetime.datetime). Это означает, например, что следующий код корректен и делает то, что ожидается:

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

Поскольку это наивный `datetime`, он будет интерпретирован как временная метка UTC, и результирующее значение будет иметь часовой пояс `-0000`. Гораздо полезнее использовать функцию [`localtime()`](https://python-all.ru/3.3/library/email.util.html#email.utils.localtime) из модуля [`utils`](https://python-all.ru/3.3/library/email.util.html#module-email.utils):

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

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

#### `class email.headerregistry.AddressHeader`

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

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

#### `groups`

Кортеж объектов [`Group`](https://python-all.ru/3.3/library/email.headerregistry.html#email.headerregistry.Group), кодирующих адреса и группы, найденные в значении заголовка. Адреса, не входящие в группу, представлены в этом списке как `Groups` с одним адресом, у которых [`display_name`](https://python-all.ru/3.3/library/email.headerregistry.html#email.headerregistry.Group.display_name) равен `None`.

#### `addresses`

Кортеж объектов [`Address`](https://python-all.ru/3.3/library/email.headerregistry.html#email.headerregistry.Address), кодирующих все отдельные адреса из значения заголовка. Если значение заголовка содержит какие-либо группы, отдельные адреса из группы включаются в список в том месте, где эта группа встречается в значении (то есть список адресов сводится к одномерному списку).

`Декодированное` значение заголовка будет содержать все закодированные слова, декодированные в Юникод. [`idna`](https://python-all.ru/3.3/library/codecs.html#module-encodings.idna)-закодированные доменные имена также декодируются в Юникод. `Декодированное` значение устанавливается объединением ([`join`](https://python-all.ru/3.3/library/stdtypes.html#str.join)) строковых представлений ([`str`](https://python-all.ru/3.3/library/stdtypes.html#str)) элементов атрибута `groups` с `', '`.

Список объектов [`Address`](https://python-all.ru/3.3/library/email.headerregistry.html#email.headerregistry.Address) и [`Group`](https://python-all.ru/3.3/library/email.headerregistry.html#email.headerregistry.Group) в любом сочетании может использоваться для установки значения заголовка адреса. Объекты `Group`, у которых `display_name` равен `None`, будут интерпретироваться как отдельные адреса, что позволяет копировать список адресов с сохранением групп, используя список, полученный из атрибута `groups` исходного заголовка.

#### `class email.headerregistry.SingleAddressHeader`

Подкласс [`AddressHeader`](https://python-all.ru/3.3/library/email.headerregistry.html#email.headerregistry.AddressHeader), добавляющий один дополнительный атрибут:

#### `address`

Единственный адрес, закодированный значением заголовка. Если значение заголовка фактически содержит более одного адреса (что является нарушением RFC при использовании политики по умолчанию [`policy`](https://python-all.ru/3.3/library/email.policy.html#module-email.policy)), обращение к этому атрибуту приведёт к [`ValueError`](https://python-all.ru/3.3/library/exceptions.html#ValueError).

Многие из перечисленных классов также имеют вариант `Unique` (например, `UniqueUnstructuredHeader`). Единственное отличие состоит в том, что в варианте `Unique` параметр [`max_count`](https://python-all.ru/3.3/library/email.headerregistry.html#email.headerregistry.BaseHeader.max_count) установлен в 1.

#### `class email.headerregistry.MIMEVersionHeader`

На самом деле для заголовка *MIME-Version* существует только одно допустимое значение – `1.0`. Для обеспечения совместимости в будущем этот класс заголовков поддерживает и другие допустимые номера версий. Если номер версии соответствует допустимому значению согласно [**RFC 2045**](https://python-all.ru/3.3/library/email.headerregistry.html), то объект заголовка будет иметь не `None` значения следующих атрибутов:

#### `version`

Номер версии в виде строки, из которой удалены все пробелы и/или комментарии.

#### `major`

Номер основной версии в виде целого числа.

#### `minor`

Номер дополнительной версии в виде целого числа.

#### `class email.headerregistry.ParameterizedMIMEHeader`

Все MIME-заголовки начинаются с префикса «Content-». Каждый конкретный заголовок имеет определённое значение, описанное в соответствующем классе. Некоторые могут также принимать список дополнительных параметров, имеющих общий формат. Этот класс служит базовым для всех MIME-заголовков, принимающих параметры.

#### `params`

Словарь, сопоставляющий имена параметров со значениями параметров.

#### `class email.headerregistry.ContentTypeHeader`

Класс [`ParameterizedMIMEHeader`](https://python-all.ru/3.3/library/email.headerregistry.html#email.headerregistry.ParameterizedMIMEHeader), обрабатывающий заголовок *Content-Type*.

#### `content_type`

Строка типа содержимого в формате `maintype/subtype`.

#### `maintype`

#### `subtype`

#### `class email.headerregistry.ContentDispositionHeader`

Класс [`ParameterizedMIMEHeader`](https://python-all.ru/3.3/library/email.headerregistry.html#email.headerregistry.ParameterizedMIMEHeader), обрабатывающий заголовок *Content-Disposition*.

#### `content-disposition`

`inline` и `attachment` – единственные допустимые значения, используемые на практике.

#### `class email.headerregistry.ContentTransferEncoding`

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

#### `cte`

Допустимые значения: `7bit`, `8bit`, `base64` и `quoted-printable`. Дополнительную информацию см. в [**RFC 2045**](https://python-all.ru/3.3/library/email.headerregistry.html).

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

Это фабрика, используемая по умолчанию объектом [`EmailPolicy`](https://python-all.ru/3.3/library/email.policy.html#email.policy.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 |
> | from: | UniqueAddressHeader |
> | resent-from: | AddressHeader |
> | reply-to: | UniqueAddressHeader |

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

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

```python
[display_name] <username@domain>
```

или:

```python
username@domain
```

где каждая часть должна соответствовать определённым правилам синтаксиса, изложенным в [**RFC 5322**](https://python-all.ru/3.3/library/email.headerregistry.html).

В целях удобства вместо *addr\_spec* можно указать *username* и *domain*; в этом случае *username* и *domain* будут извлечены из *addr\_spec*. *addr\_spec* должна быть правильно процитированной строкой в формате RFC; если это не так, `Address` вызовет ошибку. Допускаются символы Unicode, которые будут соответствующим образом закодированы при сериализации. Однако согласно RFC, Unicode *не* допускается в части имени пользователя (username).

#### `display_name`

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

#### `username`

Часть адреса `username`, из которой удалены все кавычки.

#### `domain`

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

#### `addr_spec`

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

#### `__str__()`

Строковое значение `str` объекта – это адрес, процитированный в соответствии с правилами [**RFC 5322**](https://python-all.ru/3.3/library/email.headerregistry.html), но без кодирования пересылки содержимого для любых не-ASCII символов.

Для поддержки SMTP ([**RFC 5321**](https://python-all.ru/3.3/library/email.headerregistry.html)) класс `Address` обрабатывает один особый случай: если `username` и `domain` оба являются пустыми строками (или `None`), то строковое значение `Address` равно `<>`.

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

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

```python
display_name: [address-list];
```

Для удобства обработки списков адресов, состоящих из смеси групп и отдельных адресов, `Group` может также использоваться для представления отдельных адресов, не входящих в группу, путём установки *display\_name* в `None` и передачи списка из одного адреса в качестве *addresses*.

#### `display_name`

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

#### `addresses`

Возможно пустой кортеж объектов [`Address`](https://python-all.ru/3.3/library/email.headerregistry.html#email.headerregistry.Address), представляющих адреса в группе.

#### `__str__()`

Строковое значение `str` объекта `Group` форматируется в соответствии с [**RFC 5322**](https://python-all.ru/3.3/library/email.headerregistry.html), но без кодирования пересылки содержимого для любых не-ASCII символов. Если `display_name` равно none и в списке `addresses` есть единственный `Address`, то строковое значение `str` будет таким же, как `str` этого единственного `Address`.
