RFC 2060

Internet Message Access Protocol - Version 4rev1

๐Ÿ“… published December 1996, from ietf

RFC 2060: INTERNET MESSAGE ACCESS PROTOCOL - VERSION 4rev1 ๐Ÿ’Œ

Request for Comments: 2060 ๐Ÿ“ฌ Author: M. Crispin, University of Washington ๐ŸŽ“ Date: December 1996 ๐Ÿ—“๏ธ Category: Standards Track โœจ Obsoletes: RFC 1730 ๐Ÿ” Working Group: Network Working Group ๐ŸŒธ

Okay bestie, this is the big one: IMAP4rev1, the protocol that lets your email app talk to the mail server. It's a Standards Track doc, which means it's the real deal, and it obsoletes RFC 1730 ๐Ÿ’…. So if you ever run into the old version, this is the upgrade. Iconic. ๐Ÿ‘‘

Status of This Memo โœจ

Okay so this is the official "what kind of document is this" part ๐Ÿง. It specifies an Internet standards track protocol for the Internet community, and it's basically inviting everyone to discuss it and suggest improvements ๐Ÿ’ฌ. If you want to know where the protocol stands in the official standardization world, check the current edition of the "Internet Official Protocol Standards" (STD 1) ๐Ÿ“‹. And the best part? Distribution of this memo is unlimited ๐ŸŒˆ. Anyone can read it, no cap ๐Ÿซถ.

Abstract

So, the vibe of IMAP4rev1 is: it lets a client access and manipulate email messages that are sitting on a server ๐Ÿ“จโœจ. It treats remote message folders, called "mailboxes," as functionally equivalent to local mailboxes, which is honestly so main character ๐ŸŽ€. It also gives an offline client the ability to resynchronize with the server (see also [IMAP-DISC]) ๐Ÿ”„๐Ÿฆ‹.

The protocol is packed with operations ๐Ÿ’–. You can create, delete, and rename mailboxes ๐Ÿ“; check for new messages ๐Ÿ‘€; permanently remove messages ๐Ÿ—‘๏ธ; set and clear flags ๐Ÿšฉ; do [RFC-822] and [MIME-IMB] parsing ๐Ÿงฉ; search ๐Ÿ”; and selectively fetch message attributes, texts, and portions of them ๐Ÿ“. Messages are accessed by numbers, and those numbers are either message sequence numbers or unique identifiers ๐Ÿ”ข. Iykyk, the number game is a whole thing ๐Ÿ™ˆ.

IMAP4rev1 supports a single server ๐Ÿ–ฅ๏ธ. If you need configuration info to handle multiple IMAP4rev1 servers, that's covered in [ACAP] ๐Ÿงš.

Also, IMAP4rev1 does NOT handle posting mail. That job goes to a mail transfer protocol like [SMTP] ๐Ÿ“ฎ. Different friend, different job, periodt ๐Ÿ’….

IMAP4rev1 is designed to be upwards compatible with the [IMAP2] and the unpublished IMAP2bis protocols ๐Ÿค. Over time, some stuff from the earlier protocol became obsolete ๐Ÿ•ฐ๏ธ. The obsolete commands, responses, and data formats an IMAP4rev1 implementation might run into when talking to an earlier implementation are described in [IMAP-OBSOLETE] ๐Ÿ—‚๏ธ.

For other compatibility drama with IMAP2bis, the most common variant of the earlier protocol, check [IMAP-COMPAT] ๐Ÿงƒ. And for the rare (and presumed extinct) variants of [IMAP2], there's a full write-up in [IMAP-HISTORICAL]. Honestly that one is mostly for history nerds ๐Ÿ“œ๐Ÿ’€.

Table of Contents ๐Ÿ“š

IMAP4rev1 Protocol Specification ..................................    4
1.      How to Read This Document .................................    4
1.1.    Organization of This Document .............................    4
1.2.    Conventions Used in This Document .........................    4
2.      Protocol Overview .........................................    5
2.1.    Link Level ................................................    5
2.2.    Commands and Responses ....................................    6
2.2.1.  Client Protocol Sender and Server Protocol Receiver .......    6
2.2.2.  Server Protocol Sender and Client Protocol Receiver .......    7
2.3.    Message Attributes ........................................    7
2.3.1.  Message Numbers ...........................................    7
2.3.1.1.        Unique Identifier (UID) Message Attribute .........    7
2.3.1.2.        Message Sequence Number Message Attribute .........    9
2.3.2.  Flags Message Attribute ....................................   9
2.3.3.  Internal Date Message Attribute ...........................   10
2.3.4.  [RFC-822] Size Message Attribute ..........................   11
2.3.5.  Envelope Structure Message Attribute ......................   11
2.3.6.  Body Structure Message Attribute ..........................   11
2.4.    Message Texts .............................................   11
3.      State and Flow Diagram ....................................   11
3.1.    Non-Authenticated State ...................................   11
3.2.    Authenticated State .......................................   11
3.3.    Selected State ............................................   12
3.4.    Logout State ..............................................   12
4.      Data Formats ..............................................   12
4.1.    Atom ......................................................   13
4.2.    Number ....................................................   13
4.3.    String .....................................................  13
4.3.1.  8-bit and Binary Strings ..................................   13
4.4.    Parenthesized List ........................................   14
4.5.    NIL .......................................................   14
5.      Operational Considerations ................................   14
5.1.    Mailbox Naming ............................................   14
5.1.1.  Mailbox Hierarchy Naming ..................................   14
5.1.2.  Mailbox Namespace Naming Convention .......................   14
5.1.3.  Mailbox International Naming Convention ...................   15
5.2.    Mailbox Size and Message Status Updates ...................   16
5.3.    Response when no Command in Progress ......................   16
5.4.    Autologout Timer ..........................................   16
5.5.    Multiple Commands in Progress .............................   17
6.      Client Commands ...........................................   17
6.1.    Client Commands - Any State ...............................   18
6.1.1.  CAPABILITY Command ........................................   18
6.1.2.  NOOP Command ..............................................   19
6.1.3.  LOGOUT Command ............................................   20
6.2.    Client Commands - Non-Authenticated State .................   20
6.2.1.  AUTHENTICATE Command ......................................   21
6.2.2.  LOGIN Command .............................................   22
6.3.    Client Commands - Authenticated State .....................   22
6.3.1.  SELECT Command ............................................   23
6.3.2.  EXAMINE Command ...........................................   24
6.3.3.  CREATE Command ............................................   25
6.3.4.  DELETE Command ............................................   26
6.3.5.  RENAME Command ............................................   27
6.3.6.  SUBSCRIBE Command .........................................   29
6.3.7.  UNSUBSCRIBE Command .......................................   30
6.3.8.  LIST Command ..............................................   30
6.3.9.  LSUB Command ..............................................   32
6.3.10. STATUS Command ............................................   33
6.3.11. APPEND Command ............................................   34
6.4.    Client Commands - Selected State ..........................   35
6.4.1.  CHECK Command .............................................   36
6.4.2.  CLOSE Command .............................................   36
6.4.3.  EXPUNGE Command ...........................................   37
6.4.4.  SEARCH Command ............................................   37
6.4.5.  FETCH Command .............................................   41
6.4.6.  STORE Command .............................................   45
6.4.7.  COPY Command ..............................................   46
6.4.8.  UID Command ...............................................   47
6.5.    Client Commands - Experimental/Expansion ..................   48
6.5.1.  X<atom> Command ...........................................   48
7.      Server Responses ..........................................   48
7.1.    Server Responses - Status Responses .......................   49
7.1.1.  OK Response ...............................................   51
7.1.2.  NO Response ...............................................   51
7.1.3.  BAD Response ..............................................   52
7.1.4.  PREAUTH Response ..........................................   52
7.1.5.  BYE Response ..............................................   52
7.2.    Server Responses - Server and Mailbox Status ..............   53
7.2.1.  CAPABILITY Response .......................................   53
7.2.2.  LIST Response ..............................................  54
7.2.3.  LSUB Response .............................................   55
7.2.4   STATUS Response ...........................................   55
7.2.5.  SEARCH Response ...........................................   55
7.2.6.  FLAGS Response ............................................   56
7.3.    Server Responses - Mailbox Size ...........................   56
7.3.1.  EXISTS Response ...........................................   56
7.3.2.  RECENT Response ...........................................   57
7.4.    Server Responses - Message Status .........................   57
7.4.1.  EXPUNGE Response ..........................................   57
7.4.2.  FETCH Response ............................................   58
7.5.    Server Responses - Command Continuation Request ...........   63
8.      Sample IMAP4rev1 connection ...............................   63
9.      Formal Syntax .............................................   64
10.     Author's Note .............................................   74
11.     Security Considerations ...................................   74
12.     Author's Address ..........................................   75
Appendices ........................................................   76
A.      References ................................................   76
B.      Changes from RFC 1730 .....................................   77
C.      Key Word Index ............................................   79
โœจ Heads up, we're only on part 1 of 18, so the real protocol meat (the actual commands, responses, and formal syntax) is still coming, bestie ๐Ÿซถ๐Ÿ’œ

1. How to Read This Document โœจ

1.1. Organization of This Document

Okay bestie, this doc is written for the implementor ๐Ÿ› ๏ธ of an IMAP4rev1 client or server. Apart from the protocol overview in section 2, it's not really built for someone who just wants to understand how the protocol works ๐Ÿซถ The stuff in sections 3 through 5 gives you the general context and definitions that IMAP4rev1 runs on ๐Ÿ’œ

Sections 6, 7, and 9 cover the IMAP commands, responses, and syntax ๐Ÿฆ‹ They're all so tangled together that it's almost impossible to understand any one of them on its own ๐Ÿ˜ญ So please don't try to figure out command syntax from the command section alone ๐Ÿ™ˆ Go to the Formal Syntax section instead ๐Ÿ’…

1.2. Conventions Used in This Document

In examples, C: and S: show lines sent by the client and the server ๐ŸŒธ

These are the terms this document uses to signal how strict each requirement is ๐ŸŽ€

  1. MUST, or the adjective REQUIRED, means that the definition is an absolute requirement of the specification.
  2. MUST NOT means that the definition is an absolute prohibition of the specification.
  3. SHOULD means that there may exist valid reasons in particular circumstances to ignore a particular item, but the full implications MUST be understood and carefully weighed before choosing a different course.
  4. SHOULD NOT means that there may exist valid reasons in particular circumstances when the particular behavior is acceptable or even useful, but the full implications SHOULD be understood and the case carefully weighed before implementing any behavior described with this label.
  5. MAY, or the adjective OPTIONAL, means that an item is truly optional. One vendor may choose to include the item because a particular marketplace requires it or because the vendor feels that it enhances the product, while another vendor may omit the same item ๐ŸŒˆ An implementation which does not include a particular option MUST be prepared to interoperate with another implementation which does include the option ๐Ÿค
"Can" is used instead of "may" when referring to a possible circumstance or situation, as opposed to an optional facility of the protocol. So it's a vibe check: "can" is about what's possible, "may" is about what's optional ๐Ÿ’€

"User" refers to a human user, whereas "client" refers to the software the user is running ๐Ÿงš

"Connection" refers to the entire sequence of client/server interaction, from the moment the network connection is set up until it's terminated ๐Ÿ”ฅ "Session" refers to the sequence of client/server interaction from the time a mailbox is selected (SELECT or EXAMINE command) until that selection ends. That happens when you SELECT or EXAMINE another mailbox, send a CLOSE command, or terminate the connection ๐Ÿ“


Characters are 7-bit US-ASCII unless otherwise specified ๐ŸŒธ Other character sets are indicated using a "CHARSET", as described in [MIME-IMT] and defined in [CHARSET]. CHARSETs have important additional semantics beyond defining a character set, so go check those documents for the details ๐Ÿ’–

2. Protocol Overview ๐Ÿฆ‹

IMAP4rev1 assumes a reliable data stream, like the one TCP provides ๐Ÿงท When TCP is used, an IMAP4rev1 server listens on port 143 ๐ŸŽ€

2.2. Commands and Responses

An IMAP4rev1 connection is made up of three things: setting up a client/server network connection, an initial greeting from the server, and then client/server interactions โœจ Each of those interactions is a client command, server data, and a server completion result response ๐Ÿ’…

Everything the client and server send is in the form of lines, meaning strings that end with a CRLF ๐Ÿ“ The protocol receiver of an IMAP4rev1 client or server is either reading a line, or reading a sequence of octets with a known count followed by a line ๐Ÿ”

2.2.1. Client Protocol Sender and Server Protocol Receiver

The client command kicks off an operation ๐Ÿš€ Every client command gets prefixed with an identifier called a "tag". It's usually a short alphanumeric string, like A0001, A0002, and so on ๐Ÿท๏ธ The client generates a different tag for each command ๐Ÿ’œ

There are two cases where a line from the client isn't a complete command ๐Ÿ™ƒ In the first, a command argument is quoted with an octet count (see the description of literal in String under Data Formats). In the second, the command arguments need server feedback (see the AUTHENTICATE command). Either way, if the server is ready for the octets (where that applies) and the rest of the command, it sends a command continuation request response, which is prefixed with the token + ๐Ÿฆ‹

Note: If the server instead detects an error in the command, it sends a BAD completion response with a tag matching the command (as described below). This rejects the command and stops the client from sending any more of it ๐Ÿšซ

It's also possible for the server to send a completion response for some other command (if multiple commands are in progress), or to send untagged data ๐ŸŒ€ In either case, the command continuation request is still pending. The client takes the appropriate action for the response and reads another response from the server ๐Ÿง  In all cases, the client MUST send a complete command (including receiving all command continuation request responses and command continuations for the command) before initiating a new command ๐Ÿ™Œ

The protocol receiver of an IMAP4rev1 server reads a command line from the client, parses the command and its arguments, and then transmits server data and a server command completion result response ๐ŸŽ€

2.2.2. Server Protocol Sender and Client Protocol Receiver

Data the server sends to the client, and status responses that don't indicate command completion, are prefixed with the token *. These are called untagged responses ๐ŸŒธ

Server data MAY be sent as a result of a client command, or MAY be sent unilaterally by the server ๐Ÿ’ซ There's no syntactic difference between server data that came from a specific command and server data that was sent unilaterally ๐Ÿซถ

The server completion result response tells you whether the operation succeeded or failed ๐Ÿ It's tagged with the same tag as the client command that started the operation ๐Ÿท๏ธ So if more than one command is in progress, the tag on a server completion response tells you which command it applies to ๐Ÿ”Ž There are three possible server completion responses: OK (success), NO (failure), and BAD (protocol error, like an unrecognized command or a command syntax error) ๐Ÿ“

The protocol receiver of an IMAP4rev1 client reads a response line from the server. It then acts on the response based on its first token, which can be a tag, a *, or a + ๐Ÿงš

A client MUST be prepared to accept any server response at all times ๐Ÿ›ก๏ธ This includes server data that wasn't requested. Server data SHOULD be recorded, so the client can reference its recorded copy instead of sending a command to the server to request the data again โœจ For certain server data, the data MUST be recorded ๐Ÿ“Œ

This topic is discussed in greater detail in the Server Responses section ๐Ÿ’…

2.3. Message Attributes

Besides the message text, each message has several attributes attached to it ๐ŸŽ€ These attributes can be retrieved individually, or together with other attributes or message texts ๐Ÿฆ‹

2.3.1. Message Numbers โœจ

okay so messages in IMAP4rev1 can be accessed by one of two numbers ๐ŸŽ€: the unique identifier and the message sequence number. two different vibes, both iconic ๐Ÿ’…

2.3.1.1. Unique Identifier (UID) Message Attribute ๐Ÿฆ‹

a UID is a 32-bit value given to each message. paired with the UID validity value (more on that in a sec), it becomes a 64-bit value that is permanently guaranteed to never point at any other message in the mailbox ๐Ÿ”’ that's literally the whole point bestie. UIDs are assigned in a strictly ascending order in the mailbox, so every new message that shows up gets a higher UID than the ones that came before it ๐Ÿ“ˆ

unlike message sequence numbers, UIDs are not necessarily contiguous (aka there can be gaps, no cap ๐Ÿ™ˆ). UIDs also persist across sessions, which lets a client resync its state from a previous session with the server. this is super useful for disconnected or offline access clients, and [IMAP-DISC] goes deeper on it ๐ŸŒธ

every mailbox has its own unique identifier validity value. it gets sent in an UIDVALIDITY response code inside an OK untagged response when the mailbox gets selected ๐Ÿ’œ if the UIDs from an earlier session don't carry over into this session, the unique identifier validity value MUST be greater than the one used in the earlier session. that's the signal that says "hey, the old UIDs are not it anymore" ๐Ÿšจ

Note: UIDs MUST be strictly ascending in the mailbox at all times. ๐Ÿ’€ if a non-IMAP agent reorders the physical message store, the UIDs in the mailbox have to be regenerated, because the old ones won't be ascending anymore after the shuffle. another situation where UIDs get regenerated is when the message store has no way to store UIDs at all. the spec admits this might be unavoidable in some server setups, but it strongly encourages message store implementations that dodge this problem entirely ๐Ÿซถ
Note (continued): another way UIDs stop persisting is when a mailbox gets deleted and a new one with the same name gets created later. since the name matches, a client can't tell it's a brand new mailbox unless the UID validity value is different ๐Ÿ‘€ a good value for it is a 32-bit representation of the mailbox's creation date/time โœจ using a constant like 1 is alright too, but ONLY if it's guaranteed that UIDs will never be reused, even if the mailbox gets deleted (or renamed) and a new one with the same name shows up later. no cheating ๐Ÿ˜ค

the UID of a message MUST NOT change during the session, and SHOULD NOT change between sessions. however, if it's not possible to keep a message's UID in a later session, then each subsequent session MUST have a new UID validity value that's larger than any used before. the vibe is always "newer is bigger" ๐Ÿ“

2.3.1.2. Message Sequence Number Message Attribute ๐Ÿงš

a message sequence number is a relative position, going from 1 up to the number of messages in the mailbox. this position MUST be ordered by ascending UID ๐Ÿ’– as each new message is added, it gets a sequence number that is 1 higher than the number of messages in the mailbox before it got added. easy peasy ๐ŸŒˆ

sequence numbers can get reassigned during the session. for example, when a message gets permanently removed (expunged) from the mailbox, the sequence number of every message after it goes down by one ๐Ÿ“‰ and a new message can end up with a sequence number that some other message used to have before an expunge. it's a lot, but it's giving chaos in a fun way ๐ŸŒช๏ธ

