RFC 1730

Internet Message Access Protocol - Version 4

๐Ÿ“… published December 1994, from ietf

RFC 1730 ๐Ÿ’Œ Title Block Tea

  • Network Working Group ๐ŸŒธ (this is the group that put it out)
  • RFC number: 1730
  • Title: INTERNET MESSAGE ACCESS PROTOCOL - VERSION 4 ๐Ÿ“ฌ
  • Author: M. Crispin, University of Washington
  • Category: Standards Track โœจ
  • Date: December 1994
  • It doesn't say it obsoletes or updates anything, so there's no drama there ๐Ÿซถ

Status of this Memo ๐Ÿ“‹

Okay so this one is an Internet standards track protocol for the Internet community, and the authors are literally asking for discussion and suggestions for improvements ๐Ÿ—ฃ๏ธ If you want the current standardization state and status of this protocol, check the current edition of the "Internet Official Protocol Standards" (STD 1) ๐Ÿ“š Distribution of this memo is unlimited, so share it with your whole group chat ๐Ÿ’…

Abstract ๐Ÿฆ‹

IMAP4 (that's Internet Message Access Protocol, Version 4) lets a client access and manage email messages sitting on a server ๐Ÿ’– It treats remote folders, called "mailboxes", in a way that's functionally equivalent to local mailboxes, which is honestly so iconic ๐Ÿ‘‘ IMAP4 also gives an offline client a way to resynchronize with the server (see also [IMAP-DISC]) ๐Ÿ”„

It covers a whole list of moves: creating, deleting, and renaming mailboxes โœจ checking for new messages ๐Ÿ“ฉ permanently removing messages ๐Ÿ—‘๏ธ setting and clearing flags ๐Ÿšฉ RFC 822 and MIME parsing ๐Ÿงฉ searching ๐Ÿ” and selectively fetching message attributes, texts, and portions of them ๐ŸŽ€ Messages are accessed by numbers, and those numbers come in two flavors. Message sequence numbers are relative positions running from 1 up to the number of messages in the mailbox ๐Ÿ“ Unique identifiers are immutable, strictly ascending values given to each message, though they aren't necessarily contiguous ๐Ÿงš

IMAP4 supports a single server ๐Ÿ’œ A mechanism for supporting multiple IMAP4 servers is discussed in [IMSP]. IMAP4 doesn't cover posting mail, since that's handled by a mail transfer protocol like [SMTP] ๐Ÿ“ฎ Last but not least, IMAP4 is designed to be upwards compatible from the [IMAP2] protocol, and the compatibility issues are discussed in [IMAP-COMPAT] ๐Ÿซถ

Table of Contents ๐Ÿ“‘

IMAP4 Protocol Specification ......................................    1
1.      Organization of this Document .............................    1
1.1.    How to Read This Document .................................    1
1.2.    Conventions Used in this Document .........................    1
2.      Protocol Overview .........................................    1
2.1.    Link Level ................................................    1
2.2.    Commands and Responses ....................................    1
2.2.1.  Client Protocol Sender and Server Protocol Receiver .......    2
2.2.2.  Server Protocol Sender and Client Protocol Receiver .......    2
3.      State and Flow Diagram ....................................    4
3.1.    Non-Authenticated State ...................................    4
3.2.    Authenticated State .......................................    4
3.3.    Selected State ............................................    4
3.4.    Logout State ..............................................    4
4.      Data Formats ..............................................    6
4.1.    Atom ......................................................    6
4.2.    Number ....................................................    6
4.3.    String ....................................................    6
4.3.1.  8-bit and Binary Strings ..................................    7
4.4.    Parenthesized List ........................................    7
4.5.    NIL .......................................................    7
5.      Operational Considerations ................................    8
5.1.    Mailbox Naming ............................................    8
5.2.    Mailbox Size and Message Status Updates ...................    8
5.3.    Response when no Command in Progress ......................    8
5.4.    Autologout Timer ..........................................    9
5.5.    Multiple Commands in Progress .............................    9
6.      Client Commands ...........................................   10
6.1.    Client Commands - Any State ...............................   10
6.1.1.  CAPABILITY Command ........................................   10
6.1.2.  NOOP Command ..............................................   11
6.1.3.  LOGOUT Command ............................................   11
6.2.    Client Commands - Non-Authenticated State .................   12
6.2.1.  AUTHENTICATE Command ......................................   12
6.2.2.  LOGIN Command .............................................   14
6.3.    Client Commands - Authenticated State .....................   14
6.3.1.  SELECT Command ............................................   15
6.3.2.  EXAMINE Command ...........................................   16
6.3.3.  CREATE Command ............................................   17
6.3.4.  DELETE Command ............................................   18
6.3.5.  RENAME Command ............................................   18
6.3.6.  SUBSCRIBE Command .........................................   19
6.3.7.  UNSUBSCRIBE Command .......................................   19
6.3.8.  LIST Command ..............................................   20
6.3.9.  LSUB Command ..............................................   22
6.3.10. APPEND Command ............................................   22
6.4.    Client Commands - Selected State ..........................   23
6.4.1.  CHECK Command .............................................   23
6.4.2.  CLOSE Command .............................................   24
6.4.3.  EXPUNGE Command ...........................................   25
6.4.4.  SEARCH Command ............................................   25
6.4.5.  FETCH Command .............................................   29
6.4.6.  PARTIAL Command ...........................................   32
6.4.7.  STORE Command .............................................   33
6.4.8.  COPY Command ..............................................   34
6.4.9.  UID Command ...............................................   35
6.5.    Client Commands - Experimental/Expansion ..................   37
6.5.1.  X<atom> Command ...........................................   37
7.      Server Responses ..........................................   38
7.1.    Server Responses - Status Responses .......................   39
7.1.1.  OK Response ...............................................   40
7.1.2.  NO Response ...............................................   40
7.1.3.  BAD Response ..............................................   41
7.1.4.  PREAUTH Response ..........................................   41
7.1.5.  BYE Response ..............................................   41
7.2.    Server Responses - Server and Mailbox Status ..............   42
7.2.1.  CAPABILITY Response .......................................   42
7.2.2.  LIST Response .............................................   43
7.2.3.  LSUB Response .............................................   44
7.2.4.  SEARCH Response ...........................................   44
7.2.5.  FLAGS Response ............................................   44
7.3.    Server Responses - Message Status .........................   45
7.3.1.  EXISTS Response ...........................................   45
7.3.2.  RECENT Response ...........................................   45
7.3.3.  EXPUNGE Response ..........................................   45
7.3.4.  FETCH Response ............................................   46
7.3.5.  Obsolete Responses ........................................   51
7.4.    Server Responses - Command Continuation Request ...........   51
8.      Sample IMAP4 session ......................................   52
9.      Formal Syntax .............................................   53
10.     Author's Note .............................................   64
11.     Security Considerations ...................................   64
12.     Author's Address ..........................................   64
Appendices ........................................................   65
A.      Obsolete Commands .........................................   65
A.6.3.OBS.1.    FIND ALL.MAILBOXES Command ........................   65
A.6.3.OBS.2.    FIND MAILBOXES Command ............................   65
A.6.3.OBS.3.    SUBSCRIBE MAILBOX Command .........................   66
A.6.3.OBS.4.    UNSUBSCRIBE MAILBOX Command .......................   66
B.      Obsolete Responses ........................................   68
B.7.2.OBS.1.    MAILBOX Response ..................................   68
B.7.3.OBS.1.    COPY Response .....................................   68
B.7.3.OBS.2.    STORE Response ....................................   69
C.      References ................................................   70
E.      IMAP4 Keyword Index .......................................   71

IMAP4 Protocol Specification ๐Ÿง

1. Organization of this Document โœจ

1.1. How to Read This Document ๐Ÿ“–

This doc is written for the implementor of an IMAP4 client or server, so it's not really optimized for someone trying to understand how the protocol works. Beyond the protocol overview in section 2, the stuff in sections 3 through 5 gives you the general context and definitions IMAP4 runs on ๐Ÿง 

Sections 6, 7, and 9 cover the IMAP commands, responses, and syntax. They're so intertwined that it's almost impossible to understand any one of them on its own ๐Ÿ˜ญ 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 server, respectively ๐Ÿ’ฌ

2. Protocol Overview ๐ŸŒˆ

IMAP4 assumes a reliable data stream, like the one TCP gives you. When TCP is used, an IMAP4 server listens on port 143 ๐Ÿฆ‹

2.2. Commands and Responses ๐Ÿ’Œ

An IMAP4 session is made up of three things: setting up a client/server connection, an initial greeting from the server, and then client/server interactions ๐Ÿ‘ฏ Each interaction has a client command, server data, and a server completion result response โœจ

Everything the client and server send is a line, meaning a string that ends with a CRLF ๐Ÿ“ The protocol receiver on an IMAP4 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

okay so the client kicks off every operation with a command ๐Ÿ’– each command gets a tag ๐ŸŽ€, which is a short alphanumeric label the client makes up (like A0001, A0002, and so on). the client uses a different tag for every command.

there are two situations where a line from the client isn't a full command yet ๐Ÿ™ˆ. one is when a command argument is quoted with an octet count (check out literal under String in Data Formats). the other is when the command arguments need server feedback (see the AUTHENTICATE command). either way, if the server is ready for the octets (when that applies) and for the rest of the command, it sends a command continuation request response, which starts with the token + โœจ

Note: if the server spots an error in the command instead, it sends a BAD completion response with the matching tag (more on that below) to reject the command and stop 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 several are in progress), or untagged data ๐Ÿฆ‹ in either case, the command continuation request is still pending. the client deals with whatever came in and reads the next response from the server.

the protocol receiver of an IMAP4 server reads a command line from the client, parses the command and its arguments, and sends back server data and a server command completion result response ๐Ÿงš


2.2.2. Server Protocol Sender and Client Protocol Receiver

anything the server sends to the client as data, or any status response that doesn't mark a command as finished, starts with the token * ๐ŸŒธ these are called untagged responses.

server data can show up because of a client command, or the server can send it unilaterally ๐Ÿ’… there's no syntactic difference between server data that came from a specific command and server data that was sent on its own.

the server completion result response tells you if the operation worked or not ๐Ÿ‘‘ it carries the same tag as the client command that started the operation. so if more than one command is in progress, the tag tells you which command the response belongs to. there are three possible ones: OK (success), NO (failure), or BAD (protocol error, like an unrecognized command or a command syntax error) ๐Ÿ”ฅ

the protocol receiver of an IMAP4 client reads a response line from the server, then acts on it based on its first token, which might be a tag, a *, or a +, as described above ๐Ÿซถ

A client MUST be prepared to accept any server response at all times ๐Ÿ˜ค that includes server data it never asked for. server data SHOULD be recorded, so the client can reference its saved copy instead of sending a command to request the data again ๐Ÿง  for certain server data, recording it is mandatory ๐Ÿ’€

this topic gets a deeper dive in the Server Responses section ๐ŸŒˆ


