How IMAP Works: Server-Side Email Access and Synchronization

IMAP (Internet Message Access Protocol) is the standard protocol for accessing and managing email messages stored on a remote mail server. Unlike POP3, which downloads messages to a single device and optionally deletes them from the server, IMAP treats the server as the authoritative store: messages remain on the server, organized into mailboxes, and can be accessed from multiple devices simultaneously. Defined in RFC 9051 (IMAP4rev2, published 2021, superseding RFC 3501's IMAP4rev1 from 2003), IMAP provides a rich command set for searching, filtering, flagging, and organizing email without downloading entire mailboxes. It is the protocol that makes modern multi-device email work.

IMAP vs POP3: Fundamental Differences

POP3 (Post Office Protocol, RFC 1939) was designed for an era when users checked email from a single computer on a dial-up connection. The model is simple: connect, download new messages, optionally delete them from the server, disconnect. This works for one device but breaks completely with multiple devices — a message downloaded to your phone is no longer available on your laptop.

IMAP inverts this model. The server is the source of truth. Clients synchronize with the server rather than downloading from it. This distinction has cascading implications:

AspectPOP3IMAP
Message storageClient (after download)Server (always)
Multi-device syncNot supportedCore feature
Server-side searchNot supportedSEARCH command
Folder managementNot supportedFull mailbox hierarchy
Partial fetchNo (download entire message)Yes (headers only, body sections)
Message flagsNot supported\Seen, \Answered, \Flagged, \Deleted, \Draft
Bandwidth usageHigh (downloads everything)Low (fetches on demand)
Connection modelShort-lived (connect, download, disconnect)Long-lived (IDLE for push notifications)
Server storageMinimal (messages deleted after download)Requires significant storage
Offline accessFull (all messages local)Limited (cached subset)

The IMAP Connection Model

An IMAP session begins with a TCP connection to port 143 (cleartext) or port 993 (IMAPS, IMAP over TLS). In practice, all modern IMAP connections use TLS — either IMAPS on port 993 or STARTTLS upgrade on port 143. The session progresses through four states:

IMAP Session State Machine Not Authenticated CAPABILITY, STARTTLS LOGIN, AUTHENTICATE Authenticated LIST, CREATE, DELETE SELECT, EXAMINE Selected FETCH, STORE, SEARCH COPY, MOVE, EXPUNGE Logout LOGIN OK SELECT CLOSE LOGOUT SELECT other Connection Setup Port 993: IMAPS (TLS) Port 143: STARTTLS upgrade Tagged Commands a001 LOGIN user pass a001 OK LOGIN completed

Not Authenticated — the initial state after TCP connection. The server sends a greeting (* OK for cleartext, * PREAUTH if already authenticated via TLS client certificate). The client typically issues CAPABILITY to discover server features, then authenticates via LOGIN (plaintext username/password, only safe over TLS) or AUTHENTICATE (SASL mechanisms like PLAIN, XOAUTH2, SCRAM-SHA-256).

Authenticated — the client can manage mailboxes (LIST, CREATE, DELETE, RENAME, SUBSCRIBE) but cannot access messages. The client must SELECT a mailbox to enter the Selected state.

Selected — a specific mailbox is open. The client can now access messages: FETCH, STORE (modify flags), SEARCH, COPY, MOVE, EXPUNGE (permanently delete flagged messages). Selecting a different mailbox implicitly closes the current one.

Logout — the session is terminating. The server sends a BYE response and closes the connection.

Every IMAP command is prefixed with a client-generated tag (e.g., a001, a002), and the server's completion response uses the same tag. This allows multiple commands to be in flight simultaneously (command pipelining), with the server responding out of order.

The Mailbox Model

IMAP organizes messages into mailboxes (commonly called folders in email clients). Every IMAP server must support at least the INBOX mailbox. Beyond that, the mailbox namespace is hierarchical, with a server-defined delimiter (usually / or .):

a001 LIST "" "*"
* LIST (\HasChildren) "/" "INBOX"
* LIST (\HasNoChildren) "/" "INBOX/Work"
* LIST (\HasNoChildren) "/" "INBOX/Personal"
* LIST (\HasNoChildren \Drafts) "/" "Drafts"
* LIST (\HasNoChildren \Sent) "/" "Sent"
* LIST (\HasNoChildren \Trash) "/" "Trash"
* LIST (\HasNoChildren \Junk) "/" "Junk"
* LIST (\HasNoChildren \Archive) "/" "Archive"
a001 OK LIST completed

The special-use mailbox attributes (\Drafts, \Sent, \Trash, \Junk, \Archive) are defined in RFC 6154. They allow email clients to discover the purpose of mailboxes without relying on name conventions (which vary by language and server).

When a client SELECTs a mailbox, the server returns metadata about the mailbox:

a002 SELECT INBOX
* 172 EXISTS         -- 172 messages in the mailbox
* 1 RECENT           -- 1 message since last SELECT
* OK [UNSEEN 168]    -- first unseen message is sequence number 168
* OK [UIDVALIDITY 3857529045]  -- UID validity value
* OK [UIDNEXT 4392]  -- next UID to be assigned
* FLAGS (\Answered \Flagged \Deleted \Seen \Draft $Forwarded)
* OK [PERMANENTFLAGS (\Answered \Flagged \Deleted \Seen \Draft $Forwarded \*)]
a002 OK [READ-WRITE] SELECT completed

Two critical concepts here are sequence numbers and UIDs. Sequence numbers are positional (1 through N for N messages) and change when messages are expunged. UIDs are persistent identifiers assigned by the server that never change for a given message within a UIDVALIDITY epoch. Clients should use UIDs for bookmarking messages because sequence numbers are unstable. If UIDVALIDITY changes (due to mailbox reconstruction), all cached UIDs are invalid and the client must re-synchronize from scratch.

FETCH: Retrieving Message Data

The FETCH command is IMAP's workhorse. It retrieves specified data items for specified messages. IMAP's power lies in its ability to fetch selective parts of a message without downloading the entire thing:

# Fetch envelope (From, To, Subject, Date) for messages 1-10
a003 FETCH 1:10 (ENVELOPE)

# Fetch headers only (no body)
a004 FETCH 42 (BODY[HEADER])

# Fetch specific headers
a005 FETCH 42 (BODY[HEADER.FIELDS (From To Subject Date)])

# Fetch the plain text body part of a MIME message
a006 FETCH 42 (BODY[1.1])

# Fetch entire message (RFC822 format)
a007 FETCH 42 (BODY[])

# Fetch flags and internal date
a008 FETCH 42 (FLAGS INTERNALDATE)

# Fetch body structure (MIME tree) without downloading content
a009 FETCH 42 (BODYSTRUCTURE)

The BODYSTRUCTURE response describes the MIME structure of a message as a nested tree. For a multipart message with attachments, it might look like:

* 42 FETCH (BODYSTRUCTURE (
  (("text" "plain" ("charset" "utf-8") NIL NIL "quoted-printable" 1234 42 NIL NIL NIL NIL)
   ("text" "html" ("charset" "utf-8") NIL NIL "quoted-printable" 5678 89 NIL NIL NIL NIL)
   "alternative" ("boundary" "----=_Part_123") NIL NIL NIL)
  ("application" "pdf" ("name" "report.pdf") NIL NIL "base64" 98765 NIL ("attachment" ("filename" "report.pdf")) NIL NIL)
  "mixed" ("boundary" "----=_Part_456") NIL NIL NIL))

This tells the client: the message has two parts. Part 1 is a multipart/alternative with a plain text version (part 1.1) and an HTML version (part 1.2). Part 2 is a PDF attachment (98765 bytes, base64-encoded). The client can display the HTML body by fetching only BODY[1.2] — no need to download the 98KB PDF attachment.

The BODY.PEEK[] variant fetches data without setting the \Seen flag. This is important for "preview" functionality where the client shows a snippet without marking the message as read.

STORE and Flags

IMAP messages have flags that track their state. The standard system flags are:

Servers can also support custom keyword flags (like $Forwarded, $Junk, $NotJunk, or any custom label). The STORE command modifies flags:

# Mark message 42 as read
a010 STORE 42 +FLAGS (\Seen)

# Mark messages 1-10 as flagged
a011 STORE 1:10 +FLAGS (\Flagged)

# Remove the \Answered flag
a012 STORE 42 -FLAGS (\Answered)

# Set flags to exactly these values (replacing all existing flags)
a013 STORE 42 FLAGS (\Seen \Answered)

IMAP's deletion model is two-phase: first, mark messages with \Deleted using STORE, then permanently remove them with EXPUNGE. This allows undoing deletions (by removing the \Deleted flag) before EXPUNGE is called. Modern servers often support the MOVE extension (RFC 6851), which atomically moves messages to another mailbox — typically the Trash folder.

SEARCH: Server-Side Filtering

The SEARCH command finds messages matching specified criteria without downloading them. This is critical for performance — a mailbox with 50,000 messages cannot be searched by downloading all of them:

# Search for unread messages from a specific sender
a014 SEARCH UNSEEN FROM "[email protected]"

# Search by date range
a015 SEARCH SINCE "01-Apr-2026" BEFORE "25-Apr-2026"

# Complex boolean search
a016 SEARCH OR (FROM "noc@" SUBJECT "BGP") (FLAGGED UNSEEN)

# Full-text body search
a017 SEARCH BODY "route hijack"

# Search by message size
a018 SEARCH LARGER 1000000

# Search using UIDs
a019 UID SEARCH UNSEEN SINCE "20-Apr-2026"

The server returns a list of sequence numbers (or UIDs for UID SEARCH) matching the criteria:

* SEARCH 3 5 12 42 168 170 171
a014 OK SEARCH completed

SEARCH criteria can be combined (implicit AND) or joined with OR. Available criteria include: ALL, ANSWERED, BCC, BEFORE, BODY, CC, DELETED, DRAFT, FLAGGED, FROM, HEADER, KEYWORD, LARGER, NEW, NOT, OLD, ON, OR, RECENT, SEEN, SENTBEFORE, SENTON, SENTSINCE, SINCE, SMALLER, SUBJECT, TEXT, TO, UID, UNANSWERED, UNDELETED, UNDRAFT, UNFLAGGED, UNKEYWORD, UNSEEN.

The ESEARCH extension (RFC 4731) provides more efficient search results by returning only the minimum information needed: MIN (smallest matching UID), MAX (largest), COUNT (total matches), or ALL (complete list in a compressed format).

IDLE: Push Notifications

Without the IDLE extension (RFC 2177), an IMAP client must poll the server periodically to check for new messages. IDLE eliminates polling by allowing the server to push unsolicited notifications to the client when new messages arrive, flags change, or messages are expunged:

a020 IDLE
+ idling
* 173 EXISTS         -- new message arrived
* 42 FETCH (FLAGS (\Seen \Answered))  -- flags changed on message 42
DONE                  -- client sends DONE to stop IDLE
a020 OK IDLE terminated

IDLE is essential for real-time email delivery. Without it, email clients must poll every 1-5 minutes, introducing delays of up to 5 minutes between message arrival and notification. With IDLE, notification is effectively instantaneous.

However, IDLE only works for the currently selected mailbox. If the user has Inbox, Sent, and three other folders, the client only receives push notifications for whichever one is currently SELECTed. Monitoring multiple mailboxes requires either multiple IMAP connections (one per mailbox, each in IDLE state) or periodic polling of non-selected mailboxes. The NOTIFY extension (RFC 5465) addresses this by allowing clients to register interest in events across multiple mailboxes on a single connection, but NOTIFY support is not universal.

IDLE connections have a practical limitation: network intermediaries (NATs, firewalls, load balancers) often close idle TCP connections after 5-30 minutes. IMAP clients must periodically break out of IDLE (send DONE), issue a NOOP command (which elicits an OK response, keeping the connection alive), and re-enter IDLE. The recommended interval is every 29 minutes (RFC 2177).

CONDSTORE and QRESYNC: Efficient Synchronization

The hardest problem in IMAP client development is efficient synchronization: how does a client with a local cache of 50,000 messages determine what changed since the last sync without re-downloading everything?

The CONDSTORE extension (RFC 7162) introduces modification sequences (mod-sequences): monotonically increasing 64-bit integers that the server assigns to every mailbox modification. Each message has a mod-sequence, and the mailbox has a HIGHESTMODSEQ value. On reconnection, the client says "give me everything that changed since mod-sequence X":

# Fetch flags for messages changed since mod-sequence 12345
a021 FETCH 1:* (FLAGS) (CHANGEDSINCE 12345)
* 42 FETCH (FLAGS (\Seen \Answered) MODSEQ (12350))
* 170 FETCH (FLAGS (\Seen) MODSEQ (12348))
a021 OK FETCH completed

CONDSTORE only tracks flag changes. It does not handle message expunges — the client cannot determine which messages were deleted since the last sync. The QRESYNC extension (RFC 7162, same document) fills this gap. QRESYNC allows the client to select a mailbox with a known UIDVALIDITY and HIGHESTMODSEQ, and the server responds with both the changed messages and the expunged UIDs:

# Select with QRESYNC: "I last synced at modseq 12345, UIDs were valid"
a022 SELECT INBOX (QRESYNC (3857529045 12345))
* OK [HIGHESTMODSEQ 12360]
* VANISHED (EARLIER) 56,78:80     -- UIDs 56, 78, 79, 80 were expunged
* 42 FETCH (FLAGS (\Seen \Answered) MODSEQ (12350))
* 170 FETCH (FLAGS (\Seen) MODSEQ (12348))
a022 OK [READ-WRITE] SELECT completed

The VANISHED (EARLIER) response reports UIDs that were expunged since the client's last known state. Without QRESYNC, the client must compare its entire local UID list against the server's — a process that requires fetching all UIDs and diffing, which is slow for large mailboxes.

IMAP Sync: Without vs With QRESYNC Without QRESYNC 1. FETCH 1:* (UID FLAGS) [50,000 UIDs] 2. Client diffs local vs server UID list 3. FETCH changed UIDs (FLAGS BODY.PEEK[]) Transfers ~2MB of UID/flag data even when nothing changed With QRESYNC 1. SELECT INBOX (QRESYNC (uid_val modseq)) 2. Server: VANISHED 56,78:80 + changed flags 3. Client applies delta to local cache Transfers only ~200 bytes of actual changes For a 50,000-message mailbox with 3 changes since last sync: Without QRESYNC: ~2MB transfer, ~5s | With QRESYNC: ~200B transfer, <100ms

IMAP AUTHENTICATE and OAuth

The LOGIN command sends username and password in cleartext (which is safe over TLS but disallowed on plaintext connections). The AUTHENTICATE command supports SASL (Simple Authentication and Security Layer, RFC 4422) mechanisms that provide more sophisticated authentication:

OAuth is increasingly important as major providers (Google, Microsoft) deprecate "less secure apps" (password-based IMAP authentication) in favor of OAuth-based access. This shift requires IMAP clients to implement a full OAuth flow: redirect the user to the provider's consent screen, receive an authorization code, exchange it for access and refresh tokens, and periodically refresh the access token.

IMAP Extensions

IMAP's extensibility is one of its strengths. Extensions are negotiated via the CAPABILITY command, and the server advertises supported extensions. Key extensions beyond CONDSTORE and QRESYNC include:

IMAPS and Transport Security

IMAP traffic includes authentication credentials and email content — both highly sensitive. Two TLS deployment models exist:

IMAPS (port 993) wraps the entire IMAP connection in TLS from the first byte. This is analogous to HTTPS: the TLS handshake occurs before any IMAP protocol data is exchanged. This is the recommended approach and the default for all modern email clients.

STARTTLS (port 143) starts as a plaintext IMAP connection, then upgrades to TLS via the STARTTLS command. The client connects on port 143, discovers STARTTLS support via CAPABILITY, issues STARTTLS, and the connection switches to TLS. The problem: a man-in-the-middle can strip the STARTTLS capability from the CAPABILITY response, tricking the client into continuing in plaintext. This is called a STARTTLS stripping attack. To prevent it, clients should refuse to authenticate on plaintext connections.

Email security extends beyond the IMAP connection itself. Messages may have been delivered to the server via SMTP with or without TLS (opportunistic TLS). The message content may include DKIM signatures that the client can verify, though few IMAP clients do so. End-to-end encryption (S/MIME, PGP) operates at the message layer, independent of IMAP transport security.

JMAP: The Modern Alternative

JMAP (JSON Meta Application Protocol, RFC 8620/8621) is a modern protocol designed as a successor to IMAP. Where IMAP was designed for interactive terminal sessions over slow links (its command syntax dates to 1986's original ISTRSTRSTRSTRSTR RFC 1langford protocol), JMAP is built for modern client applications:

Despite its technical advantages, JMAP adoption has been slow. Gmail and Outlook do not support it. Fastmail (a key contributor to the JMAP specification) is the most prominent JMAP provider. For the foreseeable future, IMAP remains the universal protocol for email access.

IMAP at Scale

Running an IMAP server at scale presents significant challenges. Each user's mailbox may contain hundreds of thousands of messages spanning decades. IMAP's stateful connection model means the server must maintain per-connection state (selected mailbox, search results, pending IDLE notifications) for every connected client.

Large-scale IMAP deployments (Gmail, Outlook, Yahoo) typically use:

Summary

IMAP is a remarkably capable protocol that has evolved significantly from its origins. Its client-server synchronization model, with messages stored authoritatively on the server, enables seamless multi-device access. The FETCH command's ability to retrieve selective message parts minimizes bandwidth. IDLE provides push notifications for the selected mailbox. CONDSTORE and QRESYNC enable efficient incremental synchronization that transforms reconnection from an O(n) operation to an O(changes) operation.

The protocol's complexity is a direct reflection of the email problem's complexity: MIME message structure, mailbox hierarchies, concurrent access from multiple clients, and the need for both real-time notification and efficient batch synchronization. Modern alternatives like JMAP offer cleaner semantics, but IMAP's universal support makes it the protocol that email clients must implement for broad compatibility.

Email delivery via SMTP, authentication via DKIM, SPF, and DMARC, and transport security via TLS are all interconnected pieces of the email ecosystem. To explore the network infrastructure that carries this traffic, try the god.ad BGP Looking Glass to look up the routes and autonomous systems behind any mail server's IP address.

See BGP routing data in real time

Open Looking Glass
More Articles
What is DNS? The Internet's Phone Book
What is an IP Address?
IPv4 vs IPv6: What's the Difference?
What is a Network Prefix (CIDR)?
How Does Traceroute Work?
What is a CDN? Content Delivery Networks Explained