the cool part is that sequence numbers can also be used in math, not just to point at a message by its spot in the mailbox ๐Ÿงฎ for example, if an untagged EXISTS 11 shows up and an untagged 8 EXISTS came through earlier, that means three new messages arrived, with sequence numbers 9, 10, and 11. another example: if message 287 in a 523 message mailbox has UID 12345, then there are exactly 286 messages with lesser UIDs and 236 messages with greater UIDs. the way the numbers line up is honestly so satisfying ๐Ÿ˜ญ๐Ÿซถ

2.3.2. Flags Message Attribute ๐Ÿณ๏ธโ€๐ŸŒˆ

flags are a list of zero or more named tokens attached to the message. setting a flag means adding it to that list, and clearing it means removing it ๐Ÿ” there are two types of flags in IMAP4rev1, and any flag of either type can be permanent or session-only ๐Ÿ’…

a system flag is a flag name that's already pre-defined in this specification. every system flag starts with "" ๐Ÿ’ซ a couple of them (\Deleted and \Seen) have special semantics that get described elsewhere. the currently defined system flags are:

        \Seen       Message has been read

        \Answered   Message has been answered

        \Flagged    Message is "flagged" for urgent/special attention

        \Deleted    Message is "deleted" for removal by later EXPUNGE

        \Draft      Message has not completed composition (marked as a
                    draft).

        \Recent     Message is "recently" arrived in this mailbox.  This
                    session is the first session to have been notified
                    about this message; subsequent sessions will not see
                    \Recent set for this message.  This flag can not be
                    altered by the client.

                    If it is not possible to determine whether or not
                    this session is the first session to be notified
                    about a message, then that message SHOULD be
                    considered recent.

                    If multiple connections have the same mailbox
                    selected simultaneously, it is undefined which of
                    these connections will see newly-arrives messages
                    with \Recent set and which will see it without
                    \Recent set.

okay the \Recent one is the main character of this whole list ๐ŸŽญ it means a message just showed up in this mailbox, and this session is the first one to be told about it. later sessions won't see \Recent set for that message ๐Ÿ‘‘ and if you can't figure out whether this session is the first one to be notified, that message SHOULD be considered recent. if a bunch of connections have the same mailbox selected at once, it's undefined which of them sees new messages with \Recent set and which ones don't. chaotic but valid ๐ŸŒ€

a keyword is defined by the server implementation. keywords do not begin with "". servers MAY let the client define new keywords in the mailbox (check out the PERMANENTFLAGS response code for the deets ๐Ÿ’œ).

a flag can be permanent or session-only on a per-flag basis. permanent flags are the ones the client can add or remove from the message flags permanently, which means later sessions will see any change to them ๐Ÿ”’ changes to session flags only count inside that session, and then they vanish ๐Ÿซง

Note: the \Recent system flag is a special case of a session flag. \Recent can not be used as an argument in a STORE command, so it literally can't be changed at all ๐Ÿ™…โ€โ™€๏ธ

2.3.3. Internal Date Message Attribute ๐Ÿ“…

this is the internal date and time of the message on the server. it's NOT the date and time in the [RFC-822] header ๐Ÿ™…โ€โ™€๏ธ it's the date and time that reflects when the message was received. for messages delivered via [SMTP], this SHOULD be the date and time of final delivery of the message as defined by [SMTP]. for messages delivered by the IMAP4rev1 COPY command, this SHOULD be the internal date and time of the source message. for messages delivered by the IMAP4rev1 APPEND command, this SHOULD be the date and time specified in the APPEND command description. everything else is implementation defined ๐Ÿ› ๏ธ

2.3.4. [RFC-822] Size Message Attribute ๐Ÿ“

this is the number of octets in the message, written in [RFC-822] format. simple, clean, no drama ๐Ÿฐ

2.3.5. Envelope Structure Message Attribute ๐Ÿ’Œ

this is a parsed representation of the [RFC-822] envelope information. it's not the same thing as an [SMTP] envelope, so don't mix them up bestie ๐Ÿ™ˆ the envelope is basically the message's parsed "wrapper info", and it's kinda iconic ๐Ÿฆ‹

2.3.6. Body Structure Message Attribute ๐Ÿงฉ

okay so this one is giving parsed representation energy ๐Ÿ’… it's a parsed version of the [MIME-IMB] body structure info of the message. the structure is the whole vibe ๐Ÿฆ‹


2.4. Message Texts ๐Ÿ“จ

bestie, besides grabbing the full [RFC-822] text of a message, IMAP4rev1 lets you fetch just the pieces โœจ specifically: the [RFC-822] message header, the [RFC-822] message body, a [MIME-IMB] body part, or a [MIME-IMB] header. slay ๐Ÿ’–


3. State and Flow Diagram ๐Ÿ—บ๏ธ

okay so an IMAP4rev1 server is in one of four states ๐Ÿ‘‘ most commands only work in certain states, and if the client tries a command while the connection is in the wrong state, that's a protocol error ๐Ÿ’€ in that case the server answers with a BAD or NO (depending on how the server was built) as the command completion result ๐Ÿ™ˆ

3.1. Non-Authenticated State ๐Ÿ”’

in non-authenticated state, the client MUST supply authentication credentials before most commands are allowed ๐Ÿซถ you land here when a connection starts, unless it was already pre-authenticated.

3.2. Authenticated State ๐Ÿ”“

in authenticated state, the client is authenticated and MUST select a mailbox to access before commands that touch messages will work ๐ŸŽ€ you get here when a pre-authenticated connection starts, when acceptable credentials have been provided, or after an error while selecting a mailbox.

3.3. Selected State ๐Ÿ“ฌ

in selected state, a mailbox has been selected to access. this is where you end up once a mailbox is successfully selected โœจ

3.4. Logout State ๐Ÿšช

in logout state, the connection is being terminated and the server will close it ๐Ÿ˜ญ this can happen because the client asked for it, or because the server decided on its own.

Here's the state map, it's giving subway diagram ๐Ÿš‡

            +--------------------------------------+
            |initial connection and server greeting|
            +--------------------------------------+
                      || (1)       || (2)        || (3)
                      VV           ||            ||
            +-----------------+    ||            ||
            |non-authenticated|    ||            ||
            +-----------------+    ||            ||
             || (7)   || (4)       ||            ||
             ||       VV           VV            ||
             ||     +----------------+           ||
             ||     | authenticated  |<=++       ||
             ||     +----------------+  ||       ||
             ||       || (7)   || (5)   || (6)   ||
             ||       ||       VV       ||       ||
             ||       ||    +--------+  ||       ||
             ||       ||    |selected|==++       ||
             ||       ||    +--------+           ||
             ||       ||       || (7)            ||
             VV       VV       VV                VV
            +--------------------------------------+
            |     logout and close connection      |
            +--------------------------------------+

         (1) connection without pre-authentication (OK greeting)
         (2) pre-authenticated connection (PREAUTH greeting)
         (3) rejected connection (BYE greeting)
         (4) successful LOGIN or AUTHENTICATE command
         (5) successful SELECT or EXAMINE command
         (6) CLOSE command, or failed SELECT or EXAMINE command
         (7) LOGOUT command, server shutdown, or connection closed

4. Data Formats ๐ŸŽ€

IMAP4rev1 uses textual commands and responses ๐Ÿ’… data can come in one of a few forms: atom, number, string, parenthesized list, or NIL.

4.1. Atom ๐Ÿ“

an atom is one or more non-special characters.

4.2. Number ๐Ÿ”ข

a number is one or more digit characters, and it represents a numeric value.

4.3. String ๐Ÿงถ

a string comes in two forms: literal and quoted string. the literal form is the general one ๐Ÿ’– the quoted string is an alternative that skips the overhead of processing a literal, but you get limits on which characters you can use in it.

a literal is a sequence of zero or more octets (including CR and LF), prefix-quoted with an octet count in the form of an open brace ({), the number of octets, a close brace (}), and CRLF. for literals sent from server to client, the CRLF is immediately followed by the octet data. for literals sent from client to server, the client MUST wait to receive a command continuation request (described later in this document) before sending the octet data and the rest of the command ๐Ÿซถ

