Кратко

  • RFC 3503 ввёл общий регистронезависимый ключ $MDNSent, чтобы несколько почтовых клиентов одного IMAP-ящика не создавали повторные Message Disposition Notification.
  • Ключ описывал запрет на будущее, а не достоверное событие в прошлом: отказ пользователя, сохранённая отправленная или незаконченная копия и автоматическое решение без фактического MDN приводили к тому же состоянию.

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

Опубликованный в марте 2003 года RFC 3503 устранил именно этот разрыв координации. Он не добавил в IMAP новой команды или ответа. Вместо этого документ определил специальный ключ почтового ящика $MDNSent и правила для Mail User Agent. Общее хранилище стало местом, где независимые клиенты оставляли минимально необходимое состояние.

Название похоже на утверждение «MDN отправлено». Нормативные правила записи шире. При автоматической обработке клиент ставил ключ независимо от того, было ли уведомление фактически отправлено. Если пользователь запрещал отправку, тот же ключ мог остановить другой клиент. Копия исходящего письма получала его при сохранении. Незаконченное письмо также сохранялось с ним.

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

Перед использованием клиент проверял возможность постоянного хранения. При открытии ящика он изучал PERMANENTFLAGS: сервер должен был поддерживать сам $MDNSent либо произвольные ключи. Но объявленная способность не гарантировала отдельную операцию. Сервер мог вернуть NO на STORE, например из-за исчерпанного лимита ключей конкретного ящика.

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

Другие флаги нельзя было произвольно назначить на эту роль. \Recent прямо запрещалось использовать как сигнал: если несколько соединений одновременно выбрали один ящик, протокол не определял, какое увидит сообщение как недавнее. Наблюдение, доступное не всем участникам, не распределяет общую обязанность. \Seen мог стать дополнительной причиной не отправлять, а \Draft отдельно защищал незавершённое письмо. При наличии $MDNSent остальные флаги для решения о MDN игнорировались.

Состояние было однонаправленным. Клиенту запрещалось снимать $MDNSent после установки. Это не позволяло случайно оживить старый запрос, но одновременно показывало ограничение: монотонный бит не является журналом. В нём нет автора, времени, основания, согласия и результата транспорта. Он управляет будущим, не восстанавливая прошлое.

Копирование создавало риск потерять запрет. Клиент должен был проверять, сохраняет ли COPY ключ. При межсерверной копии через APPEND ключ требовалось передать правильно. Если содержание прибывало без состояния, получатель мог принять потерю метаданных за отсутствие предыдущего решения.

Правило ACL разделяло полномочия. Сервер по-прежнему проверял право клиента копировать сообщение. Если копия разрешена, рекомендовалось сохранять $MDNSent, даже когда у клиента нет общего права писать флаги. Право переместить объект не превращалось в право свободно менять его свойства; сохранение координационной характеристики следовало за разрешённой копией.

Регистр символов не создавал новые состояния. $MdnSENt, $MdnSENT и $mdnsent считались одним ключом. Примеры показывали его в одной форме и искали в другой. Иначе два клиента могли бы вести параллельную «общую» память, которая на деле не была общей.

Сам MDN принадлежит другой цепочке доказательств. RFC 2298 описал ранний формат, RFC 3798 пересмотрел его, а RFC 8098 стал стандартом Интернета STD 85. Даже его disposition ограничены: displayed означает, что MUA показал сообщение кому-то, кто просматривал ящик, но не гарантирует чтение и понимание. processed может быть результатом правила без человека. deleted не доказывает, что письмо раньше не видели или не восстановят.

Приватность также ограничивает генерацию. По умолчанию уведомление лучше не отправлять; несовпадения адресов требуют подтверждения; MDN можно подделать, потерять, использовать для почтового усиления или раскрытия деталей клиента. RFC 8098 прямо отрицает неоспоримое доказательство доставки и гарантию того, что письмо было или не было увидено.

Поздняя регистрация в RFC 5788 формулировала смысл точнее имени: $MDNSent — общий ключ, который указывает не отправлять MDN для помеченного сообщения. Это запрет для следующего участника, а не свидетельство о предыдущем.

RFC 9007 теснее связал действие и состояние в JMAP. Вызов MDN/send должен сопровождаться обновлением $mdnsent; сервер обязан отклонить операцию, которая не приведёт к этому обновлению, и может ответить mdnAlreadySent, если ключ уже присутствует. Такая композиция уменьшает зазор внутри метода JMAP, но не доказывает человеческое чтение или окончательную доставку и не переписывает требования старых систем.

Операционная проверка должна сохранить ступени. PERMANENTFLAGS подтверждает заявленную способность. STORE OK — принятую мутацию. $MDNSent — общее состояние подавления. Формирование, подача, передача и получение уведомления требуют собственных квитанций. Disposition остаётся типизированным утверждением. Внимание, понимание и действие человека находятся дальше.

Историческая сила RFC 3503 заключалась в узкой общей функции. Клиентам требовалось не повторять действие для одного объекта. Им не требовалось передавать серверу власть решать, что человек прочитал, понял или признал. Тонкий общий слой координировал программы, не выдавая запись за реальность.

Ошибка начинается, когда удобное имя повышают до результата. Тогда запрет становится отправкой, отправка — доставкой, отображение — чтением. Пути записи в RFC 3503 разрывают эту цепь: иногда $MDNSent был верен именно потому, что уведомление не должно было уйти.

Источники