# `email.headerregistry`: Custom Header Objects

Вихідний код: Lib/email/headerregistry.py

Нове в версії 3.6: 1

Заголовки представлені налаштованими підкласами `str`. Конкретний клас, який використовується для представлення даного заголовка, визначається `header_factory` `policy`, що діє під час створення заголовків. У цьому розділі описано конкретну `header_factory`, реалізовану пакетом електронної пошти для обробки RFC 5322 сумісних повідомлень електронної пошти, яка не тільки надає налаштовані об’єкти заголовків для різних типів заголовків, але також забезпечує механізм розширення для додатків для додавання своїх власні типи заголовків.

При використанні будь-якого з об’єктів політики, отриманих від `EmailPolicy`, усі заголовки створюються `HeaderRegistry` і мають `BaseHeader` як останній базовий клас. Кожен клас заголовка має додатковий базовий клас, який визначається типом заголовка. Наприклад, багато заголовків мають клас `UnstructuredHeader` як інший базовий клас. Спеціалізований другий клас для заголовка визначається назвою заголовка за допомогою таблиці пошуку, що зберігається в `HeaderRegistry`. Усім цим керується прозоро для типової прикладної програми, але надаються інтерфейси для зміни типової поведінки для використання більш складними програмами.

У розділах нижче спочатку описані базові класи заголовків та їх атрибути, потім API для зміни поведінки `HeaderRegistry` і, нарешті, класи підтримки, які використовуються для представлення даних, проаналізованих із структурованих заголовків.

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

  name і value передаються в `BaseHeader` з виклику `header_factory`. Рядкове значення будь-якого об’єкта заголовка є значенням, повністю декодованим у Юнікод.

  Цей базовий клас визначає наступні властивості лише для читання:

  `name`

    Назва заголовка (частина поля перед «:»). Це саме значення, передане у виклику `header_factory` для name; тобто регістр зберігається.

  `defects`

    Кортеж екземплярів `HeaderDefect`, які повідомляють про будь-які проблеми відповідності RFC, виявлені під час аналізу. Пакет електронної пошти намагається бути повним щодо виявлення проблем відповідності. Перегляньте модуль `errors` для обговорення типів дефектів, про які можна повідомити.

  `max_count`

    Максимальна кількість заголовків цього типу, які можуть мати однакову назву. Значення `None` означає необмежений. Значення `BaseHeader` для цього атрибута є `None`; очікується, що спеціалізовані класи заголовків замінять це значення за потреби.

  `BaseHeader` також надає наступний метод, який викликається кодом бібліотеки електронної пошти і, як правило, не повинен викликатися прикладними програмами:

  `fold`(*, policy)

    Повертає рядок, що містить символи `linesep`, необхідні для правильного згортання заголовка відповідно до policy. `cte_type` `8bit` буде розглядатися як `7bit`, оскільки заголовки не можуть містити довільних двійкових даних. Якщо `utf8` має значення `False`, дані, відмінні від ASCII, будуть закодовані RFC 2047.

  `BaseHeader` сам по собі не може використовуватися для створення об’єкта заголовка. Він визначає протокол, з яким співпрацює кожен спеціалізований заголовок, щоб створити об’єкт заголовка. Зокрема, `BaseHeader` вимагає, щоб спеціалізований клас надавав `classmethod()` під назвою `parse`. Цей метод називається наступним чином:

      parse(string, kwds)

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

  Потім `__new__` `BaseHeader` створює екземпляр заголовка та викликає його метод `init`. Спеціалізованому класу потрібно лише надати метод `init`, якщо він бажає встановити додаткові атрибути крім тих, що надаються самим `BaseHeader`. Такий метод `init` має виглядати так:

      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. Будь-який заголовок, який не має визначеного синтаксису, вважається неструктурованим. Класичним прикладом неструктурованого заголовка є заголовок Subject.

  У RFC 5322 неструктурований заголовок — це довільний текст у наборі символів ASCII. RFC 2047, однак, має RFC 5322 сумісний механізм для кодування не-ASCII тексту як символів ASCII у значенні заголовка. Коли значення, що містить закодовані слова, передається конструктору, аналізатор `UnstructuredHeader` перетворює такі закодовані слова в юнікод, дотримуючись правил RFC 2047 для неструктурованого тексту. Синтаксичний аналізатор використовує евристику, щоб спробувати декодувати певні невідповідні закодовані слова. У таких випадках реєструються дефекти, а також такі дефекти, як недійсні символи в закодованих словах або незакодований текст.

  Цей тип заголовка не містить додаткових атрибутів.