3. State and Flow Diagram โœจ

an IMAP4 server is in one of four states ๐Ÿ“ most commands only work in certain states. if the client tries a command while the server is in a state where it doesn't belong, that's a protocol error ๐Ÿ™ˆ in that case, the server responds with a BAD or NO completion result, depending on the server implementation.


3.1. Non-Authenticated State

in non-authenticated state, the user has to supply authentication credentials before most commands are allowed ๐Ÿ” this state is entered when a connection starts, unless the connection has been pre-authenticated.


3.2. Authenticated State

in authenticated state, the user is authenticated and has to select a mailbox before commands that affect messages are allowed ๐Ÿ’Œ this state is entered when a pre-authenticated connection starts, when acceptable authentication credentials have been provided, or after an error in selecting a mailbox.


3.3. Selected State

in selected state, a mailbox has been selected to access ๐Ÿ“ฌ this state is entered when a mailbox has been successfully selected.


3.4. Logout State

in logout state, the session is being wrapped up and the server will close the connection ๐Ÿ‘‹ this can happen because the client asked for it, or because the server decided on its own. this state can be entered as a result of a client request or by unilateral server decision.

        +--------------------------------------+
        |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 ๐Ÿ’œ

IMAP4 uses textual commands and responses ๐Ÿ’ฌ data in IMAP4 can take one of several 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 form is an alternative that skips the overhead of processing a literal, but it comes with restrictions on what can go inside it.

a literal is zero or more octets (CR and LF included), prefixed 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 it sends the octet data and the remainder of the command โณ

