Своё письмо с сайта - тип события, шаблон, поля и отправка
Делаем своё письмо с сайта: тип события со списком полей, шаблон, отправку из кода и проверку доставки.
Механика
Письмо на платформе - это связка из трёх частей, и путать их не стоит. Тип события описывает, какие поля вообще бывают у этого письма и что они значат. Шаблон хранит тему письма, адреса отправителя и получателя и тело с подстановками. Код отправляет событие и передаёт в него значения полей по именам.
Разделение даёт главную выгоду: тело письма правит контент-менеджер, а не разработчик. Текст, тема и адрес получателя лежат в админке, поэтому смена формулировки не требует ни выкладки, ни программиста.
Значения полей подставляются в текст письма по именам, обрамлённым с двух сторон решёткой. Платформа просто заменяет подстроку значением, никакой проверки при этом нет: опечатка в имени оставляет в письме сырую подстановку, а забытое поле - пустое место.
Шаблонов у одного события бывает несколько, и уйдут при отправке они все сразу. Так делают уведомление менеджеру и покупателю на одно и то же событие, но лишний незамеченный шаблон превращается в дубль письма.
Шаблон письма привязан к сайту, а тип события - к языку интерфейса админки. На втором сайте письмо берётся из своего шаблона, и его заводят отдельно; общего шаблона на все сайты у платформы нет.
Отправка письма по умолчанию идёт не сразу, а через очередь событий. Событие только кладёт запись, а реальную отправку выполняет агент, поэтому письмо, не ушедшее за минуту, ищут сначала в очереди, а не у почтового провайдера.
Массовые письма отправляют совсем не так, и это важное ограничение механизма. Для рассылок есть отдельный модуль со списками, отписками и статистикой, а почтовые события рассчитаны на одиночные уведомления по действию человека.
Шаги
- Завести тип почтового события и перечислить в описании все его поля.
- Создать шаблон письма с темой, адресами и телом с подстановками.
- Отправить событие из кода, передав значения полей по именам.
- Проверить очередь отправки и работу агента, который её разбирает.
- Завести отдельный шаблон для второго сайта или языка, если они есть.
- Проверить письмо на живом ящике, а не только по журналу отправки.
Код
Заводим тип почтового события:
use Bitrix\Main\Mail\Internal\EventTypeTable;
EventTypeTable::add([ 'LID' => 'ru', // язык интерфейса, а не сайт 'EVENT_NAME' => 'VENDOR_CALLBACK', 'NAME' => 'Заявка на обратный звонок', 'DESCRIPTION' => "#NAME# - имя\n#PHONE# - телефон\n#PAGE# - страница заявки",]);// описание видит контент-менеджер при правке шаблона: это его единственная подсказкаОписание типа - не украшение, а документация полей. Через полгода никто не вспомнит, какие подстановки допустимы, и пустое описание превращает правку шаблона в угадывание.
Создаём шаблон письма:
use Bitrix\Main\Mail\Internal\EventMessageTable;
EventMessageTable::add([ 'EVENT_NAME' => 'VENDOR_CALLBACK', 'LID' => 's1', 'ACTIVE' => 'Y', 'EMAIL_FROM' => '#DEFAULT_EMAIL_FROM#', 'EMAIL_TO' => 'sales@example.org', 'SUBJECT' => 'Заявка с сайта от #NAME#', 'BODY_TYPE' => 'html', // текстовое письмо - это отдельное значение 'MESSAGE' => '<p>Имя: #NAME#</p><p>Телефон: #PHONE#</p><p>Страница: #PAGE#</p>',]);Тип тела задаётся полем, а не содержимым сообщения. Разметка в теле при текстовом типе уедет получателю как есть, вместе с угловыми скобками, и это самая частая жалоба на «кривое письмо».
Отправляем письмо из кода:
\Bitrix\Main\Mail\Event::send([ 'EVENT_NAME' => 'VENDOR_CALLBACK', 'LID' => SITE_ID, // сайт решает, какой шаблон возьмётся 'C_FIELDS' => ['NAME' => $name, 'PHONE' => $phone, 'PAGE' => $page],]);// значения передают строками: массив в поле подставится как слово ArrayОтправка кладёт запись в очередь и возвращается сразу. Долгих операций внутри нет, поэтому вызывать её из обработчика формы безопасно даже при недоступном почтовом сервере.
Отправляем сразу, минуя очередь:
\Bitrix\Main\Mail\Event::sendImmediate([ 'EVENT_NAME' => 'VENDOR_CALLBACK', 'LID' => SITE_ID, 'C_FIELDS' => ['NAME' => $name, 'PHONE' => $phone],]);// подходит для проверки шаблона руками, но не для боевого обработчика формыНемедленная отправка удобна при отладке: письмо либо уходит, либо сразу показывает ошибку. В боевом коде её избегают - недоступный почтовый сервер задержит ответ страницы на всё время ожидания.
Смотрим очередь отправки:
SELECT ID, EVENT_NAME, DATE_INSERT, SUCCESS_EXECFROM b_event ORDER BY ID DESC LIMIT 10;-- SUCCESS_EXEC = N означает, что письмо ещё не обработано агентомОчередь отвечает на главный вопрос разбора: письмо не сформировалось или не ушло. Записи в очереди нет - виноват код отправки; запись есть, но не обработана - виноват агент.
Заводим шаблон для второго сайта:
EventMessageTable::add([ 'EVENT_NAME' => 'VENDOR_CALLBACK', 'LID' => 's2', 'ACTIVE' => 'Y', 'EMAIL_TO' => 'sales-en@example.org', 'BODY_TYPE' => 'html', 'SUBJECT' => 'Request from #NAME#', 'MESSAGE' => '<p>Phone: #PHONE#</p>',]);// шаблон второго сайта заводят отдельно: общего на оба сайта не бываетПрикладываем файл к письму:
\Bitrix\Main\Mail\Event::send([ 'EVENT_NAME' => 'VENDOR_INVOICE', 'LID' => SITE_ID, 'C_FIELDS' => ['ORDER_ID' => $orderId], 'FILE' => [$fileId], // идентификатор файла из таблицы файлов]);Вложение передают идентификатором зарегистрированного файла, а не путём. Файл, лежащий во временной папке, до получателя не доедет, а письмо уйдёт без него и без единого сообщения об ошибке.
Ограничения
Подстановки в шаблоне не проверяются вообще, ни на одном из этапов. Ни при сохранении шаблона, ни при отправке платформа не сверяет список полей с переданными значениями, поэтому опечатка живёт до первой жалобы получателя.
Несколько активных шаблонов у одного события дают на каждое действие несколько писем. Это удобно для уведомления менеджеру и покупателю, но забытый старый шаблон рассылает дубли, и ищут его именно в списке шаблонов события.
Очередь разбирает агент, а агенты на малопосещаемом сайте стоят неделями без запуска. Уведомления о заявках на таком сайте приходят пачками раз в сутки, и лечится это переводом агентов на расписание системы.
Кодировка темы и тела письма берётся из настроек сайта, а не из шаблона. Письмо в верной кодировке с неверной пометкой выглядит набором символов, поэтому пометку меняют вместе с кодировкой сайта, а не отдельно.
Почтовые события совершенно не годятся для массовой рассылки по базе адресов. У них нет отписки, статистики и ограничения скорости, а массовая отправка с адреса сайта быстро приводит к попаданию домена в чёрные списки.
Проверять готовое письмо нужно на живом почтовом ящике, а не по журналу. Журнал отправки говорит лишь о том, что письмо ушло с сервера; как оно выглядит у получателя и попало ли в спам, видно только из самого ящика.
Типичные проблемы
В письме видна разметка вместо оформления.
У шаблона задан текстовый тип тела, а в сообщении лежит разметка. Тип тела письма - это отдельное поле шаблона, и переключают его явно руками.
В письме остались подстановки вида решётка-имя-решётка.
Поле не передано при отправке или его имя написано с опечаткой. Платформа подстановки не проверяет ни при сохранении, ни при отправке, и оставляет как есть.
На одно действие приходит два одинаковых письма.
У этого события больше одного активного шаблона, и уходят они оба. Лишний шаблон отключают, а не удаляют: он бывает нужен как черновик.
Письма приходят пачкой раз в сутки.
Очередь отправки разбирает агент, а запускается он обычными посетителями сайта, без расписания. Агенты в таком случае переводят на расписание операционной системы сервера.
На втором сайте письмо уходит по шаблону первого.
Шаблон привязан к сайту, и для второго его не завели. Общего шаблона сразу на оба сайта в платформе не предусмотрено вовсе.
Письмо ушло без вложения.
В параметрах передан путь к файлу, а не идентификатор зарегистрированного файла. Временные файлы, не попавшие в таблицу файлов, к письму не прикладываются.
Частые вопросы
Есть ли общий шаблон письма для сайта?
Общего шаблона нет: у каждого события свои шаблоны, привязанные к сайту. Единое оформление обычно делают одинаковой вёрсткой в теле шаблонов или подключением своей обёртки в обработчике отправки.
Как вставить разметку в почтовый шаблон?
Переключить тип тела шаблона на разметку и писать её прямо в сообщении. При текстовом типе разметка уйдёт получателю как обычный текст, вместе со всеми тегами.
Почему при заполнении формы письмо не создаётся?
У веб-формы своё почтовое событие, и шаблон для него нужно создать или включить отдельно. Форма сама шаблон не заводит, а без активного шаблона событие не превращается в письмо.
Как передать в письмо свои данные из обработчика?
Передать их в списке полей при отправке события, а в шаблоне поставить подстановки с теми же именами. Имена полей стоит перечислить в описании типа события, иначе о них никто не узнает.
Чем почтовое событие отличается от рассылки?
Событие - это одиночное письмо по действию, рассылка - массовая отправка списку с отпиской и статистикой. Для второй задачи в платформе есть отдельный модуль, и подменять его событиями не стоит.
Смежное
-
Почта и письма - оглавление подтемы
-
Приём входящих писем: ящик, разбор, привязка к заказу - обратное направление: письма на сайт
-
СМС из кода: событие и шаблон, прямая отправка, свой провайдер - тот же механизм для сообщений на телефон
-
Настройка отправки почты: локальная отправка и SMTP - чем письмо физически отправляется
-
Письма с сайта не доходят: разбор причин - что делать, когда письмо не пришло
-
Уведомления покупателю: письма и SMS по статусам заказа - готовые события магазина
-
Агенты не выполняются: разбор причин - почему очередь стоит
-
Инфраструктура - устройство сервера и окружения
-
Письмо с заявкой приходит пустым: разбор причин - когда подстановки не заменяются
-
Почтовые шаблоны: макросы, поля, мультисайт - правка готовых шаблонов и их макросов