Spec-Zone.ru › Python 3.12

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. Значения словаря — это строки с дополнительными методами. Заголовки сохраняются и возвращаются с сохранением регистра, но имена полей сопоставляются без учёта регистра. Ключи упорядочены, но, в отличие от обычного словаря, могут повторяться. Для работы с заголовками, имеющими повторяющиеся ключи, предусмотрены дополнительные методы.

Содержимое — это либо строка или объект bytes в простых объектах сообщений, либо список объектов EmailMessage для MIME-контейнеров, таких как multipart/* и message/rfc822.

class email.message.EmailMessage(policy=default)

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

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

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

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

Обратите внимание: этот метод предоставлен для удобства и может быть не самым подходящим способом сериализации сообщений в вашем приложении, особенно если вы работаете с несколькими сообщениями. Более гибкий API для сериализации сообщений см. в email.generator.Generator. Также обратите внимание, что этот метод ограничен созданием сообщений в формате «чистых 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 могут быть созданы или изменены).

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

__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 никогда не возникает.

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

При использовании стандартных политик (не 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 (по умолчанию он равен 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 должны быть строками. По умолчанию для charset используется utf8, а для language — None.

Если 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 в кавычки, если это необходимо. Если объект сообщения не содержит заголовка Content-Type, возникает исключение HeaderParseError.

Обратите внимание: этот метод немного отличается от удаления старого заголовка Content-Type и добавления нового с новой границей с помощью 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-тип каждой части составного сообщения:

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

>>> from email.iterators import _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, корневая часть (или её подчасть) любого встретившегося объекта related рассматривается как подходящий вариант, если эта часть соответствует одному из предпочтений.

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

Если у части есть заголовок Content-Disposition, она рассматривается как подходящая только в том случае, если значение заголовка — inline.

Если ни одна из частей не соответствует предпочтениям из 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, использует его как строку-разделитель для multipart; в противном случае оставляет создание разделителя на тот момент, когда он понадобится (например, при сериализации сообщения).

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 допускает наличие текста между пустой строкой после заголовков и первой строкой-разделителем multipart. Обычно этот текст не виден в почтовых программах с поддержкой 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, за исключением того, что при вызове set_content() заголовки MIME-Version не добавляются, поскольку вложенным частям не нужны собственные заголовки MIME-Version.

Сноски

[1]

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

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

Spec-Zone.ru

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