email.parser: Парсинг сообщений электронной почты


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

Пакет email предоставляет стандартный парсер, который понимает большинство структур документов электронной почты, включая MIME документы. Вы можете передать парсеру байты, строку или файловый объект, и парсер вернёт вам корневой экземпляр EmailMessage структуры объекта. Для простых сообщений, отличных от MIME, полезная нагрузка этого корневого объекта, скорее всего, будет строкой, содержащей текст сообщения. Для MIME сообщений корневой объект вернёт True из своего метода is_multipart(), а доступ к подчастям можно получить с помощью методов обработки полезной нагрузки, таких как get_body(), iter_parts() и walk().

На самом деле для использования доступны два интерфейса парсера: API Parser и инкрементный API FeedParser. API Parser наиболее полезен, если у вас есть весь текст сообщения в памяти или если все сообщение находится в файле в файловой системе. FeedParser больше подходит, когда вы читаете сообщение из потока, который может заблокировать ожидание дополнительных входных данных (например, чтение сообщения электронной почты из сокета). FeedParser может принимать и анализировать сообщение поэтапно и вернуть корневой объект только при закрытии парсера.

Обратите внимание, что парсер можно расширять ограниченными способами, и, конечно же, вы можете полностью реализовать свой собственный парсер с нуля. Вся логика, связывающая встроенный парсер пакета email и класс EmailMessage, воплощена в классе policy, поэтому пользовательский парсер может создавать деревья объектов сообщений любым способом, который он сочтёт необходимым, путём реализации пользовательских версий соответствующих методов policy.

FeedParser API

BytesFeedParser, импортированный из модуля email.feedparser, предоставляет API, который способствует поэтапному парсингу сообщений электронной почты, например, необходимому при чтении текста сообщения электронной почты из источника, который может блокироваться (например, из сокета). BytesFeedParser, конечно, можно использовать для анализа сообщения электронной почты, полностью содержащегося в байтоподобном объекте, строке или файле, но API BytesParser может быть более удобным для таких случаев использования. Семантика и результаты двух API парсера идентичны.

API BytesFeedParser прост; вы создаёте экземпляр, передаёте ему кучу байтов до тех пор, пока его больше не останется, а затем закрываете парсер, чтобы получить корневой объект сообщения. BytesFeedParser чрезвычайно точен при анализе сообщений, соответствующих стандартам, и очень хорошо справляется с анализом несоответствующих сообщений, предоставляя информацию о том, почему сообщение было сочтено повреждённым. Он заполнит атрибут defects объекта сообщения списком всех проблем, обнаруженных в сообщении. См. модуль email.errors для получения списка дефектов, которые он может найти.

Далее представлен API для BytesFeedParser:

class email.parser.BytesFeedParser(_factory=None, *, policy=policy.compat32)

Создать экземпляр BytesFeedParser. Необязательный _factory вызывается без аргументов; если не указано, используйте message_factory из policy. Вызывайте _factory всякий раз, когда требуется новый объект сообщения.

Если указан policy, используйте указанные им правила для обновления представления сообщения. Если policy не задан, используйте политику compat32, которая поддерживает обратную совместимость с email версией пакета Python 3.2 и предоставляет Message в качестве фабрики по умолчанию. Все остальные политики предоставляют EmailMessage по умолчанию _factory. Дополнительные сведения о том, что ещё контролирует policy, см. в документации policy.

Примечание: Всегда следует указывать ключевой аргумент policy; Значение по умолчанию изменится на email.policy.default в будущей версии Python.

Добавлено в версии 3.2.

Изменено в версии 3.3: Добавлен ключевой аргумент policy.

Изменено в версии 3.6: _factory по умолчанию для политики message_factory.

feed(data)

Передать парсеру ещё немного данных. data должен быть байтоподобным объектом, содержащим одну или несколько строк. Строки могут быть неполными, и парсер правильно склеит такие неполные строки. Строки могут иметь любое из трёх общих окончаний строки: возврат каретки, новая строка или возврат каретки и новая строка (они даже могут быть смешаны).

close()

Завершить парсинг всех ранее переданных данных и возвращает корневой объект сообщения. Неизвестно, что произойдет, если feed() будет вызван после вызова этого метода.

class email.parser.FeedParser(_factory=None, *, policy=policy.compat32)

Работает как BytesFeedParser, за исключением того, что входными данными для метода feed() должна быть строка. Он имеет ограниченную полезность, поскольку единственный способ сделать такое сообщение правильным — это содержать только текст ASCII или, если utf8 — это True, никаких двоичных вложений.

Изменено в версии 3.3: Добавлен ключевой аргумент policy.

API парсера

Класс BytesParser, импортированный из модуля email.parser, предоставляет API, который можно использовать для парсинга сообщения, когда полное содержимое сообщения доступно в байтоподобном объекте или файле. Модуль email.parser также предоставляет Parser для парсинга строк и только заголовков, BytesHeaderParser и HeaderParser, которые можно использовать, если вас интересуют только заголовки сообщения. BytesHeaderParser и HeaderParser могут быть намного быстрее в таких ситуациях, т. к. они не пытаются анализировать тело сообщения, вместо этого устанавливая полезную нагрузку в необработанное тело.

class email.parser.BytesParser(_class=None, *, policy=policy.compat32)

Создать экземпляр BytesParser. Аргументы _class и policy имеют то же значение и семантику, что и аргументы _factory и policy BytesFeedParser.

Примечание: Всегда следует указывать ключевой аргумент policy; Значение по умолчанию изменится на email.policy.default в будущей версии Python.

Изменено в версии 3.3: Удален аргумент strict, который устарел в версии 2.4. Добавлено ключевой аргумент policy.

