Допустим, ваша команда выпускает новое письмо для сброса пароля. QA принимает его на staging: письмо приходит, ссылка работает, шаблон выглядит правильно. Через два дня после релиза у поддержки очередь обращений. Люди с адресами Gmail говорят, что письмо не пришло. Сотрудники нескольких крупных компаний говорят, что пришло, но ссылка при первом нажатии оказалась «уже использованной». Между staging и боевой средой никто не менял код, и все тесты по-прежнему проходят.
Какой тестовый адрес почты для разработчиков поймал бы это? Ни один сам по себе. Локальный SMTP-перехватчик подходит для ежедневной разработки, песочница вашего провайдера или тестовый домен под вашим контролем — для автоматических тестов, а настоящий внешний ящик — для ручной проверки того, что почта выходит из окружения, близкого к боевому, и доходит до чужого домена. Временный ящик вроде VookMail закрывает этот последний случай без всякой настройки, потому что адрес готов при загрузке страницы. Контрольные аккаунты у крупных почтовых провайдеров затем покрывают то, чего не видит ничто из перечисленного. Остальная часть руководства о том, как выбирать из этих вариантов, как читать сбои, когда они случаются, и какие проверки стоит включить в релиз.
Почему сброс прошёл на staging
Staging и боевая среда редко так похожи, как предполагает схема развёртывания, а почта вскрывает различия сильнее, чем большинство функций. Сообщение проходит через ваше приложение, очередь, провайдера, DNS, сервер получателя и клиент получателя. На staging почти всё из этого может быть другой версии.
Возьмём первое обращение, пользователей Gmail, которые ничего не получили. Допустим, staging отправляет через поддомен провайдера, аутентифицированный несколько месяцев назад, а боевая среда отправляет с нового домена From, появившегося при ребрендинге. Правила Google для отправителей требуют от всех отправителей аутентификации через SPF или DKIM, а в таблице ошибок Gmail для неаутентифицированной почты указан код 5.7.26. Внутренний ящик QA на вашем собственном домене может пропустить то же письмо, потому что ваш собственный сервер может доверять вашему же ретранслятору. Тест просто не мог провалиться.
Второе обращение, ссылка «уже использована», имеет другую причину. Корпоративные шлюзы безопасности обычно открывают ссылки во входящих письмах, чтобы проверить их раньше, чем человек их увидит. Если ваша ссылка погашает токен простым запросом GET, сканер его расходует, и сотрудник нажимает на мёртвую ссылку. Ни один ваш ящик на staging этот сканер не запускает, если только ваша компания сама не использует такой.
Эти два бага нельзя увидеть из одного места. Для одного нужна настоящая доставка в принимающую систему, которой вы не управляете. Для другого нужно изменить поведение ссылки, и код-ревью поймало бы это легче, чем тест. В этом и состоит довод в пользу многослойного тестирования: каждый тип адреса отвечает на один вопрос и молчит о других.
| Что часто отличается между staging и боевой средой | Что это может скрыть |
|---|---|
Домен отправки и адрес From | Отсутствующие или несовпадающие SPF и DKIM |
| Аккаунт или субаккаунт у провайдера | Режим песочницы, лимиты отправки, другая репутация IP |
| Получатели | Внутренние домены, которые вам доверяют, и белые списки, скрывающие плохие адреса |
| Отслеживание кликов | Переписанные ссылки, которые ломаются, или домен отслеживания без действительного сертификата |
| Объём | Очереди и лимиты скорости, проявляющиеся только под нагрузкой |
| Списки подавления | Боевые адреса, которые однажды вернули отказ и теперь молча пропускаются |
| Настройки базового URL | Ссылки, указывающие не на тот хост |
Какой адрес на какой вопрос отвечает
Вот варианты, каждый с вопросом, на который он действительно может ответить.
Локальный перехватчик: «что произвело моё приложение?»
SMTP-перехватчик принимает всё, что отправляет ваше приложение, и показывает на веб-странице, ничего не доставляя. Популярный вариант с открытым кодом — Mailpit. По умолчанию он слушает SMTP на порту 1025 и отдаёт веб-интерфейс на порту 8025, поэтому вы направляете настройки разработки на localhost:1025 и открываете http://localhost:8025. Ethereal от Nodemailer — похожая идея с размещённым поддельным SMTP-сервисом. Перехватчик быстрый и закрытый, и он позволяет отправлять на любой адрес без малейшего риска, что письмо дойдёт до живого человека. Он также ничего не говорит о DNS, аутентификации или фильтрации, потому что ничто не покидает вашу сеть.
Тестовый помощник фреймворка: «просил ли мой код правильное письмо?»
Большинство фреймворков умеют записывать исходящую почту в памяти во время прогона тестов. В Laravel есть Mail::fake(), Django собирает сообщения в django.core.mail.outbox, а в Rails есть ActionMailer::Base.deliveries. Используйте их, чтобы проверить, что задание срабатывает один раз с правильным получателем и токеном. Это самая быстрая обратная связь, и они проверяют ещё меньше внешнего мира, чем перехватчик.
Тестовый режим провайдера: «работает ли моя интеграция?»
Провайдеры предлагают разную помощь, и различия важны. У Amazon SES есть симулятор почтового ящика с адресами вроде success@simulator.amazonses.com, bounce@simulator.amazonses.com и complaint@simulator.amazonses.com, которые порождают эти исходы, не вредя вашей репутации. Новый аккаунт SES также начинает в песочнице, где может отправлять только на подтверждённые адреса. Режим песочницы SendGrid, включаемый через mail_settings.sandbox_mode.enable, проверяет ваш запрос без доставки. Postmark принимает для той же цели токен POSTMARK_API_TEST. Это хорошо для ошибок API и для вебхуков об отказах и жалобах, но не показывает, что почта кого-то достигла. Проверяйте актуальную документацию своего провайдера, так как эти функции меняются.
Тестовый домен, которым вы владеете: «работает ли весь процесс, раз за разом?»
Для автоматических сквозных тестов настройте домен или поддомен под своим контролем с ящиком «ловушкой всей почты» или входящим вебхуком, чтобы тестовый код мог читать письма через API. Настройка требует усилий, но он закрытый и стабильный и не зависит от чужого сайта. Не придумывайте адреса на доменах, которыми не владеете. Кто-то может владеть testuser@gmail.com и получит то, что вы отправите. RFC 2606 резервирует example.com и домены верхнего уровня .test и .example, чтобы у документации и тестовых данных было безопасное место, на которое можно указывать. Эти имена не могут принимать почту, поэтому они подходят для фикстур и бесполезны для проверки доставки.
Настоящий внешний временный ящик: «получит ли это чужой домен?»
Здесь временный ящик оправдывает своё место. Это настоящий ящик на домене, которым вы не управляете и для которого у вас нет белого списка. Вашему письму нужно найти MX-запись, установить SMTP-соединение и быть принятым. В VookMail MX-записи доменов указывают на провайдера доставки почты, который принимает письмо и пересылает его по HTTPS. Новый адрес также означает отсутствие истории: ни старых писем, ни прежних отказов в вашем списке подавления, ни фильтров. Поэтому это быстрый способ воспроизвести «я зарегистрировался с новым адресом и ничего не получил». Это полезно и не только разработчикам. Дизайнер или продакт-менеджер может прочитать, что получает новый пользователь, без доступа к вашим инструментам.
Контрольные аккаунты у крупных почтовых провайдеров: «куда это попадает?»
Доставленное письмо на одном домене ничего не говорит о папке «Спам» на другом. Держите небольшой набор настоящих аккаунтов у провайдеров, которыми действительно пользуются ваши пользователи, и проверяйте попадание перед значительными изменениями шаблона или домена. Затем следите за числом отказов и жалоб после релиза. Если ваша почта выглядит как проблема со спамом, именно в этих аккаунтах вы увидите её первыми.
| Подход | Выходит в интернет | Настройка | Автоматизация | Конфиденциальность содержимого | Лучший этап |
|---|---|---|---|---|---|
| Тестовый помощник фреймворка | Нет | Нет | Отличная | Остаётся внутри процесса | Модульные и функциональные тесты |
| Локальный SMTP-перехватчик | Нет | Небольшая | Хорошая | Остаётся локально | Разработка |
| Тестовый режим провайдера | Обычно нет | Небольшая | Хорошая | Остаётся у провайдера | Интеграционные тесты |
| Собственный тестовый домен | Да | От средней до высокой | Хорошая | Вы контролируете | Сквозные тесты в CI, staging |
| Временный ящик | Да | Нет | Не рекомендуется | Считайте общедоступным | Ручной QA и предрелизные проверки |
| Контрольные аккаунты | Да | Средняя | Ограниченная | Умеренная | Проверка попадания |
Ручной прогон с временным ящиком
Вот повторяемый проход по процессу регистрации на staging или в предпродакшн-окружении. Когда вы его освоите, он должен занимать минут десять.
- Убедитесь, что окружение использует ту же конфигурацию провайдера, что и боевое, кроме учётных данных, и содержит только выдуманные данные. Если нет, запишите это, потому что это ограничивает ваши выводы.
- Откройте VookMail и нажмите Новый. Введите имя пользователя, кодирующее тест, например
email-signup-03-x7, выберите один из более чем 30 доменов и нажмите стрелку. Используйте жёлтую кнопку «Случайный», если в письме может быть что-то чувствительное, потому что любой, кто знает или угадает адрес, может открыть этот ящик. - Нажмите Копировать и зарегистрируйтесь как новый пользователь с выдуманными данными профиля.
- Отметьте время отправки формы и время появления письма. Ящик проверяет почту каждые несколько секунд, поэтому разрыв в минуты указывает на вашу очередь или провайдера. Нажмите Обновить, если хотите убедиться.
- Прочитайте письмо так, как его прочитал бы новый пользователь: имя отправителя, тема, текст предпросмотра, тело, кнопка, обычная ссылка, подвал. VookMail показывает найденные коды и ссылки подтверждения над письмом, что даёт грубую проверку того, что ваш код и ссылку легко заметить.
- Посмотрите на него с отключёнными изображениями. VookMail не показывает изображения, пока вы не разрешите, и удаляет скрытые отслеживающие пиксели. Если письмо в таком виде бессмысленно, часть ваших пользователей видит то же самое. Но не используйте этот ящик для оценки отслеживания открытий, так как пиксели не сработают.
- Нажмите кнопку QR, отсканируйте адрес тестовым телефоном и откройте там тот же ящик, чтобы нажать настоящую ссылку на настоящем устройстве, особенно если вы используете универсальные ссылки или app links.
- Завершите подтверждение и убедитесь, что состояние аккаунта меняется как нужно.
- Проведите отрицательные случаи из контрольного списка ниже: повторно используйте ссылку, дождитесь истечения срока, запросите повторную отправку.
- Сохраните доказательства: скриншоты, время и использованный адрес. Письма удаляются примерно через сутки, так что отчёт об ошибке, написанный на следующей неделе, будет не на что опереть.
- Нажмите Удалить и удалите тестовый аккаунт, если этого требует ваш процесс.
В одном браузере можно держать несколько адресов, поэтому пригласивший и приглашённый или старый и новый адрес при смене почты могут быть открыты одновременно. Если вы прикладываете в тесте файлы, помните, что VookMail отклоняет распространённые программные файлы вроде .exe и показывает предупреждение для архивов, так что отклонённое там вложение может не быть ошибкой с вашей стороны.
Как читать сбой
«Письмо не пришло» описывает симптом, который может возникнуть примерно в шести местах, и команды теряют часы, начиная не с того. Двигайтесь по пути от вашего кода наружу и останавливайтесь на первом месте, где вы больше не видите письма.
- Пыталось ли приложение? Найдите в журнале приложения попытку отправки и любое исключение. Ищите задание, которое так и не создали, часто потому что условие или флаг функции были ложными.
- Запускался ли обработчик? Проверьте зависшие, упавшие или повторяемые задания. Обработчик очереди, который не перезапустили после развёртывания, может исполнять старый код, а политика повторов может отправлять дубликаты.
- Принял ли письмо провайдер? Найдите получателя или
Message-IDв журнале активности провайдера. «Принято», «отложено», «отказ» и «отброшено» — четыре разные истории. - Не подавлено ли оно? Если этот адрес раньше вернул отказ или пожаловался, многие провайдеры молча пропускают будущие отправки. Это часто ловит тестировщиков, повторно использующих старый адрес.
- Что сказал принимающий сервер? Журналы провайдера обычно показывают ответ SMTP, и этот текст — самая полезная строка во всём расследовании.
- Правильный ли DNS? Проверьте SPF, DKIM и DMARC для реального домена отправки.
- Письмо есть, но скрыто? Папки спама, вкладки и фильтры клиента идут последними, когда это сможет показать контрольный аккаунт.
Что говорит ответ SMTP
По RFC 5321 ответ, начинающийся с 4, означает временный сбой, и отправителю следует повторить попытку позже. Ответ, начинающийся с 5, постоянный. Расширенные коды состояния из RFC 3463 добавляют подробности после него. Выдуманная строка журнала может выглядеть так, только как пример формата:
Только пример: to=user@gmail.example status=bounced reply="550 5.7.26 unauthenticated sender"
Читайте слева направо. 5 означает, что повторы не помогут. Семейство 5.7 касается безопасности или политики, что направляет вас к DNS и подписи, а не к адресу получателя. Таблица ниже даёт отправную точку для частых случаев.
| Что вы видите | Наиболее вероятный слой | Где смотреть сначала |
|---|---|---|
| Ничего в журнале провайдера | Приложение или очередь | Журналы приложения и упавшие задания |
| Провайдер пишет «dropped» или «suppressed» | Список подавления провайдера | Удалите тестовый адрес или используйте новый |
| API возвращает успех, но нигде не записано, что письмо отправлено | Режим песочницы всё ещё включён | Настройки провайдера для этого окружения |
5.1.1 или подобное | Адрес получателя | Опечатки и проверка формы, которая изменила адрес |
5.7.26 в Gmail | Аутентификация | SPF, DKIM и согласованность с доменом From |
Отсрочки 4xx, проходящие через некоторое время | Получатель вас замедляет | Объём, репутация или новый IP отправки |
| Доставлено во внешний ящик, отсутствует в Gmail | Политика или фильтрация получателя | Контрольные аккаунты и правила Google для отправителей |
| Приходит, но ссылка пишет «уже использована» | Сканер предзагружает ссылку | Погашайте токены через POST, а не GET |
| Ссылка ведёт на предупреждение безопасности | Домен отслеживания кликов | Сертификат на поддомене отслеживания |
| Приходит дважды | Логика повторов | Идемпотентность заданий и таймауты, запускающие повторы |
| Приходит очень поздно | Очередь | Мощность обработчиков и делит ли письмо сброса очередь с массовой рассылкой |
Последняя строка — вопрос проектирования, заслуживающий ещё одного предложения. Если сбросы паролей делят очередь с рассылкой новостей, они ждут за ней. Дайте транзакционной почте собственную очередь и, в идеале, собственный поддомен и поток отправки, чтобы маркетинговая проблема не задерживала вход.
Команды, сокращающие поиск
Почти всё это можно проверить, не выходя из терминала. В этих примерах замените примерные имена своими.
dig +short MX example.comпоказывает, где домен принимает почту. Пустой ответ требует внимания, так как RFC 5321 позволяет отправителям вернуться к адресной записи, а ответ0 .— это нулевая MX по RFC 7505, то есть домен вообще не принимает почту.dig +short TXT example.comпоказывает запись SPF среди прочих текстовых записей.dig +short TXT selector._domainkey.example.comпоказывает ключ DKIM. Настоящий селектор возьмите из значенияs=в заголовкеDKIM-Signatureписьма.dig +short TXT _dmarc.example.comпоказывает политику DMARC.openssl s_client -starttls smtp -connect smtp.example.com:587проверяет, что вы можете подключиться к своему ретранслятору, и показывает его сертификат. Сбой здесь означает проблему брандмауэра или TLS задолго до чего-либо про содержимое.swaks --to qa@example.test --from app@example.test --server localhost:1025отправляет простое письмо вручную. Оно обходит ваше приложение, поэтому вы можете понять, относится ли проблема к вашему коду или к маршруту.
Для доказательств на уровне заголовков самый надёжный вариант — ящик под вашим контролем у крупного провайдера. В Gmail откройте письмо, воспользуйтесь меню с тремя точками и выберите Показать оригинал, где вверху перечислены результаты SPF, DKIM и DMARC. Помните, что «пройдено» у одного получателя не гарантирует того же у другого.
Что проверять в каждом процессе
«Пришло ли?» — первый вопрос и обычно наименее интересный. После этого у каждого процесса свои способы пойти не так.
Сброс пароля
Памятка OWASP Forgot Password Cheat Sheet — тот источник, на который стоит опираться. Она требует одинакового сообщения независимо от того, существует ли аккаунт, ответов за одинаковое время, токенов случайных, длинных, надёжно хранимых и одноразовых, и заголовка Referrer-Policy: no-referrer на странице сброса.
- Страница запроса показывает одно и то же сообщение для зарегистрированных и незарегистрированных адресов и отвечает примерно за одно и то же время. Мгновенный ответ для неизвестных адресов раскрывает столько же, сколько и формулировка.
- Ссылка работает один раз. Откройте её второй раз, и вы получите понятное объяснение со способом запросить другую.
- Новый запрос сброса аннулирует старые ссылки, или ваш замысел намеренно говорит иное.
- Срок действия контролирует сервер, и это проверено ожиданием или изменением времени в тестовой среде.
- Успешный сброс отправляет письмо-подтверждение, а остальные сессии обрабатываются согласно вашей политике.
- Открытие ссылки само ничего не меняет. Токен погашается при отправке формы.
- Страница сброса не отправляет свой URL в сторонние системы аналитики или отслеживания ошибок.
- Лимиты скорости действуют и для аккаунта, и для IP, чтобы никто не мог завалить чужой ящик.
- Адреса с разным регистром или знаками плюс работают так же, как простые.
Подтверждение регистрации
- Одна регистрация отправляет одно письмо, в том числе при повторе задания.
- Ссылка или код работает один раз, а страница истёкшей ссылки предлагает, что делать дальше.
- Повторная отправка либо аннулирует прежний токен, либо сосуществует с ним по замыслу и ограничена по скорости.
- У неподтверждённых аккаунтов именно те ограничения, которые вы задумали.
- Повторная регистрация с уже зарегистрированным адресом не сообщает анонимному посетителю, что аккаунт существует, если ваш продукт считает это чувствительным. Распространённый приём — вместо этого написать существующему владельцу.
- Ссылка указывает на правильное окружение. Письмо со staging со ссылкой на боевую среду рано или поздно изменит боевые данные.
Коды входа и волшебные ссылки
- Коды достаточно длинные, быстро истекают и имеют лимит попыток.
- Волшебные ссылки показывают страницу с кнопкой и погашаются по этому POST, так что GET от сканера не вредит.
- Открытие ссылки на другом устройстве делает то, что сказано в вашем замысле, и пользователь понимает, что произошло.
- В теме письма указывается код, только если вы решили, что это допустимо, так как уведомления показывают её на экранах блокировки.
Смена адреса почты
- Подтверждение идёт на новый адрес, и ничего не меняется, пока оно не подтверждено.
- Уведомление идёт на старый адрес, чтобы настоящий владелец мог отреагировать на несанкционированное изменение.
- Невыполненные токены сброса перестают работать после смены.
- Два временных ящика позволяют быстро проверить это вручную.
Приглашения, чеки и уведомления
- Приглашение человеку без аккаунта ведёт к регистрации с заполненным или заблокированным адресом, как задумано. Истёкшее или отозванное приглашение об этом сообщает.
- Приглашение не может быть принято другим аккаунтом, если ваш замысел этого не допускает.
- Чеки показывают верные суммы, валюты, даты и часовые пояса для локали пользователя, а у вложений разумные имена, и они нормально открываются.
- Изменения настроек вступают в силу со следующей отправки.
- У второстепенной почты работает отписка, а письма об аккаунте и безопасности явно отделены. Наша статья о перегрузке рассылками показывает, как это выглядит со стороны читателя.
- Переведённые шаблоны есть для каждого поддерживаемого языка, с правильной вёрсткой справа налево там, где это нужно, и без непереведённых фрагментов в теме.
Проверка кода токенов
Тестирование через ящик показывает поведение. Короткий код-ревью ловит недостатки проектирования, которые не покажет ни один ящик. Когда читаете код, стоящий за сбросом, подтверждением и волшебными ссылками, ищите следующее.
- Источник случайности. Это должен быть криптографически стойкий генератор, например
secrets.token_urlsafe(32)в Python,crypto.randomBytes(32)в Node илиrandom_bytes(32)в PHP. Метка времени, возрастающий ID или хеш адреса почты недопустимы. - Длина. Токены в ссылках обычно несут не менее 128 бит случайности. Шестизначный код приемлем только при жёстком сроке действия и лимите попыток.
- Хранение. Храните хеш токена, чтобы утечка базы данных не раздала рабочие ссылки сброса.
- Сравнение. Используйте функцию с постоянным временем, например
hmac.compare_digest,hash_equalsилиcrypto.timingSafeEqual, там, где сравниваете секретные значения напрямую. - Назначение. Токен подтверждения не должен работать как токен сброса, а токен для одного аккаунта не должен работать для другого.
- Срок действия. Время истечения хранит сервер, поэтому его нельзя изменить правкой ссылки.
- Аннулирование. Использование токена, смена пароля другим путём или смена почты должны отменять невыполненные токены.
- Журналирование. Полные URL с токенами не должны попадать в журналы приложения, события аналитики или системы отслеживания ошибок. Проверьте и журналы доступа HTTP.
Заголовки и аутентификация
Откройте исходный код письма в перехватчике, чтобы увидеть, что произвело ваше приложение, и в ящике под вашим контролем у крупного провайдера, чтобы увидеть, что добавили провайдер и сеть.
| Заголовок или элемент | Что проверить |
|---|---|
From | Правильное название бренда на домене, которым вы владеете и который аутентифицирован |
Reply-To | Ящик, за которым следят, или осознанное отсутствие |
Return-Path | Домен отказов, согласованный с вашим доменом, если вы полагаетесь на SPF для DMARC |
DKIM-Signature | Присутствует, с доменом d=, согласованным с доменом From |
Message-ID | Присутствует и уникален, так как это ваш ключ для отслеживания в журналах провайдера |
Content-Type | multipart/alternative с HTML-частью и частью простого текста |
List-Unsubscribe, List-Unsubscribe-Post | Присутствуют в массовой и маркетинговой почте, поддерживают отписку в один клик по RFC 8058 |
Auto-Submitted | auto-generated для автоматической почты, как определено в RFC 3834, чтобы помочь предотвратить циклы ответов |
Несколько правил, которые стоит проверить перед запуском нового домена отправки. Проверка SPF не может превышать десять запросов DNS (RFC 7208), и превышение лимита — лёгкий способ получить сбой, добавив в запись ещё одного поставщика. Для DKIM нужно, чтобы запись селектора провайдера была опубликована и проверялась. Для DMARC нужна запись на вашем домене From, обычно начиная с p=none с включёнными отчётами и ужесточая после подтверждения согласованности.
Объём тоже меняет правила. Правила Google считают отправителя массовым примерно при 5000 писем в день на личные аккаунты Gmail, и массовым отправителям нужны SPF, DKIM и DMARC, отписка в один клик в рекламной почте и доля пользовательских жалоб на спам ниже 0,3%, с рекомендуемой целью 0,1%. У других провайдеров свои правила. Например, Amazon SES берёт аккаунт на проверку при доле отказов 5% или доле жалоб 0,1%. Берите актуальные цифры из документации своего провайдера, прежде чем строить на них планы, поскольку они меняются.
Обработка и проверка адресов
Формы отвергают допустимые адреса чаще, чем люди думают, а ошибка проверки на входе может выглядеть в точности как сбой доставки. Проверьте свою на этом.
| Ввод | Ожидаемая обработка | Частая ошибка |
|---|---|---|
user+tag@example.com | Принять | Регулярное выражение отвергает знак плюс |
User@Example.COM | Принять и считать домен нечувствительным к регистру | Дубликаты аккаунтов, различающиеся только регистром |
o'brien@example.com | Принять | Отвергается или ломает запрос либо шаблон без экранирования |
first.last@sub.example.co.uk | Принять | Проверка предполагает одну точку в домене |
| Пробелы в начале или конце | Сначала обрезать | «Неверный email» при правильной вставке |
| Очень длинный адрес | Ограничить 64 символами для локальной части и 254 в целом | Короткий столбец базы данных молча его обрезает |
| Интернационализированные домены и адреса | Принимать или отказывать последовательно, с понятным сообщением | Сбой в кодировке или журналировании |
| Домен без маршрута почты | Предупредить или отвергнуть | Аккаунт, который никогда не подтвердится |
Проверяйте в форме нестрого, а затем пусть письмо-подтверждение докажет, что адрес работает. Строгое регулярное выражение отсеивает настоящих пользователей и очень мало говорит о том, существует ли ящик.
Если ваш продукт в боевой среде отвергает одноразовые домены, вашему процессу QA всё равно нужен путь на staging. Варианты: белый список тестовых доменов вне боевой среды, флаг, отключающий проверку в тестовых окружениях, или собственный тестовый домен. Не ослабляйте боевое правило ради удобства тестирования. А если вы решаете, нужно ли такое правило вообще, наша статья о том, почему сайты блокируют одноразовую почту, излагает издержки и выгоды с точки зрения владельца.
Как это отображается
Отображение — то место, где ревью дизайнера помогает больше всего, и для него нужны настоящие письма в настоящих клиентах.
- Часть простого текста читается хорошо и содержит полную ссылку. «Нажмите кнопку ниже» там бесполезно.
- Тёмная тема оставляет логотипы видимыми и сохраняет контраст. В VookMail есть тёмная тема, это начало, а настоящий тест — клиенты, которым отдают предпочтение ваши пользователи.
- При заблокированных изображениях призыв к действию остаётся настоящей текстовой ссылкой или HTML-кнопкой.
- Кнопки достаточно велики для нажатия, а длинные URL не ломают вёрстку на телефоне.
- Текст предпросмотра написан намеренно, без остатков формулировок шаблона.
- Заголовки семантические, контраст достаточный, текст ссылок описательный, а у HTML есть атрибут языка.
- Отсутствие данных не порождает «Здравствуйте, {first_name}» или «Здравствуйте, ,».
- Размер письма остаётся заметно меньше примерно 102 КБ — точки, после которой, по широко распространённым сообщениям, Gmail обрезает длинные письма. Обрезка может скрыть подвал и любую ссылку отписки в теле.
Защита от случайностей
Конфузные почтовые инциденты — в основном ошибки конфигурации: почта со staging доходит до настоящих клиентов, боевая среда работает на тестовом ключе, ссылки ведут на localhost. Несколько настроек предотвращают большинство из них.
Держите отдельные учётные данные для каждого окружения, в переменных окружения или хранилище секретов. Вне боевой среды используйте белый список получателей, чтобы почтовая служба доставляла только на одобренные тестовые домены, а всё остальное перенаправляла или отбрасывала. Стройте каждую ссылку из одной настройки, такой как APP_URL, чтобы в шаблонах не было жёстко прописанных хостов. Добавляйте к темам небоевых окружений префикс вроде [STAGING], чтобы ошибочно отправленное письмо было очевидно тому, кто его получит.
Если вы копируете боевые данные на staging, замените каждый настоящий адрес синтетическим до запуска любого почтового обработчика. Порядок важен, потому что обработчик, запущенный первым, может сразу начать разбирать запланированную почту. И отслеживайте режим песочницы для каждого окружения сознательно. Запуск с боевой средой, всё ещё находящейся в песочнице, — классика: API возвращает успех, журналы чистые, а почта не уходит.
Автоматические наборы тестов должны оставаться на инфраструктуре под вашим контролем
Публичный временный ящик — неправильная зависимость для CI. Скрейпинг чужой веб-страницы хрупок, а ваши сборки падали бы по причинам, не связанным с вашим кодом. Это также направляет ваш тестовый трафик на сервис, которым вы не управляете. Письма там может прочитать любой, у кого есть адрес, поэтому ничто автоматическое не должно на них зависеть.
Разумная схема выглядит так. Помощники фреймворка проверяют, что запрошено правильное письмо. Контейнер Mailpit в вашем тестовом стеке получает настоящее письмо, а тест читает его через HTTP API Mailpit (GET /api/v1/messages), извлекает ссылку и переходит по ней. Тестовый режим провайдера проверяет вебхуки и обработку ошибок. Ночное задание на вашем тестовом домене отправляет через настоящего провайдера и читает результат через входящий вебхук, так что вы ежедневно получаете сигнал, что настоящая доставка всё ещё работает.
Временная почта относится к человеческим частям тестирования: исследовательским сессиям, где быстро нужна свежая личность, дымовому тесту перед релизом, воспроизведению сообщения пользователя, ревью текстов и дизайна и тестированию на телефоне. Для последнего кнопка QR или приложение из Google Play или Huawei AppGallery переносит ящик на тестовое устройство. Проверьте, что ссылки открывают ваше приложение, когда оно установлено, и переходят на работающую веб-страницу, когда нет, и что приложение замечает статус подтверждения без нового входа.
Тест-кейс, который переживёт передачу дел
Единообразные тест-кейсы легче повторять каждый релиз и передавать между тестировщиками. Этот пример содержит поля, которые обычно важны.
| Поле | Пример |
|---|---|
| ID теста | EMAIL-RESET-03 |
| Процесс | Сброс пароля, повторное использование токена |
| Предусловия | Подтверждённый тестовый аккаунт на staging, со свежим временным адресом |
| Шаги | Запросить сброс, открыть ссылку, задать новый пароль, снова открыть ту же ссылку |
| Ожидаемый результат | Второе использование объясняет, что ссылка больше недействительна, и предлагает новый запрос |
| Доказательства | Скриншоты, Message-ID при наличии, время, использованный адрес |
| Окружение | Номер сборки staging и конфигурация почты |
Если указать ID теста в имени пользователя, как в email-reset-03-x7, каждый ящик привязывается к своему кейсу, а два тестировщика не сталкиваются на одном адресе. Короткий случайный суффикс нужен потому, что любой может открыть ящик, если угадает имя.
Чего не отправлять в публичный ящик
Считайте любой временный ящик доступным каждому, кто знает адрес, и тестируйте соответственно.
- Отправляйте только синтетические данные: вымышленные имена, вымышленные заказы, вымышленные адреса. Данным настоящих клиентов там не место, и в зависимости от того, где вы работаете, их отправка может создать для вас и юридическую проблему.
- Никогда не отправляйте ключи API, учётные данные базы данных или приглашения администратора для настоящих систем.
- Регулярно удаляйте тестовые аккаунты, особенно привилегированные. Тестовый администратор, привязанный к публичному ящику, — это путь внутрь, если кто-то другой откроет этот ящик и запросит сброс. Поскольку после очистки адрес за вами не закреплён, этот риск сохраняется и после теста.
- Никогда не используйте временный адрес как владельца настоящего боевого аккаунта или стороннего сервиса, на который опирается ваша компания.
- Знайте срок хранения. Письма и вложения удаляются примерно через сутки, а подробности есть в политике конфиденциальности.
Тестирование собственного продукта — одно из самых ясных законных применений одноразовой почты. Пусть так и остаётся: тестируйте системы, которыми владеете или которые вам разрешено тестировать. Не используйте временные ящики, чтобы создавать аккаунты на сервисах других компаний вопреки их условиям, собирать пробные периоды или нагрузочно тестировать чужую форму регистрации. Условия использования описывают допустимое использование, а страница о методологии объясняет, как работает сервис. VookMail входит в сеть бесплатных инструментов PAYATE.
Перед релизом
- SPF, DKIM и DMARC проверены для реального боевого домена отправки, домен
Fromсогласован. - Боевая почтовая служба работает на боевых учётных данных, режим песочницы выключен, подтверждено настоящим письмом.
- Подтверждение регистрации получено на свежий внешний адрес, ссылка использована один раз, срок действия проверен.
- Сброс пароля проверен от начала до конца, включая одинаковые ответы для неизвестных адресов и письмо-подтверждение.
- Токены сброса и волшебных ссылок погашаются при отправке формы, чтобы GET от сканера их не расходовал.
- Смена почты отправляет письма и на новый, и на старый адрес.
- Все ссылки указывают на боевой хост по HTTPS, включая переписанные отслеживанием кликов.
- Транзакционная почта отделена от массовой, хотя бы в очереди.
- HTML и простой текст присутствуют и читаемы, тёмная тема и заблокированные изображения проверены.
- Проверка попадания на контрольных аккаунтах, если домен или шаблон значительно изменились.
- Отписка работает в второстепенной почте, переведённые шаблоны просмотрены.
- Доказательства приложены к заявке на релиз, а числа отказов и жалоб выведены на панель, за которой кто-то будет следить после запуска.
Вопросы, которые задают разработчики
Настоящий ящик принял моё письмо. Безопасно ли это в Gmail?
Нет. Доставка на один домен показывает, что ваше письмо ушло, нашло маршрут и было там принято. У Gmail свои правила аутентификации и фильтрации, как и у любого другого крупного провайдера. Для этого вопроса используйте контрольные аккаунты и Postmaster Tools от Google.
Можно ли использовать один и тот же тестовый адрес повторно?
В пределах сессии можно, но свежий адрес даёт более чистый тест. Старые адреса накапливают записи подавления и старые письма, а на временном сервисе ящик в любом случае очищается примерно через сутки.
Письма приходят в мой перехватчик, но не приходят наружу. С чего начать?
Перехватчик показывает, что ваше приложение создало письмо, и ничего сверх этого, поэтому начните с журнала активности провайдера. Чаще всего ответ — настройка песочницы, запись подавления, неверные учётные данные или отказ SMTP, называющий аутентификацию.
Как долго должна действовать ссылка сброса?
Достаточно коротко, чтобы ограничить ущерб, и достаточно долго, чтобы успело прийти медленное письмо. Многие команды останавливаются где-то между 15 минутами и часом, но это зависит от вашего риска и от того, как быстро доставляется ваша почта, а почта ваших пользователей может задерживаться не по вашей вине. Что бы вы ни выбрали, проверьте состояние истечения и скажите людям, что делать дальше.
