Summary
- RFC 5182 gives an IMAP session one mutable result slot.
SEARCH RETURN (SAVE)fills it and later commands use$; the slot is not a stored query, a named snapshot or a durable job. - Selection changes, a new UIDVALIDITY, SAVE failure, resource refusal and EXPUNGE all alter or clear that state. A later command can return
OKon an empty set, so protocol success does not prove that any message was affected.
The cleanup job reported success. Its search had identified expired messages; the next command copied them into an archive; a final command marked them for deletion. Every IMAP command ended with OK. The audit record therefore said the policy had run.
But no message was copied. Between the original search and the copy, another SAVE search failed. Under RFC 5182, that failure emptied the sole search result variable. The later COPY $ was not an error: an empty $ is a valid, non-matching message set, so the server correctly completed an operation that affected nothing.
That scenario is conceptual, not evidence of a named incident. Its value is that the protocol itself makes the evidence boundary visible. SEARCHRES was designed to avoid sending a long list of message identifiers to a client merely so the client could parse and send the same list back. It saves bandwidth, permits safe pipelining and gives the server room to optimize. It does not create a business object called “the saved search.”
One character, one mutable slot
RFC 5182 added the SEARCHRES capability and required a supporting server to implement ESEARCH. A client adds the SAVE return option to SEARCH, UID SEARCH or a search-based command such as SORT or THREAD. The server stores the resulting message set in an internal variable. Later, $ stands where a message set would ordinarily appear.
The variable has no client-assigned name. It has no version, creation identifier or collection of independently addressable results. A successful new SAVE replaces the old value. If two SAVE commands are sent in sequence, the second received command owns the slot after both complete. The first result does not remain available under another symbol.
This is a deliberately small common specification. It lets unlike clients and servers agree on a useful optimization without standardising a durable search service. A product may build durable jobs, named snapshots or policy records above it, but those are local objects with their own identifiers and evidence. They cannot be inferred from $.
The distinction becomes sharper because SAVE normally suppresses the result list when no other return option asks for it. The client may never receive the identifiers that the server stored. That is the efficiency gain. It is also why a useful audit record must retain the criteria, command tag, selected mailbox, UID generation and later consumers rather than recording only “used saved result.”
The slot belongs to a selection epoch
After a successful SELECT or EXAMINE, the search result variable becomes empty. If the server announces a new UIDVALIDITY while the mailbox remains open, it becomes empty again. These are not housekeeping details. They define the identity boundary of the message numbers and UIDs that later commands can use.
EXPUNGE changes the slot without a new search. When a saved member is expunged, the server removes it. If the implementation represents the set using message sequence numbers, it must also adjust the remaining numbers as IMAP sequence positions shift. The set consumed at 10:05 can therefore be smaller, and numerically different, from the set produced at 10:00 even though $ still looks identical on the wire.
The consuming command decides the number space. A set produced by ordinary SEARCH may be passed to UID FETCH, where $ is resolved as UIDs. A set produced by UID SEARCH may be passed to ordinary FETCH, where it is resolved as message sequence numbers. The producer's spelling does not freeze the later interpretation.
For operations teams, the minimum identity is consequently not the symbol. It is connection plus selected mailbox plus UIDVALIDITY plus producer command plus received order plus the state changes before consumption. Drop any of those fields and the log can no longer prove which messages the later operation addressed.
Failure empties state on purpose
RFC 5182 distinguishes failures carefully. A SEARCH ending in BAD does not change the variable. A successful search without SAVE does not change it either, and neither does a NO result from a search that lacked SAVE. But a SAVE search ending in NO sets the variable to empty.
The rule is fail-closed. It prevents a client from assuming that a failed attempt installed a fresh set while the server silently retained the older one. The cost is that retry logic cannot treat the previous result as a fallback. The RFC's unsupported-character-set example shows that the client must repeat the earlier search if it wants to reconstruct the chain.
Servers may also refuse to store a result when saved-result resources are exhausted. They return tagged NO with NOTSAVED and clear the slot. SEARCHRES adds server state, and the RFC explicitly recognises denial-of-service pressure across connections. Capability advertisement proves the protocol is understood; it does not promise unlimited storage or a successful SAVE on every command.
An automation that ignores the tagged response and continues to STORE $ has not preserved an older safe set. It has selected nothing. This is why failure policy belongs next to the command sequence rather than in a generic retry wrapper.
Empty success is still success
An empty result is legitimate. A search can find no messages. A selection or UIDVALIDITY reset can clear the variable. A SAVE failure or NOTSAVED can clear it. EXPUNGE can remove its final member. In every case, commands that accept message sets must treat empty $ as valid and non-matching.
RFC 5182 gives the direct consequence: FETCH $ may produce no FETCH responses and still finish with tagged OK. Its COPY example finishes OK and copies nothing. That is correct command execution, not evidence that an archive, retention or security objective changed any message.
Three counts must therefore stay separate: the population intended by policy, the population installed in the result variable, and the population actually affected by the consuming command. A fourth receipt records the outcome visible to the user or control system. One green protocol status cannot collapse those layers.
This matters most when $ feeds a destructive or compliance-sensitive operation. A no-op may be safe at the transport layer and unacceptable at the governance layer. The closeout condition is not simply OK; it is an explained reconciliation among intended, stored, remaining and affected sets.
Pipelining requires a dependency graph
SEARCHRES enables a client to send SAVE and a consumer without waiting for the first response. The server must execute dependent commands in received order. RFC 5182 even permits implementations to optimize compatible work internally—for example by substituting search criteria—so long as the observable dependency remains intact.
One SAVE followed by COPY and STORE can be an unambiguous chain: both later commands consume the saved result in order. Two SAVE commands are different. They do not allocate two slots. The second overrides the first. A scheduler that sees only independent command tags but not the shared variable can legally parse the traffic and still reconstruct the wrong business story.
The evidence model should therefore record producer-consumer edges. Every $ consumer points to the SAVE that supplied the variable at that position in the received command stream. A second SAVE closes the first producer's future reach, even if earlier consumers are still being reported. Response arrival order alone is not sufficient; IMAP tags correlate responses, while the state transition follows the command dependency rules.
RFC 5267's CONTEXT extension helps show what SEARCHRES is not. CONTEXT can establish update contexts identified by command tags, emit incremental changes and cancel updates. $ is the last-result slot. Using one as if it were the other produces a local convention that peers cannot verify.
Return options define what was saved
Even a successful, complete search does not imply that $ holds every match. With ESEARCH, SAVE MIN stores only the minimum matching message; SAVE MAX stores only the maximum; SAVE MIN MAX stores one or two endpoints. If ALL or COUNT is also requested, RFC 5182 requires the full found set to be saved, including when a count-only implementation might otherwise avoid constructing it.
Later extensions add more boundaries. RFC 9394 says SAVE with PARTIAL, absent ALL, retains the requested partial window plus applicable MIN or MAX values. RFC 9738 says a search constrained by MESSAGELIMIT saves the truncated set. That latter completeness problem already has its own BTW analysis; the lesson needed here is narrower. The contents of $ follow the exact return-option contract, not the human title of the query.
An audit entry saying “saved the search for expired mail” is therefore under-specified. It should say whether the server saved all matches, endpoints, a page or a limited subset. Otherwise a later command may execute perfectly against a population the operator never intended.
Preserve the authority of the optimization
The IANA registry assigns SEARCHRES its capability token. RFC 9051 incorporates the state machine into IMAP4rev2. Those facts make the mechanism interoperable; they do not attest to a provider deployment, client use, resource availability or policy outcome.
Leadership should keep the shared protocol small and build stronger claims explicitly. A compliance-sensitive workflow needs a local immutable operation ID, the exact criteria and return options, mailbox and UIDVALIDITY, producer and consumer tags, command receive order, reset and EXPUNGE events, stored and affected counts, and an observed result. Multiple concurrent populations need separately named local objects or a protocol mechanism designed for contexts, not repeated reuse of one character.
The test is simple: can the organisation reconstruct why each affected message belonged to the operation, and explain every intended message that did not? If the answer is only “the server accepted $,” the symbol has acquired more authority than the running code ever gave it.
Sources
- RFC 5182 — HTML
- RFC 5182 — plain text
- RFC Editor information page
- IETF Datatracker document page
- IETF Datatracker history
- IETF Datatracker references
- RFC 5182 errata
- RFC 9051 — IMAP4rev2
- RFC 9051 information page
- RFC 4731 — ESEARCH
- RFC 4466 — collected IMAP ABNF
- RFC 4315 — UIDPLUS
- RFC 3501 — IMAP4rev1
- RFC 5267 — IMAP CONTEXT
- RFC 9738 — MESSAGELIMIT
- RFC 9394 — PARTIAL
- IANA IMAP Capabilities registry
- Heng Lu — reality layers
- Heng Lu — minimum initial specification and voluntary adoption
- Heng Lu — running code is primary
Member Briefing
Deeper Profile Context
Sign in with the right membership level to unlock the full briefing and source notes.
Only for Strategic Circle
Strategic Circle
Open to all readers. Unlock profile briefings after joining and signing in.
Join Strategic CircleOnly for Leadership Alliance
Leadership Alliance
For qualified IP-asset owners and management; sign in to unlock alliance briefings.
Join Leadership Alliance