Изменено в версии 3.6: _class по умолчанию политика message_factory.

parse(fp, headersonly=False)

Читает все данные из двоичного файлового объекта fp, парсит полученные байты и возвращает объект сообщения. fp должен поддерживать методы readline() и read().

Байты, содержащиеся в fp, должны быть отформатированы как блок заголовков в стиле RFC 5322 (или, если utf8True, RFC 6532) и строк продолжения заголовка, которым может предшествовать заголовок конверта. Блок заголовка завершается либо концом данных, либо пустой строкой. За блоком заголовка следует тело сообщения (которое может содержать части, закодированные в MIME, включая части с Content-Transfer-Encoding или 8bit).

Необязательный headersonly — это флаг, указывающий, следует ли прекращать парсинг после чтения заголовков или нет. По умолчанию используется False, что означает анализ всего содержимого файла.

parsebytes(bytes, headersonly=False)

Аналогичен методу parse(), за исключением того, что он принимает байтоподобный объект вместо файлового объекта. Вызов этого метода для байтоподобного объекта эквивалентен переносу bytes сначала в экземпляр BytesIO и вызову parse().

Необязательный headersonly аналогичен методу parse().

Добавлено в версии 3.2.

class email.parser.BytesHeaderParser(_class=None, *, policy=policy.compat32)

Точно такой же, как BytesParser, за исключением того, что headersonly по умолчанию равен True.

Добавлено в версии 3.3.

class email.parser.Parser(_class=None, *, policy=policy.compat32)

Данный класс параллелен BytesParser, но обрабатывает строковый ввод.

Изменено в версии 3.3: Удален аргумент strict. Добавлено ключевой аргумент policy.

Изменено в версии 3.6: _class по умолчанию для политики message_factory.

parse(fp, headersonly=False)

Прочитать все данные из файлового объекта текстового режима fp, парсит полученный текст и возвращает корневой объект сообщения. fp должен поддерживать методы readline() и read() для файловых объектов.

Помимо требования текстового режима, данный метод работает как BytesParser.parse().

parsestr(text, headersonly=False)

Аналогичен методу parse(), за исключением того, что он принимает строковый объект вместо файлового объекта. Вызов этого метода для строки эквивалентен переносу text сначала в экземпляр StringIO и вызову parse().

Необязательный headersonly аналогичен методу parse().

class email.parser.HeaderParser(_class=None, *, policy=policy.compat32)

Точно такой же, как Parser, за исключением того, что headersonly по умолчанию равен True.

Поскольку создание структуры объекта сообщения из строки или файлового объекта является такой распространенной задачей, для удобства предоставляются четыре функции. Они доступны в пространстве имён пакетов верхнего уровня email.

email.message_from_bytes(s, _class=None, *, policy=policy.compat32)

Возвращает структуру объекта сообщения из байтоподобного объекта. Это эквивалентно BytesParser().parsebytes(s). Необязательные _class и policy интерпретируются как конструктор класса BytesParser.

Добавлено в версии 3.2.

Изменено в версии 3.3: Удален аргумент strict. Добавлено ключевой аргумент policy.

email.message_from_binary_file(fp, _class=None, *, policy=policy.compat32)

Возвращает дерево структуры объекта сообщения из открытого двоичного файла файлового объекта. Это эквивалентно BytesParser().parse(fp). _class и policy интерпретируются как конструктор класса BytesParser.

Добавлено в версии 3.2.

Изменено в версии 3.3: Удален аргумент strict. Добавлено ключевой аргумент policy.

email.message_from_string(s, _class=None, *, policy=policy.compat32)

Возвращает структуру объекта сообщения из строки. Это эквивалентно Parser().parsestr(s). _class и policy интерпретируются как конструктор класса Parser.

Изменено в версии 3.3: Удалён аргумент strict. Добавлен ключевой аргумент policy.

email.message_from_file(fp, _class=None, *, policy=policy.compat32)

Возвращает дерево структуры объекта сообщения из открытого файлового объекта. Эквивалентна Parser().parse(fp). _class и policy интерпретируются как конструктор класса Parser.

Изменено в версии 3.3: Удалён аргумент strict. Добавлен ключевой аргумент policy.

Изменено в версии 3.6: _class по умолчанию для политики message_factory.

Вот пример того, как вы можете использовать message_from_bytes() в интерактивном приглашении Python:

>>> import email
>>> msg = email.message_from_bytes(myBytes)  

Дополнительные примечания

Вот несколько замечаний по семантике парсера:

  • Большинство сообщений, отличных от не-multipart, анализируются как один объект сообщения со строковой полезной нагрузкой. Данные объекты вернут False вместо is_multipart(), а iter_parts() отдаст пустой список.

  • Все сообщения типа multipart будут парситься как объект сообщения-контейнера со списком объектов вложенного сообщения для их полезной нагрузки. Сообщение внешнего контейнера вернёт True вместо is_multipart(), а iter_parts() отдаст список частей.

  • Большинство сообщений с типом содержимого message/* (например, message/delivery-status и message/rfc822) также будут проанализированы как объект-контейнер, содержащий полезные данные списка длиной 1. Их метод is_multipart() вернёт True. Единственный элемент, полученный iter_parts(), будет объектом подсообщения.

    Некоторые сообщения, не соответствующие стандартам, могут быть внутренне несогласованными в отношении их multipart-ности. Такие сообщения могут иметь заголовок Content-Type типа multipart, но их метод is_multipart() может возвращать False. Если такие сообщения были проанализированы с помощью FeedParser, они будут иметь экземпляр класса MultipartInvariantViolationDefect в своём списке атрибутов defects. Подробности см. в email.errors.