RFC 9051

Internet Message Access Protocol (IMAP) - Version 4rev2

๐Ÿ“… published August 2021, from ietf

Internet Message Access Protocol (IMAP) - Version 4rev2 ๐Ÿ’Œ

Hiii bestie, okay so this is RFC 9051 and it's the big IMAP upgrade. ๐Ÿฆ‹ Here's the title block tea:

  • Number: RFC 9051 โœจ
  • Title: Internet Message Access Protocol (IMAP) - Version 4rev2
  • Editors and authors: A. Melnikov, Ed. (Isode Ltd) and B. Leiba, Ed. (Futurewei Technologies). They're the main characters here ๐Ÿ‘‘
  • Stream: Internet Engineering Task Force (IETF) ๐ŸŒˆ
  • Category: Standards Track
  • ISSN: 2070-1721
  • Date: August 2021
  • Obsoletes: RFC 3501 (so yes, it's replacing the old IMAP4rev1 ๐Ÿ’…)

Abstract โœจ

okay so the Internet Message Access Protocol Version 4rev2 (IMAP4rev2) lets a client get at and mess with electronic mail messages sitting on a server ๐Ÿ“ฌ. IMAP4rev2 lets you handle mailboxes (remote message folders) in a way that's functionally equivalent to local folders, which is so iconic ๐Ÿ“. It also lets an offline client resynchronize with the server, so no more out-of-sync chaos ๐Ÿซถ.

IMAP4rev2 has operations for creating, deleting, and renaming mailboxes ๐Ÿงš, checking for new messages, removing messages permanently, setting and clearing flags, parsing per RFCs 5322, 2045, and 2231, searching, and selectively fetching message attributes, texts, and portions of them. Messages are accessed by numbers, and those numbers are either message sequence numbers or unique identifiers. Very precise, very obsessed ๐Ÿ’œ.

IMAP4rev2 does not specify a way to post mail. That job goes to a mail submission protocol, like the one in RFC 6409. Not its lane, not its problem ๐Ÿ’….

Status of This Memo โœจ

This is an Internet Standards Track document ๐ŸŽ€.

This document is a product of the Internet Engineering Task Force (IETF). It represents the consensus of the IETF community, and it got public review and was approved for publication by the Internet Engineering Steering Group (IESG). More info on Internet Standards is in Section 2 of RFC 7841 ๐Ÿ“–.

Info about the current status of this document, any errata, and how to give feedback is at https://www.rfc-editor.org/info/rfc9051 ๐Ÿ”—.

Copyright (c) 2021 IETF Trust and the persons identified as the document authors. All rights reserved.

This document is subject to BCP 78 and the IETF Trust's Legal Provisions Relating to IETF Documents (https://trustee.ietf.org/license-info) in effect on the date of publication of this document. Please review these documents carefully, because they describe your rights and restrictions with respect to this document. Code Components extracted from this document must include Simplified BSD License text as described in Section 4.e of the Trust Legal Provisions, and they are provided without warranty as described in the Simplified BSD License.

This document may contain material from IETF Documents or IETF Contributions published or made publicly available before November 10, 2008. The person(s) controlling the copyright in some of this material may not have granted the IETF Trust the right to allow modifications of such material outside the IETF Standards Process. Without an adequate license from the person(s) controlling the copyright in such materials, this document may not be modified outside the IETF Standards Process, and derivative works of it may not be created outside the IETF Standards Process, except to format it for publication as an RFC or to translate it into languages other than English ๐ŸŒธ.

Table of Contents ๐Ÿ“š

   1.  How to Read This Document
     1.1.  Organization of This Document
     1.2.  Conventions Used in This Document
     1.3.  Special Notes to Implementors
   2.  Protocol Overview
     2.1.  Link Level
     2.2.  Commands and Responses
       2.2.1.  Client Protocol Sender and Server Protocol Receiver
       2.2.2.  Server Protocol Sender and Client Protocol Receiver
     2.3.  Message Attributes
       2.3.1.  Message Numbers
       2.3.2.  Flags Message Attribute
       2.3.3.  Internal Date Message Attribute
       2.3.4.  RFC822.SIZE Message Attribute
       2.3.5.  Envelope Structure Message Attribute
       2.3.6.  Body Structure Message Attribute
     2.4.  Message Texts
   3.  State and Flow Diagram
     3.1.  Not Authenticated State
     3.2.  Authenticated State
     3.3.  Selected State
     3.4.  Logout State
   4.  Data Formats
     4.1.  Atom
       4.1.1.  Sequence Set and UID Set
     4.2.  Number
     4.3.  String
       4.3.1.  8-Bit and Binary Strings
     4.4.  Parenthesized List
     4.5.  NIL
   5.  Operational Considerations
     5.1.  Mailbox Naming
       5.1.1.  Mailbox Hierarchy Naming
       5.1.2.  Namespaces
     5.2.  Mailbox Size and Message Status Updates
     5.3.  Response When No Command in Progress
     5.4.  Autologout Timer
     5.5.  Multiple Commands in Progress (Command Pipelining)
   6.  Client Commands
     6.1.  Client Commands - Any State
       6.1.1.  CAPABILITY Command
       6.1.2.  NOOP Command
       6.1.3.  LOGOUT Command
     6.2.  Client Commands - Not Authenticated State
       6.2.1.  STARTTLS Command
       6.2.2.  AUTHENTICATE Command
       6.2.3.  LOGIN Command
     6.3.  Client Commands - Authenticated State
       6.3.1.  ENABLE Command
       6.3.2.  SELECT Command
       6.3.3.  EXAMINE Command
       6.3.4.  CREATE Command
       6.3.5.  DELETE Command
       6.3.6.  RENAME Command
       6.3.7.  SUBSCRIBE Command
       6.3.8.  UNSUBSCRIBE Command
       6.3.9.  LIST Command
       6.3.10. NAMESPACE Command
       6.3.11. STATUS Command
       6.3.12. APPEND Command
       6.3.13. IDLE Command
     6.4.  Client Commands - Selected State
       6.4.1.  CLOSE Command
       6.4.2.  UNSELECT Command
       6.4.3.  EXPUNGE Command
       6.4.4.  SEARCH Command
       6.4.5.  FETCH Command
       6.4.6.  STORE Command
       6.4.7.  COPY Command
       6.4.8.  MOVE Command
       6.4.9.  UID Command
     6.5.  Client Commands - Experimental/Expansion
   7.  Server Responses
     7.1.  Server Responses - Generic Status Responses
       7.1.1.  OK Response
       7.1.2.  NO Response
       7.1.3.  BAD Response
       7.1.4.  PREAUTH Response
       7.1.5.  BYE Response
     7.2.  Server Responses - Server Status
       7.2.1.  ENABLED Response
       7.2.2.  CAPABILITY Response
     7.3.  Server Responses - Mailbox Status
       7.3.1.  LIST Response
       7.3.2.  NAMESPACE Response
       7.3.3.  STATUS Response
       7.3.4.  ESEARCH Response
       7.3.5.  FLAGS Response
     7.4.  Server Responses - Mailbox Size
       7.4.1.  EXISTS Response
     7.5.  Server Responses - Message Status
       7.5.1.  EXPUNGE Response
       7.5.2.  FETCH Response
     7.6.  Server Responses - Command Continuation Request
   8.  Sample IMAP4rev2 Connection
   9.  Formal Syntax
   10. Author's Note
   11. Security Considerations
     11.1.  TLS-Related Security Considerations
     11.2.  STARTTLS Command versus Use of Implicit TLS Port
     11.3.  Client Handling of Unsolicited Responses Not Suitable for
            the Current Connection State
     11.4.  COPYUID and APPENDUID Response Codes
     11.5.  LIST Command and Other Users' Namespace
     11.6.  Use of MD5
     11.7.  Other Security Considerations
   12. IANA Considerations
     12.1.  Updates to IMAP Capabilities Registry
     12.2.  GSSAPI/SASL Service Name
     12.3.  LIST Selection Options, LIST Return Options, and LIST
            Extended Data Items
     12.4.  IMAP Mailbox Name Attributes and IMAP Response Codes
   13. References
     13.1.  Normative References
     13.2.  Informative References
       13.2.1.  Related Protocols
       13.2.2.  Historical Aspects of IMAP and Related Protocols
   Appendix A.  Backward Compatibility with IMAP4rev1
     A.1.  Mailbox International Naming Convention for Compatibility
           with IMAP4rev1
   Appendix B.  Backward Compatibility with BINARY Extension
   Appendix C.  Backward Compatibility with LIST-EXTENDED Extension
   Appendix D.  63-Bit Body Part and Message Sizes
   Appendix E.  Changes from RFC 3501 / IMAP4rev1
   Appendix F.  Other Recommended IMAP Extensions
   Acknowledgements
   Index
   Authors' Addresses

1. How to Read This Document ๐Ÿ“–

1.1. Organization of This Document ๐Ÿ—‚๏ธ

okay so this document is written from the point of view of the implementor of an IMAP4rev2 client or server ๐Ÿ› ๏ธ. Apart from the protocol overview in Section 2, it is not optimized for someone who's just trying to understand how the protocol works. The stuff in Sections 3, 4, and 5 gives the general context and definitions that IMAP4rev2 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 ๐Ÿ™ˆ. So, bestie, do not try to figure out command syntax from the command section alone. Go to "Formal Syntax" (Section 9) instead ๐Ÿ’….

1.2. Conventions Used in This Document ๐ŸŽ€

"Conventions" are basic principles or procedures, and the document's conventions are noted in this section ๐Ÿ’œ.

In examples, "C:" and "S:" mark lines sent by the client and server, respectively. Each line includes the terminating CRLF, so keep that in mind ๐Ÿฆ‹.

The key words "MUST", "MUST NOT", "REQUIRED", "SHALL", "SHALL NOT", "SHOULD", "SHOULD NOT", "RECOMMENDED", "NOT RECOMMENDED", "MAY", and "OPTIONAL" in this document are to be interpreted as described in BCP 14 [RFC2119] [RFC8174] when, and only when, they appear in all capitals, as shown here ๐Ÿ”ฅ.

The word "can" (not "may") is used to refer to a possible circumstance or situation, as opposed to an optional facility of the protocol ๐ŸŒˆ.

"User" is used to refer to a human user, whereas "client" refers to the software being run by the user ๐Ÿงš.

"Connection" refers to the entire sequence of client/server interaction, from the initial establishment of the network connection until its termination ๐ŸŒธ.

"Session" refers to the sequence of client/server interaction from the time a mailbox is selected (SELECT or EXAMINE command) until the time that selection ends. That happens when SELECT or EXAMINE selects another mailbox, on a CLOSE command, on an UNSELECT command, or on connection termination โญ.

The term "Implicit TLS" refers to the automatic negotiation of TLS whenever a TCP connection is made on a particular TCP port that's used exclusively by that server for TLS connections ๐Ÿ”. The term is meant to contrast with the STARTTLS command in IMAP, which the client and server use to explicitly negotiate TLS on an already-established cleartext TCP connection ๐Ÿซถ.

Characters are 8-bit UTF-8 (of which 7-bit US-ASCII is a subset), unless otherwise specified. Other character sets are indicated using a "CHARSET", as described in [MIME-IMT] and defined in [CHARSET]. CHARSETs have important extra semantics beyond defining a character set, so check those documents for more detail ๐ŸŒ.

There are several protocol conventions in IMAP ๐Ÿ“. These refer to aspects of the specification that aren't strictly part of the IMAP protocol but reflect generally accepted practice. Implementations need to be aware of these conventions and avoid conflicts, whether or not they implement the convention. For example, "&" may not be used as a hierarchy delimiter, since it conflicts with the Mailbox International Naming Convention, and other uses of "&" in mailbox names are impacted as well ๐Ÿ™ˆ.

1.3. Special Notes to Implementors โœจ

Okay bestie, implementers of IMAP are strongly encouraged to read the IMAP implementation recommendations document [IMAP-IMPLEMENTATION] alongside this one ๐Ÿ“š It helps you understand the intricacies of this protocol and how to build a product that actually plays nice with everyone else ๐Ÿซถ

IMAP4rev2 is designed to be upwards compatible from the IMAP4rev1 [RFC3501], IMAP2 [IMAP2], and unpublished IMAP2bis [IMAP2BIS] protocols ๐ŸŒธ It's largely compatible with the IMAP4rev1 protocol in RFC 3501 and the IMAP4 protocol in [RFC1730]. The exception is some facilities added in [RFC1730] and [RFC3501] that turned out to be problematic, so they were later removed or replaced by better alternatives ๐Ÿ™ˆ As IMAP4rev2 evolved, some aspects of the earlier protocols became obsolete. The obsolete commands, responses, and data formats that an IMAP4rev2 implementation can run into when working with an earlier implementation are described in Appendices A and E and [IMAP-OBSOLETE]. IMAP4rev2 supports 63-bit body parts and message sizes ๐Ÿ’ช IMAP4rev2 compatibility with the BINARY and LIST-EXTENDED IMAP extensions is covered in Appendices B and C, respectively.

Other compatibility issues with IMAP2bis, the most common variant of the earlier protocol, are discussed in [IMAP-COMPAT] ๐Ÿ’… A full discussion of compatibility issues with the rare (and presumed extinct) variants of [IMAP2] is in [IMAP-HISTORICAL]. Honestly, that one is primarily of historical interest ๐Ÿฆ‹

IMAP was originally developed for the older [RFC822] standard, so the RFC822.SIZE fetch item incorporates "RFC822" in its name ๐Ÿงš "RFC822" is meant to be read as a reference to the updated [RFC5322] standard.

IMAP4rev2 does not specify a way to post mail. That job belongs to a mail submission protocol, such as the one specified in [RFC6409] ๐Ÿ“ฌ


2. Protocol Overview โœจ

The IMAP4rev2 protocol assumes a reliable data stream, like the one TCP provides ๐ŸŒˆ When TCP is used, an IMAP4rev2 server listens on port 143 (cleartext port) or port 993 (Implicit TLS port).

2.2. Commands and Responses

An IMAP4rev2 connection is made up of three things: establishing a client/server network connection, an initial greeting from the server, and then client/server interactions ๐ŸŽ€ Each of those interactions is a client command, server data, and a server completion result response.

Everything the client and server send is in the form of lines, meaning strings that end with a CRLF ๐Ÿ’– The protocol receiver of an IMAP4rev2 client or server is reading either a line, or a sequence of octets with a known count followed by a line.

2.2.1. Client Protocol Sender and Server Protocol Receiver

The client command begins an operation โœจ Each client command is prefixed with an identifier called a "tag." It's typically a short alphanumeric string, like A0001, A0002, and so on. The client generates a different tag for each command. More formally: the client SHOULD generate a unique tag for every command, but a server MUST accept tag reuse ๐Ÿซถ

Clients MUST follow the syntax outlined in this specification strictly ๐Ÿ™…โ€โ™€๏ธ It's a syntax error to send a command with missing or extraneous spaces or arguments.

There are two cases where a line from the client doesn't represent a complete command ๐Ÿงฉ In one case, a command argument is quoted with an octet count (see the description of literal in Section 4.3). In the other case, the command arguments need server feedback (see the AUTHENTICATE command in Section 6.2.2). In either case, the server sends a command continuation request response if it's ready for the octets (if that's appropriate) and the rest of the command. This response is prefixed with the token "+".

Note: If, instead, the server detected an error in the command, it sends a BAD completion response with a tag matching the command (as described below) to reject the command and prevent the client from sending any more of it. It's also possible for the server to send a completion response for some other command (if multiple commands are in progress) or untagged data ๐ŸŒธ In either case, the command continuation request is still pending. The client takes the appropriate action for the response and reads another response from the server. In all cases, the client MUST send a complete command (including receiving all command continuation request responses and sending command continuations for the command) before initiating a new command. No skipping ahead, bestie ๐Ÿ’…

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

2.2.2. Server Protocol Sender and Client Protocol Receiver

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

Server data MAY be sent as a result of a client command, or it MAY be sent unilaterally by the server ๐Ÿงš There's no syntactic difference between server data that resulted from a specific command and server data that was sent unilaterally.

The server completion result response tells you whether the operation succeeded or failed ๐ŸŽ€ It's tagged with the same tag as the client command that began the operation. So if more than one command is in progress, the tag in a server completion response tells you which command it applies to. There are three possible server completion responses: OK (success), NO (failure), or BAD (a protocol error, like an unrecognized command or a command syntax error) ๐Ÿ’–

Servers SHOULD strictly enforce the syntax outlined in this specification ๐Ÿ‘‘ Any client command with a protocol syntax error, including (but not limited to) missing or extraneous spaces or arguments, SHOULD be rejected, and the client gets a BAD server completion response.

The protocol receiver of an IMAP4rev2 client reads a response line from the server. It then takes action based on the first token of the response, which can be a tag, a "*", or a "+" ๐Ÿ”ฅ

A client MUST be prepared to accept any server response at all times, including server data that wasn't requested ๐Ÿ˜ญ Server data SHOULD be remembered (cached), so the client can reference its remembered copy instead of sending a command to the server to request the data. For certain server data, the data MUST be remembered, as specified elsewhere in this document ๐Ÿ“

This topic gets a deeper dive in "Server Responses" (see Section 7) ๐Ÿง 

2.3. Message Attributes

Besides the message text, each message has several attributes attached to it โœจ These attributes can be retrieved one at a time, or together with other attributes or message texts.

2.3.1. Message Numbers

Messages in IMAP4rev2 are accessed by one of two numbers: the Unique Identifier (UID) or the message sequence number ๐Ÿฆ‹

2.3.1.1. Unique Identifier (UID) Message Attribute ๐Ÿ†”

okay so a UID is an unsigned, non-zero 32-bit value that gets handed to every message ๐Ÿ’Œ. Paired with the unique identifier validity value (more on that below), it becomes a 64-bit value that MUST NOT point at any other message in the mailbox, or in any later mailbox with the same name, forever ๐Ÿ”. UIDs are assigned in strictly ascending order. Every time a new message lands, it gets a higher UID than everything already sitting in the mailbox ๐Ÿ“ˆ. Unlike message sequence numbers, UIDs don't have to be contiguous, so gaps are totally fine ๐Ÿ™ƒ

The UID of a message MUST NOT change during the session and SHOULD NOT change between sessions ๐Ÿ”’. If UIDs do change between sessions, that MUST be detectable through the UIDVALIDITY mechanism we'll get to shortly ๐Ÿšจ. Persistent UIDs are required so a client can resync its state from a previous session with the server. That's super important for disconnected or offline access clients [IMAP-MODEL], and it's discussed further in [IMAP-DISC] ๐Ÿง 

Every mailbox has two 32-bit unsigned non-zero values that help with UID handling: UIDNEXT (the next unique identifier value) and UIDVALIDITY (the unique identifier validity value) ๐ŸŽ€

UIDNEXT is the predicted value that will be given to the next new message in the mailbox โœจ. Unless UIDVALIDITY also changes, UIDNEXT MUST have two characteristics. First, UIDNEXT MUST NOT change unless new messages are added to the mailbox. Second, UIDNEXT MUST change whenever new messages are added, even if those messages get expunged right after ๐Ÿ’…

Note: UIDNEXT is there so a client can tell whether any messages have been delivered since the last time it checked. It is NOT a guarantee that any particular message will have that UID ๐Ÿ™ˆ. All a client can assume, when it grabs UIDNEXT, is that messages arriving after that moment will have a UID greater than or equal to that value.

The UIDVALIDITY value gets sent in a UIDVALIDITY response code inside an OK untagged response when a mailbox is selected ๐Ÿ“ฌ. If UIDs from an earlier session fail to persist into this one, UIDVALIDITY MUST be greater than the value used in the earlier session ๐Ÿ“ˆ. A solid choice is a 32-bit representation of the current date and time when the value gets assigned. That keeps it unique and always increasing โฐ. Another option is a global counter that goes up every time a mailbox is created ๐Ÿ”ข

Note: Ideally, UIDs SHOULD persist at all times ๐Ÿฅน. The spec admits that failing to persist can be unavoidable on some server setups, but it really encourages message store techniques that avoid the problem. For example:
  1. UIDs MUST be strictly ascending in the mailbox at all times. If the physical message store gets reordered by a non-IMAP agent, the UIDs in the mailbox MUST be regenerated, because the old ones are no longer strictly ascending after the reorder ๐Ÿ”„
  2. If the message store has no mechanism to store UIDs, it must regenerate them at each session, and each session must have a unique UIDVALIDITY value. Heads up, this can be super disruptive to client message caching ๐Ÿ˜ญ
  3. If a mailbox is deleted or renamed and a new mailbox with the same name is created later, the server must either keep track of the UIDs from the previous instance of the mailbox or assign a new UIDVALIDITY value to the new instance ๐Ÿ—‚๏ธ
  4. The combination of mailbox name, UIDVALIDITY, and UID MUST refer to a single, immutable (or expunged) message on that server forever ๐Ÿ‘‘. In particular, the internal date, RFC822.SIZE, envelope, body structure, and message texts (all BODY[...] fetch data items) MUST never change. This doesn't cover message numbers, and it doesn't cover attributes that can be set by a STORE command (such as FLAGS) ๐Ÿซถ. When a message is expunged, its UID MUST NOT be reused under the same UIDVALIDITY value ๐Ÿšซ

2.3.1.2. Message Sequence Number Message Attribute ๐Ÿ”ข

A message sequence number is a relative position from 1 up to the number of messages in the mailbox ๐Ÿ“. This position MUST be ordered by ascending UIDs. When a new message is added, it gets a message sequence number that is 1 higher than the number of messages in the mailbox before it arrived ๐ŸŒฑ

Message sequence numbers can get reassigned during the session, and that's the tea โ˜•. For example, when a message is permanently removed (expunged), the sequence number of every message after it goes down by one, and the mailbox's message count goes down too ๐Ÿ“‰. Similarly, a new message can end up with a sequence number that some other message held before an expunge ๐Ÿฆ‹

Sequence numbers aren't just for positions, either. You can do math with them ๐Ÿงฎ. For example, if an untagged "11 EXISTS" comes in and an untagged "8 EXISTS" came in earlier, that means three new messages arrived, with sequence numbers 9, 10, and 11 ๐ŸŽ‰. Another example: if message 287 in a 523-message mailbox has UID 12345, then there are exactly 286 messages with lesser UIDs and 236 messages with greater UIDs ๐Ÿคฏ


2.3.2. Flags Message Attribute ๐Ÿšฉ

A message has a list of zero or more named tokens attached to it, called "flags" ๐Ÿท๏ธ. A flag gets set by being added to that list and gets cleared by being removed. There are two types of flags in IMAP4rev2: system flags and keywords. A flag of either type can be permanent or session-only ๐Ÿ’œ

A system flag is a predefined flag name in this specification that begins with \. Some system flags (\Deleted and \Seen) have special semantics that get explained elsewhere in this document ๐Ÿ“–. The system flags defined right now are:

\Seen         Message has been read

\Answered     Message has been answered

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

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

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

\Recent       This flag was in use in IMAP4rev1 and is now
              deprecated.

A keyword is defined by the server implementation, and keywords don't start with \ ๐Ÿ”‘. Servers MAY let the client define new keywords in the mailbox (check out the PERMANENTFLAGS response code description for more on that) ๐Ÿช„. A few keywords that start with $ are also defined in this specification ๐Ÿ’…

This document defines several keywords that weren't originally in [RFC3501] but that client implementations found useful โœจ. Server implementations SHOULD support these (allowed in SEARCH, and allowed and preserved in APPEND, COPY, and MOVE commands) ๐Ÿซถ

$Forwarded Message has been forwarded to another email address by being embedded within, or attached to a new message. An email client sets this keyword when it successfully forwards the message to another email address. The usual use is to show a different (or additional) icon for a forwarded message ๐Ÿ’Œ. Once set, the flag SHOULD NOT be cleared ๐Ÿ”’.

$MDNSent Message Disposition Notification [RFC8098] was generated and sent for this message. See [RFC3503] for more details on how this keyword is used and for requirements on clients and servers ๐Ÿ“จ.

$Junk The user (or a delivery agent on behalf of the user) may choose to mark a message as definitely containing junk ($Junk; see also the related keyword $NotJunk). The $Junk keyword can be used to mark, group, or hide undesirable messages (and such messages might be moved or deleted later). See [IMAP-KEYWORDS-REG] for more information ๐Ÿ—‘๏ธ.

$NotJunk The user (or a delivery agent on behalf of the user) may choose to mark a message as definitely not containing junk ($NotJunk; see also the related keyword $Junk). The $NotJunk keyword can be used to mark, group, or show messages that the user wants to see. See [IMAP-KEYWORDS-REG] for more information ๐Ÿ’–.

$Phishing The $Phishing keyword can be used by a delivery agent to mark a message as highly likely to be a phishing email. A message that a delivery agent determines to be a phishing email should also be considered a junk email and have the appropriate junk filtering applied, including setting the $Junk flag and placing the message in the \Junk special-use mailbox (see Section 7.3.1), if available ๐ŸŽฃ.

If both the $Phishing flag and the $Junk flag are set, the user agent should display an additional warning message to the user. Additionally, the user agent might display a warning, such as something of the form, "This message may be trying to steal your personal information," when the user clicks on any hyperlinks within the message ๐Ÿšจ.

The requirement for both $Phishing and $Junk to be set before a user agent displays a warning is for better backwards compatibility with existing clients that understand the $Junk flag but not the $Phishing flag. This is so that when an unextended client removes the $Junk flag, an extended client will also show the correct state ๐Ÿง . See [IMAP-KEYWORDS-REG] for more information.

$Junk and $NotJunk are mutually exclusive. If more than one of these is set for a message, the client MUST treat it as if none are set, and it SHOULD unset both of them on the IMAP server ๐Ÿ™…โ€โ™€๏ธ.

Other registered keywords can be found in the "IMAP and JMAP Keywords" registry [IMAP-KEYWORDS-REG]. New keywords SHOULD be registered in this registry using the procedure specified in [RFC5788] ๐Ÿ“.

A flag can be permanent or session-only on a per-flag basis ๐Ÿฆ‹. Permanent flags are the ones the client can add or remove from the message flags permanently, which means concurrent and subsequent sessions will see any change to them. Changes to session flags are valid only in that session โณ.


2.3.3. Internal Date Message Attribute ๐Ÿ“…

The Internal Date message attribute is the internal date and time of the message on the server ๐Ÿ•ฐ๏ธ. It is NOT the date and time in the [RFC5322] header. It's the date and time that reflects when the message was received. For messages delivered via [SMTP], it's the date and time of final delivery as defined by [SMTP] ๐Ÿ“ฌ. For messages created by the IMAP4rev2 COPY or MOVE command, the value SHOULD be the same as the Internal Date attribute of the source message ๐Ÿ”. For messages created by the IMAP4rev2 APPEND command, the value SHOULD be the date and time specified in the APPEND command description โœ๏ธ. All other cases are implementation defined ๐ŸŒˆ

2.3.4. RFC822.SIZE Message Attribute โœจ

okay so RFC822.SIZE is the number of octets in the message when it's written in [RFC5322] format ๐Ÿ“ฌ. This size SHOULD match what you get back from a FETCH BODY[] command ๐Ÿ’…. If the server stores the message in some other format, it has to work out the size itself, and it often saves that number so it doesn't have to recalculate every time ๐Ÿงš

2.3.5. Envelope Structure Message Attribute ๐Ÿ’Œ

an envelope structure is a parsed version of the [RFC5322] header of the message ๐ŸŽ€ Quick heads-up: the IMAP envelope structure is NOT the same thing as an [SMTP] envelope, so don't mix them up ๐Ÿ™ˆ

2.3.6. Body Structure Message Attribute ๐ŸŒธ

a body structure is a parsed version of the [MIME-IMB] body structure information of the message ๐Ÿฆ‹

2.4. Message Texts ๐Ÿ“–

ngl this one is so useful. Besides grabbing the whole [RFC5322] text of a message, IMAP4rev2 lets you fetch just pieces of it ๐Ÿ’– You can get the [RFC5322] message header, the [RFC5322] message body, a [MIME-IMB] body part, or a [MIME-IMB] header. Main character energy, picking only what you need โœจ

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

Once the client and server connect, an IMAP4rev2 connection is in one of four states ๐ŸŒˆ The starting state is shown in the server greeting. Most commands only work in certain states, so it's giving "right place, right time." If the client tries a command in a state that doesn't fit, that's a protocol error ๐Ÿ˜ญ The server will reply with a BAD or NO (depending on how the server is built) as the command completion result ๐Ÿ’€

3.1. Not Authenticated State ๐Ÿ”

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

3.2. Authenticated State ๐Ÿ”“

in the authenticated state, the client is logged in and MUST select a mailbox before any commands that affect messages will work ๐Ÿ‘‘ You get here when a pre-authenticated connection starts, when good credentials are provided, after a mailbox selection error, or after a successful CLOSE or UNSELECT command.

3.3. Selected State ๐Ÿ“‚

in the selected state, a mailbox has been picked to access ๐Ÿ“ You land here once a mailbox is successfully selected.

3.4. Logout State ๐Ÿ‘‹

in the logout state, the connection is getting shut down ๐Ÿ˜ญ This can happen because the client asked for it with the LOGOUT command, or because either the client or the server decided to do it on its own.

If the client asks to log out, the server MUST send an untagged BYE response and a tagged OK response to the LOGOUT command before it closes the connection ๐Ÿ’œ And the client MUST read that tagged OK response to the LOGOUT command before the client closes the connection. Both sides need to say goodbye properly ๐Ÿฅบ

A server SHOULD NOT close the connection on its own without first sending an untagged BYE response that gives the reason ๐Ÿ™…โ€โ™€๏ธ A client SHOULD NOT close the connection on its own either. Instead it SHOULD send a LOGOUT command ๐Ÿ’… If the server notices the client closed the connection unilaterally, the server MAY skip the untagged BYE response and just close its own side ๐ŸŒ™

Here's the state diagram, and yes it's giving spaghetti but it's iconic ๐Ÿ

                      +----------------------+
                      |connection established|
                      +----------------------+
                                 ||
                                 \/
               +--------------------------------------+
               |          server greeting             |
               +--------------------------------------+
                         || (1)       || (2)        || (3)
                         \/           ||            ||
               +-----------------+    ||            ||
               |Not Authenticated|    ||            ||
               +-----------------+    ||            ||
                || (7)   || (4)       ||            ||
                ||       \/           \/            ||
                ||     +----------------+           ||
                ||     | Authenticated  |<=++       ||
                ||     +----------------+  ||       ||
                ||       || (7)   || (5)   || (6)   ||
                ||       ||       \/       ||       ||
                ||       ||    +--------+  ||       ||
                ||       ||    |Selected|==++       ||
                ||       ||    +--------+           ||
                ||       ||       || (7)            ||
                \/       \/       \/                \/
               +--------------------------------------+
               |               Logout                 |
               +--------------------------------------+
                                 ||
                                 \/
                   +-------------------------------+
                   |both sides close the connection|
                   +-------------------------------+

Legend for the diagram above, bestie ๐Ÿ—๏ธ:

   Legend for the above diagram:

   (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 or UNSELECT command, unsolicited CLOSED response code, or
        failed SELECT or EXAMINE command
   (7)  LOGOUT command, server shutdown, or connection closed

4. Data Formats ๐ŸŽ€

IMAP4rev2 uses textual commands and responses ๐Ÿ’ฌ Data can show up in a few forms: atom, number, string, parenthesized list, or NIL. A single data item can take more than one form, though. For example, a data item that uses "astring" syntax can be an atom or a string, so it's lowkey flexible ๐Ÿฆ‹

4.1. Atom โš›๏ธ

an atom is one or more non-special characters ๐ŸŒธ

4.1.1. Sequence Set and UID Set ๐Ÿ”ข

you can point at a bunch of messages with a sequence set, which holds either message sequence numbers or unique identifiers ๐Ÿงธ Check Section 9 for the details. A sequence set can have ranges like 5:50, a list of specific sequence numbers, or a mix of both. It can use the special symbol * to mean the highest sequence number in the mailbox. A sequence set NEVER holds unique identifiers, though ๐Ÿ™…โ€โ™€๏ธ

A "UID set" is basically the same idea, but it uses unique identifiers instead of message sequence numbers. It is not allowed to contain the * symbol ๐Ÿ”’

4.2. Number ๐Ÿ”Ÿ

a number is one or more digit characters that stand for a numeric value ๐Ÿ”ฅ

4.3. String ๐Ÿงต

a string comes in one of three forms: synchronizing literal, non-synchronizing literal, or quoted string ๐Ÿ’– The synchronizing literal is the general form, and it has no limits on which characters it can hold โœจ The non-synchronizing literal is also the general form, but it has a length cap ๐Ÿ™ˆ The quoted string is the shortcut that skips the literal processing overhead, but it can't hold every character ๐Ÿ’…

When the difference between synchronizing and non-synchronizing literals doesn't matter, this document just says "literal" ๐ŸŒˆ

A synchronizing literal is zero or more octets (CR and LF included) with a prefix that has the octet count in the form of an open brace ({), the number of octets, a close brace (}), and then a CRLF ๐Ÿง When the server sends a synchronizing literal to the client, the octet data comes right after the CRLF ๐Ÿ’Œ When the client sends one to the server, the client MUST wait to receive a command continuation request (more on that later in this document) before it sends the octet data and the rest of the command โณ

The non-synchronizing literal is a different flavor of synchronizing literal, and the client can use it anywhere a synchronizing literal is allowed ๐Ÿซถ The non-synchronizing literal form MUST NOT be sent from server to client ๐Ÿšซ You can tell them apart because the non-synchronizing literal has a plus (+) between the octet count and the closing brace (}) โœจ The server doesn't send a command continuation request back for a non-synchronizing literal, and clients don't have to wait before sending its octets ๐Ÿƒโ€โ™€๏ธ Unless an IMAP extension says otherwise, non-synchronizing literals MUST NOT be larger than 4096 octets ๐Ÿ“ Any literal bigger than 4096 bytes MUST be sent as a synchronizing literal ๐Ÿ”ฅ (The non-synchronizing literals in this document are the same as the ones defined by the LITERAL- extension from [RFC7888]. Read that document for how to handle invalid non-synchronizing literals longer than 4096 octets, and for how they interact with other IMAP extensions ๐Ÿ“š)

A quoted string is zero or more Unicode characters, excluding CR and LF, encoded in UTF-8, wrapped in double quotes (<">) at each end ๐ŸŽ€

The empty string can be written three ways: as "" (a quoted string with zero characters between the double quotes), as {0} followed by a CRLF (a synchronizing literal with an octet count of 0), or as {0+} followed by a CRLF (a non-synchronizing literal with an octet count of 0) ๐Ÿซง

Note: Even if the octet count is 0, a client transmitting a synchronizing literal MUST wait to receive a command continuation request. ๐Ÿ›‘

4.3.1. 8-Bit and Binary Strings ๐ŸŒ

8-bit textual and binary mail is supported through a [MIME-IMB] content transfer encoding ๐Ÿ“จ IMAP4rev2 implementations MAY transmit 8-bit or multi-octet characters in literals, but they SHOULD only do that when the [CHARSET] is identified ๐ŸŒ

IMAP4rev2 is compatible with [I18N-HDRS] ๐Ÿค So the identified charset for header-field values with 8-bit content is UTF-8 [UTF-8]. IMAP4rev2 implementations MUST accept [UTF-8] text in quoted-strings, and they MAY transmit it too, as long as the string doesn't contain NUL, CR, or LF ๐Ÿญ This is a difference from IMAP4rev1 implementations, so keep that in mind ๐Ÿ‘€

A BINARY content transfer encoding is defined, but unencoded binary strings are NOT permitted, unless they come back in a <literal8> in response to a BINARY.PEEK[<section-binary>]<<partial>> or BINARY[<section-binary>]<<partial>> FETCH data item ๐Ÿ™…โ€โ™€๏ธ A "binary string" is any string with NUL characters. A string with an excessive number of CTL characters MAY also be considered binary ๐Ÿซฃ Unless it's returned in response to a BINARY.PEEK[...]/BINARY[...] FETCH, client and server implementations MUST encode binary data into a textual form, such as base64, before transmitting it ๐Ÿ”

4.4. Parenthesized List ๐Ÿงบ

data structures are shown as a "parenthesized list": a sequence of data items, separated by spaces, and wrapped in parentheses at each end ๐ŸŽ€ A parenthesized list can contain other parenthesized lists, using multiple levels of parentheses to show nesting ๐Ÿช†

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

4.5. NIL โœจ

okay so NIL is the special form that means "this thing just isn't there" ๐Ÿซฅ It's for data items that show up as a string or a parenthesized list. It is NOT the same as "" (the empty string) or () (the empty list), which are both there, just empty ๐Ÿ’…

Note: NIL is never used for any data item that takes the form of an atom ๐Ÿšซ For example, a mailbox name of "NIL" is a mailbox named NIL, as opposed to a mailbox name that doesn't exist. That's because mailbox uses astring syntax, which is an atom or a string. Flip it around, and an addr-name of NIL is a non-existent personal name, because addr-name uses nstring syntax, which is NIL or a string, but never an atom ๐Ÿคฏ

Examples time ๐ŸŽ€

The following LIST response:

* LIST () "/" NIL

is equivalent to:

* LIST () "/" "NIL"

as LIST response ABNF is using astring for mailbox name. Iconic, right? ๐Ÿงš

However, the following response:

* FETCH 1 (BODY[1] NIL)

is NOT equivalent to:

* FETCH 1 (BODY[1] "NIL")

The former means the body part is absent ๐Ÿ‘ป, while the latter means it contains a string with the three characters "NIL". Not the same vibe at all ๐Ÿ’€


5. Operational Considerations ๐ŸŒธ

okay bestie, these are the rules we need to follow so that every IMAP4rev2 implementation actually plays nicely with the others ๐Ÿซถ

5.1. Mailbox Naming ๐Ÿ“ฌ

In IMAP4rev2, mailbox names are encoded in Net-Unicode [NET-UNICODE] (this is different from IMAP4rev1, so pay attention ๐Ÿ‘€). Client implementations MAY try to create Net-Unicode mailbox names, and they MUST interpret any 8-bit mailbox names returned by LIST as [NET-UNICODE]. Server implementations MUST prohibit the creation of 8-bit mailbox names that don't comply with Net-Unicode. Servers MAY accept a denormalized UTF-8 mailbox name, but they have to convert it to Unicode Normalization Form C (NFC) (as per Net-Unicode requirements) before creating the mailbox โœจ Servers that choose to accept those denormalized UTF-8 names MUST accept them in every IMAP command that has a mailbox name parameter. Like, SELECT <name> MUST open the same mailbox that CREATE <name> made, even if <name> is a denormalized UTF-8 mailbox name. No excuses ๐Ÿ’…

The case-insensitive mailbox name INBOX is a special name reserved to mean "the primary mailbox for this user on this server" ๐Ÿ“ฅ (Heads up: this special name might not exist on some servers for some users, for example if the user has no access to a personal namespace.) The interpretation of all other names is implementation dependent ๐Ÿคทโ€โ™€๏ธ

This specification takes NO position on case sensitivity in non-INBOX mailbox names. Some servers are fully case sensitive in the ASCII range, some preserve the case of a newly created name but are otherwise case insensitive, and others coerce names to one particular case ๐ŸŒˆ Client implementations must be able to interact with any of these. Bestie, that's the whole job ๐Ÿ˜ญ

There are certain client considerations when creating a new mailbox name:

  1. Any character that is one of the atom-specials (see "Formal Syntax" in Section 9) will require that the mailbox name be represented as a quoted string or literal ๐ŸŽ€
  2. CTL and other non-graphic characters are difficult to show in a user interface and are best avoided ๐Ÿ™ˆ Servers MAY refuse to create mailbox names containing Unicode CTL characters.
  3. Although the list-wildcard characters ("%" and "*") are valid in a mailbox name, it is difficult to use such mailbox names with the LIST command because of the conflict with wildcard interpretation ๐Ÿ’€
  4. Usually, a character (determined by the server implementation) is reserved to delimit levels of hierarchy ๐ŸŒณ
  5. Two characters, "#" and "&", have meanings by convention and should be avoided except when used in that convention. See Section 5.1.2.1 and Appendix A.1, respectively ๐Ÿฆ‹

5.1.1. Mailbox Hierarchy Naming ๐ŸŒฟ

If you want to export hierarchical mailbox names, mailbox names MUST be left-to-right hierarchical, using a single ASCII character to separate levels of hierarchy. The same hierarchy separator character is used for all levels of hierarchy within a single name. One separator, all the way down ๐Ÿงš

5.1.2. Namespaces ๐Ÿ—‚๏ธ

Personal Namespace: A namespace that the server considers within the personal scope of the authenticated user on a particular connection. Typically, only the authenticated user has access to mailboxes in their Personal Namespace ๐Ÿ’– It's the part of the namespace that belongs to the user and is set aside for mailboxes. If an INBOX exists for a user, it MUST appear within the user's Personal Namespace. In the typical case, there SHOULD be only one Personal Namespace per user on a server.

Other Users' Namespace: A namespace that consists of mailboxes from the Personal Namespaces of other users. To access mailboxes in the Other Users' Namespace, the currently authenticated user MUST be explicitly granted access rights. For example, it's super common for a manager to grant their admin support staff access to their mailbox ๐Ÿ’ผ In the typical case, there SHOULD be only one Other Users' Namespace per user on a server.

Shared Namespace: A namespace that consists of mailboxes that are meant to be shared amongst users and do NOT exist within a user's Personal Namespace ๐Ÿค

The namespaces a server uses MAY differ on a per-user basis ๐ŸŒˆ

5.1.2.1. Historic Mailbox Namespace Naming Convention ๐Ÿ“œ

By convention, the first hierarchical element of any mailbox name that begins with "#" identifies the "namespace" of the rest of the name. This makes it possible to tell apart different types of mailbox stores, each of which has its own namespaces ๐Ÿ”

For example, implementations that offer access to USENET newsgroups MAY use the "#news" namespace to keep the USENET newsgroup namespace separate from other mailboxes. So the comp.mail.misc newsgroup would have a mailbox name of "#news.comp.mail.misc", and the name "comp.mail.misc" can refer to a different object (e.g., a user's private mailbox) ๐Ÿ—ž๏ธ

Namespaces that include the "#" character are not IMAP URL [IMAP-URL] friendly and need the "#" character to be written as %23 inside URLs ๐Ÿ˜ฌ Because of that, server implementors MAY instead consider using namespace prefixes that don't contain the "#" character.

5.1.2.2. Common Namespace Models ๐Ÿ›๏ธ

The previous version of this protocol did not define a default server namespace, so two common namespace models have evolved ๐ŸŒฑ

The "Personal Mailbox" model is where the default namespace presented consists of only the user's personal mailboxes. To reach shared mailboxes, the user has to use an escape mechanism to get to another namespace ๐Ÿšช

The "Complete Hierarchy" model is where the default namespace presented includes the user's personal mailboxes along with any other mailboxes they have access to ๐ŸŒŸ

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

At any time, a server can send data that the client didn't ask for ๐Ÿ‘€ Sometimes this behavior is required by this specification and/or extensions. For example, other agents besides the server may add messages to the mailbox (like new message delivery), change the flags of messages in the mailbox (like simultaneous access to the same mailbox by multiple agents), or even remove messages from the mailbox. A server MUST send mailbox size updates automatically if a mailbox size change is observed while processing a command. A server SHOULD send message flag updates automatically, without the client having to request them explicitly ๐Ÿ”ฅ

There are special rules for server notification of a client about the removal of messages, to prevent synchronization errors. See the description of the EXPUNGE response (Section 7.5.1) for more detail ๐Ÿ’… In particular, it is NOT permitted to send an EXISTS response that would reduce the number of messages in the mailbox. Only the EXPUNGE response can do that ๐Ÿ™…โ€โ™€๏ธ

Whatever a client decides about remembering data from the server, a client implementation MUST remember mailbox size updates. It MUST NOT assume that any command after the initial mailbox selection will return the size of the mailbox ๐Ÿง 

5.3. Response When No Command in Progress โณ

Server implementations are allowed to send an untagged response (except for EXPUNGE) while no command is 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 does not 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 applies to sessions after authentication, the duration of that timer MUST be at least 30 minutes. Any command the client sends during that interval resets the autologout timer ๐Ÿซง

Note that this specification doesn't put any restrictions on an autologout timer used before successful client authentication ๐Ÿ’œ In particular, servers are allowed to use a shortened pre-authentication timer to protect themselves from Denial-of-Service attacks ๐Ÿ›ก๏ธ

5.5. Multiple Commands in Progress (Command Pipelining) โœจ

Okay so, the client is allowed to fire off another command without waiting for the completion result of the one before it ๐Ÿš€. That's the vibe, but it's subject to ambiguity rules and to flow control on the underlying data stream. The server gets the same freedom: it can start working on another command before it finishes the current one, still subject to those ambiguity rules. BUT, and this is a big but, any command continuation request responses and command continuations MUST be negotiated before any subsequent command is initiated ๐Ÿซถ.

The exception is when an ambiguity would happen because one command would change the results of other commands. If the server spots a possible ambiguity, it MUST execute commands to completion in the order the client gave them ๐Ÿ™ˆ.

The most obvious example of ambiguity is when one command would affect the results of another. Like, a FETCH that sets \Seen flags, followed by a SEARCH UNSEEN command. Literally the same messages are involved, so the order matters ๐Ÿ’€.

Now the non-obvious one, and this is where it gets spicy ๐ŸŒถ๏ธ. Commands that are allowed to get an untagged EXPUNGE response (so, anything other than FETCH, STORE, and SEARCH) can cause trouble, because an untagged EXPUNGE response can invalidate sequence numbers in a later command. FETCH, STORE, and SEARCH are fine, though, because servers are prohibited from sending EXPUNGE responses while any of those commands are in progress. So if the client sends any command other than FETCH, STORE, or SEARCH, it MUST wait for the completion result response before sending a command that uses message sequence numbers ๐ŸŽ€.

Note: EXPUNGE responses are permitted while UID FETCH, UID STORE, and UID SEARCH are in progress. If the client sends a UID command, it MUST wait for a completion result response before sending a command that uses message sequence numbers (this may include UID SEARCH). Any message sequence numbers in an argument to UID SEARCH are associated with messages prior to the effect of any untagged EXPUNGE responses returned by the UID SEARCH.

Here are the non-waiting sequences that are INVALID (no cap, these are a no-go ๐Ÿ™…โ€โ™€๏ธ):

FETCH + NOOP + STORE

STORE + COPY + FETCH

COPY + COPY

And these are the valid non-waiting sequences, the ones you can actually use โœจ:

FETCH + STORE + SEARCH + NOOP

STORE + COPY + EXPUNGE

UID SEARCH + UID SEARCH is giving "it depends" ๐Ÿคทโ€โ™€๏ธ. It may be valid or invalid as a non-waiting command sequence, depending on whether or not the second UID SEARCH contains message sequence numbers.

Last thing: using a SEARCH result variable (see Section 6.4.4.1) creates a direct dependency between two commands, so they're basically linked. For more considerations about pipelining dependent commands like that, check Section 6.4.4.2 ๐Ÿงš.


6. Client Commands ๐Ÿ‘‘

Okay this is where the actual commands live ๐Ÿ’…. They're organised by the state in which each one is allowed. Commands that are allowed in multiple states get listed under the minimum permitted state. So anything valid in both authenticated and selected states shows up in the authenticated state commands ๐ŸŒธ.

The arguments of each command, the ones marked "Arguments:" in the descriptions below, are described by what they do, not by their syntax. The precise syntax lives in "Formal Syntax" (Section 9) ๐Ÿฆ‹.

Some commands make specific server responses come back. Those are marked "Responses:" below. For what those responses mean, look in "Responses" (Section 7), and for their exact syntax, look in "Formal Syntax" (Section 9) ๐Ÿ’œ. Server data can show up as a result of ANY command, so commands that don't specifically need server data say "no specific responses for this command" instead of "none". Iconic honesty ๐Ÿ˜ญ.

The "Result:" line refers to the possible tagged status responses to a command, plus any special meaning those status responses have ๐ŸŽ€.

A connection's state only changes through successful commands that are documented as changing state. A rejected command (BAD response) NEVER changes the state of the connection or the selected mailbox, so that's a hard no ๐Ÿ™…โ€โ™€๏ธ. A failed command (NO response) usually doesn't change the state either, with the exception of SELECT and EXAMINE ๐Ÿ“.

6.1. Client Commands - Any State ๐ŸŒˆ

The following commands are valid in any state: CAPABILITY, NOOP, and LOGOUT. Main character commands, always available โญ.

6.1.1. CAPABILITY Command ๐Ÿ’–

Arguments:    none

Responses:    REQUIRED untagged response:  CAPABILITY

Result:       OK -  capability completed
              BAD -  arguments invalid

The CAPABILITY command asks the server for a list of its capabilities (extensions and/or changes to how the server behaves). The server MUST send a single untagged CAPABILITY response that includes "IMAP4rev2" as one of the listed capabilities, and it has to do that before the (tagged) OK response ๐Ÿงš.

A capability name that starts with "AUTH=" means the server supports that particular authentication mechanism, as defined in the Simple Authentication and Security Layer (SASL) [SASL]. All of those names are, by definition, part of this specification ๐Ÿ”.

Other capability names refer to extensions, revisions, or amendments to this specification. The CAPABILITY response in Section 7.2.2 has more info on those. If the IMAP4rev1 capability isn't advertised, then no capabilities beyond the base IMAP4rev2 set in this specification are enabled unless the client explicitly does something to invoke them. If BOTH IMAP4rev1 and IMAP4rev2 capabilities are advertised, then no capabilities beyond the base IMAP4rev1 set specified in [RFC3501] are enabled unless the client explicitly invokes them ๐Ÿฆ‹.

Client and server implementations MUST implement the STARTTLS (Section 6.2.1) and LOGINDISABLED capabilities on cleartext ports. Client and server implementations MUST ALSO implement the AUTH=PLAIN capability (described in [PLAIN]) on both cleartext and Implicit TLS ports. Go read the Security Considerations (Section 11) for the important stuff, seriously ๐Ÿ”ฅ.

Unless otherwise specified, all registered extensions to IMAP4rev1 are also valid extensions to IMAP4rev2 โœจ.

Example:

C: abcd CAPABILITY
S: * CAPABILITY IMAP4rev2 STARTTLS AUTH=GSSAPI
 LOGINDISABLED
S: abcd OK CAPABILITY completed
C: efgh STARTTLS
S: efgh OK STARTTLS completed
<TLS negotiation, further commands are under TLS layer>
C: ijkl CAPABILITY
S: * CAPABILITY IMAP4rev2 AUTH=GSSAPI AUTH=PLAIN
S: ijkl OK CAPABILITY completed

6.1.2. NOOP Command ๐Ÿ™ˆ

Arguments:    none

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

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

The NOOP command always succeeds. It does nothing. Iconic energy ๐Ÿ’….

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 (the IDLE command; see Section 6.3.13) should be used instead of NOOP if real-time updates to mailbox state are desirable). 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: * 14 FETCH (UID 1305 FLAGS (\Seen \Deleted))
S: a047 OK NOOP completed

6.1.3. LOGOUT Command ๐Ÿ‘‹

Arguments:    none

Responses:    REQUIRED untagged response:  BYE

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

The LOGOUT command tells the server the client is done with the connection ๐Ÿงšโ€โ™€๏ธ. The server MUST send a BYE untagged response before the (tagged) OK response, and then close the network connection.

Example:

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

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

In the not authenticated state, the AUTHENTICATE or LOGIN command establishes authentication and moves you into the authenticated state ๐Ÿšช. AUTHENTICATE is the general-purpose option, covering a whole bunch of authentication techniques, privacy protection, and integrity checking. LOGIN uses a regular user name and plaintext password pair, and it has NO way to establish privacy protection or integrity checking, so it's the least fancy option ๐Ÿซฃ.

The STARTTLS command is another way to set up session privacy protection and integrity checking. It does NOT, by itself, establish authentication or move you into the authenticated state ๐Ÿ”’.

Server implementations MAY allow access to certain mailboxes without establishing authentication. This can be done with the ANONYMOUS [SASL] authenticator described in [ANONYMOUS]. An older convention is a LOGIN command using the userid "anonymous". In that case a password is required, although the server may choose to accept any password. The restrictions on anonymous users are implementation dependent ๐ŸŒธ.

Once you've authenticated (including as anonymous), it is not possible to re-enter the not authenticated state. No going back, bestie ๐Ÿ’€.

In addition to the universal commands (CAPABILITY, NOOP, and LOGOUT), these commands are valid in the not authenticated state: STARTTLS, AUTHENTICATE, and LOGIN. Read the Security Considerations (Section 11) for important information about these commands ๐Ÿ”ฅ.

6.2.1. STARTTLS Command โœจ

  • Arguments: none
  • Responses: no specific response for this command
  • Result:
OK -  starttls completed, begin TLS negotiation
NO -  TLS negotiation can't be initiated, due to server
   configuration error
BAD -  STARTTLS received after a successful TLS
   negotiation or arguments invalid

Okay so, STARTTLS only works on cleartext ports ๐Ÿงš. The server MUST always respond with a tagged BAD response when it gets the STARTTLS command on an Implicit TLS port. That's a hard no, bestie ๐Ÿ™ˆ.

The TLS [TLS-1.3] negotiation kicks off right after the CRLF at the end of the server's tagged OK response. Once the client sends STARTTLS, it MUST NOT issue any more commands until it sees a server response and the TLS negotiation is finished. Lowkey, this part is so important ๐Ÿ’….

Some older server implementations messed up their STARTTLS processing and are known to have a STARTTLS plaintext command injection vulnerability [CERT-555316] ๐Ÿ’€. To avoid that, server implementations MUST do one of the following if any data shows up in the same TCP buffer after the CRLF that starts the STARTTLS command:

  1. Extra data from the TCP buffer is interpreted as the beginning of the TLS handshake. (If the data is in cleartext, this will result in the TLS handshake failing.)
  2. Extra data from the TCP buffer is thrown away.

Option one is the friendlier one for clients that pipeline the start of the STARTTLS command with TLS handshake data ๐Ÿซถ.

After a successful TLS negotiation, the server stays in the non-authenticated state, even if the client supplies credentials during the TLS negotiation. That doesn't block an authentication mechanism like EXTERNAL (defined in [SASL]) from using the client identity that came out of the TLS negotiation โœจ.

Once TLS has started, the client MUST discard cached information about server capabilities and SHOULD reissue the CAPABILITY command. This is needed to protect against active attacks that change the capabilities list before STARTTLS ๐Ÿ›ก๏ธ. The server MAY advertise different capabilities. In particular, after a successful STARTTLS command it SHOULD NOT advertise the STARTTLS capability ๐ŸŒธ.

Example:

   C: a001 CAPABILITY
   S: * CAPABILITY IMAP4rev2 STARTTLS LOGINDISABLED
   S: a001 OK CAPABILITY completed
   C: a002 STARTTLS
   S: a002 OK Begin TLS negotiation now
   <TLS negotiation, further commands are under TLS layer>
   C: a003 CAPABILITY
   S: * CAPABILITY IMAP4rev2 AUTH=PLAIN
   S: a003 OK CAPABILITY completed
   C: a004 AUTHENTICATE PLAIN dGVzdAB0ZXN0AHRlc3Q=
   S: a004 OK Success (tls protection)

6.2.2. AUTHENTICATE Command โœจ

Arguments:    SASL authentication mechanism name

              OPTIONAL initial response

Responses:    continuation data can be requested

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

okay so AUTHENTICATE is the command where the client basically goes "hey, I wanna log in with THIS [SASL] authentication mechanism" ๐Ÿ” If the server supports that mechanism, it runs a whole authentication exchange to authenticate and identify the client. It MAY also negotiate an OPTIONAL security layer for everything that comes after ๐Ÿซถ If the requested mechanism isn't supported, the server SHOULD reject the AUTHENTICATE command by sending a tagged NO response. Not the vibe ๐Ÿ’€

The AUTHENTICATE command supports the optional "initial response" feature defined in Section 4 of [SASL] โœจ The client doesn't need to use it. If a SASL mechanism supports "initial response" but the client doesn't specify one, the server handles it as specified in Section 3 of [SASL].

The service name specified by this protocol's profile of [SASL] is "imap" ๐Ÿ“

The authentication exchange is a back-and-forth of server challenges and client responses, and they're specific to whichever mechanism you picked ๐Ÿ’ฌ A server challenge is a command continuation request response with the + token, followed by a base64-encoded (see Section 4 of [RFC4648]) string. The client response is a single line holding a base64-encoded string. If the client wants to bail on the exchange, it sends a line that's just *. If the server gets that, or gets an invalid base64 string (like characters outside the base64 alphabet or a non-terminal =), it MUST reject the AUTHENTICATE command by sending a tagged BAD response. Big no-no zone ๐Ÿ™…โ€โ™€๏ธ

As with any other client response, the initial response MUST be encoded as base64 ๐Ÿ’… It also MUST be transmitted outside of a quoted string or literal. To send a zero-length initial response, the client MUST send a single pad character (=). That's how it says "the response is here, it's just empty" ๐Ÿงš

When decoding the base64 data in the initial response, decoding errors MUST be treated like they would be for any normal SASL client response, which means a tagged BAD response ๐Ÿ˜ญ The server should also check for any characters that aren't in the base64 alphabet, plus any base64 sequence that has the pad character ('=') somewhere other than the end of the string. So =AAA and AAA=BBB are both a no-go ๐Ÿ™ˆ

If the client sends an initial response with a SASL mechanism that doesn't support one, the server MUST reject the command with a tagged BAD response ๐Ÿšซ

If a security layer gets negotiated through the [SASL] authentication exchange, it kicks in right after the CRLF that wraps up the exchange on the client side, and the CRLF of the tagged OK response on the server side ๐Ÿ”’

While client and server implementations MUST implement the AUTHENTICATE command itself, they're NOT required to implement any authentication mechanisms other than PLAIN, which is described in [PLAIN] ๐ŸŒˆ Also, an authentication mechanism doesn't have to support any security layers at all.

Note: a server implementation MUST implement a configuration in which it does NOT permit any plaintext password mechanisms, unless the STARTTLS command has been negotiated, TLS has been negotiated on an Implicit TLS port, or some other mechanism that protects the session from password snooping has been provided. Server sites SHOULD NOT use any configuration that permits a plaintext password mechanism without such a protection mechanism against password snooping. Client and server implementations SHOULD implement additional [SASL] mechanisms that do not use plaintext passwords, such as the GSSAPI mechanism described in [RFC4752], the SCRAM-SHA-256/SCRAM-SHA-256-PLUS [SCRAM-SHA-256] mechanisms, and/or the EXTERNAL [SASL] mechanism for mutual TLS authentication. (Note that the SASL framework allows for the creation of SASL mechanisms that support 2-factor authentication (2FA); however, none are fully ready to be recommended by this document.)

Plaintext passwords are a whole security nightmare, so please, bestie, don't set up your server to allow them unless something is protecting the session ๐Ÿ‘‘

Servers and clients can support multiple authentication mechanisms ๐Ÿฆ‹ The server SHOULD list its supported authentication mechanisms in the response to the CAPABILITY command so the client knows which ones to pick from.

A server MAY include a CAPABILITY response code in the tagged OK response of a successful AUTHENTICATE command, so it can send capabilities automatically โœจ It's unnecessary for the client to send a separate CAPABILITY command if it already recognizes those automatic capabilities. This should only be done if a security layer wasn't negotiated by the AUTHENTICATE command, because the tagged OK response from an AUTHENTICATE command isn't protected by encryption or integrity checking. [SASL] requires the client to re-issue a CAPABILITY command in this case. The server MAY advertise different capabilities after a successful AUTHENTICATE command ๐Ÿ‘€

If an AUTHENTICATE command fails with a NO response, the client MAY try another authentication mechanism by issuing another AUTHENTICATE command ๐Ÿ” It MAY also attempt to authenticate using the LOGIN command (see Section 6.2.3 for more detail). In other words, the client MAY request authentication types in decreasing order of preference, with the LOGIN command as a last resort ๐Ÿซ 

The authorization identity passed from the client to the server during the authentication exchange gets interpreted by the server as the user name whose privileges the client is requesting ๐Ÿ‘‘

Example:

S: * OK [CAPABILITY IMAP4rev2 STARTTLS AUTH=GSSAPI]
 Capabilities
C: A001 AUTHENTICATE GSSAPI
S: +
C: YIIB+wYJKoZIhvcSAQICAQBuggHqMIIB5qADAgEFoQMCAQ6iBw
   MFACAAAACjggEmYYIBIjCCAR6gAwIBBaESGxB1Lndhc2hpbmd0
   b24uZWR1oi0wK6ADAgEDoSQwIhsEaW1hcBsac2hpdmFtcy5jYW
   Mud2FzaGluZ3Rvbi5lZHWjgdMwgdCgAwIBAaEDAgEDooHDBIHA
   cS1GSa5b+fXnPZNmXB9SjL8Ollj2SKyb+3S0iXMljen/jNkpJX
   AleKTz6BQPzj8duz8EtoOuNfKgweViyn/9B9bccy1uuAE2HI0y
   C/PHXNNU9ZrBziJ8Lm0tTNc98kUpjXnHZhsMcz5Mx2GR6dGknb
   I0iaGcRerMUsWOuBmKKKRmVMMdR9T3EZdpqsBd7jZCNMWotjhi
   vd5zovQlFqQ2Wjc2+y46vKP/iXxWIuQJuDiisyXF0Y8+5GTpAL
   pHDc1/pIGmMIGjoAMCAQGigZsEgZg2on5mSuxoDHEA1w9bcW9n
   FdFxDKpdrQhVGVRDIzcCMCTzvUboqb5KjY1NJKJsfjRQiBYBdE
   NKfzK+g5DlV8nrw81uOcP8NOQCLR5XkoMHC0Dr/80ziQzbNqhx
   O6652Npft0LQwJvenwDI13YxpwOdMXzkWZN/XrEqOWp6GCgXTB
   vCyLWLlWnbaUkZdEYbKHBPjd8t/1x5Yg==
S: + YGgGCSqGSIb3EgECAgIAb1kwV6ADAgEFoQMCAQ+iSzBJoAMC
   AQGiQgRAtHTEuOP2BXb9sBYFR4SJlDZxmg39IxmRBOhXRKdDA0
   uHTCOT9Bq3OsUTXUlk0CsFLoa8j+gvGDlgHuqzWHPSQg==
C:
S: + YDMGCSqGSIb3EgECAgIBAAD/////6jcyG4GE3KkTzBeBiVHe
   ceP2CWY0SR0fAQAgAAQEBAQ=
C: YDMGCSqGSIb3EgECAgIBAAD/////3LQBHXTpFfZgrejpLlLImP
   wkhbfa2QteAQAgAG1yYwE=
S: A001 OK GSSAPI authentication successful

Now the next one, the initial response example ๐ŸŽ€

S: * OK [CAPABILITY IMAP4rev2 STARTTLS AUTH=GSSAPI
 LOGINDISABLED] Server ready
C: A01 STARTTLS
S: A01 OK STARTTLS completed
<TLS negotiation, further commands are under TLS layer>
C: A02 CAPABILITY
S: * CAPABILITY IMAP4rev2 AUTH=GSSAPI AUTH=PLAIN
S: A02 OK CAPABILITY completed
C: A03 AUTHENTICATE PLAIN dGVzdAB0ZXN0AHRlc3Q=
S: A03 OK Success (tls protection)

Because the initial response is optional, the negotiation that skips it is still totally valid, and the server MUST support it ๐Ÿซถ Here it is:

... client connects to server and negotiates a TLS
    protection layer ...
C: C01 CAPABILITY
S: * CAPABILITY IMAP4rev2 AUTH=PLAIN
S: C01 OK Completed
C: A01 AUTHENTICATE PLAIN
S: +
C: dGVzdAB0ZXN0AHRlc3Q=
S: A01 OK Success (tls protection)

Heads up, in the example above there's a space after the server's "+" ๐Ÿ‘€

Last one, using SASL EXTERNAL under a TLS protection layer with an empty initial response ๐Ÿฆ‹

... client connects to server and negotiates a TLS
    protection layer ...
C: C01 CAPABILITY
S: * CAPABILITY IMAP4rev2 AUTH=PLAIN AUTH=EXTERNAL
S: C01 OK Completed
C: A01 AUTHENTICATE EXTERNAL =
S: A01 OK Success (tls protection)
Note: The line breaks within server challenges and client responses are for editorial clarity and are not in real authenticators.

6.2.3. LOGIN Command ๐Ÿ”‘

Arguments:    user name

              password

Responses:    no specific responses for this command

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

The LOGIN command identifies the client to the server and carries the plaintext password for this user ๐Ÿ˜ฌ The LOGIN command SHOULD NOT be used except as a last resort (after attempting and failing to authenticate with AUTHENTICATE one or more times), and it is recommended that client implementations have a way to turn off any automatic use of the LOGIN command. Last resort energy only, periodt ๐Ÿ’€

A server MAY include a CAPABILITY response code in the tagged OK response to a successful LOGIN command, so it can send capabilities automatically โœจ It's unnecessary for a client to send a separate CAPABILITY command if it recognizes these automatic capabilities.

Example:

C: a001 LOGIN SMITH SESAME
S: a001 OK LOGIN completed
Note: Use of the LOGIN command over an insecure network (such as the Internet) is a security risk, because anyone monitoring network traffic can obtain plaintext passwords. For that reason, clients MUST NOT use LOGIN on unsecure networks. ๐Ÿšจ

Unless the client is accessing IMAP service on an Implicit TLS port [RFC8314], the STARTTLS command has been negotiated, or some other mechanism that protects the session from password snooping has been provided, a server implementation MUST implement a configuration in which it advertises the LOGINDISABLED capability and does NOT permit the LOGIN command ๐Ÿ™…โ€โ™€๏ธ Server sites SHOULD NOT use any configuration that permits the LOGIN command without such a protection mechanism against password snooping. A client implementation MUST NOT send a LOGIN command if the LOGINDISABLED capability is advertised. Respect the LOGINDISABLED ๐Ÿซถ


6.3. Client Commands - Authenticated State ๐ŸŒธ

In the authenticated state, commands that manipulate mailboxes as atomic entities are permitted โœจ Of those, SELECT and EXAMINE will select a mailbox for access and move you into the selected state ๐Ÿงš

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

6.3.1. ENABLE Command โœจ

Arguments: capability names

Responses: no specific responses for this command

Result:

  • OK - Relevant capabilities enabled
  • BAD - No arguments, or syntax error in an argument

Okay so, a lot of IMAP extensions let the server send special unsolicited responses, right? But the server can't send those until it knows the client actually speaks that extension, otherwise the client would get data it can't parse ๐Ÿ˜ญ. The one exception is response codes (see Section 7.1) tucked inside tagged or untagged OK/NO/BAD responses, since those are always allowed ๐Ÿ’….

So ENABLE is the client's way of saying "hey, I support these" ๐Ÿซถ. It's designed so the client can send one simple constant string listing the extensions it knows, and the server turns on the shared subset that both of them support. Iconic, right? ๐Ÿฆ‹

The ENABLE command takes a list of capability names and asks the server to switch those extensions on. Once something is enabled with ENABLE, it stays on until the IMAP connection closes. For each argument, the server does the following:

  • If the argument is not an extension known to the server, the server MUST ignore the argument.
  • If the argument is an extension known to the server, and it is not specifically permitted to be enabled using ENABLE, the server MUST ignore the argument. (Note that knowing about an extension doesn't necessarily imply supporting that extension. ๐Ÿ™ˆ)
  • If the argument is an extension that is supported by the server and that needs to be enabled, the server MUST enable the extension for the duration of the connection. Note that once an extension is enabled, there is no way to disable it. No take-backs, bestie ๐Ÿ’€.

If the ENABLE command is successful, the server MUST send an untagged ENABLED response (Section 7.2.1), which includes all enabled extensions as specified above. The ENABLED response is sent even if no extensions were enabled, so you'll always get one back โœจ.

Clients SHOULD only include extensions that need to be enabled by the server. For example, a client can enable IMAP4rev2-specific behavior when both IMAP4rev1 and IMAP4rev2 are advertised in the CAPABILITY response. Future RFCs may add to this list ๐ŸŒˆ.

The ENABLE command is only valid in the authenticated state, before any mailbox is selected. Clients MUST NOT issue ENABLE once they SELECT/EXAMINE a mailbox. Servers don't have to check whether a mailbox was selected or previously selected during the connection, though ๐Ÿ‘€.

The ENABLE command can be issued multiple times in a session, and it's additive. So "ENABLE a b", followed by "ENABLE c", is the same as one single command "ENABLE a b c" ๐Ÿงš. When multiple ENABLE commands are issued, each corresponding ENABLED response SHOULD only contain extensions enabled by that particular ENABLE command. So for the example above, the ENABLED response to "ENABLE c" should not contain "a" or "b" ๐Ÿ“.

There are no limitations on pipelining ENABLE. For example, you can send ENABLE and then immediately SELECT, or send a LOGIN immediately followed by ENABLE ๐Ÿš€.

The server MUST NOT change the CAPABILITY list as a result of executing ENABLE. That means a CAPABILITY command issued right after an ENABLE command MUST list the same capabilities as a CAPABILITY command issued before the ENABLE command. Here's how that plays out. Note that "X-GOOD-IDEA" below is a fictitious extension capability that can be ENABLED ๐ŸŽ€.

  C: t1 CAPABILITY
  S: * CAPABILITY IMAP4rev2 ID LITERAL+ X-GOOD-IDEA
  S: t1 OK foo
  C: t2 ENABLE CONDSTORE X-GOOD-IDEA
  S: * ENABLED X-GOOD-IDEA
  S: t2 OK foo
  C: t3 CAPABILITY
  S: * CAPABILITY IMAP4rev2 ID LITERAL+ X-GOOD-IDEA
  S: t3 OK foo again

In the following example, the client enables the Conditional Store (CONDSTORE) extension [RFC7162] ๐Ÿ’–:

  C: a1 ENABLE CONDSTORE
  S: * ENABLED CONDSTORE
  S: a1 OK Conditional Store enabled

6.3.1.1. Note to Designers of Extensions That May Use the ENABLE Command

Extension designers, listen up ๐Ÿ“ฃ. You're discouraged from making extensions that require ENABLE, unless there's truly no good alternative design. Extensions that cause potentially incompatible behavior changes to deployed server responses (and therefore benefit from ENABLE) have a higher complexity cost than extensions that don't. So think twice before you go there ๐Ÿ™ˆ.


6.3.2. SELECT Command ๐Ÿ’…

Arguments: mailbox name

Responses:

  • REQUIRED untagged responses: FLAGS, EXISTS, LIST
  • REQUIRED OK untagged responses: PERMANENTFLAGS, UIDNEXT, UIDVALIDITY

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

The SELECT command picks a mailbox so you can access the messages inside it ๐Ÿ“ฌ. Before the server returns an OK to the client, it MUST send the following untagged data. (The order of the individual responses doesn't matter, fr.) Heads up: earlier versions of this protocol, like the IMAP4rev1 version specified in [RFC2060], only required the FLAGS and EXISTS untagged responses and the UIDVALIDITY response code. So if your client needs to stay compatible with those older versions, you'll have to build default behavior for missing data, as discussed with each individual item ๐Ÿฅน.

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

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

LIST The server MUST return a LIST response with the mailbox name. The list of mailbox attributes MUST be accurate ๐Ÿ’ฏ. If the server allows denormalized UTF-8 mailbox names (see Section 5.1) and the supplied mailbox name differs from the normalized version, the server MUST return LIST with the OLDNAME extended data item. See Section 6.3.9.7 for more details.

OK [PERMANENTFLAGS (<list of flags>)] A list of message flags that the client can change permanently. If this is missing, the client should assume that all flags can be changed permanently.

OK [UIDNEXT <n>] The next unique identifier value. Refer to Section 2.3.1.1 for more information.

OK [UIDVALIDITY <n>] The unique identifier validity value. Refer to Section 2.3.1.1 for more information.

Only one mailbox can be selected at a time in a connection. If you want simultaneous access to multiple mailboxes, you need multiple connections ๐Ÿ™Œ. The SELECT command automatically deselects any currently selected mailbox before it attempts the new selection. So if a mailbox is selected and a SELECT command that fails gets attempted, no mailbox is selected anymore ๐Ÿ˜ฌ. When deselecting a selected mailbox, the server MUST return an untagged OK response with the "[CLOSED]" response code when the currently selected mailbox is closed (see Section 7.1).

If the client is permitted to modify the mailbox, the server SHOULD prefix the text of the tagged OK response with the "[READ-WRITE]" response code โœ๏ธ.

If the client is not permitted to 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 differs from the EXAMINE command in that certain read-only mailboxes MAY permit the change of permanent state on a per-user (as opposed to global) basis. Netnews messages marked in a server-based .newsrc file are an example of that kind of per-user permanent state, which can be modified even with read-only mailboxes ๐Ÿ—ž๏ธ.

Example:

  C: A142 SELECT INBOX
  S: * 172 EXISTS
  S: * OK [UIDVALIDITY 3857529045] UIDs valid
  S: * OK [UIDNEXT 4392] Predicted next UID
  S: * FLAGS (\Answered \Flagged \Deleted \Seen \Draft)
  S: * OK [PERMANENTFLAGS (\Deleted \Seen \*)] Limited
  S: * LIST () "/" INBOX
  S: A142 OK [READ-WRITE] SELECT completed

Example:

  C: A142 SELECT INBOX
  S: * 172 EXISTS
  S: * OK [UIDVALIDITY 3857529045] UIDs valid
  S: * OK [UIDNEXT 4392] Predicted next UID
  S: * FLAGS (\Answered \Flagged \Deleted \Seen \Draft)
  S: * OK [PERMANENTFLAGS (\Deleted \Seen \*)] Limited
  S: A142 OK [READ-WRITE] SELECT completed
  [...some time later...]
  C: A143 SELECT Drafts
  S: * OK [CLOSED] Previous mailbox is now closed
  S: * 5 EXISTS
  S: * OK [UIDVALIDITY 9877410381] UIDs valid
  S: * OK [UIDNEXT 102] Predicted next UID
  S: * LIST () "/" Drafts
  S: * FLAGS (\Answered \Flagged \Deleted \Seen \Draft)
  S: * OK [PERMANENTFLAGS (\Deleted \Seen \Answered
      \Flagged \Draft \*)] System flags and keywords allowed
  S: A143 OK [READ-WRITE] SELECT completed

Note that IMAP4rev1-compliant servers can also send the untagged RECENT response that was deprecated in IMAP4rev2, e.g., "* 0 RECENT". Pure IMAP4rev2 clients are advised to ignore the untagged RECENT response ๐Ÿงน.


6.3.3. EXAMINE Command ๐Ÿ”

Arguments: mailbox name

Responses:

  • REQUIRED untagged responses: FLAGS, EXISTS, LIST
  • REQUIRED OK untagged responses: PERMANENTFLAGS, UIDNEXT, UIDVALIDITY

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

The EXAMINE command is identical to SELECT and returns the same output. The difference is that the selected mailbox is identified as read-only ๐Ÿ‘€. No changes to the permanent state of the mailbox are permitted, including per-user state. Hands off, no edits allowed ๐Ÿ™…โ€โ™€๏ธ.

The text of the tagged OK response to the EXAMINE command MUST begin with the "[READ-ONLY]" response code.

Example:

   C: A932 EXAMINE blurdybloop
   S: * 17 EXISTS
   S: * OK [UIDVALIDITY 3857529045] UIDs valid
   S: * OK [UIDNEXT 4392] Predicted next UID
   S: * LIST () "/" blurdybloop
   S: * FLAGS (\Answered \Flagged \Deleted \Seen \Draft)
   S: * OK [PERMANENTFLAGS ()] No permanent flags permitted
   S: A932 OK [READ-ONLY] EXAMINE completed

6.3.4. CREATE Command โœจ

Arguments:    mailbox name

Responses:    OPTIONAL untagged response:  LIST

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

okay so CREATE is how you make a brand new mailbox ๐Ÿ“ฌ๐ŸŽ€ You only get an OK back if a new mailbox with that name actually got made. Trying to create INBOX, or a name that already belongs to a mailbox, is an error, and any creation problem comes back as a tagged NO ๐Ÿ’€ If a client sends a UTF-8 mailbox name that isn't a valid Net-Unicode name, the server MUST reject the creation or convert the name to Net-Unicode before making the mailbox. If the server does decide to normalize the name, it SHOULD send back an untagged LIST with an OLDNAME extended data item. The OLDNAME value is the name the client sent, and the name parameter is the normalized one ๐Ÿงš (Check Section 6.3.9.7 for the full details.)

Mailboxes created in one IMAP session MAY be announced to other IMAP sessions with an unsolicited LIST response ๐Ÿฆ‹ If the server automatically subscribes a mailbox when it gets created, then the unsolicited LIST response for each affected subscribed mailbox name MUST include the \Subscribed attribute. Main character energy for sure ๐Ÿ‘‘

If the mailbox name ends with the server's hierarchy separator character (the one the server returned from LIST), that's the client saying "I plan to make names under this one." Servers that don't need that heads-up MUST ignore it. Either way, the name that actually gets created doesn't include the trailing hierarchy delimiter ๐ŸŒธ

If the hierarchy separator shows up somewhere in the middle of the name, the server SHOULD create any superior hierarchical names the CREATE command needs in order to finish successfully. So creating "foo/bar/zap" on a server where "/" is the separator SHOULD make foo/ and foo/bar/ if they don't already exist. It's giving nested folders ๐Ÿ—‚๏ธโœจ

If a new mailbox gets the same name as one that was deleted, its unique identifiers MUST be greater than any unique identifiers used in the previous incarnation of the mailbox. The exception is when the new incarnation has a different unique identifier validity value. Check Section 6.4.9 for more on the UID command ๐Ÿ”ฅ

Example:

C: A003 CREATE owatagusiam/
S: A003 OK CREATE completed
C: A004 CREATE owatagusiam/blurdybloop
S: A004 OK CREATE completed
C: A005 CREATE NonNormalized
S: * LIST () "/" "Normalized" ("OLDNAME" ("NonNormalized"))
S: A005 OK CREATE completed

Okay the last example is a bit of a plot twist ๐Ÿ™ˆ Picture "NonNormalized" as a non-NFC normalized Unicode name, and "Normalized" as its NFC version.

   |  Note: The interpretation of this example depends on whether "/"
   |  was returned as the hierarchy separator from LIST.  If "/" is
   |  the hierarchy separator, a new level of hierarchy named
   |  "owatagusiam" with a member called "blurdybloop" is created.
   |  Otherwise, two mailboxes at the same hierarchy level are
   |  created.

6.3.5. DELETE Command ๐Ÿ’…

Arguments:    mailbox name

Responses:    OPTIONAL untagged response:  LIST

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

DELETE permanently removes the mailbox with the given name ๐Ÿ’€ You only get a tagged OK when the mailbox is actually gone. Trying to delete INBOX, or a mailbox that doesn't exist, is an error.

The DELETE command MUST NOT remove inferior hierarchical names ๐Ÿ™…โ€โ™€๏ธ For example, if a mailbox "foo" has an inferior "foo.bar" (with "." as the hierarchy delimiter), removing "foo" MUST NOT remove "foo.bar". Deleting a name that has inferior hierarchical names AND the \Noselect mailbox name attribute is an error. (Look at the LIST response in Section 7.3.1 for more details.)

Deleting a name that has inferior hierarchical names is allowed as long as it doesn't have the \Noselect attribute. If the server won't let you delete the name while those inferiors exist, it SHOULD disallow the DELETE command with a tagged NO response, and that NO response SHOULD include the HASCHILDREN response code. Or the server MAY allow the DELETE and just set the \Noselect attribute on that name instead. Two valid vibes ๐ŸŒˆ

If the server returns an OK response, DELETE removes all the messages in that mailbox ๐Ÿซถ

The highest-used unique identifier of the deleted mailbox MUST be preserved. That way, a new mailbox created with the same name won't reuse the old identifiers, unless the new incarnation has a different unique identifier validity value. See Section 6.4.9 for more on the UID command ๐Ÿฆ‹

If the server decides to normalize the mailbox name, it SHOULD return an untagged LIST with the "\NonExistent" attribute and an OLDNAME extended data item. The OLDNAME value is the mailbox name the client supplied, and the name parameter is the normalized one. (Section 6.3.9.7 has the extra details.)

Mailboxes deleted in one IMAP session MAY be announced to other IMAP sessions with an unsolicited LIST response that includes the "\NonExistent" attribute ๐Ÿ“

Example:

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

Example:

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

6.3.6. RENAME Command ๐ŸŽ€

Arguments:    existing mailbox name

              new mailbox name

Responses:    OPTIONAL untagged response:  LIST

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

RENAME changes the name of a mailbox โœจ You only get a tagged OK once the mailbox has actually been renamed. Renaming from a name that doesn't exist, or to a name that already exists, is an error. Any renaming problem comes back as a tagged NO ๐Ÿ’”

If the name has inferior hierarchical names, those inferiors MUST also be renamed ๐ŸŒณ For example, renaming "foo" to "zap" will rename "foo/bar" (with "/" as the hierarchy delimiter) to "zap/bar".

If the server's hierarchy separator shows up in the new mailbox name, the server SHOULD create any superior hierarchical names the RENAME command needs in order to finish successfully. So renaming "foo/bar/zap" to "baz/rag/zowie" on a server where "/" is the separator in that namespace SHOULD create "baz/" and "baz/rag/" if they don't already exist ๐Ÿงš

The highest-used unique identifier of the old mailbox name MUST be preserved. That way a new mailbox created with the same name won't reuse the old identifiers, unless the new incarnation has a different unique identifier validity value. Check Section 6.4.9 for the UID command details ๐Ÿ”ฅ

Renaming INBOX is permitted and does NOT get a tagged BAD response. It has special behavior though: it moves all the messages in INBOX into a new mailbox with the given name, which leaves INBOX empty. If the server supports inferior hierarchical names of INBOX, those stay put when INBOX gets renamed. (Heads up: some servers disallow renaming INBOX with a tagged NO response, so clients need to handle that failure ๐Ÿ™ˆ)

If the server allows creating mailboxes with names that aren't valid Net-Unicode names, the server normalizes both the existing mailbox name parameter and the new mailbox name parameter. If the normalized version of either one differs from what was supplied, the server SHOULD return an untagged LIST response with an OLDNAME extended data item. The OLDNAME value is the existing mailbox name that was supplied, and the name parameter is the normalized new mailbox name (see Section 6.3.9.7). This lets the client match up the supplied name with the normalized one ๐Ÿซถ

Mailboxes renamed in one IMAP session MAY be announced to other IMAP sessions with an unsolicited LIST response that has an OLDNAME extended data item.

In both of the cases above, if the server automatically subscribes a mailbox when it gets renamed, then the unsolicited LIST response for each affected subscribed mailbox name MUST include the \Subscribed attribute. No unsolicited LIST responses need to be sent for child mailboxes. When INBOX is successfully renamed, it's assumed a new INBOX gets created, so no unsolicited LIST responses need to be sent for INBOX in that case ๐Ÿ’œ

Examples:

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

Renaming a mailbox doesn't update the subscription info on the original name ๐Ÿ‘€ To keep subscriptions in sync, you can use this sequence of commands:

C: 1001 RENAME X Y
C: 1002 SUBSCRIBE Y
C: 1003 UNSUBSCRIBE X

Just a heads up: that sequence doesn't take care of updating the subscriptions for any child mailboxes of mailbox X ๐ŸŒธ

6.3.7. SUBSCRIBE Command ๐Ÿ’–

okay bestie, this one is all about the subscribed list ๐ŸŽ€ SUBSCRIBE adds a mailbox name to the server's "active" or "subscribed" set, the same set you see when you run LIST (SUBSCRIBED) ๐Ÿ“ฌ

Arguments:    mailbox

Responses:    no specific responses for this command

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

if the subscription works, you get a tagged OK. if the mailbox is already subscribed, you also get a tagged OK, so no stress if you accidentally double-subscribe ๐Ÿซถ

A server MAY validate the mailbox argument to SUBSCRIBE to check that it exists. โœจ But it SHOULD NOT unilaterally remove an existing mailbox name from the subscription list, even if a mailbox by that name doesn't exist anymore ๐Ÿ’…

๐Ÿ™ˆ Note: this rule is there because a server site can totally choose to routinely remove a mailbox with a well-known name (like system-alerts) after its contents expire, with the plan of recreating it when new contents are ready. so the subscription should survive the gap.

Example:

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

6.3.8. UNSUBSCRIBE Command ๐Ÿฆ‹

UNSUBSCRIBE is the opposite energy ๐ŸŒธ it removes the specified mailbox name from that same "active" or "subscribed" set, the one LIST (SUBSCRIBED) shows you โœจ

Arguments:    mailbox name

Responses:    no specific responses for this command

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

Same vibe as SUBSCRIBE: a tagged OK comes back if the unsubscription succeeds, and also if the mailbox wasn't subscribed in the first place ๐Ÿงš

Example:

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

6.3.9. LIST Command โœจ

Arguments (basic):
              reference name
              mailbox name with possible wildcards

Arguments (extended):
              selection options (OPTIONAL)
              reference name
              mailbox patterns
              return options (OPTIONAL)

Responses:    untagged responses: LIST

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

okay so the LIST command is how a client asks "what mailboxes do you have??" ๐Ÿฆ‹ The server answers with zero or more untagged LIST responses, each carrying the name attributes, the hierarchy delimiter, the name, and any possible extension information. If you want the full tea on the LIST response, check out Section 7.3.1 ๐Ÿ“–

The LIST command SHOULD return its data quickly, without undue delay ๐Ÿƒโ€โ™€๏ธ๐Ÿ’จ bestie, it should not go to excess trouble to calculate the \Marked or \Unmarked status or do other processing. Like, if each name needs 1 second of processing, then a list of 1200 names would take 20 minutes!

๐Ÿ’€ twenty minutes for a mailbox list?? nah. Keep it snappy.

The extended LIST command was originally introduced in [RFC5258] โœจ and it gives you way more power than the original IMAP LIST command. The extended syntax gets used if one or more of these conditions is true:

  1. the first word after the command name begins with a parenthesis ("LIST selection options");
  2. the second word after the command name begins with a parenthesis; and
  3. the LIST command has more than 2 parameters ("LIST return options").

An empty ("" string) reference name argument means the mailbox name is interpreted as by SELECT ๐Ÿ’… The returned mailbox names MUST match the supplied mailbox name pattern(s), no exceptions, periodt ๐Ÿซถ A non-empty reference name argument is the name of a mailbox or a level of mailbox hierarchy, and it tells you the context the mailbox name gets read in. Clients SHOULD use the empty reference argument ๐ŸŒธ

In the basic syntax only, an empty ("" string) mailbox name argument is a special request to return the hierarchy delimiter and the root name of the name given in the reference ๐Ÿงš The value returned as the root MAY be the empty string if the reference is non-rooted or is an empty string. In all cases, a hierarchy delimiter (or NIL if there is no hierarchy) is returned. This is so iconic, because a client can get the hierarchy delimiter (or find out that the mailbox names are flat) even when no mailboxes by that name exist right now ๐Ÿ™ˆ

In the extended syntax, any mailbox name arguments that are empty strings are ignored. Empty mailbox names have no special meaning when the extended syntax is used ๐Ÿ’œ

The reference and mailbox name arguments get interpreted into a canonical form that represents an unambiguous left-to-right hierarchy. The returned mailbox names will be in the interpreted form, which we call a "canonical LIST pattern": the canonical pattern the server builds internally from the reference and mailbox name arguments โœจ

Note: The interpretation of the reference argument is implementation defined. It depends on whether the server implementation has a concept of the "current working directory" and leading "break out characters", which override the current working directory.

For example, on a server that exports a UNIX or NT file system, the reference argument contains the current working directory, and the mailbox name argument contains the name as interpreted in the current working directory.

If a server implementation has no concept of break out characters, the canonical form is normally the reference name appended with the mailbox name. Note that if the server implements the namespace convention (Section 5.1.2.1), "#" is a break out character and must be treated as such.

If the reference argument is not a level of mailbox hierarchy (that is, it is a \NoInferiors name), and/or the reference argument does not end with the hierarchy delimiter, it is interpreted as implementation dependent. For example, a reference of "foo/bar" and mailbox name of "rag/baz" could be interpreted as "foo/bar/rag/baz", "foo/barrag/baz", or "foo/rag/baz". A client SHOULD NOT use such a reference argument except at the explicit request of the user ๐Ÿ™…โ€โ™€๏ธ A hierarchical browser MUST NOT make any assumptions about server interpretation of the reference unless the reference is a level of mailbox hierarchy AND ends with the hierarchy delimiter. Don't guess, bestie ๐Ÿ’…

Any part of the reference argument that is included in the interpreted form SHOULD prefix the interpreted form. It SHOULD also be in the same form as the reference name argument. This rule lets the client figure out whether the returned mailbox name is in the context of the reference argument or if something about the mailbox argument overrode the reference argument ๐Ÿ” Without this rule, the client would need to know the server's naming semantics, including which characters are "breakouts" that override a naming context. Nobody wants that homework ๐Ÿ˜ญ

Here are some examples of how references and mailbox names might be 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/*      |
         +--------------+--------------+-------------------+

                               Table 1

The first three examples above show interpretations in the context of the reference argument. Note that "~smith/Mail" SHOULD NOT be transformed into something like "/u2/users/smith/Mail", or the client would have no way of telling that the interpretation happened in the context of the reference ๐Ÿซฃ

The character * is a wildcard and matches zero or more characters at this position ๐ŸŒˆ The character % is similar to *, but it does not match a hierarchy delimiter. If the % wildcard is the last character of a mailbox name argument, matching levels of hierarchy are also returned. If those levels of hierarchy are not also selectable mailboxes, they come back with the \Noselect mailbox name attribute (see the description of the LIST response (Section 7.3.1) for more details) โœจ

Any syntactically valid pattern that a server does not accept for any reason MUST be silently ignored, meaning it results in no LIST responses, and the LIST command still returns a tagged OK response ๐Ÿคซ

Selection options tell the server to limit the mailbox names that the LIST operation selects ๐ŸŽ€ If selection options are used, the mailboxes returned are the ones that match both the list of canonical LIST patterns and the selection options. Unless a particular selection option provides special rules, the selection options are cumulative: a mailbox that matches the mailbox patterns is selected only if it also matches all of the selection options. (An example of a selection option with special rules is the RECURSIVEMATCH option.) ๐Ÿง 

Return options control what information is returned for each matched mailbox ๐ŸŽ Return options MUST NOT cause the server to report information about additional mailbox names other than those that match the canonical LIST patterns and selection options. If no return options are specified, the client is only expecting information about mailbox attributes. The server MAY return other information about the matched mailboxes, and clients MUST be able to handle that situation ๐Ÿ’–

Initial selection options and return options are defined in the following subsections, and new ones will also be defined in extensions ๐Ÿ“š Initial options defined in this document MUST be supported. Each non-initial option will be enabled by a capability string (one capability may enable multiple options), and a client MUST NOT send an option for which the server has not advertised support ๐Ÿšซ A server MUST respond to options it does not recognize with a BAD response. The client SHOULD NOT specify any option more than once; however, if the client does this, the server MUST act as if it received the option only once. The order in which options are specified by the client is not significant ๐ŸŒŸ

In general, each selection option except RECURSIVEMATCH will have a corresponding return option with the same name. The REMOTE selection option is an anomaly in this regard and does not have a corresponding return option. That is because it expands, rather than restricts, the set of mailboxes that are returned. Future extensions to this specification should keep this parallelism in mind and define a pair of corresponding selection and return options ๐Ÿฆ‹

Server implementations are permitted to "hide" otherwise accessible mailboxes from the wildcard characters, by preventing certain characters or names from matching a wildcard in certain situations ๐Ÿ™ˆ For example, a UNIX-based server might restrict the interpretation of * so that an initial / character does not match.

The special name INBOX is included in the output from LIST โœจ๐ŸŒˆ if INBOX is supported by this server for this user and if the uppercase string "INBOX" matches the interpreted reference and mailbox name arguments with wildcards as described above. The criteria for omitting INBOX is whether SELECT INBOX will return a failure. It is not relevant whether the user's real INBOX lives on this server or some other one ๐Ÿ‘‘

6.3.9.1. LIST Selection Options ๐ŸŽ€

okay so these are the selection options this spec defines, bestie ๐Ÿงš

SUBSCRIBED ๐ŸŒธ makes LIST show your subscribed names instead of all the existing mailboxes. That list is often a smaller slice of the real mailboxes, and it can even include names of mailboxes that don't exist ๐Ÿ‘€ Either way, the list MUST include exactly the mailbox names that match the canonical list pattern and are subscribed to.

This option also defines a mailbox attribute, "\Subscribed", which says a mailbox name is subscribed to. The "\Subscribed" attribute MUST be supported and MUST be accurately computed whenever the SUBSCRIBED selection option is specified.

Note that the SUBSCRIBED selection option implies the SUBSCRIBED return option (see below) ๐Ÿ’…

REMOTE ๐Ÿฆ‹ makes LIST show remote mailboxes as well as local ones, as described in [RFC2193]. It's meant to replace the RLIST command and, together with the SUBSCRIBED selection option, the RLSUB command. Servers that don't support remote mailboxes can ignore this option ๐Ÿซถ

This option defines a mailbox attribute, "\Remote", which says that a mailbox is a remote mailbox. The "\Remote" attribute MUST be accurately computed when the REMOTE option is specified.

REMOTE has no interaction with the other options. Its whole job is to tell the server to apply the other options, if any, to remote mailboxes too, on top of local ones. In particular, it doesn't interact with RECURSIVEMATCH (see below). A request for (REMOTE RECURSIVEMATCH) is invalid, because a request for (RECURSIVEMATCH) is also invalid ๐Ÿ™ˆ A request for (REMOTE RECURSIVEMATCH SUBSCRIBED) is asking for all subscribed mailboxes, both local and remote โœจ

RECURSIVEMATCH ๐ŸŒˆ forces the server to return info about parent mailboxes that don't match the other selection options but do have some submailboxes that do. Info about the children comes back in the CHILDINFO extended data item, as described in Section 6.3.9.6.

  • Note 1: In order for a parent mailbox to be returned, it still has to match the canonical LIST pattern.
  • Note 2: When returning the CHILDINFO extended data item, it doesn't matter whether or not the submailbox matches the canonical LIST pattern. See also Example 9 in Section 6.3.9.8.

The RECURSIVEMATCH option MUST NOT occur as the only selection option (or only together with REMOTE), because it only makes sense alongside other selection options. The server MUST return a BAD tagged response in that case ๐Ÿ’€

Even if RECURSIVEMATCH is specified, the client MUST still be able to handle a CHILDINFO extended data item that shows up when no submailboxes meet the selection criteria of the follow-up LIST command. Why? They can get deleted or renamed after the LIST response was sent but before the client gets to them ๐Ÿ˜ญ

6.3.9.2. LIST Return Options ๐Ÿ’œ

These are the return options defined in this spec, periodt ๐Ÿ’–

SUBSCRIBED ๐Ÿ“ makes LIST return the subscription state for every matching mailbox name. The "\Subscribed" attribute MUST be supported and MUST be accurately computed when the SUBSCRIBED return option is specified. Also, all other mailbox attributes MUST be accurately computed. (This is different from the obsolete LSUB command from [RFC3501], just so you know ๐Ÿ‘€) The above requirements don't override the requirement for LIST to return results quickly (see Section 6.3.9). Basically, servers need to compute results quickly and accurately. Server implementors might need to set up quick access indices to pull that off โšก

CHILDREN ๐Ÿงธ requests mailbox child information, as originally proposed in [RFC3348]. More on that in Section 6.3.9.5, below.

STATUS ๐Ÿ“Š requests a STATUS response for each matching mailbox.

This option takes STATUS data items as parameters. For each selectable mailbox that matches the list pattern and selection options, the server MUST return an untagged LIST response followed by an untagged STATUS response with the info requested in the STATUS return option, except in some cases described below.

If an attempted STATUS for a listed mailbox fails because the mailbox can't be selected, the STATUS response MUST NOT be returned, and the LIST response MUST include the \NoSelect attribute. That happens, for example, when the "l" Access Control List (ACL) right [RFC4314] is granted on the mailbox but the "r" right isn't, or when a race condition between LIST and STATUS changes the mailbox to \NoSelect. This means the server may have to buffer the LIST reply until it has successfully looked up the STATUS info it needs ๐Ÿง

If the server runs into unexpected problems while looking up the STATUS info, it MAY drop the corresponding STATUS reply. In that situation, the LIST command still returns a tagged OK reply ๐Ÿซง

For info about getting status on the currently selected mailbox, check the note in the STATUS command discussion in Section 6.3.11 โœจ

6.3.9.3. General Principles for Returning LIST Responses ๐Ÿฆ‹

This section lays out a few principles that server implementations of this document can use to decide whether a LIST response should be returned, plus how many responses there should be and what kind of info they can contain. Think of it as the vibe check for LIST replies ๐Ÿ’…

  1. At most, one LIST response should be returned for each mailbox name that matches the canonical LIST pattern. Server implementors must not assume that clients will be able to put together mailbox attributes and other info that comes back across multiple LIST responses.
  2. There are only two reasons to include a matching mailbox name in the responses to the LIST command. (The server is allowed to send unsolicited responses at any time, and those aren't governed by this rule ๐ŸŒธ)
    • A. The mailbox name also satisfies the selection criteria.
    • B. The mailbox name doesn't satisfy the selection criteria, but it has at least one descendant mailbox name that does satisfy them and that doesn't match the canonical LIST pattern.

For more on this case, see the CHILDINFO extended data item described in Section 6.3.9.6. The CHILDINFO extended data item can only be returned when the RECURSIVEMATCH selection option is specified.

  1. Attributes returned in the same LIST response are treated additively. For example, this response:
S: * LIST (\Subscribed \NonExistent) "/" "Fruit/Peach"

means that the "Fruit/Peach" mailbox doesn't exist, but it is subscribed ๐Ÿ‘

All clients MUST treat a LIST attribute with a stronger meaning as implying any attribute that can be inferred from it. (See Section 7.3.1 for the list of currently defined attributes.) For example, the client must treat the presence of the \NoInferiors attribute as if the \HasNoChildren attribute was also sent by the server. Inference, bestie ๐Ÿง 

The following table summarizes the inference rules ๐Ÿ‘‡

             +====================+===================+
             | returned attribute | implied attribute |
             +====================+===================+
             |    \NoInferiors    |   \HasNoChildren  |
             +--------------------+-------------------+
             |    \NonExistent    |     \NoSelect     |
             +--------------------+-------------------+

                              Table 2

6.3.9.5. The CHILDREN Return Option ๐ŸŒณ

The CHILDREN return option is basically the client saying, "tell me whether mailboxes have child mailboxes." A server MAY provide it even if the option isn't specified ๐Ÿคทโ€โ™€๏ธ

Lots of IMAP clients show the user a hierarchical view of the mailboxes they can access. Showing the whole hierarchy right away is often less ideal, especially with a big pile of mailboxes, so it's usually nicer to show a collapsed outline list that the user can expand as needed. It's common to add a visual clue (like a ''+'') in the collapsed hierarchy to show that a mailbox has children. When someone clicks that clue, the list expands to show the child mailboxes ๐Ÿช„ The CHILDREN return option lets a client efficiently find out whether a mailbox has children, without sending a LIST "" * or a LIST "" % for each mailbox name. It defines two new attributes that MUST be returned within a LIST response: \HasChildren and \HasNoChildren. These attributes MAY be returned in response to any LIST command, but the CHILDREN return option is how the client says it really wants this info. If the CHILDREN return option is present, the server MUST return these attributes even if computing them is expensive ๐Ÿ’ธ

\HasChildren ๐ŸŒท means the mailbox has child mailboxes. A server SHOULD NOT set this attribute if there are child mailboxes but the user has no permission to access any of them. In that case, \HasNoChildren SHOULD be used. In many cases, though, a server may not be able to efficiently figure out whether the user has access to any child mailbox. Even though the \HasChildren attribute must be correct at the time the mailbox is processed, a client must be ready for a mailbox marked \HasChildren with no child mailbox showing up in the LIST response. This might happen, for example, if another client deletes the child mailboxes or makes them inaccessible to the user (using access control) before the server can list them ๐Ÿ˜…

\HasNoChildren ๐Ÿซง means the mailbox has NO child mailboxes that are accessible to the currently authenticated user.

It is an error for the server to return both \HasChildren and \HasNoChildren in the same LIST response ๐Ÿšซ

Note: the \HasNoChildren attribute should not be confused with the \NoInferiors attribute. \NoInferiors means no child mailboxes exist now and none can be created in the future. Different vibe entirely ๐Ÿ’œ

6.3.9.6. CHILDINFO Extended Data Item โœจ

Okay bestie, the CHILDINFO extended data item is a total gatekeeper ๐Ÿ’… It MUST NOT be returned unless the client has specified the RECURSIVEMATCH selection option ๐Ÿ™…

When CHILDINFO shows up in a LIST response, it tells you which selection criteria got that mailbox returned, and that the mailbox has at least one descendant mailbox matching those criteria ๐ŸŒณ

Note: Some servers let mailboxes exist without their parent existing ๐Ÿซฃ For example, "Customers/ABC" can exist while "Customers" does not. Since CHILDINFO isn't allowed when the RECURSIVEMATCH selection option isn't specified, those servers SHOULD use the "\NonExistent \HasChildren" attribute pair to let the client know there's a descendant mailbox that matches the selection criteria. See Example 11 in Section 6.3.9.8.

The returned selection criteria is how the client can tell a solicited response from an unsolicited one. It also helps sort out solicited responses caused by multiple pipelined LIST commands that specify different criteria ๐Ÿงฉ

Servers SHOULD only return a non-matching mailbox name along with CHILDINFO if at least one matching child is not also being returned. In other words, servers SHOULD suppress redundant CHILDINFO responses ๐Ÿ™ˆ

Examples 8 and 10 in Section 6.3.9.8 show the difference between CHILDINFO and the \HasChildren attribute ๐Ÿฆ‹

The following table summarizes the interaction between the "\NonExistent" attribute and CHILDINFO. The first column tells you whether the parent mailbox exists ๐Ÿ’œ

  +========+===========+====================+=====================+
  | Exists | Meets the |  Has a child that  | Returned IMAP4rev2/ |
  |        | selection |     meets the      |    LIST-EXTENDED    |
  |        |  criteria | selection criteria |    attributes and   |
  |        |           |                    |      CHILDINFO      |
  +========+===========+====================+=====================+
  |   no   |     no    |         no         |   no LIST response  |
  |        |           |                    |       returned      |
  +--------+-----------+--------------------+---------------------+
  |  yes   |     no    |         no         |   no LIST response  |
  |        |           |                    |       returned      |
  +--------+-----------+--------------------+---------------------+
  |   no   |    yes    |         no         |    (\NonExistent    |
  |        |           |                    |       <attr>)       |
  +--------+-----------+--------------------+---------------------+
  |  yes   |    yes    |         no         |       (<attr>)      |
  +--------+-----------+--------------------+---------------------+
  |   no   |     no    |        yes         |   (\NonExistent) +  |
  |        |           |                    |      CHILDINFO      |
  +--------+-----------+--------------------+---------------------+
  |  yes   |     no    |        yes         |    () + CHILDINFO   |
  +--------+-----------+--------------------+---------------------+
  |   no   |    yes    |        yes         |    (\NonExistent    |
  |        |           |                    | <attr>) + CHILDINFO |
  +--------+-----------+--------------------+---------------------+
  |  yes   |    yes    |        yes         |      (<attr>) +     |
  |        |           |                    |      CHILDINFO      |
  +--------+-----------+--------------------+---------------------+

Table 3

Here <attr> means one or more attributes that match the selection criteria. For example, for the SUBSCRIBED option, <attr> is \Subscribed ๐ŸŒธ


6.3.9.7. OLDNAME Extended Data Item ๐ŸŽ€

The OLDNAME extended data item gets included when a mailbox name is created (with the CREATE command), renamed (with the RENAME command), or deleted (with the DELETE command). (When a mailbox is deleted, the "\NonExistent" attribute is included too.) IMAP extensions can specify other conditions for when OLDNAME should be included ๐Ÿงƒ

If the server allows denormalized mailbox names (see Section 5.1) in SELECT/EXAMINE, CREATE, RENAME, or DELETE, it SHOULD return an unsolicited LIST response that includes the OLDNAME extended data item, whenever the supplied mailbox name differs from the resulting normalized mailbox name. From the client's point of view, this is indistinguishable from another user renaming or deleting the mailbox, as specified in the previous paragraph ๐Ÿ‘€

A deleted mailbox can be announced like this:

  S: * LIST (\NonExistent) "." "INBOX.DeletedMailbox"

Example of a renamed mailbox:

  S: * LIST () "/" "NewMailbox" ("OLDNAME" ("OldMailbox"))

6.3.9.8. LIST Command Examples ๐Ÿ“š

This example shows some uses of the basic LIST command:

Example:

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

Extended examples:

1: This first one shows the complete local hierarchy that the other examples will use. Let's set the scene ๐Ÿ“

  C: A01 LIST "" "*"
  S: * LIST (\Marked \NoInferiors) "/" "inbox"
  S: * LIST () "/" "Fruit"
  S: * LIST () "/" "Fruit/Apple"
  S: * LIST () "/" "Fruit/Banana"
  S: * LIST () "/" "Tofu"
  S: * LIST () "/" "Vegetable"
  S: * LIST () "/" "Vegetable/Broccoli"
  S: * LIST () "/" "Vegetable/Corn"
  S: A01 OK done

2: Next up, we look at the subscribed mailboxes. This is similar to, but not equivalent with, the now deprecated <LSUB "" "*"> (see [RFC3501] for more details on the LSUB command). Notice that the mailbox called "Fruit/Peach" is subscribed to, but it doesn't actually exist (maybe it was deleted while still subscribed ๐Ÿ˜…). The "Fruit" mailbox isn't subscribed to, but it has two subscribed children. The "Vegetable" mailbox is subscribed and has two children, and one of them is subscribed as well ๐Ÿฅฆ

  C: A02 LIST (SUBSCRIBED) "" "*"
  S: * LIST (\Marked \NoInferiors \Subscribed) "/" "inbox"
  S: * LIST (\Subscribed) "/" "Fruit/Banana"
  S: * LIST (\Subscribed \NonExistent) "/" "Fruit/Peach"
  S: * LIST (\Subscribed) "/" "Vegetable"
  S: * LIST (\Subscribed) "/" "Vegetable/Broccoli"
  S: A02 OK done

3: This one shows the CHILDREN option in action โœจ Without having to list the second level of the hierarchy, the client now knows which top-level mailboxes have submailboxes (children) and which don't. Also note that the server doesn't need to return the \HasNoChildren attribute for the inbox, because the \NoInferiors attribute already implies that and has a stronger meaning ๐Ÿ’…

  C: A03 LIST () "" "%" RETURN (CHILDREN)
  S: * LIST (\Marked \NoInferiors) "/" "inbox"
  S: * LIST (\HasChildren) "/" "Fruit"
  S: * LIST (\HasNoChildren) "/" "Tofu"
  S: * LIST (\HasChildren) "/" "Vegetable"
  S: A03 OK done

4: Here we see more mailboxes that live on another server ๐ŸŒˆ This is similar to the command <RLIST "" "%">.

  C: A04 LIST (REMOTE) "" "%" RETURN (CHILDREN)
  S: * LIST (\Marked \NoInferiors) "/" "inbox"
  S: * LIST (\HasChildren) "/" "Fruit"
  S: * LIST (\HasNoChildren) "/" "Tofu"
  S: * LIST (\HasChildren) "/" "Vegetable"
  S: * LIST (\Remote \HasNoChildren) "/" "Bread"
  S: * LIST (\HasChildren \Remote) "/" "Meat"
  S: A04 OK done

5: This next example also asks the server to include mailboxes on another server. The server returns info about all the subscribed mailboxes. It's similar to the command <RLSUB "" "*"> (see [RFC2193] for more details on RLSUB). We also get to see two selection options working together ๐Ÿซถ

  C: A05 LIST (REMOTE SUBSCRIBED) "" "*"
  S: * LIST (\Marked \NoInferiors \Subscribed) "/" "inbox"
  S: * LIST (\Subscribed) "/" "Fruit/Banana"
  S: * LIST (\Subscribed \NonExistent) "/" "Fruit/Peach"
  S: * LIST (\Subscribed) "/" "Vegetable"
  S: * LIST (\Subscribed) "/" "Vegetable/Broccoli"
  S: * LIST (\Remote \Subscribed) "/" "Bread"
  S: A05 OK done

6: This one asks the server to include mailboxes on another server too ๐ŸŒ This time, the server is asked to return subscription information for all the returned mailboxes, which is different from the example above.

Notice that the output of this command is not a superset of the output in the previous example, because it doesn't include a LIST response for the non-existent "Fruit/Peach" ๐Ÿ‘€

  C: A06 LIST (REMOTE) "" "*" RETURN (SUBSCRIBED)
  S: * LIST (\Marked \NoInferiors \Subscribed) "/" "inbox"
  S: * LIST () "/" "Fruit"
  S: * LIST () "/" "Fruit/Apple"
  S: * LIST (\Subscribed) "/" "Fruit/Banana"
  S: * LIST () "/" "Tofu"
  S: * LIST (\Subscribed) "/" "Vegetable"
  S: * LIST (\Subscribed) "/" "Vegetable/Broccoli"
  S: * LIST () "/" "Vegetable/Corn"
  S: * LIST (\Remote \Subscribed) "/" "Bread"
  S: * LIST (\Remote) "/" "Meat"
  S: A06 OK done

7: This one shows the difference between the \HasChildren attribute and the CHILDINFO extended data item ๐Ÿง  Let's assume there's the following hierarchy:

  C: C01 LIST "" "*"
  S: * LIST (\Marked \NoInferiors) "/" "inbox"
  S: * LIST () "/" "Foo"
  S: * LIST () "/" "Foo/Bar"
  S: * LIST () "/" "Foo/Baz"
  S: * LIST () "/" "Moo"
  S: C01 OK done

If the client asks for RETURN (CHILDREN), it gets this:

  C: CA3 LIST "" "%" RETURN (CHILDREN)
  S: * LIST (\Marked \NoInferiors) "/" "inbox"
  S: * LIST (\HasChildren) "/" "Foo"
  S: * LIST (\HasNoChildren) "/" "Moo"
  S: CA3 OK done

A) Let's also assume that the mailbox "Foo/Baz" is the only subscribed mailbox. Then we get this result:

   C: C02 LIST (SUBSCRIBED) "" "*"
   S: * LIST (\Subscribed) "/" "Foo/Baz"
   S: C02 OK done

Now, if the client issues <LIST (SUBSCRIBED) "" "%">, the server returns no mailboxes, because the mailboxes "Moo", "Foo", and "Inbox" are NOT subscribed. However, if the client issues this:

   C: C04 LIST (SUBSCRIBED RECURSIVEMATCH) "" "%"
   S: * LIST () "/" "Foo" ("CHILDINFO" ("SUBSCRIBED"))
   S: C04 OK done

(That is, the mailbox "Foo" isn't subscribed, but it has a child that is.) Then A1 or A2 happens ๐ŸŽญ

A1) If the mailbox "Foo" had also been subscribed, the last command would return this:

   C: C04 LIST (SUBSCRIBED RECURSIVEMATCH) "" "%"
   S: * LIST (\Subscribed) "/" "Foo" ("CHILDINFO"
       ("SUBSCRIBED"))
   S: C04 OK done

or even this:

   C: C04 LIST (SUBSCRIBED RECURSIVEMATCH) "" "%"
   S: * LIST (\Subscribed \HasChildren) "/" "Foo"
       ("CHILDINFO" ("SUBSCRIBED"))
   S: C04 OK done

Okay so A2 is the twist ๐Ÿ‘€, where "Foo" isn't in the original hierarchy and isn't subscribed. Then the last command gives this ๐Ÿ’…

C: C04 LIST (SUBSCRIBED RECURSIVEMATCH) "" "%"
S: * LIST (\NonExistent) "/" "Foo" ("CHILDINFO"
    ("SUBSCRIBED"))
S: C04 OK done

B) Now let's assume no mailbox is subscribed ๐Ÿ™ˆ. Then LIST (SUBSCRIBED RECURSIVEMATCH) "" "%" returns zero responses, because there are no subscribed children, even though "Foo" still has children. Iconic emptiness ๐Ÿซฅ

(no responses)

C) And finally, suppose only "Foo" and "Moo" are subscribed โœจ. Now we get this:

C: C04 LIST (SUBSCRIBED RECURSIVEMATCH) "" "%" RETURN
    (CHILDREN)
S: * LIST (\HasChildren \Subscribed) "/" "Foo"
S: * LIST (\HasNoChildren \Subscribed) "/" "Moo"
S: C04 OK done

That tells us "Foo" has children, but none of them is subscribed ๐Ÿฅน

8: Okay, this one shows that CHILDINFO comes back whether or not child mailboxes match the canonical LIST pattern ๐Ÿฆ‹. Let's say we have this hierarchy:

C: D01 LIST "" "*"
S: * LIST (\Marked \NoInferiors) "/" "inbox"
S: * LIST () "/" "foo2"
S: * LIST () "/" "foo2/bar1"
S: * LIST () "/" "foo2/bar2"
S: * LIST () "/" "baz2"
S: * LIST () "/" "baz2/bar2"
S: * LIST () "/" "baz2/bar22"
S: * LIST () "/" "baz2/bar222"
S: * LIST () "/" "eps2"
S: * LIST () "/" "eps2/mamba"
S: * LIST () "/" "qux2/bar2"
S: D01 OK done

And these mailboxes are subscribed ๐Ÿ’œ:

C: D02 LIST (SUBSCRIBED) "" "*"
S: * LIST (\Subscribed) "/" "foo2/bar1"
S: * LIST (\Subscribed) "/" "foo2/bar2"
S: * LIST (\Subscribed) "/" "baz2/bar2"
S: * LIST (\Subscribed) "/" "baz2/bar22"
S: * LIST (\Subscribed) "/" "baz2/bar222"
S: * LIST (\Subscribed) "/" "eps2"
S: * LIST (\Subscribed) "/" "eps2/mamba"
S: * LIST (\Subscribed) "/" "qux2/bar2"
S: D02 OK done

The client starts with this command ๐ŸŽ€:

C: D03 LIST (RECURSIVEMATCH SUBSCRIBED) "" "*2"
S: * LIST () "/" "foo2" ("CHILDINFO" ("SUBSCRIBED"))
S: * LIST (\Subscribed) "/" "foo2/bar2"
S: * LIST (\Subscribed) "/" "baz2/bar2"
S: * LIST (\Subscribed) "/" "baz2/bar22"
S: * LIST (\Subscribed) "/" "baz2/bar222"
S: * LIST (\Subscribed) "/" "eps2" ("CHILDINFO" ("SUBSCRIBED"))
S: * LIST (\Subscribed) "/" "qux2/bar2"
S: D03 OK done

The server is also allowed to include these two, but this would break a restriction in Section 6.3.9.6, because CHILDINFO is redundant here ๐Ÿ™…โ€โ™€๏ธ

S: * LIST () "/" "baz2" ("CHILDINFO" ("SUBSCRIBED"))
S: * LIST (\NonExistent) "/" "qux2" ("CHILDINFO" ("SUBSCRIBED"))

So CHILDINFO shows up for "foo2", "baz2", and "eps2" because each one has subscribed children ๐Ÿ’–. But the details are different. For "foo2", only one of its two subscribed children matches the pattern. For "baz2", all of the subscribed children match. For "eps2", none of the subscribed children match ๐Ÿ˜ญ

Now watch this. If the client sends this instead ๐Ÿงš:

C: D03 LIST (RECURSIVEMATCH SUBSCRIBED) "" "*"
S: * LIST () "/" "foo2" ("CHILDINFO" ("SUBSCRIBED"))
S: * LIST (\Subscribed) "/" "foo2/bar1"
S: * LIST (\Subscribed) "/" "foo2/bar2"
S: * LIST () "/" "baz2" ("CHILDINFO" ("SUBSCRIBED"))
S: * LIST (\Subscribed) "/" "baz2/bar2"
S: * LIST (\Subscribed) "/" "baz2/bar22"
S: * LIST (\Subscribed) "/" "baz2/bar222"
S: * LIST (\Subscribed) "/" "eps2" ("CHILDINFO" ("SUBSCRIBED"))
S: * LIST (\Subscribed) "/" "eps2/mamba"
S: * LIST (\Subscribed) "/" "qux2/bar2"
S: D03 OK done

then the LIST responses for "foo2", "baz2", and "eps2" still carry CHILDINFO ๐Ÿ™ƒ. That info is redundant, since the client can work it out on its own ๐Ÿคทโ€โ™€๏ธ

9: This one is a flex ๐Ÿ’… with extended syntax for the mailbox pattern. It also proves that having CHILDINFO doesn't automatically mean \HasChildren โœจ

C: a1 LIST "" ("foo")
S: * LIST () "/" foo
S: a1 OK done

C: a2 LIST (SUBSCRIBED) "" "foo/*"
S: * LIST (\Subscribed \NonExistent) "/" foo/bar
S: a2 OK done

C: a3 LIST (SUBSCRIBED RECURSIVEMATCH) "" foo RETURN (CHILDREN)
S: * LIST (\HasNoChildren) "/" foo ("CHILDINFO" ("SUBSCRIBED"))
S: a3 OK done

10: Here a server that supports missing mailbox hierarchy elements tells a client that didn't pick the RECURSIVEMATCH selection option that a child mailbox matches the selection criteria ๐ŸŒˆ

C: a1 LIST (REMOTE) "" *
S: * LIST () "/" music/rock
S: * LIST (\Remote) "/" also/jazz
S: a1 OK done

C: a2 LIST () "" %
S: * LIST (\NonExistent \HasChildren) "/" music
S: a2 OK done

C: a3 LIST (REMOTE) "" %
S: * LIST (\NonExistent \HasChildren) "/" music
S: * LIST (\NonExistent \HasChildren) "/" also
S: a3 OK done

C: a3.1 LIST "" (% music/rock)
S: * LIST () "/" music/rock
S: a3.1 OK done

Since "music/rock" is the only mailbox under "music", the server doesn't need to also return "music" ๐Ÿ“ But clients must handle both cases, so be ready for either one ๐Ÿ’…

11: These examples show the STATUS return option in action ๐Ÿ“Š

C: A01 LIST "" % RETURN (STATUS (MESSAGES UNSEEN))
S: * LIST () "."  "INBOX"
S: * STATUS "INBOX" (MESSAGES 17 UNSEEN 16)
S: * LIST () "." "foo"
S: * STATUS "foo" (MESSAGES 30 UNSEEN 29)
S: * LIST (\NoSelect) "." "bar"
S: A01 OK List completed.

"bar" isn't selectable, so it gets no STATUS reply ๐Ÿ™…โ€โ™€๏ธ

C: A02 LIST (SUBSCRIBED RECURSIVEMATCH) "" % RETURN (STATUS
     (MESSAGES))
S: * LIST (\Subscribed) "."  "INBOX"
S: * STATUS "INBOX" (MESSAGES 17)
S: * LIST () "." "foo" (CHILDINFO ("SUBSCRIBED"))
S: A02 OK List completed.

"foo" still gets a LIST reply because it has matching children ๐Ÿซถ, but there's no STATUS reply for it, since "foo" itself doesn't match the selection criteria ๐Ÿ’œ

6.3.10. NAMESPACE Command โœจ

Arguments:    none

Responses:    REQUIRED untagged responses:  NAMESPACE

Result:       OK -  command completed
              NO -  Can't complete the command
              BAD -  arguments invalid

okay bestie, NAMESPACE is the "so, what's my mailbox neighbourhood look like?" command ๐Ÿ˜๏ธ๐Ÿ’… It makes the server send back exactly one untagged NAMESPACE response ๐ŸŽ€ That response lists the prefix and hierarchy delimiter for the server's Personal Namespace(s), Other Users' Namespace(s), and Shared Namespace(s) it's willing to show off ๐Ÿฆ‹ If a namespace class isn't available, you get a NIL in its spot, no drama ๐Ÿ™ˆ The namespace-response-extensions ABNF non-terminal exists for future expansion, and it MAY be included in the NAMESPACE response โœจ

Example 1:

In this one, the server has a single Personal Namespace. There's no leading prefix on personal mailboxes, and "/" is the hierarchy delimiter ๐ŸŒธ

  C: A001 NAMESPACE
  S: * NAMESPACE (("" "/")) NIL NIL
  S: A001 OK NAMESPACE command completed

Example 2:

A user logged on anonymously ๐Ÿ‘€ No personal mailboxes are tied to the anonymous user, and they don't have access to the Other Users' Namespace. Shared mailboxes need no prefix, and the hierarchy delimiter is "." ๐Ÿ’œ

  C: A001 NAMESPACE
  S: * NAMESPACE NIL NIL (("" "."))
  S: A001 OK NAMESPACE command completed

Example 3:

A server with a Personal Namespace and one Shared Namespace ๐Ÿงš

  C: A001 NAMESPACE
  S: * NAMESPACE (("" "/")) NIL (("Public Folders/" "/"))
  S: A001 OK NAMESPACE command completed

Example 4:

Now we're getting fancy: a Personal Namespace, an Other Users' Namespace, and multiple Shared Namespaces ๐Ÿ‘‘ Notice that each namespace can use a different hierarchy delimiter. Iconic behaviour ๐Ÿ”ฅ

  C: A001 NAMESPACE
  S: * NAMESPACE (("" "/")) (("~" "/")) (("#shared/" "/")
      ("#public/" "/")("#ftp/" "/")("#news." "."))
  S: A001 OK NAMESPACE command completed

The prefix string is what lets a client do cool stuff, like automatically making personal mailboxes or LISTing every available mailbox inside a namespace ๐Ÿ“

Example 5:

A server that only offers the Personal Namespace, with a leading prefix of INBOX on personal mailboxes and a hierarchy delimiter of "." ๐Ÿฆ‹

  C: A001 NAMESPACE
  S: * NAMESPACE (("INBOX." ".")) NIL  NIL
  S: A001 OK NAMESPACE command completed

Then the client automatically creates a mailbox to store sent items ๐Ÿ’Œ

  C: A002 CREATE "INBOX.Sent Mail"
  S: A002 OK CREATE command completed

Okay, real talk: a server will usually only support one Personal Namespace and one Other User's Namespace, but there are situations where there MAY be multiples of these, and a client MUST be prepared for them ๐Ÿ˜ญ If a client is configured to create a certain mailbox, it can get confusing about which Personal Namespace to put it in. In that case, a client SHOULD let the user pick which namespaces to create the mailbox in, or it can just use the first Personal Namespace ๐Ÿซถ

Example 6:

Here the server has two Personal Namespaces. Besides the regular one, the user also has an extra Personal Namespace that gives access to mailboxes in an MH format mailstore ๐ŸŒˆ

The client is set up to save a copy of everything the user sends into a mailbox with the \Sent attribute (see Section 7.3.1) ๐Ÿ“จ Also, whenever a message is deleted from a mailbox, the client moves it to a mailbox with the \Trash attribute ๐Ÿ—‘๏ธ The server uses the \NonExistent mailbox attribute to say "these don't exist yet, but you can make them." Once they're created, they can be used for \Sent or \Trash, and the server stops including \NonExistent for them ๐Ÿ’…

Heads up: this example shows how extension parameters can be passed along to describe the #mh namespace. Look at the made-up "X-PARAM" extension parameter ๐Ÿง

  C: A001 NAMESPACE
  S: * NAMESPACE (("" "/")("#mh/" "/" "X-PARAM"
      ("FLAG1" "FLAG2"))) NIL NIL
  S: A001 OK NAMESPACE command completed

  C: A002 LIST (SPECIAL-USE) "" "*"
  S: * LIST (\NonExistent \Archive) "/" Archives
  S: * LIST (\NonExistent \Drafts) "/" Drafts
  S: * LIST (\NonExistent \Junk) "/" Junk
  S: * LIST (\NonExistent \Sent) "/" "Sent Mail"
  S: * LIST (\NonExistent \Trash) "/" "Deleted Items"
  S: A002 OK LIST Completed

  C: A003 LIST (SPECIAL-USE) "#mh/" "*"
  S: * LIST (\NonExistent \Archive) "/" "#mh/Archives"
  S: * LIST (\NonExistent \Drafts) "/" "#mh/Drafts"
  S: * LIST (\NonExistent \Junk) "/" "#mh/Junk"
  S: * LIST (\NonExistent \Sent) "/" "#mh/Sent Mail"
  S: * LIST (\NonExistent \Trash) "/" "#mh/Deleted Items"
  S: A003 OK LIST Completed

The user wants to keep just one copy of sent mail, but it's unclear which Personal Namespace the client should use to create the 'Sent Mail' mailbox ๐Ÿค” So the user gets prompted to pick a namespace, and only one 'Sent Mail' mailbox gets created โœจ

  C: A004 CREATE "Sent Mail"
  S: A004 OK CREATE command completed

The client is designed to keep two 'Deleted Items' mailboxes, one for each namespace ๐Ÿง 

  C: A005 CREATE "Delete Items"
  S: A005 OK CREATE command completed

  C: A006 CREATE "#mh/Deleted Items"
  S: A006 OK CREATE command completed

The next level of hierarchy after the Other Users' Namespace prefix SHOULD consist of <username>, where <username> is a user name as per the LOGIN or AUTHENTICATE command ๐Ÿ‘ค

A client can build a LIST command by adding a "%" onto the Other Users' Namespace prefix. That lets it discover the Personal Namespaces of other users that the currently authenticated user is allowed to see ๐Ÿ‘€

When the server answers a LIST command like that, it SHOULD NOT return user names that haven't granted the user in question access to their personal mailboxes. Privacy first, bestie ๐Ÿ”’

A server MAY return a LIST response containing only the names of users who have explicitly granted access to the user in question โœจ

Or, a server MAY return NO to such a LIST command. In that case, the user name has to be included with the Other Users' Namespace prefix before any other user's mailboxes can be listed ๐Ÿ™…โ€โ™€๏ธ

Example 7:

A server that gives you a list of other users' mailboxes that the logged-on user can access ๐Ÿ’–

  C: A001 NAMESPACE
  S: * NAMESPACE (("" "/")) (("Other Users/" "/")) NIL
  S: A001 OK NAMESPACE command completed

  C: A002 LIST "" "Other Users/%"
  S: * LIST () "/" "Other Users/Mike"
  S: * LIST () "/" "Other Users/Karen"
  S: * LIST () "/" "Other Users/Matthew"
  S: * LIST () "/" "Other Users/Tesa"
  S: A002 OK LIST command completed

Example 8:

A server that does NOT give you a list of other users' accessible mailboxes ๐Ÿ™ˆ The mailboxes can only be listed if the client includes the other user's name after the Other Users' Namespace prefix.

  C: A001 NAMESPACE
  S: * NAMESPACE (("" "/")) (("#Users/" "/")) NIL
  S: A001 OK NAMESPACE command completed

Here, the logged-on user can access Mike's Personal Namespace, but the server chose to hide that info from the LIST response. Still, by adding the user name Mike (taken from user input) to the Other Users' Namespace prefix, the client can get a listing of Mike's personal mailboxes ๐ŸŽ€

  C: A002 LIST "" "#Users/%"
  S: A002 NO The requested item could not be found.

  C: A003 LIST "" "#Users/Mike/%"
  S: * LIST () "/" "#Users/Mike/INBOX"
  S: * LIST () "/" "#Users/Mike/Foo"
  S: A003 OK LIST command completed.

A prefix string doesn't always have to include a hierarchy delimiter, since in some cases it isn't needed as part of the prefix ๐Ÿฐ

Example 9:

A server that reaches the Other Users' Namespace by putting a '~' followed by <username> in front of others' mailboxes, where <username> is a user name as per the LOGIN or AUTHENTICATE command ๐Ÿฆ‹

  C: A001 NAMESPACE
  S: * NAMESPACE (("" "/")) (("~" "/")) NIL
  S: A001 OK NAMESPACE command completed

Listing the mailboxes for user mark ๐Ÿ’œ

  C: A002 LIST "" "~mark/%"
  S: * LIST () "/" "~mark/INBOX"
  S: * LIST () "/" "~mark/foo"
  S: A002 OK LIST command completed

6.3.11. STATUS Command โœจ

Arguments:    mailbox name

              status data item names

Responses:    REQUIRED untagged responses:  STATUS

Result:       OK -  status completed
              NO -  status failure: no status for that name
              BAD -  command unknown or arguments invalid

The STATUS command asks for the status of a specific mailbox ๐Ÿ“ฌ It doesn't change the currently selected mailbox, and it doesn't touch the state of any messages in the mailbox being checked ๐Ÿง˜โ€โ™€๏ธ

STATUS is basically the shortcut for opening a second IMAP4rev2 connection and running EXAMINE on a mailbox just to peek at its status, while keeping your current mailbox selected in the first connection ๐Ÿซถ

Unlike LIST, STATUS is NOT guaranteed to respond fast ๐ŸŒ In some cases it can be really slow. Some implementations have the server internally open the mailbox as "read-only" to get certain status info. Also, unlike LIST, STATUS doesn't accept wildcards ๐Ÿ™…โ€โ™€๏ธ

Note: STATUS is meant for checking mailboxes other than the one currently selected. Because STATUS can cause the mailbox to be opened internally, and because that info is already available another way on the selected mailbox, the STATUS command SHOULD NOT be used on the currently selected mailbox. Still, servers MUST be able to run STATUS on the selected mailbox. (That might also happen implicitly when the STATUS return option is used in a LIST command.) The STATUS command MUST NOT be used as a "check for new messages in the selected mailbox" operation. (For the proper way to check for new messages, see Sections 7 and 7.4.1.) STATUS SIZE can take a significant amount of time, depending on the server implementation. Clients should use STATUS SIZE cautiously. ๐Ÿฅบ

The status data items you can currently request are:

  • MESSAGES: the number of messages in the mailbox ๐Ÿ“ฎ
  • UIDNEXT: the next unique identifier value of the mailbox. Refer to Section 2.3.1.1 for more information ๐Ÿ”ข
  • UIDVALIDITY: the unique identifier validity value of the mailbox. Refer to Section 2.3.1.1 for more information ๐Ÿชช
  • UNSEEN: the number of messages that do not have the \Seen flag set ๐Ÿ‘๏ธ
  • DELETED: the number of messages that have the \Deleted flag set ๐Ÿ—‘๏ธ
  • SIZE: the total size of the mailbox in octets. This isn't strictly required to be an exact value, but it MUST be equal to or greater than the sum of the values of the RFC822.SIZE FETCH message data items (see Section 6.4.5) of all messages in the mailbox ๐Ÿ“

Example:

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

6.3.12. APPEND Command โœจ

Arguments:    mailbox name

              OPTIONAL flag parenthesized list

              OPTIONAL date/time string

              message literal

Responses:    OPTIONAL untagged response:  LIST

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

okay so APPEND is how you drop a brand-new message into the END of a mailbox ๐Ÿ“ฌ๐Ÿ’– You hand it the literal message as the argument, and it gets tacked on like a fresh text at the bottom of the chat. The message SHOULD look like an [RFC5322] or [I18N-HDRS] message ๐Ÿฆ‹ 8-bit characters are totally allowed in there, no cap. BUT if your server can't handle 8-bit data properly, it MUST be able to reversibly convert that 8-bit APPEND data down to 7 bits using a [MIME-IMB] content transfer encoding. Like, it has to be able to undo it perfectly ๐Ÿซถ

Note: There may be exceptions, such as draft messages, in which required [RFC5322] header fields are omitted in the message literal argument to APPEND. The full implications of doing so must be understood and carefully weighed. ๐Ÿ’…

If you include a flag parenthesized list, those flags SHOULD get set on the new message ๐ŸŽ€ If you don't, the flag list defaults to "empty" ๐ŸŒธ

If you give a date-time, the internal date SHOULD be set to it โฐ If you don't, it defaults to the current date and time, which is honestly iconic for a default โœจ

Now the big-deal part: if the append fails for ANY reason, the mailbox MUST be restored to how it was before the APPEND attempt ๐Ÿ˜ญ The only thing allowed to change is possibly the UIDNEXT value. No partial appending, bestie. It's all or nothing ๐Ÿ’€

If the destination mailbox doesn't exist, the server MUST return an error, and it MUST NOT automatically create the mailbox ๐Ÿ™…โ€โ™€๏ธ Unless it's certain the mailbox can't be created, the server MUST send the response code "[TRYCREATE]" as the prefix of the text of the tagged NO response ๐Ÿงš That's basically a hint saying "hey, you could try a CREATE and then retry the APPEND if that works!" ๐ŸŒˆ

When the APPEND goes through, the server returns an APPENDUID response code (see Section 7.1), unless otherwise specified below. โœจ

Here's a sneaky one ๐Ÿ‘€ If a mailbox lets the client APPEND to it but NOT SELECT or EXAMINE it, the server MUST NOT send an APPENDUID response code, because that would disclose information about the mailbox. Privacy is a whole vibe ๐Ÿ”’

And if a mailbox has UIDNOTSTICKY status (see Section 7.1), the server MAY omit the APPENDUID response code, since it isn't meaningful there anyway ๐Ÿ“

If the mailbox is currently selected, normal new message actions SHOULD happen ๐Ÿ”ฅ Specifically, the server SHOULD tell the client right away with an untagged EXISTS response. If it doesn't, the client MAY issue a NOOP command after one or more APPEND commands ๐Ÿ’œ

If the server decides to convert (normalize) the mailbox name, it SHOULD return an untagged LIST with an OLDNAME extended data item. The OLDNAME value is the mailbox name you supplied, and the name parameter is the normalized one. (See Section 6.3.9.7 for more details.) ๐Ÿฆ‹

Example:

  C: A003 APPEND saved-messages (\Seen) {326}
  S: + Ready for literal data
  C: Date: Mon, 7 Feb 1994 21:52:25 -0800 (PST)
  C: From: Fred Foobar <foobar@Blurdybloop.example>
  C: Subject: afternoon meeting
  C: To: mooch@owatagu.siam.edu.example
  C: Message-Id: <B27397-0100000@Blurdybloop.example>
  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

Example:

  C: A003 APPEND saved-messages (\Seen) {297+}
  C: Date: Mon, 7 Feb 1994 21:52:25 -0800 (PST)
  C: From: Fred Foobar <foobar@example.com>
  C: Subject: afternoon meeting
  C: To: mooch@example.com
  C: Message-Id: <B27397-0100000@example.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 [APPENDUID 38505 3955] APPEND completed
  C: A004 COPY 2:4 meeting
  S: A004 OK [COPYUID 38505 304,319:320 3956:3958] Done
  C: A005 UID COPY 305:310 meeting
  S: A005 OK No matching messages, so nothing copied
  C: A006 COPY 2 funny
  S: A006 OK Done
  C: A007 SELECT funny
  S: * 1 EXISTS
  S: * OK [UIDVALIDITY 3857529045] Validity session-only
  S: * OK [UIDNEXT 2] Predicted next UID
  S: * NO [UIDNOTSTICKY] Non-persistent UIDs
  S: * FLAGS (\Answered \Flagged \Deleted \Seen \Draft)
  S: * OK [PERMANENTFLAGS (\Deleted \Seen)] Limited
  S: * LIST () "." funny
  S: A007 OK [READ-WRITE] SELECT completed

In this example, A003 and A004 show a successful append and copy to a mailbox that hands back the UIDs assigned to the messages ๐ŸŽ€ A005 is the "nothing copied" one ๐Ÿ™ˆ Back in A003, message 2 had UID 304 and message 3 had UID 319, so UIDs 305 through 310 don't exist (check Section 2.3.1.1 for the deets). A006 copies a message and gets no COPYUID back, and as expected, A007 reveals that the mail store behind that mailbox doesn't support persistent UIDs ๐Ÿฅบ

Note: The APPEND command is not used for message delivery, because it does not provide a mechanism to transfer [SMTP] envelope information. ๐Ÿ“ฎ

6.3.13. IDLE Command ๐Ÿฆ‹

Arguments:    none

Responses:    continuation data will be requested; the client sends
              the continuation data "DONE" to end the command

Result:       OK -  IDLE completed after client sent "DONE"
              NO -  failure: the server will not allow the IDLE
                 command at this time
              BAD -  command unknown or arguments invalid

So without IDLE, a client has to keep poll-poll-polling the server for changes to the selected mailbox (new mail, deletions, flag changes) ๐Ÿ˜ฉ Way more desirable is the server just pushing updates in real time, so you see new mail the instant it lands โšก That's exactly what IDLE does: it's the client saying "hey, I'm ready for live updates" ๐ŸŒธ

The client sends IDLE when it's ready to accept unsolicited updates. The server asks for a response to IDLE with the continuation ("+") response. IDLE stays active until the client answers that continuation, and while IDLE is active, the server is free to send untagged EXISTS, EXPUNGE, FETCH, and other responses at any time ๐Ÿ”ฅ If the server chooses to send unsolicited FETCH responses, they MUST include a UID FETCH item ๐Ÿซถ

IDLE ends when the server gets a "DONE" continuation from the client, which satisfies the server's continuation request ๐Ÿ™Œ At that point, the server MAY send any remaining queued untagged responses, and then it MUST immediately send the tagged response to the IDLE command and get ready for other commands ๐Ÿ’œ Like with any other command, processing a new command may trigger unsolicited untagged responses, subject to the ambiguity limitations. And the client MUST NOT send a command while the server is waiting for DONE, because the server wouldn't be able to tell a command apart from a continuation ๐Ÿ’€

Also, the server MAY consider a client inactive if it has an IDLE command running. If that server has an inactivity timeout, it MAY log the client off implicitly once the timeout period ends ๐ŸŒ™ So clients using IDLE are advised to end IDLE and reissue it at least every 29 minutes to avoid getting logged off โฐ The good news: you still get instant mailbox updates, even though you only need to "poll" every half hour ๐Ÿ“

Example:

  C: A001 SELECT INBOX
  S: * FLAGS (\Deleted \Seen \Flagged)
  S: * OK [PERMANENTFLAGS (\Deleted \Seen \Flagged)] Limited
  S: * 3 EXISTS
  S: * OK [UIDVALIDITY 1]
  S: * OK [UIDNEXT 1]
  S: * LIST () "/" INBOX
  S: A001 OK [READ-WRITE] SELECT completed
  C: A002 IDLE
  S: + idling
  ...time passes; new mail arrives...
  S: * 4 EXISTS
  C: DONE
  S: A002 OK IDLE terminated
  ...another client expunges message 2 now...
  C: A003 FETCH 4 ALL
  S: * 4 FETCH (...)
  S: A003 OK FETCH completed
  C: A004 IDLE
  S: * 2 EXPUNGE
  S: * 3 EXISTS
  S: + idling
  ...time passes; another client expunges message 3...
  S: * 3 EXPUNGE
  S: * 2 EXISTS
  ...time passes; new mail arrives...
  S: * 3 EXISTS
  C: DONE
  S: A004 OK IDLE terminated
  C: A005 FETCH 3 ALL
  S: * 3 FETCH (...)
  S: A005 OK FETCH completed
  C: A006 IDLE

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, NAMESPACE, CREATE, DELETE, RENAME, SUBSCRIBE, UNSUBSCRIBE, LIST, STATUS, and APPEND), the following commands are valid in the selected state: CLOSE, UNSELECT, EXPUNGE, SEARCH, FETCH, STORE, COPY, MOVE, and UID ๐ŸŽ€

6.4.1. CLOSE Command ๐Ÿšช

Arguments:    none

Responses:    no specific responses for this command

Result:       OK -  close completed, now in authenticated state
              BAD -  command unknown or arguments invalid

CLOSE permanently removes all messages with the \Deleted flag set from the currently selected mailbox, and it takes you back from the selected state to the authenticated state ๐Ÿ’ฅ No untagged EXPUNGE responses get sent along the way ๐Ÿ™ˆ

No messages are removed and no error is given if the mailbox was selected by EXAMINE or is otherwise read-only, so it's chill ๐ŸŒธ

Even with a mailbox selected, you MAY issue a SELECT, EXAMINE, or LOGOUT command without CLOSE-ing first ๐Ÿฆ‹ Those three implicitly close the current mailbox without doing an expunge. BUT when you've deleted a ton of messages, CLOSE-LOGOUT or CLOSE-SELECT is way faster than EXPUNGE-LOGOUT or EXPUNGE-SELECT, because it skips sending the untagged EXPUNGE responses (which the client would probably just ignore anyway) ๐ŸŽ๏ธ๐Ÿ’จ

Example:

  C: A341 CLOSE
  S: A341 OK CLOSE completed

6.4.2. UNSELECT Command ๐Ÿซง

Arguments:    none

Responses:    no specific responses for this command

Result:       OK -  unselect completed, now in authenticated state
              BAD -  no mailbox selected, or argument supplied but
                 none permitted

UNSELECT frees up the session's resources tied to the selected mailbox and sends the server back to the authenticated state ๐Ÿงน It does the exact same stuff as CLOSE, except that NO messages get permanently removed from the mailbox. Gentle exit, no drama ๐ŸŒท

Example:

  C: A342 UNSELECT
  S: A342 OK Unselect completed

6.4.3. EXPUNGE Command ๐Ÿงนโœจ

Arguments:    none

Responses:    untagged responses:  EXPUNGE

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

Okay bestie, EXPUNGE is the big delete button ๐Ÿ’€. It permanently removes every message in the currently selected mailbox that has the \Deleted flag set. Before the server says OK, it sends an untagged EXPUNGE response for each message it removes, so you always know exactly what got yeeted ๐Ÿ—‘๏ธ.

Example:

C: A202 EXPUNGE
S: * 3 EXPUNGE
S: * 3 EXPUNGE
S: * 5 EXPUNGE
S: * 8 EXPUNGE
S: A202 OK EXPUNGE completed

Note: In this example, messages 3, 4, 7, and 11 had the \Deleted flag set. See the description of the EXPUNGE response (Section 7.5.1) for further explanation. ๐Ÿ™ˆ

6.4.4. SEARCH Command ๐Ÿ”๐Ÿ’…

Arguments:    OPTIONAL result specifier

              OPTIONAL [CHARSET] specification

              searching criteria (one or more)

Responses:    OPTIONAL untagged response:  ESEARCH

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

SEARCH is how you dig through a mailbox for the messages that match your vibe, aka your searching criteria ๐Ÿ”Žโœจ.

The SEARCH command can also include result options. These control what info comes back about the matching messages, inside an untagged ESEARCH response ๐ŸŽ€. If you don't give any result option, or you give an empty list written as (), ALL is assumed (more on that below). The order of the options doesn't matter ๐ŸŒธ. Options can have parameters in parentheses. The exception is when an option has a mandatory parameter that can always be written as a number or a sequence-set. Then that parameter doesn't need the parentheses. Check out "Formal Syntax" (Section 9) for the details ๐Ÿ“–. If an option has parameters, they're made of atoms, strings, and/or lists, in one specific order. Any options that aren't defined by extensions the server supports MUST be rejected with a BAD response ๐Ÿšซ.

Note that IMAP4rev1 used SEARCH responses [RFC3501] instead of ESEARCH responses. Clients that only support IMAP4rev2 MUST ignore SEARCH responses ๐Ÿ™ƒ.

This document specifies the following result options:

MIN

Returns the lowest message number/UID that satisfies the SEARCH criteria ๐Ÿ“‰.

If the SEARCH gives no matches, the server MUST NOT include the MIN result option in the ESEARCH response. It still MUST send the ESEARCH response, though ๐Ÿซถ.

MAX

Returns the highest message number/UID that satisfies the SEARCH criteria ๐Ÿ“ˆ.

If the SEARCH gives no matches, the server MUST NOT include the MAX result option in the ESEARCH response. It still MUST send the ESEARCH response, though ๐Ÿซถ.

ALL

Returns all message numbers/UIDs that satisfy the SEARCH criteria, using the sequence-set syntax ๐Ÿงƒ. The client MUST NOT assume that the messages/UIDs will be listed in any particular order ๐Ÿ™…โ€โ™€๏ธ.

If the SEARCH gives no matches, the server MUST NOT include the ALL result option in the ESEARCH response. It still MUST send the ESEARCH response ๐Ÿซถ.

COUNT

Returns the number of messages that satisfy the SEARCH criteria ๐Ÿ”ข. This result option MUST always be included in the ESEARCH response ๐Ÿ’ฏ.

SAVE

This option tells the server to remember the result of the SEARCH or UID SEARCH command (and also any command based on SEARCH, like SORT and THREAD [RFC5256]). It then stores that result in an internal variable we'll call the "search result variable" ๐Ÿง . The client can use the "$" marker to refer to what's in that variable. The "$" marker can go wherever a message sequence or UID sequence would go, and the server swaps it out for the list of messages in the search result variable. So the client can reuse the result of the latest remembered SEARCH as a parameter for another command ๐Ÿช„. See Section 6.4.4.1 for how the value of the search result variable is figured out, how other commands affect it, and how the SAVE return option plays with the other return options ๐Ÿ“š.

If there's no other SEARCH result option, the SAVE result option also suppresses any ESEARCH response the SEARCH command would have sent otherwise ๐Ÿคซ.

Note: Future extensions to this document might let servers return multiple ESEARCH responses for one extended SEARCH command. However, all of the options above MUST result in a single ESEARCH response, whether they're used alone or together. This guarantee keeps things simple for IMAP4rev2 clients ๐Ÿงธ. Future SEARCH extensions that loosen this rule will have to describe how results from multiple ESEARCH responses get combined ๐Ÿงฉ.

Searching criteria are made of one or more search keys ๐Ÿ”‘.

When you give more than one key, the result is the intersection (AND function) of the messages that match all of them. For example, the criteria DELETED FROM "SMITH" SINCE 1-Feb-1994 refers to all deleted messages from Smith with an INTERNALDATE after February 1, 1994 ๐Ÿ’Œ. A search key can also be a parenthesized list of one or more search keys. That's how you use things like OR and NOT ๐ŸŽญ.

Server implementations MAY exclude [MIME-IMB] body parts with terminal content media types other than TEXT and MESSAGE from consideration in SEARCH matching ๐Ÿ™ˆ.

The OPTIONAL [CHARSET] specification is the word "CHARSET" followed by the name of a character set from the registry [CHARSET-REG] ๐Ÿ—‚๏ธ. It tells you the [CHARSET] of the strings that appear in the search criteria. [MIME-IMB] content transfer encodings and [MIME-HDRS] strings in [RFC5322]/[MIME-IMB] headers MUST be decoded before text gets compared ๐Ÿ”“. Servers MUST support the US-ASCII and UTF-8 charsets. Other CHARSETs MAY be supported. Clients SHOULD use UTF-8 ๐Ÿ’–. If CHARSET isn't provided, IMAP4rev2 servers MUST assume UTF-8, so picking CHARSET UTF-8 is redundant. It's still allowed, though, for better compatibility with existing IMAP4rev1 clients ๐Ÿค.

If the server doesn't support the CHARSET you asked for, it MUST return a tagged NO response (not a BAD) ๐Ÿ™…โ€โ™€๏ธ. This response SHOULD contain the BADCHARSET response code, which MAY list the CHARSETs the server supports ๐Ÿงพ.

For any search key that uses strings, and unless it says otherwise, a message matches if the string is a substring of the associated text ๐Ÿงต. The matching SHOULD be case insensitive for characters in the ASCII range. For language-sensitive, case-insensitive searching, consider using [IMAP-I18N] ๐ŸŒ. Note that the empty string counts as a substring. This is handy for a HEADER search when you want to check whether a header field is present in the message ๐Ÿ‘€.

The defined search keys are below. Check "Formal Syntax" (Section 9) for the exact syntax of the arguments ๐Ÿ“.

<sequence set>

Messages whose message sequence numbers match the specified message sequence number set ๐Ÿ”ข.

ALL

Every message in the mailbox. It's also the default initial key for ANDing ๐Ÿ‘‘.

ANSWERED

Messages with the \Answered flag set โœ….

BCC <string>

Messages that have the specified string in the envelope structure's Blind Carbon Copy (BCC) field ๐Ÿ•ต๏ธ.

BEFORE <date>

Messages whose internal date (ignoring time and timezone) is earlier than the specified date โช.

BODY <string>

Messages that have the specified string in the body of the message. Unlike TEXT (see below), this doesn't look at any header fields ๐Ÿ“. Servers are allowed to do flexible matching for this key. For example, they could match "swim" to both "swam" and "swum" in English text, or only do full-word matching, where "swim" won't match "swimming" ๐ŸŠโ€โ™€๏ธ.

CC <string>

Messages that have 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 have the specified string in the envelope structure's FROM field ๐Ÿ“ฌ.

HEADER <field-name> <string>

Messages that have a header field with the specified field-name (as defined in [RFC5322]) and that contain the specified string in the text of that header field (what comes after the colon) ๐ŸŽฏ. If the string to search is zero-length, this matches every message that has a header field with the specified field-name, no matter what it says. Servers should use a substring search for this SEARCH item, since clients can use it for automatic processing that isn't started by end users ๐Ÿค–. For example, it can be used when searching for Message-ID or Content-Type header field values that need to be exact, or for searching header fields the IMAP server might not know anything about ๐Ÿง .

KEYWORD <flag>

Messages with the specified keyword flag set ๐Ÿท๏ธ.

LARGER <n>

Messages with an RFC822.SIZE larger than the specified number of octets ๐Ÿ˜.

NOT <search-key>

Messages that do NOT match the specified search key ๐Ÿ™…โ€โ™€๏ธ.

ON <date>

Messages whose internal date (ignoring time and timezone) falls within the specified date ๐Ÿ“….

OR <search-key1> <search-key2>

Messages that match either search key ๐Ÿ”€.

SEEN

Messages with the \Seen flag set ๐Ÿ‘€.

SENTBEFORE <date>

Messages whose [RFC5322] Date: header field (ignoring time and timezone) is earlier than the specified date ๐Ÿ•ฐ๏ธ.

SENTON <date>

Messages whose [RFC5322] Date: header field (ignoring time and timezone) falls within the specified date ๐Ÿ—“๏ธ.

SENTSINCE <date>

Messages whose [RFC5322] Date: header field (ignoring time and timezone) is within or later than the specified date ๐Ÿ’ซ.

SINCE <date>

Messages whose internal date (ignoring time and timezone) 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 have the specified string in the envelope structure's SUBJECT field ๐Ÿ“ฃ.

TEXT <string>

Messages that have the specified string in the header (including MIME header fields) or body of the message ๐Ÿงบ. Servers are allowed to do flexible matching for this key too, like matching "swim" to both "swam" and "swum" in English, or only doing full-word matching, where "swim" won't match "swimming" ๐ŸŠโ€โ™€๏ธ.

TO <string>

Messages that have the specified string in the envelope structure's TO field ๐Ÿ’Œ.

UID <sequence set>

Messages whose unique identifiers match the specified unique identifier set. Sequence-set ranges are permitted ๐Ÿ†”.

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 flag set ๐Ÿง.

UNSEEN

Messages that do NOT have the \Seen flag set ๐Ÿ‘ป.

Example:

Okay bestie, the examples are still going, so let's keep the vibe ๐Ÿ’…

C: A282 SEARCH RETURN (MIN COUNT) FLAGGED
    SINCE 1-Feb-1994 NOT FROM "Smith"
S: * ESEARCH (TAG "A282") MIN 2 COUNT 3
S: A282 OK SEARCH completed

Example:

C: A283 SEARCH RETURN () FLAGGED
    SINCE 1-Feb-1994 NOT FROM "Smith"
S: * ESEARCH (TAG "A283") ALL 2,10:11
S: A283 OK SEARCH completed

Example:

C: A284 SEARCH TEXT "string not in mailbox"
S: * ESEARCH (TAG "A284")
S: A284 OK SEARCH completed
C: A285 SEARCH CHARSET UTF-8 TEXT {12}
S: + Ready for literal text
C: ะพั‚ะฟัƒัะบ
S: * ESEARCH (TAG "A285") ALL 43
S: A285 OK SEARCH completed

The next example shows how to find the first unseen message in the mailbox. So cute, right? ๐Ÿฆ‹

Example:

C: A284 SEARCH RETURN (MIN) UNSEEN
S: * ESEARCH (TAG "A284") MIN 4
S: A284 OK SEARCH completed

This one is my favourite ๐Ÿ˜ญ If the ESEARCH UID indicator is there, then all the data in the ESEARCH response is about UIDs. So the MIN result specifier gets followed by a UID, no exceptions ๐Ÿซถ

Example:

C: A285 UID SEARCH RETURN (MIN MAX) 1:5000
S: * ESEARCH (TAG "A285") UID MIN 7 MAX 3800
S: A285 OK SEARCH completed

And here's how you get the number of deleted messages ๐Ÿงš

Example:

C: A286 SEARCH RETURN (COUNT) DELETED
S: * ESEARCH (TAG "A286") COUNT 15
S: A286 OK SEARCH completed

6.4.4.1. SAVE Result Option and SEARCH Result Variable โœจ

Okay, the SAVE result option is giving main character energy ๐Ÿ‘‘

Upon successful completion of a SELECT or an EXAMINE command (after the tagged OK response), the current search result variable is reset to the empty sequence.

A successful SEARCH command with the SAVE result option sets the value of the search result variable to the list of messages found in the SEARCH command. For example, if no messages were found, the search result variable will contain the empty sequence.

Any of the following SEARCH commands MUST NOT change the search result variable:

  • a SEARCH command that caused the server to return the BAD tagged response,
  • a SEARCH command with no SAVE result option that caused the server to return NO tagged response, and
  • a successful SEARCH command with no SAVE result option.

A SEARCH command with the SAVE result option that caused the server to return the NO tagged response sets the value of the search result variable to the empty sequence.

When a message listed in the search result variable is EXPUNGEd, it is automatically removed from the list. Implementors are reminded that if the server stores the list as a list of message numbers, it MUST automatically adjust them when notifying the client about expunged messages, as described in Section 7.5.1. Servers, this is your sign to keep those numbers in sync ๐Ÿ”ฅ

If the server decides to send a new UIDVALIDITY value while the mailbox is opened, it causes the resetting of the search variable to the empty sequence.

Note that even if the $ marker contains the empty sequence of messages, it must be treated by all commands accepting message sets as parameters as a valid, but non-matching, list of messages. For example, the FETCH $ command would return a tagged OK response and no FETCH responses. See also Example 5 in Section 6.4.4.4. ๐Ÿ™ˆ

The SAVE result option doesn't change whether the server would return items corresponding to MIN, MAX, ALL, or COUNT result options.

When the SAVE result option is combined with the MIN or MAX result option, and both ALL and COUNT result options are absent, the corresponding MIN/MAX is returned (if the search result is not empty), but the $ marker would contain a single message as returned in the MIN/MAX return item.

If the SAVE result option is combined with both MIN and MAX result options, and both ALL and COUNT result options are absent, the $ marker would contain zero messages, one message, or two messages as returned in the MIN/MAX return items.

If the SAVE result option is combined with the ALL and/or COUNT result option(s), the $ marker would always contain all messages found by the SEARCH or UID SEARCH command.

The following table summarizes the additional requirement on ESEARCH server implementations described in this section.

           +==============================+====================+
           | Combination of Result Option |  "$" Marker Value  |
           +==============================+====================+
           |           SAVE MIN           |        MIN         |
           +------------------------------+--------------------+
           |           SAVE MAX           |        MAX         |
           +------------------------------+--------------------+
           |         SAVE MIN MAX         |     MIN & MAX      |
           +------------------------------+--------------------+
           |          SAVE * [m]          | all found messages |
           +------------------------------+--------------------+

                                  Table 4

where '*' means "ALL" and/or "COUNT", and '[m]' means optional "MIN" and/or "MAX"

Implementation note: server implementors, "$" can reference IMAP message sequences or UID sequences, depending on the context where it is used. For example, the $ marker can be set as a result of a SEARCH (SAVE) command and used as a parameter to a UID FETCH command (which accepts a UID sequence, not a message sequence), or the $ marker can be set as a result of a UID SEARCH (SAVE) command and used as a parameter to a FETCH command (which accepts a message sequence, not a UID sequence). Server implementations need to automatically map the $ marker value to message numbers or UIDs, depending on the context where the $ marker is used. ๐Ÿง 


6.4.4.2. Multiple Commands in Progress ๐ŸŽ€

Use of a SEARCH RETURN (SAVE) command followed by a command using the "$" marker creates direct dependency between the two commands. As directed by Section 5.5, a server MUST execute the two commands in the order they were received.

A client MAY pipeline a SEARCH RETURN (SAVE) command with one or more commands using the "$" marker, as long as this doesn't create an ambiguity, as described in Section 5.5. Examples 7-9 in Section 6.4.4.4 explain this in more details. Pipelining, but make it organised ๐Ÿ’š


6.4.4.3. Refusing to Save Search Results ๐ŸŒธ

In some cases, the server MAY refuse to save a SEARCH (SAVE) result, for example, if an internal limit on the number of saved results is reached. In this case, the server MUST return a tagged NO response containing the NOTSAVED response code and set the search result variable to the empty sequence, as described in Section 6.4.4.1. Sorry server, no saving today ๐Ÿ’€

6.4.4.4. Examples Showing Use of the SAVE Result Option โœจ

Okay bestie, quick heads up: anything starting with // in these examples is just a comment for us humans. It's not part of the protocol ๐Ÿ’…

1. First up, the client can use a SEARCH result to FETCH headers of the messages it found ๐Ÿ“ฌ

Example 1:

C: A282 SEARCH RETURN (SAVE) FLAGGED SINCE 1-Feb-1994
    NOT FROM "Smith"
S: A282 OK SEARCH completed, result saved
C: A283 FETCH $ (UID INTERNALDATE FLAGS BODY.PEEK[HEADER])
S: * 2 FETCH (UID 14 ...
S: * 84 FETCH (UID 100 ...
S: * 882 FETCH (UID 1115 ...
S: A283 OK completed

The client can also pipeline the two commands ๐Ÿ”ฅ

Example 2:

C: A282 SEARCH RETURN (SAVE) FLAGGED SINCE 1-Feb-1994
    NOT FROM "Smith"
C: A283 FETCH $ (UID INTERNALDATE FLAGS BODY.PEEK[HEADER])
S: A282 OK SEARCH completed
S: * 2 FETCH (UID 14 ...
S: * 84 FETCH (UID 100 ...
S: * 882 FETCH (UID 1115 ...
S: A283 OK completed

2. Next, the result of one SEARCH can be used as input to another SEARCH. It's giving chaining ๐Ÿฆ‹

Example 3:

C: A300 SEARCH RETURN (SAVE) SINCE 1-Jan-2004
    NOT FROM "Smith"
S: A300 OK SEARCH completed
C: A301 UID SEARCH UID $ SMALLER 4096
S: * ESEARCH (TAG "A301") UID ALL 17,900,901
S: A301 OK completed

Note: the second command in Example 3 can be swapped out for this one:

C: A301 UID SEARCH $ SMALLER 4096

and the result of the command would be the same. โœจ

3. Here the "$" marker gets combined with other message numbers using the OR SEARCH criterion. ๐Ÿงš

Example 4:

C: P282 SEARCH RETURN (SAVE) SINCE 1-Feb-1994
    NOT FROM "Smith"
S: P282 OK SEARCH completed
C: P283 SEARCH CHARSET UTF-8 (OR $ 1,3000:3021) TEXT {8+}
C: ะผะฐั‚ัŒ
S: * ESEARCH (TAG "P283") ALL 882,1102,3003,3005:3006
S: P283 OK completed

4. A failed SEARCH sets the search result variable to the empty list. Oof ๐Ÿ’€ The server doesn't implement the KOI8-R charset, so this one fails.

Example 5:

C: B282 SEARCH RETURN (SAVE) SINCE 1-Feb-1994
    NOT FROM "Smith"
S: B282 OK SEARCH completed
C: B283 SEARCH RETURN (SAVE) CHARSET KOI8-R
    (OR $ 1,3000:3021) TEXT {4}
C: XXXX
S: B283 NO [BADCHARSET UTF-8] KOI8-R is not supported
//After this command, the saved result variable contains
//no messages.  A client that wants to reissue the B283
//SEARCH command with another CHARSET would have to reissue
//the B282 command as well.  One possible workaround for
//this is to include the desired CHARSET parameter
//in the earliest SEARCH RETURN (SAVE) command in a
//sequence of related SEARCH commands, to cause
//the earliest SEARCH in the sequence to fail.
//A better approach might be to always use CHARSET UTF-8
//instead.
Note: this document format is limited to 7-bit ASCII text, so there's no way to show actual KOI8-R data here. The "XXXX" is just a placeholder for what would be 4 octets of 8-bit data in a real transaction. ๐Ÿ™ˆ

5. Using the "$" marker when it holds no messages is not an error, bestie. Totally valid ๐ŸŒธ

Example 6:

C: E282 SEARCH RETURN (SAVE) SINCE 28-Oct-2006
    NOT FROM "Eric"
C: E283 COPY $ "Other Messages"
//The "$" contains no messages
 S: E282 OK SEARCH completed
 S: E283 OK COPY completed, nothing copied

Example 7:

C: F282 SEARCH RETURN (SAVE) KEYWORD $Junk
C: F283 COPY $ "Junk"
C: F284 STORE $ +FLAGS.Silent (\Deleted)
S: F282 OK SEARCH completed
S: F283 OK COPY completed
S: F284 OK STORE completed

Example 8:

C: G282 SEARCH RETURN (SAVE) KEYWORD $Junk
C: G283 SEARCH RETURN (ALL) SINCE 28-Oct-2006
    FROM "Eric"
// The server can execute the two SEARCH commands
// in any order, as they don't have any dependency.
// For example, it may return:
 S: * ESEARCH (TAG "G283") ALL 3:15,27,29:103
 S: G283 OK SEARCH completed
 S: G282 OK SEARCH completed

The following example shows that the result of the second SEARCH RETURN (SAVE) always overrides the result of the first. Plot twist ๐ŸŽ€

Example 9:

C: H282 SEARCH RETURN (SAVE) KEYWORD $Junk
C: H283 SEARCH RETURN (SAVE) SINCE 28-Oct-2006
    FROM "Eric"
 S: H282 OK SEARCH completed
 S: H283 OK SEARCH completed
// At this point "$" would contain results of H283

The following example shows the behavioral difference between different combinations of ESEARCH result options. So many combos, so much drama ๐Ÿ‘‘

Example 10:

  C: C282 SEARCH RETURN (ALL) SINCE 12-Feb-2006
      NOT FROM "Smith"
  S: * ESEARCH (TAG "C283") ALL 2,10:15,21
//$ value hasn't changed
  S: C282 OK SEARCH completed

  C: C283 SEARCH RETURN (ALL SAVE) SINCE 12-Feb-2006
      NOT FROM "Smith"
  S: * ESEARCH (TAG "C283") ALL 2,10:15,21
//$ value is 2,10:15,21
  S: C283 OK SEARCH completed

  C: C284 SEARCH RETURN (SAVE MIN) SINCE 12-Feb-2006
      NOT FROM "Smith"
  S: * ESEARCH (TAG "C284") MIN 2
//$ value is 2
  S: C284 OK SEARCH completed

  C: C285 SEARCH RETURN (MAX SAVE MIN) SINCE
      12-Feb-2006 NOT FROM "Smith"
  S: * ESEARCH (TAG "C285") MIN 2 MAX 21
//$ value is 2,21
  S: C285 OK SEARCH completed

  C: C286 SEARCH RETURN (MAX SAVE MIN COUNT)
      SINCE 12-Feb-2006 NOT FROM "Smith"
  S: * ESEARCH (TAG "C286") MIN 2 MAX 21 COUNT 8
//$ value is 2,10:15,21
  S: C286 OK SEARCH completed

  C: C286 SEARCH RETURN (ALL SAVE MIN) SINCE
      12-Feb-2006 NOT FROM "Smith"
  S: * ESEARCH (TAG "C286") MIN 2 ALL 2,10:15,21
//$ value is 2,10:15,21
  S: C286 OK SEARCH completed

6.4.5. FETCH Command โœจ

Arguments:

  • sequence set
  • message data item names or macro

Responses:

  • untagged responses: FETCH

Result:

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

The FETCH command pulls up data attached to a message in the mailbox ๐Ÿ“ฅ The data items you want can be a single atom or a parenthesized list.

Most data items, the ones listed under the msg-att-static rule in the formal syntax (Section 9), are static and MUST NOT change for any particular message. โœจ Other data items, the ones under the msg-att-dynamic rule, MAY change because of a STORE command or outside events. ๐Ÿฆ‹

For example, if a client gets an ENVELOPE for a message it already knows the envelope for, it can safely ignore the newly sent envelope. ๐Ÿ’…

There are three macros that bundle up commonly used sets of data items so you can use them instead of listing items one by one. A macro has to be used all on its own, never mixed with other macros or data items. ๐ŸŽ€

  • ALL: Macro equivalent to: (FLAGS INTERNALDATE RFC822.SIZE ENVELOPE)
  • FAST: Macro equivalent to: (FLAGS INTERNALDATE RFC822.SIZE)
  • FULL: Macro equivalent to: (FLAGS INTERNALDATE RFC822.SIZE ENVELOPE BODY)

Several data items reference "section" or "section-binary". See Section 6.4.5.1 for their detailed definition. ๐Ÿงš

The data items you can currently fetch are:

BINARY[<section-binary>]<<partial>> Asks for the specified section to be sent after its Content-Transfer-Encoding has been decoded. ๐ŸŒˆ

The <partial> argument, if present, asks for only a subset of the data to come back. A partial FETCH BINARY works the same way as a partial FETCH BODY, with one difference: the <partial> arguments refer to the DECODED section data. ๐Ÿ’–

Note that this data item can only be requested for leaf body parts: those with media types other than multipart/*, message/rfc822, or message/global.

BINARY.PEEK[<section-binary>]<<partial>> An alternate form of BINARY[<section-binary>] that doesn't implicitly set the \Seen flag. ๐Ÿ™ˆ

BINARY.SIZE[<section-binary>] Asks for the decoded size of the section (basically, the size you should expect back from the matching FETCH BINARY request). ๐Ÿ“

Note: client authors are cautioned that this might be an expensive operation for some server implementations. Asking for it when you don't need it could hurt performance, since servers would have to calculate the value every single time you request it. ๐Ÿ˜ญ

Note that this data item can only be requested for leaf body parts: those with media types other than multipart/*, message/rfc822, or message/global.

BODY A non-extensible form of BODYSTRUCTURE. ๐Ÿ“

BODY[<section>]<<partial>> The text of a particular body section. If BODY[] is specified (with the section left out), the FETCH is asking for the [RFC5322] expression of the entire message. ๐Ÿ“จ

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

Any partial fetch that tries to read past the end of the text gets truncated as needed. A partial fetch that starts at octet 0 comes back as a partial fetch, even when that truncation happens. ๐Ÿ’…

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

The \Seen flag gets implicitly set. If that makes the flags change, they SHOULD be included as part of the FETCH responses. โœจ

BODY.PEEK[<section>]<<partial>> An alternate form of BODY[<section>] that doesn't implicitly set the \Seen flag. ๐Ÿฆ‹

BODYSTRUCTURE The [MIME-IMB] body structure of the message. The server computes this by parsing the [MIME-IMB] header fields in the [RFC5322] header and the [MIME-IMB] headers. See Section 7.5.2 for more details. ๐Ÿงฉ

ENVELOPE The envelope structure of the message. The server computes this by parsing the [RFC5322] header into its component parts, filling in various fields with defaults where needed. See Section 7.5.2 for more details. ๐Ÿ’Œ

FLAGS The flags that are set for this message. ๐Ÿšฉ

INTERNALDATE The internal date of the message. ๐Ÿ—“๏ธ

RFC822.SIZE The size of the message, as defined in Section 2.3.4. ๐Ÿ“

UID The unique identifier for the message. ๐Ÿ”‘

Example:

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

6.4.5.1. FETCH Section Specification

okay so a bunch of FETCH data items point at a "section" or "section-binary" ๐Ÿงฉ A section specification is a set of zero or more part specifiers, separated by periods. Each part specifier is either a part number or one of these: HEADER, HEADER.FIELDS, HEADER.FIELDS.NOT, MIME, or TEXT. (Non-numeric part specifiers have to be the last one in a section specification. ๐Ÿ’…) An empty section specification means the entire message, header included. โœจ

Every message has at least one part number. Messages that don't use MIME, and MIME messages that aren't multipart and don't have an encapsulated message inside them, only have a part 1. ๐ŸŒธ

Multipart messages get consecutive part numbers, in the order they show up in the message. If a particular part is of type message or multipart, its parts MUST be indicated by a period followed by the part number within that nested multipart part. ๐ŸŽ€

A part of type MESSAGE/RFC822 or MESSAGE/GLOBAL also has nested part numbers, which refer to parts of the MESSAGE part's body. ๐Ÿฆ‹

The HEADER, HEADER.FIELDS, HEADER.FIELDS.NOT, and TEXT part specifiers can stand alone, or they can be prefixed by one or more numeric part specifiers, as long as that numeric part specifier refers to a part of type MESSAGE/RFC822 or MESSAGE/GLOBAL. The MIME part specifier MUST be prefixed by one or more numeric part specifiers. ๐Ÿง

The HEADER, HEADER.FIELDS, and HEADER.FIELDS.NOT part specifiers point at the [RFC5322] header of the message, or of an encapsulated [MIME-IMT] MESSAGE/RFC822 or MESSAGE/GLOBAL message. HEADER.FIELDS and HEADER.FIELDS.NOT are followed by a list of field-names (as defined in [RFC5322]) and give back a subset of the header. The HEADER.FIELDS subset only has the header fields whose field-name matches one of the names in the list. HEADER.FIELDS.NOT is the opposite: it only has the header fields whose field-name doesn't match. Field matching is ASCII-range case insensitive, but otherwise it's exact. ๐Ÿ”

Subsetting doesn't cut out the blank line from [RFC5322] that separates the header from the body. That blank line is included in every header fetch, except when the message has no body and no blank line. ๐Ÿซถ

The MIME part specifier points at the [MIME-IMB] header for that part. ๐Ÿ’œ

The TEXT part specifier points at the text body of the message, and it leaves out the [RFC5322] header. ๐Ÿ“

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

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

6.4.6. STORE Command ๐Ÿ’พ

Arguments:    sequence set

              message data item name

              value for message data item

Responses:    untagged responses:  FETCH

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

The STORE command changes data attached to a message in the mailbox. โœ๏ธ Normally, STORE gives back the updated value of the data in an untagged FETCH response. Adding a ".SILENT" suffix to the data item name stops that untagged FETCH, and the server SHOULD assume that the client has worked out the updated value itself, or doesn't care about it. ๐Ÿคซ

Note: Whether or not you used the ".SILENT" suffix, the server SHOULD send an untagged FETCH response if it sees a change to a message's flags coming from an external source. The point is that the flag status is known for sure, with no race condition. ๐Ÿ™ˆ

The data items you can store right now are:

FLAGS <flag list> : Replaces the flags for the message with the argument. The new value of the flags comes back as if you'd done a FETCH of those flags. ๐ŸŽ€

FLAGS.SILENT <flag list> : Same as FLAGS, but it doesn't send back a new value. ๐Ÿค

+FLAGS <flag list> : Adds the argument to the flags for the message. The new value comes back as if you'd done a FETCH of those flags. โž•

+FLAGS.SILENT <flag list> : Same as +FLAGS, but no new value comes back. ๐Ÿซฅ

-FLAGS <flag list> : Removes the argument from the flags for the message. The new value comes back as if you'd done a FETCH of those flags. โž–

-FLAGS.SILENT <flag list> : Same as -FLAGS, but no new value comes back. ๐ŸŒ™

Example:

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

6.4.7. COPY Command ๐Ÿ“‹

Arguments:    sequence set

              mailbox name

Responses:    no specific responses for this command

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

The COPY command copies the specified message(s) to the end of the destination mailbox you pick. ๐Ÿฆ‹ The flags and internal date of the message(s) SHOULD be kept in the copy. ๐ŸŒท

If the destination mailbox doesn't exist, a server MUST return an error. It MUST NOT automatically create the mailbox. ๐Ÿšซ 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 in the tagged NO response. That's basically a hint saying "hey, you can try a CREATE and then retry the COPY if the CREATE works." ๐Ÿ’ก

If COPY fails for any reason, server implementations MUST restore the destination mailbox to how it was before the COPY attempt (other than possibly incrementing UIDNEXT). In other words, a partial copy MUST NOT be done. ๐Ÿ˜ค

On a successful COPY, the server returns a COPYUID response code (see Section 7.1). There are two exceptions to this, listed below. โœจ

For a mailbox where the client has permission to COPY to it, but not to SELECT or EXAMINE it, the server MUST NOT send a COPYUID response code, because that would reveal information about the mailbox. ๐Ÿ”’

For a mailbox with UIDNOTSTICKY status (see Section 7.1), the server MAY leave out the COPYUID response code, since it doesn't mean anything there. ๐Ÿซ 

Example:

  C: A003 COPY 2:4 MEETING
  S: A003 OK [COPYUID 38505 304,319:320 3956:3958] COPY completed

6.4.8. MOVE Command ๐Ÿšš

Arguments:    sequence set

              mailbox name

Responses:    no specific responses for this command

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

The MOVE command moves the specified message(s) to the end of the destination mailbox. ๐Ÿ“ฆ The flags and internal date of the message(s) SHOULD be preserved. ๐ŸŒˆ

Basically, a new message is made in the target mailbox with a new UID, the original gets removed from the source mailbox, and to the client it looks like one single action. โœจ For each message, that has the same effect as this sequence:

  1. [UID] COPY
  2. [UID] STORE +FLAGS.SILENT \DELETED
  3. UID EXPUNGE

Even though MOVE does the same thing as those steps, the semantics aren't identical. The in-between states those steps produce don't happen, and the response codes are different. ๐Ÿซง Specifically, the COPY and EXPUNGE response codes still get returned, but response codes for a STORE MUST NOT be generated, and the \Deleted flag MUST NOT be set for any message. ๐Ÿ™…โ€โ™€๏ธ

Unlike COPY, a MOVE of a set of messages might fail partway through the set. No matter whether the whole set gets moved, each individual message MUST be either moved or left alone. The server MUST leave each message in a state where it's in at least one of the source or target mailboxes, so no message can get lost or orphaned. ๐Ÿงณ The server SHOULD NOT leave any message in both mailboxes, because a partial failure shouldn't result in a bunch of duplicate messages. ๐Ÿ‘ฏ This holds even if the server returns a tagged NO response to the command. ๐Ÿ’€

If the destination mailbox doesn't exist, a server MUST return an error. It MUST NOT automatically create the mailbox. Unless it's certain 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. Same vibe as COPY: it hints that the client can attempt a CREATE and retry the MOVE if the CREATE works. ๐Ÿ”

Because MOVE is so similar to COPY, any extensions that affect COPY affect MOVE in the same way. Response codes listed in Section 7.1, plus the ones defined by extensions, get sent the same way they are for COPY. ๐ŸŽ€

Servers send COPYUID in response to a MOVE or a UID MOVE (see Section 6.4.9) command. For more on COPYUID, check Section 7.1. Heads up: there are several exceptions listed in Section 6.4.7 that let servers skip COPYUID. ๐Ÿ‘€

Servers are also REQUIRED to send the COPYUID response code in an untagged OK before sending EXPUNGE or similar responses. Sending COPYUID in the tagged OK instead, as described in Section 6.4.7, means clients first get an EXPUNGE for a message and only afterwards the COPYUID for that same message. That order is genuinely annoying to process usefully. ๐Ÿ˜ญ

An example:

  C: a UID MOVE 42:69 foo
  S: * OK [COPYUID 432432 42:69 1202:1229]
  S: * 22 EXPUNGE
  ...More EXPUNGE responses from the server...
  S: a OK Done

The server might send unrelated EXPUNGE responses too, if some messages happen to get expunged at the same time. That's totally normal IMAP behaviour, bestie. ๐ŸŒธ

Moving a message to the currently selected mailbox (where the source and target mailboxes are the same) is allowed, as long as copying the message to the currently selected mailbox is allowed. ๐Ÿชž

The server may send EXPUNGE responses before the tagged response, so the client can't safely send more commands that use message sequence number arguments while the server is processing MOVE. ๐Ÿšง

MOVE and UID MOVE can be pipelined with other commands, but you have to be careful. Both commands change sequence numbers and also allow unrelated EXPUNGE responses. The renumbering of other messages in the source mailbox after any EXPUNGE response can be super surprising, and it makes it unsafe to pipeline any command that relies on message sequence numbers after a MOVE or UID MOVE. Similarly, MOVE can't be pipelined with a command that might cause message renumbering. ๐ŸŒ€ See Section 5.5 for more on the ambiguities, plus the handling requirements for both clients and servers. ๐Ÿซถ

6.4.9. UID Command

Arguments: command name

command arguments

Responses: untagged responses: FETCH, ESEARCH, EXPUNGE

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

Okay so the UID command is literally the bestie of the whole protocol ๐Ÿ’– It has three forms, and each one is a little different, so let's go through them. ๐ŸŽ€

In the first form, you give it a COPY, MOVE, FETCH, or STORE command, with the arguments that go with that command. The twist is that the numbers in the sequence-set are unique identifiers instead of message sequence numbers ๐Ÿฆ‹ Sequence-set ranges are allowed, but ngl there's no promise that unique identifiers will be contiguous, so don't assume they are ๐Ÿ™ˆ

A non-existent unique identifier gets ignored with no error message at all ๐Ÿ’€ So it's totally possible for a UID FETCH to come back OK with no data, or for a UID COPY, UID MOVE, or UID STORE to come back OK without doing anything. Not a bug, just vibes ๐ŸŒธ

In the second form, the UID command wraps an EXPUNGE command with an extra parameter, a sequence set of UIDs to operate on. UID EXPUNGE permanently removes all messages that have BOTH the \Deleted flag set AND a UID inside that sequence set, from the currently selected mailbox. If a message doesn't have the \Deleted flag set, or its UID isn't in the sequence set, it's not affected at all โœจ

UID EXPUNGE is especially useful for disconnected use clients ๐Ÿงš When you resync with the server, using UID EXPUNGE instead of plain EXPUNGE means the client can't accidentally nuke messages that other clients marked \Deleted in the meantime, between the last time it was connected and the moment it resyncs. Main character protection ๐Ÿ‘‘

Example:

C: A003 UID EXPUNGE 3000:3002
S: * 3 EXPUNGE
S: * 3 EXPUNGE
S: * 3 EXPUNGE
S: A003 OK UID EXPUNGE completed

In the third form, the UID command takes a SEARCH command with its SEARCH arguments. The arguments mean the same thing as they do for SEARCH, BUT the numbers in an ESEARCH response for a UID SEARCH are unique identifiers, not message sequence numbers ๐Ÿ“ Also, the matching ESEARCH response MUST include the UID indicator ๐Ÿซถ For example, UID SEARCH 1:100 UID 443:557 gives back the unique identifiers for the intersection of two sequence sets: the message sequence number range 1:100 and the UID range 443:557 ๐Ÿ”ฅ

Note: in that example, the UID range 443:557 shows up. The same thing about non-existent unique identifiers being ignored with no error message applies here too ๐Ÿ’… So even if neither UID 443 nor UID 557 exists, that range is still valid, and it would include an existing UID 495 ๐ŸŒˆ

Also note that a UID range of 559:* always includes the UID of the last message in the mailbox, even if 559 is higher than any UID that's been assigned ๐Ÿ˜ญ That's because the contents of a range don't depend on which order the endpoints are written in. So any UID range with * as one of the endpoints covers at least one message (the one with the highest UID), unless the mailbox is empty ๐Ÿฆ‹

The number after the "*" in an untagged FETCH or EXPUNGE response is ALWAYS a message sequence number, never a unique identifier, EVEN for a UID command response ๐Ÿ™ˆ However, server implementations MUST implicitly include the UID message data item as part of any FETCH response caused by a UID command, whether or not a UID was asked for as a message data item in the FETCH ๐Ÿ’œ

Note: The rule about including the UID message data item in a FETCH response mainly applies to UID FETCH and UID STORE, including a UID FETCH that doesn't list UID as a message data item. Even though the other UID commands are unlikely to cause an untagged FETCH, this rule applies to them too ๐ŸŒธ

Example:

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

6.5. Client Commands - Experimental/Expansion

Each command that is NOT part of this specification MUST have at least one capability name (see Section 6.1.1) associated with it. (Multiple commands can share the same capability name.) ๐Ÿ’œ

Server implementations MUST NOT send any added untagged responses (the ones not specified in this specification), UNLESS the client asked for them by issuing the associated experimental command (specified in an extension document) or the ENABLE command (Section 6.3.1). ๐Ÿ”ฅ

The example below shows how a client can check for the presence of a made-up XPIG-LATIN capability, one that adds the XPIG-LATIN command and the XPIG-LATIN untagged response ๐Ÿงš (Heads up: for an extension, the command name and the capability name don't have to match ๐ŸŒˆ)

Example:

C: a441 CAPABILITY
S: * CAPABILITY IMAP4rev2 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 ๐ŸŽ€ The info in a server response, the stuff labeled "Contents:" in the response descriptions below, is described by what it DOES, not by its syntax. The exact syntax of server responses lives in "Formal Syntax" (Section 9) ๐Ÿ’…

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

Status responses can be tagged or untagged. Tagged status responses tell you the completion result (OK, NO, or BAD) of a client command, and they carry a tag matching that command ๐Ÿฆ‹

Some status responses, and ALL server data, are untagged. An untagged response is marked with the token "*" instead of a tag. Untagged status responses give you the server greeting or server status that doesn't signal a command finishing (like an impending system shutdown alert) ๐Ÿ™ˆ For historical reasons, untagged server data responses are also called "unsolicited data," although strictly speaking, only unilateral server data is truly "unsolicited" ๐Ÿค“

Certain server data MUST be remembered by the client when it arrives, and the description of that data says so ๐Ÿ”ฅ This data carries critical info that affects how ALL later commands and responses get interpreted (for example, updates about messages being created or destroyed) ๐Ÿ’€

Other server data SHOULD be remembered for later reference. If the client doesn't need to remember it, or remembering it has no obvious purpose (for example, a SEARCH response when no SEARCH command is in progress), the data can be ignored ๐ŸŒธ

Here's an example of unilateral untagged server data: when the IMAP connection is in the selected state, the server checks the mailbox for new messages as part of command execution ๐Ÿงš Normally that happens with every command, so a NOOP command is enough to check for new messages โœจ If new messages turn up, the server sends an untagged EXISTS response with the new mailbox size ๐Ÿ‘‘ Server implementations that offer multiple simultaneous access to the same mailbox SHOULD also send appropriate unilateral untagged FETCH and EXPUNGE responses if another agent changes any message flags or expunges any 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 - Generic Status Responses ๐ŸŒˆ

Status responses are OK, NO, BAD, PREAUTH, and BYE ๐Ÿ’… OK, NO, and BAD can be tagged or untagged. PREAUTH and BYE are always untagged ๐Ÿซถ

Status responses MAY include an OPTIONAL "response code" ๐Ÿ”ฅ A response code is data inside square brackets, in the form of an atom, possibly followed by a space and arguments ๐Ÿ“ The response code carries extra info or status codes for client software beyond the OK/NO/BAD condition, and it's defined when there's a specific action a client can take based on that extra info โœจ

The currently defined response codes are:

ALERT The human-readable text contains a special alert that gets shown to the user in a way that grabs their attention ๐Ÿšจ Content of ALERT response codes received on a connection WITHOUT TLS or SASL security-layer confidentiality SHOULD be ignored by clients ๐Ÿ™ˆ If they ARE displayed, such alerts MUST be clearly marked as potentially suspicious ๐Ÿ’€ (Note that some existing clients are known to hyperlink returned text, which makes them very dangerous ๐Ÿ˜ญ) Alerts received AFTER a TLS/SASL confidentiality layer has been successfully set up MUST be presented to the user ๐Ÿ”

ALREADYEXISTS The operation tries to create something that already exists, like when a CREATE or RENAME command tries to make a mailbox and one with that name is already there ๐Ÿ’…

C: o356 RENAME this that
S: o356 NO [ALREADYEXISTS] Mailbox "that" already exists

APPENDUID Followed by the UIDVALIDITY of the destination mailbox and the UID assigned to the appended message in that mailbox, it tells you the message was appended to the destination mailbox with that UID ๐Ÿฆ‹

If the server also supports the [MULTIAPPEND] extension, AND multiple messages were appended in the APPEND command, then the second value is a UID set containing the UIDs assigned to the appended messages, in the order they were sent in the APPEND command ๐Ÿงš This UID set may NOT contain extraneous UIDs or the symbol "*" ๐Ÿ™…

Note: the UID set form of the APPENDUID response code MUST NOT be used if only a single message was appended. Specifically, a server MUST NOT send a range like 123:123. This is because a client that doesn't support [MULTIAPPEND] expects only a single UID, not a UID set ๐Ÿซฃ

UIDs are assigned in strictly ascending order in the mailbox (see Section 2.3.1.1). Also, a range of 12:10 is exactly equivalent to 10:12 and refers to the sequence 10,11,12 ๐ŸŒธ

This response code is returned in a tagged OK response to the APPEND command ๐Ÿ’œ

AUTHENTICATIONFAILED Authentication failed for some reason the server won't go into detail about. Typically this includes "unknown user" and "bad password" ๐Ÿ”’

This is the same as sending no response code at all, EXCEPT that when a client sees AUTHENTICATIONFAILED, it knows the problem wasn't, e.g., UNAVAILABLE, so there's no point retrying the same login/password later ๐Ÿ’€

C: b LOGIN "fred" "foo"
S: b NO [AUTHENTICATIONFAILED] Authentication failed

AUTHORIZATIONFAILED Authentication worked fine with the authentication identity, BUT the server can't or won't let that identity act as the requested authorization identity ๐Ÿ™… This only applies when the authentication and authorization identities are different ๐ŸŒˆ

C: c1 AUTHENTICATE PLAIN
[...]
S: c1 NO [AUTHORIZATIONFAILED] No such authorization-ID
        C: c2 AUTHENTICATE PLAIN
        [...]
        S: c2 NO [AUTHORIZATIONFAILED] Authenticator is not an admin

BADCHARSET ๐ŸŽ€ Optionally followed by a parenthesized list of charsets. A SEARCH failed because the given charset isn't supported by this implementation ๐Ÿ’€. If the optional list of charsets is given, it lists the charsets that are supported by this implementation, so the client has something to work with ๐Ÿซถ.

CANNOT ๐Ÿšซ This operation violates some invariant of the server and can never succeed. Not "try again later," just no. ๐Ÿ™…โ€โ™€๏ธ

        C: l create "///////"
        S: l NO [CANNOT] Adjacent slashes are not supported

CAPABILITY โœจ Followed by a list of capabilities. This can show up in the initial OK or PREAUTH response to transmit an initial capabilities list. It can also appear in tagged responses to LOGIN or AUTHENTICATE commands. Lowkey the best part: if a client recognizes this response code and nothing changed in the TLS and/or authentication state since it was received, the client doesn't need to send a separate CAPABILITY command. Efficient, bestie ๐Ÿงš

CLIENTBUG ๐Ÿ™ˆ The server has detected a client bug. This can accompany any of OK, NO, and BAD, depending on what the client bug is. So the vibe is "the server caught you," but the exact flavor depends on the mistake ๐Ÿ˜ญ

        C: k1 select "/archive/projects/experiment-iv"
        [...]
        S: k1 OK [READ-ONLY] Done
        C: k2 status "/archive/projects/experiment-iv" (messages)
        [...]
        S: k2 OK [CLIENTBUG] Done

CLOSED ๐Ÿฆ‹ The CLOSED response code has no parameters. A server returns it when the currently selected mailbox gets closed implicitly because of a SELECT or EXAMINE command on another mailbox. It works like a boundary line ๐ŸŒˆ: everything before the CLOSED response code is about the mailbox that got closed, and everything after it is about the newly selected mailbox. Main character handoff, iykyk.

There's no need to return the CLOSED response code on completion of the CLOSE or the UNSELECT command (or similar). Those commands just close the currently selected mailbox without opening a new one, so there's nothing to hand off ๐ŸŒธ

CONTACTADMIN ๐Ÿ“ž The user should contact the system administrator or support desk. Pretty self-explanatory, but still a whole vibe ๐Ÿ’…

        C: e login "fred" "foo"
        S: e NO [CONTACTADMIN]

COPYUID ๐Ÿ’– Followed by the UIDVALIDITY of the destination mailbox, a UID set containing the UIDs of the message(s) in the source mailbox that were copied to the destination mailbox, followed by another UID set containing the UIDs assigned to the copied message(s) in the destination mailbox. Put together, it says the message(s) got copied to the destination mailbox with the stated UID(s). Very organized, very iconic ๐Ÿ‘‘

The source UID set is in the order the message(s) was copied. The destination UID set lines up with the source UID set and is in that same order. Neither UID set may contain extraneous UIDs or the symbol "*". No sneaky extras allowed ๐Ÿ™…โ€โ™€๏ธ

UIDs are assigned in strictly ascending order in the mailbox (refer to Section 2.3.1.1). Also, a range of 12:10 is exactly equivalent to 10:12, and it refers to the sequence 10,11,12. Same squad, just reversed ๐Ÿ”

This response code is returned in a tagged OK response to the COPY or UID COPY command, or in the untagged OK response to the MOVE or UID MOVE command ๐ŸŽ€

CORRUPTION ๐Ÿ’€ The server discovered that some relevant data (e.g., the mailbox) is corrupt. This response code doesn't include any information about what's corrupt, but the server can write that to its logfiles. So the client gets the bad news, and the details live in the server's logs ๐Ÿ““

        C: i select "/archive/projects/experiment-iv"
        S: i NO [CORRUPTION] Cannot open mailbox

EXPIRED ๐Ÿฅ€ Either authentication succeeded or the server no longer had the necessary data. Either way, access is no longer permitted using that passphrase. The client or user should get a new passphrase ๐Ÿ”‘

        C: d login "fred" "foo"
        S: d NO [EXPIRED] That password isn't valid any more

EXPUNGEISSUED ๐Ÿงน Someone else has issued an EXPUNGE for the same mailbox. The client may want to issue NOOP soon. [IMAP-MULTIACCESS] discusses this subject in depth, so go read it if you're curious ๐Ÿค“

        C: h search from maria@example.com
        S: * ESEARCH (TAG "h") ALL 1:3,5,8,13,21,42
        S: h OK [EXPUNGEISSUED] Search completed

HASCHILDREN ๐Ÿ‘ถ The mailbox delete operation failed because the mailbox has one or more children, and the server doesn't allow deletion of mailboxes with children. Family tree says no ๐ŸŒณ

        C: m356 DELETE Notes
        S: o356 NO [HASCHILDREN] Mailbox "Notes" has children
        that need to be deleted first

INUSE ๐Ÿชต An operation hasn't been carried out because it involves sawing off a branch someone else is sitting on ๐Ÿ˜ค. Someone else may be holding an exclusive lock needed for this operation, or the operation may involve deleting a resource someone else is using, typically a mailbox. The operation may succeed if the client tries again later, so patience is the move โณ

        C: g delete "/archive/projects/experiment-iv"
        S: g NO [INUSE] Mailbox in use

LIMIT ๐Ÿงฎ The operation ran up against an implementation limit of some kind, such as the number of flags on a single message or the number of flags used in a mailbox. Even the best servers have a ceiling, bestie ๐Ÿ™ƒ

        C: m STORE 42 FLAGS f1 f2 f3 f4 f5 ... f250
        S: m NO [LIMIT] At most 32 flags in one mailbox supported

NONEXISTENT ๐Ÿ‘ป The operation attempts to delete something that does not exist. Similar to ALREADYEXISTS, just in the opposite direction ๐Ÿชž

        C: p RENAME this that
        S: p NO [NONEXISTENT] No such mailbox

NOPERM ๐Ÿ”’ The access control system (e.g., ACL; see [RFC4314]) does not permit this user to carry out an operation, such as selecting or creating a mailbox. Not on the list, not getting in ๐Ÿšช

        C: f select "/archive/projects/experiment-iv"
        S: f NO [NOPERM] Access denied

OVERQUOTA ๐Ÿ“ The user would be over quota after the operation. (The user may or may not be over quota already. Tea ๐Ÿซ–.)

Note that if the server sends OVERQUOTA but doesn't support the IMAP QUOTA extension defined by [RFC2087], then there is a quota, but the client can't find out what the quota is. Mysterious, honestly ๐Ÿ•ต๏ธโ€โ™€๏ธ

        C: n1 uid copy 1:* oldmail
        S: n1 NO [OVERQUOTA] Sorry

        C: n2 uid copy 1:* oldmail
        S: n2 OK [OVERQUOTA] You are now over your soft quota

PARSE ๐Ÿงฉ The human-readable text represents an error in parsing the [RFC5322] header or [MIME-IMB] headers of a message in the mailbox. The message's header is giving broken, and the server is calling it out ๐Ÿ“จ

PERMANENTFLAGS ๐Ÿท๏ธ Followed by a parenthesized list of flags, and it indicates which of the known flags the client can change permanently. Any flags that are in the FLAGS untagged response but not in the PERMANENTFLAGS list cannot be set permanently. The PERMANENTFLAGS list can also include the special flag *, which indicates that it's possible to create new keywords by attempting to store those keywords in the mailbox โœจ. If the client attempts to STORE a flag that is not in the PERMANENTFLAGS list, the server will either ignore the change or store the state change for the remainder of the current session only. Temporary is still a little bit real ๐Ÿ’ซ

There's no need for a server that included the special flag * to return a new PERMANENTFLAGS response code when a new keyword was successfully set on a message upon client request. However, if the server has a limit on the number of different keywords that can be stored in a mailbox and that limit is reached, the server MUST send a new PERMANENTFLAGS response code without the special flag *. That one's a hard rule, no exceptions ๐Ÿšจ

PRIVACYREQUIRED ๐Ÿ•ถ๏ธ The operation is not permitted due to a lack of data confidentiality. If TLS isn't in use, the client could try STARTTLS (see Section 6.2.1) or alternatively reconnect on an Implicit TLS port, and then repeat the operation. Get the privacy first, then try again ๐Ÿ”

        C: d login "fred" "foo"
        S: d NO [PRIVACYREQUIRED] Connection offers no privacy

        C: d select inbox
        S: d NO [PRIVACYREQUIRED] Connection offers no privacy

READ-ONLY ๐Ÿ‘€ The mailbox is selected as read-only, or its access while selected has changed from read-write to read-only. Look, don't touch ๐Ÿ“–

READ-WRITE โœ๏ธ The mailbox is selected as read-write, or its access while selected has changed from read-only to read-write. Okay, now you can touch ๐Ÿฅฐ

SERVERBUG ๐Ÿ› The server encountered a bug in itself or violated one of its own invariants. Oops, the server messed up, and it's saying so out loud ๐Ÿ˜ญ

        C: j select "/archive/projects/experiment-iv"
        S: j NO [SERVERBUG] This should not happen

TRYCREATE ๐Ÿ› ๏ธ An APPEND, COPY, or MOVE attempt is failing because the target mailbox does not exist (as opposed to some other reason). This is a hint to the client that the operation can succeed if the mailbox is first created by the CREATE command. Build it first, then slay ๐Ÿ’…

UIDNEXT ๐Ÿ”ข Followed by a decimal number, and it indicates the next unique identifier value. Refer to Section 2.3.1.1 for more information ๐Ÿ“š

UIDNOTSTICKY ๐Ÿชจ The selected mailbox is supported by a mail store that does not support persistent UIDs. That means UIDVALIDITY will be different each time the mailbox is selected. Consequently, APPEND or COPY to this mailbox will not return an APPENDUID or COPYUID response code ๐Ÿ™ƒ

This response code is returned in an untagged NO response to the SELECT command.

Note: servers SHOULD NOT have any UIDNOTSTICKY mail stores. This facility exists to support legacy mail stores in which it is technically infeasible to support persistent UIDs. This should be avoided when designing new mail stores. Legacy only, please ๐Ÿง“

UIDVALIDITY ๐Ÿ†” Followed by a decimal number, and it indicates the unique identifier validity value. Refer to Section 2.3.1.1 for more information ๐Ÿชช

UNAVAILABLE ๐Ÿ”Œ Temporary failure because a subsystem is down. For example, an IMAP server that uses a Lightweight Directory Access Protocol (LDAP) or Radius server for authentication might use this response code when the LDAP/Radius server is down. Backend said "brb" ๐Ÿ•ฐ๏ธ

        C: a LOGIN "fred" "foo"
        S: a NO [UNAVAILABLE] User's backend down for maintenance

UNKNOWN-CTE ๐Ÿงพ The server does not know how to decode the section's Content-Transfer-Encoding. The encoding is giving unreadable, and the server is not pretending it can read it ๐Ÿคทโ€โ™€๏ธ

Client implementations MUST ignore response codes that they do not recognize. Yes, even the mystery ones, because that's how we stay compatible ๐ŸŒˆ

7.1.1. OK Response

Contents: OPTIONAL response code human-readable text

The OK response indicates an information message from the server. When tagged, it indicates successful completion of the associated command ๐ŸŽ‰. The human-readable text MAY be presented to the user as an information message. The untagged form indicates an information-only message; the nature of the information MAY be indicated by a response code ๐Ÿ’œ.

The untagged form is also used as one of three possible greetings at connection startup. It indicates that the connection is not yet authenticated and that a LOGIN or an AUTHENTICATE command is needed ๐Ÿ”‘. Hello, now log in, babe ๐Ÿซถ

Example:

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

7.1.2. NO Response

Contents: OPTIONAL response code human-readable text

The NO response is the server's way of saying "hmm, something went wrong operationally" ๐Ÿ’… When it's tagged, it means the command you sent didn't finish successfully. When it's untagged, it's more of a heads-up or warning, and the command can still complete just fine โœจ The human-readable text is where the server explains what's going on.

Example:

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

Wait, I need to correct that example. Here is the exact transcript, character for character:

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

Okay bestie, that's the real one ๐Ÿซถ The untagged NO lines are warnings, and the tagged NO at the end is the one that means the COPY actually failed ๐Ÿ˜ญ

7.1.3. BAD Response

Contents: OPTIONAL response code human-readable text

Okay so BAD is the server basically saying "that's a protocol-level error" ๐Ÿ™ˆ When it's tagged, it's pointing at the exact command that caused the problem, and the tag tells you which one. When it's untagged, the server can't pin the error on a specific command, or something inside the server itself broke. Either way, the human-readable text explains the situation ๐Ÿ’œ

Example:

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

7.1.4. PREAUTH Response

Contents: OPTIONAL response code human-readable text

PREAUTH is always untagged and it's one of the three possible greetings when you first connect ๐Ÿฆ‹ It means the connection was already authenticated some other way, so you don't need to send LOGIN or AUTHENTICATE. Lowkey iconic, but there's a catch: since PREAUTH drops you straight into the authenticated state, it kind of blocks you from using STARTTLS (Section 6.2.1). So the PREAUTH response SHOULD only be sent by servers on connections already protected by TLS (like an Implicit TLS port [RFC8314]) or protected some other way, like IPsec. Clients that need mandatory TLS MUST close the connection after getting PREAUTH on a port that isn't protected ๐Ÿšจ

Example:

S: * PREAUTH IMAP4rev2 server logged in as Smith

7.1.5. BYE Response

Contents: OPTIONAL response code human-readable text

BYE is always untagged and it means the server is about to close the connection ๐Ÿ‘‹ The human-readable text MAY be shown to the user in a status report by the client. A BYE gets sent in one of four situations:

  1. as part of a normal logout sequence. The server will close the connection after sending the tagged OK response to the LOGOUT command.
  2. as a panic shutdown announcement. The server closes the connection immediately.
  3. as an announcement of an inactivity autologout. The server closes the connection immediately.
  4. as one of three possible greetings at connection startup, indicating that the server is not willing to accept a connection from this client. The server closes the connection immediately.

The difference between a BYE from a normal LOGOUT (the first case) and a BYE from a failure (the other three) is that in the failure cases the connection closes right away ๐Ÿ˜ญ In every case, the client SHOULD keep reading response data from the server until the connection is closed. That way any pending untagged or completion responses still get read and processed ๐Ÿซถ

Example:

S: * BYE Autologout; idle for too long

7.2. Server Responses - Server Status

These responses are always untagged. This is how server status data gets sent from the server to the client ๐Ÿ’–

7.2.1. ENABLED Response

Contents: capability listing

The ENABLED response shows up as a result of an ENABLE command โœจ The capability listing is a space-separated list of capability names that the server supports and that were successfully enabled. The ENABLED response MAY contain no capabilities, which means none of the extensions the client asked for got enabled ๐Ÿ’€

Example:

S: * ENABLED CONDSTORE QRESYNC

7.2.2. CAPABILITY Response

Contents: capability listing

The CAPABILITY response comes back as a result of a CAPABILITY command ๐ŸŒˆ The capability listing is a space-separated list of capability names the server supports. The capability listing MUST include the atom "IMAP4rev2", but it doesn't have to be the first one listed. Order doesn't mean anything here, so don't stress about it ๐ŸŽ€

Client and server implementations MUST implement the capabilities "AUTH=PLAIN" (described in [PLAIN]), and MUST implement "STARTTLS" and "LOGINDISABLED" on the cleartext port. Check out the Security Considerations (Section 11) for important info about these capabilities ๐Ÿ”ฅ

A capability name that begins with "AUTH=" tells you the server supports that particular authentication mechanism [SASL] ๐Ÿ”‘

The LOGINDISABLED capability means the LOGIN command is turned off. The server will reply with a tagged NO response to any attempt to use LOGIN, even if the user name and password are valid (their validity will not be checked) ๐Ÿ™…

An IMAP client MUST NOT issue the LOGIN command if the server advertises the LOGINDISABLED capability.

Other capability names mean the server supports an extension, revision, or amendment to the IMAP4rev2 protocol. If the IMAP4rev1 capability is not advertised, server responses MUST conform to this document until the client issues a command that uses an additional capability. If both IMAP4rev1 and IMAP4rev2 capabilities are advertised, server responses MUST conform to [RFC3501] until the client issues a command that uses an additional capability. (For example, the client can issue ENABLE IMAP4rev2 to turn on IMAP4rev2-specific behavior ๐Ÿงš)

Capability names SHOULD be registered with IANA using the RFC Required policy [RFC8126]. A server SHOULD NOT offer unregistered capability names ๐Ÿ™ˆ

Client implementations SHOULD NOT require any capability name other than "IMAP4rev2", and possibly "STARTTLS" and "LOGINDISABLED" (on a cleartext port). Client implementations MUST ignore any unknown capability names ๐Ÿ’…

A server MAY send capabilities automatically, by using the CAPABILITY response code in the initial PREAUTH or OK responses and by sending an updated CAPABILITY response code in the tagged OK response as part of a successful authentication. A client doesn't need to send a separate CAPABILITY command if it recognizes these automatic capabilities and nothing changed in the TLS and/or authentication state since they arrived ๐Ÿฆ‹

The list of capabilities a server returns MAY change during the connection. It's quite common for the server to change the list after successful TLS negotiation (STARTTLS command) and/or after successful authentication (AUTHENTICATE or LOGIN commands) ๐ŸŒธ

Example:

S: * CAPABILITY STARTTLS AUTH=GSSAPI IMAP4rev2 LOGINDISABLED
 XPIG-LATIN

Note that in the above example, XPIG-LATIN is a fictitious capability name ๐Ÿงš

7.3. Server Responses - Mailbox Status

These responses are always untagged. This is how mailbox status data gets sent from the server to the client. Many of these responses typically come from a command with the same name ๐Ÿ“

7.3.1. LIST Response ๐ŸŽ€

Okay so the LIST response is what the server sends back when you send a LIST command ๐Ÿ’Œ Each one hands you back a single name that matches your LIST spec, and you can get loads of them for one command. Here's what the bundle looks like:

Contents:
            name attributes
            hierarchy delimiter
            name
            OPTIONAL extension data

Let's talk about the base mailbox name attributes first, aka the little vibe tags that describe a mailbox ๐Ÿฆ‹

\NonExistent

The "\NonExistent" attribute means the mailbox name doesn't point to a real mailbox ๐Ÿ‘ป It's not really useful on its own, because names that match the canonical LIST pattern but don't exist must not be returned unless one of the two conditions below is also satisfied:

  1. The mailbox name also satisfies the selection criteria (for example, it is subscribed and the "SUBSCRIBED" selection option has been specified).
  2. "RECURSIVEMATCH" has been specified, and the mailbox name has at least one descendant mailbox name that does not match the LIST pattern and does match the selection criteria.

In practice, the "\NonExistent" attribute is usually returned with one or more of "\Subscribed", "\Remote", "\HasChildren", or the CHILDINFO extended data item. โœจ

The "\NonExistent" attribute implies "\NoSelect". ๐Ÿ™ˆ

\Noinferiors

No child levels of hierarchy can exist under this name. None exist now, and none can be created in the future. Bestie, that's a hard no ๐Ÿšซ

\Noselect

You can't use this name as a selectable mailbox. Iykyk ๐Ÿ’€

\HasChildren

This attribute tells you the mailbox has child mailboxes ๐ŸŒณ A server SHOULD NOT set this attribute if there are child mailboxes and the user does not have permission to access any of them. In that case, \HasNoChildren SHOULD be used. Sometimes though, a server can't efficiently figure out whether the user can access any child mailboxes, so it's not always that simple ๐Ÿฅบ

Also, even though the \HasChildren attribute for a mailbox must be correct at the time the server processes the mailbox, a client must be prepared for a plot twist: the mailbox is marked with \HasChildren, but no child mailbox shows up in the response to the LIST command. This could happen if another client deleted the children, or made them inaccessible to the user with access control, before the server got around to listing them. Main character energy from the server, honestly ๐Ÿ˜ญ

\HasNoChildren

This attribute means the mailbox has NO child mailboxes that are accessible to the currently authenticated user ๐Ÿ™…โ€โ™€๏ธ

\Marked

The server has marked this mailbox as "interesting" โญ It probably contains messages that were added since the last time the mailbox was selected.

\Unmarked

The mailbox doesn't contain any additional messages since the last time it was selected. Nothing new, bestie ๐Ÿ“

\Subscribed

The mailbox name was subscribed to using the SUBSCRIBE command ๐Ÿ””

\Remote

The mailbox is a remote mailbox ๐Ÿ›ฐ๏ธ

It is an error for the server to return both a \HasChildren and a \HasNoChildren attribute in the same LIST response. If a client runs into a LIST response with both of those attributes present, it should act as if both are absent in that LIST response. Not the vibe, so we just ignore both ๐Ÿ™ƒ

Note: the \HasNoChildren attribute should not be confused with the \NoInferiors attribute, which indicates that no child mailboxes exist now and none can be created in the future. Different vibes, totally different things!

If it isn't feasible for the server to determine whether or not the mailbox is "interesting", the server SHOULD NOT send either \Marked or \Unmarked. The server MUST NOT send more than one of \Marked, \Unmarked, and \Noselect for a single mailbox, and it MAY send none of these. Choose your fighter, but never more than one ๐ŸฅŠ

In addition to the base mailbox name attributes above, an IMAP server MAY also include any or all of the following attributes that denote the "role" (or "special-use") of a mailbox ๐Ÿ’ผ These get included along with the base attributes. A given mailbox may have none, one, or more than one of these. Sometimes a special use is advice to a client about what to put in that mailbox, and other times it's advice about what to expect to find there. Both are iconic ๐Ÿ‘‘

\All

This mailbox presents all messages in the user's message store ๐Ÿ“š Implementations MAY omit some messages, such as, perhaps, those in \Trash and \Junk. When this special use is supported, it is almost certain to be a virtual mailbox.

\Archive

This mailbox is used to archive messages ๐Ÿ—„๏ธ What an "archival" mailbox means is server dependent. Typically, it's used to get messages out of the inbox, or otherwise keep them out of the user's way, while still keeping them accessible.

\Drafts

This mailbox holds draft messages, usually messages that are being composed but haven't been sent yet โœ๏ธ On some servers this might be a virtual mailbox, holding messages from other mailboxes that are marked with the "\Draft" message flag. Or it might just be advice that a client put drafts here.

\Flagged

This mailbox presents all messages marked in some way as "important" ๐Ÿšฉ When this special use is supported, it's likely a virtual mailbox collecting messages (from other mailboxes) that are marked with the "\Flagged" message flag.

\Junk

This is where messages deemed to be junk mail get held ๐Ÿ—‘๏ธ Some servers might put messages here automatically. Or it might just be advice for a client-side spam filter. Ew, but make it organized ๐Ÿ™„

\Sent

This mailbox holds copies of messages that have been sent ๐Ÿ“ค Some servers might put messages here automatically. Or it might just be advice that a client save sent messages here.

\Trash

This mailbox holds messages that have been deleted or marked for deletion ๐Ÿงบ On some servers this might be a virtual mailbox, holding messages from other mailboxes that are marked with the "\Deleted" message flag. Or it might just be advice that a client that doesn't use the IMAP "\Deleted" model should use as its trash location. On servers that strictly expect the IMAP "\Deleted" model, this special use is likely not supported.

All special-use attributes are OPTIONAL, and any given server or message store may support any combination of them, or none at all. Usually there's at most one mailbox with a given attribute for a given user, but on some servers or message stores it's possible for multiple mailboxes to have the same special-use attribute ๐Ÿงฉ

Special-use attributes are likely to be user specific ๐Ÿ’… For example, User Adam might share his \Sent mailbox with user Barb, but that mailbox is unlikely to also serve as Barb's \Sent mailbox. Not everyone gets the same main character mailbox!

Other mailbox name attributes can be found in the "IMAP Mailbox Name Attributes" registry [IMAP-MAILBOX-NAME-ATTRS-REG] ๐Ÿ“‹

The hierarchy delimiter is the character used to separate levels of hierarchy in a mailbox name ๐ŸŒฟ A client can use it to create child mailboxes and to search higher or lower levels of the naming hierarchy. All children of a top-level hierarchy node MUST use the same separator character. A NIL hierarchy delimiter means there's no hierarchy, 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 the LIST command. Unless \Noselect or \NonExistent is indicated, the name MUST also be valid as an argument for commands, such as SELECT, that accept mailbox names. So it has to work everywhere, periodt ๐Ÿ’–

The name might be followed by an OPTIONAL series of extended fields, which is a parenthesized list of tagged data (also called an "extended data item") ๐ŸŽ The first element of an extended field is a string that identifies the type of data. [RFC5258] specifies requirements on string registration (these strings are called "tags", and they're not to be confused with IMAP command tags). In particular, it states that "Tags MUST be registered with IANA". This document doesn't change that. See Section 9.5 of [RFC5258] for the registration template. The server MAY return data in the extended fields that the client didn't directly ask for in the corresponding LIST command. For example, the client can enable extra extended fields by using another IMAP extension that makes use of the extended LIST responses. The client MUST ignore all extended fields it doesn't recognize, so no drama ๐Ÿซถ

Example:

S: * LIST (\Noselect) "/" ~/Mail/foo

Example:

S: * LIST (\Marked) ":" Tables (tablecloth (("edge" "lacy")
    ("color" "red")) Sample "text")
S: * LIST () ":" Tables:new (tablecloth ("edge" "lacy")
    Sample ("text" "more text"))

7.3.2. NAMESPACE Response ๐ŸŒธ

Contents:

Contents:   the prefix and hierarchy delimiter to the server's
            Personal Namespace(s), Other Users' Namespace(s), and
            Shared Namespace(s)

The NAMESPACE response happens as a result of a NAMESPACE command ๐Ÿ—บ๏ธ It gives you the prefix and hierarchy delimiter for the server's Personal Namespace(s), Other Users' Namespace(s), and Shared Namespace(s) that the server wants to expose. For any namespace class that isn't available, the response will contain a NIL. The Namespace-Response-Extensions ABNF non-terminal is defined for extensibility and MAY be included in the response. Extensible and open to growth, love that for it ๐Ÿฆ‹

Example:

S: * NAMESPACE (("" "/")) (("~" "/")) NIL

7.3.3. STATUS Response โœจ

Contents:

Contents:
            name
            status parenthesized list

The STATUS response happens as a result of a STATUS command ๐Ÿ“Š It returns the mailbox name that matches the STATUS specification, along with the requested mailbox status information. Quick and to the point, I respect it ๐Ÿ’…

Example:

S: * STATUS blurdybloop (MESSAGES 231 UIDNEXT 44292)

7.3.4. ESEARCH Response ๐Ÿ”โœจ

Contents: one or more search-return-data pairs

Okay bestie, the ESEARCH response shows up whenever the server answers a SEARCH or UID SEARCH command ๐Ÿ’… It starts with an optional search correlator. If that's missing, the response wasn't triggered by one specific IMAP command. If it's there, it holds the tag of the command that caused it to be sent ๐ŸŽ€

After the correlator comes an optional UID indicator. When that's present, everything in the ESEARCH response is about UIDs. When it isn't, all the data is about message numbers ๐Ÿฆ‹

The rest of the response is one or more search data pairs. Each pair starts with a unique return item name, then a space, then its data. The pairs can come in any order ๐ŸŒˆ Unless an extension says otherwise, a return item name SHOULD appear only once in an ESEARCH response ๐Ÿ’œ

This document specifies these return item names:

MIN Returns the lowest message number or UID that matches the SEARCH criteria. ๐ŸŒธ

If the SEARCH finds no matches, the server MUST NOT include the MIN return item in the ESEARCH response. It still MUST send the ESEARCH response though, so it's not skipping out on the whole thing ๐Ÿ™ˆ

MAX Returns the highest message number or UID that matches the SEARCH criteria. ๐Ÿ‘‘

If the SEARCH finds no matches, the server MUST NOT include the MAX return item in the ESEARCH response. It still MUST send the ESEARCH response ๐Ÿ’…

ALL Returns every message number or UID that matches the SEARCH criteria, written using the sequence-set syntax. Each set MUST be complete. Specifically, a UID set only shows up in an ESEARCH response when every number in the range corresponds to an existing (matching) message. The client MUST NOT assume that messages or UIDs will be listed in any particular order ๐Ÿ˜ญ

If the SEARCH finds no matches, the server MUST NOT include the ALL return item in the ESEARCH response. It still MUST send the ESEARCH response โœจ

COUNT Returns the number of messages that match the SEARCH criteria. This return item MUST always be included in the ESEARCH response ๐Ÿ”ฅ

Example:

  S: * ESEARCH UID COUNT 17 ALL 4:18,21,28

Example:

  S: * ESEARCH (TAG "a567") UID COUNT 17 ALL 4:18,21,28

Example:

  S: * ESEARCH COUNT 18 ALL 1:17,21

7.3.5. FLAGS Response ๐Ÿšฉ

Contents: flag parenthesized list

The FLAGS response happens when the client runs a SELECT or EXAMINE command. The flag parenthesized list tells you which flags apply to this mailbox, and at a minimum that includes the system-defined flags. Other flags can exist too, depending on how the server is implemented ๐ŸŒท

The update from the FLAGS response MUST be remembered by the client. Literally keep that in your memory bank ๐Ÿง ๐Ÿ’–

Example:

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

7.4. Server Responses - Mailbox Size ๐Ÿ“ฆ

These responses are always untagged. This is how the server tells the client that the mailbox size has changed ๐Ÿ“ Right after the "*" token there's a number, and that number is a message count ๐Ÿ”ข

7.4.1. EXISTS Response ๐Ÿงš

Contents: 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 messages arrive) ๐Ÿ“ฌ

The update from the EXISTS response MUST be remembered by the client. Keep track of that count, bestie ๐Ÿ’œ

Example:

  S: * 23 EXISTS

7.5. Server Responses - Message Status ๐Ÿ’Œ

These responses are always untagged. This is how the server sends message data to the client, often because of a command that has the same name. Right after the "*" token is a number, and that number is a message sequence number ๐ŸŒˆ

7.5.1. EXPUNGE Response ๐Ÿ—‘๏ธ

Contents: none

The EXPUNGE response tells you that the message sequence number you named has been permanently removed from the mailbox ๐Ÿ’€ The message sequence number of each message after it goes down by 1 right away, and that decrease shows up in message sequence numbers in later responses, including other untagged EXPUNGE responses ๐Ÿฆ‹

The EXPUNGE response also lowers the number of messages in the mailbox. You don't need to send an EXISTS response with the new count, because it's already handled ๐Ÿ’…

Here's the tricky bit: because of that immediate decrement rule, the message sequence numbers in a run of successive EXPUNGE responses depend on the order the messages get removed. If they go from lower numbers to higher, or from higher numbers to lower, the output looks different. For example, if the last 5 messages in a 9-message mailbox are 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 ๐Ÿคฏ

An EXPUNGE response MUST NOT be sent when no command is in progress, and it MUST NOT be sent while responding to a FETCH, STORE, or SEARCH command. This rule keeps the message sequence numbers from getting out of sync between client and server, so it's super important ๐Ÿซถ A command isn't "in progress" until the complete command has been received. In particular, a command isn't "in progress" while the command continuation is being negotiated ๐Ÿ™ˆ

Note: UID FETCH, UID STORE, and UID SEARCH are different commands from FETCH, STORE, and SEARCH. An EXPUNGE response MAY be sent during a UID command. ๐ŸŽ€

The update from the EXPUNGE response MUST be remembered by the client.

Example:

  S: * 44 EXPUNGE

7.5.2. FETCH Response ๐ŸŽ

Contents: message data

The FETCH response sends data about a message back to the client. The data comes as pairs of data item names and values, and the values go inside parentheses ๐ŸŽ€ This response happens as the result of a FETCH or STORE command, and it can also happen when the server decides to do it on its own (like flag updates) โœจ

The current data items are:

BINARY[<section-binary>]<<number>> This is an <nstring> or <literal8> with the content of the specified section, after removing any encoding named in the matching Content-Transfer-Encoding header field. If <number> is present, it refers to the offset within the DECODED section data ๐Ÿ”“

If the domain of the decoded data is "8bit" and the data doesn't contain the NUL octet, the server SHOULD return the data in a <string> instead of a <literal8>. This lets the client figure out whether the "8bit" data has a NUL octet without having to scan the whole data stream for NULs ๐Ÿ•ต๏ธโ€โ™€๏ธ

Messaging clients and servers have been notoriously lax about the Internet CRLF convention for ending lines of textual data (text/* media types) in Internet protocols. Ugh, the worst ๐Ÿ˜ญ When sending data in a BINARY[...] FETCH data item, servers MUST ensure that textual line-oriented sections are always sent using the IMAP CRLF line termination syntax. This applies no matter how the data is stored on the server ๐Ÿ’…

If the server doesn't know how to decode the section's Content-Transfer-Encoding, it MUST fail the request and issue a "NO" response that contains the UNKNOWN-CTE response code ๐Ÿ’€

BINARY.SIZE[<section-binary>] This is the size of the section after removing any encoding named in the matching Content-Transfer-Encoding header field. The value returned MUST match the size of the <nstring> or <literal8> that the corresponding FETCH BINARY request returns ๐Ÿ“

If the server doesn't know how to decode the section's Content-Transfer-Encoding, it MUST fail the request and issue a "NO" response that contains the UNKNOWN-CTE response code ๐Ÿ™…โ€โ™€๏ธ

BODY This is a form of BODYSTRUCTURE without the extension data ๐Ÿงฉ

BODY[<section>]<<origin octet>> This is a string with the body contents of the specified section. The client SHOULD interpret the string according to the content transfer encoding, body type, and subtype ๐ŸŒธ

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

Note: The origin octet facility MUST NOT be used by a server in a FETCH response unless the client specifically requested it with a FETCH of a BODY[<section>]<<partial>> data item. ๐Ÿšซ

8-bit textual data is allowed if a [CHARSET] identifier is part of the body parameter parenthesized list for this section. Headers (the HEADER or MIME part specifiers, or the header portion of a MESSAGE/RFC822 or MESSAGE/GLOBAL part) MAY be in UTF-8. Also, the [RFC5322] delimiting blank line between the header and the body isn't affected by header-line subsetting. The blank line is always included as part of the header data, except when a message has no body and no blank line ๐Ÿฆ‹

Non-textual data, like binary data, MUST be transfer encoded into a textual form, such as base64, before it's sent to the client. To get the original binary data back, the client MUST decode the transfer-encoded string ๐Ÿ”

BODYSTRUCTURE This is a parenthesized list that describes the [MIME-IMB] body structure of a message. The server works it out by parsing the [MIME-IMB] header fields and filling in defaults for various fields where needed ๐Ÿงฑ

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

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

Multiple parts are shown with parenthesis nesting. Instead of a body type as the first element of the parenthesized list, there's a sequence of one or more nested body structures. The second element of the parenthesized list is the multipart subtype (mixed, digest, parallel, alternative, etc.) ๐Ÿช†

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

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

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

body parameter parenthesized list This is a parenthesized list of attribute/value pairs, as defined in [MIME-IMB]. For example, ("foo" "bar" "baz" "rag") means "bar" is the value of "foo", and "rag" is the value of "baz" ๐ŸŽ€ Servers SHOULD decode parameter-value continuations and parameter-value character sets as described in [RFC2231]. For example, if the message contains parameters "baz*0", "baz*1", and "baz*2", the server should decode them per [RFC2231], concatenate them, and return the resulting value as a parameter "baz". Similarly, if the message contains parameters "foo*0*" and "foo*1*", the server should decode them per [RFC2231], convert to UTF-8, concatenate them, and return the resulting value as a parameter "foo*" ๐ŸŒˆ

Okay bestie, we're still in BODYSTRUCTURE land ๐Ÿ’…โœจ The body disposition field is a parenthesized list: a disposition type string, then a parenthesized list of attribute/value pairs, all defined in [DISPOSITION]. Servers SHOULD decode parameter-value continuations as described in [RFC2231] ๐ŸŽ€

body language is a string or parenthesized list with the body language value from [LANGUAGE-TAGS] ๐ŸŒธ

body location is a string with the body content URI from [LOCATION] ๐Ÿฆ‹

Any extension data after that is not defined yet in this version of the protocol ๐Ÿ™ˆ It can be zero or more NILs, strings, numbers, or nested parenthesized lists of those. Client implementations that do a BODYSTRUCTURE fetch MUST be prepared to accept it. Server implementations MUST NOT send it until a revision of this protocol has defined it. Very strict, very important ๐Ÿ’€

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

body type is a string with the content media-type name from [MIME-IMB] ๐Ÿ’–

body subtype is a string with the content subtype name from [MIME-IMB] ๐Ÿ’œ

body parameter parenthesized list is a parenthesized list of attribute/value pairs, like ("foo" "bar" "baz" "rag"), where "bar" is the value of "foo" and "rag" is the value of "baz". It's defined in [MIME-IMB] โœจ

body id is a string with the Content-ID header field value, as defined in Section 7 of [MIME-IMB] ๐Ÿซถ

body description is a string with the Content-Description header field value, as defined in Section 8 of [MIME-IMB] ๐ŸŒˆ

body encoding is a string with the content transfer encoding, as defined in Section 6 of [MIME-IMB] ๐Ÿ“

body size is a number giving the size of the body in octets. This size is measured in its transfer encoding, NOT after any decoding. (Sorry, I had to yell that, it's a classic trap ๐Ÿ˜ญ)

A body type of type MESSAGE and subtype RFC822 has, right after the basic fields, the envelope structure, the body structure, and the 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, that size is in its content transfer encoding, not the decoded size ๐Ÿงš

Extension data follows the basic fields and the type-specific fields above. It's never returned with the BODY fetch, but it can come back with a BODYSTRUCTURE fetch. If it's present, it MUST be in the defined order ๐Ÿ‘‘

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

body MD5 is a string with the body MD5 value from [MD5] ๐Ÿ”ฅ

body disposition has the same content and function as the body disposition for a multipart body part ๐Ÿ’…

body language is a string or parenthesized list with the body language value from [LANGUAGE-TAGS] ๐ŸŒธ

body location is a string with the body content URI from [LOCATION] ๐Ÿฆ‹

Any extension data after that is still not defined in this version and would work the same way as the multipart extension data above ๐Ÿ™ˆ

ENVELOPE is a parenthesized list describing the envelope structure of a message. The server computes it by parsing the [RFC5322] header into its component parts, filling in defaults for various fields where needed ๐Ÿ’Œ

The envelope fields 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 describing an electronic mail address. Its fields come in this order: display name, the [SMTP] at-domain-list (the source route and obs-route ABNF production from [RFC5322]), the mailbox name (the local-part ABNF production from [RFC5322]), and the hostname ๐Ÿ—บ๏ธ

[RFC5322] group syntax shows up as a special address structure where the hostname field is NIL. If the mailbox name is also NIL, it's an end-of-group marker (the semicolon in RFC 822 syntax). If the mailbox name is non-NIL, it's a start-of-group marker, and the mailbox name holds the group name phrase ๐Ÿงฉ

If the Date, Subject, In-Reply-To, and Message-ID header fields are missing from the [RFC5322] header, the matching envelope member is NIL. If those header fields are present but empty, the matching member is the empty string ๐Ÿซง

Note: some servers may return a NIL envelope member in the "present but empty" case. Clients SHOULD treat NIL and the empty string as identical.
Note: [RFC5322] requires that all messages have a valid Date header field. So for a well-formed message, the date member can't be NIL or the empty string. It can be NIL for a malformed or draft message ๐Ÿ“
Note: [RFC5322] requires that In-Reply-To and Message-ID header fields, if present, have non-empty content. So for a well-formed message, those envelope members can't be the empty string. They can still be the empty string for a malformed message ๐Ÿ™ƒ

If the From, To, Cc, and Bcc header fields are missing from the [RFC5322] header, or are present but empty, the matching envelope member is NIL ๐Ÿ’ซ

If the Sender or Reply-To header fields are missing from the [RFC5322] header, or are present but empty, the server sets the matching envelope member to the same value as the from member. The client isn't expected to know how to do this ๐Ÿคซ

Note: [RFC5322] requires that all messages have a valid From header field. So for a well-formed message, the from, sender, and reply-to members can't be NIL. They can be NIL for a malformed or draft message ๐Ÿšฉ

FLAGS is a parenthesized list of the flags set for this message ๐Ÿšฉ

INTERNALDATE is a string with the internal date of the message ๐Ÿ•ฐ๏ธ

RFC822.SIZE is a number with the size of a message, as described in Section 2.3.4 ๐Ÿ“

UID is a number with the unique identifier of the message ๐Ÿ†”

If the server chooses to send unsolicited FETCH responses, they MUST include the UID FETCH item. The original spec notes this is a new requirement compared to [RFC3501] ๐Ÿ†•

Example:

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

7.6. Server Responses - Command Continuation Request

The command continuation request is marked with a "+" token instead of a tag ๐ŸŽฏ It means the server is ready to take the rest of a command from the client. The rest of the response is a line of text ๐Ÿ’ฌ

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

The client is NOT permitted to send the octets of a synchronizing literal unless the server says it's expected. That lets the server process commands and reject errors line by line ๐Ÿšฆ The rest of the command, including the CRLF that ends the command, comes after the literal octets. If there are more command arguments, the literal octets are followed by a space and those arguments ๐Ÿงƒ

Example:

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

8. Sample IMAP4rev2 Connection โœจ

Here's a transcript of an IMAP4rev2 connection on a non-TLS port ๐Ÿ”Œ A long line in this sample got broken up for editorial clarity, so don't panic if it wraps ๐Ÿ™ˆ

   S:   * OK [CAPABILITY STARTTLS AUTH=SCRAM-SHA-256 LOGINDISABLED
         IMAP4rev2] IMAP4rev2 Service Ready
   C:   a000 starttls
   S:   a000 OK Proceed with TLS negotiation
    <TLS negotiation>
   C:   A001 AUTHENTICATE SCRAM-SHA-256
         biwsbj11c2VyLHI9ck9wck5HZndFYmVSV2diTkVrcU8=
   S:   + cj1yT3ByTkdmd0ViZVJXZ2JORWtxTyVodllEcFdVYTJSYVRDQWZ1eEZJbGopaE
        5sRiRrMCxzPVcyMlphSjBTTlk3c29Fc1VFamI2Z1E9PSxpPTQwOTY=
   C:   Yz1iaXdzLHI9ck9wck5HZndFYmVSV2diTkVrcU8laHZZRHBXVWEyUmFUQ0FmdXhG
        SWxqKWhObEYkazAscD1kSHpiWmFwV0lrNGpVaE4rVXRlOXl0YWc5empmTUhnc3Ft
        bWl6N0FuZFZRPQ==
   S:   + dj02cnJpVFJCaTIzV3BSUi93dHVwK21NaFVaVW4vZEI1bkxUSlJzamw5NUc0
        PQ==
   C:
   S:   A001 OK SCRAM-SHA-256 authentication successful
   C:   babc ENABLE IMAP4rev2
   S:   * ENABLED IMAP4rev2
   S:   babc OK Some capabilities enabled
   C:   a002 select inbox
   S:   * 18 EXISTS
   S:   * FLAGS (\Answered \Flagged \Deleted \Seen \Draft)
   S:   * OK [UIDVALIDITY 3857529045] UIDs valid
   S:   * LIST () "/" INBOX ("OLDNAME" ("inbox"))
   S:   a002 OK [READ-WRITE] SELECT completed
   C:   a003 fetch 12 full
   S:   * 12 FETCH (FLAGS (\Seen) INTERNALDATE
         "17-Jul-1996 02:44:25 -0700" RFC822.SIZE 4286 ENVELOPE (
         "Wed, 17 Jul 1996 02:23:25 -0700 (PDT)"
         "IMAP4rev2 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" "MIT.EDU")) NIL NIL
         "<B27397-0100000@cac.washington.ed>")
         BODY ("TEXT" "PLAIN" ("CHARSET" "US-ASCII") NIL NIL "7BIT"
         3028 92))
   S:    a003 OK FETCH completed
   C:    a004 fetch 12 body[header]
   S:    * 12 FETCH (BODY[HEADER] {342}
   S:    Date: Wed, 17 Jul 1996 02:23:25 -0700 (PDT)
   S:    From: Terry Gray <gray@cac.washington.edu>
   S:    Subject: IMAP4rev2 WG mtg summary and minutes
   S:    To: imap@cac.washington.edu
   S:    cc: minutes@CNRI.Reston.VA.US, John Klensin <KLENSIN@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 IMAP4rev2 server terminating connection
   S:    a006 OK LOGOUT completed

9. Formal Syntax ๐Ÿ“

The syntax below is written in Augmented Backus-Naur Form (ABNF) notation, as specified in [ABNF] ๐Ÿง 

If a later rule overlaps an earlier one in alternative or optional rules, the rule listed earlier MUST take priority ๐Ÿฅ‡ For example, "\Seen" parsed as a flag is the \Seen flag name and NOT a flag-extension, even though \Seen could also be parsed as a flag-extension. A few of these overlaps are noted below, but not all of them ๐Ÿซ 

Note: [ABNF] rules MUST be followed strictly; in particular:

Okay bestie, we're still in the Formal Syntax era ๐ŸŽ€ and these rules come first, no cap โœจ

  1. Unless otherwise noted, all alphabetic characters are case insensitive. Uppercase or lowercase characters are only used to define token strings for editorial clarity ๐Ÿ’… Implementations MUST accept these strings in a case-insensitive fashion ๐Ÿซถ
  2. In all cases, SP refers to exactly one space ๐Ÿ“ It is not permitted to swap in a TAB, add extra spaces, or treat SP as equivalent to linear whitespace (LWSP). Not the vibe ๐Ÿ˜ญ
  3. The ASCII NUL character, %x00, MUST NOT be used anywhere, except in the OCTET production ๐Ÿ™ˆ

Here's the grammar, and yes it's long, but every single line matters ๐Ÿ”ฅ

   SP              = <Defined in RFC 5234>
   CTL             = <Defined in RFC 5234>
   CRLF            = <Defined in RFC 5234>
   ALPHA           = <Defined in RFC 5234>
   DIGIT           = <Defined in RFC 5234>
   DQUOTE          = <Defined in RFC 5234>
   OCTET           = <Defined in RFC 5234>

   address         = "(" addr-name SP addr-adl SP addr-mailbox SP
                     addr-host ")"

   addr-adl        = nstring
                       ; Holds route from [RFC5322] obs-route if
                       ; non-NIL

   addr-host       = nstring
                       ; NIL indicates [RFC5322] group syntax.
                       ; Otherwise, holds [RFC5322] domain name

   addr-mailbox    = nstring
                       ; NIL indicates end of [RFC5322] group; if
                       ; non-NIL and addr-host is NIL, holds
                       ; [RFC5322] group name.
                       ; Otherwise, holds [RFC5322] local-part
                       ; after removing [RFC5322] quoting

   addr-name       = nstring
                       ; If non-NIL, holds phrase from [RFC5322]
                       ; mailbox after removing [RFC5322] quoting

   append          = "APPEND" SP mailbox [SP flag-list] [SP date-time]
                     SP literal

   append-uid      = uniqueid

   astring         = 1*ASTRING-CHAR / string

   ASTRING-CHAR   = ATOM-CHAR / resp-specials

   atom            = 1*ATOM-CHAR

   ATOM-CHAR       = <any CHAR except atom-specials>

   atom-specials   = "(" / ")" / "{" / SP / CTL / list-wildcards /
                     quoted-specials / resp-specials

   authenticate    = "AUTHENTICATE" SP auth-type [SP initial-resp]
                     *(CRLF base64)

   auth-type       = atom
                       ; Authentication mechanism name, as defined by
                       ; [SASL], Section 7.1

   base64          = *(4base64-char) [base64-terminal]

   base64-char     = ALPHA / DIGIT / "+" / "/"
                       ; Case sensitive

   base64-terminal = (2base64-char "==") / (3base64-char "=")

   body            = "(" (body-type-1part / body-type-mpart) ")"

   body-extension  = nstring / number / number64 /
                      "(" body-extension *(SP 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 [SP body-fld-dsp [SP body-fld-lang
                     [SP body-fld-loc *(SP body-extension)]]]
                       ; MUST NOT be returned on non-extensible
                       ; "BODY" fetch

   body-ext-mpart  = body-fld-param [SP body-fld-dsp [SP body-fld-lang
                     [SP body-fld-loc *(SP body-extension)]]]
                       ; MUST NOT be returned on non-extensible
                       ; "BODY" fetch

   body-fields     = body-fld-param SP body-fld-id SP body-fld-desc SP
                     body-fld-enc SP body-fld-octets

   body-fld-desc   = nstring

   body-fld-dsp    = "(" string SP body-fld-param ")" / nil

   body-fld-enc    = (DQUOTE ("7BIT" / "8BIT" / "BINARY" / "BASE64"/
                     "QUOTED-PRINTABLE") DQUOTE) / string
                     ; Content-Transfer-Encoding header field value.
                     ; Defaults to "7BIT" (as per RFC 2045)
                     ; if not present in the body part.

   body-fld-id     = nstring

   body-fld-lang   = nstring / "(" string *(SP string) ")"

   body-fld-loc    = nstring

   body-fld-lines  = number64

   body-fld-md5    = nstring

   body-fld-octets = number

   body-fld-param  = "(" string SP string *(SP string SP string) ")" /
                     nil

   body-type-1part = (body-type-basic / body-type-msg / body-type-text)
                     [SP body-ext-1part]

   body-type-basic = media-basic SP body-fields
                       ; MESSAGE subtype MUST NOT be "RFC822" or
                       ; "GLOBAL"

   body-type-mpart = 1*body SP media-subtype
                     [SP body-ext-mpart]
                       ; MULTIPART body part

   body-type-msg   = media-message SP body-fields SP envelope
                     SP body SP body-fld-lines

   body-type-text  = media-text SP body-fields SP body-fld-lines

   capability      = ("AUTH=" auth-type) / atom
                       ; New capabilities SHOULD be
                       ; registered with IANA using the
                       ; RFC Required policy, i.e., in
                       ; a Standards Track, an Experimental,
                       ; or an Informational RFC.

   capability-data = "CAPABILITY" *(SP capability) SP "IMAP4rev2"
                     *(SP capability)
                       ; See Section 6.1.1 for information about
                       ; required security-related capabilities.
                       ; Servers that offer RFC 1730 compatibility MUST
                       ; list "IMAP4" as the first capability.
                       ; Servers that offer RFC 3501 compatibility MUST
                       ; list "IMAP4rev1" as one of the capabilities.

   CHAR            = <defined in [ABNF]>

   CHAR8           = %x01-ff
                       ; any OCTET except NUL, %x00

   charset         = atom / quoted

   childinfo-extended-item =  "CHILDINFO" SP "("
               list-select-base-opt-quoted
               *(SP list-select-base-opt-quoted) ")"
               ; Extended data item (mbox-list-extended-item)
               ; returned when the RECURSIVEMATCH
               ; selection option is specified.
               ; Note 1: the CHILDINFO extended data item tag can be
               ; returned with or without surrounding quotes, as per
               ; mbox-list-extended-item-tag production.
               ; Note 2: The selection options are always returned
               ; quoted, unlike their specification in
               ; the extended LIST command.

   child-mbox-flag =  "\HasChildren" / "\HasNoChildren"
               ; attributes for the CHILDREN return option, at most
               ; one possible per LIST response

   command         = tag SP (command-any / command-auth /
                     command-nonauth / command-select) CRLF
                       ; Modal based on state

   command-any     = "CAPABILITY" / "LOGOUT" / "NOOP"
                       ; Valid in all states

   command-auth    = append / create / delete / enable / examine /
                     list / namespace-command / rename /
                     select / status / subscribe / unsubscribe /
                     idle
                       ; Valid only in Authenticated or Selected state

   command-nonauth = login / authenticate / "STARTTLS"
                       ; Valid only when in Not Authenticated state

   command-select  = "CLOSE" / "UNSELECT" / "EXPUNGE" / copy /
                      move / fetch / store / search / uid
                       ; Valid only when in Selected state

   continue-req    = "+" SP (resp-text / base64) CRLF

   copy            = "COPY" SP sequence-set SP mailbox

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

   date            = date-text / DQUOTE date-text DQUOTE

   date-day        = 1*2DIGIT
                       ; Day of month

   date-day-fixed  = (SP DIGIT) / 2DIGIT
                       ; Fixed-format version of date-day

   date-month      = "Jan" / "Feb" / "Mar" / "Apr" / "May" / "Jun" /
                     "Jul" / "Aug" / "Sep" / "Oct" / "Nov" / "Dec"

   date-text       = date-day "-" date-month "-" date-year

   date-year       = 4DIGIT

   date-time       = DQUOTE date-day-fixed "-" date-month "-" date-year
                     SP time SP zone DQUOTE

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

   digit-nz        = %x31-39
                       ; 1-9

   eitem-standard-tag =  atom
               ; a tag for LIST extended data item defined in a Standard
               ; Track or Experimental RFC.

   eitem-vendor-tag =  vendor-token "-" atom
               ; a vendor-specific tag for LIST extended data item

   enable          = "ENABLE" 1*(SP capability)

   enable-data     = "ENABLED" *(SP capability)

   envelope        = "(" env-date SP env-subject SP env-from SP
                     env-sender SP env-reply-to SP env-to SP env-cc SP
                     env-bcc SP env-in-reply-to SP 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

   esearch-response  = "ESEARCH" [search-correlator] [SP "UID"]
                       *(SP search-return-data)
                     ; ESEARCH response replaces SEARCH response
                     ; from IMAP4rev1.

   examine         = "EXAMINE" SP mailbox

   fetch           = "FETCH" SP sequence-set SP (
                     "ALL" / "FULL" / "FAST" /
                     fetch-att / "(" fetch-att *(SP fetch-att) ")")

   fetch-att       = "ENVELOPE" / "FLAGS" / "INTERNALDATE" /
                     "RFC822.SIZE" /
                     "BODY" ["STRUCTURE"] / "UID" /
                     "BODY" section [partial] /
                     "BODY.PEEK" section [partial] /
                     "BINARY" [".PEEK"] section-binary [partial] /
                     "BINARY.SIZE" section-binary

   flag            = "\Answered" / "\Flagged" / "\Deleted" /
                     "\Seen" / "\Draft" / flag-keyword / flag-extension
                       ; Does not include "\Recent"

   flag-extension  = "\" atom
                       ; Future expansion.  Client implementations
                       ; MUST accept flag-extension flags.  Server
                       ; implementations MUST NOT generate
                       ; flag-extension flags except as defined by
                       ; a future Standard or Standards Track
                       ; revisions of this specification.
                       ; "\Recent" was defined in RFC 3501
                       ; and is now deprecated.

   flag-fetch      = flag / obsolete-flag-recent

   flag-keyword    = "$MDNSent" / "$Forwarded" / "$Junk" /
                     "$NotJunk" / "$Phishing" / atom

   flag-list       = "(" [flag *(SP flag)] ")"

   flag-perm       = flag / "\*"

   greeting        = "*" SP (resp-cond-auth / resp-cond-bye) CRLF

   header-fld-name = astring

   header-list     = "(" header-fld-name *(SP header-fld-name) ")"

   idle            = "IDLE" CRLF "DONE"

   initial-resp    =  (base64 / "=")
                      ; "initial response" defined in
                      ; Section 4 of [SASL]

   list            = "LIST" [SP list-select-opts] SP
                     mailbox SP mbox-or-pat
                     [SP list-return-opts]


   list-mailbox    = 1*list-char / string

Okay, the grammar era is in full swing ๐Ÿ’…๐ŸŽ€ Here's the next chunk of rules, kept exactly as written.

   list-char       = ATOM-CHAR / list-wildcards / resp-specials

   list-return-opt   =  return-option
                        ; Note that return-option is the ABNF
                        ; non-terminal used by RFC 5258

   list-return-opts =  "RETURN" SP
               "(" [list-return-opt *(SP list-return-opt)] ")"
               ; list return options, e.g., CHILDREN

   list-select-base-opt =  "SUBSCRIBED" / option-extension
               ; options that can be used by themselves

   list-select-base-opt-quoted =  DQUOTE list-select-base-opt DQUOTE

   list-select-independent-opt =  "REMOTE" / option-extension
               ; options that do not syntactically interact with
               ; other options

   list-select-mod-opt =  "RECURSIVEMATCH" / option-extension
               ; options that require a list-select-base-opt
               ; to also be present

   list-select-opt =  list-select-base-opt / list-select-independent-opt
                      / list-select-mod-opt

   list-select-opts =  "(" [
                      (*(list-select-opt SP) list-select-base-opt
                      *(SP list-select-opt))
                     / (list-select-independent-opt
                      *(SP list-select-independent-opt))
                        ] ")"
               ; Any number of options may be in any order.
               ; If a list-select-mod-opt appears, then a
               ; list-select-base-opt must also appear.
               ; This allows these:
               ; ()
               ; (REMOTE)
               ; (SUBSCRIBED)
               ; (SUBSCRIBED REMOTE)
               ; (SUBSCRIBED RECURSIVEMATCH)
               ; (SUBSCRIBED REMOTE RECURSIVEMATCH)
               ; But does NOT allow these:
               ; (RECURSIVEMATCH)
               ; (REMOTE RECURSIVEMATCH)

Next up are the literals and the mailbox rules, which are super important for not mixing up your INBOX casing ๐Ÿฆ‹

   list-wildcards  = "%" / "*"

   literal         = "{" number64 ["+"] "}" CRLF *CHAR8
                       ; <number64> represents the number of CHAR8s.
                       ; A non-synchronizing literal is distinguished
                       ; from a synchronizing literal by the presence of
                       ; "+" before the closing "}".
                       ; Non-synchronizing literals are not allowed when
                       ; sent from server to the client.

   literal8        =  "~{" number64 "}" CRLF *OCTET
                       ; <number64> represents the number of OCTETs
                       ; in the response string.

   login           = "LOGIN" SP userid SP password

   mailbox         = "INBOX" / astring
                       ; INBOX is case insensitive.  All case variants
                       ; of INBOX (e.g., "iNbOx") MUST be interpreted as
                       ; INBOX, not as an astring.  An astring that
                       ; consists of the case-insensitive sequence
                       ; "I" "N" "B" "O" "X" is considered
                       ; to be an INBOX and not an astring.
                       ; Refer to Section 5.1 for further
                       ; semantic details of mailbox names.

   mailbox-data    =  "FLAGS" SP flag-list / "LIST" SP mailbox-list /
                      esearch-response /
                      "STATUS" SP mailbox SP "(" [status-att-list] ")" /
                      number SP "EXISTS" / namespace-response /
                      obsolete-search-response /
                      obsolete-recent-response
                       ; obsolete-search-response and
                       ; obsolete-recent-response can only be returned
                       ; by servers that support both IMAPrev1
                       ; and IMAPrev2.

   mailbox-list    = "(" [mbx-list-flags] ")" SP
                      (DQUOTE QUOTED-CHAR DQUOTE / nil) SP mailbox
                      [SP mbox-list-extended]
               ; This is the list information pointed to by the ABNF
               ; item "mailbox-data", which is defined above

   mbox-list-extended =  "(" [mbox-list-extended-item
                         *(SP mbox-list-extended-item)] ")"

   mbox-list-extended-item = mbox-list-extended-item-tag SP
                              tagged-ext-val

   mbox-list-extended-item-tag = astring
                  ; The content MUST conform to either
                  ; "eitem-vendor-tag" or "eitem-standard-tag"
                  ; ABNF productions.

   mbox-or-pat =  list-mailbox / patterns

   mbx-list-flags  = *(mbx-list-oflag SP) mbx-list-sflag
                     *(SP mbx-list-oflag) /
                     mbx-list-oflag *(SP mbx-list-oflag)

   mbx-list-oflag  = "\Noinferiors" / child-mbox-flag /
                     "\Subscribed" / "\Remote" / flag-extension
                  ; Other flags; multiple from this list are
                  ; possible per LIST response, but each flag
                  ; can only appear once per LIST response

   mbx-list-sflag  = "\NonExistent" / "\Noselect" / "\Marked" /
                     "\Unmarked"
                  ; Selectability flags; only one per LIST response

Now the media types, message data, and the namespace stuff. The namespace bit has a lot of nested structure, so hold on to your hair clips ๐ŸŽ€โœจ

   media-basic     = ((DQUOTE ("APPLICATION" / "AUDIO" / "IMAGE" /
                     "FONT" / "MESSAGE" / "MODEL" / "VIDEO" ) DQUOTE)
                     / string)
                     SP media-subtype
                       ; FONT defined in [RFC8081].
                       ; MODEL defined in [RFC2077].
                       ; Other top-level media types
                       ; are defined in [MIME-IMT].

   media-message   = DQUOTE "MESSAGE" DQUOTE SP
                     DQUOTE ("RFC822" / "GLOBAL") DQUOTE
                       ; Defined in [MIME-IMT]

   media-subtype   = string
                       ; Defined in [MIME-IMT]

   media-text      = DQUOTE "TEXT" DQUOTE SP media-subtype
                       ; Defined in [MIME-IMT]

   message-data    = nz-number SP ("EXPUNGE" / ("FETCH" SP msg-att))

   move            = "MOVE" SP sequence-set SP mailbox

   msg-att         = "(" (msg-att-dynamic / msg-att-static)
                      *(SP (msg-att-dynamic / msg-att-static)) ")"

   msg-att-dynamic = "FLAGS" SP "(" [flag-fetch *(SP flag-fetch)] ")"
                       ; MAY change for a message

   msg-att-static  = "ENVELOPE" SP envelope /
                     "INTERNALDATE" SP date-time /
                     "RFC822.SIZE" SP number64 /
                     "BODY" ["STRUCTURE"] SP body /
                     "BODY" section ["<" number ">"] SP nstring /
                     "BINARY" section-binary SP (nstring / literal8) /
                     "BINARY.SIZE" section-binary SP number /
                     "UID" SP uniqueid
                       ; MUST NOT change for a message

   name-component  = 1*UTF8-CHAR
                       ; MUST NOT contain ".", "/", "%", or "*"

   namespace         = nil / "(" 1*namespace-descr ")"

   namespace-command = "NAMESPACE"

   namespace-descr   = "(" string SP
                          (DQUOTE QUOTED-CHAR DQUOTE / nil)
                           [namespace-response-extensions] ")"

   namespace-response-extensions = *namespace-response-extension

   namespace-response-extension = SP string SP
                     "(" string *(SP string) ")"

   namespace-response = "NAMESPACE" SP namespace
                         SP namespace SP namespace
                    ; The first Namespace is the Personal Namespace(s).
                    ; The second Namespace is the Other Users'
                    ; Namespace(s).
                    ; The third Namespace is the Shared Namespace(s).

Last stretch of this part: the number types, the obsolete bits, the option stuff, and the response rules. Almost there, bestie ๐Ÿฆ‹๐Ÿ’œ

   nil             = "NIL"

   nstring         = string / nil

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

   number64        = 1*DIGIT
                       ; Unsigned 63-bit integer
                       ; (0 <= n <= 9,223,372,036,854,775,807)

   nz-number       = digit-nz *DIGIT
                       ; Non-zero unsigned 32-bit integer
                       ; (0 < n < 4,294,967,296)

   nz-number64     = digit-nz *DIGIT
                       ; Unsigned 63-bit integer
                       ; (0 < n <= 9,223,372,036,854,775,807)

   obsolete-flag-recent = "\Recent"

   obsolete-recent-response = number SP "RECENT"

   obsolete-search-response = "SEARCH" *(SP nz-number)

   oldname-extended-item =  "OLDNAME" SP "(" mailbox ")"
                       ; Extended data item (mbox-list-extended-item)
                       ; returned in a LIST response when a mailbox is
                       ; renamed or deleted. Also returned when
                       ; the server canonicalized the provided mailbox
                       ; name.
                       ; Note 1: the OLDNAME tag can be returned
                       ; with or without surrounding quotes, as per
                       ; mbox-list-extended-item-tag production.

   option-extension = (option-standard-tag / option-vendor-tag)
                      [SP option-value]

   option-standard-tag =  atom
                  ; an option defined in a Standards Track or
                  ; Experimental RFC

   option-val-comp =  astring /
                      option-val-comp *(SP option-val-comp) /
                      "(" option-val-comp ")"

   option-value =  "(" option-val-comp ")"

   option-vendor-tag =  vendor-token "-" atom
                  ; a vendor-specific option, non-standard

   partial-range    = number64 ["." nz-number64]
                       ; Copied from RFC 5092 (IMAP URL)
                       ; and updated to support 64-bit sizes.

   partial         = "<" number64 "." nz-number64 ">"
                       ; Partial FETCH request. 0-based offset of
                       ; the first octet, followed by the number of
                       ; octets in the fragment.

   password        = astring

   patterns        = "(" list-mailbox ")"
                     ; [RFC5258] supports multiple patterns,
                     ; but this document only requires one
                     ; to be supported.
                     ; If the server is also implementing
                     ; [RFC5258], the "patterns" syntax from
                     ; that document must be followed.

   quoted          = DQUOTE *QUOTED-CHAR DQUOTE

   QUOTED-CHAR     = <any TEXT-CHAR except quoted-specials> /
                     "\" quoted-specials / UTF8-2 / UTF8-3 / UTF8-4

   quoted-specials = DQUOTE / "\"

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

   response        = *(continue-req / response-data) response-done

   response-data   = "*" SP (resp-cond-state / resp-cond-bye /
                     mailbox-data / message-data / capability-data /
                     enable-data) CRLF

   response-done   = response-tagged / response-fatal

   response-fatal  = "*" SP resp-cond-bye CRLF
                       ; Server closes connection immediately

   response-tagged = tag SP resp-cond-state CRLF

   resp-code-apnd  = "APPENDUID" SP nz-number SP append-uid

   resp-code-copy  = "COPYUID" SP nz-number SP uid-set SP uid-set

   resp-cond-auth  = ("OK" / "PREAUTH") SP resp-text
                       ; Authentication condition

   resp-cond-bye   = "BYE" SP resp-text

   resp-cond-state = ("OK" / "NO" / "BAD") SP resp-text
                       ; Status condition

   resp-specials   = "]"

   resp-text       = ["[" resp-text-code "]" SP] [text]

okay bestie, the grammar keeps going and it's still giving precision ๐ŸŽ€๐Ÿ’…

   resp-text-code  = "ALERT" /
                     "BADCHARSET" [SP "(" charset *(SP charset) ")" ] /
                     capability-data / "PARSE" /
                     "PERMANENTFLAGS" SP
                         "(" [flag-perm *(SP flag-perm)] ")" /
                     "READ-ONLY" / "READ-WRITE" / "TRYCREATE" /
                     "UIDNEXT" SP nz-number /
                     "UIDVALIDITY" SP nz-number /
                     resp-code-apnd / resp-code-copy / "UIDNOTSTICKY" /
                     "UNAVAILABLE" / "AUTHENTICATIONFAILED" /
                     "AUTHORIZATIONFAILED" / "EXPIRED" /
                     "PRIVACYREQUIRED" / "CONTACTADMIN" / "NOPERM" /
                     "INUSE" / "EXPUNGEISSUED" / "CORRUPTION" /
                     "SERVERBUG" / "CLIENTBUG" / "CANNOT" /
                     "LIMIT" / "OVERQUOTA" / "ALREADYEXISTS" /
                     "NONEXISTENT" / "NOTSAVED" / "HASCHILDREN" /
                     "CLOSED" /
                     "UNKNOWN-CTE" /
                     atom [SP 1*<any TEXT-CHAR except "]">]

   return-option   = "SUBSCRIBED" / "CHILDREN" / status-option /
                      option-extension

   search          = "SEARCH" [search-return-opts]
                     SP search-program

   search-correlator  = SP "(" "TAG" SP tag-string ")"

   search-key      = "ALL" / "ANSWERED" / "BCC" SP astring /
                     "BEFORE" SP date / "BODY" SP astring /
                     "CC" SP astring / "DELETED" / "FLAGGED" /
                     "FROM" SP astring / "KEYWORD" SP flag-keyword /
                     "ON" SP date / "SEEN" /
                     "SINCE" SP date / "SUBJECT" SP astring /
                     "TEXT" SP astring / "TO" SP astring /
                     "UNANSWERED" / "UNDELETED" / "UNFLAGGED" /
                     "UNKEYWORD" SP flag-keyword / "UNSEEN" /
                       ; Above this line were in [IMAP2]
                     "DRAFT" / "HEADER" SP header-fld-name SP astring /
                     "LARGER" SP number64 / "NOT" SP search-key /
                     "OR" SP search-key SP search-key /
                     "SENTBEFORE" SP date / "SENTON" SP date /
                     "SENTSINCE" SP date / "SMALLER" SP number64 /
                     "UID" SP sequence-set / "UNDRAFT" / sequence-set /
                     "(" search-key *(SP search-key) ")"

   search-modifier-name = tagged-ext-label

   search-mod-params = tagged-ext-val
                     ; This non-terminal shows recommended syntax
                     ; for future extensions.

   search-program     = ["CHARSET" SP charset SP]
                       search-key *(SP search-key)
                       ; CHARSET argument to SEARCH MUST be
                       ; registered with IANA.

   search-ret-data-ext = search-modifier-name SP search-return-value
                       ; Note that not every SEARCH return option
                       ; is required to have the corresponding
                       ; ESEARCH return data.

   search-return-data = "MIN" SP nz-number /
                       "MAX" SP nz-number /
                       "ALL" SP sequence-set /
                       "COUNT" SP number /
                       search-ret-data-ext
                       ; All return data items conform to
                       ; search-ret-data-ext syntax.
                       ; Note that "$" marker is not allowed
                       ; after the ALL return data item.

   search-return-opts = SP "RETURN" SP "(" [search-return-opt
                       *(SP search-return-opt)] ")"

   search-return-opt  = "MIN" / "MAX" / "ALL" / "COUNT" /
                        "SAVE" /
                        search-ret-opt-ext
                       ; conforms to generic search-ret-opt-ext
                       ; syntax

   search-ret-opt-ext = search-modifier-name [SP search-mod-params]

   search-return-value = tagged-ext-val
                       ; Data for the returned search option.
                       ; A single "nz-number"/"number"/"number64" value
                       ; can be returned as an atom (i.e., without
                       ; quoting).  A sequence-set can be returned
                       ; as an atom as well.

   section         = "[" [section-spec] "]"

   section-binary  = "[" [section-part] "]"

   section-msgtext = "HEADER" /
                     "HEADER.FIELDS" [".NOT"] SP header-list /
                     "TEXT"
                       ; top-level or MESSAGE/RFC822 or
                       ; MESSAGE/GLOBAL part

   section-part    = nz-number *("." nz-number)
                       ; body part reference.
                       ; Allows for accessing nested body parts.

   section-spec    = section-msgtext / (section-part ["." section-text])

   section-text    = section-msgtext / "MIME"
                       ; text other than actual body part (headers,
                       ; etc.)

   select          = "SELECT" SP mailbox

   seq-number      = nz-number / "*"
                       ; message sequence number (COPY, FETCH, STORE
                       ; commands) or unique identifier (UID COPY,
                       ; UID FETCH, UID STORE commands).
                       ; * represents the largest number in use.  In
                       ; the case of message sequence numbers, it is
                       ; the number of messages in a non-empty mailbox.
                       ; In the case of unique identifiers, it is the
                       ; unique identifier of the last message in the
                       ; mailbox or, if the mailbox is empty, the
                       ; mailbox's current UIDNEXT value.
                       ; The server should respond with a tagged BAD
                       ; response to a command that uses a message
                       ; sequence number greater than the number of
                       ; messages in the selected mailbox.  This
                       ; includes "*" if the selected mailbox is empty.

   seq-range       = seq-number ":" seq-number
                       ; two seq-number values and all values between
                       ; these two regardless of order.
                       ; Example: 2:4 and 4:2 are equivalent and
                       ; indicate values 2, 3, and 4.
                       ; Example: a unique identifier sequence range of
                       ; 3291:* includes the UID of the last message in
                       ; the mailbox, even if that value is less than
                       ; 3291.

   sequence-set    = (seq-number / seq-range) ["," sequence-set]
                       ; set of seq-number values, regardless of order.
                       ; Servers MAY coalesce overlaps and/or execute
                       ; the sequence in any order.
                       ; Example: a message sequence number set of
                       ; 2,4:7,9,12:* for a mailbox with 15 messages is
                       ; equivalent to 2,4,5,6,7,9,12,13,14,15
                       ; Example: a message sequence number set of
                       ; *:4,5:7 for a mailbox with 10 messages is
                       ; equivalent to 10,9,8,7,6,5,4,5,6,7 and MAY
                       ; be reordered and overlap coalesced to be
                       ; 4,5,6,7,8,9,10.

   sequence-set    =/ seq-last-command
                       ; Allow for "result of the last command"
                       ; indicator.

   seq-last-command   = "$"

   status          = "STATUS" SP mailbox SP
                     "(" status-att *(SP status-att) ")"

   status-att      = "MESSAGES" / "UIDNEXT" / "UIDVALIDITY" /
                     "UNSEEN" / "DELETED" / "SIZE"

   status-att-val  = ("MESSAGES" SP number) /
                     ("UIDNEXT" SP nz-number) /
                     ("UIDVALIDITY" SP nz-number) /
                     ("UNSEEN" SP number) /
                     ("DELETED" SP number) /
                     ("SIZE" SP number64)
                       ; Extensions to the STATUS responses
                       ; should extend this production.
                       ; Extensions should use the generic
                       ; syntax defined by tagged-ext.

   status-att-list =  status-att-val *(SP status-att-val)

   status-option = "STATUS" SP "(" status-att *(SP status-att) ")"
                       ; This ABNF production complies with
                       ; <option-extension> syntax.

   store           = "STORE" SP sequence-set SP store-att-flags

   store-att-flags = (["+" / "-"] "FLAGS" [".SILENT"]) SP
                     (flag-list / (flag *(SP flag)))

   string          = quoted / literal

   subscribe       = "SUBSCRIBE" SP mailbox

   tag             = 1*<any ASTRING-CHAR except "+">

   tag-string      = astring
                     ; <tag> represented as <astring>

   tagged-ext-label    = tagged-label-fchar *tagged-label-char
                         ; Is a valid RFC 3501 "atom".

   tagged-label-fchar  = ALPHA / "-" / "_" / "."

   tagged-label-char   = tagged-label-fchar / DIGIT / ":"

   tagged-ext-comp     = astring /
                         tagged-ext-comp *(SP tagged-ext-comp) /
                         "(" tagged-ext-comp ")"
                         ; Extensions that follow this general
                         ; syntax should use nstring instead of
                         ; astring when appropriate in the context
                         ; of the extension.
                         ; Note that a message set or a "number"
                         ; can always be represented as an "atom".
                         ; A URL should be represented as
                         ; a "quoted" string.

   tagged-ext-simple   = sequence-set / number / number64

   tagged-ext-val      = tagged-ext-simple /
                         "(" [tagged-ext-comp] ")"

   text            = 1*(TEXT-CHAR / UTF8-2 / UTF8-3 / UTF8-4)
                       ; Non-ASCII text can only be returned
                       ; after ENABLE IMAP4rev2 command

   TEXT-CHAR       = <any CHAR except CR and LF>

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

   uid             = "UID" SP
                     (copy / move / fetch / search / store /
                      uid-expunge)
                       ; Unique identifiers used instead of message
                       ; sequence numbers

   uid-expunge     = "EXPUNGE" SP sequence-set
                       ; Unique identifiers used instead of message
                       ; sequence numbers

   uid-set         = (uniqueid / uid-range) *("," uid-set)

   uid-range       = (uniqueid ":" uniqueid)
                       ; two uniqueid values and all values
                       ; between these two regardless of order.
                       ; Example: 2:4 and 4:2 are equivalent.

   uniqueid        = nz-number
                       ; Strictly ascending

   unsubscribe     = "UNSUBSCRIBE" SP mailbox

   userid          = astring

   UTF8-CHAR       = <Defined in Section 4 of RFC 3629>

   UTF8-2          = <Defined in Section 4 of RFC 3629>

   UTF8-3          = <Defined in Section 4 of RFC 3629>

   UTF8-4          = <Defined in Section 4 of RFC 3629>

   vendor-token    = "vendor." name-component
                       ; Definition copied from RFC 2244.
                       ; MUST be registered with IANA

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

10. Author's Note ๐ŸŽ€

okay so this document is a revision and rewrite of older docs, and it officially supersedes the protocol specs in [RFC3501], [RFC2060], [RFC1730], the unpublished IMAP2bis.TXT document, [IMAP2], and [RFC1064] ๐Ÿงš

11. Security Considerations ๐Ÿ”

bestie, IMAP4rev2 traffic (including all your email data!!) goes over the network in plain text unless protection gets negotiated. That means it can be eavesdropped on or messed with ๐Ÿ˜ญ You can lock it down with the Implicit TLS port, the STARTTLS command, negotiated confidentiality protection in the AUTHENTICATE command, or some other protection mechanism ๐Ÿซถ

this part is for both STARTTLS and the Implicit TLS port.

IMAP client and server implementations MUST comply with the relevant TLS recommendations from [RFC8314]. If recommendations or requirements in this document clash with [RFC8314], like for TLS ciphersuites, the recommendations from this document win ๐Ÿ‘‘

Clients and servers MUST implement TLS 1.2 [TLS-1.2] or newer. Using TLS 1.3 [TLS-1.3] is RECOMMENDED ๐Ÿ”ฅ TLS 1.2 can only be used when the other side hasn't implemented TLS 1.3 yet. Also, when you're on TLS 1.2, IMAP implementations MUST implement the TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256 cipher suite. This matters because it guarantees any two compliant implementations can be set up to talk to each other ๐Ÿฆ‹ Other TLS cipher suites recommended in RFC 7525 [RFC7525] are RECOMMENDED too: TLS_DHE_RSA_WITH_AES_128_GCM_SHA256, TLS_DHE_RSA_WITH_AES_256_GCM_SHA384, and TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384. All other cipher suites are OPTIONAL. Note that this is a change from Section 2.1 of [IMAP-TLS] ๐ŸŒธ

The mandatory-to-implement TLS 1.3 cipher suites are listed in Section 9.1 of [TLS-1.3] ๐Ÿง 

During the TLS negotiation [TLS-1.3] [TLS-1.2], the client MUST check that its understanding of the server hostname matches the server's identity as presented in the server Certificate message. This stops on-path attackers from pretending to be the server ๐Ÿ™ˆ This procedure is described in [RFC7817].

Both the client and server MUST check the result of the STARTTLS command and the subsequent TLS [TLS-1.3] [TLS-1.2] negotiation to see whether acceptable authentication and/or privacy was achieved ๐Ÿ›ก๏ธ

11.2. STARTTLS Command versus Use of Implicit TLS Port โœจ

for maximum backward compatibility, the client MUST implement both TLS negotiation on an Implicit TLS port AND TLS negotiation using the STARTTLS command on a cleartext port ๐ŸŽ€

The server MUST implement TLS negotiation on an Implicit TLS port. The server SHOULD also implement IMAP on a cleartext port. If the server listens on a cleartext port, it MUST allow the STARTTLS command on it ๐Ÿ’œ

some site and firewall maintainers insist on TLS everywhere and don't want to rely on a config option in every higher-level protocol. So IMAP4rev2 clients SHOULD try both ports 993 and 143 (and both IPv4 and IPv6) at the same time by default, unless the user config or DNS SRV records [RFC6186] say otherwise. A good algorithm for doing that concurrent connect is described in [RFC8305] ๐Ÿฆ‹

11.3. Client Handling of Unsolicited Responses Not Suitable for the Current Connection State ๐Ÿ™ˆ

ngl this one is a whole vibe. Cleartext mail transmission can let someone inject responses that confuse email clients or even crash them ๐Ÿ’€ That can happen because of firewall config errors that strip TLS, or weak security policies in email clients that choose not to negotiate TLS in the first place. The following measures are recommended to cut down the damage:

  • See Section 7.1.4 for special security considerations related to the PREAUTH response.
  • Lots of server responses and response codes only mean something in the authenticated or even selected state. But nothing stops a server (or an on-path attacker) from sending those invalid responses in cleartext before the STARTTLS or AUTHENTICATE commands are issued. So before authentication, clients SHOULD ignore any responses other than CAPABILITY and server status responses (Section 7.1), and any response codes other than CAPABILITY. (Some email clients are known to process LIST responses received before authentication wrong, or FETCH responses when no mailbox is selected. Yikes ๐Ÿ˜ญ) Clients SHOULD ignore the ALERT response code until TLS has been successfully negotiated (whether with STARTTLS or TLS on an Implicit TLS port), or a SASL security layer with confidentiality protection has been negotiated. Unless an IMAP extension explicitly allows it, when not in selected state, clients MUST ignore responses and response codes related to message and mailbox status, such as FLAGS, EXISTS, EXPUNGE, and FETCH ๐Ÿšซ

11.4. COPYUID and APPENDUID Response Codes ๐Ÿ“

the COPYUID and APPENDUID response codes give back info about the mailbox, and that can be sensitive if the mailbox lets the client COPY or APPEND to it but NOT SELECT or EXAMINE it ๐Ÿ‘€

So these response codes SHOULD NOT be issued if the client doesn't have access to SELECT or EXAMINE the mailbox ๐Ÿ”’

11.5. LIST Command and Other Users' Namespace ๐Ÿซฃ

when a LIST command has an argument with the Other Users' Namespace prefix, a server MUST NOT list users who haven't given list access to their personal mailboxes to the currently authenticated user. Otherwise it could leak who is on the server, or hand attackers a starting list of user accounts to go after ๐Ÿ˜ค

11.6. Use of MD5 ๐Ÿงพ

the BODYSTRUCTURE FETCH data item can carry the MD5 digest of the message body in the body MD5 field (body-fld-md5 ABNF production). MD5 isn't considered a secure cryptographic hash anymore [RFC6151]. But this field is only there to show the value of the Content-MD5 header field (if the original message had one). That's just a message integrity check, not used for crypto stuff ๐Ÿ™ƒ Also, other integrity mechanisms have come out since RFC 1864 [MD5] was published, and they're way more common now than Content-MD5. Two of them are the DKIM-Signature header field [RFC6376] and S/MIME signing [RFC8550] [RFC8551] ๐Ÿ’…

11.7. Other Security Considerations ๐Ÿงš

a server error message for an AUTHENTICATE command that fails because the credentials are invalid SHOULD NOT explain why the credentials are invalid ๐Ÿคซ

Using the LOGIN command sends passwords in the clear. You can avoid that by using the AUTHENTICATE command with a [SASL] mechanism that doesn't use plaintext passwords, and by negotiating encryption first with STARTTLS or some other protection mechanism ๐Ÿ”

A server implementation MUST implement a configuration that, at the time of authentication, requires one of the following:

  1. The STARTTLS command has been negotiated, or TLS has been negotiated on an Implicit TLS port OR
  2. Some other mechanism that protects the session from password snooping has been provided OR
  3. The following measures are in place:
    • a) The LOGINDISABLED capability is advertised, and [SASL] mechanisms (such as PLAIN) that use plaintext passwords are NOT advertised in the CAPABILITY list. AND
    • b) The LOGIN command returns an error even if the password is correct AND
    • c) The AUTHENTICATE command returns an error with all [SASL] mechanisms that use plaintext passwords, even if the password is correct.

A server error message for a failing LOGIN command SHOULD NOT say that the user name, as opposed to the password, is invalid ๐Ÿ™…โ€โ™€๏ธ

A server SHOULD have mechanisms in place to limit or delay failed AUTHENTICATE and LOGIN attempts โณ

A server SHOULD report any authentication failure and analyze those failed attempts for password brute-force attacks as well as password spraying attacks [NCSC]. Accounts whose passwords match well-known passwords from spraying attacks MUST be blocked, and the users on those accounts must be asked to change their passwords. Only a password with significant strength SHOULD be accepted ๐Ÿ’ช

More security considerations are covered in the sections that define the AUTHENTICATE and LOGIN commands (see Sections 6.2.2 and 6.2.3, respectively) ๐Ÿ“š

12. IANA Considerations ๐ŸŒˆ

IANA has updated the "Service Names and Transport Protocol Port Numbers" registry like this:

  1. The registration for TCP port 143 and the matching "imap" service name now points to this document and [RFC3501].
  2. The registration for TCP port 993 and the matching "imaps" service name now points to this document, [RFC8314], and [RFC3501].
  3. UDP ports 143 and 993 have both been marked as "Reserved" in the registry.

More IANA actions are in the subsections below ๐Ÿฆ‹

12.1. Updates to IMAP Capabilities Registry ๐Ÿงฉ

IMAP4 capabilities get registered by publishing a Standards Track or IESG-approved Informational or Experimental RFC. The registry lives at https://www.iana.org/assignments/imap4-capabilities ๐Ÿ—‚๏ธ

Since this specification revises the AUTH= prefix, STARTTLS, and LOGINDISABLED extensions, IANA has updated the registry entries for those 3 extensions to point to this document and [RFC3501] โœจ

12.2. GSSAPI/SASL Service Name ๐ŸŽŸ๏ธ

GSSAPI/Kerberos/SASL service names get registered by publishing a Standards Track or IESG-approved Experimental RFC. The registry lives at https://www.iana.org/assignments/gssapi-service-names ๐Ÿ—๏ธ

IANA has updated the "imap" service name previously registered in [RFC3501] to point to both this document and [RFC3501] ๐Ÿซถ

12.3. LIST Selection Options, LIST Return Options, and LIST Extended Data Items ๐Ÿ—’๏ธ

[RFC5258] sets out the IANA registration procedures for LIST selection options, LIST return options, and LIST extended data items. This document doesn't change those procedures. Specifically, LIST selection options (Section 6.3.9.1) and LIST return options (Section 6.3.9.2) are registered using the procedure in Section 9 of [RFC5258] (and using the registration template from Section 9.3 of [RFC5258]). LIST extended data items are registered using the registration template from Section 9.6 of [RFC5258]) ๐Ÿ’–

IANA has added a reference to RFC 9051 for the "OLDNAME" LIST-EXTENDED extended data item entry. This is on top of the existing reference to [RFC5465] ๐ŸŽ€

12.4. IMAP Mailbox Name Attributes and IMAP Response Codes ๐Ÿท๏ธ

IANA has updated the "IMAP Mailbox Name Attributes" registry to point to this document as well as [RFC3501] ๐ŸŒธ

IANA has also updated the "IMAP Response Codes" registry to point to this document as well as [RFC3501] โญ

13. References ๐Ÿ“š

13.1. Normative References โœจ

okay bestie, these are the docs the spec leans on to make its rules actually work ๐Ÿ“š๐Ÿ’…

13.2. Informative References ๐ŸŒธ

okay bestie, this is the squad list ๐Ÿ’… these are the friend protocols IMAP hangs out with, and the references that the spec leans on.


and now the throwback era ๐Ÿ•ฐ๏ธโœจ these are the OG docs, the ones that got IMAP to where it is today. honestly so iconic, we respect the elders ๐Ÿซถ

Appendix A. Backward Compatibility with IMAP4rev1 ๐Ÿ’–

okay so if you want to stay friends with IMAP4rev1 ๐Ÿ˜Œ, you can advertise both IMAP4rev1 and IMAP4rev2 in your CAPABILITY response / response code. (a server doing this will probably also want to advertise the other IMAP4rev1 extensions that got folded into IMAP4rev2, so check Appendix E ๐Ÿ’….) some IMAP4rev1 responses got cut in IMAP4rev2, but their presence won't break IMAP4rev2-only clients, so no drama ๐Ÿซถ.

if both are advertised, an IMAP client that wants IMAP4rev2 MUST issue an ENABLE IMAP4rev2 command. no skipping this one, bestie ๐Ÿ”ฅ.

compared to IMAP4rev1, some request data items, corresponding response data items, and responses got removed in IMAP4rev2 ๐Ÿ’€. see Appendix E for the full tea โ˜•. except for the obsolete SEARCH and RECENT responses, servers advertising both would never send those removed items or responses unless an IMAPrev1 client explicitly asked for them ๐Ÿ™ˆ.

servers advertising both IMAP4rev1 and IMAP4rev2 MUST NOT generate UTF-8-quoted strings unless the client has issued ENABLE IMAP4rev2. look into the mechanisms in [IMAP-UTF-8] to make that happen ๐ŸŒธ.

servers advertising both, and clients trying to stay compatible with IMAP4rev1 servers, MUST be compatible with the Mailbox International Naming Convention described in Appendix A.1. ๐ŸŒˆ

also peep Appendix D for the special considerations for servers that support 63-bit body part / message sizes and want to advertise both IMAP4rev1 and IMAP4rev2 ๐Ÿงš.

A.1. Mailbox International Naming Convention for Compatibility with IMAP4rev1

support for the Mailbox International Naming Convention in this section is not required for IMAP4rev2-only clients and servers. it's only for backward compatibility with IMAP4rev1 implementations ๐Ÿ’œ.

by convention, international mailbox names in IMAP4rev1 are written using a modified version of the UTF-7 encoding described in [UTF-7] โœจ. modified UTF-7 may also work in servers that implement an earlier version of this protocol ๐Ÿฆ‹.

in modified UTF-7, printable US-ASCII characters represent themselves, except for & ๐ŸŽ€. that means the octet values 0x20-0x25 and 0x27-0x7e. the & (0x26) gets represented by the 2-octet sequence &- ๐Ÿ’….

all other characters (octet values 0x00-0x1f and 0x7f-0xff) are written in modified base64, with one extra twist from [UTF-7]: , is used instead of / ๐Ÿ“. modified base64 MUST NOT be used to represent any printing of a US-ASCII character that can represent itself. only characters inside the modified base64 alphabet are allowed in modified base64 text ๐Ÿ™…โ€โ™€๏ธ.

& shifts you into modified base64 and - shifts you back to US-ASCII ๐ŸŒˆ. there's no implicit shift from base64 back to US-ASCII, and null shifts (-& while in base64; note that &- while in US-ASCII means &) are not permitted ๐Ÿšซ. still, every name starts in US-ASCII and MUST end in US-ASCII. so a name ending in a non-ASCII ISO-10646 character MUST end with a - ๐Ÿ”ฅ.

the reason for all these tweaks is to fix these problems with UTF-7 ๐Ÿ‘‘:

  1. UTF-7 uses the + character for shifting. that clashes with the common use of + in mailbox names, especially USENET newsgroup names ๐Ÿ˜ญ.
  2. UTF-7's encoding is base64, which uses the / character. that clashes with / being a popular hierarchy delimiter ๐Ÿ’€.
  3. UTF-7 prohibits the unencoded usage of \. that clashes with \ being a popular hierarchy delimiter ๐Ÿ™ˆ.
  4. UTF-7 prohibits the unencoded usage of ~. that clashes with ~ being used by some servers as a home directory indicator ๐Ÿก.
  5. UTF-7 allows multiple alternate forms for the same string. in particular, printable US-ASCII characters can show up in encoded form too ๐ŸŒ€.

modified UTF-7 is a convention, but it still sets some requirements for how servers handle any mailbox name with an embedded & character ๐Ÿง. in particular, server implementations MUST preserve the exact form of the modified base64 portion of a modified UTF-7 name and treat that text as case sensitive, even when names are otherwise case insensitive or case folded ๐Ÿ”’.

server implementations SHOULD verify that any mailbox name with an embedded & character, used as an argument to CREATE, is: in the correctly modified UTF-7 syntax; free of superfluous shifts; and free of any printing US-ASCII character encoded in modified base64 when that character could represent itself ๐Ÿ•ต๏ธโ€โ™€๏ธ. however, client implementations MUST NOT depend on the server doing this, and they SHOULD NOT try to create a mailbox name with an embedded & character unless it follows the modified UTF-7 syntax ๐Ÿ™.

server implementations that export a mail store that doesn't follow the modified UTF-7 convention MUST convert any mailbox name that contains non-ASCII characters or the & character to modified UTF-7 ๐Ÿ”.

โœจ examples time โœจ

for example, here's a mailbox name mixing English, Chinese, and Japanese text: ~peter/mail/&U,BTFw-/&ZeVnLIqe- ๐ŸŒ.

another example: the string &Jjo! is not a valid mailbox name, because it doesn't shift back to US-ASCII before the ! ๐Ÿ™…. the correct form is &Jjo-!. and &U,BTFw-&ZeVnLIqe- isn't allowed because it has a superfluous shift ๐Ÿ™ƒ. the correct form is &U,BTF2XlZyyKng- ๐ŸŽ€.

Appendix B. Backward Compatibility with BINARY Extension

IMAP4rev2 picks up a subset of the BINARY extension [RFC3516] ๐Ÿฆ‹. it adds the extra FETCH items (BINARY, BINARY.PEEK, and BINARY.SIZE) but doesn't bring over the extensions to the APPEND command ๐Ÿ™…โ€โ™€๏ธ. if you implement full [RFC3516] functionality, you also need to advertise the BINARY capability in your CAPABILITY response / response code โœจ.

Appendix C. Backward Compatibility with LIST-EXTENDED Extension

IMAP4rev2 has most of the goodies from the LIST-EXTENDED extension [RFC5258] ๐Ÿ’–. the syntax for multiple mailbox patterns isn't supported in IMAP4rev2, unless the LIST-EXTENDED capability is also advertised in the CAPABILITY response / response code ๐ŸŒธ.

Appendix D. 63-Bit Body Part and Message Sizes

IMAP4rev2 raises the body part and message sizes that servers can support from 32 to 63 bits ๐Ÿ“ˆ. servers don't have to support 63-bit body parts / message sizes, but clients have to expect them ๐Ÿงš.

since IMAP4rev1 didn't support 63-bit body part / message sizes, there's an interop issue for 63-bit-capable servers/mailboxes that both IMAP4rev1 and IMAP4rev2 email clients can reach ๐Ÿ˜ฌ. IMAP4rev1 can't retrieve the full content of messages bigger than 4 Gb, so those servers either need to replace messages over 4 Gb with smaller ones, or hide them from IMAP4rev1 clients ๐Ÿ™ˆ. this document doesn't prescribe any implementation strategy for dealing with this ๐Ÿคทโ€โ™€๏ธ.

Appendix E. Changes from RFC 3501 / IMAP4rev1

here's the summary of what changed since RFC 3501 ๐Ÿ“:

  1. Support for 64-bit message and body part sizes ๐Ÿ’ช.
  2. Folded in IMAP NAMESPACE [RFC2342], UNSELECT [RFC3691], UIDPLUS [RFC4315], ESEARCH [RFC4731], SEARCHRES [RFC5182], ENABLE [RFC5161], IDLE [RFC2177], SASL-IR [RFC4959], LIST-EXTENDED [RFC5258], LIST-STATUS [RFC5819], MOVE [RFC6851], and LITERAL-extensions [RFC7888] ๐ŸŽ€. also folded in IMAP ABNF extensions [RFC4466], response codes [RFC5530], the FETCH side of the BINARY extension [RFC3516], and the list of new mailbox attributes from SPECIAL-USE [RFC6154] ๐ŸŒˆ.
  3. Added STATUS SIZE [RFC8438] and STATUS DELETED ๐Ÿ“.
  4. The SEARCH command now requires returning the ESEARCH response (the SEARCH response is now deprecated) ๐Ÿ™ƒ.
  5. Clarified which SEARCH keys have to use substring match and which don't ๐Ÿ”.
  6. Clarified that the server should decode parameter value continuations as described in [RFC2231]. this requirement was hidden in [RFC2231] itself ๐Ÿ•ต๏ธโ€โ™€๏ธ.
  7. Clarified that the COPYUID response code is returned for both MOVE and UID MOVE ๐Ÿ’….
  8. Tightened the requirements about COPY/MOVE commands not creating a target mailbox. they're also required to return the TRYCREATE response code if the target mailbox doesn't exist and can be created ๐Ÿ”ฅ.
  9. Added the CLOSED response code from [RFC7162]. SELECT/EXAMINE when a mailbox is already selected now requires a CLOSED response code to be returned ๐Ÿ‘‘.
  10. SELECT/EXAMINE are now required to return an untagged LIST response ๐ŸŒธ.
  11. The UNSEEN response code on SELECT/EXAMINE is now deprecated ๐Ÿฅฒ.
  12. The RECENT response on SELECT/EXAMINE, the \Recent flag, RECENT STATUS, and SEARCH NEW items are now deprecated ๐Ÿ’€.
  13. Clarified that the server doesn't need to send a new PERMANENTFLAGS response code when a new keyword was successfully added and the server advertised \* earlier for the same mailbox โœจ.
  14. For future extensibility, the ABNF for tagged-ext-simple was extended to allow for a bare number64 ๐Ÿงš.
  15. Added a SHOULD level requirement on IMAP servers to support the $MDNSent, $Forwarded, $Junk, $NonJunk, and $Phishing keywords ๐Ÿ’œ.
  16. Mailbox names and message headers now allow for UTF-8 ๐ŸŒ. support for modified UTF-7 in mailbox names is not required, unless compatibility with IMAP4rev1 is desired ๐Ÿฆ‹.
  17. Removed the CHECK command. clients should use NOOP instead ๐Ÿ™…โ€โ™€๏ธ.
  18. The RFC822, RFC822.HEADER, and RFC822.TEXT FETCH data items were deprecated. clients should use the corresponding BODY[] variants instead ๐Ÿ“.
  19. The LSUB command was deprecated. clients should use LIST (SUBSCRIBED) instead ๐ŸŽ€.
  20. The IDLE command can now return updates not related to the currently selected mailbox state ๐ŸŒˆ.
  21. All unsolicited FETCH updates are required to include UID ๐Ÿ”‘.
  22. Clarified that client implementations MUST ignore response codes that they do not recognize. (Changed from a SHOULD to a MUST.) ๐Ÿซถ this one's a big deal bestie ๐Ÿ’….
  23. The resp-text ABNF non-terminal was updated to allow for empty text ๐ŸŒธ.
  24. After ENABLE, IMAP4rev2 human-readable response text can include non-ASCII encoded in UTF-8 ๐ŸŒ.
  25. Updated to use modern TLS-related recommendations as per [RFC7525], [RFC7817], and [RFC8314] ๐Ÿ”.
  26. Added warnings about the use of ALERT response codes and the PREAUTH response โš ๏ธ.
  27. Replaced the DIGEST-MD5 SASL mechanism with SCRAM-SHA-256. DIGEST-MD5 was deprecated ๐Ÿ‘‹.
  28. Clarified that any command received from the client resets the server autologout timer โฐ.
  29. Revised the IANA registration procedure for IMAP extensions and removed the "X" convention in accordance with [BCP178] ๐Ÿงพ.
  30. Loosened requirements on servers when closing connections, to be more aligned with existing practices ๐Ÿฆ‹โœจ.

okay so these extensions are recommended for all IMAP clients and servers ๐Ÿ’– They seriously cut down on bandwidth and/or the number of round trips IMAP needs in certain situations. ๐Ÿฆ‹ But the EXTRA WG decided that making them required as part of IMAP4rev2 would set the bar too high for brand-new implementations ๐Ÿ˜ญ And don't read anything into it if an IMAP extension isn't on this list. It's not deficient, and it's not "not recommended" for IMAP4rev2. It's just not on this list ๐Ÿ’…

  1. Quick Mailbox Resynchronization (QRESYNC) and CONDSTORE extensions [RFC7162]. These make discovering changes to IMAP mailboxes way more efficient, at the expense of storing a bit more state โœจ
  2. OBJECTID extension [RFC8474] helps preserve the IMAP client cache when messages are moved/copied or mailboxes are renamed. ๐Ÿงš

Acknowledgements ๐Ÿซถ

Earlier draft versions of this document were edited by Mark Crispin. Sadly, he is no longer available to help with this work ๐Ÿ˜ญ The editors of this revision are hoping that Mark would have approved ๐Ÿ’œ

Chris Newman contributed text on I18N and the use of UTF-8 in messages and mailbox names. ๐ŸŒˆ

Thank you to Tony Hansen for helping with the index generation ๐Ÿ“ Thank you also to Murray Kucherawy, Timo Sirainen, Bron Gondwana, Stephan Bosch, Robert Sparks, Arnt Gulbrandsen, Benjamin Kaduk, Daniel Migaul, Roman Danyliw, and ร‰ric Vyncke for extensive feedback. Iconic squad ๐Ÿ‘‘

This document incorporates text from [RFC2342] (by Mike Gahrns and Chris Newman), [RFC3516] (by Lyndon Nerenberg), [RFC4315] (by Mark Crispin), [RFC4466] (by Cyrus Daboo), [RFC4731] (by Dave Cridland), [RFC4959] (by Rob Siemborski and Arnt Gulbrandsen), [RFC5161] (by Arnt Gulbrandsen), [RFC5465] (by Arnt Gulbrandsen and Curtis King), [RFC5530] (by Arnt Gulbrandsen), [RFC5819] (by Timo Sirainen), [RFC6154] (by Jamie Nicolson), [RFC6851] (by Arnt Gulbrandsen and Ned Freed), and [RFC8438] (by Stephan Bosch). The work of those authors and editors is so appreciated ๐Ÿ™Œ Note that the editors of this document were redacted from the above list ๐Ÿ™ˆ

The CHILDREN return option was originally proposed by Mike Gahrns and Raymond Cheng in [RFC3348]. Most of the information in Section 6.3.9.5 is taken directly from their original specification [RFC3348] ๐ŸŒธ

Thank you to Damian Poddebniak, Fabian Ising, Hanno Boeck, and Sebastian Schinzel for pointing out that the ENABLE command should be a member of "command-auth" and not "command-any" ABNF production. You also pointed out security issues associated with ALERT, PREAUTH, and other responses received before authentication. Security stuff is serious, bestie ๐Ÿ˜ญ๐Ÿ”ฅ


Index ๐Ÿ“‡

   $ + - \ A B C D E F H I K L M N O P R S T U

      $

         $Forwarded (predefined flag)
            Section 2.3.2
         $Junk (predefined flag)
            Section 2.3.2
         $MDNSent (predefined flag)
            Section 2.3.2
         $NotJunk (predefined flag)
            Section 2.3.2
         $Phishing (predefined flag)
            Section 2.3.2, Paragraph 6.10.1

      +

         +FLAGS <flag list>
            Section 6.4.6
         +FLAGS.SILENT <flag list>
            Section 6.4.6

      -

         -FLAGS <flag list>
            Section 6.4.6
         -FLAGS.SILENT <flag list>
            Section 6.4.6

      \

         \All (mailbox name attribute)
            Section 7.3.1
         \Answered (system flag)
            Section 2.3.2
         \Archive (mailbox name attribute)
            Section 7.3.1
         \Deleted (system flag)
            Section 2.3.2
         \Draft (system flag)
            Section 2.3.2
         \Drafts (mailbox name attribute)
            Section 7.3.1
         \Flagged (mailbox name attribute)
            Section 7.3.1
         \Flagged (system flag)
            Section 2.3.2
         \HasChildren (mailbox name attribute)
            Section 7.3.1
         \HasNoChildren (mailbox name attribute)
            Section 7.3.1
         \Junk (mailbox name attribute)
            Section 7.3.1
         \Marked (mailbox name attribute)
            Section 7.3.1
         \Noinferiors (mailbox name attribute)
            Section 7.3.1
         \NonExistent (mailbox name attribute)
            Section 7.3.1, Paragraph 4.2.1
         \Noselect (mailbox name attribute)
            Section 7.3.1
         \Recent (system flag)
            Section 2.3.2
         \Remote (mailbox name attribute)
            Section 7.3.1
         \Seen (system flag)
            Section 2.3.2
         \Sent (mailbox name attribute)
            Section 7.3.1
         \Subscribed (mailbox name attribute)
            Section 7.3.1
         \Trash (mailbox name attribute)
            Section 7.3.1
         \Unmarked (mailbox name attribute)
            Section 7.3.1

      A

         ALERT (response code)
            Section 7.1
         ALL (fetch item)
            Section 6.4.5
         ALL (search key)
            Section 6.4.4
         ALL (search result option)
            Section 6.4.4, Paragraph 6.6.1
         ALL (search return item name)
            Section 7.3.4, Paragraph 7.6.1
         ALREADYEXISTS (response code)
            Section 7.1, Paragraph 4.4.1
         ANSWERED (search key)
            Section 6.4.4
         APPEND (command)
            Section 6.3.12
         APPENDUID (response code)
            Section 7.1, Paragraph 4.6.1
         AUTHENTICATE (command)
            Section 6.2.2
         AUTHENTICATIONFAILED (response code)
            Section 7.1, Paragraph 4.8.1
         AUTHORIZATIONFAILED (response code)
            Section 7.1, Paragraph 4.10.1

      B

         BAD (response)
            Section 7.1.3
         BADCHARSET (response code)
            Section 7.1
         BCC <string> (search key)
            Section 6.4.4
         BEFORE <date> (search key)
            Section 6.4.4
         BINARY.PEEK[<section-binary>]<<partial>> (fetch item)
            Section 6.4.5
         BINARY.SIZE[<section-binary>] (fetch item)
            Section 6.4.5, Paragraph 9.6.1
         BINARY.SIZE[<section-binary>] (fetch result)
            Section 7.5.2, Paragraph 4.4.1
         BINARY[<section-binary>]<<number>> (fetch result)
            Section 7.5.2, Paragraph 4.2.1
         BINARY[<section-binary>]<<partial>> (fetch item)
            Section 6.4.5, Paragraph 9.2.1
         BODY (fetch item)
            Section 6.4.5
         BODY (fetch result)
            Section 7.5.2
         BODY <string> (search key)
            Section 6.4.4
         BODY.PEEK[<section>]<<partial>> (fetch item)
            Section 6.4.5
         BODYSTRUCTURE (fetch item)
            Section 6.4.5
         BODYSTRUCTURE (fetch result)
            Section 7.5.2, Paragraph 4.10.1
         BODY[<section>]<<origin octet>> (fetch result)
            Section 7.5.2, Paragraph 4.8.1
         BODY[<section>]<<partial>> (fetch item)
            Section 6.4.5, Paragraph 9.10.1
         BYE (response)
            Section 7.1.5
         Body Structure (message attribute)
            Section 2.3.6

      C

         CANNOT (response code)
            Section 7.1, Paragraph 4.14.1
         CAPABILITY (command)
            Section 6.1.1
         CAPABILITY (response code)
            Section 7.1
         CAPABILITY (response)
            Section 7.2.2
         CC <string> (search key)
            Section 6.4.4
         CLIENTBUG (response code)
            Section 7.1, Paragraph 4.18.1
         CLOSE (command)
            Section 6.4.1
         CLOSED (response code)
            Section 7.1, Paragraph 4.20.1
         CONTACTADMIN (response code)
            Section 7.1, Paragraph 4.22.1
         COPY (command)
            Section 6.4.7
         COPYUID (response code)
            Section 7.1, Paragraph 4.24.1
         CORRUPTION (response code)
            Section 7.1, Paragraph 4.26.1
         COUNT (search result option)
            Section 6.4.4
         COUNT (search return item name)
            Section 7.3.4
         CREATE (command)
            Section 6.3.4

      D

         DELETE (command)
            Section 6.3.5
         DELETED (search key)
            Section 6.4.4
         DELETED (status item)
            Section 6.3.11
         DRAFT (search key)
            Section 6.4.4

      E

         ENABLE (command)
            Section 6.3.1
         ENVELOPE (fetch item)
            Section 6.4.5
         ENVELOPE (fetch result)
            Section 7.5.2, Paragraph 4.42.1
         ESEARCH (response)
            Section 7.3.4
         EXAMINE (command)
            Section 6.3.3
         EXPIRED (response code)
            Section 7.1, Paragraph 4.28.1
         EXPUNGE (command)
            Section 6.4.3
         EXPUNGE (response)
            Section 7.5.1
         EXPUNGEISSUED (response code)
            Section 7.1, Paragraph 4.30.1
         Envelope Structure (message attribute)
            Section 2.3.5

      F

         FAST (fetch item)
            Section 6.4.5
         FETCH (command)
            Section 6.4.5
         FETCH (response)
            Section 7.5.2
         FLAGGED (search key)
            Section 6.4.4
         FLAGS (fetch item)
            Section 6.4.5
         FLAGS (fetch result)
            Section 7.5.2
         FLAGS (response)
            Section 7.3.5
         FLAGS <flag list> (store command data item)
            Section 6.4.6
         FLAGS.SILENT <flag list> (store command data item)
            Section 6.4.6
         FROM <string> (search key)
            Section 6.4.4
         FULL (fetch item)
            Section 6.4.5
         Flags (message attribute)
            Section 2.3.2

      H

         HASCHILDREN (response code)
            Section 7.1, Paragraph 4.32.1
         HEADER (part specifier)
            Section 6.4.5.1, Paragraph 5
         HEADER <field-name> <string> (search key)
            Section 6.4.4
         HEADER.FIELDS (part specifier)
            Section 6.4.5.1, Paragraph 5
         HEADER.FIELDS.NOT (part specifier)
            Section 6.4.5.1, Paragraph 5

      I

         IDLE (command)
            Section 6.3.13
         INTERNALDATE ( fetch item)
            Section 6.4.5
         INTERNALDATE (fetch result)
            Section 7.5.2
         INUSE (response code)
            Section 7.1, Paragraph 4.34.1
         Internal Date (message attribute)
            Section 2.3.3

      K

         KEYWORD <flag> (search key)
            Section 6.4.4
         Keyword (type of flag)
            Section 2.3.2, Paragraph 4

      L

         LARGER <n> (search key)
            Section 6.4.4
         LIMIT (response code)
            Section 7.1, Paragraph 4.36.1
         LIST (command)
            Section 6.3.9
         LIST (response)
            Section 7.3.1
         LOGOUT (command)
            Section 6.1.3

      M

         MAX (search result option)
            Section 6.4.4, Paragraph 6.4.1
         MAX (search return item name)
            Section 7.3.4, Paragraph 7.4.1
         MAY (specification requirement term)
            Section 1.2
         MESSAGES (status item)
            Section 6.3.11
         MIME (part specifier)
            Section 6.4.5.1, Paragraph 7
         MIN (search result option)
            Section 6.4.4, Paragraph 6.2.1
         MIN (search return item name)
            Section 7.3.4, Paragraph 7.2.1
         MOVE (command)
            Section 6.4.8
         MUST (specification requirement term)
            Section 1.2
         MUST NOT (specification requirement term)
            Section 1.2
         Message Sequence Number (message attribute)
            Section 2.3.1.2

      N

Okay that's the index so far, and we're going right on from here in the next part ๐Ÿ’œ

         NAMESPACE (command)
            Section 6.3.10
         NAMESPACE (response)
            Section 7.3.2
         NO (response)
            Section 7.1.2
         NONEXISTENT (response code)
            Section 7.1, Paragraph 4.38.1
         NOOP (command)
            Section 6.1.2
         NOPERM (response code)
            Section 7.1, Paragraph 4.40.1
         NOT <search-key> (search key)
            Section 6.4.4
         NOT RECOMMENDED (specification requirement term)
            Section 1.2

      O

         OK (response)
            Section 7.1.1
         ON <date> (search key)
            Section 6.4.4
         OPTIONAL (specification requirement term)
            Section 1.2; Section 1.2
         OR <search-key1> <search-key2> (search key)
            Section 6.4.4
         OVERQUOTA (response code)
            Section 7.1, Paragraph 4.42.1

      P

         PARSE (response code)
            Section 7.1
         PERMANENTFLAGS (response code)
            Section 7.1, Paragraph 4.46.1
         PREAUTH (response)
            Section 7.1.4
         PRIVACYREQUIRED (response code)
            Section 7.1, Paragraph 4.48.1
         Permanent Flag (class of flag)
            Section 2.3.2, Paragraph 9
         Predefined keywords
            Section 2.3.2, Paragraph 5

      R

         READ-ONLY (response code)
            Section 7.1
         READ-WRITE (response code)
            Section 7.1
         RECOMMENDED (specification requirement term)
            Section 1.2
         RENAME (command)
            Section 6.3.6
         REQUIRED (specification requirement term)
            Section 1.2
         RFC822.SIZE (fetch item)
            Section 6.4.5
         RFC822.SIZE (fetch result)
            Section 7.5.2
         RFC822.SIZE (message attribute)
            Section 2.3.4

      S

         SAVE (search result option)
            Section 6.4.4, Paragraph 6.10.1
         SEARCH (command)
            Section 6.4.4
         SEEN (search key)
            Section 6.4.4
         SELECT (command)
            Section 6.3.2
         SENTBEFORE <date> (search key)
            Section 6.4.4
         SENTON <date> (search key)
            Section 6.4.4
         SENTSINCE <date> (search key)
            Section 6.4.4
         SERVERBUG (response code)
            Section 7.1, Paragraph 4.54.1
         SHOULD (specification requirement term)
            Section 1.2
         SHOULD NOT (specification requirement term)
            Section 1.2
         SINCE <date> (search key)
            Section 6.4.4
         SIZE (status item)
            Section 6.3.11
         SMALLER <n> (search key)
            Section 6.4.4
         STARTTLS (command)
            Section 6.2.1
         STATUS (command)
            Section 6.3.11
         STATUS (response)
            Section 7.3.3
         STORE (command)
            Section 6.4.6
         SUBJECT <string> (search key)
            Section 6.4.4
         SUBSCRIBE (command)
            Section 6.3.7
         Session Flag (class of flag)
            Section 2.3.2, Paragraph 9
         System Flag (type of flag)
            Section 2.3.2, Paragraph 2

      T

         TEXT (part specifier)
            Section 6.4.5.1, Paragraph 5
         TEXT <string> (search key)
            Section 6.4.4
         TO <string> (search key)
            Section 6.4.4
         TRYCREATE (response code)
            Section 7.1

      U

         UID (command)
            Section 6.4.9
         UID (fetch item)
            Section 6.4.5
         UID (fetch result)
            Section 7.5.2
         UID <sequence set> (search key)
            Section 6.4.4
         UIDNEXT (response code)
            Section 7.1
         UIDNEXT (status item)
            Section 6.3.11
         UIDNOTSTICKY (response code)
            Section 7.1, Paragraph 4.60.1
         UIDVALIDITY (response code)
            Section 7.1
         UIDVALIDITY (status item)
            Section 6.3.11
         UNANSWERED (search key)
            Section 6.4.4
         UNAVAILABLE (response code)
            Section 7.1, Paragraph 4.64.1
         UNDELETED (search key)
            Section 6.4.4
         UNDRAFT (search key)
            Section 6.4.4
         UNFLAGGED (search key)
            Section 6.4.4
         UNKEYWORD <flag> (search key)
            Section 6.4.4
         UNKNOWN-CTE (response code)
            Section 7.1
         UNSEEN (search key)
            Section 6.4.4
         UNSEEN (status item)
            Section 6.3.11
         UNSELECT (command)
            Section 6.4.2
         UNSUBSCRIBE (command)
            Section 6.3.8
         Unique Identifier (UID) (message attribute)
            Section 2.3.1.1

Authors' Addresses โœจ

   Alexey Melnikov (editor)
   Isode Ltd
   14 Castle Mews
   Hampton, Middlesex
   TW12 2NP
   United Kingdom

   Email: Alexey.Melnikov@isode.com


   Barry Leiba (editor)
   Futurewei Technologies

   Email: barryleiba@computer.org
   URI:   http://internetmessagingtechnology.org/
๐Ÿ“ฆ where this page comes from