RFC 9051: IMAP4rev2
Why This Exists
IMAP4rev1 (RFC 3501, published in 2003) served as the backbone of multi-device email for nearly two decades. But it accumulated dozens of extension RFCs, ambiguous edge cases, and features that every real-world server implemented differently. RFC 9051 — IMAP4rev2 — is a clean revision that:
- Folds in essential extensions. Features like CONDSTORE (conditional store), NAMESPACE, ESEARCH, LIST-EXTENDED, LITERAL-, and MOVE are now part of the base protocol rather than optional add-ons.
-
Removes deprecated features. The old
\Recentflag is gone. So are ambiguous behaviors around simultaneous mailbox access. - Clarifies synchronization semantics. Precise rules for UIDVALIDITY, MODSEQ, and change tracking make it possible to build reliable offline-capable clients.
If you are building a new email client or integration, target IMAP4rev2. If the server only supports IMAP4rev1, the command set is nearly identical — just negotiate extensions individually.
How It Works
Connection and Authentication
IMAP uses port 143 (STARTTLS) or port 993 (implicit TLS, recommended). After connecting, the client authenticates:
-- Connect to port 993 (IMAPS) -- * OK [CAPABILITY IMAP4rev2 AUTH=PLAIN] server ready a1 LOGIN alice@example.com s3cretP@ss a1 OK [CAPABILITY IMAP4rev2 MOVE CONDSTORE] Logged in
Every client command is prefixed with a tag (like a1). The server responds with the same tag, allowing pipelined commands. Untagged responses (prefixed with *) carry data like message counts and capability lists.
Selecting a Mailbox
a2 SELECT INBOX * 42 EXISTS ← 42 messages in INBOX * OK [UIDVALIDITY 1609459200] ← UID epoch; if this changes, re-sync * OK [UIDNEXT 1053] ← next UID to be assigned * OK [HIGHESTMODSEQ 7834] ← for incremental sync (CONDSTORE) * FLAGS (\Answered \Flagged \Deleted \Seen \Draft) a2 OK [READ-WRITE] SELECT completed
Fetching Messages
-- Fetch envelope and flags for messages 1:5 -- a3 FETCH 1:5 (FLAGS ENVELOPE) * 1 FETCH (FLAGS (\Seen) ENVELOPE ("Wed, 12 Mar 2025 ..." ...)) * 2 FETCH (FLAGS () ENVELOPE (...)) ... a3 OK FETCH completed -- Fetch full body of message UID 1050 -- a4 UID FETCH 1050 (BODY[]) * 41 FETCH (UID 1050 BODY[] {4523} (full RFC 5322 message...) ) a4 OK UID FETCH completed
Server-Side Search
a5 SEARCH UNSEEN FROM "bob@example.com" SINCE 1-Mar-2025 * SEARCH 38 41 42 a5 OK SEARCH completed
Key Technical Details
UIDs and Sequence Numbers
Every message has two identifiers: a sequence number (its position in the mailbox, which changes as messages are deleted) and a UID (a permanently assigned number that only increases). Robust clients always use UIDs via UID FETCH, UID SEARCH, etc. The UIDVALIDITY value tells the client whether its cached UIDs are still valid; if it changes, the client must re-sync from scratch.
Flags
IMAP4rev2 defines these system flags:
| Flag | Meaning |
|---|---|
\Seen |
Message has been read |
\Answered |
Message has been replied to |
\Flagged |
Marked as important / starred |
\Deleted |
Marked for deletion (removed on EXPUNGE) |
\Draft |
Message is a draft |
The \Recent flag from IMAP4rev1 is removed in rev2. Servers may also support custom keywords (e.g., $Forwarded, $Junk).
CONDSTORE and QRESYNC
CONDSTORE assigns a MODSEQ value to every flag change. A client that knows the last MODSEQ it saw can ask: "what changed since MODSEQ 7834?" and get only the deltas. QRESYNC (Quick Resynchronization) extends this to handle expunged messages efficiently. Together, they make IMAP viable on mobile networks where full re-sync is too expensive.
MOVE Command
In IMAP4rev1, moving a message required COPY + STORE \Deleted + EXPUNGE — three commands with race conditions. IMAP4rev2 includes MOVE as a native atomic operation:
a6 UID MOVE 1050 "Archive" * OK [COPYUID 1609459200 1050 287] * 41 EXPUNGE a6 OK MOVE completed
Common Mistakes
- Using sequence numbers for persistent references. Sequence numbers shift when messages are deleted. Always use UIDs for anything you cache or reference across sessions.
- Ignoring UIDVALIDITY changes. If UIDVALIDITY changes between sessions, all your cached UIDs are invalid. You must discard your local cache and re-sync.
-
Polling instead of using IDLE. The
IDLEcommand lets the server push new-message notifications. Polling every 30 seconds wastes bandwidth and battery. Use IDLE for real-time updates. -
Fetching BODY[] when you need BODY.PEEK[].
FETCH BODY[]implicitly sets the\Seenflag. UseBODY.PEEK[]to read without marking as read. - Not supporting CONDSTORE. Without CONDSTORE, every reconnection requires a full mailbox re-sync. Modern IMAP clients should always negotiate CONDSTORE.
- Running IMAP on port 143 without TLS. Use port 993 with implicit TLS per RFC 8314.
Deliverability Impact
- IMAP is a retrieval protocol, not a sending protocol. Like POP3, it does not directly affect outbound deliverability. It determines how recipients experience the mail you send.
- Flag-based engagement signals. Major providers (Gmail, Outlook) observe IMAP flag changes — marking messages as \Seen, moving to folders, starring — as engagement signals. Positive engagement can improve your sender reputation over time.
- Spam folder interaction. When a recipient moves your message out of Junk via IMAP, the provider often treats this as a "not spam" signal. Conversely, IMAP moves to Junk count against you.
- Bounce mailbox processing. IMAP is better than POP3 for bounce processing because you can SEARCH for DSN messages server-side, process them, and MOVE them to an archive — all without downloading every message.