Кратко

  • Положительный ответ после конечного маркера DATA означает, что принимающий SMTP-сервер принял сообщение и взял ответственность за его доставку либо ретрансляцию. Это передача хранения, а не квитанция конечного адресата.
  • Число 250 имеет доказательную силу только вместе с командой и состоянием транзакции. После EHLO, MAIL, RCPT, RSET или NOOP оно удостоверяет совсем другие действия.
  • Надёжная запись связывает envelope, ответы по адресатам, завершение DATA, устойчивую очередь, каждую следующую передачу и локальный результат. Размещение, фильтрация и прочтение требуют собственных источников.

Один код, шесть разных обещаний

Оператор видит в журнале 250 OK и задаёт естественный вопрос: доставлено ли письмо? Журнал не может ответить, пока рядом нет команды.

Ответом 250 сервер может завершить EHLO — подтвердить начальное состояние и перечислить расширения. Тот же класс ответа после MAIL FROM принимает обратный путь и открывает envelope. После RCPT TO он относится к одному адресу назначения. RSET получает положительный ответ после сброса состояния, а NOOP — после намеренного отсутствия работы.

Нужное нам обещание появляется только после другого диалога. Получатель сначала отправляет промежуточный 354, разрешая передать содержимое. Клиент посылает данные и конечный маркер. Сервер сопоставляет обратный путь, ранее принятых адресатов и само письмо, а затем либо принимает всю транзакцию для доставки, либо отказывает. Базовая модель SMTP на этой границе не допускает частичного принятия материала.

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

Имя John Klensin относится к этой границе строго определённым образом. Официальный профиль IETF идентифицирует Dr. John C. Klensin и на момент исследования перечислял 60 RFC. RFC 5321 называет его автором. Это подтверждает вклад в коллективный стандарт, но не управление работающей почтовой системой и не соответствие конкретного продукта.

Сначала устойчивость, потом ответ

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

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

Поэтому ссылка на RFC не доказывает конкретный fsync. Если сервис обещает «отвечаем только после репликации», доказательство должно соединять queue ID, уровень устойчивости, эпоху конфигурации и момент отправки ответа. Полное содержимое письма для такого аудита обычно не требуется.

Принцип Heng Lu о работающем коде удерживает роли раздельно. Стандарт задаёт грамматику ответственности. Реализация выбирает порядок записи. Оператор задаёт резервирование и повторные попытки. Наблюдаемое локальное состояние подтверждает исполнение. Авторство спецификации нельзя превращать в гарантийную пломбу работающего экземпляра.

Relay принимает маршрут, а не почтовый ящик

RFC 5321 говорит о принятии ответственности за доставку или ретрансляцию. Второе слово не является оговоркой: принявший сервер может находиться в нескольких переходах от адресата. Он становится SMTP-клиентом новой транзакции и ищет следующего ответственного.

Поля Received позволяют восстановить заявленный маршрут: кто передал сообщение, кто принял и когда. Но цепочка заголовков не является сквозным сертификатом. Она не доказывает устойчивость следующей очереди, корректность Alias, работу шлюза, результат списка рассылки или доступность письма пользователю.

Даже «final delivery» в RFC имеет протокольный масштаб: письмо покидает SMTP-среду и обычно приходит пользователю или в связанный Mail Drop, хотя другая почтовая система может обрабатывать его дальше. Окончание одного транспортного протокола ещё не означает окончания пользовательского пути.

Модель статусов должна называть границы: принято этим hop, сохранено в этой очереди, принято следующим hop, передано local-delivery agent, записано в mailbox, помещено в карантин, отброшено политикой, видимость пользователю неизвестна. Если система не наблюдает этап, честный ответ — «неизвестно», а не унаследованный зелёный цвет.

Отсутствие bounce ничего не подтверждает

Если ошибка выявлена уже после принятия, ответственный сервер обычно формирует уведомление на обратный путь envelope. Само уведомление использует пустой обратный путь, чтобы не вызвать бесконечную цепочку отчётов при собственной недоставке.

Но отрицательный канал может отсутствовать. При изначально пустом reverse path возвращать SMTP-ошибку некуда. Relay, рассылка, Alias или временная проблема DNS способны помешать немедленной проверке адресата. Современные правила борьбы со злоупотреблениями иногда допускают тихое удаление нежелательной почты, чтобы не создавать backscatter на подделанный адрес.

Поэтому «bounce не пришёл» совместимо с несколькими исходами: успешной доставкой, отчётом в очереди, невозможным обратным адресом, потерей корреляции в шлюзе, тихим policy discard или пробелом наблюдения. Молчание — это не положительная квитанция.

RFC 3461, RFC 3463 и RFC 3464 задают отдельную систему Delivery Status Notification. Отчёт может описать для каждого адресата failed, delayed, delivered, relayed или expanded. Запрос DSN не гарантирует ответ. relayed намеренно не утверждает конечную доставку, delivered не означает чтение человеком, а сам отчёт ещё надо успешно передать.

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

Потерянная квитанция оставляет риск дубля

Принимающий сервер надёжно сохраняет письмо и отправляет 250, однако TCP-соединение обрывается до того, как отправитель видит строку. У получателя уже есть действительная копия. Отправитель не может доказать факт приёма, оставляет свой экземпляр в очереди и повторяет передачу. Возможны два письма.

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

Состояние «финальный ответ не увиден» не равно отказу. Оно неоднозначно и несёт риск повтора. В журнале должны остаться исходный handle, обрыв, решение retry и корреляционные значения последующих попыток. Метрика положительных ответов считает подтверждённые передачи ответственности, а не ящики; повторные и неоднозначные попытки требуют отдельных знаменателей.

SMTP и LMTP по-разному считают адресатов

SMTP отвечает отдельно на каждый RCPT до содержимого. Один адрес может быть принят, другой отклонён. Однако после DATA базовый протокол даёт один финальный ответ на принятую транзакцию в целом, а не отдельный итог для каждого адресата.

LMTP предназначен для локальной границы, где агент может немедленно сообщить индивидуальные результаты. RFC 2033 требует после конечной точки выдать по одному ответу на каждый ранее успешный RCPT, сохранив порядок. Положительный ответ переносит ответственность именно за соответствующего адресата.

Коллектор обязан сохранить название протокола, порядок RCPT и число ответов. Свернуть последовательность LMTP в один статус — значит, возможно, приписать ошибку не тому адресу. Размножить один SMTP-250 на несколько окончательных успехов — значит придумать точность, которой в сообщении нет.

Минимальная книга ответственности

Первая запись фиксирует соединение и транзакцию, наблюдаемые endpoints и отдельно TLS-контекст. Затем идут MAIL FROM, каждый RCPT с ответом, 354, конечный DATA, точное время и queue ID.

После передачи новый владелец пишет состояние устойчивости, попытки, следующий hop, его ответ и неоднозначные обрывы. Локальная доставка добавляет результат агента или LMTP. DSN добавляет Action и Status каждого адресата плюс доказательство собственной передачи. Фильтрация, проприетарные шлюзы и чтение остаются неизвестными, пока независимый источник не создаст соответствующий факт.

Это Minimum Initial Specification, а не единый программный стек. Выбор очереди, retry, хранения и политики остаётся локальным. Общее правило уже: не отделять код от команды, не называть custody доставкой и не переносить уверенность через hop без новой квитанции.

Корректное заключение звучит так: этот сервер принял данный envelope и сообщение на финальной границе DATA; ответственность перешла; затем наблюдались такие-то relay- или local-delivery-состояния; остальные результаты адресата и пользователя неизвестны.

Источники