class `email.headerregistry.``DateHeader`

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

  Цей тип заголовка надає такі додаткові атрибути:

  `datetime`

    If the header value can be recognized as a valid date of one form or another, this attribute will contain a `datetime` instance representing that date. If the timezone of the input date is specified as `-0000` (indicating it is in UTC but contains no information about the source timezone), then `datetime` will be a naive `datetime`. If a specific timezone offset is found (including `+0000`), then `datetime` will contain an aware `datetime` that uses `datetime.timezone` to record the timezone offset.

  Значення `decoded` заголовка визначається форматуванням `datetime` відповідно до правил RFC 5322; тобто встановлено:

      email.utils.format_datetime(self.datetime)

  Під час створення `DateHeader` значення може бути екземпляром `datetime`. Це означає, наприклад, що наступний код дійсний і виконує те, що можна очікувати:

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

  Оскільки це проста `datetime`, вона буде інтерпретована як мітка часу UTC, а результуюче значення матиме часовий пояс `-0000`. Набагато кориснішим є використання функції `localtime()` з модуля `utils`:

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

  У цьому прикладі в заголовку дати встановлюється поточний час і дата з використанням поточного зміщення часового поясу.

class `email.headerregistry.``AddressHeader`

  Заголовки адрес є одним із найскладніших структурованих типів заголовків. Клас `AddressHeader` забезпечує загальний інтерфейс для будь-якого заголовка адреси.

  Цей тип заголовка надає такі додаткові атрибути:

  `groups`

    Кортеж об’єктів `Group`, що кодує адреси та групи, знайдені у значенні заголовка. Адреси, які не є частиною групи, представлені в цьому списку як одноадресні `Групи`, у яких `display_name` має значення `None`.

  `addresses`

    Кортеж об’єктів `Address`, що кодує всі окремі адреси зі значення заголовка. Якщо значення заголовка містить будь-які групи, окремі адреси з групи включаються до списку в тому місці, де група зустрічається у значенні (тобто список адрес «зрівнюється» в одновимірний список).

  The `decoded` value of the header will have all encoded words decoded to unicode. `idna` encoded domain names are also decoded to unicode. The `decoded` value is set by `join`ing the `str` value of the elements of the `groups` attribute with `', '`.

  Для встановлення значення заголовка адреси можна використовувати список об’єктів `Address` і `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-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`

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

  This is the factory used by `EmailPolicy` by default. `HeaderRegistry` builds the class used to create a header instance dynamically, using base_class and a specialized class retrieved from a registry that it holds. When a given header name does not appear in the registry, the class specified by default_class is used as the specialized class. When use_default_map is `True` (the default), the standard mapping of header names to classes is copied in to the registry during initialization. base_class is always the last class in the generated class’s `__bases__` list.

  Відображення за замовчуванням:

  > тема

  >   UniqueUnstructuredHeader

  > дата

  >   UniqueDateHeader

  > дата повторного відправлення

  >   DateHeader

  > дата виходу

  >   UniqueDateHeader

  > відправник

  >   UniqueSingleAddressHeader

  > resent-sender

  >   SingleAddressHeader

  > до

  >   UniqueAddressHeader

  > обурюватися

  >   AddressHeader

  > cc

  >   UniqueAddressHeader

  > resent-cc

  >   AddressHeader

  > прихована копія

  >   UniqueAddressHeader

  > resent-bcc

  >   AddressHeader

  > від

  >   UniqueAddressHeader

  > обурюватися-від

  >   AddressHeader

  > відповідати на

  >   UniqueAddressHeader

  > мім-версія

  >   MIMEVersionHeader

  > тип вмісту

  >   ContentTypeHeader

  > зміст-диспозиція

  >   ContentDispositionHeader

  > кодування передачі вмісту

  >   ContentTransferEncodingHeader

  > ідентифікатор повідомлення

  >   MessageIDHeader

  `HeaderRegistry` має такі методи:

  `map_to_type`(self, name, cls)

    ім’я — це ім’я заголовка, який буде зіставлено. У реєстрі його буде перетворено на нижній регістр. 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`

    Частина `ім’я користувача` адреси з видаленням лапок.

  `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];

  Для зручності обробки списків адрес, які складаються з суміші груп і окремих адрес, `Група` також може використовуватися для представлення окремих адрес, які не є частиною групи, встановивши display_name на `None` і надання списку однієї адреси як адрес.

  `display_name`

    `display_name` групи. Якщо значення `None` і в `адресах` є точно одна `Адреса`, тоді `Група` представляє одну адресу, яка не входить до групи.

  `addresses`

    Можливо, порожній кортеж об’єктів `Address`, що представляє адреси в групі.

  `__str__`()

    Значення `str` `Group` відформатовано відповідно до RFC 5322, але без кодування передачі вмісту будь-яких символів, відмінних від ASCII. Якщо `display_name` не має значення, а в списку `addresses` є одна `Address`, значення `str` буде таким самим, як `str` цього одного `Address`.

Виноски

1

  Спочатку додано в 3.3 як проміжний модуль