19.1.1. email.message: Представление email-сообщения¶email.message: Representing an email message
Центральный класс в пакете email – это класс Message, импортируемый из модуля email.message. Он является базовым классом для объектной модели email. Message предоставляет основную функциональность для установки и запроса полей заголовков, а также для доступа к телам сообщений.
Conceptually, a Message object consists of headers and payloads. Headers are RFC 2822 style field names and values where the field name and value are separated by a colon. The colon is not part of either the field name or the field value.
Заголовки хранятся и возвращаются с сохранением регистра, но сравнение выполняется без учёта регистра. Также может присутствовать один конвертный заголовок, также известный как заголовок Unix-From или заголовок From_. Полезная нагрузка представляет собой либо строку в случае простых объектов сообщений, либо список объектов Message для MIME-контейнерных документов (например, multipart/* и message/rfc822).
Объекты Message предоставляют интерфейс в стиле отображения для доступа к заголовкам сообщения и явный интерфейс для доступа как к заголовкам, так и к полезной нагрузке. Они предоставляют удобные методы для создания плоского текстового представления дерева объектов сообщения, для доступа к часто используемым параметрам заголовков и для рекурсивного обхода дерева объектов.
Вот методы класса Message:
- class email.message.Message(policy=compat32)¶
Аргумент policy определяет политику, которая будет использоваться для обновления модели сообщения. Значение по умолчанию compat32 обеспечивает обратную совместимость с версией Python 3.2 пакета email. Дополнительные сведения см. в документации policy.
Изменено в версии 3.3: Был добавлен именованный аргумент policy.
- as_string(unixfrom=False, maxheaderlen=0)¶
Возвращает все сообщение, преобразованное в строку. Если необязательный unixfrom равен True, в возвращаемую строку включается заголовок конверта. unixfrom по умолчанию равен False. Преобразование сообщения может привести к изменениям Message, если необходимо заполнить значения по умолчанию для завершения преобразования в строку (например, могут быть созданы или изменены MIME-границы).
Обратите внимание, что этот метод предоставляется для удобства и может не всегда форматировать сообщение так, как вам нужно. Например, по умолчанию он не выполняет преобразование строк, начинающихся с From, которое требуется форматом unix mbox. Для большей гибкости создайте экземпляр Generator и используйте его метод flatten() напрямую. Например:
from io import StringIO from email.generator import Generator fp = StringIO() g = Generator(fp, mangle_from_=True, maxheaderlen=60) g.flatten(msg) text = fp.getvalue()
- __str__()¶
Эквивалентно as_string(unixfrom=True).
- is_multipart()¶
Возвращает True, если содержимое сообщения является списком вложенных объектов Message, в противном случае возвращает False. Когда is_multipart() возвращает False, содержимое должно быть строковым объектом.
- set_unixfrom(unixfrom)¶
Устанавливает конвертный заголовок сообщения равным unixfrom, который должен быть строкой.
- get_unixfrom()¶
Возвращает конвертный заголовок сообщения. По умолчанию равен None, если конвертный заголовок никогда не был установлен.
- attach(payload)¶
Добавляет указанную полезную нагрузку к текущей полезной нагрузке, которая перед вызовом должна быть None или списком объектов Message. После вызова полезная нагрузка всегда будет списком объектов Message. Если нужно установить полезную нагрузку в скалярный объект (например, строку), используйте set_payload().
- get_payload(i=None, decode=False)¶
Возвращает текущую полезную нагрузку, которая будет списком объектов Message, когда is_multipart() равно True, или строкой, когда is_multipart() равно False. Если полезная нагрузка является списком и вы изменяете объект списка, вы изменяете полезную нагрузку сообщения на месте.
С необязательным аргументом i, get_payload() вернёт i-й элемент полезной нагрузки, считая с нуля, если is_multipart() равно True. Будет возбуждено исключение IndexError, если i меньше 0 или больше или равно количеству элементов в полезной нагрузке. Если полезная нагрузка является строкой (т.е. is_multipart() равно False) и указан i, возбуждается TypeError.
Необязательный decode – это флаг, указывающий, следует ли декодировать полезную нагрузку в соответствии с заголовком Content-Transfer-Encoding. Когда True и сообщение не является multipart-сообщением, полезная нагрузка будет декодирована, если значение этого заголовка – quoted-printable или base64. Если используется другая кодировка или заголовок Content-Transfer-Encoding отсутствует, полезная нагрузка возвращается как есть (без декодирования). Во всех случаях возвращаемое значение – бинарные данные. Если сообщение является multipart и флаг decode равен True, то возвращается None. Если полезная нагрузка закодирована в base64 и не является правильно сформированной (отсутствует дополнение, символы вне алфавита base64), то соответствующее нарушение будет добавлено в свойство defect сообщения (соответственно InvalidBase64PaddingDefect или InvalidBase64CharactersDefect).
Когда decode равен False (по умолчанию), тело возвращается в виде строки без декодирования заголовка Content-Transfer-Encoding. Однако для кодировки Content-Transfer-Encoding со значением 8bit предпринимается попытка декодировать исходные байты с использованием кодировки charset, указанной в заголовке Content-Type, с использованием обработчика ошибок replace. Если кодировка charset не указана или указанная кодировка charset не распознана пакетом email, тело декодируется с использованием кодировки ASCII по умолчанию.
- set_payload(payload, charset=None)¶
Устанавливает полезную нагрузку всего объекта сообщения в payload. Ответственность за соблюдение инвариантов полезной нагрузки лежит на клиенте. Необязательный параметр charset задаёт набор символов сообщения по умолчанию; подробнее см. set_charset().
- set_charset(charset)¶
Устанавливает набор символов полезной нагрузки в charset, который может быть либо экземпляром Charset (см. email.charset), либо строкой с именем набора символов, либо None. Если это строка, она будет преобразована в экземпляр Charset. Если charset равен None, параметр charset будет удалён из заголовка Content-Type (в остальном сообщение не изменится). Любое другое значение вызовет TypeError.
Если отсутствует заголовок MIME-Version, он будет добавлен. Если отсутствует заголовок Content-Type, он будет добавлен со значением text/plain. Независимо от того, существует ли заголовок Content-Type, его параметр charset будет установлен в charset.output_charset. Если charset.input_charset и charset.output_charset различаются, полезная нагрузка будет перекодирована в output_charset. Если не существует заголовка Content-Transfer-Encoding, то полезная нагрузка будет трансферно закодирована, если необходимо, с использованием указанного Charset, и будет добавлен заголовок с соответствующим значением. Если заголовок Content-Transfer-Encoding уже существует, предполагается, что полезная нагрузка уже правильно закодирована с использованием этого Content-Transfer-Encoding, и она не изменяется.
Следующие методы реализуют интерфейс, подобный отображению (mapping), для доступа к заголовкам сообщения RFC 2822. Обратите внимание, что между этими методами и обычным интерфейсом отображения (т.е. словаря) есть некоторые семантические различия. Например, в словаре нет повторяющихся ключей, но здесь могут быть повторяющиеся заголовки сообщения. Также в словарях нет гарантированного порядка ключей, возвращаемых keys(), но в объекте Message заголовки всегда возвращаются в том порядке, в котором они появились в исходном сообщении или были добавлены позже. Любой удалённый и затем повторно добавленный заголовок всегда добавляется в конец списка заголовков.
Эти семантические различия являются намеренными и направлены на максимальное удобство.
Обратите внимание, что во всех случаях заголовки конверта, присутствующие в сообщении, не включаются в интерфейс отображения.
В модели, созданной из байтов, любые значения заголовков, которые (в нарушение RFC) содержат не-ASCII байты, при получении через этот интерфейс будут представлены как объекты Header с кодировкой unknown-8bit.
- __len__()¶
Возвращает общее количество заголовков, включая дубликаты.
- __contains__(name)¶
Возвращает истину, если объект сообщения имеет поле с именем name. Сравнение выполняется без учёта регистра, и name не должно включать завершающее двоеточие. Используется для оператора in, например:
if 'message-id' in myMessage: print('Message-ID:', myMessage['message-id'])
- __getitem__(name)¶
Возвращает значение указанного поля заголовка. name не должно включать разделитель полей – двоеточие. Если заголовок отсутствует, возвращается None; исключение KeyError никогда не вызывается.
Обратите внимание: если указанное поле встречается в заголовках сообщения более одного раза, то какое именно из этих значений будет возвращено, не определено. Используйте метод get_all(), чтобы получить значения всех существующих заголовков с этим именем.
- __setitem__(name, val)¶
Добавляет заголовок в сообщение с именем поля name и значением val. Поле добавляется в конец существующих полей сообщения.
Обратите внимание, что это не перезаписывает и не удаляет существующие заголовки с тем же именем. Если требуется гарантировать, что новый заголовок будет единственным в сообщении с именем поля name, сначала удалите это поле, например:
del msg['subject'] msg['subject'] = 'Python roolz!'
- __delitem__(name)¶
Удаляет все вхождения поля с именем name из заголовков сообщения. Исключение не возбуждается, если указанное поле отсутствует в заголовках.
- keys()¶
Возвращает список всех имён полей заголовков сообщения.
- values()¶
Возвращает список всех значений полей сообщения.
- items()¶
Возвращает список кортежей из двух элементов, содержащих все заголовки и значения полей сообщения.
- get(name, failobj=None)¶
Возвращает значение указанного поля заголовка. Этот метод идентичен __getitem__(), за исключением того, что если указанный заголовок отсутствует, возвращается необязательный параметр failobj (по умолчанию None).
Вот несколько дополнительных полезных методов:
- get_all(name, failobj=None)¶
Возвращает список всех значений для поля с именем name. Если в сообщении нет таких заголовков, возвращается failobj (по умолчанию None).
- add_header(_name, _value, **_params)¶
Расширенная установка заголовка. Этот метод похож на __setitem__(), за исключением того, что дополнительные параметры заголовка могут быть переданы в виде именованных аргументов. _name – это добавляемое поле заголовка, а _value – это основное значение заголовка.
Для каждого элемента в словаре именованных аргументов _params ключ принимается как имя параметра, при этом символы подчёркивания преобразуются в дефисы (поскольку дефисы недопустимы в идентификаторах Python). Обычно параметр добавляется как key="value", если только значение не равно None; в этом случае добавляется только ключ. Если значение содержит не-ASCII символы, его можно указать в виде тройки в формате (CHARSET, LANGUAGE, VALUE), где CHARSET – это строка, задающая кодировку для кодирования значения, LANGUAGE обычно может быть установлен в None или пустую строку (см. RFC 2231 для других возможностей), а VALUE – это строковое значение, содержащее не-ASCII кодовые точки. Если тройка не передана и значение содержит не-ASCII символы, оно автоматически кодируется в формате RFC 2231 с использованием кодировки CHARSET utf-8 и языка LANGUAGE, равного None.
Вот пример:
msg.add_header('Content-Disposition', 'attachment', filename='bud.gif')
Это добавит заголовок, который выглядит как
Content-Disposition: attachment; filename="bud.gif"
Пример с не-ASCII символами:
msg.add_header('Content-Disposition', 'attachment', filename=('iso-8859-1', '', 'Fußballer.ppt'))
Что даёт
Content-Disposition: attachment; filename*="iso-8859-1''Fu%DFballer.ppt"
- replace_header(_name, _value)¶
Заменяет заголовок. Заменяет первый найденный в сообщении заголовок, который соответствует _name, сохраняя порядок заголовков и регистр имени поля. Если соответствующий заголовок не найден, вызывается KeyError.
- get_content_type()¶
Возвращает тип содержимого сообщения. Возвращаемая строка приводится к нижнему регистру и имеет вид maintype/subtype. Если в сообщении не было заголовка Content-Type, будет возвращён тип по умолчанию, задаваемый get_default_type(). Поскольку согласно RFC 2045 сообщения всегда имеют тип по умолчанию, get_content_type() всегда возвращает значение.
RFC 2045 определяет тип по умолчанию сообщения как text/plain, если только оно не находится внутри контейнера multipart/digest, в этом случае он будет message/rfc822. Если заголовок Content-Type содержит недопустимую спецификацию типа, RFC 2045 предписывает, что типом по умолчанию должен быть text/plain.
- get_content_maintype()¶
Возвращает основной тип содержимого сообщения. Это часть maintype строки, возвращаемой get_content_type().
- get_content_subtype()¶
Возвращает подтип содержимого сообщения. Это часть subtype строки, возвращаемой get_content_type().
- get_default_type()¶
Возвращает тип содержимого по умолчанию. Большинство сообщений имеют тип содержимого по умолчанию text/plain, за исключением сообщений, которые являются подчастями контейнеров multipart/digest. Такие подчасти имеют тип содержимого по умолчанию message/rfc822.
- set_default_type(ctype)¶
Устанавливает тип содержимого по умолчанию. ctype должен быть либо text/plain, либо message/rfc822, хотя это не принудительно. Тип содержимого по умолчанию не хранится в заголовке Content-Type.
- get_params(failobj=None, header='content-type', unquote=True)¶
Возвращает параметры заголовка Content-Type сообщения в виде списка. Элементы возвращаемого списка – это кортежи из двух элементов (ключ, значение), разделённые знаком '='. Левая часть '=' – это ключ, правая – значение. Если в параметре нет знака '=', значением будет пустая строка; иначе значение определяется так, как описано в get_param(), и при этом снимаются кавычки, если необязательный параметр unquote равен True (по умолчанию).
Необязательный параметр failobj – объект, возвращаемый при отсутствии заголовка Content-Type. Необязательный параметр header – заголовок, который нужно искать вместо Content-Type.
- get_param(param, failobj=None, header='content-type', unquote=True)¶
Возвращает значение параметра param заголовка Content-Type в виде строки. Если в сообщении нет заголовка Content-Type или такого параметра не существует, возвращается failobj (по умолчанию None).
Необязательный параметр header, если указан, задаёт заголовок сообщения, который следует использовать вместо Content-Type.
Ключи параметров всегда сравниваются без учёта регистра. Возвращаемое значение может быть либо строкой, либо кортежем из трёх элементов, если параметр был закодирован по RFC 2231. Если это кортеж из трёх элементов, то элементы значения имеют вид (CHARSET, LANGUAGE, VALUE). Обратите внимание, что как CHARSET, так и LANGUAGE могут быть None; в этом случае следует считать, что VALUE закодирован в кодировке us-ascii. Обычно параметр LANGUAGE можно игнорировать.
Если приложению не важно, был ли параметр закодирован по RFC 2231, можно свернуть значение параметра вызовом email.utils.collapse_rfc2231_value(), передав возвращаемое значение от get_param(). Этот вызов вернёт корректно декодированную строку Unicode, если значение было кортежем, или исходную строку без кавычек в противном случае. Пример:
rawparam = msg.get_param('foo') param = email.utils.collapse_rfc2231_value(rawparam)
В любом случае значение параметра (возвращаемая строка или элемент VALUE кортежа из трёх) всегда возвращается без кавычек, если только unquote не равен False.
- set_param(param, value, header='Content-Type', requote=True, charset=None, language='')¶
Устанавливает параметр в заголовке Content-Type. Если параметр уже существует в заголовке, его значение будет заменено на value. Если заголовок Content-Type ещё не задан для этого сообщения, он будет установлен в text/plain, а новое значение параметра будет добавлено в соответствии с RFC 2045.
Необязательный параметр header указывает альтернативный заголовок для Content-Type, и все параметры будут заключаться в кавычки по мере необходимости, если необязательный параметр requote не равен False (по умолчанию True).
Если указан необязательный параметр charset, параметр будет закодирован в соответствии с RFC 2231. Необязательный параметр language задаёт язык по RFC 2231, по умолчанию – пустая строка. И charset, и language должны быть строками.
- del_param(param, header='content-type', requote=True)¶
Полностью удаляет указанный параметр из заголовка Content-Type. Заголовок перезаписывается на месте без параметра и его значения. Все значения заключаются в кавычки по необходимости, если только requote не равен False (по умолчанию True). Необязательный header задаёт альтернативу Content-Type.
- set_type(type, header='Content-Type', requote=True)¶
Устанавливает основной тип и подтип для заголовка Content-Type. type должен быть строкой вида maintype/subtype, иначе вызывается ValueError.
Этот метод заменяет заголовок Content-Type, сохраняя все параметры на месте. Если requote равен False, то существующие кавычки в заголовке остаются без изменений; в противном случае параметры заключаются в кавычки (по умолчанию).
Альтернативный заголовок можно указать в аргументе header. При установке заголовка Content-Type также добавляется заголовок MIME-Version.
- get_filename(failobj=None)¶
Возвращает значение параметра filename заголовка Content-Disposition сообщения. Если заголовок не содержит параметра filename, метод ищет параметр name в заголовке Content-Type. Если не найден ни один из них или заголовок отсутствует, возвращается failobj. Возвращаемая строка всегда лишается кавычек в соответствии с email.utils.unquote().
- get_boundary(failobj=None)¶
Возвращает значение параметра boundary заголовка Content-Type сообщения или failobj, если либо заголовок отсутствует, либо не имеет параметра boundary. Возвращаемая строка всегда лишается кавычек в соответствии с email.utils.unquote().
- set_boundary(boundary)¶
Устанавливает параметр boundary заголовка Content-Type в boundary. set_boundary() всегда заключает boundary в кавычки при необходимости. Исключение HeaderParseError вызывается, если у объекта сообщения нет заголовка Content-Type.
Обратите внимание, что использование этого метода незначительно отличается от удаления старого заголовка Content-Type и добавления нового с новым разделителем через add_header(), потому что set_boundary() сохраняет порядок заголовка Content-Type в списке заголовков. Однако он не сохраняет никакие строки продолжения, которые могли присутствовать в исходном заголовке Content-Type.
- get_content_charset(failobj=None)¶
Возвращает параметр charset заголовка Content-Type, приведённый к нижнему регистру. Если заголовка Content-Type нет или в нём отсутствует параметр charset, возвращается failobj.
Обратите внимание, что этот метод отличается от get_charset(), который возвращает экземпляр Charset для кодировки по умолчанию тела сообщения.
- get_charsets(failobj=None)¶
Возвращает список, содержащий имена наборов символов в сообщении. Если сообщение является multipart, список будет содержать по одному элементу для каждой вложенной части в полезной нагрузке; в противном случае это будет список длиной 1.
Каждый элемент списка будет строкой, которая является значением параметра charset в заголовке Content-Type для представленной подчасти. Однако если подчасть не имеет заголовка Content-Type, не имеет параметра charset или не является text основным MIME-типом, то этот элемент в возвращаемом списке будет равен failobj.
- walk()¶
Метод walk() – это универсальный генератор, который можно использовать для перебора всех частей и подчастей дерева объектов сообщения в порядке обхода в глубину. Обычно walk() применяется как итератор в цикле for; каждая итерация возвращает следующую подчасть.
Вот пример, который выводит MIME-тип каждой части многокомпонентной структуры сообщения:
>>> for part in msg.walk(): ... print(part.get_content_type()) multipart/report text/plain message/delivery-status text/plain text/plain message/rfc822 text/plain
Объекты Message также могут опционально содержать два атрибута экземпляра, которые можно использовать при создании обычного текста MIME-сообщения.
- preamble¶
Формат MIME-документа допускает наличие некоторого текста между пустой строкой после заголовков и первой строкой границы multipart. Обычно этот текст не виден в MIME-совместимом почтовом клиенте, поскольку он находится вне стандартной MIME-защиты. Однако при просмотре необработанного текста сообщения или при просмотре сообщения в клиенте, не поддерживающем MIME, этот текст может стать видимым.
Атрибут preamble содержит этот начальный дополнительный текст для MIME-документов. Когда Parser обнаруживает некоторый текст после заголовков, но перед первой строкой границы, он присваивает этот текст атрибуту preamble сообщения. Когда Generator записывает текстовое представление MIME-сообщения и находит, что у сообщения есть атрибут preamble, он записывает этот текст в область между заголовками и первой границей. Подробнее см. email.parser и email.generator.
Обратите внимание: если объект сообщения не имеет преамбулы, атрибут preamble будет равен None.
- epilogue¶
Атрибут epilogue действует так же, как атрибут preamble, за исключением того, что он содержит текст, который появляется между последней границей и концом сообщения.
Вам не нужно задавать эпилог пустой строкой, чтобы Generator выводил символ новой строки в конце файла.
- defects¶
Атрибут defects содержит список всех проблем, обнаруженных при разборе этого сообщения. Подробное описание возможных дефектов разбора см. в email.errors.