Spec-Zone.ru › Python 3.14

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 используются стандартные для Python окончания строк \n). Дополнительную информацию см. в документации policy. [2]

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 bit clean», если 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). Обратите внимание, что возврат True методом is_multipart() не обязательно означает, что «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 (по умолчанию он равен 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, список будет содержать по одному элементу для каждой подчасти полезной нагрузки; в противном случае список будет состоять из одного элемента.

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

При обнаружении 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 либо его заголовок некорректен, будут считаться имеющими тип 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.

[2]

Для класса EmailMessage требуется политика, предоставляющая атрибут content_manager, необходимый для работы методов управления содержимым, таких как set_content() и get_content(). Устаревшая политика compat32 не поддерживает эти методы, поэтому ее не следует использовать с EmailMessage.

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

Spec-Zone.ru

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