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

Настройка отправки почты - локальная отправка и SMTP

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

Решение

Отправляем тестовое письмо средствами платформы:

CEvent::SendImmediate('NEW_ORDER', SITE_ID, [
'ORDER_ID' => 1,
'EMAIL_TO' => 'test@example.com',
], 'N');
// вызов минует очередь и ждёт ответа почтового сервера прямо здесь
// последний параметр - отправлять ли письмо в обход очереди

Немедленная отправка обходит очередь и сразу показывает результат. Обычная CEvent::Send кладёт письмо в очередь, и его отправит агент - удобно на проде, но неудобно при проверке.

Смотрим, приняла ли письмо почтовая программа сервера:

Окно терминала
tail -n 30 /var/log/maillog 2>/dev/null || tail -n 30 /var/log/mail.log
grep -i 'status=' /var/log/maillog | tail -10 # sent, bounced или deferred
mailq | tail -5 # что застряло в очереди сервера

Строка со статусом отвечает на главный вопрос: письмо ушло или застряло. status=sent означает, что сервер получателя его принял, и дальше разбираться надо у получателя.

Настраиваем отправку через внешний SMTP:

// пароль приложения, а не обычный пароль ящика: сервисы требуют именно его
COption::SetOptionString('main', 'smtp_server', 'smtp.example.com');
COption::SetOptionString('main', 'smtp_port', '465');
COption::SetOptionString('main', 'smtp_login', 'noreply@example.com');
COption::SetOptionString('main', 'smtp_password', $appPassword);

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

Проверяем доступность почтового сервера с сайта:

Окно терминала
# порт 465 для SSL, 587 для STARTTLS: закрытый порт даёт таймаут без объяснений
timeout 5 bash -c '</dev/tcp/smtp.example.com/465' && echo 'порт открыт'
openssl s_client -connect smtp.example.com:465 -quiet 2>&1 | head -3

Хостинги часто закрывают исходящие подключения на почтовые порты. Тогда сайт молча не отправляет ничего, а в логе не появляется вообще ничего.

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

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

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

Письма уходят, но попадают в спам.

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

SMTP не подключается, ошибок в логе нет.

Хостинг закрыл исходящие подключения на почтовые порты. Проверяют доступность порта с сервера напрямую: сайт при этом не сообщает ничего.

Сервис отклоняет обычный пароль ящика.

Публичные почтовые сервисы требуют отдельный пароль приложения. Обычный пароль они не принимают даже при верном логине.

Письмо приходит с искажённым русским текстом.

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

Часть писем не отправляется вовсе.

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

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

Чем локальная отправка отличается от SMTP?

При локальной письмо отдаётся почтовой программе сервера и уходит от его имени. При SMTP сайт подключается к почтовому сервису и отправляет от имени настоящего ящика. Второй способ надёжнее: у сервиса есть репутация, у случайного сервера её нет.

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

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

Можно ли слать письма на разных языках?

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

Почему письмо не ушло, а ошибки нет?

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

Смежное

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