a quoted string is a sequence of zero or more 7-bit characters, excluding CR and LF, with double quote (") characters at each end ๐ŸŒธ

the empty string can be written as either "" (a quoted string with zero characters between the double quotes) or as {0} followed by CRLF (a literal with an octet count of 0) ๐Ÿ™ˆ

Note: Even if the octet count is 0, a client transmitting a literal MUST wait to receive a command continuation request. โš ๏ธ

4.3.1. 8-bit and Binary Strings ๐Ÿ”

8-bit textual and binary mail is supported through a [MIME-IMB] content transfer encoding โœจ IMAP4rev1 implementations MAY transmit 8-bit or multi-octet characters in literals, but SHOULD do so only when the [CHARSET] is identified.

ngl binary strings are a no-go ๐Ÿ™…โ€โ™€๏ธ although a BINARY body encoding is defined, unencoded binary strings are not permitted. a "binary string" is any string with NUL characters. implementations MUST encode binary data into a textual form such as BASE64 before transmitting the data. a string with an excessive amount of CTL characters MAY also be considered to be binary ๐Ÿ‘€

4.4. Parenthesized List ๐ŸŒท

data structures are shown as a "parenthesized list": a sequence of data items, separated by spaces and wrapped in parentheses at each end. a parenthesized list can hold other parenthesized lists, with more levels of parentheses for nesting ๐Ÿช†

the empty list is written as (), a parenthesized list with no members.

4.5. NIL ๐Ÿซฅ

the special atom "NIL" stands for the non-existence of a data item that would be a string or a parenthesized list. it's different from the empty string "" or the empty parenthesized list () ๐Ÿ’œ


5. Operational Considerations ๐Ÿ› ๏ธ

5.1. Mailbox Naming ๐Ÿ“ซ

the way mailbox names get interpreted is up to the implementation ๐Ÿคทโ€โ™€๏ธ the case-insensitive mailbox name INBOX is special though, reserved to mean "the primary mailbox for this user on this server" ๐Ÿ‘‘

5.1.1. Mailbox Hierarchy Naming ๐ŸŒณ

if you want to export hierarchical mailbox names, mailbox names MUST be left-to-right hierarchical, using a single character to separate the levels ๐Ÿ’… the same separator character is used for every level within a single name.

5.1.2. Mailbox Namespace Naming Convention ๐Ÿท๏ธ

by convention, the first hierarchical element of any mailbox name that begins with "#" identifies the "namespace" of the rest of the name โœจ this makes it possible to tell apart different types of mailbox stores, each with their own namespaces ๐Ÿฆ‹

for example, implementations that offer access to USENET newsgroups MAY use the #news namespace to split the USENET newsgroup namespace off from other mailboxes ๐Ÿ“ฐ so the comp.mail.misc newsgroup would have a mailbox name of #news.comp.mail.misc, and the name comp.mail.misc could refer to a totally different object (e.g. a user's private mailbox) ๐Ÿ™ˆ iykyk.

5.1.3. Mailbox International Naming Convention ๐ŸŒ

okay so international mailbox names follow a convention: they use a modified version of the UTF-7 encoding from [UTF-7]. bestie, the modifications fix five real problems with plain UTF-7 ๐Ÿ’€:

  1. UTF-7 uses "+" for shifting, which clashes with "+" showing up in mailbox names, especially USENET newsgroup names ๐Ÿ™ˆ
  2. UTF-7's encoding is BASE64, which uses "/", and that clashes with "/" being a super popular hierarchy delimiter ๐Ÿ“
  3. UTF-7 prohibits unencoded "", which clashes with "" being a popular hierarchy delimiter ๐Ÿ’…
  4. UTF-7 prohibits unencoded "~", which clashes with "~" as a home directory indicator on some servers ๐Ÿ 
  5. UTF-7 allows multiple alternate forms for the same string. Printable US-ASCII characters can be written in encoded form too, which is a lot ๐ŸŒ€

In modified UTF-7, printable US-ASCII characters (except "&") represent themselves. That means octet values 0x20-0x25 and 0x27-0x7e. The "&" (0x26) gets written as the two-octet sequence &- ๐ŸŽ€

All other characters (octet values 0x00-0x1f, 0x7f-0xff, and all Unicode 16-bit octets) are written in modified BASE64. There's one more tweak from [UTF-7] here: "," is used instead of "/". Modified BASE64 MUST NOT be used to represent any printing US-ASCII character which can represent itself. โœจ

"&" shifts into modified BASE64, and "-" shifts back to US-ASCII. All names start in US-ASCII and MUST end in US-ASCII. So a name that ends with a Unicode 16-bit octet MUST end with a "-". ๐Ÿซถ

Here's an example mailbox name that mixes English, Japanese, and Chinese text:

~peter/mail/&ZeVnLIqe-/&U,BTFw-

5.2. Mailbox Size and Message Status Updates ๐Ÿ“ฌ

At any time, a server can send data that the client did not request. Sometimes this is REQUIRED ๐Ÿ˜ญ. For example, agents other than the server MAY add messages to the mailbox (like new mail delivery), change the flags of messages in the mailbox (like simultaneous access to the same mailbox by multiple agents), or even remove messages from the mailbox. A server MUST send mailbox size updates automatically if a mailbox size change is observed during the processing of a command. A server SHOULD send message flag updates automatically, without requiring the client to ask for them explicitly. There are special rules for server notification of a client about removed messages, so nothing gets out of sync. See the description of the EXPUNGE response for more detail ๐Ÿ”ฅ.

Regardless of what a client decides to remember from the server, a client implementation MUST record mailbox size updates. It MUST NOT assume that any command after initial mailbox selection will return the size of the mailbox. Main character energy is knowing when the numbers changed ๐Ÿ’–.


5.3. Response when no Command in Progress ๐Ÿ“ญ

Server implementations are allowed to send an untagged response (except for EXPUNGE) while there is no command in progress. Server implementations that do this MUST deal with flow control. Specifically, they MUST either (1) verify that the size of the data does not exceed the underlying transport's available window size, or (2) use non-blocking writes. Ngl this is the kind of careful planning I respect ๐Ÿงš.


5.4. Autologout Timer โฐ

If a server has an inactivity autologout timer, that timer MUST be at least 30 minutes long. Receiving ANY command from the client during that interval SHOULD be enough to reset the autologout timer ๐ŸŒธ.


5.5. Multiple Commands in Progress ๐Ÿ”

The client MAY send another command without waiting for the completion result response of a command. This is subject to ambiguity rules (see below) and flow control constraints on the underlying data stream. In the same way, a server MAY begin processing another command before finishing the current one, subject to ambiguity rules. However, any command continuation request responses and command continuations MUST be negotiated before any subsequent command is initiated. ๐Ÿงต

The exception is when an ambiguity would result because one command would affect the results of other commands. Clients MUST NOT send multiple commands without waiting if an ambiguity would result. If the server detects a possible ambiguity, it MUST execute commands to completion in the order the client gave them ๐Ÿšฆ.

The most obvious example of ambiguity is when one command would affect the results of another, like a FETCH of a message's flags and a STORE of that same message's flags ๐Ÿ‘€.

A non-obvious ambiguity happens with commands that permit an untagged EXPUNGE response (commands other than FETCH, STORE, and SEARCH). An untagged EXPUNGE response can invalidate sequence numbers in a later command. This is not a problem for FETCH, STORE, or SEARCH because servers are prohibited from sending EXPUNGE responses while any of those commands are in progress. So if the client sends any command other than FETCH, STORE, or SEARCH, it MUST wait for a response before sending a command with message sequence numbers. ๐Ÿ’…

For example, these non-waiting command sequences are invalid:

FETCH + NOOP + STORE
STORE + COPY + FETCH
COPY + COPY
CHECK + FETCH

These are valid non-waiting command sequences:

FETCH + STORE + SEARCH + CHECK
STORE + COPY + EXPUNGE

6. Client Commands โœจ

IMAP4rev1 commands are described in this section. Commands are grouped by the state in which they're permitted. Commands that are permitted in multiple states are listed under the minimum permitted state. For example, commands valid in the authenticated and selected states are listed under the authenticated state commands ๐ŸŽ€.

Command arguments, marked "Arguments:" in the command descriptions below, are described by what they do, not by their syntax. The exact syntax of command arguments is in the Formal Syntax section ๐Ÿ“–.

Some commands cause specific server responses, which are marked "Responses:" in the command descriptions. For information on those responses, see the response descriptions in the Responses section, and the Formal Syntax section for their exact syntax. Server data can be sent as a result of any command, so commands that don't specifically need server data say "no specific responses for this command" instead of "none" ๐Ÿฆ‹.

The "Result:" in each command description refers to the possible tagged status responses to a command, plus any special meaning for those status responses ๐Ÿง.


6.1. Client Commands - Any State ๐Ÿซถ

These commands are valid in any state: CAPABILITY, NOOP, and LOGOUT. ๐ŸŒˆ

6.1.1. CAPABILITY Command ๐Ÿงข

Arguments:  none

Responses:  REQUIRED untagged response: CAPABILITY

Result:     OK - capability completed
            BAD - command unknown or arguments invalid

The CAPABILITY command asks for a list of the capabilities the server supports. The server MUST send a single untagged CAPABILITY response with "IMAP4rev1" as one of the listed capabilities, before the (tagged) OK response. This list doesn't depend on connection state or user, so there's no need to issue a CAPABILITY command more than once in a connection ๐Ÿ’œ.

A capability name that begins with "AUTH=" tells you the server supports that particular authentication mechanism. All such names are, by definition, part of this specification. For example, the authorization capability for an experimental "blurdybloop" authenticator would be AUTH=XBLURDYBLOOP, and NOT XAUTH=BLURDYBLOOP or XAUTH=XBLURDYBLOOP ๐Ÿ˜ค.

Other capability names refer to extensions, revisions, or amendments to this specification. See the documentation of the CAPABILITY response for more info. No capabilities beyond the base IMAP4rev1 set in this specification are enabled unless the client explicitly takes action to invoke them ๐Ÿ”.

For info about the form of site or implementation-specific capabilities, see the section called "Client Commands - Experimental/Expansion" ๐Ÿ”.

Example:

C: abcd CAPABILITY
S: * CAPABILITY IMAP4rev1 AUTH=KERBEROS_V4
S: abcd OK CAPABILITY completed

6.1.2. NOOP Command ๐Ÿ˜ด

Arguments:  none

Responses:  no specific responses for this command (but see below)

Result:     OK - noop completed
            BAD - command unknown or arguments invalid

The NOOP command always succeeds. It does nothing, iconic behavior honestly ๐Ÿ™Œ.

Since any command can return a status update as untagged data, NOOP can be used as a periodic poll for new messages or message status updates during a quiet stretch. NOOP can also be used to reset any inactivity autologout timer on the server โฑ๏ธ.

Example:

C: a002 NOOP
S: a002 OK NOOP completed
   . . .
C: a047 NOOP
S: * 22 EXPUNGE
S: * 23 EXISTS
S: * 3 RECENT
S: * 14 FETCH (FLAGS (\Seen \Deleted))
S: a047 OK NOOP completed

6.1.3. LOGOUT Command ๐Ÿ‘‹

Arguments:  none

Responses:  REQUIRED untagged response: BYE

Result:     OK - logout completed
            BAD - command unknown or arguments invalid

The LOGOUT command tells the server the client is done with the connection. The server MUST send a BYE untagged response before the (tagged) OK response, and then close the network connection ๐Ÿซก.

Example:

C: A023 LOGOUT
S: * BYE IMAP4rev1 Server logging out
S: A023 OK LOGOUT completed
   (Server and client then close the connection)

6.2. Client Commands - Non-Authenticated State ๐Ÿ”

In the non-authenticated state, the AUTHENTICATE or LOGIN command sets up authentication and moves the connection into the authenticated state. AUTHENTICATE is a general mechanism for many authentication techniques, while LOGIN uses the classic user name and plaintext password pair ๐Ÿ—๏ธ.

Server implementations MAY allow non-authenticated access to certain mailboxes. The convention is to use a LOGIN command with the userid "anonymous". A password is REQUIRED. What requirements (if any) apply to the password, and what access restrictions apply to anonymous users, is up to each implementation ๐Ÿ•ต๏ธ.

Once authenticated (including as "anonymous"), it is not possible to re-enter the non-authenticated state. No takebacks ๐Ÿšซ.

In addition to the universal commands (CAPABILITY, NOOP, and LOGOUT), the following commands are valid in the non-authenticated state: AUTHENTICATE and LOGIN ๐Ÿ’….

6.2.1. AUTHENTICATE Command โœจ

   Arguments:  authentication mechanism name

   Responses:  continuation data can be requested

   Result:     OK - authenticate completed, now in authenticated state
               NO - authenticate failure: unsupported authentication
                    mechanism, credentials rejected
              BAD - command unknown or arguments invalid,
                    authentication exchange cancelled

okay bestie, so AUTHENTICATE is how the client tells the server which auth mechanism it wants, like the ones described in [IMAP-AUTH] ๐Ÿ”. If the server supports that mechanism, it runs an authentication protocol exchange to authenticate and identify the client ๐Ÿซถ. It MAY also negotiate an OPTIONAL protection mechanism for later protocol interactions โœจ. If the requested mechanism isn't supported, the server SHOULD reject the command by sending a tagged NO response ๐Ÿ™…โ€โ™€๏ธ.

the exchange itself is a bunch of server challenges and client answers that depend on the mechanism ๐Ÿฆ‹. A server challenge is a command continuation request response with the + token followed by a BASE64 encoded string. The client answer is a line with a BASE64 encoded string. If the client wants to cancel, it sends a line with just a single *. If the server gets that, it MUST reject the AUTHENTICATE command by sending a tagged BAD response ๐Ÿ’€.

now the protection mechanism, which is giving integrity and privacy for the connection ๐ŸŒธ. If one is negotiated, it covers ALL the data sent after that point. It kicks in right after the CRLF that ends the client's side of the exchange, and right after the CRLF of the tagged OK response for the server. Once it's on, the stream of command and response octets gets processed into buffers of ciphertext. Each buffer goes over the connection as a stream of octets with a four octet field in network byte order in front of it, showing the length of the data that follows. The maximum ciphertext buffer length is defined by the protection mechanism ๐Ÿงš.

Here's the big picture on OPTIONAL-ness ๐Ÿ’–. Authentication mechanisms are OPTIONAL. Protection mechanisms are also OPTIONAL, so an authentication mechanism MAY be implemented without any protection mechanism. If an AUTHENTICATE command fails with a NO response, the client MAY try a different mechanism by sending another AUTHENTICATE command, or MAY just try the LOGIN command. In other words, the client MAY request auth types in decreasing order of preference, with LOGIN as the last resort ๐Ÿ‘‘.

S: * OK KerberosV4 IMAP4rev1 Server
C: A001 AUTHENTICATE KERBEROS_V4
S: + AmFYig==
C: BAcAQU5EUkVXLkNNVS5FRFUAOCAsho84kLN3/IJmrMG+25a4DT
   +nZImJjnTNHJUtxAA+o0KPKfHEcAFs9a3CL5Oebe/ydHJUwYFd
   WwuQ1MWiy6IesKvjL5rL9WjXUb9MwT9bpObYLGOKi1Qh
S: + or//EoAADZI=
C: DiAF5A4gA+oOIALuBkAAmw==
S: A001 OK Kerberos V4 authentication successful

Note: the line breaks in the first client answer are for editorial clarity and are not in real authenticators. ๐Ÿ™ˆ


6.2.2. LOGIN Command โœจ

   Arguments:  user name
               password

   Responses:  no specific responses for this command

   Result:     OK - login completed, now in authenticated state
               NO - login failure: user name or password rejected
               BAD - command unknown or arguments invalid

the LOGIN command is how the client identifies itself to the server ๐Ÿชช. It carries the plaintext password that authenticates this user, so yes, it's sending the password in plain text ๐Ÿ˜ญ.

C: a001 LOGIN SMITH SESAME
S: a001 OK LOGIN completed

6.3. Client Commands - Authenticated State ๐ŸŽ€

In authenticated state, commands that manipulate mailboxes as atomic entities are permitted. Of those, SELECT and EXAMINE are the ones that pick a mailbox for access and move you into selected state ๐Ÿฆ‹.

In addition to the universal commands (CAPABILITY, NOOP, and LOGOUT), these are valid in authenticated state: SELECT, EXAMINE, CREATE, DELETE, RENAME, SUBSCRIBE, UNSUBSCRIBE, LIST, LSUB, STATUS, and APPEND ๐Ÿ’….


6.3.1. SELECT Command โœจ

   Arguments:  mailbox name

   Responses:  REQUIRED untagged responses: FLAGS, EXISTS, RECENT
               OPTIONAL OK untagged responses: UNSEEN, PERMANENTFLAGS

   Result:     OK - select completed, now in selected state
               NO - select failure, now in authenticated state: no
                    such mailbox, can't access mailbox
               BAD - command unknown or arguments invalid

SELECT picks a mailbox so you can actually access the messages inside ๐Ÿ“ฌ. Before the server returns an OK, it MUST send this untagged data to the client:

FLAGS       Defined flags in the mailbox.  See the description
            of the FLAGS response for more detail.

<n> EXISTS  The number of messages in the mailbox.  See the
            description of the EXISTS response for more detail.

<n> RECENT  The number of messages with the \Recent flag set.
            See the description of the RECENT response for more
            detail.

OK [UIDVALIDITY <n>]
            The unique identifier validity value.  See the
            description of the UID command for more detail.

All of that is there to set up the initial state of the mailbox on the client's side ๐ŸŒˆ.

The server SHOULD also send an UNSEEN response code in an OK untagged response ๐Ÿ‘€. It points at the message sequence number of the first unseen message in the mailbox.

If the client can not change the permanent state of one or more of the flags in the FLAGS untagged response, the server SHOULD send a PERMANENTFLAGS response code in an OK untagged response ๐Ÿšฉ. That one lists the flags the client CAN change permanently.

Only one mailbox can be selected at a time per connection ๐Ÿ™…โ€โ™€๏ธ. Want to touch multiple mailboxes? You need multiple connections. SELECT automatically deselects whatever's selected before trying the new one, so if you select a mailbox and then a SELECT fails, no mailbox is selected anymore ๐Ÿ˜ญ.

If the client is permitted to modify the mailbox, the server SHOULD prefix the text of the tagged OK response with the [READ-WRITE] response code ๐Ÿ’–.

If the client isn't permitted to modify the mailbox but IS permitted read access, the mailbox gets selected as read-only, and the server MUST prefix the tagged OK response to SELECT with the [READ-ONLY] response code ๐Ÿ”’. Read-only access through SELECT differs from EXAMINE in that certain read-only mailboxes MAY permit changing permanent state on a per-user (as opposed to global) basis. Netnews messages marked in a server-based .newsrc file are an example of that kind of per-user permanent state that can be changed with read-only mailboxes ๐Ÿ—ž๏ธ.

C: A142 SELECT INBOX
S: * 172 EXISTS
S: * 1 RECENT
S: * OK [UNSEEN 12] Message 12 is first unseen
S: * OK [UIDVALIDITY 3857529045] UIDs valid
S: * FLAGS (\Answered \Flagged \Deleted \Seen \Draft)
S: * OK [PERMANENTFLAGS (\Deleted \Seen \*)] Limited
S: A142 OK [READ-WRITE] SELECT completed

6.3.2. EXAMINE Command โœจ

   Arguments:  mailbox name

   Responses:  REQUIRED untagged responses: FLAGS, EXISTS, RECENT
               OPTIONAL OK untagged responses: UNSEEN, PERMANENTFLAGS

   Result:     OK - examine completed, now in selected state
               NO - examine failure, now in authenticated state: no
                    such mailbox, can't access mailbox
               BAD - command unknown or arguments invalid

EXAMINE is basically SELECT's read-only twin ๐Ÿ‘ฏ. It gives you the same output, but the mailbox is marked as read-only. No changes to the permanent state of the mailbox are allowed, including per-user state ๐Ÿ™…โ€โ™€๏ธ.

The text of the tagged OK response to EXAMINE MUST begin with the [READ-ONLY] response code ๐Ÿ”.

C: A932 EXAMINE blurdybloop
S: * 17 EXISTS
S: * 2 RECENT
S: * OK [UNSEEN 8] Message 8 is first unseen
S: * OK [UIDVALIDITY 3857529045] UIDs valid
S: * FLAGS (\Answered \Flagged \Deleted \Seen \Draft)
S: * OK [PERMANENTFLAGS ()] No permanent flags permitted
S: A932 OK [READ-ONLY] EXAMINE completed

6.3.3. CREATE Command โœจ

   Arguments:  mailbox name

   Responses:  no specific responses for this command

   Result:     OK - create completed
               NO - create failure: can't create mailbox with that name
               BAD - command unknown or arguments invalid

CREATE makes a brand new mailbox with the name you give it ๐Ÿ“. You only get an OK if a new mailbox with that name was actually created. It's an error to try creating INBOX, or a name that points at a mailbox that already exists ๐Ÿ™ˆ. Any creation error comes back as a tagged NO response.

If the mailbox name ends with the server's hierarchy separator character (the one the server returns from a LIST command), that's the client saying "I plan to make mailboxes under this name" ๐ŸŒณ. Server implementations that don't need that declaration MUST ignore it.

If the hierarchy separator character shows up anywhere else in the name, the server SHOULD create any superior hierarchical names needed for CREATE to succeed. So, say the server uses / as the separator and you try to create foo/bar/zap. The server SHOULD create foo/ and foo/bar/ if they don't already exist ๐Ÿง.

If a new mailbox is created with the same name as one that got deleted, its unique identifiers MUST be greater than any unique identifiers used in the previous incarnation of the mailbox, unless the new incarnation has a different unique identifier validity value. Check the description of the UID command for more detail ๐Ÿ”ข.

C: A003 CREATE owatagusiam/
S: A003 OK CREATE completed
C: A004 CREATE owatagusiam/blurdybloop
S: A004 OK CREATE completed

Note: how you read this example depends on whether / was returned as the hierarchy separator from LIST. If / is the separator, you get a new level of hierarchy called "owatagusiam" with a member named "blurdybloop" inside it ๐ŸŒท. Otherwise, you get two mailboxes sitting at the same hierarchy level ๐Ÿฆ„.

6.3.4. DELETE Command ๐Ÿ—‘๏ธโœจ

Arguments:  mailbox name

Responses:  no specific responses for this command

Result:     OK - delete completed
            NO - delete failure: can't delete mailbox with that name
            BAD - command unknown or arguments invalid

okay so DELETE is the command that permanently removes a mailbox by its name ๐Ÿ’€ A tagged OK only comes back if the mailbox was actually deleted. And you can't delete INBOX, and you can't delete a mailbox name that doesn't exist. no cap, INBOX is untouchable ๐Ÿ‘‘

The DELETE command MUST NOT remove inferior hierarchical names ๐Ÿ™…โ€โ™€๏ธ Say a mailbox "foo" has an inferior "foo.bar" (with "." as the hierarchy delimiter). Deleting "foo" MUST NOT delete "foo.bar". It's an error to delete a name that has inferior hierarchical names and the \Noselect mailbox name attribute (go check the LIST response part for the full tea โ˜•).

It's allowed to delete a name that has inferior hierarchical names but doesn't have \Noselect. In that case, all the messages in that mailbox get removed, and the name picks up the \Noselect attribute. iykyk ๐Ÿฆ‹

Also, the highest-used unique identifier of the deleted mailbox MUST be preserved ๐Ÿ” That way, a new mailbox made with the same name won't reuse the IDs of the old one, UNLESS the new one has a different unique identifier validity value. Check the UID command section if you want the deep dive ๐Ÿงš

C: A682 LIST "" *
S: * LIST () "/" blurdybloop
S: * LIST (\Noselect) "/" foo
S: * LIST () "/" foo/bar
S: A682 OK LIST completed
C: A683 DELETE blurdybloop
S: A683 OK DELETE completed
C: A684 DELETE foo
S: A684 NO Name "foo" has inferior hierarchical names
C: A685 DELETE foo/bar
S: A685 OK DELETE Completed
C: A686 LIST "" *
S: * LIST (\Noselect) "/" foo
S: A686 OK LIST completed
C: A687 DELETE foo
S: A687 OK DELETE Completed


C: A82 LIST "" *
S: * LIST () "." blurdybloop
S: * LIST () "." foo
S: * LIST () "." foo.bar
S: A82 OK LIST completed
C: A83 DELETE blurdybloop
S: A83 OK DELETE completed
C: A84 DELETE foo
S: A84 OK DELETE Completed
C: A85 LIST "" *
S: * LIST () "." foo.bar
S: A85 OK LIST completed
C: A86 LIST "" %
S: * LIST (\Noselect) "." foo
S: A86 OK LIST completed

6.3.5. RENAME Command ๐ŸŽ€

Arguments:  existing mailbox name
            new mailbox name

Responses:  no specific responses for this command

Result:     OK - rename completed
            NO - rename failure: can't rename mailbox with that name,
                 can't rename to mailbox with that name
            BAD - command unknown or arguments invalid

RENAME changes the name of a mailbox, and it's giving glow-up ๐ŸŒธ A tagged OK only shows up if the mailbox actually got renamed. It's an error to rename from a name that doesn't exist, or to a name that already exists. Any rename error gets a tagged NO back ๐Ÿ™ˆ

If the name has inferior hierarchical names, those inferior names MUST also be renamed ๐Ÿซถ For example, renaming "foo" to "zap" will rename "foo/bar" (with "/" as the hierarchy delimiter) to "zap/bar". The sibling gets dragged along, no exceptions ๐Ÿ’…

The highest-used unique identifier of the old mailbox name MUST be preserved ๐Ÿ” So a new mailbox created with the same name won't reuse the old IDs, UNLESS the new incarnation has a different unique identifier validity value. Again, the UID command section has the full story โœจ

Renaming INBOX is allowed, and it has its own special behavior ๐Ÿฆ‹ It moves every message in INBOX into a new mailbox with the given name, and INBOX gets left empty. If the server supports inferior hierarchical names of INBOX, those stay exactly where they are. Main character energy for INBOX ๐Ÿ‘‘

C: A682 LIST "" *
S: * LIST () "/" blurdybloop
S: * LIST (\Noselect) "/" foo
S: * LIST () "/" foo/bar
S: A682 OK LIST completed
C: A683 RENAME blurdybloop sarasoop
S: A683 OK RENAME completed
C: A684 RENAME foo zowie
S: A684 OK RENAME Completed
C: A685 LIST "" *
S: * LIST () "/" sarasoop
S: * LIST (\Noselect) "/" zowie
S: * LIST () "/" zowie/bar
S: A685 OK LIST completed
C: Z432 LIST "" *
S: * LIST () "." INBOX
S: * LIST () "." INBOX.bar
S: Z432 OK LIST completed
C: Z433 RENAME INBOX old-mail
S: Z433 OK RENAME completed
C: Z434 LIST "" *
S: * LIST () "." INBOX
S: * LIST () "." INBOX.bar
S: * LIST () "." old-mail
S: Z434 OK LIST completed

6.3.6. SUBSCRIBE Command ๐Ÿ“

Arguments:  mailbox

Responses:  no specific responses for this command

Result:     OK - subscribe completed
            NO - subscribe failure: can't subscribe to that name
            BAD - command unknown or arguments invalid

SUBSCRIBE adds the mailbox name to the server's set of "active" or "subscribed" mailboxes, the ones LSUB shows you ๐Ÿ“Œ A tagged OK only comes back if the subscription worked โœจ

A server MAY validate the mailbox argument to SUBSCRIBE to check that it exists ๐Ÿ” But here's the vibe check: it MUST NOT unilaterally remove an existing mailbox name from the subscription list, even if that mailbox doesn't exist anymore ๐Ÿซถ

Note: this requirement is because some server sites may routinely remove a mailbox with a well-known name (e.g. "system-alerts") after its contents expire, with the intention of recreating it when new contents are appropriate. So the server can't just yank the subscription away ๐Ÿฅบ
C: A002 SUBSCRIBE #news.comp.mail.mime
S: A002 OK SUBSCRIBE completed

6.3.7. UNSUBSCRIBE Command ๐ŸŒˆ

Arguments:  mailbox name

Responses:  no specific responses for this command

Result:     OK - unsubscribe completed
            NO - unsubscribe failure: can't unsubscribe that name
            BAD - command unknown or arguments invalid

UNSUBSCRIBE is the opposite of SUBSCRIBE ๐Ÿ’– It removes the mailbox name from the server's set of "active" or "subscribed" mailboxes (the same set LSUB returns). A tagged OK only shows up if the unsubscription actually went through ๐ŸŒท

C: A002 UNSUBSCRIBE #news.comp.mail.mime
S: A002 OK UNSUBSCRIBE completed

6.3..8. LIST Command โœจ

bestie, the LIST command is basically the "show me the folders" move ๐Ÿ“‚๐Ÿซถ Here's how the arguments, responses, and results go:

  • Arguments: a reference name, and a mailbox name with possible wildcards
  • Responses: untagged LIST responses
  • Result:
    • OK: list completed
    • NO: list failure, can't list that reference or name
    • BAD: command unknown or arguments invalid

okay so LIST returns a subset of the names the client can see ๐Ÿ’… You get zero or more untagged LIST replies, and each one carries the name attributes, the hierarchy delimiter, and the name itself. Check the LIST reply description for the full tea โ˜•

LIST SHOULD return its data quickly, without undue delay ๐Ÿƒโ€โ™€๏ธ๐Ÿ’จ It SHOULD NOT go to excess trouble to work out \Marked or \Unmarked status or do other extra processing. Imagine if each name took 1 second to process: a list of 1200 names would take 20 minutes!! ๐Ÿ˜ญ nobody has time for that bestie ๐Ÿ’€

An empty ("" string) reference name means the mailbox name gets interpreted the same way SELECT would do it ๐ŸŽ€ The mailbox names that come back MUST match the mailbox name pattern you sent. A non-empty reference name is the name of a mailbox or a level of mailbox hierarchy, and it sets a context where the mailbox name is interpreted in an implementation-defined way ๐Ÿฆ‹

An empty ("" string) mailbox name is a special request that gets you the hierarchy delimiter and the root name of the reference name ๐ŸŒธ The root MAY be null if the reference is non-rooted or is null. Either way the hierarchy delimiter always comes back, which is so useful because the client can grab it even when no mailboxes with that name exist yet ๐Ÿงš

The reference and mailbox name arguments get interpreted, in an implementation-dependent way, into a canonical form that represents an unambiguous left-to-right hierarchy โœจ The returned mailbox names will be in that interpreted form.

Any part of the reference argument that gets included in the interpreted form SHOULD prefix the interpreted form ๐Ÿ’– It SHOULD also be in the same form as the reference name argument. This is the rule that lets the client tell whether a returned mailbox name lives in the context of the reference argument, or whether something in the mailbox argument overrode it ๐Ÿ‘‘ Without this rule the client would need to know the server's naming semantics, including which characters are "breakouts" that override a naming context. no thank you ๐Ÿ™…โ€โ™€๏ธ

Here are some examples of how references and mailbox names might get interpreted on a UNIX-based server ๐Ÿง

         Reference     Mailbox Name  Interpretation
         ------------  ------------  --------------
         ~smith/Mail/  foo.*         ~smith/Mail/foo.*
         archive/      %             archive/%
         #news.        comp.mail.*   #news.comp.mail.*
         ~smith/Mail/  /usr/doc/foo  /usr/doc/foo
         archive/      ~fred/Mail/*  ~fred/Mail/*

The first three examples show interpretations in the context of the reference argument ๐Ÿฅฐ Note that ~smith/Mail SHOULD NOT get transformed into something like /u2/users/smith/Mail, or the client would have no way to tell the interpretation was in the context of the reference ๐Ÿ˜ฉ

The * is a wildcard that matches zero or more characters at that position ๐ŸŒˆ The % is similar to *, but it does NOT match a hierarchy delimiter. If % is the last character of a mailbox name argument, the matching levels of hierarchy get returned too. If those levels aren't also selectable mailboxes, they come back with the \Noselect mailbox name attribute (check the LIST response description for more details) ๐Ÿซง

Server implementations are allowed to "hide" otherwise accessible mailboxes from the wildcards. They can stop certain characters or names from matching a wildcard in certain situations ๐Ÿ™ˆ For example, a UNIX-based server might restrict * so that an initial / character doesn't match.

The special name INBOX is included in the LIST output if INBOX is supported by this server for this user, AND if the uppercase string "INBOX" matches the interpreted reference and mailbox name arguments with wildcards, the way we just described ๐Ÿ“ The criteria for omitting INBOX is whether SELECT INBOX would return failure. It doesn't matter whether the user's real INBOX lives on this server or some other one ๐Ÿซถ

Example:

C: A101 LIST "" ""
S: * LIST (\Noselect) "/" ""
S: A101 OK LIST Completed
C: A102 LIST #news.comp.mail.misc ""
S: * LIST (\Noselect) "." #news.
S: A102 OK LIST Completed
C: A103 LIST /usr/staff/jones ""
S: * LIST (\Noselect) "/" /
S: A103 OK LIST Completed
C: A202 LIST ~/Mail/ %
S: * LIST (\Noselect) "/" ~/Mail/foo
S: * LIST () "/" ~/Mail/meetings
S: A202 OK LIST completed

6.3.9. LSUB Command ๐Ÿฆ‹

LSUB is the "show me my subscribed folders" command ๐Ÿ’œ Here's the rundown:

  • Arguments: a reference name, and a mailbox name with possible wildcards
  • Responses: untagged LSUB responses
  • Result:
    • OK: lsub completed
    • NO: lsub failure, can't list that reference or name
    • BAD: command unknown or arguments invalid

LSUB returns a subset of names from the set the user has declared as "active" or "subscribed" ๐ŸŽ€ Zero or more untagged LSUB replies come back. The arguments to LSUB take the same form as the ones for LIST, so if you know LIST, you already know LSUB ๐Ÿ™Œ

A server MAY validate the subscribed names to see if they still exist ๐Ÿ” If a name doesn't exist, it SHOULD get flagged with the \Noselect attribute in the LSUB response. A server MUST NOT unilaterally remove an existing mailbox name from the subscription list, even if a mailbox by that name no longer exists. bestie, the server is NOT allowed to just delete your subscriptions on its own ๐Ÿ˜ค๐Ÿ’…

Example:

C: A002 LSUB "#news." "comp.mail.*"
S: * LSUB () "." #news.comp.mail.mime
S: * LSUB () "." #news.comp.mail.misc
S: A002 OK LSUB completed

6.3.10. STATUS Command ๐Ÿ“Š

the STATUS command asks for the status of a mailbox, and it's giving very efficient energy โœจ Here's the setup:

  • Arguments: a mailbox name, and status data item names
  • Responses: untagged STATUS responses
  • Result:
    • OK: status completed
    • NO: status failure, no status for that name
    • BAD: command unknown or arguments invalid

STATUS requests the status of the mailbox you name ๐Ÿ’– It does NOT change the currently selected mailbox, and it doesn't touch the state of any messages in the mailbox you're asking about. In particular, STATUS MUST NOT cause messages to lose the \Recent flag. protect the \Recent flag at all costs ๐Ÿ›ก๏ธ

STATUS is a handy alternative to opening a second IMAP4rev1 connection and running EXAMINE on a mailbox just to check its status. That way you don't have to deselect the mailbox you already have open in your first IMAP4rev1 connection ๐Ÿงš

Unlike LIST, STATUS is NOT guaranteed to respond fast ๐ŸŒ On some implementations the server has to open the mailbox read-only internally to get certain status info. Also unlike LIST, STATUS does NOT accept wildcards. no * here, babe ๐Ÿ™…โ€โ™€๏ธ

The currently defined status data items you can request are:

MESSAGES       The number of messages in the mailbox.

RECENT         The number of messages with the \Recent flag set.

UIDNEXT        The next UID value that will be assigned to a new
               message in the mailbox.  It is guaranteed that this
               value will not change unless new messages are added
               to the mailbox; and that it will change when new
               messages are added even if those new messages are
               subsequently expunged.

UIDVALIDITY    The unique identifier validity value of the
               mailbox.

UNSEEN         The number of messages which do not have the \Seen
               flag set.

Example:

C: A042 STATUS blurdybloop (UIDNEXT MESSAGES)
S: * STATUS blurdybloop (MESSAGES 231 UIDNEXT 44292)
S: A042 OK STATUS completed

6.3.11. APPEND Command โœจ

okay so APPEND is the command that tacks a brand new message onto the very end of a mailbox, bestie ๐Ÿ’Œ here's the lineup:

Arguments:  mailbox name
            OPTIONAL flag parenthesized list
            OPTIONAL date/time string
            message literal

Responses:  no specific responses for this command

Result:     OK - append completed
            NO - append error: can't append to that mailbox, error
                 in flags or date/time or message text
            BAD - command unknown or arguments invalid

So the literal argument is the message you're appending ๐Ÿ“ฉ and it SHOULD look like an [RFC-822] message. 8-bit characters are totally allowed in there ๐ŸŒˆ BUT if your server can't keep 8-bit data intact, it MUST be able to reversibly convert that 8-bit APPEND data to 7-bit using a [MIME-IMB] content transfer encoding. no cap, that's the safety net ๐Ÿซถ

There MAY be exceptions, like draft messages, where the required [RFC-822] header lines are left out of the message literal. But the full implications of doing that MUST be understood and carefully weighed ๐Ÿง don't just vibe with it!

Now the flags. If you send a flag parenthesized list, those flags SHOULD be set on the new message ๐ŸŽ€. If you don't, the flag list just defaults to empty ๐Ÿซง

Same energy for dates. If a date_time is given, the internal date SHOULD be set on the resulting message ๐Ÿ—“๏ธ otherwise it defaults to the current date and time โฐ

Here's the big drama moment ๐Ÿ˜ญ If the append fails for any reason, the mailbox MUST be restored to how it was before the APPEND attempt. No partial appending is permitted. it's all or nothing, babe ๐Ÿ’…

And if the destination mailbox doesn't exist, the server MUST return an error and MUST NOT auto-create it ๐Ÿ™…โ€โ™€๏ธ unless it's certain that the mailbox can't be created, the server MUST send the response code [TRYCREATE] as the prefix of the text in the tagged NO response. This is basically a hint saying "hey, try a CREATE and then retry the APPEND if that works" ๐Ÿงš

If the mailbox is currently selected, the normal new mail actions SHOULD happen โœจ specifically, the server SHOULD tell the client right away with an untagged EXISTS response. If it doesn't, the client MAY send a NOOP command (or, failing that, a CHECK command) after one or more APPEND commands ๐Ÿ””

Example:

C: A003 APPEND saved-messages (\Seen) {310}
C: Date: Mon, 7 Feb 1994 21:52:25 -0800 (PST)
C: From: Fred Foobar <foobar@Blurdybloop.COM>
C: Subject: afternoon meeting
C: To: mooch@owatagu.siam.edu
C: Message-Id: <B27397-0100000@Blurdybloop.COM>
C: MIME-Version: 1.0
C: Content-Type: TEXT/PLAIN; CHARSET=US-ASCII
C:
C: Hello Joe, do you think we can meet at 3:30 tomorrow?
C:
S: A003 OK APPEND completed
Note: the APPEND command is not used for message delivery ๐Ÿšซ๐Ÿ“ฌ, because it does not provide a mechanism to transfer [SMTP] envelope information. so don't use it as your mail delivery truck, bestie!

6.4. Client Commands - Selected State ๐Ÿ“

in selected state, you get to play with the messages inside a mailbox ๐Ÿ’– commands that manipulate messages are permitted here.

On top of the universal commands (CAPABILITY, NOOP, and LOGOUT) and the authenticated state commands (SELECT, EXAMINE, CREATE, DELETE, RENAME, SUBSCRIBE, UNSUBSCRIBE, LIST, LSUB, STATUS, and APPEND), the following commands are valid in the selected state: CHECK, CLOSE, EXPUNGE, SEARCH, FETCH, STORE, COPY, and UID ๐Ÿ‘‘

6.4.1. CHECK Command

Arguments:  none

Responses:  no specific responses for this command

Result:     OK - check completed
            BAD - command unknown or arguments invalid

CHECK requests a checkpoint of the currently selected mailbox ๐Ÿงน a checkpoint is any implementation-dependent housekeeping for the mailbox (like syncing the server's in-memory state of the mailbox with what's on its disk) that doesn't normally run with every command. A checkpoint MAY take a non-instantaneous amount of real time to finish โณ and if a server has no housekeeping to do, CHECK is equivalent to NOOP ๐Ÿคทโ€โ™€๏ธ

There is no guarantee that an EXISTS untagged response will happen because of CHECK ๐Ÿ™ˆ so NOOP, not CHECK, SHOULD be used for new mail polling. the vibe check says NOOP ๐Ÿ“ฎ

Example:

C: FXXZ CHECK
S: FXXZ OK CHECK Completed

6.4.2. CLOSE Command

Arguments:  none

Responses:  no specific responses for this command

Result:     OK - close completed, now in authenticated state
            NO - close failure: no mailbox selected
            BAD - command unknown or arguments invalid

CLOSE permanently removes every message with the \Deleted flag set from the currently selected mailbox ๐Ÿ—‘๏ธ and takes you from selected state back to authenticated state ๐Ÿ”™ No untagged EXPUNGE responses are sent, so it's quiet and clean โœจ

No messages are removed and no error is given if the mailbox was selected by an EXAMINE command or is otherwise selected read-only ๐Ÿ‘€ it's a no-drama zone.

Even if a mailbox is selected, a SELECT, EXAMINE, or LOGOUT command MAY be issued without issuing a CLOSE first ๐Ÿซถ those three implicitly close the selected mailbox without doing an expunge. BUT when a bunch of messages get deleted, a CLOSE-LOGOUT or CLOSE-SELECT sequence is way faster than EXPUNGE-LOGOUT or EXPUNGE-SELECT ๐ŸŽ๏ธ๐Ÿ’จ because no untagged EXPUNGE responses (which the client would probably ignore anyway) get sent. efficiency is iconic ๐Ÿ’…

Example:

C: A341 CLOSE
S: A341 OK CLOSE completed

6.4.3. EXPUNGE Command

Arguments:  none

Responses:  untagged responses: EXPUNGE

Result:     OK - expunge completed
            NO - expunge failure: can't expunge (e.g. permission
                 denied)
            BAD - command unknown or arguments invalid

EXPUNGE permanently removes every message with the \Deleted flag set from the currently selected mailbox ๐Ÿ’€ and before the server sends its OK, it sends an untagged EXPUNGE response for each message it removes. That's the receipts ๐Ÿงพ

Example:

C: A202 EXPUNGE
S: * 3 EXPUNGE
S: * 3 EXPUNGE
S: * 5 EXPUNGE
S: * 8 EXPUNGE
S: A202 OK EXPUNGE completed
Note: in this example, messages 3, 4, 7, and 11 had the \Deleted flag set. see the description of the EXPUNGE response for further explanation ๐Ÿฆ‹

6.4.4. SEARCH Command ๐Ÿ”โœจ

Arguments:  OPTIONAL [CHARSET] specification
            searching criteria (one or more)

Responses:  REQUIRED untagged response: SEARCH

Result:     OK - search completed
            NO - search error: can't search that [CHARSET] or
                 criteria
            BAD - command unknown or arguments invalid

okay bestie, SEARCH is the command that goes digging through the mailbox ๐Ÿ•ต๏ธโ€โ™€๏ธ for messages that match your searching criteria. The criteria are made of one or more search keys, and the server's untagged SEARCH response is basically a little list of message sequence numbers for everything that matched ๐Ÿ’…

When you stack multiple keys, it's an AND situation. Only the messages that match all of them make the cut ๐ŸŽ€ So DELETED FROM "SMITH" SINCE 1-Feb-1994 is asking for deleted messages from Smith that were placed in the mailbox since February 1, 1994. A search key can also be a parenthesized list of one or more search keys, which is how you use the OR and NOT keys together ๐Ÿงš

Server implementations MAY leave out [MIME-IMB] body parts with terminal content media types other than TEXT and MESSAGE when they're doing SEARCH matching ๐Ÿ™ˆ

The OPTIONAL [CHARSET] specification is the word CHARSET followed by a registered [CHARSET] ๐ŸŒˆ It tells the server which [CHARSET] the strings in your search criteria are using. [MIME-IMB] content transfer encodings, and [MIME-HDRS] strings in [RFC-822]/[MIME-IMB] headers, MUST be decoded before comparing text in a [CHARSET] other than US-ASCII. US-ASCII MUST be supported, and other [CHARSET]s MAY be supported too. If the server doesn't support the [CHARSET] you specified, it MUST return a tagged NO response (not a BAD) ๐Ÿ’€

In all search keys that use strings, a message matches if the string is a substring of the field. The matching is case-insensitive ๐Ÿฆ‹

The defined search keys are below. For the exact syntax of the arguments, check out the Formal Syntax section ๐Ÿซถ

  • <message set>: messages with message sequence numbers corresponding to the specified message sequence number set
  • ALL: all messages in the mailbox. This is the default initial key for ANDing ๐Ÿ‘‘
  • ANSWERED: messages with the \Answered flag set
  • BCC <string>: messages that contain the specified string in the envelope structure's BCC field
  • BEFORE <date>: messages whose internal date is earlier than the specified date
  • BODY <string>: messages that contain the specified string in the body of the message
  • CC <string>: messages that contain the specified string in the envelope structure's CC field
  • DELETED: messages with the \Deleted flag set
  • DRAFT: messages with the \Draft flag set
  • FLAGGED: messages with the \Flagged flag set
  • FROM <string>: messages that contain the specified string in the envelope structure's FROM field
  • HEADER <field-name> <string>: messages that have a header with the specified field-name (as defined in [RFC-822]) and that contain the specified string in the [RFC-822] field-body
  • KEYWORD <flag>: messages with the specified keyword set
  • LARGER <n>: messages with an [RFC-822] size larger than the specified number of octets
  • NEW: messages that have the \Recent flag set but not the \Seen flag. This is functionally equivalent to "(RECENT UNSEEN)" ๐ŸŒธ
  • NOT <search-key>: messages that do not match the specified search key
  • OLD: messages that do not have the \Recent flag set. This is functionally equivalent to "NOT RECENT" (as opposed to "NOT NEW") ๐Ÿ“
  • ON <date>: messages whose internal date is within the specified date
  • OR <search-key1> <search-key2>: messages that match either search key
  • RECENT: messages that have the \Recent flag set
  • SEEN: messages that have the \Seen flag set
  • SENTBEFORE <date>: messages whose [RFC-822] Date: header is earlier than the specified date
  • SENTON <date>: messages whose [RFC-822] Date: header is within the specified date
  • SENTSINCE <date>: messages whose [RFC-822] Date: header is within or later than the specified date
  • SINCE <date>: messages whose internal date is within or later than the specified date
  • SMALLER <n>: messages with an [RFC-822] size smaller than the specified number of octets
  • SUBJECT <string>: messages that contain the specified string in the envelope structure's SUBJECT field
  • TEXT <string>: messages that contain the specified string in the header or body of the message
  • TO <string>: messages that contain the specified string in the envelope structure's TO field
  • UID <message set>: messages with unique identifiers corresponding to the specified unique identifier set ๐Ÿ”ฅ
  • UNANSWERED: messages that do not have the \Answered flag set
  • UNDELETED: messages that do not have the \Deleted flag set
  • UNDRAFT: messages that do not have the \Draft flag set
  • UNFLAGGED: messages that do not have the \Flagged flag set
  • UNKEYWORD <flag>: messages that do not have the specified keyword set
  • UNSEEN: messages that do not have the \Seen flag set

Here's the example, bestie ๐Ÿ’–

C: A282 SEARCH FLAGGED SINCE 1-Feb-1994 NOT FROM "Smith"
S: * SEARCH 2 84 882
S: A282 OK SEARCH completed

6.4.5. FETCH Command โœจ

   Arguments:  message set
               message data item names

   Responses:  untagged responses: FETCH

   Result:     OK - fetch completed
               NO - fetch error: can't fetch that data
               BAD - command unknown or arguments invalid

okay so FETCH is how you grab data about a message in the mailbox ๐Ÿ“ฌ๐Ÿ’–. The data items you want can be a single atom or a parenthesized list, so you can ask for one thing or a whole bundle ๐ŸŽ€.

These are the data items you can currently fetch:

  • ALL ๐Ÿ’… is a macro that means (FLAGS INTERNALDATE RFC822.SIZE ENVELOPE).
  • BODY is the non-extensible form of BODYSTRUCTURE ๐Ÿงš.
  • BODY[<section>]<<partial>> gives you the text of one particular body section ๐Ÿ“–. The section is zero or more part specifiers separated by periods. A part specifier is either a part number or one of HEADER, HEADER.FIELDS, HEADER.FIELDS.NOT, MIME, or TEXT. An empty section means the whole message, header included ๐Ÿ‘‘.
    • Every message has at least one part number. Messages that aren't [MIME-IMB] messages, and multipart [MIME-IMB] messages with no encapsulated message, only have part 1 ๐ŸŒธ.
    • Multipart messages get consecutive part numbers in the order they show up in the message. If a part is type message or multipart, its parts MUST be indicated by a period followed by the part number within that nested multipart part ๐Ÿฆ‹.
    • A part of type MESSAGE/RFC822 has nested part numbers too, pointing at the parts of that MESSAGE part's body ๐Ÿ“.
    • HEADER, HEADER.FIELDS, HEADER.FIELDS.NOT, and TEXT can stand alone, or they can be prefixed by one or more numeric part specifiers, as long as that numeric part specifier points at a part of type MESSAGE/RFC822 ๐Ÿซถ. The MIME part specifier MUST be prefixed by one or more numeric part specifiers ๐Ÿ’œ.
    • HEADER, HEADER.FIELDS, and HEADER.FIELDS.NOT refer to the [RFC-822] header of the message, or of an encapsulated [MIME-IMT] MESSAGE/RFC822 message โœจ. HEADER.FIELDS and HEADER.FIELDS.NOT are followed by a list of field-name names (as defined in [RFC-822]) and give back a subset of the header ๐Ÿ”ฅ. HEADER.FIELDS returns only the fields whose field-name matches one of the names in the list. HEADER.FIELDS.NOT returns only the fields whose field-name does not match ๐Ÿ’…. Field matching is case-insensitive but otherwise exact ๐Ÿ™ˆ. In every case, the blank line that separates the header from the body is always included ๐ŸŒˆ.
    • The MIME part specifier refers to the [MIME-IMB] header for this part ๐ŸŽ€.
    • The TEXT part specifier refers to the text body of the message, leaving out the [RFC-822] header ๐Ÿฆ‹.

Here's a complex message with some of its part specifiers, so you can see how the numbering works:

                        HEADER     ([RFC-822] header of the message)
                        TEXT       MULTIPART/MIXED
                        1          TEXT/PLAIN
                        2          APPLICATION/OCTET-STREAM
                        3          MESSAGE/RFC822
                        3.HEADER   ([RFC-822] header of the message)
                        3.TEXT     ([RFC-822] text body of the message)
                        3.1        TEXT/PLAIN
                        3.2        APPLICATION/OCTET-STREAM
                        4          MULTIPART/MIXED
                        4.1        IMAGE/GIF
                        4.1.MIME   ([MIME-IMB] header for the IMAGE/GIF)
                        4.2        MESSAGE/RFC822
                        4.2.HEADER ([RFC-822] header of the message)
                        4.2.TEXT   ([RFC-822] text body of the message)
                        4.2.1      TEXT/PLAIN
                        4.2.2      MULTIPART/ALTERNATIVE
                        4.2.2.1    TEXT/PLAIN
                        4.2.2.2    TEXT/RICHTEXT

You can also fetch a substring of the designated text ๐ŸŒท. To do that, add an open angle bracket (<), the octet position of the first octet you want, a period, the maximum number of octets you want, and a close angle bracket (>) to the part specifier. If the starting octet is beyond the end of the text, you get back an empty string ๐Ÿซง.

Any partial fetch that tries to read past the end of the text gets truncated as needed ๐Ÿ’€. A partial fetch that starts at octet 0 comes back as a partial fetch, even if that truncation happened ๐Ÿญ.

Note: this means that BODY[]<0.2048> of a 1500-octet message will return BODY[]<0> with a literal of size 1500, not BODY[].
Note: a substring fetch of a HEADER.FIELDS or HEADER.FIELDS.NOT part specifier is calculated after the header has been subset ๐Ÿง.

The \Seen flag gets set implicitly ๐Ÿ‘€. If that changes the flags, they SHOULD be included as part of the FETCH responses โœจ.

  • BODY.PEEK[<section>]<<partial>> is an alternate form of BODY[<section>] that does not set the \Seen flag ๐Ÿ™ˆ.
  • BODYSTRUCTURE is the [MIME-IMB] body structure of the message ๐Ÿฆ‹. The server works it out by parsing the [MIME-IMB] header fields in the [RFC-822] header and the [MIME-IMB] headers ๐ŸŒธ.
  • ENVELOPE is the envelope structure of the message ๐Ÿ’Œ. The server builds it by parsing the [RFC-822] header into its component parts, filling in default values for various fields where needed ๐ŸŽ€.
  • FAST is a macro that means (FLAGS INTERNALDATE RFC822.SIZE) โšก.
  • FLAGS gives you the flags that are set for this message ๐Ÿšฉ.
  • FULL is a macro that means (FLAGS INTERNALDATE RFC822.SIZE ENVELOPE BODY) ๐Ÿ‘‘.
  • INTERNALDATE is the internal date of the message ๐Ÿ—“๏ธ.
  • RFC822 is functionally equivalent to BODY[], but the untagged FETCH data comes back in the RFC822 syntax ๐Ÿ“.
  • RFC822.HEADER is functionally equivalent to BODY.PEEK[HEADER], but the untagged FETCH data comes back as RFC822.HEADER ๐Ÿงš.
  • RFC822.SIZE is the [RFC-822] size of the message ๐Ÿ“.
  • RFC822.TEXT is functionally equivalent to BODY[TEXT], but the untagged FETCH data comes back as RFC822.TEXT ๐Ÿ’œ.
  • UID is the unique identifier for the message ๐Ÿ”‘.

Here's an example ๐Ÿ’–:

   C: A654 FETCH 2:4 (FLAGS BODY[HEADER.FIELDS (DATE FROM)])
   S: * 2 FETCH ....
   S: * 3 FETCH ....
   S: * 4 FETCH ....
   S: A654 OK FETCH completed

6.4.6. STORE Command โœจ

   Arguments:  message set
               message data item name
               value for message data item

   Responses:  untagged responses: FETCH

   Result:     OK - store completed
               NO - store error: can't store that data
               BAD - command unknown or arguments invalid

the STORE command changes data associated with a message in the mailbox ๐Ÿ› ๏ธ. Normally, STORE sends back the updated value of the data in an untagged FETCH response ๐Ÿ’Œ. Add a .SILENT suffix to the data item name and the untagged FETCH gets skipped ๐Ÿคซ. In that case the server SHOULD assume that the client has worked out the updated value itself, or doesn't care about it ๐Ÿซถ.

Note: whether or not you use the .SILENT suffix, the server SHOULD send an untagged FETCH response if it notices a change to a message's flags from an external source ๐Ÿ‘€. The point is that the flag status is always clear, with no race condition ๐Ÿ”ฅ.

The data items you can currently store are:

  • FLAGS <flag list> replaces the flags for the message with the argument ๐Ÿ’…. The new value of the flags comes back as if you had done a FETCH of those flags ๐ŸŽ€.
  • FLAGS.SILENT <flag list> is the same as FLAGS, but it doesn't return a new value ๐Ÿคซ.
  • +FLAGS <flag list> adds the argument to the flags for the message โž•. The new value comes back as if you had done a FETCH of those flags ๐ŸŒธ.
  • +FLAGS.SILENT <flag list> is the same as +FLAGS, but without a new value returned ๐Ÿฆ‹.
  • -FLAGS <flag list> removes the argument from the flags for the message โž–. The new value comes back as if you had done a FETCH of those flags ๐Ÿง.
  • -FLAGS.SILENT <flag list> is the same as -FLAGS, but without a new value returned ๐Ÿ’œ.

Here's an example ๐Ÿ“:

   C: A003 STORE 2:4 +FLAGS (\Deleted)
   S: * 2 FETCH FLAGS (\Deleted \Seen)
   S: * 3 FETCH FLAGS (\Deleted)
   S: * 4 FETCH FLAGS (\Deleted \Flagged \Seen)
   S: A003 OK STORE completed

6.4.7. COPY Command โœจ

   Arguments:  message set
               mailbox name

   Responses:  no specific responses for this command

   Result:     OK - copy completed
               NO - copy error: can't copy those messages or to that
                    name
               BAD - command unknown or arguments invalid

the COPY command copies the specified message(s) to the end of the specified destination mailbox ๐Ÿ“ฆโœจ. The flags and internal date of the message(s) SHOULD be preserved in the copy ๐Ÿ’–.

If the destination mailbox doesn't exist, a server SHOULD return an error ๐Ÿ™…โ€โ™€๏ธ. It SHOULD NOT create the mailbox automatically ๐Ÿšซ. Unless it's certain the destination mailbox can't be created, the server MUST send the response code [TRYCREATE] as the prefix of the text of the tagged NO response ๐ŸŽ€. That's a hint for the client that it can try a CREATE command and then retry the COPY if the CREATE works ๐Ÿงš.

If the COPY command fails for any reason, server implementations MUST restore the destination mailbox to its state from before the COPY attempt ๐Ÿ›Ÿ๐Ÿ’œ.

Here's an example ๐ŸŒˆ:

   C: A003 COPY 2:4 MEETING
   S: A003 OK COPY completed

6.4.8. UID Command โœจ

  • Arguments: command name, command arguments
  • Responses: untagged responses: FETCH, SEARCH
  • Result: OK - UID command completed, NO - UID command error, BAD - command unknown or arguments invalid

okay so the UID command comes in two forms ๐Ÿ’… In the first one, you give it a COPY, FETCH, or STORE command with the arguments that command normally takes. The only difference is that the numbers in the message set are unique identifiers instead of message sequence numbers ๐Ÿฆ‹

The second form takes a SEARCH command with SEARCH arguments. They're read the same way as a regular SEARCH, but the numbers in the SEARCH response are unique identifiers instead of message sequence numbers. For example, UID SEARCH 1:100 UID 443:557 gives you the unique identifiers for the intersection of the message sequence number set 1:100 and the UID set 443:557 ๐Ÿงš

Message set ranges are allowed, but unique identifiers are not guaranteed to be contiguous, so don't expect them to line up neatly ๐Ÿ™ˆ If a unique identifier in a range doesn't exist, it gets ignored and no error message is generated. Quietly skipped, no drama ๐Ÿ’œ

One thing to keep straight: the number after the "*" in an untagged FETCH response is always a message sequence number, not a unique identifier, even when it's a response to a UID command ๐ŸŽ€ Still, server implementations MUST implicitly include the UID message data item in any FETCH response caused by a UID command, whether or not the client asked for a UID as a message data item in the FETCH. Iconic behaviour, no notes ๐Ÿ‘‘

Example:

C: A999 UID FETCH 4827313:4828442 FLAGS
S: * 23 FETCH (FLAGS (\Seen) UID 4827313)
S: * 24 FETCH (FLAGS (\Seen) UID 4827943)
S: * 25 FETCH (FLAGS (\Seen) UID 4828442)
S: A999 UID FETCH completed

6.5. Client Commands - Experimental/Expansion ๐ŸŒˆ

6.5.1. X<atom> Command ๐Ÿงช

  • Arguments: implementation defined
  • Responses: implementation defined
  • Result: OK - command completed, NO - failure, BAD - command unknown or arguments invalid

so any command starting with an X is an experimental command ๐Ÿงช Anything that isn't part of this specification, a standard or standards-track revision of it, or an IESG-approved experimental protocol MUST use the X prefix. Main character energy for sure, lowkey the vibe is "label your experiments" ๐Ÿ’…

Any untagged responses added by an experimental command MUST also be prefixed with an X. And server implementations MUST NOT send any of those untagged responses unless the client asked for them by issuing the matching experimental command. Consent is everything ๐Ÿซถ

Example:

C: a441 CAPABILITY
S: * CAPABILITY IMAP4rev1 AUTH=KERBEROS_V4 XPIG-LATIN
S: a441 OK CAPABILITY completed
C: A442 XPIG-LATIN
S: * XPIG-LATIN ow-nay eaking-spay ig-pay atin-lay
S: A442 OK XPIG-LATIN ompleted-cay

7. Server Responses ๐ŸŽ€

okay so server responses come in three forms: status responses, server data, and command continuation requests ๐ŸŒธ The info in a server response (the stuff labelled "Contents:" in the descriptions below) is explained by what it means, not by how it's written. The exact syntax lives in the Formal Syntax section, so look there if you want the nitty gritty ๐Ÿค“

The client MUST be prepared to accept any response at all times. Literally always, no exceptions ๐Ÿ˜ญ

Status responses can be tagged or untagged. Tagged ones tell you the result (OK, NO, or BAD) of a client command, and they carry the same tag as that command ๐Ÿ’–

Some status responses, and all server data, are untagged. Untagged responses start with the token * instead of a tag. They show the server greeting, or server status that doesn't finish a command (like an impending system shutdown alert) ๐Ÿšจ Historically, untagged server data gets called "unsolicited data," though technically only unilateral server data is truly unsolicited ๐Ÿ™ˆ

Certain server data MUST be recorded by the client when it arrives, and the description of that data will say so. This stuff is critical, because it changes how every later command and response gets read, like updates about messages being created or destroyed ๐Ÿ’€

Other server data SHOULD be recorded for later reference. If the client doesn't need to keep it, or there's no obvious reason to record it (like a SEARCH response when no SEARCH command is in progress), the data SHOULD be ignored ๐Ÿงน

Here's an example of unilateral untagged server data: when the IMAP connection is in the selected state, the server checks the mailbox for new messages as part of running a command ๐Ÿฆ‹ Usually that check happens with every command, so a NOOP command is enough to look for new messages. If it finds some, the server sends untagged EXISTS and RECENT responses showing the new mailbox size โœจ Server implementations that let several agents access the same mailbox at once SHOULD also send the right unilateral untagged FETCH and EXPUNGE responses when another agent changes message flags or expunges messages. Group chat, but make it server edition ๐Ÿ’ฌ

Command continuation request responses use the token + instead of a tag. The server sends these to say it accepts an incomplete client command and is ready for the rest of it ๐Ÿงš

7.1. Server Responses - Status Responses ๐Ÿ’œ

Status responses are OK, NO, BAD, PREAUTH and BYE. OK, NO, and BAD can be tagged or untagged. PREAUTH and BYE are always untagged ๐ŸŽ€

Status responses MAY include an OPTIONAL "response code." A response code is data in square brackets, made of an atom and maybe a space plus some arguments ๐Ÿ“ It carries extra info or status codes for client software beyond the OK/NO/BAD result, and it's only defined when there's a specific action a client can take based on that extra info ๐Ÿง 

The currently defined response codes are:

  • ALERT: The human-readable text has a special alert that MUST be presented to the user in a way that grabs their attention ๐Ÿšจ
  • NEWNAME: Followed by a mailbox name and a new mailbox name. A SELECT or EXAMINE is failing because the target mailbox name doesn't exist anymore, since it was renamed to the new mailbox name. It's a hint that the operation can work if you reissue the SELECT or EXAMINE with the new name ๐Ÿ”
  • PARSE: The human-readable text is an error in parsing the [RFC-822] header or [MIME-IMB] headers of a message in the mailbox ๐Ÿ“จ
  • PERMANENTFLAGS: Followed by a parenthesized list of flags, showing which of the known flags the client can change permanently. Any flag that's in the FLAGS untagged response but not in the PERMANENTFLAGS list can not be set permanently. If the client tries to STORE a flag that isn't in the PERMANENTFLAGS list, the server will either reject it with a NO reply or store the state for the rest of the current session only ๐Ÿ™…โ€โ™€๏ธ The PERMANENTFLAGS list can also include the special flag \*, which means you can create new keywords by trying to store those flags in the mailbox โœจ
  • READ-ONLY: The mailbox is selected read-only, or its access changed from read-write to read-only ๐Ÿ‘€
  • READ-WRITE: The mailbox is selected read-write, or its access changed from read-only to read-write โœ๏ธ
  • TRYCREATE: An APPEND or COPY is failing because the target mailbox doesn't exist (as opposed to some other reason). It's a hint that the operation can work if you CREATE the mailbox first ๐Ÿ› ๏ธ
  • UIDVALIDITY: Followed by a decimal number, showing the unique identifier validity value ๐Ÿ”ข
  • UNSEEN: Followed by a decimal number, showing the number of the first message without the \Seen flag set ๐Ÿ‘๏ธ

Additional response codes defined by particular client or server implementations SHOULD be prefixed with an "X" until they're added to a revision of this protocol. Client implementations SHOULD ignore response codes they don't recognize ๐Ÿซถ

7.1.1. OK Response ๐ŸŒŸ

  • Contents: OPTIONAL response code, human-readable text

the OK response is an information message from the server ๐Ÿ’– When it's tagged, it means the associated command finished successfully. The human-readable text MAY be shown to the user as an information message. The untagged form is info only, and the nature of the info MAY be shown with a response code ๐ŸŒธ

The untagged form also shows up as one of three possible greetings at connection startup. It tells you the connection isn't authenticated yet and a LOGIN command is needed ๐Ÿ”

Example:

S: * OK IMAP4rev1 server ready
C: A001 LOGIN fred blurdybloop
S: * OK [ALERT] System shutdown in 10 minutes
S: A001 OK LOGIN Completed

7.1.2. NO Response ๐Ÿ™…โ€โ™€๏ธ

  • Contents: OPTIONAL response code, human-readable text

the NO response is an operational error message from the server ๐Ÿ˜ฌ When it's tagged, the associated command did not finish successfully. The untagged form is a warning, and the command can still complete successfully anyway ๐Ÿคž The human-readable text describes what's going on ๐Ÿ“

Example:

C: A222 COPY 1:2 owatagusiam
S: * NO Disk is 98% full, please delete unnecessary data
S: A222 OK COPY completed
C: A223 COPY 3:200 blurdybloop
S: * NO Disk is 98% full, please delete unnecessary data
S: * NO Disk is 99% full, please delete unnecessary data
S: A223 NO COPY failed: disk is full

7.1.3. BAD Response ๐Ÿ’€

  • Contents: OPTIONAL response code, human-readable text

the BAD response is an error message from the server ๐Ÿšซ When it's tagged, it reports a protocol-level error in the client's command, and the tag tells you which command caused it. The untagged form is a protocol-level error where the command can't be figured out, and it can also mean an internal server failure ๐Ÿ”ง The human-readable text describes the condition ๐Ÿ“‹

Example:

C: ...very long command line...
S: * BAD Command line too long
C: ...empty line...
S: * BAD Empty command line
C: A443 EXPUNGE
S: * BAD Disk crash, attempting salvage to a new disk!
S: * OK Salvage successful, no data lost
S: A443 OK Expunge completed

7.1.4. PREAUTH Response

Contents: OPTIONAL response code, human-readable text

okay so the PREAUTH response is ALWAYS untagged ๐Ÿ’… and it's one of three possible greetings when you first connect ๐Ÿงš it basically says "hey, this connection is already authenticated by some outside method," so no LOGIN command is needed. main character energy, no login screen ๐ŸŽ€

Example: S: * PREAUTH IMAP4rev1 server logged in as Smith โœจ

7.1.5. BYE Response

Contents: OPTIONAL response code, human-readable text

bestie, the BYE response is always untagged, and it means the server is about to close the connection ๐Ÿฅ€ the human-readable text MAY be shown to the user in a status report by the client ๐Ÿ’– there are four situations where you'll get a BYE:

  1. as part of a normal logout sequence. the server will close the connection after sending the tagged OK response to the LOGOUT command ๐Ÿซถ
  2. as a panic shutdown announcement. the server closes the connection immediately ๐Ÿ˜ญ
  3. as an announcement of an inactivity autologout. the server closes the connection immediately ๐Ÿ’€
  4. as one of three possible greetings at connection startup, saying the server is not willing to accept a connection from this client. the server closes the connection immediately ๐Ÿ™ˆ

the tea is that the difference between a BYE from a normal LOGOUT (case 1) and a BYE from a failure (cases 2, 3 and 4) is just that in the failure cases the connection closes right away ๐Ÿ”ฅ

Example: S: * BYE Autologout; idle for too long ๐ŸŒธ

7.2. Server Responses - Server and Mailbox Status

these responses are always untagged ๐Ÿฆ‹ this is how server and mailbox status data gets sent from the server to the client ๐Ÿงš a lot of them usually come back from a command with the same name, so it's giving dรฉjร  vu ๐Ÿ’œ

7.2.1. CAPABILITY Response

Contents: capability listing

the CAPABILITY response shows up as a result of a CAPABILITY command ๐ŸŽ€ the capability listing is a space-separated list of capability names the server supports. the capability listing MUST include the atom "IMAP4rev1" ๐Ÿ‘‘

a capability name that begins with "AUTH=" tells you the server supports that particular authentication mechanism ๐Ÿ”

other capability names mean the server supports an extension, revision, or amendment to the IMAP4rev1 protocol ๐ŸŒˆ server responses MUST conform to this document until the client issues a command that uses the associated capability โœจ

capability names MUST either begin with "X" or be standard or standards-track IMAP4rev1 extensions, revisions, or amendments registered with IANA ๐Ÿซถ a server MUST NOT offer unregistered or non-standard capability names, unless those names are prefixed with an "X" ๐Ÿ™…โ€โ™€๏ธ

client implementations SHOULD NOT require any capability name other than "IMAP4rev1", and they MUST ignore any unknown capability names ๐Ÿ’…

Example: S: * CAPABILITY IMAP4rev1 AUTH=KERBEROS_V4 XPIG-LATIN ๐Ÿท

7.2.2. LIST Response

Contents: name attributes, hierarchy delimiter, name

the LIST response occurs as a result of a LIST command ๐ŸŒธ it returns a single name that matches the LIST specification. there can be MULTIPLE LIST responses for one LIST command ๐Ÿ“

okay, four name attributes are defined:

\Noinferiors: it is not possible for any child levels of hierarchy to exist under this name. no child levels exist now and none can be created in the future ๐Ÿšซ

\Noselect: it is not possible to use this name as a selectable mailbox ๐Ÿ™ˆ

\Marked: the server has marked the mailbox as "interesting". it probably has messages added since the last time it was selected ๐Ÿ‘€

\Unmarked: the mailbox doesn't have any additional messages since the last time it was selected โœจ

if it isn't feasible for the server to figure out whether the mailbox is "interesting" or not, or if the name is a \Noselect name, the server SHOULD NOT send either \Marked or \Unmarked ๐Ÿซ 

the hierarchy delimiter is the character used to separate levels of hierarchy in a mailbox name ๐Ÿ—‚๏ธ clients use it to create child mailboxes and to search higher or lower levels of the naming hierarchy ๐Ÿ’– all children of a top-level hierarchy node MUST use the same separator character ๐Ÿ’œ a NIL hierarchy delimiter means there's no hierarchy at all, and the name is a "flat" name ๐Ÿฅž

the name represents an unambiguous left-to-right hierarchy, and it MUST be valid for use as a reference in LIST and LSUB commands ๐Ÿงญ unless \Noselect is indicated, the name MUST also be valid as an argument for commands, such as SELECT, that accept mailbox names ๐ŸŽ€

Example: S: * LIST (\Noselect) "/" ~/Mail/foo ๐Ÿ“ฌ

7.2.3. LSUB Response

Contents: name attributes, hierarchy delimiter, name

the LSUB response occurs as a result of an LSUB command ๐Ÿฆ‹ it returns a single name that matches the LSUB specification. there can be multiple LSUB responses for a single LSUB command ๐ŸŒˆ the data is identical in format to the LIST response, so you already know how to read it ๐Ÿ’…

Example: S: * LSUB () "." #news.comp.mail.misc ๐Ÿ“ฐ

7.2.4 STATUS Response

Contents: name, status parenthesized list

the STATUS response occurs as a result of a STATUS command ๐ŸŒท it returns the mailbox name that matches the STATUS specification, plus the requested mailbox status information ๐Ÿ“Š

Example: S: * STATUS blurdybloop (MESSAGES 231 UIDNEXT 44292) ๐Ÿงš

7.2.5. SEARCH Response

Contents: zero or more numbers

the SEARCH response occurs as a result of a SEARCH or UID SEARCH command ๐Ÿ” the numbers refer to the messages that match your search criteria. for SEARCH these are message sequence numbers, and for UID SEARCH these are unique identifiers ๐Ÿ†” each number is delimited by a space ๐Ÿซง

Example: S: * SEARCH 2 3 6 ๐Ÿ’œ

7.2.6. FLAGS Response

Contents: flag parenthesized list

the FLAGS response occurs as a result of a SELECT or EXAMINE command ๐Ÿšฉ the flag parenthesized list tells you which flags apply to this mailbox (at a minimum, the system-defined flags). other flags can exist too, depending on the server implementation ๐ŸŒŸ

the update from the FLAGS response MUST be recorded by the client ๐Ÿ“

Example: S: * FLAGS (\Answered \Flagged \Deleted \Seen \Draft) ๐ŸŽ€


7.3. Server Responses - Mailbox Size

these responses are always untagged ๐ŸŒธ this is how changes in the size of the mailbox get sent from the server to the client ๐Ÿ“ˆ right after the "*" token there's a number that represents a message count ๐Ÿ”ข

7.3.1. EXISTS Response

Contents: none

the EXISTS response reports how many messages are in the mailbox ๐Ÿ’Œ it occurs as a result of a SELECT or EXAMINE command, and also whenever the size of the mailbox changes (e.g. new mail) ๐Ÿ“ฌ

the update from the EXISTS response MUST be recorded by the client ๐Ÿ’–

Example: S: * 23 EXISTS โœจ

7.3.2. RECENT Response

Contents: none

the RECENT response reports how many messages have the \Recent flag set ๐Ÿ†• it occurs as a result of a SELECT or EXAMINE command, and whenever the size of the mailbox changes (e.g. new mail) ๐Ÿ“จ

Note: it is NOT guaranteed that the message sequence numbers of recent messages form a contiguous range of the highest n messages in the mailbox (where n is the value reported by the RECENT response). situations where this isn't the case include multiple clients having the same mailbox open (the first session to be notified will see it as recent, while the others will probably see it as non-recent), and when the mailbox is re-ordered by a non-IMAP agent ๐Ÿ˜ณ

the only reliable way to find recent messages is to look at the message flags and see which ones have the \Recent flag set, or to do a SEARCH RECENT ๐Ÿ”Ž

the update from the RECENT response MUST be recorded by the client ๐Ÿซถ

Example: S: * 5 RECENT ๐ŸŒˆ


7.4. Server Responses - Message Status

these responses are always untagged ๐Ÿฆ‹ this is how message data gets sent from the server to the client, often as a result of a command with the same name ๐Ÿ’… right after the "*" token there's a number that represents a message sequence number ๐Ÿ”ข

7.4.1. EXPUNGE Response

Contents: none

the EXPUNGE response reports that the specified message sequence number has been permanently removed from the mailbox ๐Ÿ—‘๏ธ the message sequence number for each message after it is immediately decremented by 1, and that decrement shows up in message sequence numbers in later responses (including other untagged EXPUNGE responses) ๐Ÿงฎ

because of that immediate decrement rule, the message sequence numbers in a bunch of successive EXPUNGE responses depend on whether messages get removed from lower numbers to higher numbers, or from higher numbers to lower numbers ๐ŸŒ€ for example, if the last 5 messages in a 9-message mailbox get expunged, a "lower to higher" server will send five untagged EXPUNGE responses for message sequence number 5, while a "higher to lower server" will send successive untagged EXPUNGE responses for message sequence numbers 9, 8, 7, 6, and 5 ๐ŸŽข

an EXPUNGE response MUST NOT be sent when no command is in progress, and it MUST NOT be sent while responding to a FETCH, STORE, or SEARCH command ๐Ÿšซ this rule is necessary to prevent the message sequence numbers between client and server from falling out of sync ๐Ÿ˜ญ

the update from the EXPUNGE response MUST be recorded by the client ๐Ÿ“

Example: S: * 44 EXPUNGE ๐Ÿ‘‹

7.4.2. FETCH Response

Contents: message data

the FETCH response returns data about a message to the client ๐Ÿ“ฅ the data comes as pairs of data item names and their values, in parentheses ๐Ÿง this response happens as the result of a FETCH or STORE command, and also when the server decides to send it on its own (e.g. flag updates) ๐Ÿ””

the current data items are:

BODY: a form of BODYSTRUCTURE without extension data ๐Ÿงฑ

BODY[<section>]<<origin_octet>>: a string expressing the body contents of the specified section. the string SHOULD be interpreted by the client according to the content transfer encoding, body type, and subtype ๐Ÿ”ค

if the origin octet is specified, this string is a substring of the entire body contents, starting at that origin octet. this means that BODY[]<0> MAY be truncated, but BODY[] is NEVER truncated ๐Ÿซฃ

8-bit textual data is permitted if a [CHARSET] identifier is part of the body parameter parenthesized list for this section. Heads up though: headers (the part specifiers HEADER or MIME, or the header portion of a MESSAGE/RFC822 part) MUST be 7-bit, so 8-bit characters are not allowed in headers. Also, the blank line at the end of the header is always included in header data. ๐Ÿ’Œ

Non-textual data like binary data MUST be transfer encoded into a textual form such as BASE64 before it gets sent to the client. To get the original binary back, the client MUST decode the transfer encoded string. ๐Ÿซถ

  • BODYSTRUCTURE ๐Ÿฆ‹ A parenthesized list that describes the [MIME-IMB] body structure of a message. The server computes it by parsing the [MIME-IMB] header fields and filling in defaults for various fields as needed.

For example, a simple text message of 48 lines and 2279 octets can have a body structure of:

("TEXT" "PLAIN" ("CHARSET" "US-ASCII") NIL NIL "7BIT" 2279 48)

Multiple parts are shown by parenthesis nesting. Instead of a body type as the first element of the parenthesized list, there's a nested body. The second element of the parenthesized list is the multipart subtype (mixed, digest, parallel, alternative, etc.). Iconic. ๐Ÿ‘‘

For example, a two part message made up of a text part and a BASE645-encoded text attachment can have a body structure of:

(("TEXT" "PLAIN" ("CHARSET" "US-ASCII") NIL NIL "7BIT" 1152 23)("TEXT" "PLAIN"
("CHARSET" "US-ASCII" "NAME" "cc.diff")
"<960723163407.20117h@cac.washington.edu>"
"Compiler diff" "BASE64" 4554 73) "MIXED"))

Extension data follows the multipart subtype. Extension data is never returned with the BODY fetch, but it can be returned with a BODYSTRUCTURE fetch. Extension data, if present, MUST be in the defined order. ๐Ÿ“‹

The extension data of a multipart body part comes in the following order:

  • body parameter parenthesized list A parenthesized list of attribute/value pairs, like ("foo" "bar" "baz" "rag") where "bar" is the value of "foo" and "rag" is the value of "baz", as defined in [MIME-IMB].
  • body disposition A parenthesized list made of a disposition type string followed by a parenthesized list of disposition attribute/value pairs. The disposition type and attribute names will be defined in a future standards-track revision to [DISPOSITION]. ๐ŸŒธ
  • body language A string or parenthesized list giving the body language value as defined in [LANGUAGE-TAGS].

Any following extension data isn't defined yet in this version of the protocol. That extension data can be zero or more NILs, strings, numbers, or potentially nested parenthesized lists of that stuff. Client implementations that do a BODYSTRUCTURE fetch MUST be prepared to accept such extension data. Server implementations MUST NOT send such extension data until it has been defined by a revision of this protocol. ๐Ÿ™ˆ

The basic fields of a non-multipart body part come in the following order:

  • body type A string giving the content media type name as defined in [MIME-IMB].
  • body subtype A string giving the content subtype name as defined in [MIME-IMB].
  • body parameter parenthesized list A parenthesized list of attribute/value pairs, like ("foo" "bar" "baz" "rag") where "bar" is the value of "foo" and "rag" is the value of "baz", as defined in [MIME-IMB].
  • body id A string giving the content id as defined in [MIME-IMB].
  • body description A string giving the content description as defined in [MIME-IMB].
  • body encoding A string giving the content transfer encoding as defined in [MIME-IMB].
  • body size A number giving the size of the body in octets. This size is the size in its transfer encoding, not the resulting size after any decoding. ๐Ÿ“

A body type of type MESSAGE and subtype RFC822 contains, right after the basic fields, the envelope structure, body structure, and size in text lines of the encapsulated message.

A body type of type TEXT contains, right after the basic fields, the size of the body in text lines. This size is the size in its content transfer encoding, not the resulting size after any decoding. โœจ

Extension data follows the basic fields and the type-specific fields listed above. Extension data is never returned with the BODY fetch, but it can be returned with a BODYSTRUCTURE fetch. Extension data, if present, MUST be in the defined order.

The extension data of a non-multipart body part comes in the following order:

  • body MD5 A string giving the body MD5 value as defined in [MD5].
  • body disposition A parenthesized list with the same content and function as the body disposition for a multipart body part.
  • body language A string or parenthesized list giving the body language value as defined in [LANGUAGE-TAGS].

Any following extension data isn't defined yet in this version of the protocol, and it works the same way as the multipart extension data described above. ๐Ÿ’œ

  • ENVELOPE ๐Ÿ’… A parenthesized list that describes the envelope structure of a message. The server computes it by parsing the [RFC-822] header into its component parts, filling in defaults for various fields as needed.

The fields of the envelope structure come in the following order: date, subject, from, sender, reply-to, to, cc, bcc, in-reply-to, and message-id. The date, subject, in-reply-to, and message-id fields are strings. The from, sender, reply-to, to, cc, and bcc fields are parenthesized lists of address structures.

An address structure is a parenthesized list that describes an electronic mail address. Its fields come in the following order: personal name, [SMTP] at-domain-list (source route), mailbox name, and host name. ๐Ÿ“ฎ

[RFC-822] group syntax is shown by a special form of address structure where the host name field is NIL. If the mailbox name field is also NIL, that's an end of group marker (semi-colon in RFC 822 syntax). If the mailbox name field is non-NIL, that's a start of group marker, and the mailbox name field holds the group name phrase. ๐Ÿงš

Any field of an envelope or address structure that doesn't apply is presented as NIL. The server MUST default the reply-to and sender fields from the from field; a client isn't expected to know to do this. Main character energy from the server. ๐Ÿ”ฅ

  • FLAGS ๐ŸŒˆ A parenthesized list of flags that are set for this message.
  • INTERNALDATE A string representing the internal date of the message.
  • RFC822 Equivalent to BODY[].
  • RFC822.HEADER Equivalent to BODY.PEEK[HEADER].
  • RFC822.SIZE A number expressing the [RFC-822] size of the message.
  • RFC822.TEXT Equivalent to BODY[TEXT].
  • UID A number expressing the unique identifier of the message.

Example:

S: * 23 FETCH (FLAGS (\Seen) RFC822.SIZE 44827)

7.5. Server Responses - Command Continuation Request ๐Ÿฆ‹

The command continuation request response is shown by a "+" token instead of a tag. This response means the server is ready to accept the client's continuation of a command. The rest of this response is a line of text. ๐ŸŒธ

This response is used in the AUTHORIZATION command to send server data to the client and ask for more client data. It's also used when any command argument is a literal. ๐Ÿ’–

The client is not permitted to send the octets of the literal unless the server says it expects them. This lets the server process commands and reject errors on a line-by-line basis. The rest of the command, including the CRLF that ends a command, follows the octets of the literal. If there are any more command arguments, the literal octets are followed by a space and those arguments. ๐Ÿ™Œ

Example:

C: A001 LOGIN {11}
S: + Ready for additional command text
C: FRED FOOBAR {7}
S: + Ready for additional command text
C: fat man
S: A001 OK LOGIN completed
C: A044 BLURDYBLOOP {102856}
S: A044 BAD No such command as "BLURDYBLOOP"

8. Sample IMAP4rev1 connection ๐ŸŽ€

The following is a transcript of an IMAP4rev1 connection. A long line in this sample is broken up for editorial clarity. ๐ŸŒŸ

8. Sample IMAP4rev1 connection โœจ

okay so here's a whole conversation from start to finish ๐ŸŽ€ the C: lines are the client talking and the S: lines are the server answering. every command gets a tag like a001, and the server's reply uses the same tag so you can match them up ๐Ÿ’…

S:   * OK IMAP4rev1 Service Ready
C:   a001 login mrc secret
S:   a001 OK LOGIN completed
C:   a002 select inbox
S:   * 18 EXISTS
S:   * FLAGS (\Answered \Flagged \Deleted \Seen \Draft)
S:   * 2 RECENT
S:   * OK [UNSEEN 17] Message 17 is the first unseen message
S:   * OK [UIDVALIDITY 3857529045] UIDs valid
S:   a002 OK [READ-WRITE] SELECT completed
C:   a003 fetch 12 full
S:   * 12 FETCH (FLAGS (\Seen) INTERNALDATE "17-Jul-1996 02:44:25 -0700"
      RFC822.SIZE 4286 ENVELOPE ("Wed, 17 Jul 1996 02:23:25 -0700 (PDT)"
      "IMAP4rev1 WG mtg summary and minutes"
      (("Terry Gray" NIL "gray" "cac.washington.edu"))
      (("Terry Gray" NIL "gray" "cac.washington.edu"))
      (("Terry Gray" NIL "gray" "cac.washington.edu"))
      ((NIL NIL "imap" "cac.washington.edu"))
      ((NIL NIL "minutes" "CNRI.Reston.VA.US")
      ("John Klensin" NIL "KLENSIN" "INFOODS.MIT.EDU")) NIL NIL
      "<B27397-0100000@cac.washington.edu>")
       BODY ("TEXT" "PLAIN" ("CHARSET" "US-ASCII") NIL NIL "7BIT" 3028 92))
S:    a003 OK FETCH completed
C:    a004 fetch 12 body[header]
S:    * 12 FETCH (BODY[HEADER] {350}
S:    Date: Wed, 17 Jul 1996 02:23:25 -0700 (PDT)
S:    From: Terry Gray <gray@cac.washington.edu>
S:    Subject: IMAP4rev1 WG mtg summary and minutes
S:    To: imap@cac.washington.edu
S:    cc: minutes@CNRI.Reston.VA.US, John Klensin <KLENSIN@INFOODS.MIT.EDU>
S:    Message-Id: <B27397-0100000@cac.washington.edu>
S:    MIME-Version: 1.0
S:    Content-Type: TEXT/PLAIN; CHARSET=US-ASCII
S:
S:    )
S:    a004 OK FETCH completed
C:    a005 store 12 +flags \deleted
S:    * 12 FETCH (FLAGS (\Seen \Deleted))
S:    a005 OK +FLAGS completed
C:    a006 logout
S:    * BYE IMAP4rev1 server terminating connection
S:    a006 OK LOGOUT completed

9. Formal Syntax โœจ

okay bestie, the grammar is written in augmented BNF from [RFC-822], with ONE twist: the # construct uses a single space (SPACE) as its delimiter instead of one or more commas ๐Ÿงš

when two rules overlap and a later one could match the same text as an earlier one, the rule that's listed earlier MUST take priority ๐Ÿ’œ for example, "\Seen" parsed as a flag is the \Seen flag name and not a flag_extension, even though it could be parsed as a flag_extension. not every overlap is called out below, so keep this in mind ๐Ÿ™ˆ

alphabetic characters are case-insensitive unless the grammar says otherwise, and using upper or lower case to write token strings is just for editorial clarity ๐Ÿ’… implementations MUST accept these strings in a case-insensitive fashion ๐Ÿซถ

address         ::= "(" addr_name SPACE addr_adl SPACE addr_mailbox
                    SPACE addr_host ")"

addr_adl        ::= nstring
                    ;; Holds route from [RFC-822] route-addr if
                    ;; non-NIL

addr_host       ::= nstring
                    ;; NIL indicates [RFC-822] group syntax.
                    ;; Otherwise, holds [RFC-822] domain name

addr_mailbox    ::= nstring
                    ;; NIL indicates end of [RFC-822] group; if
                    ;; non-NIL and addr_host is NIL, holds
                    ;; [RFC-822] group name.
                    ;; Otherwise, holds [RFC-822] local-part

addr_name       ::= nstring
                    ;; Holds phrase from [RFC-822] mailbox if
                    ;; non-NIL

alpha           ::= "A" / "B" / "C" / "D" / "E" / "F" / "G" / "H" /
                    "I" / "J" / "K" / "L" / "M" / "N" / "O" / "P" /
                    "Q" / "R" / "S" / "T" / "U" / "V" / "W" / "X" /
                    "Y" / "Z" /
                    "a" / "b" / "c" / "d" / "e" / "f" / "g" / "h" /
                    "i" / "j" / "k" / "l" / "m" / "n" / "o" / "p" /
                    "q" / "r" / "s" / "t" / "u" / "v" / "w" / "x" /
                    "y" / "z"
                    ;; Case-sensitive

append          ::= "APPEND" SPACE mailbox [SPACE flag_list]
                    [SPACE date_time] SPACE literal

astring         ::= atom / string

atom            ::= 1*ATOM_CHAR

ATOM_CHAR       ::= <any CHAR except atom_specials>

atom_specials   ::= "(" / ")" / "{" / SPACE / CTL / list_wildcards /
                    quoted_specials

authenticate    ::= "AUTHENTICATE" SPACE auth_type *(CRLF base64)

auth_type       ::= atom
                    ;; Defined by [IMAP-AUTH]

base64          ::= *(4base64_char) [base64_terminal]

base64_char     ::= alpha / digit / "+" / "/"

base64_terminal ::= (2base64_char "==") / (3base64_char "=")

body            ::= "(" body_type_1part / body_type_mpart ")"

body_extension  ::= nstring / number / "(" 1#body_extension ")"
                    ;; Future expansion.  Client implementations
                    ;; MUST accept body_extension fields.  Server
                    ;; implementations MUST NOT generate
                    ;; body_extension fields except as defined by
                    ;; future standard or standards-track
                    ;; revisions of this specification.

body_ext_1part  ::= body_fld_md5 [SPACE body_fld_dsp
                    [SPACE body_fld_lang
                    [SPACE 1#body_extension]]]
                    ;; MUST NOT be returned on non-extensible
                    ;; "BODY" fetch

body_ext_mpart  ::= body_fld_param
                    [SPACE body_fld_dsp SPACE body_fld_lang
                    [SPACE 1#body_extension]]
                    ;; MUST NOT be returned on non-extensible
                    ;; "BODY" fetch

body_fields     ::= body_fld_param SPACE body_fld_id SPACE
                    body_fld_desc SPACE body_fld_enc SPACE
                    body_fld_octets

body_fld_desc   ::= nstring

body_fld_dsp    ::= "(" string SPACE body_fld_param ")" / nil

body_fld_enc    ::= (<"> ("7BIT" / "8BIT" / "BINARY" / "BASE64"/
                    "QUOTED-PRINTABLE") <">) / string

body_fld_id     ::= nstring

body_fld_lang   ::= nstring / "(" 1#string ")"
body_fld_lines  ::= number

body_fld_md5    ::= nstring

body_fld_octets ::= number

body_fld_param  ::= "(" 1#(string SPACE string) ")" / nil

body_type_1part ::= (body_type_basic / body_type_msg / body_type_text)
                    [SPACE body_ext_1part]

body_type_basic ::= media_basic SPACE body_fields
                    ;; MESSAGE subtype MUST NOT be "RFC822"

body_type_mpart ::= 1*body SPACE media_subtype
                    [SPACE body_ext_mpart]

body_type_msg   ::= media_message SPACE body_fields SPACE envelope
                    SPACE body SPACE body_fld_lines

body_type_text  ::= media_text SPACE body_fields SPACE body_fld_lines

capability      ::= "AUTH=" auth_type / atom
                    ;; New capabilities MUST begin with "X" or be
                    ;; registered with IANA as standard or
                    ;; standards-track

capability_data ::= "CAPABILITY" SPACE [1#capability SPACE] "IMAP4rev1"
                    [SPACE 1#capability]
                    ;; IMAP4rev1 servers which offer RFC 1730
                    ;; compatibility MUST list "IMAP4" as the first
                    ;; capability.

CHAR            ::= <any 7-bit US-ASCII character except NUL,
                     0x01 - 0x7f>

CHAR8           ::= <any 8-bit octet except NUL, 0x01 - 0xff>

command         ::= tag SPACE (command_any / command_auth /
                    command_nonauth / command_select) CRLF
                    ;; Modal based on state

command_any     ::= "CAPABILITY" / "LOGOUT" / "NOOP" / x_command
                    ;; Valid in all states

command_auth    ::= append / create / delete / examine / list / lsub /
                    rename / select / status / subscribe / unsubscribe
                    ;; Valid only in Authenticated or Selected state

command_nonauth ::= login / authenticate
                    ;; Valid only when in Non-Authenticated state

command_select  ::= "CHECK" / "CLOSE" / "EXPUNGE" /
                     copy / fetch / store / uid / search
                    ;; Valid only when in Selected state

continue_req    ::= "+" SPACE (resp_text / base64)

copy            ::= "COPY" SPACE set SPACE mailbox

CR              ::= <ASCII CR, carriage return, 0x0D>

create          ::= "CREATE" SPACE mailbox
                    ;; Use of INBOX gives a NO error

CRLF            ::= CR LF

CTL             ::= <any ASCII control character and DEL,
                        0x00 - 0x1f, 0x7f>

date            ::= date_text / <"> date_text <">

date_day        ::= 1*2digit
                    ;; Day of month

date_day_fixed  ::= (SPACE digit) / 2digit
                    ;; Fixed-format version of date_day

date_month      ::= "Jan" / "Feb" / "Mar" / "Apr" / "May" / "Jun" /
                    "Jul" / "Aug" / "Sep" / "Oct" / "Nov" / "Dec"

date_text       ::= date_day "-" date_month "-" date_year

date_year       ::= 4digit

date_time       ::= <"> date_day_fixed "-" date_month "-" date_year
                    SPACE time SPACE zone <">

delete          ::= "DELETE" SPACE mailbox
                    ;; Use of INBOX gives a NO error

digit           ::= "0" / digit_nz

digit_nz        ::= "1" / "2" / "3" / "4" / "5" / "6" / "7" / "8" /
                    "9"

envelope        ::= "(" env_date SPACE env_subject SPACE env_from
                    SPACE env_sender SPACE env_reply_to SPACE env_to
                    SPACE env_cc SPACE env_bcc SPACE env_in_reply_to
                    SPACE env_message_id ")"

env_bcc         ::= "(" 1*address ")" / nil

env_cc          ::= "(" 1*address ")" / nil

env_date        ::= nstring

env_from        ::= "(" 1*address ")" / nil

env_in_reply_to ::= nstring

env_message_id  ::= nstring

env_reply_to    ::= "(" 1*address ")" / nil

env_sender      ::= "(" 1*address ")" / nil

env_subject     ::= nstring

env_to          ::= "(" 1*address ")" / nil

examine         ::= "EXAMINE" SPACE mailbox

fetch           ::= "FETCH" SPACE set SPACE ("ALL" / "FULL" /
                    "FAST" / fetch_att / "(" 1#fetch_att ")")

fetch_att       ::= "ENVELOPE" / "FLAGS" / "INTERNALDATE" /
                    "RFC822" [".HEADER" / ".SIZE" / ".TEXT"] /
                    "BODY" ["STRUCTURE"] / "UID" /
                    "BODY" [".PEEK"] section
                    ["<" number "." nz_number ">"]

flag            ::= "\Answered" / "\Flagged" / "\Deleted" /
                    "\Seen" / "\Draft" / flag_keyword / flag_extension

flag_extension  ::= "\" atom
                    ;; Future expansion.  Client implementations
                    ;; MUST accept flag_extension flags.  Server
                    ;; implementations MUST NOT generate
                    ;; flag_extension flags except as defined by
                    ;; future standard or standards-track
                    ;; revisions of this specification.

flag_keyword    ::= atom
flag_list       ::= "(" #flag ")"

greeting        ::= "*" SPACE (resp_cond_auth / resp_cond_bye) CRLF

header_fld_name ::= astring

header_list     ::= "(" 1#header_fld_name ")"

LF              ::= <ASCII LF, line feed, 0x0A>

list            ::= "LIST" SPACE mailbox SPACE list_mailbox

list_mailbox    ::= 1*(ATOM_CHAR / list_wildcards) / string
list_wildcards  ::= "%" / "*"

literal         ::= "{" number "}" CRLF *CHAR8
                    ;; Number represents the number of CHAR8 octets

login           ::= "LOGIN" SPACE userid SPACE password

lsub            ::= "LSUB" SPACE mailbox SPACE list_mailbox

mailbox         ::= "INBOX" / astring
                    ;; INBOX is case-insensitive.  All case variants of
                    ;; INBOX (e.g. "iNbOx") MUST be interpreted as INBOX
                    ;; not as an astring.  Refer to section 5.1 for
                    ;; further semantic details of mailbox names.

mailbox_data    ::=  "FLAGS" SPACE flag_list /
                     "LIST" SPACE mailbox_list /
                     "LSUB" SPACE mailbox_list /
                     "MAILBOX" SPACE text /
                     "SEARCH" [SPACE 1#nz_number] /
                     "STATUS" SPACE mailbox SPACE
                     "(" #<status_att number ")" /
                     number SPACE "EXISTS" / number SPACE "RECENT"

mailbox_list    ::= "(" #("\Marked" / "\Noinferiors" /
                    "\Noselect" / "\Unmarked" / flag_extension) ")"
                    SPACE (<"> QUOTED_CHAR <"> / nil) SPACE mailbox

media_basic     ::= (<"> ("APPLICATION" / "AUDIO" / "IMAGE" /
                    "MESSAGE" / "VIDEO") <">) / string)
                    SPACE media_subtype
                    ;; Defined in [MIME-IMT]

media_message   ::= <"> "MESSAGE" <"> SPACE <"> "RFC822" <">

                    ;; Defined in [MIME-IMT]

media_subtype   ::= string
                    ;; Defined in [MIME-IMT]

media_text      ::= <"> "TEXT" <"> SPACE media_subtype
                    ;; Defined in [MIME-IMT]

message_data    ::= nz_number SPACE ("EXPUNGE" /
                                    ("FETCH" SPACE msg_att))

msg_att         ::= "(" 1#("ENVELOPE" SPACE envelope /
                    "FLAGS" SPACE "(" #(flag / "\Recent") ")" /
                    "INTERNALDATE" SPACE date_time /
                    "RFC822" [".HEADER" / ".TEXT"] SPACE nstring /
                    "RFC822.SIZE" SPACE number /
                    "BODY" ["STRUCTURE"] SPACE body /
                    "BODY" section ["<" number ">"] SPACE nstring /
                    "UID" SPACE uniqueid) ")"

nil             ::= "NIL"

nstring         ::= string / nil

number          ::= 1*digit
                    ;; Unsigned 32-bit integer
                    ;; (0 <= n < 4,294,967,296)

nz_number       ::= digit_nz *digit
                    ;; Non-zero unsigned 32-bit integer
                    ;; (0 < n < 4,294,967,296)

password        ::= astring

quoted          ::= <"> *QUOTED_CHAR <">

QUOTED_CHAR     ::= <any TEXT_CHAR except quoted_specials> /
                    "\" quoted_specials

quoted_specials ::= <"> / "\"

rename          ::= "RENAME" SPACE mailbox SPACE mailbox
                    ;; Use of INBOX as a destination gives a NO error

response        ::= *(continue_req / response_data) response_done

response_data   ::= "*" SPACE (resp_cond_state / resp_cond_bye /
                    mailbox_data / message_data / capability_data)
                    CRLF

response_done   ::= response_tagged / response_fatal

response_fatal  ::= "*" SPACE resp_cond_bye CRLF
                    ;; Server closes connection immediately

response_tagged ::= tag SPACE resp_cond_state CRLF

resp_cond_auth  ::= ("OK" / "PREAUTH") SPACE resp_text
                    ;; Authentication condition

resp_cond_bye   ::= "BYE" SPACE resp_text

resp_cond_state ::= ("OK" / "NO" / "BAD") SPACE resp_text
                    ;; Status condition

resp_text       ::= ["[" resp_text_code "]" SPACE] (text_mime2 / text)
                    ;; text SHOULD NOT begin with "[" or "="

resp_text_code  ::= "ALERT" / "PARSE" /
                    "PERMANENTFLAGS" SPACE "(" #(flag / "\*") ")" /
                    "READ-ONLY" / "READ-WRITE" / "TRYCREATE" /
                    "UIDVALIDITY" SPACE nz_number /
                    "UNSEEN" SPACE nz_number /
                    atom [SPACE 1*<any TEXT_CHAR except "]">]

search          ::= "SEARCH" SPACE ["CHARSET" SPACE astring SPACE]
                    1#search_key
                    ;; [CHARSET] MUST be registered with IANA

search_key      ::= "ALL" / "ANSWERED" / "BCC" SPACE astring /
                    "BEFORE" SPACE date / "BODY" SPACE astring /
                    "CC" SPACE astring / "DELETED" / "FLAGGED" /
                    "FROM" SPACE astring /
                    "KEYWORD" SPACE flag_keyword / "NEW" / "OLD" /
                    "ON" SPACE date / "RECENT" / "SEEN" /
                    "SINCE" SPACE date / "SUBJECT" SPACE astring /
                    "TEXT" SPACE astring / "TO" SPACE astring /
                    "UNANSWERED" / "UNDELETED" / "UNFLAGGED" /
                    "UNKEYWORD" SPACE flag_keyword / "UNSEEN" /
                    ;; Above this line were in [IMAP2]
                    "DRAFT" /
                    "HEADER" SPACE header_fld_name SPACE astring /
                    "LARGER" SPACE number / "NOT" SPACE search_key /
                    "OR" SPACE search_key SPACE search_key /
                    "SENTBEFORE" SPACE date / "SENTON" SPACE date /
                    "SENTSINCE" SPACE date / "SMALLER" SPACE number /
                    "UID" SPACE set / "UNDRAFT" / set /
                    "(" 1#search_key ")"

section         ::= "[" [section_text / (nz_number *["." nz_number]
                    ["." (section_text / "MIME")])] "]"

section_text    ::= "HEADER" / "HEADER.FIELDS" [".NOT"]
                    SPACE header_list / "TEXT"

select          ::= "SELECT" SPACE mailbox

sequence_num    ::= nz_number / "*"
                    ;; * is the largest number in use.  For message
                    ;; sequence numbers, it is the number of messages
                    ;; in the mailbox.  For unique identifiers, it is
                    ;; the unique identifier of the last message in
                    ;; the mailbox.

set             ::= sequence_num / (sequence_num ":" sequence_num) /
                    (set "," set)
                    ;; Identifies a set of messages.  For message
                    ;; sequence numbers, these are consecutive
                    ;; numbers from 1 to the number of messages in
                    ;; the mailbox
                    ;; Comma delimits individual numbers, colon
                    ;; delimits between two numbers inclusive.
                    ;; Example: 2,4:7,9,12:* is 2,4,5,6,7,9,12,13,
                    ;; 14,15 for a mailbox with 15 messages.

SPACE           ::= <ASCII SP, space, 0x20>

status          ::= "STATUS" SPACE mailbox SPACE "(" 1#status_att ")"

status_att      ::= "MESSAGES" / "RECENT" / "UIDNEXT" / "UIDVALIDITY" /
                    "UNSEEN"

store           ::= "STORE" SPACE set SPACE store_att_flags

store_att_flags ::= (["+" / "-"] "FLAGS" [".SILENT"]) SPACE
                    (flag_list / #flag)

string          ::= quoted / literal

subscribe       ::= "SUBSCRIBE" SPACE mailbox

tag             ::= 1*<any ATOM_CHAR except "+">

text            ::= 1*TEXT_CHAR
text_mime2       ::= "=?" <charset> "?" <encoding> "?"
                     <encoded-text> "?="
                     ;; Syntax defined in [MIME-HDRS]

TEXT_CHAR       ::= <any CHAR except CR and LF>

time            ::= 2digit ":" 2digit ":" 2digit
                    ;; Hours minutes seconds

uid             ::= "UID" SPACE (copy / fetch / search / store)
                    ;; Unique identifiers used instead of message
                    ;; sequence numbers

uniqueid        ::= nz_number
                    ;; Strictly ascending

unsubscribe     ::= "UNSUBSCRIBE" SPACE mailbox

userid          ::= astring

x_command       ::= "X" atom <experimental command arguments>

zone            ::= ("+" / "-") 4digit
                    ;; Signed four-digit value of hhmm representing
                    ;; hours and minutes west of Greenwich (that is,
                    ;; (the amount that the given time differs from
                    ;; Universal Time).  Subtracting the timezone
                    ;; from the given time will give the UT form.
                    ;; The Universal Time zone is "+0000".

10. Author's Note ๐Ÿ’–

okay so this whole document is a glow-up of older specs, and it literally supersedes them all ๐Ÿ’…โœจ the ones it replaces are RFC 1730, the unpublished IMAP2bis.TXT document, RFC 1176, and RFC 1064. bye bye, old drafts ๐Ÿซถ

11. Security Considerations ๐Ÿ”ฅ

bestie, this part is SERIOUS and i need you to hear me ๐Ÿ˜ญ๐Ÿ”’

IMAP4rev1 protocol transactions, including electronic mail data, are sent in the clear over the network unless privacy protection is negotiated in the AUTHENTICATE command. so yeah, your emails are basically postcards unless you negotiate privacy ๐Ÿ’€๐Ÿ“ฎ

a server error message for an AUTHENTICATE command that fails because of invalid credentials SHOULD NOT detail why the credentials are invalid. don't give the attacker a hint, periodt ๐Ÿ™ˆ

using the LOGIN command sends passwords in the clear ๐Ÿ˜ฌ you can avoid that by using the AUTHENTICATE command instead. main character move ๐Ÿ‘‘

a server error message for a failing LOGIN command SHOULD NOT specify that the user name, as opposed to the password, is invalid. again, no hints for the bad guys ๐Ÿฆ‹

there are additional security considerations discussed in the section about the AUTHENTICATE and LOGIN commands, so go read those too ๐Ÿงš

12. Author's Address ๐ŸŽ€

here's who to find if you need the author, fr fr ๐ŸŒธ

Mark R. Crispin
Networks and Distributed Computing
University of Washington
4545 15th Aveneue NE
Seattle, WA  98105-4527

Phone: (206) 543-5762

EMail: MRC@CAC.Washington.EDU

Appendices ๐ŸŒˆ

A. References โœจ

these are the docs this spec is built on, and yes, they're all worth a read ๐Ÿ“š๐Ÿ’œ

  • [ACAP] Myers, J. "ACAP -- Application Configuration Access Protocol", Work in Progress.
  • [CHARSET] Reynolds, J., and J. Postel, "Assigned Numbers", STD 2, RFC 1700, USC/Information Sciences Institute, October 1994.
  • [DISPOSITION] Troost, R., and Dorner, S., "Communicating Presentation Information in Internet Messages: The Content-Disposition Header", RFC 1806, June 1995.
  • [IMAP-AUTH] Myers, J., "IMAP4 Authentication Mechanism", RFC 1731. Carnegie-Mellon University, December 1994.
  • [IMAP-COMPAT] Crispin, M., "IMAP4 Compatibility with IMAP2bis", RFC 2061, University of Washington, November 1996.
  • [IMAP-DISC] Austein, R., "Synchronization Operations for Disconnected IMAP4 Clients", Work in Progress.
  • [IMAP-HISTORICAL] Crispin, M. "IMAP4 Compatibility with IMAP2 and IMAP2bis", RFC 1732, University of Washington, December 1994.
  • [IMAP-MODEL] Crispin, M., "Distributed Electronic Mail Models in IMAP4", RFC 1733, University of Washington, December 1994.
  • [IMAP-OBSOLETE] Crispin, M., "Internet Message Access Protocol - Obsolete Syntax", RFC 2062, University of Washington, November 1996.
  • [IMAP2] Crispin, M., "Interactive Mail Access Protocol - Version 2", RFC 1176, University of Washington, August 1990.
  • [LANGUAGE-TAGS] Alvestrand, H., "Tags for the Identification of Languages", RFC 1766, March 1995.
  • [MD5] Myers, J., and M. Rose, "The Content-MD5 Header Field", RFC 1864, October 1995.
  • [MIME-IMB] Freed, N., and N. Borenstein, "MIME (Multipurpose Internet Mail Extensions) Part One: Format of Internet Message Bodies", RFC 2045, November 1996.
  • [MIME-IMT] Freed, N., and N. Borenstein, "MIME (Multipurpose Internet Mail Extensions) Part Two: Media Types", RFC 2046, November 1996.
  • [MIME-HDRS] Moore, K., "MIME (Multipurpose Internet Mail Extensions) Part Three: Message Header Extensions for Non-ASCII Text", RFC 2047, November 1996.
  • [RFC-822] Crocker, D., "Standard for the Format of ARPA Internet Text Messages", STD 11, RFC 822, University of Delaware, August 1982.
  • [SMTP] Postel, J., "Simple Mail Transfer Protocol", STD 10, RFC 821, USC/Information Sciences Institute, August 1982.
  • [UTF-7] Goldsmith, D., and Davis, M., "UTF-7: A Mail-Safe Transformation Format of Unicode", RFC 1642, July 1994.

B. Changes from RFC 1730 ๐Ÿฆ‹

here's what changed since RFC 1730, bestie ๐Ÿ“

  1. The STATUS command has been added. ๐Ÿ’œ
  2. Clarify in the formal syntax that the "#" construct can never refer to multiple spaces. ๐Ÿซถ
  3. Obsolete syntax has been moved to a separate document. ๐Ÿงš
  4. The PARTIAL command has been obsoleted. ๐Ÿ˜ญ
  5. okay bestie, the RFC822.HEADER.LINES, RFC822.HEADER.LINES.NOT, RFC822.PEEK, and RFC822.TEXT.PEEK fetch attributes have been obsoleted ๐Ÿฅ€ they're officially retired from the group chat ๐Ÿ’€
  6. the "<" origin "." size ">" suffix for BODY text attributes has been added โœจ so cute, origin and size all in one little suffix ๐ŸŽ€
  7. the HEADER, HEADER.FIELDS, HEADER.FIELDS.NOT, MIME, and TEXT part specifiers have been added ๐Ÿงš
  8. support for Content-Disposition and Content-Language has been added ๐Ÿ’…
  9. the restriction on fetching nested MULTIPART parts has been removed ๐Ÿ™Œ no more gatekeeping, periodt
  10. body part number 0 has been obsoleted ๐Ÿฅ€
  11. server-supported authenticators are now identified by capabilities ๐Ÿ”
  12. the capability that identifies this protocol is now called "IMAP4rev1" ๐Ÿ‘‘ A server that provides backwards support for RFC 1730 SHOULD emit the "IMAP4" capability in addition to "IMAP4rev1" in its CAPABILITY response. Because RFC-1730 required "IMAP4" to appear as the first capability, it MUST be listed first in the response ๐Ÿซถ
  13. a description of the mailbox name namespace convention has been added ๐Ÿ“‚
  14. a description of the international mailbox name convention has been added ๐ŸŒ
  15. the UID-NEXT and UID-VALIDITY status items are now called UIDNEXT and UIDVALIDITY ๐Ÿ“ This is a change from the IMAP STATUS Work in Progress and not from RFC-1730, so it's not a RFC-1730 thing, it's a STATUS draft thing ๐Ÿฆ‹
  16. add a clarification that a null mailbox name argument to the LIST command returns an untagged LIST response with the hierarchy delimiter and root of the reference argument ๐Ÿ“
  17. define terms such as "MUST", "SHOULD", and "MUST NOT" ๐Ÿ“š the key words finally get their own definitions, iconic โœจ
  18. add a section which defines message attributes and more thoroughly details the semantics of message sequence numbers, UIDs, and flags ๐Ÿ”ฅ main character energy for this section ๐Ÿ‘‘
  19. add a clarification detailing the circumstances when a client may send multiple commands without waiting for a response, and the circumstances in which ambiguities may result ๐ŸŒธ
  20. add a recommendation on server behavior for DELETE and RENAME when inferior hierarchical names of the given name exist ๐Ÿ“
  21. add a clarification that a mailbox name may not be unilaterally unsubscribed by the server, even if that mailbox name no longer exists ๐Ÿซถ the server can't just unsubscribe you on its own, no cap ๐Ÿ™…โ€โ™€๏ธ
  22. add a clarification that LIST should return its results quickly without undue delay ๐Ÿงšโ€โ™€๏ธ
  23. add a clarification that the date_time argument to APPEND sets the internal date of the message ๐Ÿ•ฐ๏ธ
  24. add a clarification on APPEND behavior when the target mailbox is the currently selected mailbox ๐ŸŽ€
  25. add a clarification that external changes to flags should be always announced via an untagged FETCH even if the current command is a STORE with the ".SILENT" suffix ๐Ÿ’œ even with .SILENT, the flag changes still get announced, bestie ๐Ÿ“ฃ
  26. add a clarification that COPY appends to the target mailbox โœจ
  27. add the NEWNAME response code ๐Ÿงš
  28. rewrite the description of the untagged BYE response to clarify its semantics ๐Ÿ‘‘
  29. change the reference for the body MD5 to refer to the proper RFC ๐Ÿ’–
  30. clarify that the formal syntax contains rules which may overlap, and that in the event of such an overlap the rule which occurs first takes precedence ๐Ÿ“œ
  31. correct the definition of body_fld_param ๐Ÿ”ง
  32. more formal syntax for capability_data ๐ŸŒˆ
  33. clarify that any case variant of "INBOX" must be interpreted as INBOX ๐Ÿ’…
  34. clarify that the human-readable text in resp_text should not begin with "[" or "=" ๐Ÿ™ˆ
  35. change MIME references to Draft Standard documents ๐ŸŽ€
  36. clarify \Recent semantics ๐Ÿ’€ and that's the whole changelog, iykyk ๐Ÿฆ‹
  37. Additional examples. ๐ŸŽ€ And that's the very last change on the list, bestie ๐Ÿ˜ญโœจ

C. Key Word Index ๐Ÿ”Ž๐Ÿ’…

Okay so this is the cheat sheet, the place where every command, response, flag, search key and fetch item is listed next to the page it lives on ๐Ÿงš Use it like a lookup table and you'll never get lost again ๐Ÿฆ‹

       +FLAGS <flag list> (store command data item) ...............   45
       +FLAGS.SILENT <flag list> (store command data item) ........   46
       -FLAGS <flag list> (store command data item) ...............   46
       -FLAGS.SILENT <flag list> (store command data item) ........   46
       ALERT (response code) ......................................   50
       ALL (fetch item) ...........................................   41
       ALL (search key) ...........................................   38
       ANSWERED (search key) ......................................   38
       APPEND (command) ...........................................   34
       AUTHENTICATE (command) .....................................   20
       BAD (response) .............................................   52
       BCC <string> (search key) ..................................   38
       BEFORE <date> (search key) .................................   39
       BODY (fetch item) ..........................................   41
       BODY (fetch result) ........................................   58
       BODY <string> (search key) .................................   39
       BODY.PEEK[<section>]<<partial>> (fetch item) ...............   44
       BODYSTRUCTURE (fetch item) .................................   44
       BODYSTRUCTURE (fetch result) ...............................   59
       BODY[<section>]<<origin_octet>> (fetch result) .............   58
       BODY[<section>]<<partial>> (fetch item) ....................   41
       BYE (response) .............................................   52
       Body Structure (message attribute) .........................   11
       CAPABILITY (command) .......................................   18
       CAPABILITY (response) ......................................   53
       CC <string> (search key) ..................................   39
       CHECK (command) ............................................   36
       CLOSE (command) ............................................   36
       COPY (command) .............................................   46
       CREATE (command) ...........................................   25
       DELETE (command) ...........................................   26
       DELETED (search key) .......................................   39
       DRAFT (search key) .........................................   39
       ENVELOPE (fetch item) ......................................   44
       ENVELOPE (fetch result) ....................................   62
       EXAMINE (command) ..........................................   24
       EXISTS (response) ..........................................   56
       EXPUNGE (command) ..........................................   37
       EXPUNGE (response) .........................................   57
       Envelope Structure (message attribute) .....................   11
       FAST (fetch item) ..........................................   44
       FETCH (command) ............................................   41
       FETCH (response) ...........................................   58
       FLAGGED (search key) .......................................   39
       FLAGS (fetch item) .........................................   44
       FLAGS (fetch result) .......................................   62
       FLAGS (response) ...........................................   56
       FLAGS <flag list> (store command data item) ................   45
       FLAGS.SILENT <flag list> (store command data item) .........   45
       FROM <string> (search key) .................................   39
       FULL (fetch item) ..........................................   44
       Flags (message attribute) ..................................    9
       HEADER (part specifier) ....................................   41
       HEADER <field-name> <string> (search key) ..................   39
       HEADER.FIELDS <header_list> (part specifier) ...............   41
       HEADER.FIELDS.NOT <header_list> (part specifier) ...........   41
       INTERNALDATE (fetch item) ..................................   44
       INTERNALDATE (fetch result) ................................   62
       Internal Date (message attribute) ..........................   10
       KEYWORD <flag> (search key) ................................   39
       Keyword (type of flag) .....................................   10
       LARGER <n> (search key) ....................................   39
       LIST (command) .............................................   30
       LIST (response) ............................................   54
       LOGIN (command) ............................................   22
       LOGOUT (command) ...........................................   20
       LSUB (command) .............................................   32
       LSUB (response) ............................................   55
       MAY (specification requirement term) .......................    5
       MESSAGES (status item) .....................................   33
       MIME (part specifier) ......................................   42
       MUST (specification requirement term) ......................    4
       MUST NOT (specification requirement term) ..................    4
       Message Sequence Number (message attribute) ................    9
       NEW (search key) ...........................................   39
       NEWNAME (response code) ....................................   50
       NO (response) ..............................................   51
       NOOP (command) .............................................   19
       NOT <search-key> (search key) ..............................   39
       OK (response) ..............................................   51
       OLD (search key) ...........................................   39
       ON <date> (search key) .....................................   39
       OPTIONAL (specification requirement term) ..................    5
       OR <search-key1> <search-key2> (search key) ................   39
       PARSE (response code) ......................................   50
       PERMANENTFLAGS (response code) .............................   50
       PREAUTH (response) .........................................   52
       Permanent Flag (class of flag) .............................   10
       READ-ONLY (response code) ..................................   50
       READ-WRITE (response code) .................................   50
       RECENT (response) ..........................................   57
       RECENT (search key) ........................................   39
       RECENT (status item) .......................................   33
       RENAME (command) ...........................................   27
       REQUIRED (specification requirement term) ..................    4
       RFC822 (fetch item) ........................................   44
       RFC822 (fetch result) ......................................   63
       RFC822.HEADER (fetch item) .................................   44
       RFC822.HEADER (fetch result) ...............................   62
       RFC822.SIZE (fetch item) ...................................   44
       RFC822.SIZE (fetch result) .................................   62
       RFC822.TEXT (fetch item) ...................................   44
       RFC822.TEXT (fetch result) .................................   62
       SEARCH (command) ...........................................   37
       SEARCH (response) ..........................................   55
       SEEN (search key) ..........................................   40
       SELECT (command) ...........................................   23
       SENTBEFORE <date> (search key) .............................   40
       SENTON <date> (search key) .................................   40
       SENTSINCE <date> (search key) ..............................   40
       SHOULD (specification requirement term) ....................    5
       SHOULD NOT (specification requirement term) ................    5
       SINCE <date> (search key) ..................................   40
       SMALLER <n> (search key) ...................................   40
       STATUS (command) ...........................................   33
       STATUS (response) ..........................................   55
       STORE (command) ............................................   45
       SUBJECT <string> (search key) ..............................   40
       SUBSCRIBE (command) ........................................   29
       Session Flag (class of flag) ...............................   10
       System Flag (type of flag) .................................    9
       TEXT (part specifier) ......................................   42
       TEXT <string> (search key) .................................   40
       TO <string> (search key) ...................................   40
       TRYCREATE (response code) ..................................   51
       UID (command) ..............................................   47
       UID (fetch item) ...........................................   44
       UID (fetch result) .........................................   63
       UID <message set> (search key) .............................   40
       UIDNEXT (status item) ......................................   33
       UIDVALIDITY (response code) ................................   51
       UIDVALIDITY (status item) ..................................   34
       UNANSWERED (search key) ....................................   40
       UNDELETED (search key) .....................................   40
       UNDRAFT (search key) .......................................   40
       UNFLAGGED (search key) .....................................   40
       UNKEYWORD <flag> (search key) ..............................   40
       UNSEEN (response code) .....................................   51
       UNSEEN (search key) ........................................   40
       UNSEEN (status item) .......................................   34
       UNSUBSCRIBE (command) ......................................   30
       Unique Identifier (UID) (message attribute) ................    7
       X<atom> (command) ..........................................   48
       [RFC-822] Size (message attribute) .........................   11
       \Answered (system flag) ....................................    9
       \Deleted (system flag) .....................................    9
       \Draft (system flag) .......................................    9
       \Flagged (system flag) .....................................    9
       \Marked (mailbox name attribute) ...........................   54
       \Noinferiors (mailbox name attribute) ......................   54
       \Noselect (mailbox name attribute) .........................   54
       \Recent (system flag) ......................................   10
       \Seen (system flag) ........................................    9
       \Unmarked (mailbox name attribute) .........................   54

That's the whole thing, bestie! ๐ŸŒˆ๐Ÿ’– Every single entry, every page number, all tucked into the index โœจ๐Ÿ‘‘

๐Ÿ“ฆ where this page comes from