Spec-Zone.ru › Python 3.7

email.message: Представление электронного сообщения

Исходный код: Lib/email/message.py

Новая версия 3.6: 1

Центральным классом в пакете email является класс EmailMessage, импортируемый из модуля email.message. Он является базовым классом для объекта модели email. EmailMessage предоставляет основные возможности для установки и запроса полей заголовка, для доступа к телам сообщений и для создания или изменения структурированных сообщений.

Электронное сообщение состоит из заголовков и полезной нагрузки (также называемой содержанием). Заголовки — это имена и значения полей в стиле RFC 5322 или RFC 6532, где имя и значение поля разделены двоеточием. Двоеточие не является частью ни имени, ни значения поля. Полезная нагрузка может быть простым текстовым сообщением, двоичным объектом или структурированной последовательностью подсообщений, каждое со своими наборами заголовков и собственной полезной нагрузкой. Последний тип полезной нагрузки указывается типом MIME сообщения, таким как multipart/* или message/rfc822.

Концептуальная модель, предоставляемая объектом EmailMessage, представляет собой упорядоченный словарь заголовков, связанный с полезной нагрузкой, которая представляет тело сообщения в формате RFC 5322, которое может быть списком под-EmailMessage объектов. Помимо обычных методов словаря для доступа к именам и значениям заголовков, существуют методы для доступа к специализированной информации из заголовков (например, типу MIME содержимого), для работы с полезной нагрузкой, для генерации сериализованной версии сообщения и для рекурсивного обхода дерева объектов.

Интерфейс EmailMessage, подобный словарю, индексируется именами заголовков, которые должны быть ASCII-значениями. Значения словаря — это строки с дополнительными методами. Заголовки хранятся и возвращаются в форме с сохранением регистра, но имена полей сопоставляются без учета регистра. В отличие от реального словаря, ключи имеют порядок, и ключи могут быть дублированы. Предоставляются дополнительные методы для работы с заголовками, имеющими дублированные ключи.

Полезная нагрузка — это либо строка, либо байтовый объект в случае простых объектов сообщений, либо список объектов EmailMessage для документов контейнеров MIME, таких как multipart/* и message/rfc822 объектов сообщений.

class email.message.EmailMessage(policy=default)

Если указан параметр policy, будут использоваться правила, заданные им, для обновления и сериализации представления сообщения. Если policy не задан, используется политика default, которая следует правилам RFC для электронной почты, за исключением окончания строк (вместо предписанных RFC \r\n, используется стандартный Python \n). Дополнительную информацию см. в документации policy.

as_string(unixfrom=False, maxheaderlen=None, policy=None)

Возвращает всё сообщение, сплощённое в строку. При значении unixfrom, равном True, в возвращаемой строке будет содержаться заголовок конверта. По умолчанию unixfrom равно False. Для обратной совместимости с базовым классом Message поддерживается параметр maxheaderlen, но по умолчанию он равен None, что означает, что длина строки по умолчанию контролируется параметром max_line_length политики. Аргумент policy может быть использован для переопределения политики, полученной из экземпляра сообщения. Это может быть использовано для управления некоторым форматированием, производимым методом, поскольку указанная policy будет передана в Generator.

Сплощение сообщения может вызвать изменения в EmailMessage, если по умолчанию требуется заполнение для завершения преобразования в строку (например, могут быть сгенерированы или изменены границы MIME).

Обратите внимание, что этот метод предоставляется для удобства и может не быть наиболее полезным способом сериализации сообщений в вашем приложении, особенно если вы работаете с несколькими сообщениями. См. email.generator.Generator для более гибкого API сериализации сообщений. Также обратите внимание, что этот метод ограничен производством сообщений, сериализованных как «7-битные чистые», когда utf8 равно False, что является значением по умолчанию.

Изменено в версии 3.6: поведение по умолчанию, когда maxheaderlen не указан, было изменено с значения 0 на значение max_line_length из политики.

__str__()

Эквивалентно as_string(policy=self.policy.clone(utf8=True)). Позволяет str(msg) создавать строку, содержащую сериализованное сообщение в читаемом формате.

Изменено в версии 3.4: метод был изменён на использование utf8=True, тем самым, создавая представление сообщения в стиле RFC 6531 вместо прямого алиаса для as_string().

as_bytes(unixfrom=False, policy=None)

Возвращает всё сообщение, сплощённое в объект типа bytes. При значении unixfrom, равном True, в возвращаемой строке будет содержаться заголовок конверта. По умолчанию unixfrom равно False. Аргумент policy может быть использован для переопределения политики, полученной из экземпляра сообщения. Это может быть использовано для управления некоторым форматированием, производимым методом, поскольку указанная policy будет передана в BytesGenerator.

Сплощение сообщения может вызвать изменения в EmailMessage, если по умолчанию требуется заполнение для завершения преобразования в строку (например, могут быть сгенерированы или изменены границы MIME).

Обратите внимание, что этот метод предоставляется для удобства и может не быть наиболее полезным способом сериализации сообщений в вашем приложении, особенно если вы работаете с несколькими сообщениями. См. email.generator.BytesGenerator для более гибкого API сериализации сообщений.

__bytes__()

Эквивалентно as_bytes(). Позволяет bytes(msg) создавать объект типа bytes, содержащий сериализованное сообщение.

is_multipart()

Возвращает True если содержимое сообщения представляет собой список дочерних объектов EmailMessage, в противном случае возвращает False. Когда is_multipart() возвращает False, содержимое должно быть строковым объектом (который может представлять собой бинарное содержимое, закодированное с помощью CTE). Обратите внимание, что is_multipart() возвращающее True не обязательно означает, что «msg.get_content_maintype() == ‘multipart’» вернёт True. Например, is_multipart вернёт True, когда EmailMessage является объектом типа message/rfc822.

set_unixfrom(unixfrom)

Устанавливает заголовок конверта сообщения на unixfrom, который должен быть строкой. (См. mboxMessage для краткого описания этого заголовка.)

get_unixfrom()

Возвращает заголовок конверта сообщения. По умолчанию возвращает None если заголовок конверта никогда не был установлен.

Следующие методы реализуют интерфейс, похожий на отображение, для доступа к заголовкам сообщения. Обратите внимание, что существуют некоторые семантические различия между этими методами и обычным интерфейсом отображения (т. е. словаря). Например, в словаре нет дублирующих ключей, но здесь могут быть дублирующиеся заголовки сообщений. Кроме того, в словарях нет гарантированного порядка ключей, возвращаемых keys(), но в объекте EmailMessage заголовки всегда возвращаются в том порядке, в котором они появлялись в исходном сообщении или в котором они были добавлены к сообщению позже. Любой удалённый и затем повторно добавленный заголовок всегда добавляется в конец списка заголовков.

Эти семантические различия являются преднамеренными и направлены на повышение удобства в наиболее распространённых случаях использования.

Обратите внимание, что во всех случаях любой заголовок конверта, присутствующий в сообщении, не включается в интерфейс отображения.

__len__()

Возвращает общее количество заголовков, включая дубликаты.

__contains__(name)

Возвращает True если объект сообщения имеет поле с именем name. Сопоставление выполняется без учёта регистра, а name не включает в себя заключительный двоеточие. Используется для оператора in. Например:

if 'message-id' in myMessage:
   print('Message-ID:', myMessage['message-id'])
__getitem__(name)

Возвращает значение поля заголовка с указанным именем. name не включает в себя двоеточие. Если заголовок отсутствует, возвращается None; ошибка KeyError никогда не возникает.

Обратите внимание, что если указанное поле встречается более одного раза в заголовках сообщения, то точно какое из этих значений поля будет возвращено, не определено. Используйте метод get_all() для получения значений всех существующих заголовков с именем name.

Используя стандартные (не-compat32) политики, возвращаемое значение является экземпляром подкласса email.headerregistry.BaseHeader.

__setitem__(name, val)

Добавляет заголовок в сообщение с именем поля name и значением val. Поле добавляется в конец существующих заголовков сообщения.

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

del msg['subject']
msg['subject'] = 'Python roolz!'

Если policy определяет уникальные заголовки (как и стандартные политики), этот метод может вызвать ValueError при попытке присвоить значение такому заголовку, если он уже существует. Такое поведение является преднамеренным для сохранения согласованности, но не полагайтесь на него, так как мы можем в будущем выбрать автоматическое удаление существующего заголовка при таких операциях присваивания.

__delitem__(name)

Удаляет все вхождения поля с именем name из заголовков сообщения. Исключение не генерируется, если указанное поле отсутствует в заголовках.

keys()

Возвращает список всех имён полей заголовков сообщения.

values()

Возвращает список всех значений полей сообщения.

items()

Возвращает список пар кортежей (2-кортежей), содержащих все заголовки и значения полей сообщения.

get(name, failobj=None)

Возвращает значение поля с указанным именем заголовка. Это идентично __getitem__(), за исключением того, что в случае отсутствия заголовка с указанным именем возвращается failobj (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'))
replace_header(_name, _value)

Заменить заголовок. Заменяет первый найденный в сообщении заголовок, соответствующий _name, сохраняя порядок заголовков и регистр имени поля исходного заголовка. Если соответствующий заголовок не найден, генерируется исключение KeyError.

get_content_type()

Возвращает тип содержимого сообщения, приведенный к нижнему регистру в формате maintype/subtype. Если в сообщении нет заголовка Content-Type, возвращается значение, возвращаемое get_default_type(). Если заголовок Content-Type некорректен, возвращается text/plain.

(Согласно 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_content_type при отсутствии заголовка Content-Type в сообщении.

set_param(param, value, header='Content-Type', requote=True, charset=None, language='', replace=False)

Установить параметр в заголовке Content-Type. Если параметр уже существует в заголовке, заменить его значение на value. Когда header равно Content-Type (по умолчанию) и заголовок ещё не существует в сообщении, добавить его, установить его значение на text/plain и добавить новое значение параметра. Необязательный параметр header указывает альтернативный заголовок вместо Content-Type.

Если значение содержит символы, не входящие в ASCII, кодировка и язык могут быть явно указаны с помощью необязательных параметров charset и language. Необязательный параметр language указывает язык RFC 2231, по умолчанию пустая строка. Оба charset и language должны быть строками. По умолчанию используется utf8 для charset и None для language.

Если replace равно False (по умолчанию), заголовок перемещается в конец списка заголовков. Если replace равно True, заголовок будет обновлён на месте.

Использование параметра requote с объектами EmailMessage устарело.

Обратите внимание, что существующие значения параметров заголовков могут быть получены через атрибут params значения заголовка (например, msg['Content-Type'].params['charset']).

Изменено в версии 3.4: replace ключевой параметр был добавлен.

del_param(param, header='content-type', requote=True)

Полностью удалить указанный параметр из заголовка Content-Type. Заголовок будет переписан на месте без параметра или его значения. Необязательный параметр header указывает альтернативу заголовку Content-Type.

Использование параметра requote с объектами EmailMessage устарело.

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 и добавления нового с новым значением boundary с помощью add_header(), потому что set_boundary() сохраняет порядок заголовка Content-Type в списке заголовков.

get_content_charset(failobj=None)

Возвращает параметр charset заголовка Content-Type, преобразованный к нижнему регистру. Если заголовка Content-Type нет или у него нет параметра charset, возвращается failobj.

get_charsets(failobj=None)

Возвращает список, содержащий имена наборов символов в сообщении. Если сообщение является multipart, то список будет содержать по одному элементу для каждого подраздела в полезной нагрузке, в противном случае он будет иметь длину 1.

Каждый элемент списка будет строкой, являющейся значением параметра charset в заголовке Content-Type для соответствующего подраздела. Если у подчасти нет заголовка Content-Type, нет параметра charset или тип MIME подчасти не text, то соответствующий элемент возвращаемого списка будет failobj.

is_attachment()

Возвращает True, если есть заголовок Content-Disposition и его значение (независимо от регистра) равно attachment, False в противном случае.

Изменено в версии 3.4.2: is_attachment теперь является методом, а не свойством, для обеспечения согласованности с is_multipart().

get_content_disposition()

Возвращает значение заголовка Content-Disposition сообщения (без параметров) в нижнем регистре, если оно есть, или None. Возможные значения для этого метода: inline, attachment или None если сообщение соответствует RFC 2183.

Введено в версии 3.5.

Следующие методы связаны с запросом и изменением содержимого (полезной нагрузки) сообщения.

walk()

Метод walk() — универсальный генератор, который можно использовать для итерации по всем частям и подчастям дерева объекта сообщения в порядке обхода в глубину. Обычно вы будете использовать walk() в качестве итератора в цикле for; на каждой итерации возвращается следующая подчасть.

Вот пример, который выводит тип MIME каждой части структуры сообщения multipart:

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

walk итерируется по подчастям любой части, где is_multipart() возвращает True, даже если msg.get_content_maintype() == 'multipart' может вернуть False. Мы можем увидеть это в нашем примере, используя вспомогательную функцию отладки _structure:

>>> for part in msg.walk():
...     print(part.get_content_maintype() == 'multipart',
...           part.is_multipart())
True True
False False
False True
False False
False False
False True
False False
>>> _structure(msg)
multipart/report
    text/plain
    message/delivery-status
        text/plain
        text/plain
    message/rfc822
        text/plain

Здесь части message не являются multiparts, но они содержат подчасти. is_multipart() возвращает True и walk спускается в подчасти.

get_body(preferencelist=('related', 'html', 'plain'))

Возвращает MIME-часть, которая является лучшим кандидатом на роль «тела» сообщения.

preferencelist должен быть последовательностью строк из набора related, html, и plain, и указывает порядок предпочтения типа содержимого возвращаемой части.

Начните поиск соответствий с объектом, к которому применяется метод get_body.

Если related не включен в preferencelist, рассмотрите корневую часть (или подчасть корневой части) любых связанных частей, если (под)часть соответствует предпочтению.

При обнаружении multipart/related, проверьте параметр start и, если найдена часть с соответствующим заголовком Content-ID, рассмотрите только ее при поиске соответствий кандидатов. В противном случае рассмотрите только первую (по умолчанию корневую) часть multipart/related.

Если ни одна из частей не соответствует ни одному из предпочтений в preferencelist, возвращается None.

Примечания: (1) Для большинства применений единственными сочетаниями preferencelist, которые действительно имеют смысл, являются ('plain',), ('html', 'plain'), и значения по умолчанию ('related', 'html', 'plain'). (2) Поскольку сопоставление начинается с объекта, к которому применяется get_body, вызов get_body на multipart/related вернет сам объект, если только preferencelist не имеет значения, отличного от значения по умолчанию. (3) Сообщения (или части сообщений), не указывающие заголовок Content-Type или у которых заголовок Content-Type некорректен, будут обрабатываться как если бы они имели тип text/plain, что в некоторых случаях может привести к тому, что get_body вернет неожиданные результаты.

iter_attachments()

Возвращает итератор по всем непосредственным подчастям сообщения, которые не являются частями «тела». То есть пропустите первое вхождение каждой из text/plain, text/html, multipart/related, или multipart/alternative (если они не отмечены явно как вложения с помощью Content-Disposition: attachment), и верните все оставшиеся части. При непосредственном применении к multipart/related, возвращает итератор по всем связанным частям, за исключением корневой части (т.е. части, на которую указывает параметр start, или первой части, если параметр start отсутствует или параметр start не соответствует Content-ID ни одной из частей). При непосредственном применении к multipart/alternative или не-multipart, возвращает пустой итератор.

iter_parts()

Возвращает итератор по всем непосредственным подчастям сообщения, который будет пустым для не-multipart. (См. также walk().)

get_content(*args, content_manager=None, **kw)

Вызывает метод get_content() объекта content_manager, передавая self в качестве объекта сообщения и передавая любые другие аргументы или ключевые слова в качестве дополнительных аргументов. Если content_manager не указан, используется content_manager, указанный текущим policy.

set_content(*args, content_manager=None, **kw)

Вызывает метод set_content() объекта content_manager, передавая self в качестве объекта сообщения и передавая любые другие аргументы или ключевые слова в качестве дополнительных аргументов. Если content_manager не указан, используется content_manager, указанный текущим policy.

make_related(boundary=None)

Преобразует сообщение, которое не является multipart, в сообщение multipart/related, перемещая все имеющиеся заголовки Content- и полезную нагрузку в первую (новую) часть multipart. Если указан boundary, используйте его в качестве строки разделителя в multipart, иначе оставьте разделитель для автоматического создания при необходимости (например, при сериализации сообщения).

make_alternative(boundary=None)

Преобразует сообщение, которое не является multipart или multipart/related, в multipart/alternative, перемещая все имеющиеся заголовки Content- и полезную нагрузку в первую (новую) часть multipart. Если указан boundary, используйте его в качестве строки разделителя в multipart, иначе оставьте разделитель для автоматического создания при необходимости (например, при сериализации сообщения).

make_mixed(boundary=None)

Преобразуйте не-multipart, multipart/related, или multipart-alternative в multipart/mixed, переместив все существующие заголовки Content- и тело в первую (новую) часть multipart. Если указан boundary, используйте его в качестве разделителя в составном сообщении, иначе оставьте разделитель для автоматического создания при необходимости (например, при сериализации сообщения).

add_related(*args, content_manager=None, **kw)

Если сообщение является multipart/related, создайте новый объект сообщения, передайте все аргументы в его метод set_content(), и attach() его к multipart. Если сообщение является не-multipart, вызовите make_related(), а затем выполните действия, как описано выше. Если сообщение — любой другой тип multipart, вызовите исключение TypeError. Если content_manager не указан, используйте content_manager , указанный текущим policy. Если добавляемой части нет заголовка Content-Disposition, добавьте его со значением inline.

add_alternative(*args, content_manager=None, **kw)

Если сообщение является multipart/alternative, создайте новый объект сообщения, передайте все аргументы в его метод set_content(), и attach() его к multipart. Если сообщение является не-multipart или multipart/related, вызовите make_alternative(), а затем выполните действия, как описано выше. Если сообщение — любой другой тип multipart, вызовите исключение TypeError. Если content_manager не указан, используйте content_manager , указанный текущим policy.

add_attachment(*args, content_manager=None, **kw)

Если сообщение является multipart/mixed, создайте новый объект сообщения, передайте все аргументы в его метод set_content(), и attach() его к multipart. Если сообщение — не-multipart, multipart/related, или multipart/alternative, вызовите make_mixed(), а затем выполните действия, как описано выше. Если content_manager не указан, используйте content_manager , указанный текущим policy. Если добавляемой части нет заголовка Content-Disposition, добавьте его со значением attachment. Данный метод может использоваться как для явных вложений (Content-Disposition: attachment), так и для inline вложений (Content-Disposition: inline), передав соответствующие параметры в content_manager.

clear()

Удалить тело и все заголовки.

clear_content()

Удалить тело и все заголовки Content-, оставив все остальные заголовки и их исходный порядок.

EmailMessage объекты имеют следующие атрибуты экземпляров:

preamble

Формат MIME-документа допускает некоторый текст между пустой строкой после заголовков и первой строкой разделителя составного сообщения. Обычно этот текст не отображается в почтовом клиенте, совместимом с MIME, потому что он находится вне стандартной области MIME. Однако при просмотре исходного текста сообщения или при просмотре сообщения в почтовом клиенте, не поддерживающем MIME, этот текст может быть отображен.

Атрибут preamble содержит этот дополнительный текст до начала MIME-сообщения. Когда Parser обнаруживает некоторый текст после заголовков, но перед первой строкой разделителя, он присваивает этот текст атрибуту preamble сообщения. Когда Generator записывает обычное текстовое представление MIME-сообщения и обнаруживает, что у сообщения есть атрибут preamble, он запишет этот текст между заголовками и первым разделителем. См. email.parser и email.generator для получения подробностей.

Обратите внимание, что если у объекта сообщения нет преамбулы, то атрибут preamble будет None.

epilogue

Атрибут epilogue действует аналогично атрибуту preamble, за исключением того, что он содержит текст, появляющийся между последним разделителем и концом сообщения. Как и с preamble, если нет текста эпилога, этот атрибут будет None.

defects

Атрибут defects содержит список всех проблем, обнаруженных при разборе этого сообщения. См. email.errors для подробного описания возможных ошибок разбора.

class email.message.MIMEPart(policy=default)

Этот класс представляет собой подчасть MIME-сообщения. Он идентичен EmailMessage, за исключением того, что заголовки MIME-Version не добавляются при вызове set_content(), так как подчасти не нуждаются в собственных заголовках MIME-Version.

Примечания

1

Изначально добавлен в версии 3.4 как временный модуль. Документация для устаревшего класса сообщения перенесена в email.message.Message: Представление электронного сообщения с помощью API compat32.

© 2001–2020 Python Software Foundation
Licensed under the PSF License.
https://docs.python.org/3.7/library/email.message.html

Spec-Zone.ru

Настройки Оффлайн Что нового Помощь О нас
Spec-Zone .ru
спецификации, руководства, описания, API