a quoted string is zero or more 7-bit characters, excluding CR and LF, with double quote (<">) characters at each end ๐Ÿ’…

the empty string is represented as either "" (a quoted string with zero characters between 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 โœจ

okay so 8-bit textual and binary mail is totally supported, as long as it goes through [MIME-1] encoding ๐Ÿ’Œ. IMAP4 implementations MAY transmit 8-bit or multi-octet characters in literals, but they should do so only when the character set is identified ๐ŸŒธ.

now the binary part is where it gets serious ๐Ÿฅบ. Even though 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, although this is not required ๐Ÿค”.


4.4. Parenthesized List ๐ŸŽ€

data structures are represented as a "parenthesized list" ๐Ÿง: a sequence of data items, delimited by space, and bounded at each end by parentheses. A parenthesized list can contain other parenthesized lists too, using multiple levels of parentheses to show nesting. It's giving Russian doll energy ๐Ÿช†.

the empty list is written as (), a parenthesized list with no members ๐Ÿซง.


4.5. NIL ๐ŸŒ™

the special atom "NIL" means the non-existence of a particular data item that's represented as a string or parenthesized list. This is different from the empty string "" or the empty parenthesized list () ๐Ÿ™ˆ. Don't mix them up, bestie!


5. Operational Considerations ๐Ÿ’…

5.1. Mailbox Naming ๐Ÿ“ซ

the interpretation of mailbox names is implementation-dependent ๐Ÿคทโ€โ™€๏ธ. BUT the mailbox name INBOX is special and reserved to mean "the primary mailbox for this user on this server" ๐Ÿ‘‘. If you want to export hierarchical mailbox names, they must be left-to-right hierarchical, using a single character to separate levels of hierarchy ๐ŸŒณ. The same hierarchy separator character gets used for all levels within a single name, so no mixing it up ๐Ÿ™…โ€โ™€๏ธ.

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

at any time, a server can send data the client didn't request ๐Ÿ‘€. Sometimes that's required! For example, other agents besides the server might add messages to the mailbox (like new mail delivery), change the flags of messages (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 too, without the client needing to ask for them explicitly โœจ. There are special rules for telling the client about removed messages so nothing gets out of sync, so check the description of the EXPUNGE response for the full scoop ๐Ÿง.

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. Don't be that client ๐Ÿ’€.

5.3. Response when no Command in Progress โธ๏ธ

server implementations are permitted to send an untagged response (except for EXPUNGE) while there's no command in progress ๐Ÿซถ. Server implementations that send such responses MUST deal with flow control considerations. Specifically, they must either (1) verify that the size of the data doesn't exceed the underlying transport's available window size, or (2) use non-blocking writes ๐ŸŒŠ.

5.4. Autologout Timer โฐ

if a server has an inactivity autologout timer, that timer MUST be of at least 30 minutes' duration โŒ›. 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 doesn't have to wait for the completion result response of a command before sending another one, as long as it's within the flow control limits of the underlying data stream ๐ŸŒˆ. Likewise, a server doesn't have to finish processing one command before starting the next, UNLESS an ambiguity would result because a command would affect the results of other commands ๐Ÿ™ƒ. If there's an ambiguity like that, the server executes commands to completion in the order the client gave them ๐Ÿง .


6. Client Commands ๐Ÿฆ‹

IMAP4 commands are described in this section, organized by the state in which they're permitted ๐Ÿ—‚๏ธ. Commands permitted in multiple states are listed in the minimum permitted state (for example, commands valid in authenticated and selected state are listed in the authenticated state commands) โœจ.

Command arguments, marked "Arguments:" in the command descriptions below, are described by function, not by syntax. The precise syntax of command arguments is in the Formal Syntax section ๐Ÿ“.

Some commands cause specific server data to be returned. These are marked "Data:" below. See the response descriptions in the Responses section for info on them, and the Formal Syntax section for their exact syntax. Server data can be transmitted as a result of any command, which is why commands that don't specifically require server data say "no specific data 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 interpretation of those status responses ๐Ÿท๏ธ.


6.1. Client Commands - Any State ๐ŸŒธ

the following commands are valid in any state: CAPABILITY, NOOP, and LOGOUT ๐Ÿ’œ.

6.1.1. CAPABILITY Command ๐Ÿงฉ

Arguments:  none

Data:       mandatory untagged response: CAPABILITY

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

the CAPABILITY command requests a listing of the capabilities the server supports ๐Ÿ“‹. The server MUST send a single untagged CAPABILITY response with "IMAP4" as the first listed capability before the (tagged) OK response ๐Ÿฅ‡. This listing isn't dependent on connection state or user, so there's no need to issue a CAPABILITY command more than once in a session ๐Ÿ™Œ.

Capability names other than "IMAP4" refer to extensions, revisions, or amendments to this specification. See the documentation of the CAPABILITY response for more info ๐Ÿ“š. No capabilities are enabled without the client explicitly invoking them ๐Ÿ”’. For info on the form of site or implementation-specific capabilities, see the section entitled "Client Commands - Experimental/Expansion" โœจ.

Example:

C: abcd CAPABILITY
S: * CAPABILITY IMAP4
S: abcd OK CAPABILITY completed

6.1.2. NOOP Command ๐Ÿ˜ด

Arguments:  none

Data:       no specific data for this command (but see below)

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

the NOOP command always succeeds, and it does nothing ๐Ÿซ . 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 period of inactivity ๐Ÿ”. 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

Data:       mandatory 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 session ๐Ÿซก. 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 IMAP4 Server logging out
S: A023 OK LOGOUT completed
(Server and client then close the connection)

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

in non-authenticated state, the AUTHENTICATE or LOGIN command establishes authentication and enters authenticated state ๐Ÿšช. AUTHENTICATE is a general mechanism for a variety of authentication techniques, whereas LOGIN uses the traditional 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, go on the password, and what access restrictions apply to anonymous users, is implementation-dependent ๐Ÿ•ต๏ธโ€โ™€๏ธ.

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

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

6.2.1. AUTHENTICATE Command โœจ

okay so AUTHENTICATE is how the client tells the server "bestie, I wanna log in with THIS mechanism" ๐Ÿ” Here's the spec at a glance:

Arguments:  authentication mechanism name

Data:       continuation data may 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

So AUTHENTICATE is the client saying which auth mechanism it wants, like the ones described in [IMAP-AUTH] ๐Ÿ’… If the server knows that mechanism, it runs an auth exchange to figure out who you are ๐Ÿชช It can optionally also negotiate a protection mechanism for everything after that ๐Ÿ›ก๏ธ If the mechanism isn't supported, the server should reject the command with a tagged NO response. hard pass ๐Ÿ’€

The back-and-forth is a bunch of server challenges and client answers, and they're specific to whichever mechanism you picked ๐Ÿงฉ A server challenge is a command continuation request response that starts with the + token, followed by a BASE64 encoded string. Your answer is a line that's just a BASE64 encoded string. Wanna bail mid-exchange? The client should issue a line with a single * in it ๐Ÿ™…โ€โ™€๏ธ If the server gets that *, it must reject the AUTHENTICATE command with a tagged BAD response. no notes ๐Ÿ’€

Now the protection mechanism, which is giving security main character energy ๐Ÿ”’ It provides integrity and privacy protection to the protocol session. If one gets negotiated, it's applied to all subsequent data sent over the connection. It kicks in right after the CRLF that wraps up the authentication exchange for the client, and right after the CRLF of the tagged OK response for the server โœจ From then on, the stream of command and response octets gets chopped into buffers of ciphertext ๐Ÿง Each buffer goes over the connection as a stream of octets with a four octet field in front of it, in network byte order, that tells you how long the data after it is. The maximum ciphertext buffer length is defined by the protection mechanism ๐Ÿ“

Last but not least, the server is not required to support any particular authentication mechanism, and mechanisms aren't required to support any protection mechanisms either ๐Ÿ™ƒ If an AUTHENTICATE command fails with a NO response, the client may try another authentication mechanism by sending another AUTHENTICATE command, or may just use the LOGIN command. In other words, the client can request auth types in decreasing order of preference, with LOGIN as a last resort ๐Ÿซถ

S: * OK KerberosV4 IMAP4 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: those line breaks in the first client answer are just for editorial clarity ๐Ÿ™ˆ Real authenticators don't have them.


6.2.2. LOGIN Command ๐Ÿ”‘

Here's the spec for LOGIN:

Arguments:  user name
            password

Data:       no specific data 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

LOGIN identifies the user to the server and carries the plaintext password that authenticates them, as the name suggests ๐Ÿ˜ฌ

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 ๐Ÿฆ‹

Besides the universal commands (CAPABILITY, NOOP, and LOGOUT), these are valid in authenticated state: SELECT, EXAMINE, CREATE, DELETE, RENAME, SUBSCRIBE, UNSUBSCRIBE, LIST, LSUB, and APPEND ๐Ÿ’œ

6.3.1. SELECT Command ๐Ÿ“ฌ

Arguments:  mailbox name

Data:       mandatory 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 opens a mailbox so you can get at the messages inside it ๐Ÿ“จ Before the server returns an OK to the client, it MUST send these untagged bits of data:

  • FLAGS: defined flags in the mailbox
  • <n> EXISTS: the number of messages in the mailbox
  • <n> RECENT: the number of messages added to the mailbox since the previous time this mailbox was read
  • OK [UIDVALIDITY <n>]: the unique identifier validity value. See the description of the UID command for more detail.

Together, those set the initial state of the mailbox at the client ๐Ÿง  If it's not possible to figure out which messages were added since the mailbox was last read, then all messages SHOULD be considered recent ๐Ÿ•ฐ๏ธ

The server SHOULD also send an UNSEEN response code in an OK untagged response, pointing 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 listed in the FLAGS untagged response, the server SHOULD send a PERMANENTFLAGS response code in an OK untagged response, listing the flags the client may change permanently ๐Ÿท๏ธ

Only one mailbox can be selected at a time in a session. If you want to access multiple mailboxes at once, you need multiple sessions ๐Ÿ™ƒ SELECT automatically deselects whatever mailbox is currently selected before it tries the new one. So if a mailbox is selected and a SELECT that fails gets attempted, no mailbox is selected anymore ๐Ÿ’€

If the user 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 user can't modify the mailbox but is permitted read access, the mailbox is selected as read-only, and the server MUST prefix the text of the tagged OK response to SELECT with the [READ-ONLY] response code ๐Ÿ“– Read-only access through SELECT is different from EXAMINE because certain read-only mailboxes may permit changes to permanent state on a per-user (as opposed to global) basis. Netnews messages marked in a user's .newsrc file are an example of that per-user permanent state, and it can be modified 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

Data:       mandatory 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 twin ๐Ÿ‘ฏโ€โ™€๏ธ It returns the same output, but the selected mailbox is marked as read-only. No changes to the permanent state of the mailbox are permitted, including per-user state ๐Ÿšซโœ๏ธ

The text of the tagged OK response to the EXAMINE command 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

Data:       no specific data 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 mailbox with the given name ๐ŸŒฑ You only get an OK back if a brand-new mailbox with that name was actually created. It's an error to try creating INBOX, or a mailbox whose name refers to an existing mailbox ๐Ÿ™…โ€โ™€๏ธ Any error during creation gets a tagged NO response ๐Ÿ’”

If the mailbox name ends with the server's hierarchy separator character (the one the server hands back from a LIST command), that's a heads-up that the client may create mailbox names under this one later on ๐ŸŒณ Server implementations that don't need that heads-up MUST ignore it ๐Ÿซง

If a new mailbox gets the same name as a mailbox that was 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 ๐Ÿ†” See 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: what this example means depends on whether / was returned as the hierarchy separator from LIST ๐ŸŒฒ If / is the hierarchy 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

Data: no specific data 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 giving permanent ๐Ÿ’€ It removes the mailbox with the given name for good. You only get a tagged OK back if the mailbox has actually been deleted. Trying to delete INBOX, or a name that doesn't exist, is an error, and any deletion error gets you a tagged NO response. no cap, read those carefully ๐Ÿซถ

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 identifiers of the old one, unless the new mailbox has a different unique identifier validity value. Check out the UID command section if you want the full tea on that ๐Ÿ‘€

Example:

C: A683 DELETE blurdybloop
S: A683 OK DELETE completed

6.3.5. RENAME Command ๐Ÿฆ‹

Arguments: existing mailbox name, new mailbox name

Data: no specific data 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 lets you change the name of a mailbox, and it's lowkey so satisfying โœจ A tagged OK comes back only if the rename actually happened. It's an error to rename from a name that doesn't exist, or to a name that already exists. Any renaming error returns a tagged NO response.

Renaming INBOX is permitted, and here's the iconic part: a brand new, empty INBOX gets created right in its place ๐ŸŒธ

Example:

C: Z4S9 RENAME blurdybloop owatagusiam
S: Z4S9 OK RENAME completed

6.3.6. SUBSCRIBE Command ๐ŸŽ€

Arguments: mailbox

Data: no specific data 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 you give it to the server's set of "active" or "subscribed" mailboxes, the same ones LSUB returns ๐Ÿ“ฌ You only get a tagged OK back if the subscription worked.

Example:

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

6.3.7. UNSUBSCRIBE Command ๐Ÿ“

Arguments: mailbox name

Data: no specific data for this command

Result:

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

UNSUBSCRIBE is the undo button for SUBSCRIBE ๐Ÿ™ˆ It removes the mailbox name from that same "active" or "subscribed" set that LSUB reports on. A tagged OK only comes back if the unsubscription went through.

Example:

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

6.3.8. LIST Command ๐Ÿ”โœจ

Arguments: reference name, mailbox name with possible wildcards

Data: untagged responses: LIST

Result:

  • OK - list completed
  • NO - list failure: can't list that reference or name
  • BAD - command unknown or arguments invalid

LIST gives you a subset of the names the user can see, out of the full set of everything available ๐Ÿ’œ You get zero or more untagged LIST replies back. Each one has the name attributes, the hierarchy delimiter, and the name. Check the LIST reply section for the deep dive.

An empty "" reference name means the mailbox name gets interpreted the same way SELECT would interpret it. The returned mailbox names MUST match the mailbox name pattern you supplied. A non-empty reference name is a mailbox, or a level of mailbox hierarchy, and it sets up a context where the mailbox name gets interpreted in an implementation-defined way. implementation-defined = the server decides, and it's not my place to spill that tea ๐Ÿคซ

The reference and mailbox name get interpreted, in an implementation-dependent way, into a canonical form that shows an unambiguous left-to-right hierarchy. The returned mailbox names come back 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 name is inside the reference's context, 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's 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. Notice that "~smith/Mail" should not get turned into something like "/u2/users/smith/Mail", because then the client would have no way to tell that the interpretation was in the context of the reference ๐Ÿฅบ

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

Server implementations are allowed to "hide" mailboxes that are otherwise accessible from the wildcard characters, by stopping 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 it matches the input arguments and INBOX is supported by this server for this user. The only thing that decides whether INBOX gets omitted is whether SELECT INBOX would return failure. Whether the user's real INBOX lives on this server or somewhere else doesn't matter at all ๐Ÿ“ฅ

Example:

C: A002 LIST "~/Mail/" "%"
S: * LIST (\Noselect) "/" ~/Mail/foo
S: * LIST () "/" ~/Mail/meetings
S: A002 OK LIST completed

6.3.9. LSUB Command ๐Ÿ’Œ

Arguments: reference name, mailbox name with possible wildcards

Data: untagged responses: LSUB

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" ๐Ÿซง You get zero or more untagged LSUB replies back. The arguments to LSUB are in the same form as the ones for LIST, so if you know LIST, you already know LSUB.

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. APPEND Command ๐Ÿ“ฉโœจ

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

Data: no specific data 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

APPEND adds the literal argument as a new message in the mailbox you pick ๐Ÿ’… That literal has to be in the format of an [RFC-822] message. 8-bit characters are allowed in the message. A server that can't keep 8-bit data intact MUST be able to reversibly convert 8-bit APPEND data to 7-bit using [MIME-1] encoding. Very careful, very important ๐Ÿ”ฅ

If you specify a flag parenthesized list or a date_time, that data SHOULD be set on the resulting message. If you don't, the defaults are empty flags and the current date/time.

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. If the mailbox is currently selected, the normal new mail actions should occur ๐Ÿ“ฌ

If the destination mailbox doesn't exist, a server MUST return an error, and MUST NOT automatically create the mailbox. Unless it's certain that the destination mailbox cannot be created, the server MUST send the response code [TRYCREATE] as the prefix of the text in the tagged NO response. That's a little hint for the client that it can try a CREATE command and then retry the APPEND if the CREATE works ๐Ÿงš

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 doesn't give you a way to transfer [SMTP] envelope information. Don't use it as your mail delivery method, bestie ๐Ÿ™…โ€โ™€๏ธ

6.4. Client Commands - Selected State ๐ŸŒธ

In the selected state, commands that manipulate messages in a mailbox are permitted ๐Ÿงšโ€โ™€๏ธ

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

6.4.1. CHECK Command โœจ

Arguments:  none

Data:       no specific data for this command

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

Okay so, CHECK is basically asking the server for a checkpoint on the mailbox you've got selected ๐Ÿงš. A checkpoint is any implementation-dependent housekeeping the server does for the mailbox (like syncing its in-memory picture of the mailbox with what's actually on disk) that doesn't normally happen with every single command. It can take a little real time to finish ๐Ÿ’…. If a server doesn't have any housekeeping like that, then CHECK is literally the same as NOOP. Main character energy for NOOP ๐ŸŒธ

Also, don't get it twisted: there's no promise you'll get an EXISTS untagged response back from CHECK ๐Ÿ™ˆ. If you're trying to poll for new mail, use NOOP, not CHECK. Trust me on this one, bestie ๐Ÿซถ

C: FXXZ CHECK
S: FXXZ OK CHECK Completed

6.4.2. CLOSE Command ๐Ÿฆ‹

Arguments:  none

Data:       no specific data for this command

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

CLOSE is the one that permanently removes every message with the \Deleted flag set from the mailbox you've selected, and then drops you from selected state back to authenticated state ๐Ÿ”ฅ. The server doesn't send any untagged EXPUNGE responses for this, so it's super clean.

If the mailbox was selected with EXAMINE, or it's otherwise read-only, then nothing gets removed and you won't get an error either. Nothing happens, no drama ๐ŸŒˆ

You don't actually have to send CLOSE before you SELECT, EXAMINE, or LOGOUT ๐Ÿ’œ. Those three commands implicitly close whatever mailbox is currently selected, but they don't do an expunge when they do it. Here's the tea though: if you've deleted a whole bunch of messages, CLOSE-LOGOUT or CLOSE-SELECT is way faster than EXPUNGE-LOGOUT or EXPUNGE-SELECT. Why? Because no untagged EXPUNGE responses get sent, and the client would probably just ignore those anyway ๐Ÿ˜ญโœจ

C: A341 CLOSE
S: A341 OK CLOSE completed

6.4.3. EXPUNGE Command ๐Ÿ“

Arguments:  none

Data:       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 ๐Ÿ—‘๏ธ. Before the server says OK, it sends one untagged EXPUNGE response for each message that gets removed. So it's very much a "watch it happen" kind of command ๐Ÿ‘‘

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 character set specification
            searching criteria (one or more)

Data:       mandatory untagged response: SEARCH

Result:     OK - search completed
            NO - search error: can't search that character set or
                 criteria
            BAD - command unknown or arguments invalid

SEARCH digs through the mailbox for messages that match your searching criteria ๐Ÿ•ต๏ธโ€โ™€๏ธ. Criteria are made of one or more search keys. The server answers with an untagged SEARCH response that lists the message sequence numbers of everything that matched, so you get a little list of wins ๐ŸŽ€

When you use more than one key, the result is the intersection (an AND of all of them). So DELETED FROM "SMITH" SINCE 1-Feb-1994 means all the deleted messages from Smith that showed up in the mailbox since February 1, 1994. Iconic. You can also wrap search keys in parentheses, which is handy when you're using OR and NOT ๐Ÿง 

Server implementations MAY exclude [MIME-1] body parts with terminal content types other than TEXT and MESSAGE from SEARCH matching. That's a choice the server gets to make, so it's giving flexibility ๐Ÿ’…

The optional character set specification is the word "CHARSET" followed by a registered MIME character set. It tells the server what character set the strings in your search criteria are using ๐ŸŒ. [MIME-2] strings that show up in RFC 822/MIME message headers, and [MIME-1] content transfer encodings, MUST be decoded before matching, no exceptions ๐Ÿ™…โ€โ™€๏ธ. Except for US-ASCII, you don't get any guarantee that a particular character set is supported. And if the server doesn't support the character set you asked for, it MUST return a tagged NO response (not a BAD). Don't freak out, it's just a NO ๐Ÿ’–

For every search key that takes a string, a message matches if that string is a substring of the field. Matching is case-insensitive, so "smith" and "SMITH" are the same to the server ๐ŸŒธ

Here are the defined search keys. Check the Formal Syntax section for the exact syntax of each argument ๐Ÿ“–

<message set>  Messages with message sequence numbers
               corresponding to the specified message sequence
               number set

ALL            All messages in the mailbox; 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
               contains the specified string in the [RFC-822]
               field-body.

KEYWORD <flag> Messages with the specified keyword set.

LARGER <n>     Messages with an RFC822.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 RFC822.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 a quick example to see it all click together ๐ŸŽ€

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

Data:       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 the data for a message in the mailbox ๐Ÿ“ฌ the data items can be a single atom or a parenthesized list, and these are the ones you can ask for rn ๐Ÿ’…

  • ALL is a macro, basically a shortcut for (FLAGS INTERNALDATE RFC822.SIZE ENVELOPE) ๐ŸŒธ
  • BODY is the non-extensible form of BODYSTRUCTURE ๐ŸŽ€
  • BODY[<section>] is the text of one particular body section ๐Ÿฆ‹ the section spec is one or more part numbers, separated by periods
    • single-part messages only have a 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 have to be listed with a period and then the number inside that nested multipart part ๐Ÿซถ
    • you cannot fetch a multipart part by itself, only its individual members ๐Ÿ™ˆ
    • a part of type MESSAGE and subtype RFC822 has nested parts too, which are the parts of the MESSAGE part's body โœจ
    • nested part 0 of a MESSAGE/RFC822 part is the [RFC-822] header of the message ๐Ÿ“
    • every message has at least one part ๐ŸŒˆ
    • the \Seen flag gets implicitly set here, and if that changes the flags, they should be included as part of the fetch responses ๐Ÿ‘€

here's a super complex message with its section specs, it's giving multipart chaos ๐Ÿ˜ญ

0   ([RFC-822] header of the message)
    MULTIPART/MIXED
1   TEXT/PLAIN
2   APPLICATION/OCTET-STREAM
3   MESSAGE/RFC822
3.0   ([RFC-822] header of the message)
3.1   TEXT/PLAIN
3.2   APPLICATION/OCTET-STREAM
      MULTIPART/MIXED
4.1   IMAGE/GIF
4.2   MESSAGE/RFC822
4.2.0   ([RFC-822] header of the message)
4.2.1   TEXT/PLAIN
        MULTIPART/ALTERNATIVE
4.2.2.1  TEXT/PLAIN
4.2.2.2  TEXT/RICHTEXT

notice there's no section spec for the multipart parts themselves (no section 4 or 4.2.2) ๐Ÿ™ƒ

  • BODY.PEEK[<section>] is the alternate form of BODY[section] that does NOT implicitly set \Seen ๐Ÿซฃ
  • BODYSTRUCTURE is the [MIME-1] body structure of the message, computed by the server by parsing the [MIME-1] header lines ๐Ÿง 
  • ENVELOPE is the envelope structure of the message, computed by the server by parsing the [RFC-822] header into its component parts, defaulting various fields as necessary ๐Ÿ’Œ
  • FAST is another macro, equivalent to (FLAGS INTERNALDATE RFC822.SIZE) โšก
  • FLAGS gives the flags that are set for this message ๐Ÿšฉ
  • FULL is a macro equivalent to (FLAGS INTERNALDATE RFC822.SIZE ENVELOPE BODY) ๐Ÿ‘‘
  • INTERNALDATE is the date and time of final delivery of the message, as defined by RFC 821 ๐Ÿ“…
  • RFC822 is the message in [RFC-822] format ๐Ÿ’– it implicitly sets \Seen (and if that changes the flags, they should be included in the fetch responses), and it's the concatenation of RFC822.HEADER and RFC822.TEXT
  • RFC822.PEEK is the alternate form of RFC822 that does not implicitly set \Seen ๐Ÿฆ‹
  • RFC822.HEADER is the [RFC-822] format header as stored on the server, including the delimiting blank line between the header and the body ๐Ÿ“œ
  • RFC822.HEADER.LINES <header_list> gives all the header lines (continuation lines too) whose field-name matches any string in header_list. the matching is case-insensitive but otherwise exact, and the delimiting blank line is always included ๐Ÿ”
  • RFC822.HEADER.LINES.NOT <header_list> is the opposite vibe: all header lines (continuation lines included) whose field-name does NOT match any string in header_list. again case-insensitive but otherwise exact, and the blank line is always included ๐Ÿ™…โ€โ™€๏ธ
  • RFC822.SIZE is the number of octets in the message, expressed in [RFC-822] format ๐Ÿ“
  • RFC822.TEXT is the text body of the message, minus the [RFC-822] header. it implicitly sets \Seen too, so same deal with the flags ๐Ÿ“
  • RFC822.TEXT.PEEK is the alternate form of RFC822.TEXT that doesn't implicitly set \Seen ๐ŸŒท
  • UID is the unique identifier for the message ๐Ÿชช

here's an example, the server replies per message ๐ŸŽ€

C: A654 FETCH 2:4 (FLAGS RFC822.HEADER.LINES (DATE FROM))
S: * 2 FETCH ....
S: * 3 FETCH ....
S: * 4 FETCH ....
S: A003 OK FETCH completed

6.4.6. PARTIAL Command โœจ

Arguments:  message sequence number
            message data item name
            position of first octet
            number of octets

Data:       untagged responses: FETCH

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

PARTIAL is basically FETCH but with a slice ๐Ÿฐ you get back only the number of octets you asked for, starting from the starting octet you named. you can only fetch one message at a time, and the first octet of a message is octet 1, so that's the lowest starting octet you can use ๐Ÿง

these FETCH items work with PARTIAL: RFC822, RFC822.HEADER, RFC822.TEXT, BODY[section], plus any .PEEK forms of those ๐Ÿ’…

if your partial fetch tries to read past the end of the text, it gets truncated as needed. and if your starting octet is already past the end, you get an empty string back ๐Ÿซ 

the data comes back in the FETCH response, but there's no indication of what range the partial data covers, so keep track of that yourself ๐Ÿ‘€ also, you can't stream multiple PARTIAL commands for the same data item without processing and synchronizing at each step, because streamed commands might run out of order ๐ŸŒ€

there's no requirement that partial fetches follow any sequence. for example, if a partial fetch of octets 1 through 10000 breaks in an awkward spot for BASE64 decoding, it's allowed to continue with a partial fetch of 9987 through 19987, and so on ๐Ÿฆ‹

the \Seen flag gets handled the same way as in the associated FETCH command ๐ŸŒธ

here's an example, very cute ๐Ÿฅน

C: A005 PARTIAL 4 RFC822 1 1024
S: * 1 FETCH (RFC822 {1024}
S: Return-Path: <gray@cac.washington.edu>
S: ...
S: .........  FLAGS (\Seen))
S: A005 OK PARTIAL completed

6.4.7. STORE Command โœจ

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

Data:       untagged responses: FETCH

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

STORE is the command that changes the data attached to a message ๐Ÿ”ง normally it sends back the updated value in an untagged FETCH response. but if you add .SILENT to the data item name, the untagged FETCH is skipped, and the server should assume the client already worked out the updated value itself or just doesn't care about it ๐Ÿคซ

these are the data items you can store rn ๐Ÿ’–

  • FLAGS <flag list> replaces the flags for the message with the argument ๐Ÿšฉ the new values come back as if you did a FETCH of those flags
  • FLAGS.SILENT <flag list> is the same as FLAGS but doesn't return a new value ๐Ÿค
  • +FLAGS <flag list> adds the argument to the message's flags โž• the new values come back as if you did a FETCH of those flags
  • +FLAGS.SILENT <flag list> is the same as +FLAGS, no new value returned ๐Ÿซฅ
  • -FLAGS <flag list> removes the argument from the message's flags โž– the new values come back as if you did a FETCH of those flags
  • -FLAGS.SILENT <flag list> is the same as -FLAGS, but no new value returned ๐ŸŒ™

here's an example, watch the flags glow up ๐ŸŒˆ

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.8. COPY Command โœจ

Arguments:  message set
            mailbox name

Data:       no specific data 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

COPY copies the specified message(s) over to the specified destination mailbox ๐Ÿ“ฆ the flags and internal date of the messages SHOULD be preserved in the copy ๐Ÿซถ

if the destination mailbox doesn't exist, a server SHOULD return an error ๐Ÿšซ it SHOULD NOT automatically create the mailbox, periodt ๐Ÿ’… unless it's certain the destination mailbox can not be created, the server MUST send the response code "[TRYCREATE]" as the prefix of the text of the tagged NO response. that's basically a hint for the client that it can try a CREATE command and then retry the COPY if the CREATE works ๐ŸŽ€

if COPY fails for any reason at all, server implementations MUST restore the destination mailbox to its state from before the COPY attempt. no half-finished copies, bestie ๐Ÿ˜ญ

here's the example ๐Ÿฆ‹

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

6.4.9. UID Command ๐Ÿ’–โœจ

Arguments:  command name
            command arguments

Data:       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 and it's giving main character energy ๐Ÿ’… In the first form, it takes a COPY, FETCH, or STORE command as its arguments, with arguments that fit whichever command it is. The twist is that the numbers in the message set argument are unique identifiers instead of message sequence numbers ๐Ÿฆ‹

In the second form, the UID command takes a SEARCH command with SEARCH command arguments. The arguments are read the same way as with SEARCH, but the numbers returned in a SEARCH response to a UID SEARCH command are unique identifiers instead of message sequence numbers. For example, UID SEARCH 1:100 UID 443:557 returns the unique identifiers that match the intersection of the message sequence number set 1:100 and the UID set 443:557 ๐ŸŽ€

A unique identifier is a number, and it's guaranteed not to point at any other message in the mailbox ๐Ÿ”ฅ Unique identifiers get assigned in strictly ascending order for each message added to the mailbox. Unlike message sequence numbers, they persist across sessions ๐Ÿ‘‘ That lets a client resync its state from a previous session with the server (think disconnected or offline access clients), and [IMAP-DISC] goes deeper on this ๐Ÿซถ

Every mailbox has a unique identifier validity value ๐ŸŒˆ It gets sent in an UIDVALIDITY response code inside an OK untagged response when the mailbox is selected. If unique identifiers from an earlier session fail to persist into this session, the unique identifier validity value MUST be greater than it was in the earlier session. No cap, this is the rule that keeps everyone from getting confused ๐Ÿ’€

Note: A good value for the unique identifier validity value is a 32-bit representation of the creation date/time of the mailbox. It's alright to use a constant such as 1, but only if it's guaranteed that unique identifiers will never be reused, even if a mailbox gets deleted and a new mailbox with the same name is created at some future time.

Message set ranges are allowed ๐Ÿ“ However, there's no guarantee that unique identifiers are contiguous. A non-existent unique identifier inside a message set range gets ignored, and no error message is generated for it ๐Ÿ™ˆ

The number after the "*" in an untagged FETCH response is always a message sequence number, not a unique identifier, even for a UID command response ๐Ÿงš Still, server implementations MUST implicitly include the UID message data item as part of any FETCH response caused by a UID command, whether or not UID was specified as a message data item in the FETCH โœจ

Example:

C: A003 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

Data:       implementation defined

Result:     OK - command completed
            NO - failure
            BAD - command unknown or arguments invalid

Any command prefixed with an X is an experimental command ๐Ÿ”ฌ Commands that aren't part of this specification, or a standard or standards-track revision of it, MUST use the X prefix. Bestie, that's how everyone knows what's experimental and what's the real deal ๐Ÿ’…

Any added untagged responses issued by an experimental command MUST also be prefixed with an X. Server implementations MUST NOT send any such untagged responses unless the client asked for them by issuing the associated experimental command ๐Ÿ™…โ€โ™€๏ธ

Example:

C: a441 CAPABILITY
S: * CAPABILITY IMAP4 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 ๐Ÿซง

Server responses come in three forms: status responses, server data, and command continuation requests ๐ŸŽ€

Server response data is marked "Data:" in the response descriptions below. It's described by what it does, not by how it's written. The exact syntax of server response data lives in the Formal Syntax section ๐Ÿ“–

The client MUST be prepared to accept any response at all times ๐Ÿซถ

Status responses that are tagged tell you the completion result of a client command, and they carry a tag that matches the command ๐Ÿ

Some status responses, and all server data, are untagged. An untagged response uses the token * instead of a tag. Untagged status responses show the server greeting, or server status that doesn't mark a command as finished. For historical reasons, untagged server data responses are also called "unsolicited data," though strictly speaking only unilateral server data is truly "unsolicited" ๐Ÿ™ƒ

Certain server data MUST be recorded by the client when it's received, and that's called out in the description of that data. This stuff is critical because it affects how every later command and response gets interpreted (for example, updates about messages being created or destroyed) ๐Ÿ’ฅ

Other server data SHOULD be recorded for later reference. If the client doesn't need to record the data, or recording it has no obvious purpose (for example, a SEARCH response when no SEARCH command is in progress), the data SHOULD be ignored ๐Ÿ—‘๏ธ

Unilateral untagged responses happen in selected state. In selected state, the server checks the mailbox for new messages as part of running each command. If it finds new messages, it sends untagged EXISTS and RECENT responses that reflect the new size of the mailbox ๐Ÿ“ฌ Server implementations that allow multiple simultaneous access to the same mailbox should also send the right unilateral untagged FETCH and EXPUNGE responses when another agent changes message flags or expunges messages ๐Ÿ‘€

Command continuation request responses use the token + instead of a tag. The server sends these to say it accepted an incomplete client command and is ready for the rest of it โœจ


7.1. Server Responses - Status Responses ๐ŸŽ€

Status responses may include an optional response code. A response code is data inside square brackets, written as an atom and possibly followed by a space and arguments. It carries extra info or status codes for client software beyond the OK/NO/BAD condition, and it's only defined when there's a specific action the client can take based on that info ๐Ÿง 

The currently defined response codes are:

  • ALERT: the human-readable text contains a special alert that MUST be presented to the user in a way that grabs their attention ๐Ÿšจ
  • PARSE: the human-readable text is an error in parsing the [RFC-822] or [MIME-1] headers of a message in the mailbox ๐Ÿงพ
  • PERMANENTFLAGS: followed by a parenthesized list of flags, this shows which of the known flags the client may change permanently ๐Ÿ” Any flag that's in the FLAGS untagged response but not in the PERMANENTFLAGS list cannot 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 while selected changed from read-write to read-only ๐Ÿ”’
  • READ-WRITE: the mailbox is selected read-write, or its access while selected changed from read-only to read-write โœ๏ธ
  • TRYCREATE: an APPEND or COPY attempt is failing because the target mailbox doesn't exist (and not for some other reason). It's a hint that the operation may succeed if the mailbox is created first with the CREATE command ๐Ÿ› ๏ธ
  • UIDVALIDITY: followed by a decimal number, this shows the unique identifier validity value. Check the UID command description for more detail ๐Ÿ”ข
  • UNSEEN: followed by a decimal number, this shows 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 any response codes they don't recognize ๐Ÿซ 

7.1.1. OK Response โœ…

Data:       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 completed 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 by a response code ๐Ÿ’โ€โ™€๏ธ

The untagged form is also one of three possible greetings at session startup. It means the session isn't authenticated yet and a LOGIN command is needed ๐Ÿ”‘

Example:

S: * OK IMAP4 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 โš ๏ธ

Data:       optional response code
            human-readable text

The NO response is an operational error message from the server ๐Ÿ˜ฌ When it's tagged, it means the associated command did not complete successfully. The untagged form is a warning, and the command may still complete successfully. The human-readable text describes the condition ๐Ÿซฃ

Example:

C: A222 COPY 1:2 owatagusiam
S: * NO Disk is 98% full, please delete unnecessary data
S: A222 OK COPY completed
C: A222 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: A222 NO COPY failed: disk is full

7.1.3. BAD Response

Data:       optional response code
            human-readable text

okay so the BAD response is the server basically going "ugh, that's an error" ๐Ÿ’€ It's an error message from the server ๐Ÿšจ. When it's tagged ๐Ÿท๏ธ, it's calling out a protocol-level error in the client's command, and the tag tells you which command caused the drama. The untagged version is for protocol-level errors where the server can't figure out which command caused it, and it can also mean an internal server failure ๐Ÿ˜ญ. Either way, the human-readable text explains what happened ๐ŸŽ€.

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

This example is giving full disaster movie ๐ŸŽฌ. The server rejects the super long command line, then the empty line, then the EXPUNGE hits a disk crash, but the server is like "don't worry, salvage worked, nothing lost" ๐Ÿฅน and then finally says the expunge is done โœจ.


7.1.4. PREAUTH Response

Data:       optional response code
            human-readable text

the PREAUTH response is always untagged ๐Ÿฆ‹, and it's one of three possible greetings when a session starts ๐ŸŒธ. It tells you the session is already authenticated by external means, so no LOGIN command is needed ๐Ÿ”‘. No password dance, bestie ๐Ÿ’….

Example:    S: * PREAUTH IMAP4 server ready and logged in as Smith

7.1.5. BYE Response

Data:       optional response code
            human-readable text

the BYE response is always untagged too ๐ŸŒˆ, and it means the server is about to close the connection ๐Ÿ‘‹. The human-readable text can be shown to the user in a status report by the client ๐Ÿ“‹. A BYE can show up as part of a normal logout sequence, or as a panic shutdown announcement from the server ๐Ÿ˜ฑ. Some server implementations also use it to announce an inactivity autologout ๐Ÿ’ค.

BYE is also one of the three possible greetings at session startup ๐Ÿงš. In that case it means the server is not willing to accept a session from this client ๐Ÿ™…โ€โ™€๏ธ. Rude, but honest ๐Ÿ’€.

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 data gets sent to the client, often as the result of a command with the same name ๐ŸŽ€.

7.2.1. CAPABILITY Response

Data:       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 first name in that list MUST be the atom "IMAP4" ๐Ÿ‘‘. That's the rule, no exceptions, bestie.

A capability name other than IMAP4 means the server supports an extension, revision, or amendment to the IMAP4 protocol ๐Ÿงฉ. Server responses MUST conform to this document until the client issues a command that uses the associated capability ๐Ÿ“œ. So the old rules stay in place until you actually use the new stuff ๐Ÿ™ˆ.

Capability names MUST either begin with "X" or be standard or standards-track IMAP4 extensions, revisions, or amendments registered with IANA ๐Ÿ—‚๏ธ. A server MUST NOT offer unregistered or non-standard capability names, unless such names are prefixed with an "X" ๐Ÿšซ. Not me offering random names with no "X" ๐Ÿ’….

Client implementations SHOULD NOT require any capability name other than "IMAP4" ๐ŸŒธ, and MUST ignore any unknown capability names ๐Ÿซ . So clients should be chill about anything they don't recognise and just skip it ๐Ÿฆ‹.

Example:    S: * CAPABILITY IMAP4 XPIG-LATIN

Yes, XPIG-LATIN is the pig latin extension, and it's giving pure chaos ๐Ÿทโœจ.


7.2.2. LIST Response

Data:       name attributes
            hierarchy delimiter
            name

the LIST response shows up as a result of a LIST command ๐Ÿ“‚. It returns a single name that matches the LIST specification ๐ŸŽฏ. There may be multiple LIST responses for a single LIST command ๐Ÿ“.

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. Dead end, no kids allowed ๐Ÿ™…โ€โ™€๏ธ.
  • \Noselect: It is not possible to use this name as a selectable mailbox. Look, but don't touch ๐Ÿ‘€.
  • \Marked: The mailbox has been marked "interesting" by the server; the mailbox probably contains messages that have been added since the last time the mailbox was selected. Ooh, something new in there ๐Ÿ‘€โœจ.
  • \Unmarked: The mailbox does not contain any additional messages since the last time the mailbox was selected. Nothing new, bestie ๐Ÿ˜Œ.

If it is not feasible for the server to determine whether the mailbox is "interesting" or not, or if the name is a \Noselect name, the server should not send either \Marked or \Unmarked ๐Ÿคทโ€โ™€๏ธ. Basically, if the server can't tell, it just skips both labels.

The hierarchy delimiter is a character used to delimit levels of hierarchy in a mailbox name ๐Ÿช„. A client may use it to create child mailboxes, and to search higher or lower levels of naming hierarchy ๐ŸŒณ. All children of a top-level hierarchy node must use the same separator character ๐Ÿงก. A NIL hierarchy delimiter means that no hierarchy exists, and the name is a "flat" name ๐Ÿฅž.

The name represents an unambiguous left-to-right hierarchy, and 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

Data:       name attributes
            hierarchy delimiter
            name

the LSUB response shows up as a result of an LSUB command ๐Ÿ’ซ. It returns a single name that matches the LSUB specification ๐ŸŽฏ. There may be multiple LSUB responses for a single LSUB command ๐ŸŒธ. The data is identical in format to the LIST response, so it's the same vibe ๐Ÿค.

Example:    S: * LSUB () "." #news.comp.mail.misc

7.2.4. SEARCH Response

Data:       zero or more numbers

the SEARCH response shows up as a result of a SEARCH or UID SEARCH command ๐Ÿ”Ž. The numbers point to the messages that match the search criteria ๐ŸŽฏ. For SEARCH, these are message sequence numbers; for UID SEARCH, these are unique identifiers ๐Ÿ†”. Each number is delimited by a space โœจ.

Example:    S: * SEARCH 2 3 6

7.2.5. FLAGS Response

Data:       flag parenthesized list

the FLAGS response shows up as a result of a SELECT or EXAMINE command ๐Ÿณ๏ธโ€๐ŸŒˆ. The flag parenthesized list tells you which flags apply to this mailbox ๐Ÿšฉ. At a minimum you get the system-defined flags, but the server might have other flags too, depending on how it's implemented ๐ŸŒˆ.

The update from the FLAGS response MUST be recorded by the client ๐Ÿ“. No skipping this one, bestie ๐Ÿซถ.

Example:    S: * FLAGS (\Answered \Flagged \Deleted \Seen \Draft)

7.3. Server Responses - Message Status

these responses are always untagged ๐ŸŒŸ. This is how message data gets sent from the server to the client, often as the result of a command with the same name ๐Ÿ’Œ. Right after the "*" token there's a number ๐Ÿ”ข, and it represents either a message sequence number or a message count. Main character number energy โœจ.

7.3.1. EXISTS Response

Data:       none

the EXISTS response reports how many messages are in the mailbox ๐Ÿ“ฆ. It shows up as a result of a SELECT or EXAMINE command, and also whenever the size of the mailbox changes, like when new mail arrives ๐Ÿ“ฌ.

The update from the EXISTS response MUST be recorded by the client ๐Ÿ’œ.

Example:    S: * 23 EXISTS

7.3.2. RECENT Response

Data:       none

the RECENT response reports how many messages have arrived since the last time a SELECT command was run on this mailbox ๐Ÿ†•. It shows up as a result of a SELECT or EXAMINE command, and also whenever the size of the mailbox changes, like new mail ๐Ÿ’Œ.

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

Example:    S: * 5 RECENT

7.3.3. EXPUNGE Response

Data:       none

the EXPUNGE response reports that the specified message sequence number has been permanently removed from the mailbox ๐Ÿ—‘๏ธ๐Ÿ’€. After that, the message sequence number for each message after it in the mailbox is immediately decremented by 1 ๐Ÿ“‰. That decrement shows up in message sequence numbers in later responses too, including other untagged EXPUNGE responses ๐ŸŒ€.

Because of that immediate decrement rule, the message sequence numbers in a bunch of EXPUNGE responses depend on the order the messages get removed in ๐Ÿง . Lower to higher, or higher to lower, makes a difference. For example, say 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. A "higher to lower server" will send successive untagged EXPUNGE responses for message sequence numbers 9, 8, 7, 6, and 5. Same messages gone, totally different numbers, iykyk ๐Ÿ™ˆ.

An EXPUNGE response MUST NOT be sent when no command is in progress ๐Ÿšซ, nor while responding to a FETCH, STORE, or SEARCH command ๐Ÿ™…โ€โ™€๏ธ. This rule is necessary to prevent a loss of synchronization of message sequence numbers between client and server ๐Ÿ”’. Without it, everyone's numbers get out of sync and it's chaos ๐Ÿ˜ญ.

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

Example:    S: * 44 EXPUNGE

7.3.4. FETCH Response โœจ

Data: message data

The FETCH response is how the server hands the client info about a message ๐Ÿ“ฌ It comes back as pairs of data item names and their values, all wrapped in parentheses. You'll see it when the client sends a FETCH or STORE command, and also when the server decides on its own to send something (like flag updates) ๐Ÿฆ‹

The current data items are:

  • BODY: a form of BODYSTRUCTURE without extension data ๐ŸŽ€
  • BODY[section]: a string with the body contents of the specified section ๐Ÿ’Œ
    • The client should interpret this string based on the content transfer encoding, body type, and body subtype.
    • 8-bit textual data is allowed if a character set identifier is part of the body parameter parenthesized list for this section.
    • Non-textual data, like binary, has to 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 has to decode the transfer encoded string ๐Ÿ”
  • BODYSTRUCTURE: a parenthesized list that describes the body structure of a message ๐Ÿงฉ The server works this out by parsing the [RFC-822] header and body into component parts, filling in defaults for various fields whenever needed.
    • Multiple parts are shown through parenthesis nesting. Where you'd normally expect a body type as the first element of the list, you get a nested body instead. The second element of the list is the multipart subtype (mixed, digest, parallel, alternative, etc.).
    • Extension data comes right after the multipart subtype. It's never returned with the BODY fetch, but it may come back with a BODYSTRUCTURE fetch. If extension data is present, it must be in the defined order.
    • The extension data of a multipart body part comes in this order:
      • body parameter parenthesized list: a parenthesized list of attribute/value pairs [e.g. (foo bar baz rag) where "bar" is the value of "foo" and "rag" is the value of "baz"] as defined in [MIME-1].
    • Any extension data after that isn't defined yet in this version of the protocol. It may be made up of zero or more NILs, strings, numbers, or possibly nested parenthesized lists of that stuff. Client implementations that do a BODYSTRUCTURE fetch MUST be prepared to accept that extension data ๐Ÿซถ Server implementations MUST NOT send that extension data until a revision of this protocol has defined it ๐Ÿšซ
    • The basic fields of a non-multipart body part come in this order:
      • body type: a string giving the content type name as defined in [MIME-1].
      • body subtype: a string giving the content subtype name as defined in [MIME-1].
      • body parameter parenthesized list: a parenthesized list of attribute/value pairs [e.g. (foo bar baz rag) where "bar" is the value of "foo" and "rag" is the value of "baz"] as defined in [MIME-1].
      • body id: a string giving the content id as defined in [MIME-1].
      • body description: a string giving the content description as defined in [MIME-1].
      • body encoding: a string giving the content transfer encoding as defined in [MIME-1].
      • body size: a number giving the size of the body in octets. This size is the size in its transfer encoding, not the size after any decoding.
    • A body type of type MESSAGE and subtype RFC822 has, 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 has, right after the basic fields, the size of the body in text lines. Again, this size is the size in its transfer encoding, not the size after any decoding.
    • Extension data follows the basic fields and the type-specific fields listed above. It's never returned with the BODY fetch, but it may come back with a BODYSTRUCTURE fetch. If extension data is present, it must be in the defined order.
    • The extension data of a non-multipart body part comes in this order:
      • body MD5: a string giving the content MD5 value as defined in [MIME-1].
    • Any extension data after that 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 gets this by parsing the [RFC-822] header into component parts, filling in defaults for various fields as needed.
    • The fields of the envelope structure come in this 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 email address. Its fields come in this order: personal name, [SMTP] at-domain-list (source route), mailbox name, and host name.
    • [RFC-822] group syntax is shown with 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 (the semi-colon in RFC 822 syntax). If the mailbox name field is not 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 gets presented as NIL. Also, the server must default the reply-to and sender fields from the from field, because a client isn't expected to know to do that ๐Ÿ™ˆ
  • FLAGS: a parenthesized list of flags that are set for this message ๐Ÿšฉ This can include keywords plus these system flags:
    • \Seen: the message has been read ๐Ÿ‘€
    • \Answered: the message has been answered ๐Ÿ’ฌ
    • \Flagged: the message is "flagged" for urgent or special attention โญ
    • \Deleted: the message is "deleted" for removal by a later EXPUNGE ๐Ÿ—‘๏ธ
    • \Draft: the message hasn't finished composition (it's marked as a draft) โœ๏ธ
    • There's also one special flag that can be fetched but not stored:
      • \Recent: the message has arrived since the last time this mailbox was selected ๐Ÿ†•
  • INTERNALDATE: a string with the date and time of final delivery of the message as defined by [SMTP] ๐Ÿ“…
  • RFC822: a string with the message in [RFC-822] format. The header portion of the message must be 7-bit. 8-bit characters are only allowed in the non-header portion, and only if there are [MIME-1] data in the message that identify the character set of the message ๐ŸŒˆ
  • RFC822.HEADER: a string with the [RFC-822] format header of the message, including the blank line between the header and the body that delimits them. The entire string must be 7-bit, because 8-bit characters aren't allowed in headers. RFC822.HEADER is used to return data for the RFC822.HEADER, RFC822.HEADER.LINES, and RFC822.HEADER.LINES.NOT FETCH data items. Note that a blank line is always included, no matter what header line restrictions apply ๐Ÿ“
  • RFC822.SIZE: a number with the count of octets in the message in [RFC-822] format ๐Ÿ”ข
  • RFC822.TEXT: a string with the text body of the message, leaving out the [RFC-822] header. 8-bit characters are only allowed if there are [MIME-1] data in the message that identify the character set of the message ๐Ÿ’…
  • UID: a number that's the unique identifier of the message ๐Ÿ†”

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

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

7.3.5. Obsolete Responses

In addition to the responses listed here, client implementations MUST accept and implement the obsolete responses described in Appendix B ๐Ÿ•ฐ๏ธ Yes, even the old ones, bestie ๐Ÿ˜ญ


7.4. Server Responses - Command Continuation Request

The command continuation request response is marked with a "+" token instead of a tag ๐Ÿช„ That's the server saying "ready when you are." 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 whenever an argument to any command is a literal ๐Ÿ“ฆ

The client isn't allowed to send the octets of the literal unless the server says it expects them. This lets the server process commands and reject errors line by line, which is so smart ๐Ÿง  The rest of the command, including the CRLF that ends a command, comes after the octets of the literal. If there are more command arguments, the literal octets are followed by a space and then those arguments ๐ŸŽ€

So here's how a literal looks when it's sent to the server, with the braces counting the bytes ๐Ÿ’Œ

   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 IMAP4 session โœจ

Okay bestie, this is a full IMAP4 session transcript, basically a whole group chat between the client (C) and the server (S) ๐Ÿ’ฌ. One long line got split up so it's easier to read, and that's just for editorial clarity ๐ŸŒธ.

   S:   * OK IMAP4 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 "14-Jul-1993 02:44:25 -0700"
         RFC822.SIZE 4282 ENVELOPE ("Wed, 14 Jul 1993 02:23:25 -0700 (PDT)"
         "IMAP4 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 rfc822.header
   S:    * 12 FETCH (RFC822.HEADER {346}
   S:    Date: Wed, 14 Jul 1993 02:23:25 -0700 (PDT)
   S:    From: Terry Gray <gray@cac.washington.edu>
   S:    Subject: IMAP4 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 IMAP4 server terminating connection
   S:    a006 OK LOGOUT completed

9. Formal Syntax โœจ

Time for the grammar ๐Ÿง โœจ. This spec uses the augmented Backus-Naur Form (BNF) notation from [RFC-822], with one twist: the delimiter for the "#" construct is a single space (SPACE), not a comma ๐ŸŽ€.

Everything is case-insensitive, except where noted, and using upper or lower case for token strings is just for editorial clarity ๐Ÿ’…. Implementations MUST accept these strings in a case-insensitive fashion ๐Ÿซถ.

Obsolete syntax might still show up if you're talking to implementations written for an earlier version of this protocol (like IMAP2) ๐Ÿฆ‹. New implementations SHOULD accept obsolete syntax as input, but MUST NOT otherwise use such syntax ๐Ÿ’€.

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

   addr_adl        ::= nstring

   addr_host       ::= nstring
                       ;; NIL indicates [RFC-822] group syntax

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

   addr_name       ::= nstring

   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 / CTLs / list_wildcards /
                       quoted_specials

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

   auth_type       ::= atom

   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 1#body_extension]
                       ;; MUST NOT be returned on non-extensible
                       ;; "BODY" fetch

   body_ext_mpart  ::= body_fld_param [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_enc    ::= (<"> ("7BIT" / "8BIT" / "BINARY" / "BASE64"/
                       "QUOTED-PRINTABLE") <">) / string

   body_fld_id     ::= nstring

   body_fld_lines  ::= number
   body_fld_md5    ::= nstring

   body_fld_octets ::= number

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

   body_fld_subtyp ::= string

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

   body_type_basic ::= (<"> ("APPLICATION" / "AUDIO" / "IMAGE" /
                       "MESSAGE" / "VIDEO") <">) / string) SPACE
                       body_fld_subtyp SPACE body_fields
                       ;; MESSAGE subtype MUST NOT be "RFC822"

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

   body_type_msg   ::= <"> "MESSAGE" <"> SPACE <"> "RFC822" <"> SPACE
                       body_fields SPACE envelope SPACE body SPACE
                       body_fld_lines

   body_type_text  ::= <"> "TEXT" <"> SPACE body_fld_subtyp SPACE
                        body_fields SPACE body_fld_lines

   capability      ::= atom
                       ;; Must begin with "X" or be registered with
                       ;; IANA as standard or standards-track

   capability_data ::= "CAPABILITY" SPACE "IMAP4" [SPACE 1#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 / find / list /
                       lsub / rename / select / 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 / partial / 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, 0x0C>

   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_old)

   date_year       ::= 4digit

   date_year_old   ::= 2digit
                       ;; OBSOLETE, (year - 1900)

   date_time       ::= <"> (date_time_new / date_time_old) <">

   date_time_new   ::= date_day_fixed "-" date_month "-" date_year
                       SPACE time SPACE zone

   date_time_old   ::= date_day_fixed "-" date_month "-" date_year_old
                       SPACE time "-" zone_old
                       ;; OBSOLETE

   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       ::= "BODY" / "BODYSTRUCTURE" /
                       "BODY" [".PEEK"] "[" section "]" / "ENVELOPE" /
                       "FLAGS" / "INTERNALDATE" / "UID" /
                       "RFC822" (([".TEXT"] [".PEEK"]) / ".SIZE" /
                       (".HEADER" [".LINES" [".NOT"] SPACE header_list])

   find            ::= "FIND" SPACE ["ALL."] "MAILBOXES" SPACE
                       list_mailbox
                       ;; OBSOLETE

   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_line     ::= astring

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

   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; other names may be
                       ;; case-sensitive depending on implementation.

   mailbox_data    ::=  "FLAGS" SPACE flag_list /
                        "LIST" SPACE mailbox_list /
                        "LSUB" SPACE mailbox_list /
                        "MAILBOX" SPACE text /
                        "SEARCH" [SPACE 1#nz_number] /
                        number SPACE "EXISTS" / number SPACE "RECENT"

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

   message_data    ::= nz_number SPACE ("EXPUNGE" /
                       ("FETCH" SPACE msg_fetch) / msg_obsolete)

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

   msg_obsolete    ::= "COPY" / ("STORE" SPACE msg_fetch)
                       ;; OBSOLETE untagged data responses

   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)

   partial         ::= "PARTIAL" SPACE nz_number SPACE
                       ("BODY" [".PEEK"] "[" section "]" /
                       "RFC822" (([".TEXT"] [".PEEK"]) / ".HEADER")
                       SPACE number SPACE number

   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        ::= *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

   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
                       ;; Server will disconnect condition

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

   resp_text       ::= ["[" resp_text_code "]" SPACE] (text_mime2 / text)

   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]
                       search_criteria
                       ;; Character set must be registered with IANA
                       ;; as a MIME character set

   search_criteria ::= 1#search_key

   search_key      ::= search_new / search_old

   search_new      ::= "DRAFT" /
                       "HEADER" SPACE header_line 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 /
                       "(" search_criteria ")"
                       ;; New in IMAP4

   search_old      ::= "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"
                       ;; Defined in [IMAP2]

   section         ::= "0" / nz_number ["." section]

   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>

   store           ::= "STORE" SPACE set SPACE store_att_flags

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

   string          ::= quoted / literal

   subscribe       ::= ("SUBSCRIBE" SPACE mailbox) / subscribe_obs

   subscribe_obs   ::= "SUBSCRIBE" SPACE "MAILBOX" SPACE mailbox
                       ;;OBSOLETE

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

   text            ::= 1*TEXT_CHAR

   text_mime2       ::= "=?" <charset> "?" <encoding> "?"
                        <encoded-text> "?="
                        ;; Syntax defined in [MIME-2]

   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) / unsubscribe_obs

   unsubscribe_obs ::= "UNSUBSCRIBE" SPACE "MAILBOX" SPACE mailbox
                       ;;OBSOLETE

   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".

   zone_old        ::= "UT" / "GMT" / "Z" /                ;; +0000
                       "AST" / "EDT" /                     ;; -0400
                       "EST" / "CDT" /                     ;; -0500
                       "CST" / "MDT" /                     ;; -0600
                       "MST" / "PDT" /                     ;; -0700
                       "PST" / "YDT" /                     ;; -0800
                       "YST" / "HDT" /                     ;; -0900
                       "HST" / "BDT" /                     ;; -1000
                       "BST" /                             ;; -1100
                       "A" / "B" / "C" / "D" / "E" / "F" / ;; +1 to +6
                       "G" / "H" / "I" / "K" / "L" / "M" / ;; +7 to +12
                       "N" / "O" / "P" / "Q" / "R" / "S" / ;; -1 to -6
                       "T" / "U" / "V" / "W" / "X" / "Y"   ;; -7 to -12
                       ;; OBSOLETE

10. Author's Note ๐Ÿ“

okay so this bit is the author being real about the history ๐Ÿซถ this document is a revision or rewrite of earlier documents, and it supersedes the protocol specification in those older docs: the IMAP4 Internet drafts, the IMAP2bis Internet drafts, the unpublished IMAP2bis.TXT document, RFC 1176, and RFC 1064. so if you're hunting through old specs, this is the one that wins ๐Ÿ‘‘


11. Security Considerations ๐Ÿ”

okay bestie, this one is SERIOUS so let's pay attention ๐Ÿ˜ญ๐Ÿ”ฅ

IMAP4 protocol transactions, including electronic mail data, are sent in the clear over the network unless the optional privacy protection is negotiated in the AUTHENTICATE command. so by default everything is just floating around out there unencrypted unless that privacy protection gets negotiated ๐Ÿ’€

A server error message for an AUTHENTICATE command which fails due to invalid credentials should not detail why the credentials are invalid. basically the server should keep its lips sealed about the exact reason ๐Ÿค

Use of the LOGIN command sends passwords in the clear. This can be avoided by using the AUTHENTICATE command instead. so if you can, reach for AUTHENTICATE and keep those passwords off the open wire ๐Ÿฆ‹

A server error message for a failing LOGIN command should not specify that the user name, as opposed to the password, is invalid. same energy here: don't tell people which part of the login was wrong ๐Ÿ™ˆ

Additional security considerations are discussed in the section discussing the AUTHENTICATE and LOGIN commands. so go check those sections too, they've got more tea โ˜•


12. Author's Address ๐Ÿ“ฎ

Mark R. Crispin ๐ŸŒธ

Networks and Distributed Computing, JE-30

University of Washington

Seattle, WA 98195

Phone: (206) 543-5762

EMail: MRC@CAC.Washington.EDU


Appendices ๐ŸŽ€

A. Obsolete Commands ๐Ÿ•ฐ๏ธ

okay so these commands are all OBSOLETE, which means it is NOT required to support any of them in new server implementations ๐Ÿ’… they're only documented here for the benefit of implementors who may want to support them so they can keep talking to old client implementations. the section headings below are meant to line up with where these commands would have lived in the main document if they hadn't been obsoleted ๐Ÿงš

A.6.3.OBS.1. FIND ALL.MAILBOXES Command ๐Ÿ”

  • Arguments: mailbox name with possible wildcards
  • Data: untagged responses: MAILBOX
  • Result:
OK - find completed
NO - find failure: can't list that name
BAD - command unknown or arguments invalid

the FIND ALL.MAILBOXES command returns a subset of names from the complete set of all names available to the user ๐Ÿซง it returns zero or more untagged MAILBOX replies. the mailbox argument is similar to the one for LIST with an empty reference, except that the characters "%" and "?" match a single character. it's giving LIST but make it a little different โœจ

Example:

C: A002 FIND ALL.MAILBOXES *
S: * MAILBOX blurdybloop
S: * MAILBOX INBOX
S: A002 OK FIND ALL.MAILBOXES completed

A.6.3.OBS.2. FIND MAILBOXES Command ๐Ÿฆ‹

  • Arguments: mailbox name with possible wildcards
  • Data: untagged responses: MAILBOX
  • Result:
OK - find completed
NO - find failure: can't list that name
BAD - command unknown or arguments invalid

Okay so FIND MAILBOXES ๐Ÿ’… this one hands back a subset of names from the set the user has declared as "active" or "subscribed" ๐Ÿฆ‹ It sends back zero or more untagged MAILBOX replies. The mailbox argument works like LSUB with an empty reference, except that % and ? each match a single character ๐ŸŽ€

C: A002 FIND MAILBOXES *
S: * MAILBOX blurdybloop
S: * MAILBOX INBOX
S: A002 OK FIND MAILBOXES completed

A.6.3.OBS.3. SUBSCRIBE MAILBOX Command โœจ

Arguments: mailbox name

Data: no specific data for this command

Result:

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

SUBSCRIBE MAILBOX is basically the same as SUBSCRIBE in effect ๐Ÿซถ but a server that does this command must be able to tell apart a SUBSCRIBE MAILBOX command and a SUBSCRIBE command whose mailbox name is literally "MAILBOX" ๐Ÿ™ˆ

C: A002 SUBSCRIBE MAILBOX #news.comp.mail.mime
S: A002 OK SUBSCRIBE MAILBOX to #news.comp.mail.mime
completed
C: A003 SUBSCRIBE MAILBOX
S: A003 OK SUBSCRIBE to MAILBOX completed

A.6.3.OBS.4. UNSUBSCRIBE MAILBOX Command ๐ŸŒธ

Arguments: mailbox name

Data: no specific data for this command

Result:

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

UNSUBSCRIBE MAILBOX is identical in effect to UNSUBSCRIBE ๐Ÿ’œ A server that implements it must be able to distinguish between an UNSUBSCRIBE MAILBOX command and an UNSUBSCRIBE command with a mailbox name argument of "MAILBOX" ๐Ÿ‘‘

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

B. Obsolete Responses ๐Ÿงš

The following responses are OBSOLETE ๐Ÿฅ€ Except as noted below, these responses MUST NOT be transmitted by new server implementations. Fair warning, bestie.

The section headings here line up with where these responses would sit in the main document if they hadn't been obsoleted ๐ŸŽ€

B.7.2.OBS.1. MAILBOX Response ๐Ÿฆ‹

Data: name

The MAILBOX response MUST NOT be transmitted by server implementations except in response to the obsolete FIND MAILBOXES and FIND ALL.MAILBOXES commands. Client implementations that don't use these commands MAY ignore this response. It's documented here so implementors who want compatibility with old client implementations can support it ๐Ÿซถ

This response shows up as a result of FIND MAILBOXES and FIND ALL.MAILBOXES. It returns a single name that matches the FIND specification. There are no attributes or hierarchy delimiter, so it's very minimal ๐Ÿ’…

S: * MAILBOX blurdybloop

B.7.3.OBS.1. COPY Response ๐Ÿ“

Data: none

The COPY response MUST NOT be transmitted by new server implementations. Client implementations MUST ignore the COPY response. It's documented here for client implementors who might run into it from old server implementations ๐Ÿ™ˆ

In some experimental versions of this protocol, this response came back in reply to a COPY command, marking on a per-message basis that the message was copied successfully โœจ

S: * 44 COPY

B.7.3.OBS.2. STORE Response ๐Ÿ’€

Data: message data

The STORE response MUST NOT be transmitted by new server implementations. Client implementations MUST treat the STORE response as equivalent to the FETCH response. It's documented here for client implementors who might see it from old server implementations ๐Ÿ˜ญ

In some experimental versions of this protocol, this response was returned instead of FETCH in reply to a STORE command, reporting the new value of the flags ๐Ÿ”ฅ

S: * 69 STORE (FLAGS (\Deleted))

C. References ๐Ÿ“š

[IMAP-AUTH] Myers, J., "IMAP4 Authentication Mechanism", RFC 1731. Carnegie-Mellon University, December 1994.

[IMAP-COMPAT] Crispin, M. "IMAP4 Compatibility with IMAP2 and IMAP2bis", RFC 1732, University of Washington, December 1994.

[IMAP-DISC] Austein, R. "Synchronization Operations for Disconnected IMAP4 Clients", Work in Progress.

[IMAP-MODEL] Crispin, M. "Distributed Electronic Mail Models in IMAP4", RFC 1733, University of Washington, December 1994.

[IMAP-NAMING] Crispin, M. "Mailbox Naming Convention in IMAP4", Work in Progress.

[IMAP2] Crispin, M., "Interactive Mail Access Protocol - Version 2", RFC 1176, University of Washington, August 1990.

[IMSP] Myers, J. "IMSP -- Internet Message Support Protocol", Work in Progress.

[MIME-1] Borenstein, N., and Freed, N., "MIME (Multipurpose Internet Mail Extensions) Part One: Mechanisms for Specifying and Describing the Format of Internet Message Bodies", RFC 1521, Bellcore, Innosoft, September 1993.

[MIME-2] Moore, K., "MIME (Multipurpose Internet Mail Extensions) Part Two: Message Header Extensions for Non-ASCII Text", RFC 1522, University of Tennessee, September 1993.

[RFC-822] Crocker, D., "Standard for the Format of ARPA Internet Text Messages", STD 11, RFC 822, University of Delaware, August 1982.

[SMTP] Postel, Jonathan B. "Simple Mail Transfer Protocol", STD 10, RFC 821, USC/Information Sciences Institute, August 1982.

E. IMAP4 Keyword Index ๐Ÿ”‘

Index โœจ

Okay bestie, this is the index, and it's giving full alphabetical organization. ๐Ÿ—‚๏ธ๐Ÿ’… Every command, response, search key, fetch item, and flag lives here with its page number, so you can jump straight to the good stuff. Lowkey the most useful part of the whole doc. ๐Ÿซถ

       +FLAGS <flag list> (store command data item) ...............   34
       +FLAGS.SILENT <flag list> (store command data item) ........   34
       -FLAGS <flag list> (store command data item) ...............   34
       -FLAGS.SILENT <flag list> (store command data item) ........   34
       ALERT (response code) ......................................   39
       ALL (fetch item) ...........................................   29
       ALL (search key) ...........................................   27
       ANSWERED (search key) ......................................   27
       APPEND (command) ...........................................   22
       AUTHENTICATE (command) .....................................   12
       BAD (response) .............................................   41
       BCC <string> (search key) ..................................   27
       BEFORE <date> (search key) .................................   27
       BODY (fetch item) ..........................................   29
       BODY (fetch result) ........................................   46
       BODY <string> (search key) .................................   27
       BODY.PEEK[<section>] (fetch item) ..........................   30
       BODYSTRUCTURE (fetch item) .................................   31
       BODYSTRUCTURE (fetch result) ...............................   47
       BODY[<section>] (fetch item) ...............................   29
       BODY[section] (fetch result) ...............................   46
       BYE (response) .............................................   41
       CAPABILITY (command) .......................................   10
       CAPABILITY (response) ......................................   42
       CC <string> (search key) ...................................   27
       CHECK (command) ............................................   23
       CLOSE (command) ............................................   24
       COPY (command) .............................................   34
       COPY (response) ............................................   68
       CREATE (command) ...........................................   17
       DELETE (command) ...........................................   18
       DELETED (search key) .......................................   27
       DRAFT (search key) .........................................   27
       ENVELOPE (fetch item) ......................................   31
       ENVELOPE (fetch result) ....................................   49
       EXAMINE (command) ..........................................   16
       EXISTS (response) ..........................................   45
       EXPUNGE (command) ..........................................   25
       EXPUNGE (response) .........................................   45
       FAST (fetch item) ..........................................   31
       FETCH (command) ............................................   29
       FETCH (response) ...........................................   46
       FIND ALL.MAILBOXES (command) ...............................   65
       FIND MAILBOXES (command) ...................................   65
       FLAGGED (search key) .......................................   27
       FLAGS (fetch item) .........................................   31
       FLAGS (fetch result) .......................................   50
       FLAGS (response) ...........................................   44
       FLAGS <flag list> (store command data item) ................   34
       FLAGS.SILENT <flag list> (store command data item) .........   34
       FROM <string> (search key) .................................   27
       FULL (fetch item) ..........................................   31
       HEADER <field-name> <string> (search key) ..................   27
       INTERNALDATE (fetch item) ..................................   31
       INTERNALDATE (fetch result) ................................   50
       KEYWORD <flag> (search key) ................................   27
       LARGER <n> (search key) ....................................   27
       LIST (command) .............................................   20
       LIST (response) ............................................   43
       LOGIN (command) ............................................   14
       LOGOUT (command) ...........................................   11
       LSUB (command) .............................................   22
       LSUB (response) ............................................   44
       MAILBOX (response) .........................................   68
       NEW (search key) ...........................................   27
       NO (response) ..............................................   40
       NOOP (command) .............................................   11
       NOT <search-key> (search key) ..............................   28
       OK (response) ..............................................   40
       OLD (search key) ...........................................   28
       ON <date> (search key) .....................................   28
       OR <search-key1> <search-key2> (search key) ................   28
       PARSE (response code) ......................................   39
       PARTIAL (command) ..........................................   32
       PERMANENTFLAGS (response code) .............................   39
       PREAUTH (response) .........................................   41
       READ-ONLY (response code) ..................................   39
       READ-WRITE (response code) .................................   39
       RECENT (response) ..........................................   45
       RECENT (search key) ........................................   28
       RENAME (command) ...........................................   18
       RFC822 (fetch item) ........................................   31
       RFC822 (fetch result) ......................................   50
       RFC822.HEADER (fetch item) .................................   31
       RFC822.HEADER (fetch result) ...............................   50
       RFC822.HEADER.LINES <header_list> (fetch item) .............   31
       RFC822.HEADER.LINES.NOT <header_list> (fetch item) .........   32
       RFC822.PEEK (fetch item) ...................................   31
       RFC822.SIZE (fetch item) ...................................   32
       RFC822.SIZE (fetch result) .................................   50
       RFC822.TEXT (fetch item) ...................................   32
       RFC822.TEXT (fetch result) .................................   51
       RFC822.TEXT.PEEK (fetch item) ..............................   32
       SEARCH (command) ...........................................   25
       SEARCH (response) ..........................................   44
       SEEN (search key) ..........................................   28
       SELECT (command) ...........................................   15
       SENTBEFORE <date> (search key) .............................   28
       SENTON <date> (search key) .................................   28
       SENTSINCE <date> (search key) ..............................   28
       SINCE <date> (search key) ..................................   28
       SMALLER <n> (search key) ...................................   28
       STORE (command) ............................................   33
       STORE (response) ...........................................   69
       SUBJECT <string> (search key) ..............................   28
       SUBSCRIBE (command) ........................................   19
       SUBSCRIBE MAILBOX (command) ................................   66
       TEXT <string> (search key) .................................   28
       TO <string> (search key) ...................................   28
       TRYCREATE (response code) ..................................   39
       UID (command) ..............................................   35
       UID (fetch item) ...........................................   32
       UID (fetch result) .........................................   51
       UID <message set> (search key) .............................   28
       UIDVALIDITY (response code) ................................   40
       UNANSWERED (search key) ....................................   29
       UNDELETED (search key) .....................................   29
       UNDRAFT (search key) .......................................   29
       UNFLAGGED (search key) .....................................   29
       UNKEYWORD <flag> (search key) ..............................   29
       UNSEEN (response code) .....................................   40
       UNSEEN (search key) ........................................   29
       UNSUBSCRIBE (command) ......................................   19
       UNSUBSCRIBE MAILBOX (command) ..............................   66
       X<atom> (command) ..........................................   37
       \Answered (system flag) ....................................   50
       \Deleted (system flag) .....................................   50
       \Draft (system flag) .......................................   50
       \Flagged (system flag) .....................................   50
       \Marked (mailbox name attribute) ...........................   43
       \Noinferiors (mailbox name attribute) ......................   43
       \Noselect (mailbox name attribute) .........................   43
       \Recent (system flag) ......................................   50
       \Seen (system flag) ........................................   50
       \Unmarked (mailbox name attribute) .........................   43

That's the whole index, babe! ๐ŸŒˆโœจ Every entry, every page number, all accounted for. Main character energy fr. ๐Ÿ‘‘๐Ÿฆ‹


๐Ÿ“ฆ where this page comes from