Документация Python неофициальный перевод
Содержание страницы

19.1.2. email.parser: Разбор сообщений электронной почтыemail.parser: Parsing email messages

Структуры объектов сообщений можно создать одним из двух способов: создать с нуля, создав экземпляры объектов Message и связав их с помощью вызовов attach() и set_payload(), или же разобрав плоское текстовое представление сообщения электронной почты.

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

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

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

19.1.2.1. API FeedParserFeedParser API

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

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

Вот API для FeedParser:

class email.parser.FeedParser(_factory=email.message.Message, *, policy=policy.default)

Создаёт экземпляр FeedParser. Необязательный параметр _factory – это вызываемый объект без аргументов, который будет вызываться всякий раз, когда потребуется новый объект сообщения. По умолчанию используется класс email.message.Message.

Ключевое слово policy задаёт объект policy, управляющий рядом аспектов работы анализатора. Политика по умолчанию обеспечивает обратную совместимость.

Изменено в версии 3.3: Добавлен параметр policy.

feed(data)

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

close()

Закрытие FeedParser завершает разбор всех ранее переданных данных и возвращает корневой объект сообщения. Поведение при попытке передать дополнительные данные закрытому FeedParser не определено.

class email.parser.BytesFeedParser(_factory=email.message.Message)

Работает точно так же, как FeedParser, за исключением того, что входные данные для метода feed() должны быть байтами, а не строкой.

Новое в версии 3.2.

19.1.2.2. API класса ParserParser class API

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

Новое в версии 3.3: Класс BytesHeaderParser.

class email.parser.Parser(_class=email.message.Message, *, policy=policy.default)

Конструктор класса Parser принимает необязательный аргумент _class. Это должна быть вызываемая фабрика (например, функция или класс), которая используется всякий раз, когда необходимо создать объект вложенного сообщения. По умолчанию используется Message (см. email.message). Фабрика будет вызываться без аргументов.

Ключевое слово policy задаёт объект policy, управляющий рядом аспектов работы анализатора. Политика по умолчанию обеспечивает обратную совместимость.

Изменено в версии 3.3: Удалён аргумент strict, устаревший в версии 2.4. Добавлен параметр policy.

Другие публичные методы Parser:

parse(fp, headersonly=False)

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

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

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

parsestr(text, headersonly=False)

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

Необязательный параметр headersonly работает так же, как в методе parse().

class email.parser.BytesParser(_class=email.message.Message, *, policy=policy.default)

Этот класс полностью аналогичен Parser, но обрабатывает входные данные в виде байтов. Аргументы _class и strict интерпретируются так же, как для конструктора Parser.

Ключевое слово policy задаёт объект policy, управляющий рядом аспектов работы анализатора. Политика по умолчанию обеспечивает обратную совместимость.

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

parse(fp, headeronly=False)

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

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

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

parsebytes(bytes, headersonly=False)

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

Необязательный параметр headersonly работает так же, как в методе parse().

Новое в версии 3.2.

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

email.message_from_string(s, _class=email.message.Message, *, policy=policy.default)

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

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

email.message_from_bytes(s, _class=email.message.Message, *, policy=policy.default)

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

Новое в версии 3.2.

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

email.message_from_file(fp, _class=email.message.Message, *, policy=policy.default)

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

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

email.message_from_binary_file(fp, _class=email.message.Message, *, policy=policy.default)

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

Новое в версии 3.2.

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

Вот пример использования этого в интерактивном приглашении Python:

>>> import email
>>> msg = email.message_from_string(myString)  

19.1.2.3. Дополнительные примечанияAdditional notes

Вот некоторые замечания по семантике разбора:

  • Большинство сообщений типа non-multipart разбираются как единый объект сообщения со строковой полезной нагрузкой. У таких объектов метод is_multipart() вернёт False. Их метод get_payload() вернёт строковый объект.
  • Все сообщения типа multipart разбираются как объект-контейнер со списком объектов-подсообщений в качестве полезной нагрузки. Внешний контейнерный объект вернёт True для is_multipart(), а его метод get_payload() вернёт список подчастей Message.
  • Большинство сообщений с типом содержимого message/* (например, message/delivery-status и message/rfc822) также разбираются как объект-контейнер, содержащий полезную нагрузку в виде списка длиной 1. Их метод is_multipart() вернёт True. Единственный элемент в списке полезной нагрузки будет объектом-подсообщением.
  • Some non-standards compliant messages may not be internally consistent about their multipart-edness. Such messages may have a Content-Type header of type multipart, but their is_multipart() method may return False. If such messages were parsed with the FeedParser, they will have an instance of the MultipartInvariantViolationDefect class in their defects attribute list. See email.errors for details.

Сноски

[1]Начиная с версии 3.0 пакета email, введённой в Python 2.4, классический Parser был перереализован на основе FeedParser, поэтому семантика и результаты у обоих парсеров идентичны.