Теория
Сообщения электронной почты форматируются с использованием в основном одного из следующих двух форматов.
Самый старый из них определяется как RFC 5322 (изначально это былоRFC 822, но с тех пор он был обновлен).
Этот формат не поддерживает сообщения, использующие кодировки символов, отличные от ASCII, и не поддерживает общедоступные выражения «вложения».
Для исправленияВ этой ситуации был изобретен набор стандартов, широко известный как MIME .Стандарты в этом наборе определяют:
- Способы использования кодировок не-ASCII.
- Способы составления составных сообщений.
Два самых интересных стандарта MIME: RFC 2045 и RFC 2046 .
Стандарты, включенные в MIME, были специально разработаны для того, чтобы сделать MIME-закодированный материал, все еще совместимый с RFC 822 - это, среди прочего, позволило не изменять MTA для поддержки нового формата сообщений.
Практика
Библиотеки, реализованные в различныхЯзыки программирования для работы с различными битами, определенными MIME, обычно следуют тенденции самого MIME и способны прозрачно обрабатывать «простые» письма в формате RFC 822 и MIME.
Для обработки сообщений в формате MIME,Go предлагает в своей стандартной библиотеке три пакета:
иеще один, net/textproto
, для работы с заголовками в стиле MIME (также используется в HTTP, IMAP / POP3 и т. д.).
Вместе эти пакеты охватывают большую часть (или все) из того, чтовам нужно читать и писать сообщения электронной почты в формате MIME.
Основной подход к синтаксическому анализу
Основной подход к синтаксическому анализу сообщений электронной почты заключается в следующем:
Создайте экземпляр bufio.Reader
из io.Reader
, предоставляющего данные сообщения электронной почты для анализа.
Создайте экземпляр net/textproto.Reader
из bufio.Reader
, сделанного на предыдущем шаге.
Используйте его метод ReadMIMEHeader()
, чтобы прочитать и проанализировать блок заголовка сообщения.
Проверьте, содержит ли оно поле MIME-Version
, предписанное RFC 2045 для указания содержимого в формате MIME.
- Если оно содержит одно,убедитесь, что его значение буквально "1.0".Если это не так, то это какой-то MIME-формат из будущего, с которым вы не сможете справиться.Барф соответственно;в противном случае переходите к следующему шагу.
- Если такого поля нет, сообщение представляет собой простой старый электронный адрес, состоящий из одной части.Рассматривайте все его содержимое так, как если бы оно было одной частью сообщения MIME (это упрощенно, но в основном будет работать).
Если вы убедились, что имеете дело с MIME1.0, затем
- Считайте поле заголовка
Content-Type
, затем используйте mime.ParseMediaType()
для его анализа. - Если результирующее значение
mediatype
будет начинаться с префикса «multipart /», буквально, тогда будьте готовы работать с несколькими частями, которые требуют рекурсивной обработки, поскольку каждая часть отформатирована почти как сообщение верхнего уровня- то есть содержит заголовок и тело (см. Ниже). - В противном случае тип содержимого будет указывать на какую-то «прямую» полезную нагрузку (например, «text / plain» или «text / html» или что-либо еще).).В этом случае специальный «параметр» такого типа носителя (см. Ниже) указывает кодировку символов, используемую для содержимого детали, если оно текстовое.(Также обратите внимание, что это может быть «message / rfc822», которое фактически указывает на то, что полезная нагрузка является другим сообщением электронной почты, которое, возможно, потребуется проанализировать в соответствии с теми же правилами, что и в кодировке.)
Работа с "листовой" частью или полезными нагрузками сообщений, не состоящих из нескольких частей
Поле заголовка важной для чтения следующей строки - Content-Transfer-Encoding
, которое определяет физическую часть детализакодирован для передачи по проводам.
В большинстве случаев это будет «base64», но также может быть и «цитируемым».
Работа с сообщениями, состоящими из нескольких частей
Во-первых, будьте готовы правильно разобраться с различными аспектами того, что такое «многочастная часть»: детали могут быть либо альтернативами друг другу, то есть программой, которая должна передать сообщение пользователь может выбрать любой из них - все, что лучше всего соответствует предпочтениям пользователя, или спросить их или что-то еще, - или они могут быть сущностями, примерно равными друг другу.
Первая схема обозначена мультимедийным типом «multipart / alternative» и обычно используется MUA, которые позволяют пользователю составлять почтовое сообщение с использованием разметки, а затем кодировать результат так, чтобы он содержал две альтернативные части - одну, помеченную как «text /». html "и еще один, помеченный как" text / plain "и содержащий исходный контент без этой разметки.
Последнее обозначается как «multipart / mixed» и обычно используется для вложений: в этой схеме первая часть обычно (но это не обязательно) является текстом сообщения в любом формате, а остальные части являются вложениями.
Чтобы иметь возможность выбирать отдельные части из кодировки сообщения, мультимедийный тип "multipart / what" большую часть времени содержит так называемый "параметр" с именем "border" и содержит уникальную строку, которая используется для разграничить части.
Функция mime.ParseMediaType()
возвращает параметры типа носителя в виде карты в качестве второго значения результата.
После извлечения этого «граничного» параметра типа носителя,
Вы можете использовать его для создания экземпляра mime/multipart.Reader
из экземпляра bufio.Reader
, созданного на самом первом шаге.
Затем вы можете прочитать части сообщения одну за другой и действовать по ним.
Обратите внимание, что, как уже указывалось, часть сообщения может иметь тип содержимого "message / rfc822", что означает, что оно содержит еще одно полное почтовое сообщение (и само оно может быть составным, содержать другие почтовые сообщения и т. Д.) .