email.header: интернационализированные заголовки


Данный модуль является частью устаревшего API электронной почты (Compat32). В текущем API кодирование и декодирование заголовков прозрачно обрабатывается подобным словарю API класса EmailMessage. Помимо использования в устаревшем коде, данный модуль может быть полезен в приложениях, которым необходимо полностью контролировать используемые при кодировании заголовков наборы символов.

Остальной текст в этом разделе является оригинальной документацией модуля.

RFC 2822 — это базовый стандарт, определяющий формат сообщений электронной почты. Он основан на более старом стандарте RFC 822, который получил широкое распространение в то время, когда большая часть электронной почты состояла только из ASCII символов. RFC 2822 — это спецификация, написанная в предположении, что электронная почта содержит только 7-битные ASCII символы.

Конечно, по мере распространения электронной почты по всему миру она стала интернационализированной, так что теперь в сообщениях электронной почты можно использовать наборы символов для разных языков. Базовый стандарт по- прежнему требует, чтобы сообщения электронной почты передавались с использованием только 7-битных символов ASCII, поэтому было написано множество RFC, определяющих, как кодировать электронную почту, содержащую отличные от ASCII символы, в совместимый с RFC 2822 форматом. Данные RFC включают RFC 2045, RFC 2046, RFC 2047 и RFC 2231. Пакет email поддерживает данные стандарты в своих модулях email.header и email.charset.

Если вы хотите включить отличные от ASCII символы в заголовки электронной почты, скажем, в поля Subject или To, вам следует использовать класс Header и назначить поле в объекте Message экземпляром Header вместо использования строки для значения заголовка. Для этого импортируйте класс Header из модуля email.header. Например:

>>> from email.message import Message
>>> from email.header import Header
>>> msg = Message()
>>> h = Header('p\xf6stal', 'iso-8859-1')
>>> msg['Subject'] = h
>>> msg.as_string()
'Subject: =?iso-8859-1?q?p=F6stal?=\n\n'

Обратите внимание, как мы хотели, чтобы поле Subject содержало символ, отличный от ASCII. Мы сделали это, создав экземпляр Header и передав множество символов, в котором была закодирована строка байтов. Когда последующий экземпляр Message был сплющен, поле Subject было правильно закодировано RFC 2047. Читатели почты с поддержкой MIME будут отображать данный заголовок, используя встроенный символ ISO-8859-1.

Вот описание класса Header:

class email.header.Header(s=None, charset=None, maxlinelen=None, header_name=None, continuation_ws=' ', errors='strict')

Создаёт заголовок, совместимый с MIME, который может содержать строки с разными наборами символов.

Необязательный s — это начальное значение заголовка. Если None (по умолчанию), начальное значение заголовка не устанавливается. Позже вы можете добавить к заголовку вызовы метода append(). s может быть экземпляром bytes или str, но семантику см. в документации append().

Необязательный charset служит двум целям: он имеет то же значение, что и аргумент charset метода append(). Он также устанавливает множество символов по умолчанию для всех последующих вызовов append(), в которых отсутствует аргумент charset. Если charset не указан в конструкторе (по умолчанию), множество символов us-ascii используется как в качестве исходного набора символов s, так и по умолчанию для последующих вызовов append().

Максимальная длина строки может быть указана явно через maxlinelen. Для разделения первой строки на более короткое значение (для учёта заголовка поля, который не включён в s, например, Subject), передайте имя поля в header_name. Значение по умолчанию maxlinelen — 76, а значение по умолчанию для header_nameNone, т. е. оно не учитывается для первой строки длинного разделённого заголовка.

Необязательный continuation_ws должен быть RFC 2822 -совместимым складным (folding) пробелом и обычно является либо пробелом, либо жёстким символом табуляции. Данный символ будет добавлен к строкам продолжения. continuation_ws по умолчанию — один пробел.

Необязательный errors передаётся прямо в метод append().

append(s, charset=None, errors='strict')

Добавляет строку s к MIME заголовку.

