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

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

18.1.2.1. FeedParser API

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

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

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

Вот API для FeedParser:

class email.parser.FeedParser([_factory])

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

feed(data)

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

close()

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

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

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

class email.parser.Parser([_class])

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

Необязательный флаг strict игнорируется.

Устарело с версии 2.4: Поскольку класс Parser является обратно совместимой оберткой API вокруг нового в Python 2.4 FeedParser, весь разбор фактически является нестрогим. Следует просто прекратить передавать флаг strict конструктору Parser.

Изменено в версии 2.2.2: Флаг strict был добавлен.

Изменено в версии 2.4: Флаг strict был объявлен устаревшим.

Другие открытые методы Parser:

parse(fp[, headersonly])

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

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

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

Изменено в версии 2.2.2: Флаг headersonly был добавлен.

parsestr(text[, headersonly])

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

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

Изменено в версии 2.2.2: Флаг headersonly был добавлен.

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

email.message_from_string(s[, _class[, strict]])

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

Изменено в версии 2.2.2: Флаг strict был добавлен.

email.message_from_file(fp[, _class[, strict]])

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

Изменено в версии 2.2.2: Флаг strict был добавлен.

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

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

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

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

  • Большинство сообщений, не являющихся multipart, разбираются как одиночный объект сообщения со строковым содержимым. Такие объекты будут возвращать False для is_multipart(). Их метод get_payload() будет возвращать строковый объект.

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

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

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

Сноски

1

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