Чек-лист тестирования транзакционных писем: 40 пунктов, о которых забывают
Классика, которую я ловил не раз: регистрация работает, а письмо со сбросом пароля улетает в спам. Или приходит с «Здравствуйте, {{first_name}}» вместо имени. Или ссылка «подтвердить почту» протухает за 15 минут, а письмо доходит через 20. Никто это не тестировал, потому что «это же просто письмо, что там может сломаться».
Ломается многое — и цена высокая: непришедшее письмо о сбросе пароля = заблокированный аккаунт и тикет в саппорт; письмо в спаме = потерянная регистрация. Транзакционные письма (welcome, сброс пароля, чек об оплате, алерты) — часть продукта, и тестировать их надо как продукт.
Почему письма — слепая зона QA
Письмо проходит длинный путь: событие в приложении → шаблон → рендер с подстановкой переменных → отправка через провайдера (SES/SendGrid/Postmark) → фильтры получателя → отрисовка в конкретном клиенте. Баг может жить на любом стыке, а видит его только тот, кто реально открыл письмо в реальном ящике — не «отправка вернула 200».
Триггер и содержимое
- Письмо приходит на нужное событие и ровно один раз (не на каждый ретрай запроса).
- Подставился правильный шаблон (не welcome вместо чека).
- Переменные заполнены: имя, сумма, дата, ссылка. Проверь пустые/отсутствующие поля — не должно быть «{{name}}», «undefined», «null», пустых строк.
- Множественное число и форматы: «1 товар / 2 товара / 5 товаров», суммы и даты по локали.
- Спецсимволы и юникод в имени/данных не ломают вёрстку и не вставляют HTML (экранирование — иначе XSS через письмо).
Доставляемость (доходит ли вообще)
- SPF, DKIM, DMARC настроены и проходят — иначе почта улетает в спам или отбивается.
- Прогони через спам-скоринг (mail-tester и подобные): вложения, «спам-слова», битый HTML, отсутствие plain-text — всё роняет репутацию.
- Корректные From / Reply-To / Return-Path, узнаваемое имя отправителя.
- Проверь доставку в Gmail, Outlook/Office365, Apple Mail, Яндекс/Mail.ru — фильтры у всех разные.
- Bounce и жалобы обрабатываются (hard bounce → не слать снова).
Ссылки и токены
- Ссылки ведут на правильное окружение (не на staging из прод-письма — частый и позорный баг).
- Срок жизни токена разумный и согласован с задержкой доставки (ссылка не должна протухать раньше, чем письмо дойдёт).
- Одноразовые ссылки (сброс пароля, подтверждение) отрабатывают ровно один раз.
- Ссылки не ломаются при переносе строк в клиенте; трекинг-редиректы не отваливаются.
- Unsubscribe работает и обязателен для рассылок (List-Unsubscribe заголовок + ссылка).
Рендеринг в почтовых клиентах
- Subject и preheader осмысленны, не обрезаются, без «(no subject)».
- Есть plain-text версия (multipart) — не только HTML.
- Тёмная тема: письмо читаемо (тёмный текст на тёмном фоне — классика провала).
- Картинки выключены (по умолчанию во многих клиентах): есть
alt, письмо понятно без картинок, ключевая инфа — не в картинке. - Gmail-клиппинг: письмо тяжелее ~102 КБ обрезается — держи компактным.
- Outlook (движок Word) ломает современный CSS — проверь отдельно; мобильная вёрстка адаптивна.
- Проверка рендера через caniemail/сервисы предпросмотра, а не «у меня в Gmail открылось нормально».
Тайминг, дубли, ретраи
- Без задвоения: ретрай отправки или двойной клик не шлёт два письма (идемпотентность по ключу события).
- Задержка приемлемая; критичные (сброс пароля, OTP) — быстро.
- Очередь переживает сбой провайдера: письмо не теряется и не шлётся 5 раз после восстановления.
Локализация и юридика
- Язык письма = язык/локаль пользователя; RTL не разъезжается.
- Для маркетинговых — физический адрес отправителя и unsubscribe (CAN-SPAM/GDPR).
- Персональные данные в письме — по минимуму (письма пересылают и логируют).
Чек-лист (быстрый прогон)
- Приходит на нужное событие, ровно один раз, правильный шаблон.
- Все переменные заполнены; пустые поля не дают «{{…}}»/undefined; экранирование есть.
- Множественное число, форматы сумм/дат по локали.
- SPF/DKIM/DMARC проходят; спам-скоринг зелёный.
- Доставка проверена в Gmail / Outlook / Apple Mail / Яндекс-Mail.ru.
- From/Reply-To корректны; bounce обрабатывается.
- Ссылки ведут на прод-окружение; токены одноразовые и не протухают раньше доставки.
- Unsubscribe работает (ссылка + List-Unsubscribe).
- Subject/preheader не обрезаны; есть plain-text версия.
- Читаемо в тёмной теме и с выключенными картинками (alt на месте).
- Не клиппится в Gmail (<~102 КБ); Outlook и мобилка проверены.
- Нет задвоения при ретраях/двойном клике; критичные письма быстрые.
- Локаль верная; для рассылок — адрес отправителя и согласие.
Коротко — что забрать с собой
- Транзакционное письмо — часть продукта, а не «просто письмо». Открывай его в реальном ящике.
- Доставляемость (SPF/DKIM/DMARC + спам-скоринг) решает больше, чем вёрстка: непришедшее письмо = 0.
- Три самых частых бага: пустая переменная («{{name}}»), ссылка на staging из прода, протухший токен.
- Рендер проверяй в тёмной теме, с выключенными картинками и в Outlook — там ломается.
- Идемпотентность отправки — чтобы ретрай не превратился в 5 писем.
Почитать: Can I email — поддержка в почтовых клиентах · Mail-Tester — проверка спам-скоринга и SPF/DKIM · DMARC.org — про аутентификацию почты