Если задан необязательный charset, должен быть экземпляром Charset (см. email.charset) или именем набора символов, который будет преобразован в экземпляр Charset. Значение None (по умолчанию) означает, что используется charset, указанный в конструкторе.

s может быть экземпляром bytes или str. Если это экземпляр bytes, то charset является кодировкой этой байтовой строки, и будет вызвано UnicodeError, если строка не может быть декодирована с этим набором символов.

Если s является экземпляром str, то charset является подсказкой, указывающей множество символов в строке.

В любом случае, при создании заголовка, совместимого с RFC 2822, с использованием правил RFC 2047, строка будет закодирована с использованием выходного кодека набора символов. Если строка не может быть закодирована с помощью выходного кодека, будет выдано сообщение об ошибке UnicodeError.

Необязательный errors передаётся в качестве аргумента ошибки для вызова декодирования, если s является строкой байтов.

encode(splitchars=';, \t', maxlinelen=None, linesep='\n')

Кодирует заголовок сообщения в совместимом с RFC формате, возможно, перенося длинные строки и инкапсулируя части, отличные от ASCII, в кодировку base64 или кавычки.

Необязательный splitchars — это строка, содержащая символы, которым алгоритм разделения должен придать дополнительный вес при обычном переносе заголовка. Это очень грубая поддержка «синтаксических разрывов более высокого уровня» RFC 2822: точки разделения, которым предшествует разделительный символ, предпочтительны во время разделения строки, причём символы предпочтительны в том порядке, в котором они появляются в строке. Пробел и табуляция могут быть включены в строку, чтобы указать, следует ли отдавать предпочтение одному над другим в качестве точки разделения, когда другие символы разделения не появляются в разделяемой строке. Splitchars не влияет на закодированные строки RFC 2047.

Если задан maxlinelen, переопределяет значение экземпляра для максимальной длины строки.

linesep указывает символы, используемые для разделения строк свёрнутого заголовка. По умолчанию это наиболее полезное значение для кода приложения Python (\n), но можно указать \r\n, чтобы создавать совместимые с RFC заголовки с разделителями строк.

Изменено в версии 3.2: Добавлен аргумент linesep.

Класс Header также предоставляет ряд методов для поддержки стандартных операторов и встроенных функций.

__str__()

Возвращает приближение Header в виде строки, используя неограниченную длину строки. Все фрагменты преобразуются в Юникод с использованием указанной кодировки и соответствующим образом соединяются вместе. Любые фрагменты с кодировкой 'unknown-8bit' декодируются как ASCII с помощью обработчика ошибок 'replace'.

Изменено в версии 3.2: Добавлена обработка кодировки 'unknown-8bit'.

__eq__(other)

Данный метод позволяет сравнивать два экземпляра Header на равенство.

__ne__(other)

Данный метод позволяет сравнить два экземпляра Header на предмет неравенства.

Модуль email.header также предоставляет следующие удобные функции.

email.header.decode_header(header)

Декодирует значение заголовка сообщения без преобразования набора символов. Значение заголовка находится в header.

Данная функция возвращает список пар (decoded_string, charset), содержащих каждую из декодированных частей заголовка. charsetNone для незакодированных частей заголовка, в противном случае строка нижнего регистра, содержащая имя набора символов, указанного в закодированной строке.

Вот пример:

>>> from email.header import decode_header
>>> decode_header('=?iso-8859-1?q?p=F6stal?=')
[(b'p\xf6stal', 'iso-8859-1')]
email.header.make_header(decoded_seq, maxlinelen=None, header_name=None, continuation_ws=' ')

Создаёт экземпляр Header из последовательности пар, возвращаемой decode_header().

decode_header() принимает строку значения заголовка и возвращает последовательность пар формата (decoded_string, charset), где charset — имя набора символов.

Данная функция принимает одну из данных последовательностей пар и возвращает экземпляр Header. Необязательные maxlinelen, header_name и continuation_ws аналогичны конструктору Header.