Перейти к содержимому

Своё письмо с сайта - тип события, шаблон, поля и отправка

Делаем своё письмо с сайта: тип события со списком полей, шаблон, отправку из кода и проверку доставки.

Механика

Письмо на платформе - это связка из трёх частей, и путать их не стоит. Тип события описывает, какие поля вообще бывают у этого письма и что они значат. Шаблон хранит тему письма, адреса отправителя и получателя и тело с подстановками. Код отправляет событие и передаёт в него значения полей по именам.

Разделение даёт главную выгоду: тело письма правит контент-менеджер, а не разработчик. Текст, тема и адрес получателя лежат в админке, поэтому смена формулировки не требует ни выкладки, ни программиста.

Значения полей подставляются в текст письма по именам, обрамлённым с двух сторон решёткой. Платформа просто заменяет подстроку значением, никакой проверки при этом нет: опечатка в имени оставляет в письме сырую подстановку, а забытое поле - пустое место.

Шаблонов у одного события бывает несколько, и уйдут при отправке они все сразу. Так делают уведомление менеджеру и покупателю на одно и то же событие, но лишний незамеченный шаблон превращается в дубль письма.

Шаблон письма привязан к сайту, а тип события - к языку интерфейса админки. На втором сайте письмо берётся из своего шаблона, и его заводят отдельно; общего шаблона на все сайты у платформы нет.

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

Массовые письма отправляют совсем не так, и это важное ограничение механизма. Для рассылок есть отдельный модуль со списками, отписками и статистикой, а почтовые события рассчитаны на одиночные уведомления по действию человека.

Шаги

  1. Завести тип почтового события и перечислить в описании все его поля.
  2. Создать шаблон письма с темой, адресами и телом с подстановками.
  3. Отправить событие из кода, передав значения полей по именам.
  4. Проверить очередь отправки и работу агента, который её разбирает.
  5. Завести отдельный шаблон для второго сайта или языка, если они есть.
  6. Проверить письмо на живом ящике, а не только по журналу отправки.

Код

Заводим тип почтового события:

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_EXEC
FROM 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], // идентификатор файла из таблицы файлов
]);

Вложение передают идентификатором зарегистрированного файла, а не путём. Файл, лежащий во временной папке, до получателя не доедет, а письмо уйдёт без него и без единого сообщения об ошибке.

Ограничения

Подстановки в шаблоне не проверяются вообще, ни на одном из этапов. Ни при сохранении шаблона, ни при отправке платформа не сверяет список полей с переданными значениями, поэтому опечатка живёт до первой жалобы получателя.

Несколько активных шаблонов у одного события дают на каждое действие несколько писем. Это удобно для уведомления менеджеру и покупателю, но забытый старый шаблон рассылает дубли, и ищут его именно в списке шаблонов события.

Очередь разбирает агент, а агенты на малопосещаемом сайте стоят неделями без запуска. Уведомления о заявках на таком сайте приходят пачками раз в сутки, и лечится это переводом агентов на расписание системы.

Кодировка темы и тела письма берётся из настроек сайта, а не из шаблона. Письмо в верной кодировке с неверной пометкой выглядит набором символов, поэтому пометку меняют вместе с кодировкой сайта, а не отдельно.

Почтовые события совершенно не годятся для массовой рассылки по базе адресов. У них нет отписки, статистики и ограничения скорости, а массовая отправка с адреса сайта быстро приводит к попаданию домена в чёрные списки.

Проверять готовое письмо нужно на живом почтовом ящике, а не по журналу. Журнал отправки говорит лишь о том, что письмо ушло с сервера; как оно выглядит у получателя и попало ли в спам, видно только из самого ящика.

Типичные проблемы

В письме видна разметка вместо оформления.

У шаблона задан текстовый тип тела, а в сообщении лежит разметка. Тип тела письма - это отдельное поле шаблона, и переключают его явно руками.

В письме остались подстановки вида решётка-имя-решётка.

Поле не передано при отправке или его имя написано с опечаткой. Платформа подстановки не проверяет ни при сохранении, ни при отправке, и оставляет как есть.

На одно действие приходит два одинаковых письма.

У этого события больше одного активного шаблона, и уходят они оба. Лишний шаблон отключают, а не удаляют: он бывает нужен как черновик.

Письма приходят пачкой раз в сутки.

Очередь отправки разбирает агент, а запускается он обычными посетителями сайта, без расписания. Агенты в таком случае переводят на расписание операционной системы сервера.

На втором сайте письмо уходит по шаблону первого.

Шаблон привязан к сайту, и для второго его не завели. Общего шаблона сразу на оба сайта в платформе не предусмотрено вовсе.

Письмо ушло без вложения.

В параметрах передан путь к файлу, а не идентификатор зарегистрированного файла. Временные файлы, не попавшие в таблицу файлов, к письму не прикладываются.

Частые вопросы

Есть ли общий шаблон письма для сайта?

Общего шаблона нет: у каждого события свои шаблоны, привязанные к сайту. Единое оформление обычно делают одинаковой вёрсткой в теле шаблонов или подключением своей обёртки в обработчике отправки.

Как вставить разметку в почтовый шаблон?

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

Почему при заполнении формы письмо не создаётся?

У веб-формы своё почтовое событие, и шаблон для него нужно создать или включить отдельно. Форма сама шаблон не заводит, а без активного шаблона событие не превращается в письмо.

Как передать в письмо свои данные из обработчика?

Передать их в списке полей при отправке события, а в шаблоне поставить подстановки с теми же именами. Имена полей стоит перечислить в описании типа события, иначе о них никто не узнает.

Чем почтовое событие отличается от рассылки?

Событие - это одиночное письмо по действию, рассылка - массовая отправка списку с отпиской и статистикой. Для второй задачи в платформе есть отдельный модуль, и подменять его событиями не стоит.

Смежное

Первоисточник