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

---

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

**Исходный код:** [Lib/email/headerregistry.py](https://python-all.ru/src/3.6/Lib/email/headerregistry.py)

---

Новое в версии 3.6: [1](https://python-all.ru/3.6/library/email.headerregistry.html#id2)

Заголовки представлены настраиваемыми подклассами [`str`](https://python-all.ru/3.6/library/stdtypes.html#str). Конкретный класс, используемый для представления данного заголовка, определяется [`header_factory`](https://python-all.ru/3.6/library/email.policy.html#email.policy.EmailPolicy.header_factory) [`policy`](https://python-all.ru/3.6/library/email.policy.html#module-email.policy), действующей на момент создания заголовков. В этом разделе описаны конкретные `header_factory`, реализованные в пакете email для обработки [**RFC 5322**](https://python-all.ru/3.6/library/email.headerregistry.html)-совместимых сообщений электронной почты. Они не только предоставляют настраиваемые объекты заголовков для различных типов заголовков, но и содержат механизм расширения, позволяющий приложениям добавлять собственные типы заголовков.

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

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

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

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

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

#### `name`

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

#### `defects`

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

#### `max_count`

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

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

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

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

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

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

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

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

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

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

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

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

In [**RFC 5322**](https://python-all.ru/3.6/library/email.headerregistry.html), an unstructured header is a run of arbitrary text in the ASCII character set. [**RFC 2047**](https://python-all.ru/3.6/library/email.headerregistry.html), however, has an [**RFC 5322**](https://python-all.ru/3.6/library/email.headerregistry.html) compatible mechanism for encoding non-ASCII text as ASCII characters within a header value. When a *value* containing encoded words is passed to the constructor, the `UnstructuredHeader` parser converts such encoded words into unicode, following the [**RFC 2047**](https://python-all.ru/3.6/library/email.headerregistry.html) rules for unstructured text. The parser uses heuristics to attempt to decode certain non-compliant encoded words. Defects are registered in such cases, as well as defects for issues such as invalid characters within the encoded words or the non-encoded text.

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

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

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

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

#### `datetime`

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

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

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

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

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

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

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

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

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

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

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

#### `groups`

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

#### `addresses`

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

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

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

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

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

#### `address`

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

Многие из перечисленных выше классов также имеют вариант `Unique` (например, `UniqueUnstructuredHeader`). Единственное отличие состоит в том, что в варианте `Unique` [`max_count`](https://python-all.ru/3.6/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.6/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.6/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.6/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.6/library/email.headerregistry.html).

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

Это фабрика, используемая [`EmailPolicy`](https://python-all.ru/3.6/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
>
> **на**
>
> 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.6/library/email.headerregistry.html).

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

#### `display_name`

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

#### `username`

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

#### `domain`

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

#### `addr_spec`

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

#### `__str__()`

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

Для поддержки SMTP ([**RFC 5321**](https://python-all.ru/3.6/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.6/library/email.headerregistry.html#email.headerregistry.Address), представляющих адреса в группе.

#### `__str__()`

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

Сноски

**[1](https://python-all.ru/3.6/library/email.headerregistry.html#id1)**

Изначально добавлен в версии 3.3 как [временный модуль](https://python-all.ru/3.6/glossary.html#term-provisional-package)
