руководство · возврат писем
Как продуктовой команде безопасно диагностировать и обрабатывать возвраты писем?
Рассматривайте возврат письма (bounce-back) как данные о доставке, привязанные к одному получателю и одной попытке, а не как общий флаг ошибки. Сохраняйте исходный идентификатор письма, отправителя в конверте, получателя, код SMTP или расширенный код состояния, диагностическое сообщение, сообщивший сервер и время события. Отделяйте немедленное отклонение по SMTP от последующего уведомления о статусе доставки (DSN). Повторяйте только временные ошибки 4.x с ограниченной задержкой (backoff) и лимитом времени в очереди; после подтверждённой постоянной ошибки 5.x прекращайте повторы для этого получателя и добавляйте его в стоп-лист. Аутентифицируйте события провайдера, устраняйте дубли, не порождайте обратное рассеяние (backscatter) и разделяйте состояния: приём провайдером, приём сервером назначения, последующая недоставка и попадание во «Входящие».
Определите, где был зафиксирован сбой
Продукт может узнать о недоставке во время SMTP-сессии, из последующего уведомления о статусе доставки или из аутентифицированного события провайдера. У этих наблюдений разная доказательная база. Немедленный отказ на RCPT TO относится к этому получателю ещё до приёма данных письма. Отклонение на этапе DATA может относиться ко всей переданной транзакции. Последующий DSN сообщает, что система приняла ответственность, а затем не смогла доставить или переслать письмо. Фиксируйте этап, сервер, область получателей, попытку, временную метку, SMTP-ответ, расширенный код состояния, диагностическое сообщение и исходные идентификаторы корреляции. Не сводите все случаи к «отказу». Храните исходную полезную нагрузку (payload) провайдера или DSN в стандартном формате только столько, сколько требуют операционные нужды и политика, и с ограниченным доступом. Скриншот из поддержки или пересказ человеком — недостаточное основание для автоматических повторов, добавления в стоп-лист или статуса, показываемого клиенту.
Разделяйте временные и постоянные результаты
SMTP использует ответы 4yz для временного отрицательного завершения и 5yz — для постоянного. Расширенные коды состояния добавляют класс, начинающийся с 4 для устойчивой временной ошибки или с 5 для постоянной, за которым следуют значения темы и детализации. Сохраняйте и базовый, и расширенный коды, потому что один лишь текст зависит от провайдера и может меняться. Временный результат может оправдывать повтор того же логического письма после задержки; он не оправдывает немедленные циклы или бесконечное пребывание в очереди. Постоянная ошибка получателя должна останавливать автоматические повторы для этого получателя и этой попытки, пока адрес или политика не изменятся через авторизованный процесс. Не определяйте «жёсткий» или «мягкий» отказ только по неформальным меткам провайдера. Стройте политику на точном статусе, этапе, диагностическом сообщении, классе писем, получателе и актуальной документации провайдера. Неизвестные или некорректные ответы должны безопасно отправляться на ручной разбор или в очередь недоставленных сообщений (dead-letter), а не приводить к повторной отправке по умолчанию.
Разбирайте уведомления о статусе доставки с осторожностью
RFC 3464 определяет машиночитаемый формат уведомления о статусе доставки, передаваемого в multipart/report с полями message/delivery-status. Полезными могут быть поля Reporting-MTA, Final-Recipient, Action, Status, Remote-MTA, Diagnostic-Code, а также время поступления или последней попытки. Считайте каждое поле недоверенными входными данными, даже если MIME-структура успешно разбирается. Ограничивайте размер письма, число заголовков, число частей, вложенность, декодирование символов и длину сохраняемого диагностического сообщения. Никогда не исполняйте вложения, не переходите автоматически по ссылкам из диагностики и не принимайте адрес получателя за идентификатор тенанта. Сопоставляйте уведомление с попыткой, которой владеет приложение, по стабильному идентификатору письма у провайдера, исходным метаданным конверта или безопасному с точки зрения приватности заголовку корреляции. DSN может содержать части исходного письма и данные получателя, поэтому ограничивайте логирование и срок хранения. Если сопоставление неоднозначно, сохраните данные, но не добавляйте в стоп-лист посторонний адрес и не раскрывайте историю писем другого тенанта.
Моделируйте переходы состояний на уровне получателя
Одно письмо может быть адресовано нескольким получателям и иметь разные результаты. Храните статус по каждому получателю и попытке, а не только в строке письма. Провайдер может принять одни команды RCPT и отклонить другие или позже сообщить о доставке одному получателю и об ошибке другому. Определите монотонные переходы, чтобы запоздавшее событие о приёме или отсрочке не могло перезаписать более позднюю подтверждённую постоянную ошибку, жалобу или отписку. Сохраняйте журнал событий и выводите текущее отображаемое состояние по явным правилам приоритета. Разделяйте состояния: отправлено, принято провайдером, принято сервером получателя, временно отложено, постоянная ошибка, в стоп-листе, жалоба, отписка и неизвестно. Приём сервером назначения всё равно не говорит об итоговой папке почтового ящика или о прочтении человеком. Пусть повторы создают связанные попытки под тем же логическим ключом события, чтобы риск дублирования и доказательства оставались видимыми. Не отмечайте запланированный повтор как новое действие клиента.
Повторяйте при временных ошибках в строгих рамках
Для подходящих временных результатов планируйте экспоненциальную задержку (exponential backoff) со случайным разбросом (jitter), конечным числом попыток и максимальным временем в очереди. Используйте документированное поведение повторов провайдера и не надстраивайте агрессивный цикл в приложении над релеем, который уже выполняет повторы. Сохраняйте одну и ту же логическую идентичность письма и проверку стоп-листа для каждой попытки. Прекращайте повторы, когда получатель попадает в стоп-лист, меняется согласие, истекает срок события, отзывается адрес отправителя или приходит более поздний постоянный ответ. Ограничивайте частоту по тенанту, домену назначения, отправителю и классу ошибок, чтобы сбой одного получателя не монополизировал очередь. Соблюдайте Retry-After или документированные рекомендации по отсрочке, если они есть, но никогда не доверяйте произвольному содержимому письма как инструкциям по повтору. Настройте оповещения о росте времени в очереди, повторяющихся временных кодах, необычных доменах и попытках, срок которых подходит к концу. Временный код может скрывать устойчивую проблему с политикой или репутацией; ограниченные повторы дают время на восстановление, а не право игнорировать причину.
Добавляйте в стоп-лист подтверждённые постоянные ошибки получателей
Подтверждённая постоянная ошибка адреса или почтового ящика должна обновлять запись стоп-листа, принадлежащую продукту, до отправки любой последующей задачи. Храните тенанта, нормализованный ключ получателя, область действия, исходное событие, категорию статуса и диагностики, время вступления в силу и ссылку на доказательства, не раскрывая адрес широко. Применяйте стоп-лист в момент отправки, а не только при импорте списка. Различайте недействительный адрес, несуществующий домен, отклонение по политике, отклонение из-за содержимого, ошибку аутентификации, квоту и репутацию отправителя, потому что безопасные способы исправления у них разные. Недействительный получатель оправдывает добавление в стоп-лист на уровне получателя; отклонение из-за аутентификации отправителя должно приостанавливать конфигурацию отправителя, а не добавлять в стоп-лист всех получателей. Защищайте ручное удаление строгой авторизацией, указанием причины и историей аудита. Повторное подтверждение или исправление должно создавать новое проверенное решение, а не удалять старые доказательства. Стоп-листы провайдеров полезны, но не заменяют журнал согласий и безопасности в приложении, особенно при миграции между провайдерами.
Избегайте циклов отказов и обратного рассеяния
SMTP использует пустой обратный путь (null reverse path) для уведомлений о статусе доставки, чтобы сбой при доставке уведомления не порождал ещё один отказ. Сохраняйте это поведение в релеях и не отправляйте автоответы на DSN, автоматические ответы или письма с признаками автоматической генерации. RFC 3834 содержит рекомендации для автоматических ответов на письма, в том числе касающиеся циклов и усиления. Никогда не отправляйте отказ на неподтверждённый видимый адрес From после приёма подозрительного письма: поддельные адреса отправителей могут превратить вашу систему в источник обратного рассеяния (backscatter). По возможности отклоняйте недействительных получателей во время SMTP-сессии, а не принимайте письмо и затем уведомляйте поддельный адрес. Ограничивайте автоматические ответы для каждого отправителя и переписки и используйте контролируемые адреса для ответов. Вебхук продукта или внутреннее событие об ошибке часто безопаснее, чем генерация нового письма в интернет. Тестируйте поддельный From, пустого отправителя в конверте, повторяющиеся DSN, заголовки Auto-Submitted, трафик списков рассылки и некорректные отчёты в изолированных тестовых данных.
Аутентифицируйте события провайдера до их применения
Если провайдер присылает события отказов через вебхуки, проверяйте документированную подпись или механизм аутентификации по точному запросу до разбора бизнес-полей. Проверяйте свежесть временной метки, защищайтесь от повторного воспроизведения, ограничивайте размер тела и сопоставляйте тенанта. Сохраните аутентифицированное событие или поставьте его в очередь до того, как вернуть успешный ответ, затем устраняйте дубли по стабильному идентификатору события провайдера или по консервативному составному ключу, который не может объединить разных получателей или попытки. Храните время события отдельно от времени обработки, потому что события могут задерживаться и приходить не по порядку. Отклоняйте события, у которых домен отправителя, аккаунт, рабочее пространство, идентификатор письма или область получателей невозможно связать с ожидаемым тенантом. Проводите ротацию секретов вебхуков отдельно от учётных данных SMTP или API. Отслеживайте ошибки подписи, долю дублей, задержку, очереди недоставленных сообщений и неизвестные типы событий. Аутентифицированный вебхук подтверждает происхождение при настроенном секрете; он не доказывает, что событие сопоставлено с правильной внутренней задачей, пока корреляция не выполнена успешно.
Диагностируйте по семейству статусов, а не по догадкам о формулировках
Начните с темы расширенного кода состояния: статус адреса, статус почтового ящика, статус почтовой системы, статус сети или маршрутизации, статус протокола доставки почты, статус содержимого или медиа письма либо статус безопасности и политики. Затем используйте код детализации и полное диагностическое сообщение вместе с актуальной документацией получателя или провайдера. При ошибках адреса проверяйте синтаксис получателя и DNS домена; при ошибках почтового ящика — данные о существовании ящика и квоте; при транспортных ошибках — MX, маршрутизацию, TLS и сеть; при ошибках письма — размер, MIME, кодировку и содержимое; при ошибках безопасности — SPF, DKIM, DMARC, учётные данные, политику в отношении отправителя или репутацию. Меняйте одну переменную в каждом контрольном повторном тесте. Не меняйте IP-адреса, домены или провайдеров, чтобы обойти постоянное решение по политике. Сохраняйте исходный ответ и откатывайте любое изменение конфигурации, которое расширяет полномочия отправителя или ослабляет аутентификацию, не устраняя наблюдаемую причину.
Измеряйте состояние отказов без утечки данных получателей
Отслеживайте приём с первой попытки, временные отсрочки, постоянные ошибки, восстановление после повторов, неизвестные результаты, жалобы, добавления в стоп-лист и время в очереди по когортам, безопасным с точки зрения приватности. Полезные измерения: домен отправителя, домен назначения на согласованном уровне агрегации, класс писем, ревизия шаблона, провайдер, семейство статусов и время. Не используйте в рутинной аналитике полные адреса, содержимое писем, диагностические блоки или исходные заголовки. Отделяйте долю недействительных получателей от ошибок политики, аутентификации, содержимого, репутации и временных инфраструктурных сбоев: единая доля отказов скрывает причины, с которыми можно работать. Используйте знаменатели на основе попыток по получателям и относите поздние события к их исходной когорте. Задавайте оповещения на основе исторических базовых значений и бизнес-рисков, а не одного универсального процента. Проводите аудит применения стоп-листа и ручных переопределений. Храните только те данные, которые нужны для эксплуатации, безопасности, юридических обязательств и споров, а затем удаляйте или агрегируйте их. Низкая доля отказов не доказывает согласие, вовлечённость или попадание во «Входящие».
Как SendHQ вписывается в эту схему
SendHQ документирует отслеживание доставки и отказов (bounce), а также стоп-листы. Подробности о поддерживаемом поведении смотрите в актуальной документации.
Частые вопросы
Что такое возврат письма (bounce-back)?
Это свидетельство того, что доставка SMTP-получателю или последующая попытка доставки не удалась или была отложена; о нём сообщается во время SMTP-сессии, через DSN или через событие провайдера.
Чем отказ 4xx отличается от отказа 5xx?
Ответ 4xx временный и может оправдывать ограниченный повтор. Ответ 5xx постоянный для этой попытки и обычно требует исправления или добавления в стоп-лист.
Нужно ли добавлять в стоп-лист каждый адрес с отказом?
Нет. Добавляйте в стоп-лист подтверждённые постоянные ошибки получателей. Ошибки аутентификации отправителя, содержимого, репутации, квоты или временные инфраструктурные сбои требуют других мер с соответствующей областью действия. Применяйте меру к наблюдаемой причине и затронутым получателям.
Может ли письмо вернуться частично?
Да. SMTP может принять одних получателей и отклонить других, а последующие DSN могут сообщать разные результаты для каждого получателя. Храните состояние на уровне получателя.
Как повторять отправку при временных отказах?
Используйте ту же надёжно сохранённую логическую задачу с экспоненциальной задержкой, случайным разбросом, ограничениями на число попыток и время в очереди и свежей проверкой стоп-листа перед каждой попыткой.
Исключает ли SMTP-ответ 250 последующий отказ?
Нет. Сервер может принять ответственность, а позже сообщить о недоставке. Приём сервером назначения также не означает попадания во «Входящие» или взаимодействия человека с письмом.
Почему уведомления об отказах должны использовать пустой обратный путь?
Пустой обратный путь не даёт сбоям при доставке DSN порождать новый DSN, что предотвращает циклы отказов и их усиление.
Обрабатывает ли SendHQ отказы (bounce)?
Да. SendHQ документирует отслеживание доставки и отказов (bounce), а также стоп-листы.