Кратко

  • RFC 5182 позволяет серверу сохранить результат SEARCH в одной переменной и подставлять его по $. При EXPUNGE удалённый участник исчезает, а sequence numbers остальных могут сдвинуться.
  • Поэтому доказательством служит не символ, а эпоха: соединение, выбранный ящик, UIDVALIDITY, команда-производитель, порядок, изменения и команда-потребитель.

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

Нельзя назвать это нарушением RFC 5182. Именно так определена переменная. Она не замораживает почтовый ящик и не возвращает удалённые объекты. Ошибка возникла бы в отчёте, если бы он назвал поздний FETCH доказательством исходной выборки.

Это аналитический сценарий, а не утверждение о конкретном сервисе. Он показывает, почему удобный результат сеанса нельзя выдавать за неизменный объект расследования.

Переменная заменяет обратную передачу списка

Обычная последовательность заставляет сервер вернуть идентификаторы SEARCH, клиента — разобрать и оформить их, а затем послать обратно для FETCH, STORE, COPY, следующего SEARCH или UID EXPUNGE. SEARCHRES оставляет список на сервере: RETURN (SAVE) записывает значение, $ подставляет его позже.

Поддержка объявляется capability SEARCHRES и требует ESEARCH. Если других result options нет, SAVE подавляет сам SEARCH response со списком. Клиент может запустить следующий шаг, ни разу не получив все элементы.

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

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

EXPUNGE меняет то, что будет исполнено

RFC требует автоматически удалять из переменной сообщение, которое EXPUNGEd. Если сервер хранит sequence numbers, он также корректирует номера при уведомлении клиента: позиции после удалённого письма сдвигаются.

Значит, множество при SAVE и множество при потреблении могут различаться. $ не несёт времени создания и не сообщает, какие элементы исчезли. Чтобы объяснить разницу, локальный журнал должен записывать EXPUNGE между производителем и потребителем.

Успешный SELECT или EXAMINE сбрасывает переменную в пустое множество. Новый UIDVALIDITY при открытом ящике тоже сбрасывает её. Номера последовательности принадлежат выбранному ящику, а UID сохраняет смысл только вместе с именем ящика и UIDVALIDITY.

Контекст потребителя определяет и пространство чисел. Результат обычного SEARCH может использоваться в UID FETCH как UID; результат UID SEARCH — в обычном FETCH как sequence numbers. По названию команды-производителя нельзя восстановить позднюю интерпретацию.

Пустое множество исполняется успешно

Поиск может не найти писем. Последний участник может исчезнуть через EXPUNGE. SELECT, EXAMINE или UIDVALIDITY могут сбросить состояние. SAVE с NO и отказ NOTSAVED также делают его пустым.

Во всех случаях пустой $ остаётся допустимым message-set, который ни с чем не совпадает. FETCH может вернуть ноль FETCH responses и завершиться OK. COPY может завершиться OK, не скопировав ничего.

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

Нужно сверять как минимум четыре слоя: что требовало решение; что нашёл SEARCH; что оставалось в переменной при потреблении; что реально изменилось или было прочитано. Пользовательский результат — ещё один слой. Доля OK не заменяет эту разность.

Ошибка SAVE закрывает прежнее значение

BAD после SEARCH не меняет переменную. SEARCH без SAVE тоже не меняет её — как при успехе, так и при NO. Но SAVE-поиск с NO устанавливает пустое множество.

Правило не даёт старой совокупности незаметно пережить неудачную попытку обновления. В примере RFC неподдерживаемая кодировка заставляет клиента повторить и предыдущий SEARCH, если он хочет восстановить цепочку.

Сервер может отказать SAVE из-за лимита состояния между соединениями. Тогда он возвращает NO с NOTSAVED и очищает значение. Дополнительное состояние связано с риском denial of service; capability не является гарантией неограниченного ресурса.

После такого отказа продолжать STORE или COPY по $ — не значит безопасно использовать старое. Это операция над пустотой. Retry должен заново создать намерение и результат.

Pipeline хранит порядок, но не две истории

SAVE, за которым идёт команда с $, образует прямую зависимость. Сервер соблюдает порядок получения, хотя может оптимизировать внутреннюю работу. Один SAVE способен питать несколько потребителей, например COPY и STORE.

Два SAVE не создают два handles. Второй заменяет первый. Tags связывают responses с commands, но не называют отдельные переменные. Порядок прихода ответов также не доказывает, какой результат был действующим в точке потребления.

Каждый потребитель должен ссылаться в локальном журнале на SAVE-производителя, действовавшего в его позиции command stream. Если требуются несколько именованных или обновляемых контекстов, RFC 5267 предлагает другой механизм — CONTEXT с идентификацией по tag, обновлениями и отменой.

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

Return options определяют содержимое

Даже успешный полный SEARCH не всегда кладёт в $ все совпадения. SAVE MIN сохраняет только минимальный элемент, SAVE MAX — максимальный, вместе они дают один или два края. ALL или COUNT требуют сохранить все найденные сообщения.

RFC 9394 добавляет PARTIAL: без ALL сохраняется окно и применимые MIN/MAX. RFC 9738 требует сохранять усечённый набор при MESSAGELIMIT; эта граница неполноты уже разобрана в отдельном материале BTW. Здесь важнее другое: точные result options являются частью личности множества.

Название «старые письма» не говорит, сохранили ли все совпадения, край или страницу. Аудит должен удерживать исполненную строку и её параметры.

Доказательство должно пережить сеанс

IANA регистрирует SEARCHRES, а RFC 9051 включает его state machine в IMAP4rev2. Это доказывает общий язык, но не внедрение у поставщика, правильность клиента, наличие ресурса или завершение расследования.

Перед необратимым действием нужен локальный неизменный объект: ID решения, критерии и options, ящик и UIDVALIDITY, producer и consumers, порядок, resets, EXPUNGE, размеры множеств и наблюдаемый эффект. Тогда $ остаётся быстрым транспортом внутри сеанса.

Закрывающий вопрос: можем ли мы объяснить, почему каждое обработанное сообщение относилось к решению и куда исчезло каждое исходно ожидаемое? Если сохранился только знак, основание выбора уже утрачено.

Источники

  1. RFC 5182 — HTML
  2. RFC 5182 — текст
  3. Информационная страница RFC Editor
  4. Страница документа IETF Datatracker
  5. История IETF Datatracker
  6. Ссылки IETF Datatracker
  7. Errata RFC 5182
  8. RFC 9051 — IMAP4rev2
  9. Информационная страница RFC 9051
  10. RFC 4731 — ESEARCH
  11. RFC 4466 — сводная IMAP ABNF
  12. RFC 4315 — UIDPLUS
  13. RFC 3501 — IMAP4rev1
  14. RFC 5267 — IMAP CONTEXT
  15. RFC 9738 — MESSAGELIMIT
  16. RFC 9394 — PARTIAL
  17. Реестр IMAP Capabilities IANA
  18. Heng Lu — слои реальности
  19. Heng Lu — минимальная исходная спецификация и добровольное принятие
  20. Heng Lu — приоритет работающего кода