- Как грамотно отправлять почту из скриптов (в частности — на PHP)
- Формат почтового сообщения
- Грамотное использование русских символов в заголовках почтового сообщения
- Content-type: multipart/.
- Ошибка первая — неверный subtype
- Ошибка вторая — неверный порядок частей
- Ошибка третья — выбор только одного субтипа
- И напоследок — еще пара рекомендаций
- Content-Type
- Синтаксис
- Директивы
- Примеры
- Content-Type в HTML формах
- Спецификации
- Совместимость с браузерами
- Смотрите также
- Found a content problem with this page?
- Как прикрепить файл к письму из почтового шаблона в 1С Битрикс
Как грамотно отправлять почту из скриптов (в частности — на PHP)
Отправка почты из скриптов на PHP — вещь, которая очень часто встречается в веб-приложениях. К сожалению, как показывает практика, большинство разработчиков используют эту функцию неправильно, допуская в своих скриптах одни и те же ошибки. В результате оказывается, что письмо получателю пришло в неверной кодировке, просто не дошло, или дошло, но отображается совсем не так, как этого хотел автор.
Для того, чтобы быть уверенным, что ваше сообщение отправляется действительно верно, необходимо иметь по меньшей мере базовые представления о формате почтового сообщения. Формат почтового сообщения описан в нескольких стандартизирующих документах, основными из которых являются RFC 822 (описывает формат передачи простого текста на английском языке) и RFC 2045 и далее (описывает расширения этого формата для передачи произвольных данных).
Формат почтового сообщения
Ниже приведен самый простой пример текстового сообщения, составленного в соответствии с приведенными выше стандартами и готового к отправке.
From: =?windows-1251?b?0J7RgtC/0YDQsNCy0LjRgtC10LvRjD89?=
To: =?windows-1251?b?0J/QvtC70YPRh9Cw0YLQtdC70Yw/PQ==?=
Subject: =?windows-1251?b?0Y3RgtC+INGC0LXQvNCwINGB0L7QvtCx0YnQtdC90LjRjz89?=
Content-Type: text/plain; charset=«windows-1251»
Content-Transfer-Encoding: 8bit
Это почтовое сообщение на русском языке
Содержит несколько строк
Именно в таком формате клиент для отправки почты (MS Outlook или Mozilla Thunderbird) подготавливает сообщение, а затем отправляет его получателю (кстати, большинство почтовых клиентов позволяют просмотреть исходный код сообщения, в Mozilla Thunderbird, например, для этого служит комбинация клавиш Ctrl+U). Задача нашего скрипта языке PHP — добиться точно такого же формата письма.
Как видно из приведенного выше примера, электронное письмо содержит две части: в одной (верхней) размещаются заголовки, а в другой (нижней) собствено текст письма. Отделены эти части друг от друга пустой строкой. Заголовки состоят из строк, в которых содержится тема письма (Subject), имя и адрес отправителя (From), получателя (To) и другая информация. В самом простом случае каждая строка содержит пару «ИмяЗаголовка: ЗначениеЗаголовка». Особенно необходимо подчеркнуть, что, согласно стандартам, в заголовках ни при каких обстоятельствах не должны содержаться символы, не присутствующие в ASCII таблице — латинские буквы, цифры, знаки пунктуации и псевдографики.
Грамотное использование русских символов в заголовках почтового сообщения
Итак, в явном виде русский текст в заголовке присутствовать не должен, поэтому для того, чтобы включить его туда, этот текст предварительно нужно закодировать. Стандарты описывают способ кодирования «запрещенных» символов. Общий формат выглядит так:
Кодировка может быть любой из списка «windows-1251», «koi8-r», «utf-8» и т.д. Во всех случаях, как правило, кодировка сообщения будет совпадать с кодировкой в которой работает сайт. То есть в большинстве случаев это будет «windows-1251», реже — «utf-8».
Способ кодирования указывает на то, каким именно образом русские символы будут преобразованы в безопасный набор. Способа определяется два: так называемый «Q-encoding» (обозначается одной буквой «Q») и «Base64» (обозначается одной буквой «B»).
К сожалению, штатной функции, которая бы могла бы обычную строку преобразовать в Q-encoded текст, в PHP нет, зато есть функция, которая умеет выполнять аналогичное преобразование в Base64. Итак, PHP код правильного создания заголовка темы почтового сообщения может выглядеть следующим образом:
$subject = «=?windows-1251?b?». base64_encode($_POST[«subject»]). «? =?windows-1251?B?». base64_encode($_POST[«username»]). «?= «;
Content-type: multipart/.
С этим заголовком знаком любой разработчик, которому доводилось решать проблемы отправки писем с вложениями или HTML письмами. И зачастую письма, сформированные без использования библиотек вроде PEAR::Mail_mime отображаются не очень корректно. Практика показывает, что если при формировании письма жестко придерживаться стандарта, которы задается в RFC (в частности — RFC 2046) — подавляющее большинство клиентских программ (включая таких любителей придерживаться стандартов, как Mozilla Thunderbird) отображает письмо корректно. Далее мы будем исходить из того, что читатель этого документа представляет себе основной синтаксис команд и понимает, что таке boundary и почему необходимо указывать Content-type для каждой из частей письма. Постараемся отметить основные ошибки.
Ошибка первая — неверный subtype
Тип multipart имеет три субтипа — mixed, alternative и related, которые используются синтаксически одинаково, но имеют разное предназначение
- mixed — используется, когда в рамках одного почтового сообщения имеется несколько независимых друг от друга, и равнозначных частей. Самый простой пример такого письма — сообщение с вложением.
alternative — используется, когда в одном почтовом сообщении содержится несколько частей, содержащих одну и ту же информацию, предназначенную для отображения на различном клиентском ПО — например текстовая и HTML версия одного и того же письма.
related — используется, когда в одном почтовом сообщении содержится несколько частей, формирующих один итоговый документ. Яркий пример — HTML письмо с картинками. Запомните, по стандарту только в этом случае должны работать ссылки на Contend-id элементов (вида ).
Помните и применяйте по назначению.
Ошибка вторая — неверный порядок частей
- mixed — порядок частей для наших задач не имеет значения.
alternative — части должны быть расставлены по порядку, от более простых к более сложным. RFC регламентирует процесс выбора одной из версий письма клиентом пользователя примерно так: «В общем случае, почтовый клиент должен отображать последнюю доступную ему версию документа». Т.е. при формировании текстовой и HTML-версий письма необходимо вперед поставить текстовую.
related — первой в очереди должна идти основная часть (HTML документ, например). Следом — все остальные. По большому счету, стандартом регламентирован специальный параметр «start», который указывает на основную часть документа, но этим лучше не злоупотреблять.
Ошибка третья — выбор только одного субтипа
Зачастую разработчик, формирующий из программы письмо забывает, что любая из частей письма может так же иметь Content-type: multipart, а значит можно выстроить некоторое подобие древовидной структуры, гарантирующей, что каждая из частей письма займет правильное место. Вот как примерно может выглядеть структура письма, имеющего текстовую и HTML версию (HTML с картинками), а так же приложенный документ MS Word:
- Content-type: multipart/mixed
- Content-type: multipart/alternative
- Content-type: text/plain
Content-type: multipart/related- Content-type: text/html
Content-type: image/jpeg
Content-type: image/jpeg
И напоследок — еще пара рекомендаций
- Всегда делайте text/plain вариант письма — никто не может предсказать, как именно будут читать Ваше письмо.
Не ленитесь и придерживайтесь стандартов.
Если интересно — http://people.dsv.su.se/~jpalme/ietf/mhtml-test/mhtml.html тут есть несколько примеров.
Content-Type
Заголовок-сущность Content-Type используется для того, чтобы определить MIME тип ресурса.
В ответах сервера заголовок Content-Type сообщает клиенту, какой будет тип передаваемого контента. В некоторых случаях браузеры пытаются сами определить MIME тип передаваемого контента, но их реакция может быть неадекватной. Чтобы предотвратить такие ситуации, вы можете установить в заголовке X-Content-Type-Options значение nosniff .
В запросах (таких, как POST или PUT ), клиент сообщает серверу тип отправляемых данных.
Тип заголовка Entity header Forbidden header name нет CORS-safelisted response-header да Синтаксис
Content-Type: text/html; charset=utf-8 Content-Type: multipart/form-data; boundary=something
Директивы
Директива boundary обязательна для составных сущностей. Она содержит от 1 до 70 символов (не должна заканчиваться пробелом), которые без искажений пройдут через шлюзы email и служит для корректной инкапсуляции всех частей составной сущности.
Примеры
Content-Type в HTML формах
В POST запросе, сгенерированном в результате отправки HTML формы, Content-Type запроса определяется в атрибуте enctype тега .
form action="/" method="post" enctype="multipart/form-data"> input type="text" name="description" value="some text"> input type="file" name="myFile"> button type="submit">Submitbutton> form>
Запрос в этом случае может выглядеть так (менее интересные заголовки опущены):
POST /foo HTTP/1.1 Content-Length: 68137 Content-Type: multipart/form-data; boundary=---------------------------974767299852498929531610575 -----------------------------974767299852498929531610575 Content-Disposition: form-data; name="description" some text -----------------------------974767299852498929531610575 Content-Disposition: form-data; name="myFile"; filename="foo.txt" Content-Type: text/plain (content of the uploaded file foo.txt) -----------------------------974767299852498929531610575--
Спецификации
Спецификация Заголовок RFC 7233, секция 4.1: Content-Type in multipart Hypertext Transfer Protocol (HTTP/1.1): Range Requests RFC 7231, секция 3.1.1.5: Content-Type Hypertext Transfer Protocol (HTTP/1.1): Semantics and Content Совместимость с браузерами
BCD tables only load in the browser
Смотрите также
Found a content problem with this page?
This page was last modified on 26 окт. 2022 г. by MDN contributors.
Your blueprint for a better internet.
Как прикрепить файл к письму из почтового шаблона в 1С Битрикс
Недавно столкнулся с тем, что битрикс не имеет штатных средств, для прикрепления файла к письму.
В интернете нашел вот этот пост https://dev.1c-bitrix.ru/community/web. blog/1623/
И вот этот модуль http://marketplace.1c-bitrix.ru/solut. attaching/
Решение описанное в первом блоге мне понравилось, но хотелось бы управлять прикреплением файлов из шаблона письма. Это позволило бы добавить файлы к шаблонам, которые используются в стандартных компонентах системы без кастомизации этих компонентов.
По моей задумке к письму нужно добавить заголовок Add-File , а содержание этого заголовка должно быть таким#CARD#=>card.jpg; #CARD2#=>card2.jpg;
#CARD# — это путь к файлу на диске
card.jpg — это то как будет называться файл после прикрепления к письмуТогда в самом письме к прикрепленным файлам можно было бы обращаться вот так:Показать скрытое содержимоеИли можно передать в заголовок письма Add-File одно поле, а в нем уже будут описаны все подключенные файлы в виде
/var/www/html/img/1.jpg=>card.jpg; /var/www/html/img/2.jpg=>card2.jpg;
Битрикс отправляет письма при помощи функции bxmail описанной в файле \bitrix\modules\main\tools.php. Сама функция выглядит вот так
function bxmail($to, $subject, $message, $additional_headers=»», $additional_parameters=»» )
Чтобы перехватить данные перед самой их отправкой и подключить файлы нужно всего лишь объявить функцию и именем custom_mail.
В первом приближении она должна повторять функционал того что идет после нее в функции bxmail чтобы не нарушать работу системы после ее объвления.function custom_mail ($to, $subject, $message, $additional_headers, $additional_parameters)
Немного о том, как прикрепить файл к письму
Для этого нужно обычное письмо преобразовать в письмо, состоящее из нескольких сущностей. Тип письма определен в заголовке Content-Type.
Content-Type:text/plain; charset=… - текстовый шаблон Content-Type:text/html; charset=… - html шаблон письма Content-Type: multipart/mixed; boundary Код">
-- разделитель Content-Type: text/html; charset=UTF-8 Content-Transfer-Encoding: 8bit Два перехода на новую линию (eol) Тело письма. Два перехода на новую линию (eol) -- разделитель Content-Type: application/octet-stream;name="card.jpg" Content-Disposition:attachment;filename="card.jpg" Content-Transfer-Encoding: base64 Два перехода на новую линию (eol) Файл, разложенный по основанию 64. Два перехода на новую линию (eol)
Учитывая все вышесказанное не сложно написать функцию, которая преобразует формат письма перед отправкой. Сразу прикреплю ее код к посту.
Кода получилось немного. Его можно просто скопировать в файл bitrix\php_interface\init.php
Или скопировать в отдельный файл /bitrix/php_interface/include/classes/custom_mail.php и подключать его только когда происходит событие отправки письма.
Тогда в файл bitrix\php_interface\init.php можно написать вот так.AddEventHandler('main', 'OnBeforeEventAdd', 'includeCustomMail'); function includeCustomMail($event, $lid, $arFields) < if ($event == 'MY_TYPE') < require_once($_SERVER['DOCUMENT_ROOT'] . '/bitrix/php_interface/include/classes/custom_mail.php'); >>
В итоге для подключения файла к письму достаточно в письмо вставить строку
Преимущества : Можно подключать файлы из почтового шаблона.
Недостатки : Каждое письмо будет дополнительно обрабатываться перед отправкой - Content-type: text/html
- Content-type: text/plain
- Content-type: multipart/alternative