RFC 1203

Interactive Mail Access Protocol: Version 3

๐Ÿ“… published February 1991, from ietf

INTERACTIVE MAIL ACCESS PROTOCOL - VERSION 3 ๐ŸŽ€

okay bestie, the title block is giving "who wrote this, when, and what did it replace" ๐Ÿ’…. It's RFC 1203, written by J. Rice from Stanford ๐Ÿงš, dated February 1991. It obsoletes RFC 1064, which is the IMAP2 spec ๐ŸŒธ. The Status section says it's a standard for the SUMEX-AIM community and an Experimental Protocol for the Internet community โœจ.


Status of this Memo โœจ

this RFC suggests a way for workstations to access mail dynamically from a mailbox server (the "repository") ๐Ÿ“ฌ. it specifies a standard for the SUMEX-AIM community and an Experimental Protocol for the Internet community ๐Ÿงช. they're asking for discussion and suggestions for improvement, so speak up ๐Ÿ—ฃ๏ธ. for the standardization state and status of this protocol, check the current edition of the "IAB Official Protocol Standards" ๐Ÿ“š. distribution of this memo is unlimited ๐ŸŒˆ.


Scope ๐ŸŽ€

okay so this is a modified version of RFC 1064, which defines IMAP2 ๐Ÿ’–. it was written specifically as a counter proposal to RFC 1176, which itself proposes modifications to IMAP2 ๐Ÿ˜ค. ngl the drama is real: RFC 1176 was made without internal consultation with the IMAP community ๐Ÿ’€. so the authors feel like they have to push back, because if they don't act, RFC 1176 becomes a de facto standard ๐Ÿ˜ญ. the reasons mostly fall into these categories:

  • IMAP2 is insufficiently powerful for a number of server/client interactions that they think matter. RFC 1176 negligibly enhances IMAP2 ๐Ÿฅฑ.
  • IMAP2 makes what they believe is an erroneous definition of unsolicited vs. solicited data. IMAP3, as specified here, tries to fix that. RFC 1176 makes no effort to remedy these problems ๐Ÿ™….
  • RFC 1176 explicitly modified the intent of RFC 1064 by letting the server make assumptions about the client's caching architecture. they think this is a grave error, so they don't support it here ๐Ÿšซ.
  • RFC 1176 specifies a bunch of "optional" features without a suitable metaprotocol for servers and clients to negotiate over the features they implement. this proposal adds a mechanism so both sides can unambiguously know which features are usable by each party ๐Ÿค.
  • RFC 1176 pays lip-service to being network protocol independent and actually assumes TCP/IP. neither RFC 1064 nor this proposal makes that assumption ๐Ÿซ .

there are plenty of other detailed objections to RFC 1176, but the list above shows how strongly the authors believe in mailbox abstraction level mail protocols ๐Ÿ’œ. after a couple of years of using IMAP2 under RFC 1064, they feel they understand the issues well enough to take the next step ๐Ÿฆ‹.

this next step matters because mail systems and user interface development are moving super fast ๐Ÿš€. for IMAP to not die in its infancy, IMAP has to be ready to respond to emerging ISO and RFC standards in mail, like multi-media mail ๐ŸŽž๏ธ. RFC 1176 gives a very small bump in functionality over RFC 1064 but also adds a bunch of bugs, which would be detrimental to the IMAP cause ๐Ÿ›. so, here's the proposed definition for IMAP3 ๐Ÿ‘‘.


Compatibility notes ๐Ÿ“

they tried to make upwards compatible changes wherever possible when revising IMAP2 into IMAP3 ๐Ÿ’•. some spots had to change incompatibly anyway, to compensate for ambiguities in IMAP2 as defined by RFC 1064, or for behaviour that turned out to be undesirable in the light of experience ๐Ÿง.

the goal is that existing IMAP2 clients should still be supported, and that, at least for the foreseeable future, all IMAP3 servers will support IMAP2 behaviour as their default mode ๐Ÿซถ.

the major differences between this proposal, RFC 1176, and RFC 1064 are:

  • this proposal specifies a difference between "solicited" and "unsolicited" data sent from the server ๐Ÿ”. data the server is required to send as the result of a request is solicited, and it carries the same tag as the request that provoked it ๐Ÿท๏ธ. any data the server sends that the protocol doesn't require is unsolicited and carries the special * tag โœจ. RFC 1176 keeps the original RFC 1064 terminology, which calls all of that server data "unsolicited" even when it's actually solicited ๐Ÿ™„.
  • this proposal introduces the experimental concept of distinguishing Generic, Canonical and Concrete keys ๐Ÿงช. that lets the mailbox be viewed as a relational database indexed by these keys ๐Ÿ—„๏ธ. the idea is to help IMAP evolve away from its current reliance on RFC 822 ๐ŸŒฑ. RFC 1176 doesn't have a unifying model like this ๐Ÿ˜ฌ.
  • the SEARCH command has been changed so you can run multiple simultaneous searches, and so the server can send unsolicited search messages ๐Ÿ”Ž. that's essential for smarter servers that process commands asynchronously, possibly delaying searches a lot over slow backing storage media, for example ๐Ÿข. it also lets servers send unsolicited search messages that can tell the client about interesting patterns, like new and unseen mail ๐Ÿ“ฉ.
  • this proposal introduces a specific protocol for negotiating protocol versions and server features ๐Ÿค. this matters because it lets client/server pairs agree on what behaviour is really available ๐Ÿ’ก. RFC 1176 introduces "optional" commands, which are somewhat analogous to the "feature-introduced" commands here. the main difference is that in RFC 1176, a client has no way to discover the set of optional commands, and no way to check whether a specific command is actually supported, because RFC 1176 requires the BAD response when a feature isn't supported ๐Ÿ˜ต. so the client can't tell why the attempted command didn't work ๐Ÿคทโ€โ™€๏ธ. that also means a client can't disable certain user commands or make them invisible on menus when they aren't supported, since the only way to find out is to try running the command ๐Ÿ™ƒ.
  • this proposal introduces a mechanism for clients to create and delete user flags (keywords) ๐Ÿณ๏ธโ€๐ŸŒˆ. neither RFC 1176 nor RFC 1064 supports this, so the user has to add keys manually on the server, generally by editing some form of "init" file ๐Ÿ˜ฉ.
  • RFC 1064 has no mechanism for determining whether a mailbox is readonly ๐Ÿ“–. RFC 1176 introduces a non-enforced convention of encoding the readonly status of a mailbox in the comment field of the OK response to SELECT ๐Ÿค. that isn't regular with the rest of the protocol, where the comment field is used for no purpose other than documentation ๐Ÿ“. this proposal adds specific protocol additions for dynamically determining and modifying the readonly/readwrite status of mailboxes ๐Ÿ”.

Introduction ๐Ÿ’ซ

the intent of the Interactive Mail Access Protocol, Version 3 (IMAP3), is to let a possibly unreliable workstation or similar machine access electronic mail from a reliable mailbox server, and to do it efficiently โšก.

although IMAP3 is different from POP2 (RFC 937) in many ways, you can think of it as a functional superset of POP2 ๐Ÿงš. the POP2 RFC was used as the model for this RFC, and there was a good reason: RFC 937 deals with an identical problem, so it was desirable to have a basis for comparison ๐Ÿ“Š.

like POP2, IMAP3 specifies a means of accessing stored mail and not of posting mail ๐Ÿ“ฎ. posting is handled by a mail transfer protocol like SMTP (RFC 821) ๐Ÿ’Œ. a comparison with the DMSP protocol of PCMAIL can be found at the end of the "System Model and Philosophy" section ๐Ÿ‘€.

this protocol assumes a reliable data stream, like the one TCP or any similar protocol provides ๐ŸŒŠ. when TCP is used, the IMAP server listens on port 220 ๐Ÿ”Œ. when CHAOS is used, the IMAP server listens for the logical contact name "IMAP3" ๐Ÿงธ.

communication in IMAP is defined to use the ASCII character interpretation of data ๐Ÿ”ค. communication using other conventions may be possible if some servers select features for it ๐ŸŽ›๏ธ.


System Model and Philosophy ๐Ÿง 

electronic mail is a primary means of communication for the widely spread SUMEX-AIM community ๐Ÿ’Œ. distributed workstations are forcing a significant rethink of how that mail gets managed ๐Ÿ–ฅ๏ธ. with mainframes, each user tends to receive and process mail on the computer they use most of the time, their "primary host" ๐Ÿ . when an independent workstation shows up in front of someone, their first instinct is to start receiving mail at the workstation, and plenty of vendors have built facilities to do exactly that ๐Ÿ™‹โ€โ™€๏ธ. however, this approach has some real downsides ๐Ÿ‘‡:

  1. workstations (especially Lisp workstations) have a software design that gives the user at the console full control of every aspect of the system ๐ŸŽฎ. so background tasks, like receiving mail, could be kept from running for long periods, either because the user is using all of the machine's resources, or because the user has (maybe accidentally) changed the environment in a way that stops mail reception ๐Ÿ˜ฌ. that could lead to repeated failed delivery attempts by outside agents ๐Ÿ“ญ.
  2. the hardware failure of a single workstation could keep its user "off the air" for a considerable time, since repairing individual workstation units might be delayed ๐Ÿ› ๏ธ. with the growing number of workstations spread throughout office environments, quick repair isn't assured ๐Ÿ˜ค, whereas a centralized mainframe is generally repaired very soon after failure ๐Ÿ’ช.
  3. okay bestie, reason #3 is where it gets messy ๐Ÿ˜ญ It's way harder to keep track of mailing addresses when every single person is tied to their own separate machine ๐Ÿ“‡. Think about juggling a huge pile of postal addresses or phone numbers, especially if there wasn't one address or phone number for an organization that could reach anybody in it ๐Ÿข. Back on the ARPANET, sending email meant remembering a name plus one of several "hosts" (machines) whose name matched the organization you worked for. That was totally fine when most orgs had just one central host, but it's giving outdated today ๐Ÿ’€ unless "host" gets redefined to mean an organizational entity instead of one particular machine ๐Ÿซถ.
  4. Okay, reason #4 is a whole mood ๐ŸŒช๏ธ It is super hard to keep a bunch of different workstations running properly with complicated mailing protocols. That makes it tough to move forward as electronic communication gets better and new standards show up โœจ. Every system has to deal with receiving incoming mail, routing and delivering outgoing mail, formatting, storing, and keeping mailboxes stable across a whole pile of possible filing and mailing protocols ๐Ÿฅด.

So yeah ๐Ÿ’… the workstation can totally be called an Internet host, since it implements IP, but it should not be treated as the thing that holds the user's mailbox ๐Ÿ“ญ. Instead, a mail server machine (sometimes called a "repository") should hold the mailbox, and the workstation (from here on, a "client") should access it through mail transactions ๐Ÿ“ฌ. Since nobody's poking around on the mail server directly ๐Ÿ™ˆ, it can get high software reliability pretty easily. And since it's a shared resource, it could hit high hardware reliability too, maybe through redundancy ๐Ÿ›ก๏ธ. The mail server can be reached from basically anywhere ๐ŸŒ, so you can read mail across campus, town, or even the whole country, using clients that are getting more and more common ๐Ÿ“ฑ. Also, the same person can open their mailbox from different clients at different times, and multiple people can get into the same mailbox at once ๐Ÿ‘ฏ.

The mail server is basically the middleman ๐Ÿค between users, data storage, and other mailers. The mail access protocol is what gets messages, reads and changes message properties, and manages mailboxes ๐Ÿ“ฅ. This is different from some setups (like Unix mail over NFS ๐Ÿ—‚๏ธ) because the mail access protocol handles all message manipulation. That means the user and the client know nothing about how the data storage actually works ๐Ÿ™…โ€โ™€๏ธ. Which means the mail server can use storage however works best to organize mail in that environment ๐Ÿง , without stressing about storage representation compatibility across different machines ๐Ÿ’….

When defining a mail access protocol, remember that the client and server together make up a macrosystem ๐Ÿค. So it should be possible to use the strengths of both while covering for each other's weak spots ๐Ÿ’ช. It's also desirable to leave room to grow beyond the ancient text-only RFC 822 protocol ๐Ÿ‘ตโœจ. Unlike POP2, IMAP3 has tons of features for remote searching and parsing of messages on the server ๐Ÿ”. The server can run a free text search across the whole mailbox (optionally combined with other searches) and just hand the results to the client ๐ŸŽฏ. The client doesn't have to download the entire mailbox and search through it itself ๐Ÿ™Œ. And since the server can parse a message remotely into a structured, standard-format "envelope" ๐Ÿ“จ, a client can show envelope info and do stuff like REPLY without knowing how to parse RFC 822 headers, etc. ๐Ÿฅณ

Plus, IMAP3 has several tools for managing a mailbox beyond POP2's simple "delete message" ๐Ÿ—‘๏ธ. Even with all that, IMAP3 is still pretty simple ๐Ÿฅฐ. Servers should implement the full set of IMAP3 functions, but a simple client can be written that uses IMAP3 pretty much like a POP2 client.


IMAP3 is different from the DMSP protocol of PCMAIL (RFC 1056) in a more fundamental way ๐Ÿงฉ, because the architectures of IMAP and PCMAIL are different. PCMAIL is either online ("interactive mode") or offline ("batch mode") ๐Ÿ“ถ. IMAP is mainly online, where real-time and simultaneous mail access were seen as super important โšก.

In PCMAIL, there is a long-term client/server relationship in which some mailbox state is preserved on the client ๐Ÿ—„๏ธ. There is a registration of clients used by a particular user, and the client keeps a set of "descriptors" for each message that summarize the message. The server and client synchronize their states when the DMSP connection starts up. And if a client has not accessed the server for a while, the client does a complete reset (reload) of its state from the server ๐Ÿ”„.

In IMAP, the client/server relationship lasts only for the duration of the IMAP3 connection โณ. All mailbox state is maintained on the server, and there is no registration of clients ๐Ÿ™…โ€โ™€๏ธ. The function of a descriptor is handled by a structured representation of the message "envelope" ๐Ÿ’Œ. This structure makes it unnecessary for a client to know anything about RFC 822 parsing. There is no synchronization, since the client does not remember state between IMAP3 connections. That's not a problem, because in general the client never needs the entire state of the mailbox in a single session. So there isn't much overhead in fetching the state information that is needed, as it is needed ๐Ÿง˜โ€โ™€๏ธ.

There are also some functional differences between IMAP3 and DMSP ๐Ÿ‘€. DMSP has functions for sending messages, printing messages, and changing passwords, all of which are done outside of IMAP3. DMSP has 16 binary flags, of which 8 are defined by the system. IMAP has flag names: there are currently 5 defined system flag names, plus a facility for some number (29 in the current implementations) of user flag names ๐Ÿท๏ธ. IMAP3 has a sophisticated message search facility in the server, so it can identify interesting messages based on dates, addresses, flag status, or textual contents. The client doesn't have to be forced to fetch this data for every message ๐ŸŽฏ.

It was felt that maintaining state on the client is only advantageous when the client is used by a single user, or when there is some means on the client to restrict access to another user's data ๐Ÿ”. It can be a serious disadvantage in an environment where multiple users routinely use the same client, the same user routinely uses different clients, and there are no access restrictions on the client ๐Ÿ˜ฌ. It was also observed that most user mail access is to a relatively small set of "interesting" messages. Those were either "new" mail or mail based on some user-selected criteria ๐Ÿ’–. So IMAP3 was designed to easily identify those "interesting" messages, so the client could fetch the state of those messages and skip the ones that weren't "interesting" ๐Ÿฆ‹.

One crucial philosophical difference between IMAP and other common mail protocols is that IMAP is a mailbox access protocol, not a protocol for manipulating mail files ๐Ÿง . In the IMAP model, other mail system models store mail in a linear mail file. IMAP doesn't specify an implementation architecture for mail storage. Servers may choose to implement mailboxes as files, but that's a detail the client can be totally unaware of ๐Ÿซ .

What is more, in the IMAP model, mailboxes are viewed as mappings from keys into values ๐Ÿ—บ๏ธ. There are broadly three types of keys: generic, canonical and concrete. Generic keys are generic, mail-protocol-independent keys defined by IMAP that are meaningful across multiple mail encoding formats. An example of such a generic key might be TO, which would be associated with the To: field of an RFC 822 format message ๐Ÿ’Œ.

Canonical keys represent the way in which the server can associate values that are generally "about" a certain key concept. They might integrate several mail-format-specific fields, without having to worry the client with the particular details of any particular message format ๐Ÿช„. So the canonical TO key (called $TO) could denote anything that could reasonably be construed as being directed towards someone ๐Ÿ‘‰. That means in an RFC 822 message, the server could find the union of the To:, Resent-To, Apparently-To: and CC: fields to be the appropriate value associated with the canonical $TO key ๐Ÿงฉ.

Concrete keys allow the client to gain access to certain mail-format-specific concepts, which are not pre-specified by the IMAP protocol, in a well-defined manner ๐Ÿ”‘. For example, if the client asks for the value associated with the APPARENTLY-TO key, then (if the message is in RFC 822 format) the server would look for a header field called Apparently-To: ๐Ÿ‘€. If no such field is found, or the field is not implemented or meaningful for the particular message format, then the server will respond with the null value, called NIL, indicating the non-existence of the field ๐Ÿ™ƒ.

So IMAP servers are at liberty to implement mailboxes as relational databases if it seems convenient ๐Ÿ—ƒ๏ธ. In fact, we anticipate that future mail systems will tend to use database technology for storing and indexing mailboxes, because mailboxes keep getting bigger ๐Ÿ“ˆ.

Although IMAP is currently somewhat closely associated with RFC 822 for historical reasons, we anticipate that future IMAP developments will remove these mail-format-specific components and move toward the generic model mentioned above ๐ŸŒˆ. That will make it much easier for IMAP to incorporate things like multi-media mail ๐ŸŽจโœจ.

The Protocol โœจ

okay bestie, so IMAP3 is basically a conversation ๐Ÿ’ฌ where the client sends commands and the server sends responses back. The server can also drop extra info whenever it wants, asynchronously, and that info is totally independent from the responses to your commands. Unlike most Internet protocols, these are tagged ๐Ÿท๏ธ. Every command starts with a unique identifier, called a tag, and it's usually a short alphanumeric thing like what a Lisp "gensym" function would generate (e.g., A0001, A0002, etc.). The server replies with that same tag. It's giving organization ๐Ÿ˜ค๐ŸŽ€

We need names for two kinds of server data. Data the server sends because the client asked for it is SOLICITED. Data the server sends without being asked is UNSOLICITED ๐Ÿฆ‹. The server can send unsolicited data any time, as long as it doesn't chop up another piece of data on the same stream and make it unreadable ๐Ÿ™ˆ. Solicited data is a different story. The server is contractually required to return all of it before it sends the completion signal for that command. In other words, all solicited data has to show up inside the request/completion acknowledgement wrapper. This doesn't stop the client from running several requests at once. It just means the client needs to be sure it has all the data it asked for once a request is finished. That's what makes both synchronous and asynchronous clients possible ๐Ÿ’–

Solicited data gets identified by the tag of the client's original request. Unsolicited data uses the special reserved tag *. There's one more special reserved tag, +, which we'll get to later ๐ŸŒธ

Note: the tagging of SOLICITED data is only permitted for a selected server version other than 2.0.

A correct client can't make any assumptions about whether the server processes things one at a time or all in one go ๐Ÿ™…โ€โ™€๏ธ. The server is free to handle multiple requests from the same client in any order. This lets servers chew through expensive searches on slow backing storage in the background while still keeping things snappy for the user โšก. Clients can still count on the request/data/completion behavior I mentioned above being serialized, though ๐Ÿ’…

When a connection opens, the server sends an unsolicited OK response as a greeting and then just waits. Once commands start coming in, the server acts on them and sends back responses, often with some data mixed in ๐Ÿ‘‘

The client opens a connection, waits for that greeting, and then sends a LOGIN command with a user name and password to get authorized ๐Ÿ”. After the server says OK, the client sends a SELECT command to open the mailbox it wants. Every user's default mailbox is called INBOX, and that name is reserved and the same no matter what operating system the server runs on ๐Ÿ“ฌ. Usually the server sends back a list of valid flags, the number of messages, and how many messages have arrived since the last time someone accessed that mailbox. It sends all that as solicited data, followed by an OK response โœจ. If the client wants to leave that mailbox and check out a different one, it can just send another SELECT command ๐Ÿงš

Here's the thing that makes SELECT so special: it changes the server's state in a huge way. So the server has to process every outstanding command for a mailbox before it sends the OK tag for the SELECT command ๐Ÿ”ฅ. That way the client always knows that anything before the OK SELECT response is about the old mailbox, and anything after it is about the new one. Clean, no mix-ups, iconic ๐Ÿ’œ

Now for the versioning drama ๐ŸŽญ. In the real world, local needs and experimental work will push servers to support both supersets of the defined behavior and incompatible changes. So servers will support a SELECT.VERSION command and a SELECT.FEATURES command. Their whole job is letting clients pick the overall behavior and the specific features they want from a server ๐ŸŽ€. By default, any server processes commands and uses the same interaction syntax as IMAP2 in RFC 1064. A server isn't allowed to behave any other way unless someone uses SELECT.VERSION or SELECT.FEATURES to choose different behavior ๐Ÿ™…โ€โ™€๏ธ

Over time, when groups of generally useful changes to the default behavior are found, they'll get bundled together. Then you can turn on all of those features just by selecting a specific major version number of the protocol ๐ŸŒˆ. The version numbers (both major and minor) that SELECT.VERSION picks are versions of the IMAP protocol, not versions of the server itself, so keep that straight ๐Ÿง . Changes to the protocol are usually made to be upwards compatible, but nobody can promise that. So no client should rely on a test like if major_version > 2 then... being valid for every protocol version, because incompatible changes might show up later ๐Ÿ’€

The client reads mailbox information with FETCH commands. The actual data comes back through the solicited data mechanism. Think of FETCH as poking the server to include the data you want, along with whatever else it wants to send you ๐Ÿ‘‰๐Ÿ‘ˆ. There are three major categories of data you can fetch ๐Ÿ“

The first category is data attached to a message as an entity in the mailbox. Right now there are three items here: the "internal date", the "RFC 822 size", and the "flags" ๐Ÿท๏ธ. The internal date is when the message landed in the mailbox. The RFC 822 size is on the chopping block for future removal. It's the size of the message in bytes, expressed as an RFC 822 text string, and current clients mostly just use it in a status display line ๐Ÿ“. The flags are a list of status flags tied to the message (more on those below). You can grab all of this first-category data at once with the macro-fetch word FAST, which expands to (FLAGS INTERNALDATE RFC822.SIZE) โšก

The second category is the composition and delivery info of a message: stuff like the sender, recipient lists, message-ID, subject, and so on. This info lives in the message header in RFC 822 format, and people traditionally call it the "envelope" ๐Ÿ’Œ.

[Note: this should not be confused with the SMTP (RFC 821) envelope, which is strictly limited to delivery information.]

IMAP3 gives the envelope a structured, unambiguous representation that's especially lovely for Lisp-based parsers ๐Ÿฅฐ. A client can use the envelope for things like replying and never has to think about RFC 822 at all ๐Ÿ™Œ. We'll dig into envelopes more below. You can fetch the first and second categories together with the macro-fetch word ALL, which expands to (FLAGS INTERNALDATE RFC822.SIZE ENVELOPE) ๐Ÿซถ

The third category is data meant for direct human viewing. The current RFC 822 based IMAP3 defines three items here: RFC822.HEADER, RFC822.TEXT, and RFC822. The last one is just the first two stuck together in one text string ๐Ÿ“–. Fetching RFC822 gives you the RFC 822 representation of the message exactly as it's stored in the mailbox, with no filtering or processing at all. Raw and unfiltered, periodt ๐Ÿ’…

Here's how a typical client moves through all this ๐Ÿง. It'll FETCH ALL for some or all of the messages in the mailbox to build a presentation menu. Then, when the user wants to read a specific message, it'll FETCH RFC822.TEXT to get the body. A more basic client could also just FETCH RFC822 and call it a day, kind of like POP2-style functionality ๐Ÿค

The client can change certain data with a STORE command. For example, you delete a message by sending a STORE command that sets the \DELETED flag ๐Ÿ—‘๏ธโœจ

Other things a client can do include copying a message to another mailbox (COPY command), permanently removing deleted messages (EXPUNGE command), checking for new messages (CHECK command), and searching for messages that match certain criteria (SEARCH command) ๐Ÿ”๐Ÿ’–

To end the session, the client sends a LOGOUT command, and the server replies with a BYE followed by an OK ๐Ÿ‘‹๐ŸŒธ

A Typical Scenario ๐ŸŽ€

okay bestie, let's watch a whole session play out from start to finish ๐Ÿ’– The client opens the connection, the server says hi, and then they just trade commands and replies back and forth like a group chat ๐Ÿ’ฌ

        Client                          Server
        ------                          ------
                                    {Wait for Connection}
    {Open Connection}        -->
                                <-- * OK IMAP3 Server Ready
                                    {Wait for command}
    A001 SUPPORTED.VERSIONS   -->
                                <-- * SUPPORTED.VERSIONS ((2 0 )
                                        (3 0 EIGHT.BIT.TRANSPARENT
                                             AUTO.SET.SEEN
                                             TAGGED.SOLICITED))
                                    A001 OK Supported Versions returned.
                                    {Wait for command}
    A002 SELECT.VERSION (3 0) -->
                                <-- A002 OK Version 3.0 Selected.
                                    {Wait for command}
    A002 SELECT.FEATURES TAGGED.SOLICITED -->
                                <-- A002 OK Features selected.
                                    {Wait for command}
    A003 LOGIN Fred Secret   -->
                                <-- A003 OK User Fred logged in
                                    {Wait for command}
    A004 SELECT INBOX        -->
                                <-- A004 FLAGS (Meeting Notice \Answered
                                             \Flagged \Deleted \Seen)
                                <-- A004 19 EXISTS
                                <-- A004 2 RECENT
                                <-- A004 OK Select complete
                                    {Wait for command}
    A005 FETCH 1:19 ALL      -->
                                <-- A005 1 Fetch (......)
                                        ...
                                <-- A005 18 Fetch (......)
                                <-- A005 19 Fetch (......)
                                <-- A005 OK Fetch complete
                                    {Wait for command}
    A006 FETCH 8 RFC822.TEXT -->
                                <-- A006 8 Fetch (RFC822.TEXT {893}
                                       ...893 characters of text...
                                <-- )
                                <-- A006 OK Fetch complete
                                    {Wait for command}

    A007 STORE 8 +Flags \Deleted -->
                                <-- A007 8 Store (Flags (\Deleted
                                               \Seen))
                                <-- A007 OK Store complete
                                    {Wait for command}
    A008 EXPUNGE             -->
                                <-- A008 19 EXISTS
                                <-- A008 8 EXPUNGE
                                <-- A008 18 EXISTS
                                <-- A008 Expunge complete
                                    {Wait for command}
    A009 LOGOUT              -->
                                <-- A009 BYE IMAP3 server quitting
                                <-- A009 OK Logout complete
    {Close Connection}       --><-- {Close connection}
                                    {Go back to start}

Now for a spicier one ๐Ÿงš This version comes from a pipelining multiprocess client, so the traffic gets a lot busier โœจ

        Client                          Server
        ------                          ------
                                    {Wait for Connection}
    {Open session as above}
                                <-- A004 19 EXISTS
                                <-- A004 2 RECENT
                                <-- A004 OK Select complete
                                    {Wait for command}
    A005 SEARCH RECENT       -->
                                <-- A005 SEARCH (18 19) (RECENT)
                                <---A005 OK Search complete
    A006 FETCH 18:19 ALL RFC822.TEXT
    A007 STORE 18:19 +FLAGS (\SEEN)
    A008 FETCH 1:17 ALL      -->
                                <-- A006 18 Fetch (... RFC822.TEXT ...)
    A009 STORE 18 +FLAGS (\DELETED)
                                <-- A006 19 Fetch (... RFC822.TEXT ...)
                                <-- A006 OK Fetch complete
                                <-- A007 18 STORE (Flags (\Seen))
    A010 STORE 19 +FLAGS (\DELETED)
                                <-- A007 19 STORE (Flags (\Seen))
                                <-- A007 OK Store complete
                                <-- A008 1 Fetch (......)
                                       ...
                                <-- A008 16 Fetch (......)
                                <-- A008 17 Fetch (......)
                                <-- A008 OK Fetch complete
                                <-- A009 18 STORE (Flags (\Seen
                                                          \Deleted))

                                <-- A009 OK Store complete
                                <-- A010 19 STORE (Flags (\Seen
                                                          \Deleted))
                                <-- A010 OK Store complete
                                    {Wait for command}
                                <-- * EXISTS 23
                                <-- * RECENT 4
                                <-- * SEARCH (20 21 22 23) (RECENT)
   A011 FETCH 20:23 ALL RFC822.TEXT

Conventions โœจ

These are the meta-terms the syntax part uses, so you can read the grammar without getting lost ๐Ÿซถ

  • An ASCII-STRING is a sequence of arbitrary ASCII characters.
  • An ATOM is a sequence of ASCII characters delimited by SP or CRLF.
  • A CHARACTER is any ASCII character except """", "{", CR, LF, "%", or "\".
  • A CRLF is an ASCII carriage-return character followed immediately by an ASCII linefeed character.
  • A NUMBER is a sequence of the ASCII characters which represent decimal numerals ("0" through "9"), delimited by SP, CRLF, ",", or ":".
  • A SP is the ASCII space character.
  • A TEXT_LINE is a human-readable sequence of ASCII characters up to but not including a terminating CRLF.

One of the most common fields in IMAP3 is a STRING ๐Ÿ“ It can be an ATOM, a QUOTED-STRING (a sequence of CHARACTERs inside double-quotes), or a LITERAL. A literal is made of an open brace ("{"), a number, a close brace ("}"), a CRLF, and then an ASCII-STRING of n characters, where n is the value of the number inside the brace. In general, a string SHOULD be represented as an ATOM or QUOTED-STRING if at all possible. The semantics for QUOTED-STRING or LITERAL are checked before those for ATOM, so an ATOM used in a STRING MAY only contain CHARACTERs. Literals are most often sent from the server to the client. In the rare case of a client to server literal there is a special consideration (see the + text response below).

Another big one is the SEQUENCE โœจ It identifies a set of messages by consecutive numbers from 1 to n, where n is the number of messages in the mailbox. A sequence MAY consist of a single number, a pair of numbers delimited by colon that means all the numbers between those two, or a list of single numbers and/or number pairs. For example, the sequence 2,4:7,9,12:15 is equivalent to 2,4,5,6,7,9,12,13,14,15 and identifies all of those messages. ๐Ÿ’…


Definitions of Commands and Responses ๐ŸŒˆ

Summary of Commands and Responses

Commands:
       tag NOOP
       tag LOGIN user password
       tag LOGOUT
       tag SELECT mailbox
       tag CHECK
       tag EXPUNGE
       tag COPY sequence mailbox
       tag FETCH sequence data
       tag STORE sequence data value
       tag SEARCH criteria
       tag BBOARD bboard
       tag FIND (BBOARDS / MAILBOXES) pattern
       tag READONLY
       tag READWRITE
       tag SELECT.VERSION (major_version minor_version)
       tag SELECT.FEATURES features
       tag SUPPORTED.VERSIONS
       tag FLAGS
       tag SET.FLAGS

Responses (can be either solicited or unsolicited):
       */tag FLAGS flag_list
       */tag SEARCH (numbers) (criteria)
       */tag EXISTS
       */tag RECENT
       */tag EXPUNGE
       */tag STORE data
       */tag FETCH data
       */tag BBOARD bboard_name
       */tag MAILBOX non_inbox_mailbox_name
       */tag SUPPORTED.VERSIONS version_data
       */tag READONLY
       */tag READWRITE
       */tag OK text
       */tag NO text
       */tag BAD text
       */tag BYE text

Responses (can only be solicited):
       tag COPY message_number

Responses (can only be unsolicited):
       + text

Commands

tag NOOP ๐Ÿงš

NOOP is the chill one ๐Ÿฆ‹ The NOOP command returns an OK to the client. By itself it does nothing, but certain things MAY happen as side effects. For example, server implementations which implicitly check the mailbox for new mail MAY do so as a result of this command. The main use of this command is for the client to see if the server is still alive (and to let the server know the client is still alive, for those servers which have inactivity autologout timers) ๐Ÿ’œ

tag LOGIN user password ๐Ÿ”‘

The LOGIN command identifies the user to the server and carries the password that authenticates this user. The server uses this info to control access to the mailboxes. ๐ŸŽ€

EXAMPLE: A001 LOGIN SMITH SESAME logs in as user SMITH with password SESAME.

tag LOGOUT ๐Ÿ‘‹

The LOGOUT command tells the server the client is done with the session. The server sends a solicited BYE response before the (tagged) OK response, and then closes the connection. bye bye, bestie ๐Ÿซถ

tag SELECT mailbox ๐Ÿ“ฌ

The SELECT command selects a particular mailbox. The server MUST check that the user is permitted read access to this mailbox. Before returning an OK to the client, the server MUST send a solicited FLAGS and <n> EXISTS response to the client. That response gives the flags list for this mailbox (just the system flags if this mailbox doesn't have any special flags) and the number of messages in the mailbox. It is also RECOMMENDED that the server send a <n> RECENT unsolicited response to the client, for the benefit of clients which make use of the number of new messages in a mailbox. It is further RECOMMENDED that servers SHOULD send an unsolicited READONLY message if the mailbox that has been selected is not writable by the user.

Multiple SELECT commands are permitted in a session, in which case the prior mailbox is deselected first.

The default mailbox for the SELECT command is INBOX, a special name reserved to mean "the primary mailbox for this user on this server". The format of other mailbox names is operating system dependent (as of this writing, it reflects the path of the mailbox on the current servers), though it could reflect any server-specific naming convention for the namespace of mailboxes. That namespace need not and SHOULD NOT be viewed as equivalent to, or linked with, the server machine's file system ๐ŸŒธ

EXAMPLES:

A002 SELECT INBOX  ;; selects the default mailbox.
A002 197 EXISTS    ;; server says 197 messages in INBOX
A002 5 RECENT      ;; server says 5 are recent.
A002 OK Select complete.

or

A003 SELECT /usr/fred/my-mail.txt
 ;; select a different user specified mailbox.
...

tag CHECK ๐Ÿ”

The CHECK command forces a check for new messages and a rescan of the mailbox for internal changes. It's for those implementations which allow multiple simultaneous read/write access to the same mailbox (e.g., TOPS-20). It is RECOMMENDED that periodic implicit checks for new mail be done by servers as well. The server MUST send a solicited <n> EXISTS response prior to returning an OK to the client. ๐Ÿ’…

tag EXPUNGE โœจ

okay so EXPUNGE is the moment the mailbox gets its glow-up ๐Ÿงนโœจ It permanently removes every message that has the \DELETED flag set in its flags from the mailbox. Before the server says OK to the client, it sends a solicited <n> EXPUNGE response for each message that got removed, so the client knows exactly which one is gone ๐Ÿ’€ Every later message's message number drops by 1 right away. So if the last 5 messages in a 9-message mailbox get expunged, you'll receive 5 "5 EXPUNGE" responses for message 5. Yes, the same number five times. It's giving dรฉjร  vu ๐Ÿ™ˆ

To keep the mailbox healthy and the server and client on the same page ๐Ÿซถ, it is recommended that the server do an implicit check before the expunge starts and again once it's done. And if the server lets more than one person into the same mailbox at once, the server must guarantee both the integrity of the mailbox and the views of it held by the clients. no pressure ๐Ÿ˜ญ

EXPUNGE is not allowed if the user doesn't have write access to this mailbox ๐Ÿšซ (rip). If a user doesn't have write access to the mailbox, the server is required to signal this by replying with a NO response, plus a suitable text string that can be presented to the user explaining that the mailbox is read-only ๐Ÿ”’ It is further recommended that servers send an unsolicited READONLY message to clients that try an expunge on a read only mailbox ๐Ÿ“ข


next up is COPY ๐Ÿ“‹

tag COPY sequence mailbox

COPY copies the specified message(s) to the specified destination mailbox. If the destination mailbox doesn't exist, the server should create it ๐Ÿ—๏ธ Before the server says OK to the client, the server must return a solicited <n> COPY response for each message copied.

EXAMPLE: A003 COPY 2:4 MEETING copies messages 2, 3, and 4 to mailbox "MEETING".

COPY is not allowed if the user doesn't have write access to the destination mailbox ๐Ÿ™… If a user doesn't have write access to the destination mailbox, the server is required to signal this by replying with a NO response with a suitable text string that can be presented to the user, explaining that the mailbox is read-only. It is further recommended that servers send an unsolicited READONLY message to clients that try to copy into a read only mailbox ๐Ÿ“ข IMAP3 does not specify "where" the message will be put in the mailbox it has been copied to ๐Ÿคท


now FETCH ๐Ÿ“ this one's the main event.

tag FETCH sequence fetch_att

The data items to be fetched may be either a single atom or an S-expression list. You can fetch any of the attributes mentioned specifically below, along with any generic, canonical or concrete key ๐Ÿงš The predefined generic keys are {BCC, BODY, CC, FROM, HEADER, SIZE, SUBJECT, TEXT, TO}, and the predefined canonical keys are {$CC, $FROM, $SUBJECT, $TO}. If a key doesn't exist or isn't meaningful for the message, the server gives back the null value, NIL ๐Ÿซฅ

ALL             Equivalent to:
                (FLAGS INTERNALDATE RFC822.SIZE ENVELOPE)

ENVELOPE        The envelope of the message.  The envelope is
                computed by the server by parsing the header,
                i.e., the RFC 822 header for an RFC822 format
                message, into the component parts, defaulting
                various fields as necessary.

FAST            Macro equivalent to:
                (FLAGS INTERNALDATE RFC822.SIZE)

FLAGS           The flags which are set for this message.
                This may include the following system flags:

                        \RECENT    Message arrived since
                                    last read of this mailbox
                        \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

INTERNALDATE    The date and time the message was written to
                the mailbox.

RFC822          The message in RFC 822 format.

RFC822.HEADER   The RFC 822 format header of the message.

RFC822.SIZE     The number of characters in the message as
                expressed in RFC 822 format.

RFC822.TEXT     The text body of the message, omitting the
                RFC 822 header.

the examples are where it gets fun ๐Ÿ’…

EXAMPLES:

A003 FETCH 2:4 ALL
   fetches the flags, internal date, RFC 822 size, and envelope
   for messages 2, 3, and 4.

A004 FETCH 3 RFC822
   fetches the RFC 822 representation for message 3.

A005 FETCH 4 (FLAGS RFC822.HEADER)
   fetches the flags and RFC 822 format header for message 4.

A006 FETCH 42 $SUBJECT
A006 FETCH $SUBJECT "Some subject text..."
A006 OK FETCH completed ok.
   fetches the canonical subject field.

A007 FETCH 42 APPARENTLY-TO
A007 FETCH APPARENTLY-TO NIL
A007 OK FETCH found no value.
   fetches the concrete apparently-to field.

and now STORE ๐Ÿ”ง

tag STORE sequence data value

STORE alters the values associated with particular keys for a message in the mailbox. Just like FETCH, any generic, canonical or concrete key can be used to index the value provided. On top of those, these pre-defined keys are provided ๐Ÿ’–

   FLAGS           Replace the flags for the message with the
                   argument (in flag list format).
                  The server must respond with a solicited STORE FLAGS
                  message, showing the new state of the flags after
                  the store.

   +FLAGS          Add the flags in the argument to the
                   message's flag list.
                 The server must respond with a solicited STORE FLAGS
                 message, showing the new state of the flags after
                 the store.

  -FLAGS          Remove the flags in the argument from the
                  message's flag list.
                 The server must respond with a solicited STORE FLAGS
                 message, showing the new state of the flags after
                 the store.

  RFC822.HEADER   Replace the header of the message(s) with that
                  specified.  This allows users to use their mailboxes
                  as databases with header fields as keys.
                  The server must respond with solicited
                  STORE RFC822.HEADER, STORE RFC822.SIZE and
                  STORE ENVELOPE messages,  showing the new state
                  of the reparsed header after the store.

  RFC822.TEXT     Replace the body of the messages with that specified.
                  The server must respond with solicited
                  STORE RFC822.TEXT and STORE RFC822.SIZE messages,
                  showing the new state of the message after the store.

STORE is not allowed if the user doesn't have write access to this mailbox ๐Ÿšซ

The server is required to send a solicited STORE response for each store operation that results in a format transformation by the server. For example, the server is required to send a STORE FLAGS response when the client performs a STORE +FLAGS or a STORE -FLAGS, since the client may not easily be able to know what the result of this command will be ๐Ÿค” Similarly, if the client emits a STORE FROM command then the server should respond with a suitable STORE FROM response, because the client would be sending a string value to be stored and the server should transform this into a set of addresses. In general, though, it is legal for the server to send a solicited STORE response for each STORE operation, but this is discouraged ๐Ÿ™ƒ since it might result in the retransmission of very large and unnecessary amounts of data that have been stored.

EXAMPLE: A003 STORE 2:4 +FLAGS (\DELETED) marks messages 2, 3, and 4 for deletion.

last but not least, SEARCH ๐Ÿ”Ž

tag SEARCH search_criteria

SEARCH searches the mailbox for messages which match the given set of criteria. The server response SEARCH (criteria) (numbers) gives the set of messages which match the conjunction of the criteria specified ๐Ÿ’ซ In addition to each of the search criteria there is its logical inverse. The logical inverse criterion is denoted by the ~ (tilda) sign.

Thus, no message that matches the criterion:

FROM crispin

will match the criterion:

~FROM crispin

The criteria for the search can be any generic, canonical or concrete key. In addition to these, the following pre-defined keys are also provided โœจ

ALL             All messages in the mailbox; the default
                initial criterion for ANDing.

ANSWERED        Messages with the \ANSWERED flag set.

BCC string      Messages which contain the specified string
                in the envelope's BCC field.

BEFORE date     Messages whose internal date is earlier than
                the specified date.

BODY string     Messages which contain the specified string
                in the body of the message.

CC string       Messages which contain the specified string
                in the envelope's CC field.

DELETED         Messages with the \DELETED flag set.

FLAGGED         Messages with the \FLAGGED flag set.

FROM string     Messages which contain the specified string
                in the envelope's FROM field.

HEADER string   Messages which contain the specified string
                in the message header.

KEYWORD flag    Messages with the specified flag set.

NEW             Messages which have the \RECENT flag set but
                not the \SEEN flag.  This is functionally
                equivalent to "RECENT UNSEEN".

OLD             Messages which do not have the \RECENT flag
                set.

ON date         Messages whose internal date is the same as
                the specified date.

RECENT          Messages which have the \RECENT flag set.

SEEN            Messages which have the \SEEN flag set.

SINCE date      Messages whose internal date is later than
                the specified date.

SUBJECT string  Messages which contain the specified string
                in the envelope's SUBJECT field.

TEXT string     Messages which contain the specified string.

TO string       Messages which contain the specified string in
                the envelope's TO field.

here's the example, and it's so satisfying ๐Ÿฅฐ

EXAMPLE:  A003 SEARCH DELETED FROM "SMITH" SINCE 1-OCT-87
returns the message numbers for all deleted messages from Smith
that were placed in the mailbox since October 1, 1987.

Implementation note: The UNANSWERED, UNDELETED, UNFLAGGED, UNKEYWORD and UNSEEN criteria, described below, are preserved in IMAP3 for IMAP2 compatibility. They are, however, considered obsolete, and new Client programs are encouraged to use the ~ notation for the logical inverses of search criteria, with a view to dropping this outmoded syntax in later versions ๐Ÿ‘‹

UNANSWERED      Messages which do not have the \ANSWERED flag
                set.
  • UNDELETED ๐Ÿ’– gets you every message that does not have the \DELETED flag set. Basically the "not in the trash" squad ๐Ÿ—‘๏ธ๐Ÿšซ
  • UNFLAGGED ๐Ÿšฉ gets you every message that does not have the \FLAGGED flag set.
  • UNKEYWORD flag ๐Ÿท๏ธ gets you every message that does not have the specified flag set. You pick the flag, so you're in control ๐Ÿ‘‘
  • UNSEEN ๐Ÿ‘€ gets you every message that does not have the \SEEN flag set. No peeking allowed, lol ๐Ÿ™ˆ

tag READONLY ๐Ÿ”’

The READONLY command says the client wants to make the mailbox read-only. Think "I just wanna look, I'm not touching anything" ๐Ÿซถ. The server is required to reply with a solicited READONLY or READWRITE response.

tag READWRITE โœ๏ธ

The READWRITE command is the opposite energy. It says the client wants to make the mailbox read-write, so edits are on the table ๐Ÿ’… The server is required to reply with a solicited READONLY or READWRITE response.

tag SUPPORTED.VERSIONS ๐Ÿ“œ

The SUPPORTED.VERSIONS command asks the server for a SUPPORTED.VERSIONS message. That message is like the server's little rรฉsumรฉ ๐Ÿ’ผ It tells you which versions and features the server supports โœจ

tag SELECT.VERSION (major_version minor_version) ๐ŸŽ€

The SELECT.VERSION command says the client wants to select certain behavior on the part of the server. The major and minor versions tell the server exactly which version of the protocol is being selected ๐Ÿฆ‹

A002 SELECT.VERSION (3 0)

Okay, so here's the tea โ˜• A client may not request a server version that is not supported by the server. That means a version that isn't specifically mentioned in the response to a SUPPORTED.VERSIONS command. If a client tries anyway, the server will send back a NO response, and that's a big nope ๐Ÿ™…โ€โ™€๏ธ

It is an error for the SELECT.VERSION command to be used after a mailbox has been selected. Why? Because some server implementations might need to spawn separate programs to handle really different protocol versions ๐Ÿงš So the client can't expect any server state to be preserved after using SELECT.VERSION. Fresh start, every time ๐ŸŒธ

The default version of all servers is 2.0, i.e., IMAP2 as defined by RFC 1064. That's the baseline, bestie ๐Ÿ“

tag SELECT.FEATURES 1#features โญ

The SELECT.FEATURES command says the client wants to select certain specific features on the part of the server. A client may not request a feature that is not supported by the server. In other words, one that isn't explicitly mentioned in the set of features for the selected version returned by the SUPPORTED.VERSIONS command. If a client tries, the server sends back a NO response ๐Ÿ’€

A002 SELECT.FEATURES AUTO.SET.SEEN ~TAGGED.SOLICITED
        EIGHT.BIT.TRANSPARENT

So that's giving: select the set of features called AUTO.SET.SEEN and EIGHT.BIT.TRANSPARENT, and deselect the feature called TAGGED.SOLICITED. Using SELECT.FEATURES completely resets the set of selected features, so start clean every time ๐Ÿซง

Note: these are only example feature names, and they are not necessarily supported by any server. Check the appendix on features for more info ๐Ÿ“–
Note: some features, when present in the server, will cause the upwards compatible extension of the grammar, i.e., by adding extra commands. The server is at liberty not to remove these upwards compatible extensions to the command tables when a feature is disabled. So it is an error for a client to rely on getting a NO or BAD response in any way, for instance to determine the selectedness or presence of a feature. Don't do it, bestie ๐Ÿšซ

tag BBOARD bboard ๐Ÿ“ฃ

The BBOARD command is equivalent to SELECT, except its argument is a bulletin board (BBoard) name. The format of a BBoard name is implementation specific. It is strongly encouraged to use something that resembles a name in a generic sense, and not a file or mailbox name on the particular system ๐ŸŒˆ There is no requirement that a BBoard name be a mailbox name or a file name. (Unix netnews, for example, has a completely different namespace from mailbox or file names. Wild, right? ๐Ÿคฏ)

The result from the BBOARD command is identical to that of the SELECT command. For example, in the TOPS-20 server implementation, this:

   A0002 BBOARD FOO

is exactly equivalent to this:

   A0002 SELECT POBOX:<BBOARD>FOO.TXT
Note: the equivalence in this example is not required by the protocol. It just reflects the fuzzy line between mailboxes and BBoards on TOPS-20 ๐ŸŒ€

tag FIND (BBOARDS / MAILBOXES) pattern ๐Ÿ”

The FIND command takes the keywords BBOARDS or MAILBOXES, plus a pattern. That pattern picks out a set of BBoard or mailbox names that you can use with the BBOARD or SELECT command. There are two wildcards ๐Ÿƒ * means any number of characters (zero included) can match at that spot. % means a single character can match at that spot.

Here's how it plays out: FOO*BAR matches FOOBAR, FOOD.ON.THE.BAR and FOO.BAR. FOO%BAR only matches FOO.BAR. And * on its own matches all BBoards or mailboxes ๐ŸŒ

For wildcards, there's a quoting convention too: \* is the literal * character, \% is the literal % character, and \\ is the literal \ character. Escaping is giving precision ๐Ÿ’…

Some notes: the format of mailboxes is server implementation dependent. Also, the special mailbox name INBOX is not included in the output to the FIND MAILBOXES command. Sorry INBOX, not this time ๐Ÿฅบ

The FIND command solicits any number of BBOARD or MAILBOX responses from the server, as appropriate โœจ

Examples:

    A0002 FIND BBOARDS *
    A0002 BBOARD FOOBAR
    A0002 BBOARD GENERAL
    A0002 OK FIND completed

or

    A0002 FIND MAILBOXES FOO%BA*
    A0002 MAILBOX FOO.BAR
    A0002 MAILBOX FOO.BAZZAR
    A0002 OK FIND completed
Note: even though the use of explicit file or path names for mailboxes is discouraged by this standard, it may be unavoidable ๐Ÿซ  It's important that the value returned in the MAILBOX solicited reply be usable in the SELECT command without you having to remember any path specification that may have been used in the FIND MAILBOXES pattern. Main character energy: the answer should just work ๐ŸŽฌ

tag FLAGS ๐Ÿณ๏ธ

The FLAGS command solicits a FLAGS response from the server. Simple and iconic ๐Ÿ’œ

tag SET.FLAGS flag_list ๐Ÿท๏ธ

The SET.FLAGS command defines the user specifiable flags for this mailbox, i.e., the keywords. If this set doesn't include flags that the server previously sent to the client in a FLAGS message, then that counts as a request to delete the flag ๐Ÿ—‘๏ธ Any new flags should be created. This command does not affect the system defined flags, so any system flags included in the flag_list will be ignored ๐Ÿ™ˆ

The server must respond to this command with a solicited FLAGS message. And if deleting a flag ends up invalidating the flag sets of any messages, then the server is required to send solicited STORE FLAGS messages to the client for each modified message. Everybody gets updated, no one gets left out ๐Ÿซถ

Responses:

*/tag OK text โœ…

In its solicited form, this response identifies successful completion of the command with the indicated tag. The text is a line of human-readable text which may be useful in a protocol telemetry log for debugging purposes. Debugging buddy energy ๐Ÿงฐ

In its unsolicited form, this response simply indicates that the server is alive. No special action on the part of the client is called for. Right now this is only used by servers at startup, as a greeting that says they're ready to accept the first command. This usage is legal, but by no means required. The text is a line of human-readable text which may be logged in protocol telemetry ๐Ÿ‘‹

*/tag NO text ๐Ÿ™…โ€โ™€๏ธ

In its solicited form, this response identifies unsuccessful completion of the command with the indicated tag. The text is a line of human-readable text which probably should be displayed to the user in an error report by the client. Tell the user the tea ๐Ÿซ–

In its unsolicited form, this response indicates some operational error at the server that can't be traced to any protocol command. The text is a line of human-readable text which should be logged in protocol telemetry for the maintainer of the server and/or the client ๐Ÿ› ๏ธ

*/tag BAD text ๐Ÿ›

In its solicited form, this response indicates faulty protocol received from the client, and it indicates a bug. The text is a line of human-readable text which should be recorded in any telemetry as part of a bug report to the maintainer of the client. Someone's gotta fix that bug ๐Ÿ˜ญ

In its unsolicited form, this response indicates some protocol error at the server that can't be traced to any protocol command. The text is a line of human-readable text which should be logged in protocol telemetry for the maintainer of the server and/or the client. This generally indicates a protocol synchronization problem, and examining the protocol telemetry is advised to determine the cause of the problem ๐Ÿ”Ž

*/tag BYE text ๐Ÿ‘‹

This indicates that the server is about to close the connection. The text is a line of human-readable text which should be displayed to the user in a status report by the client. IMAP2 requires that the server emit a solicited BYE response as part of a normal logout sequence. This solicited form is not required under IMAP3, though it is still legal for compatibility ๐Ÿงณ

In its unsolicited form, the BYE response is used as a panic shutdown announcement by the server ๐Ÿšจ It is required to be used by any server that performs autologouts due to inactivity. Inactive too long? Bye bye, bestie ๐Ÿ’ค

*/tag number message_data ๐Ÿ“ฌ

The solicited (tag number message_data) response is generated as the result of a number of client requests. The server may also emit any of the following at any time as unsolicited data (i.e., * number message_data). The message_data is one of the following:

  • EXISTS ๐Ÿ”ข The specified number of messages exists in the mailbox.
  • RECENT ๐Ÿ†• The specified number of messages have arrived since the last time this mailbox was selected with the SELECT command or equivalent.
  • EXPUNGE ๐Ÿ’จ The specified message number has been permanently removed from the mailbox, and the next message in the mailbox (if any) becomes that message number. The server must send a solicited EXPUNGE response for each message that it expunges as the result of an EXPUNGE command. Note: future versions of the protocol may allow the use of a message sequence as a value returned by the EXPUNGE response, to allow more efficient compaction of client representations of mailboxes ๐Ÿงน
  • STORE data ๐Ÿ—„๏ธ Functionally equivalent to FETCH, only it is sent by the server when the state of a mailbox changes. The server must send solicited STORE responses as the result of any change caused by a STORE command. Every change gets announced, periodt ๐Ÿ“ฃ

FETCH data ๐Ÿ’– okay so this is THE main way the server tells the client stuff about a message. The data comes in a Lisp-like S-expression property list, aka nested parens, very main-character โœจ. Just like the client's FETCH request can ask for any generic, canonical or concrete key, the FETCH response can return values for any of those keys PLUS the pre-defined attributes listed below ๐ŸŽ€. The server is also permitted to send any unsolicited FETCH or STORE messages that it SHOULD choose, whether those are values for generic, canonical or concrete keys ๐Ÿฆ‹. Clients are REQUIRED to ignore any such FETCH responses that they cannot interpret ๐Ÿซถ. Like, clients are not REQUIRED to be able to understand (aka use fruitfully) the canonical $TO key, but they are REQUIRED to be able to ignore an unsolicited $TO message correctly ๐Ÿ˜ญ.

ENVELOPE ๐Ÿ“ฌ an S-expression list that describes the envelope of a message. The server builds it by parsing the RFC 822 header into its component parts, filling in various fields with defaults as needed ๐Ÿง.

The fields of the envelope 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 lists of addresses ๐Ÿ’Œ.

An address is an S-expression list that describes an electronic mail address. Its fields go in this order: personal name, source-route (aka the at-domain-list in SMTP), mailbox name, host name, and comments. Implementation note ๐Ÿค“: the comment field is an incompatible extension from IMAP2, so the server is REQUIRED not to provide this field when running in IMAP2 mode. Hard pass on that one ๐Ÿ™…โ€โ™€๏ธ.

Any field of an envelope or address that isn't applicable gets presented as the atom NIL ๐Ÿซฅ. And the server MUST default the reply-to and sender fields from the from field, because a client is not expected to know to do this ๐Ÿง . Not your job, bestie, the server's got it.

FLAGS ๐Ÿšฉ an S-expression list of flags that are set for this message. It may include these system flags:

\RECENT       Message arrived since last
              read of this mailbox
\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

INTERNALDATE ๐Ÿ—“๏ธ a string containing the date and time the message was written to the mailbox.

RFC822 ๐Ÿ“œ a string expressing the message in RFC 822 format.

Heads up ๐Ÿšจ Some implementations of IMAP2 servers had the (undocumented) behavior of setting the \SEEN flag as a side effect of fetching the body of a message. This was giving erroneous behavior for clients that prefetch messages the user might not get around to reading, so this behavior is explicitly disallowed in IMAP3. Not cute, not allowed ๐Ÿ’€.

Also, this is not a significant performance restriction, because it is always possible for IMAP3 clients to use an interaction with the server of the following type ๐Ÿงš:

A001 FETCH 42 RFC822
A002 STORE 42 +FLAGS (\SEEN)
A001 42 FETCH RFC822 {637} ......
A001 OK Fetch completed
A002 42 STORE FLAGS (\SEEN \FLAGGED...)
A002 OK Store Completed.

The rest of the attributes are giving organised energy ๐ŸŽ€:

  • RFC822.HEADER: a string expressing the RFC 822 format header of the message ๐Ÿ“จ
  • RFC822.SIZE: a number indicating the number of characters in the message as expressed in RFC 822 format ๐Ÿ”ข
  • RFC822.TEXT: a string expressing the text body of the message, omitting the RFC 822 header. See also the note for RFC822.

*/tag FLAGS flag_list ๐Ÿณ๏ธ a solicited FLAGS response MUST occur as a result of a SELECT command. The flag list is the list of flags (at a minimum, the IMAP defined flags) that are applicable for this mailbox. Flags other than the system flags are a function of the server implementation, so that's between the server and its vibes ๐ŸŒธ.

*/tag SEARCH (numbers) (search_criteria) ๐Ÿ” this response occurs as a result of a SEARCH command. The number(s) refer to those messages which match the search criteria. In its solicited form, this message lets clients find interesting groups of messages, e.g., unseen messages from Crispin ๐Ÿ‘€. In its unsolicited form, it lets the server tip the client off about interesting patterns, e.g., when new mail arrives that's recent and from Crispin ๐Ÿ“ฌ.

Compatibility note ๐Ÿงฉ: the search_criteria are sent by the server along with the matching numbers, so unsolicited SEARCH messages MAY be interpreted. This syntax is not upwards compatible with IMAP2, so the new syntax is intended to make it simple for clients that can't take advantage of unsolicited SEARCH messages to still interpret solicited SEARCH messages. They just ignore everything that follows the list of numbers, with minimal parsing ๐Ÿซ . Such clients may not, however, simply discard the rest of the line, because there might be LITERALs in the search pattern. Plot twist, bestie ๐Ÿ˜ณ.

Examples:

A00042 SEARCH (2 3 6) (FROM Crispin ~SEEN)

and

* SEARCH (42) (FROM Crispin RECENT)

*/tag READONLY ๐Ÿ”’ this indicates that the mailbox is read-only. The server is REQUIRED to respond to a READONLY or READWRITE command with either a solicited READONLY or a solicited READWRITE response. Note ๐Ÿ“: if the client attempts a mutation operation, such as STORE, on a mailbox it doesn't have write access to, then the server is REQUIRED to reply with a solicited READONLY response on the first such attempted mutation. The server MAY also choose to send solicited READONLY responses for each subsequent attempted mutation, so it can keep reminding you ๐Ÿ™ƒ.

*/tag READWRITE โœ๏ธ this indicates that the mailbox is read-write. The server is REQUIRED to respond to a READONLY or READWRITE command with either a solicited READONLY or a solicited READWRITE response. Full access, no drama ๐Ÿ’….

*/tag BBOARD bboard_name ๐Ÿ“Œ this message is produced in its solicited form as a response to a FIND BBOARDS command. In its unsolicited form, it's the server's notification that a new BBoard has been added ๐ŸŽ‰. Bboard_name MUST be a name that can be supplied to the BBOARD command so as to select the appropriate bboard.

*/tag MAILBOX non_inbox_mailbox_name ๐Ÿ“‚ this message is produced in its solicited form as a response to a FIND MAILBOXES command. In its unsolicited form, it's the server's notification that a new mailbox has been added, perhaps as the result of a COPY command creating a new mailbox ๐Ÿช„. Non_inbox_mailbox_name MUST be a name that can be supplied to the SELECT command so as to select the appropriate mailbox. Note: non_inbox_mailbox_name is never the string "INBOX". Inbox is its own whole era ๐Ÿ“ฅ.

*/tag SUPPORTED.VERSIONS (version_specs) ๐Ÿงพ this message is used either as a response to the SUPPORTED.VERSIONS command or, in its unsolicited form, to indicate the dynamic addition or removal of support for features or protocol versions ๐Ÿ”„. Each version_spec is of the form (4 2 EIGHT.BIT.TRANSPARENT AUTO.SET.SEEN ...), i.e., a major version number and a minor version number for the protocol, plus the set of features supported under the server's implementation of that protocol version ๐Ÿงฉ. A server may not dynamically remove support for any version or feature that has been selected by any currently logged-in client through use of the VERSION command. So no yanking things out from under people mid-session ๐Ÿ˜ค.

Example:

A00005 SUPPORTED.VERSIONS ((2 0 )
      (2 2 TAGGED.SOLICITED)
      (3 0 EIGHT.BIT.TRANSPARENT TAGGED.SOLICITED))

This indicates that two major versions are supported and one minor version is supported, and that tagged solicited messages are supported in versions 2.2 and 3.0, with eight bit characters being supported under version 3 ๐ŸŒˆ. For each feature mentioned in the list of features, there is also always the negation of that feature. For example, if the server supports the TAGGED.SOLICITED feature, then it also supports the ~TAGGED.SOLICITED feature, which disables this feature ๐Ÿ™ˆ. Note: these are only example feature names and are not necessarily supported by any server. See the appendix on features for more information on features ๐Ÿ“–.

+ text โœ‹ this response indicates that the server is ready to accept the text of a literal from the client. Normally, a command from the client is a single text line. If the server detects an error in the command, it can simply discard the remainder of the line. It cannot do this for commands that contain literals, since a literal can be an arbitrarily long amount of text, and the server may not even be expecting a literal ๐Ÿ˜ตโ€๐Ÿ’ซ. This mechanism is provided so the client knows not to send a literal until the server definitely expects it, which keeps client and server in sync ๐Ÿซถ.

In actual practice, this situation is rarely encountered. In the current protocol, the only client commands likely to contain literals are the LOGIN command and the STORE RFC822.HEADER or STORE RFC822.TEXT commands ๐Ÿ”. Consider a situation in which a server validates the user before checking the password. If the password contains "funny" characters and so is sent as a literal, then if the user is invalid, an error would occur before the password is parsed. Oof ๐Ÿ’€.

No such synchronization protection is provided for literals sent from the server to the client, for performance reasons ๐ŸŽ๏ธ. Any synchronization problems in this direction would be due to a bug in the client or server, not some operational problem ๐Ÿ› ๏ธ.

Sample IMAP3 session ๐Ÿ“ฌโœจ

okay so this is a real transcript of an actual IMAP3 session, bestie ๐ŸŽ€ server lines start with "S:" and client lines start with "U:". when a line was too long for the page, it got wrapped onto the next line with a tab in front, so that's a continuation and not a brand new line ๐Ÿ™ˆ

S:     * OK SUMEX-AIM.Stanford.EDU Interactive Mail Access Protocol
               III Service 6.1(349) at Mon, 14 May 90 14:58:30 PDT
U:     a001 SUPPORTED.VERSIONS
S:     * SUPPORTED.VERSIONS ((2 0 ) (3 0 EIGHT.BIT.TRANSPARENT
                  AUTO.SET.SEEN TAGGED.SOLICITED))

S:     A001 Supported Versions returned.
U:     a002 SELECT.VERSION (3 0)
S:     a002 OK Version 3.0 Selected.
U:     a003 SELECT.FEATURES TAGGED.SOLICITED
S:     a003 OK Features selected.
U:     a004 login crispin secret
S:     a004 OK User CRISPIN logged in at Thu, 9 Jun 90 14:58:42 PDT,
               job 76
U:     a005 select inbox
S:     a005 FLAGS (Bugs SF Party Skating Meeting Flames Request AI
               Question Note \XXXX \YYYY \Answered \Flagged \Deleted
               \Seen)
S:     a005 16 EXISTS
S:     a005 0 RECENT
S:     a006 OK Select complete
U:     a006 fetch 16 all
S:     a006 16 Fetch (Flags (\Seen) InternalDate " 9-Jun-88 12:55:
           RFC822.Size 637 Envelope ("Sat, 4 Jun 88 13:27:11 PDT"
           "INFO-MAC Mail Message" (("Larry Fagan" NIL "FAGAN"
           "SUMEX-AIM.Stanford.EDU" NIL)) (("Larry Fagan" NIL "FAGAN"
           "SUMEX-AIM.Stanford.EDU" NIL)) (("Larry Fagan" NIL "FAGAN"
           "SUMEX-AIM.Stanford.EDU" NIL)) ((NIL NIL "rindflEISCH"
           "SUMEX-AIM.Stanford.EDU" NIL)) NIL NIL NIL
           "<12403828905.13.FAGAN@SUMEX-AIM.Stanford.EDU>"))
S:  a006 OK Fetch completed
U:  a007 fetch 16 rfc822
S:  a007 16 Fetch (RFC822 {637}
S:  Mail-From: RINDFLEISCH created at  9-Jun-88 12:55:43
S:  Mail-From: FAGAN created at  4-Jun-88 13:27:12
S:  Date: Sat, 4 Jun 88 13:27:11 PDT
S:  From: Larry Fagan  <FAGAN@SUMEX-AIM.Stanford.EDU>
S:  To: rindflEISCH@SUMEX-AIM.Stanford.EDU
S:  Subject: INFO-MAC Mail Message
S:  Message-ID: <12403828905.13.FAGAN@SUMEX-AIM.Stanford.EDU>
S:  ReSent-Date: Thu, 9 Jun 88 12:55:43 PDT
S:  ReSent-From: TC Rindfleisch <Rindfleisch@SUMEX-AIM.Stanford.EDU>
S:  ReSent-To: Yeager@SUMEX-AIM.Stanford.EDU,
               Crispin@SUMEX-AIM.Stanford.EDU
S:  ReSent-Message-ID:
       <12405133897.80.RINDFLEISCH@SUMEX-AIM.Stanford.EDU>
S:
S:  The file is <info-mac>usenetv4-55.arc  ...
S:  Larry
S:  -------
S:  )
S:  a007 OK Fetch completed
U:  a008 logout
S:  a008 BYE UNIX IMAP III server terminating connection
S:  a008 OK SUMEX-AIM.Stanford.EDU Interim Mail Access Protocol
               Service logout

Implementation Discussion ๐Ÿงš

okay the implementation stuff is my absolute fave ๐Ÿซถ as of this writing, SUMEX has finished an IMAP2 client for Xerox Lisp machines, written in hybrid Interlisp/CommonLisp, and it's starting to hand out a client for TI Explorer Lisp machines ๐Ÿ”ฅ. they also finished a portable IMAP2 client protocol library module written in C. add a small main program (mostly the user interface) and a TCP/IP driver, and that library turned into a scrappy remote system mail-reading program under Unix ๐Ÿ’ป. the first real production use of the library is inside a MacII client that's been in daily use by real users at Stanford for quite some time now โœจ

as of this writing, SUMEX has also finished IMAP2 servers for TOPS-20, written in DEC-20 assembly language, and for 4.2/3 BSD Unix, written in C ๐Ÿ’…. the TOPS-20 server is fully compatible with MM-20, the standard TOPS-20 mailsystem, and it doesn't need any special action or setup from the user. under TOPS-20, the INBOX is the user's MAIL.TXT. that server also supports multiple simultaneous access to the same mailbox, including simultaneous access between the IMAP3 server and MM-20 ๐Ÿ‘€. the 4.2/3 BSD Unix server needs the user to be using either Unix Mail format or mail.txt format, which is compatible with SRI MM-32 or Columbia MM-C. it allows simultaneous read access, but write access has to be exclusive ๐Ÿ”’. there's also an experimental IMAP3 server running on the TI Explorer class of machine. it uses MM mailbox format and can communicate over both TCP and Chaos ๐ŸŒˆ

the Xerox Lisp client and DEC-20 server have been in production use for over two years, and the Unix server has been in production use for over a year ๐ŸŽ‰. IMAP3 has been used to reach mailboxes at remote sites from a local workstation over the Internet. for example, from the Stanford local network, one of the authors has read his mailbox at a Milnet site ๐Ÿ“ซ

a bunch of IMAP clients have been developed or are in the works now, and they run on these machines:

  • Xerox Lisp machines
  • Apple Macintosh
  • NeXT
  • IBM PC
  • TI Explorer Lisp machines
  • "Glass teletype" version that runs under Unix
  • GNU Emacs
  • X Windows
  • NTT ELIS

each of these clients is carefully tuned so the performance and user interface match the user interface model of the native machine โœจ. like, the Macintosh client has a "messy-desk" interface that lets you cut and paste text with the clipboard, plus a menu driven interface with keyboard accelerators. very iconic ๐Ÿ’…

this specification doesn't make any formal definition of size restrictions, but some of the existing servers have these limits:

  • DEC-20
    • length of a mailbox: 7,077,888 characters
    • maximum number of messages: 18,432 messages
    • length of a command line: 10,000 characters
    • length of the local host name: 64 characters
    • length of a "short" argument: 39 characters
    • length of a "long" argument: 491,520 characters
    • maximum amount of data output in a single fetch: 655,360 characters
  • TI-Explorer
    • length of a mailbox: limited by the Minimum of the size of the virtual address space and the size of the file system
    • maximum number of messages: limited by the size of the virtual address space
    • length of a command line: limited by the size of the virtual address space
    • length of the local host name: limited by the size of the virtual address space
    • length of a "short" argument: limited by the size of the virtual address space
    • length of a "long" argument: limited by the size of the virtual address space
    • maximum amount of data output in a single fetch: not limited

typical values for these limits are 30Mb for file systems and 128Mb for virtual address space ๐Ÿง . so far nobody has run up against any of these limits, and a lot of them are way bigger than most current user mail reading programs ๐Ÿ™Œ

there are a few big perks to the scheme of tags, solicited responses, and unsolicited data ๐Ÿ’–. first, the infamous synchronization problems of SMTP and similar protocols don't happen with tagged commands. a command isn't considered satisfied until a completion acknowledgement with the same tag shows up ๐ŸŽฏ. tagging lets the server send an arbitrary amount of other responses ("solicited" data) with zero chance of the client losing synchronization. compare that with the mess FTP and SMTP clients deal with around continuation, partial completion, and commentary reply codes ๐Ÿ’€

another perk is that a non-lockstep client is possible. the client can send a command and hand off the handling of the server responses to a different process, which signals the client when the tagged response comes in. some clients might even be thoroughly asynchronous, with maybe multiple outstanding commands at any given time ๐Ÿฆ‹. note: this does not require the server to process these commands in anything other than a lock-step manner. it just lets clients take advantage of servers that can do that kind of asynchronous operation โœจ

synchronization problems can happen with literals if the literal isn't recognized as one ๐Ÿ˜ญ. luckily, those cases are pretty rare, so a mechanism (the special "+" tag response) was added to handle the few cases that could happen. the proper way to fix this in every case is probably to move toward a record-oriented architecture, instead of the text stream model TCP gives you ๐Ÿงš

now, unsolicited data needs its own moment ๐Ÿ‘‘. unlike most protocols, where the server just does the client's bidding, an IMAP3 server has a semi-autonomous role. by sending "unsolicited data," the server is effectively sending a command to the client, telling it to update and/or extend its (incomplete) model of the mailbox with new info from the server ๐Ÿซง. in this view, a "fetch" command is a request for specific info from the client, but the server is always free to include more than the desired data as "unsolicited." a server acknowledgement to the "fetch" is a statement that at least all the requested data has been sent ๐Ÿ’Œ

in terms of implementation, a simple lock-step client may keep a local cache of data from the mailbox. that cache is incomplete in general, and at select time it's empty. a listener on the IMAP connection in the client processes all solicited and unsolicited data symmetrically and updates the cache based on it. basically, the client faults on a cache miss and asks the server to fill that cache slot synchronously. when a tagged completion response arrives, the listener unblocks the process that sent the tagged request ๐Ÿ”ฅ

clearly, with this model it isn't strictly necessary to tell most solicited data apart from unsolicited data. doing so, though, is clearer, and it also lets simplistic lock-step clients pull the specific value of a response to a command by trapping the tagged response. that way the client doesn't have to block on some complex predicate about watching for an update in a cache cell ๐Ÿ™ˆ

for example, maybe after opening a mailbox, solicited data arrives from the server. the first piece of data is the number of messages. this is used to size the cache. if new mail arrives, the server will cause the cache to be re-sized by sending a new "number of messages" unsolicited data message ๐Ÿ“ฌ. if the client tries to access info from the cache and hits empty spots, those trigger "fetch" requests. the request gets sent, some solicited data (including the answer to the fetch) flows back, and then the "fetch" response unblocks the client ๐Ÿฅน

people who know demand-paged virtual memory design will recognize this model as being really similar to page-fault handling on a demand-paged system ๐Ÿงšโœจ

Formal Syntax โœจ

okay bestie, the grammar is written in augmented Backus-Naur Form (BNF) notation as specified in RFC 822, with one tiny twist: the delimiter used with the "#" construct is a single space (SP), not a comma ๐ŸŽ€

address         ::= "(" addr_name SP addr_adl SP addr_mailbox SP
                    addr_host addr_comment ")"

addr_adl        ::= nil / string

addr_comment    ::= nil / string

addr_host       ::= nil / string

addr_mailbox    ::= nil / string

addr_name       ::= nil / string

bboard          ::= "BBOARD" SP bboard_name

bboard_name     ::= string

bboard_notify   ::= "BBOARD" sp bboard_name

canonical_key   ::= "$CC" /  "$FROM" / "$SUBJECT" / "$TO"
check           ::= "CHECK"

concrete_key    ::= string

copy            ::= "COPY" SP sequence SP mailbox

criterion       ::= "ALL" / "ANSWERED" /
                    "BCC" SP string / "BEFORE" SP string /
                    "BODY" SP string / "CC" SP string / "DELETED" /
                    "FLAGGED" / "KEYWORD" SP atom / "NEW" / "OLD" /
                    "ON" SP string / "RECENT" / "SEEN" /
                    "SINCE" SP string / "TEXT" SP string /
                    "TO" SP string / "UNANSWERED" / "UNDELETED" /
                    "UNFLAGGED" / "UNKEYWORD" / "UNSEEN" / key SP string

criteria        ::= 1#criterion

data            ::= ("FLAGS" SP flag_list /
                  search_notify / bboard_notify / mailbox_notify /
                  supported_versions_notify / "READONLY" / "READWRITE" /
                    "BYE" SP text_line / "OK" SP text_line /
                    "NO" SP text_line / "BAD" SP text_line)

date            ::= string in form "dd-mmm-yy hh:mm:ss-zzz"

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         ::= nil / "(" 1*address ")"

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

env_date        ::= string

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

env_in-reply-to ::= nil / string

env_length      ::= NUMBER

env_message-id  ::= nil / string

env_reply-to    ::= nil / "(" 1*address ")"

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

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

expunge         ::= "EXPUNGE"

feature         ::= ATOM

fetch           ::= "FETCH" SP sequence SP ("ALL" / "FAST" /
                    fetch_att / "(" 1#fetch_att ")")

fetch_att       ::= "ENVELOPE" / "FLAGS" / "INTERNALDATE" /
                    "RFC822" / "RFC822.HEADER" / "RFC822.SIZE" /
                    "RFC822.TEXT" / key

find            ::= "FIND" ("BBOARDS" / "MAILBOXES") pattern

flag_list       ::= ATOM / "(" 1#ATOM ")"

flags           ::= "FLAGS"

generic_key     ::= "BCC" / "BODY" / "CC" / "FROM" / "HEADER" / "SIZE" /
                    "SUBJECT" / "TEXT" / "TO"

key             ::= generic_key / canonical_key / concrete_key

literal         ::= "{" NUMBER "}" CRLF ASCII-STRING

login           ::= "LOGIN" SP userid SP password

logout          ::= "LOGOUT"

mailbox         ::= "INBOX" / string

mailbox_notify ::= MAILBOX non_inbox_mailbox_name

msg_copy        ::= "COPY"

msg_data        ::= (msg_exists / msg_recent / msg_expunge /
                    msg_fetch / msg_copy)

msg_exists      ::= "EXISTS"

msg_expunge     ::= "EXPUNGE"

msg_fetch       ::= ("FETCH" / "STORE") SP "(" 1#("ENVELOPE" SP
                     env_length envelope / "FLAGS" SP "(" 1#(recent_flag
                     flag_list) ")" / "INTERNALDATE" SP date /
                     "RFC822" SP string / "RFC822.HEADER" SP string /
                     "RFC822.SIZE" SP NUMBER / "RFC822.TEXT" SP
                     string / key SP string_list) ")"

msg_recent      ::= "RECENT"

msg_num         ::= NUMBER

nil             ::= "NIL"

non_inbox_mailbox_name ::= string

noop            ::= "NOOP"

numbers         ::= 1#NUMBER

password        ::= string

pattern         ::= string

recent_flag     ::= "\RECENT"

read_only       ::= "READONLY"

read_write      ::= "READWRITE"

ready           ::= "+" SP text_line

request         ::= tag SP (noop / login / logout / select / check /
                    expunge / copy / fetch / store / search /
                    select_version / select_features /
                    supported_versions / bboard / find /
                    read_only / read_write / flags / set_flags ) CRLF

response        ::= tag SP ("OK" / "NO" / "BAD") SP text_line CRLF

search          ::= "SEARCH" SP criteria

search_notify   ::= "SEARCH" SP (numbers) SP (criteria)

select          ::= "SELECT" SP mailbox

select_features ::= "SELECT.FEATURES" 1#feature

select_version  ::= "SELECT.VERSION" SP "(" NUMBER SP NUMBER ")"

sequence        ::= NUMBER / (NUMBER "," sequence) / (NUMBER ":"
                    sequence)

set_flags       ::= "SET.FLAGS" SP flag_list

solicited       ::= tag SP (msg_num SP msg_data / data /
                            solicited_only) CRLF

solicited_only  ::=                {None currently defined}

store           ::= "STORE" SP sequence SP store_att

store_att       ::= ("+FLAGS" SP flag_list / "-FLAGS" SP flag_list /
                    "FLAGS" SP flag_list / RFC822.TEXT SP string
                    / RFC822.HEADER SP string / key SP string)

string          ::= atom / """" 1*character """" / literal

string_list     ::= string / ("(" 1#string ")")

supported_versions ::= "SUPPORTED.VERSIONS"

supported_versions_notify ::= "SUPPORTED.VERSIONS" "(" 1#version_spec
                              ")"

system_flags    ::= "\ANSWERED" SP "\FLAGGED" SP "\DELETED" SP
                    "\SEEN"

tag             ::= atom

unsolicited     ::= "*" SP (msg_num SP msg_data / data) CRLF

userid          ::= string

version_spec    ::= "(" NUMBER SP NUMBER SP 1#feature ")"

Appendix: Features ๐Ÿฆ‹

this bit is the feature checklist ๐Ÿ“‹ it lists the standard features every IMAP3 server supports, and flags which ones are recommended or experimental. every feature has a default setting spelled out, and it is required of any server that supports a feature to make that feature's default enabledness match what's written below ๐Ÿ’– also, for every feature a server supports, the inverse feature should also be supported. the inverse name is always the feature name with ~ in front, so the AUTO.SET.SEEN feature is disabled by ~AUTO.SET.SEEN โœจ

Required Features ๐Ÿ’…

AUTO.SET.SEEN ๐Ÿ‘€

when this feature is enabled (default is disabled), the \\SEEN flag is set for all appropriate messages as a side effect of any of these:

Justification: this one's for clients that can't pipeline their commands well and talk over high latency connections ๐Ÿข when it's disabled, the server won't do any of those side effects. it's also here to smooth the move from IMAP2 to IMAP3 ๐Ÿฆ‹

TAGGED.SOLICITED ๐Ÿท๏ธ

when this feature is enabled (default is enabled for IMAP3, disabled for IMAP2 mode), solicited responses from the server carry the tag the client specified ๐ŸŽ€ when it's disabled, solicited responses get the IMAP2 compatible tag * instead, not the tag the client sent.

Justification: same vibe as before, this one smooths the transition from IMAP2 to IMAP3 ๐ŸŒˆ

EIGHT.BIT.TRANSPARENT ๐Ÿงš

when this feature is enabled (default is disabled), the server lets eight bit characters pass through transparently ๐Ÿซถ when it's disabled, the value of any bit other than the least significant 7 bits sent by the server is unspecified. if the feature is enabled, the characters making up all command keywords in the IMAP3 grammar and all feature names only use their 7 least significant bits.

Justification: this is for supporting national character sets in messages, encoded languages like Japanese Kanji characters, and binary data like programs, graphics and sound ๐Ÿ“

NEW.MAIL.NOTIFY ๐Ÿ“ฌ

when this feature is enabled (default is disabled for compatibility with the majority of existing IMAP2 servers), the server tells the client about new mail arriving in the currently selected mailbox using the appropriate RECENT and EXISTS unsolicited messages. the client doesn't need to keep sending periodic CHECK commands ๐Ÿ™Œ

Justification: this lets clients turn off any periodic polling they use to look for new mail. that polling eats bandwidth for no reason, and it can make things feel laggy because the user gets stuck waiting while some background process is busy doing a CHECK ๐Ÿ˜ญ

SEND ๐Ÿ’Œ

when this feature is enabled (default is disabled), a new SEND command shows up for the client ๐Ÿ’– the SEND command tells the server to send a message, instead of the client needing its own local way to send mail, for example. here's what a SEND might look like:

tag42 SEND RFC822 {2083}
From: James Rice <Rice@Sumex-Aim.Stanford.Edu>
To:.....

if the server can't parse the message being sent, it is required to issue a suitable NO notification to the client ๐Ÿ™…โ€โ™€๏ธ if the message can't be delivered for some reason, the server should send a suitable message to the FROM: address of the message explaining the delivery failure.

when the SEND feature is enabled, the send production gets added to the grammar and works as defined below. the send request also gets added to the list of requests in the request production, as shown here:

message_format  ::= RFC822

request         ::= tag SP (noop / login / logout / select / check /
                    expunge / copy / fetch / store / search /
                    select_version / select_features /
                    supported_versions / bboard / find /
                    read_only / read_write / flags /
                    set_flags / send) CRLF

send            ::= SEND SP message_format SP string

Justification: this is so mail can go out through the same reliable server that stores your mail ๐Ÿ”ฅ the big wins include:

  • Single process clients don't have to get held up by mail transmission โญ
  • Mail the client sends will have the server named as the message's sender. this matters because a lot of mailers wrongly send replies to the Sender instead of the From or Reply-To address. since the client usually isn't listening for mail sent straight to it, that can get mail lost ๐Ÿ’€
  • Clients can be written without any native message sending capability at all ๐Ÿง

ADD.MESSAGE ๐Ÿ’Œ

okay bestie, when this feature is turned on (it's disabled by default ๐Ÿ™ƒ), a brand new ADD.MESSAGE command shows up for the client ๐ŸŽ€. It's basically like COPY, except instead of copying a message number from the mailbox you've selected, you hand over the whole message as a string โœจ. Here's a cute example:

tag42 ADD.MESSAGE OUTGOING-MAIL RFC822 {2083}
From: James Rice <Rice@Sumex-Aim.Stanford.Edu>
To:.....

That drops the message into the mailbox called OUTGOING-MAIL ๐Ÿ“ฌ. If the server can't parse the message being added, it is required to send the client a suitable NO notification. ๐Ÿ˜ฌ

When this feature is on, the "add_message" production gets added to the grammar, and the "add_message" request also gets added to the list of requests in the request production ๐Ÿ’…:

add_message            ::= ADD.MESSAGE SP mailbox SP format SP string

message_format  ::= RFC822

request         ::= tag SP (noop / login / logout / select / check /
                    expunge / copy / fetch / store / search /
                    select_version / select_features /
                    supported_versions / bboard / find /
                    read_only / read_write / flags / set_flags /
                    add_message) CRLF

Justification: this is here so clients can easily add mail to specific mailboxes ๐Ÿ™Œ. That means a client can do things like outgoing mail storage (BCC) without having to mail special BCC mailboxes. big brain moves only ๐Ÿง ๐Ÿ’–


RENUMBER ๐Ÿ”ข

when this feature is enabled (again, disabled by default), the RENUMBER command becomes available to the client ๐Ÿฆ‹. It reorders the message numbers assigned to the messages in the mailbox. If that changes which message any given number is associated with, the server is required to send solicited RESET responses to the client ๐Ÿ“‹. The whole point is to let users view mailboxes in an order that actually makes sense to them, and doing it on the server is more efficient than the client doing the sorting ๐Ÿ™ˆ. The server may or may not change how the messages are actually stored, and the new ordering may or may not stick around after another mailbox gets selected or the IMAP session ends ๐ŸŒธ.

Informally, the syntax for the RENUMBER command is:

tag RENUMBER field_name ordering_type

This changes the IMAP grammar to look like this:

ordering_type   ::= DATE / NUMERIC / ALPHA

renumber        ::= RENUMBER SP field_name SP ordering_type

request         ::= tag SP (noop / login / logout / select / check /
                    expunge / copy / fetch / store / search /
                    select_version / select_features /
                    supported_versions / bboard / find /
                    read_only / read_write / flags / set_flags /
                    renumber) CRLF

Here's an example of the whole flow โœจ:

tag42 RENUMBER FROM ALPHA
                ;;;RENUMBER alphabetically by the from field
tag42 RESET 10:20,49
                ;;;Messages 10 to 20 and 49 have changed
tag42 OK RENUMBER finished.  Sequence has changed
tag43 FETCH ALL 10:20,49
                ;;;Client chooses to fetch the changed msgs.

To support this, the RESET message is defined as follows ๐ŸŽ€:

*/tag RESET message_sequence

It's a solicited or unsolicited message from the server, and it tells the client that it should flush any information it has retained for the specified messages ๐Ÿงน.

Justification: this matters a lot for mailboxes people copy messages into from other mailboxes ๐Ÿ“ฅ. That filing process is usually super random, so the apparent order can be really confusing. Messages in a mailbox are implicitly ordered (usually by arrival date, though that isn't a required ordering predicate), so RENUMBER means users never have to leave IMAP and use some other mail system just to sort their mailboxes ๐Ÿ’…โœจ


ENCODING ๐Ÿงฉ

when this feature is enabled (default is disabled ๐Ÿ™ƒ), a new generic key named ENCODING gets defined ๐ŸŒˆ. Its value is a list of (tag encoding-type options...) lists that describe the ordered, possibly encoded body of the message. Each list is one segment of the body, plus how that segment is encoded. Anything after the encoding_type is an extra qualifier describing the segment's format ๐Ÿ”. The server creates each tag, and every tag is unique compared to the other tags in the ENCODING list. The client can use those tags as concrete keys to get at a field encoded with the matching encoding type and options ๐Ÿ”‘. Like this:

tag41 FETCH 196 ENCODING ; Client asks for encoding field of msg 196.
tag41 FETCH ENCODING NIL ; Server replies. This message is not encoded.
tag41 OK Fetch completed.
tag42 FETCH 197 ENCODING ; Client asks for encoding field of msg 197.
tag42 FETCH ENCODING ((G001 UUENCODE) (G002 HEX)) ; Server replies.
tag42 OK Fetch completed.
tag43 FETCH 197 G002     ; Client asks for field named G002
tag43 FETCH G002 "A0 00 FF 13 42......." ; Server sends value of field.
tag43 OK Fetch completed.

or, to write a segment back:

tag44 STORE 197 G002 "0A 00 FF 31 24......."
   ; Store back the segment with nibbles swapped

Note: as a side effect of turning this feature on, the generic key TEXT gets redefined so it only returns the body parts of a message that are of type TEXT ๐Ÿ“„. The concrete key RFC822.TEXT, on the other hand, still returns everything in the body of the message, even if it's full of weird binary character sequences ๐Ÿ‘€.

When the client STOREs to a field denoted by one of the tags above, the server interprets the value being passed in the same format currently specified in the ENCODING field ๐Ÿง. The server is not required to be able to reformat the data associated with the ENCODING tags if the client STOREs a new value for the ENCODING field. The interpretability of a message in the context of its ENCODING field is undefined if the client side-effects that ENCODING field, unless the client also STOREs new, reformatted values for the fields whose encoding changed ๐Ÿ˜ญ.

If the client stores a new value for the ENCODING field, the tags in that new value are used to index the parts of the body ๐Ÿ—‚๏ธ. Any tag in a client-STOREd ENCODING that matches one the server originally generated in response to a FETCH ENCODING command is still considered to denote the field it originally denoted, even if it's been reordered. Any tag the server didn't originally define denotes a new message part, in the appropriate format, in the relative position specified ๐ŸŒฑ. Leaving out a tag the server originally defined in a FETCH of the ENCODING field indicates that part of the message is deleted ๐Ÿ—‘๏ธ. By default, newly created message parts are undefined, so if the client doesn't follow the STORE of the ENCODING field with suitable STOREs for the values of any newly created tags, those fields will contain the null value NIL ๐Ÿซ .

Justification: this is supplied to support emergent multi-part and multi-media mail standards ๐ŸŽž๏ธโœจ


INDEXABLE.FIELDS ๐Ÿฐ

when this feature is enabled (default is disabled), the grammar of fetch commands changes so the client can select a specific subsequence from the field in question ๐Ÿ“. For example:

tag42 FETCH 197 BODY 2000:3999

would fetch the second two thousand bytes of the body of message 197 ๐Ÿฅน. This is a lifesaver for resource-limited clients who need to access small parts of large messages ๐Ÿซถ. The formal syntax for this is:

fetch_att       ::= "ENVELOPE" / "FLAGS" / "INTERNALDATE" /
                    fetch_key / (fetch_key SP NUMBER ":" NUMBER)

fetch_key       ::= "RFC822" / "RFC822.HEADER" / "RFC822.SIZE" /
                    "RFC822.TEXT" / key

If the lower bound (the number to the left of the colon) is bigger than the maximum size of the field, the empty string is returned ๐Ÿซฅ. If the upper bound is bigger than the maximum size of the field but the lower bound isn't, the server returns the remaining substring of the field after the lower bound ๐Ÿงƒ. The bounds are zero indexed into the fields, and they index the fields by 8-bit bytes ๐Ÿ”ข.

Justification: this helps resource-limited clients read really big messages. It also lets clients improve interactive response when reading large messages by fetching the first "screen full" of data to show right away, then grabbing the rest of the message in the background ๐Ÿƒโ€โ™€๏ธ๐Ÿ’จ


SET.EOL ๐ŸŒŠ

when enabled (default is disabled), this feature makes the new SET.EOL command available and changes the grammar like this โœจ:

character       ::= "CR" / "LF" / number

request         ::= tag SP (noop / login / logout / select / check /
                    expunge / copy / fetch / store / search /
                    select_version / select_features /
                    supported_versions / bboard / find /
                    read_only / read_write / flags / set_flags /
                    set_eol) CRLF

set_eol         ::= "SET.EOL" 1#character

This changes the end of line character sequence the server generates for newlines within strings to whatever sequence of characters the client specifies ๐ŸŽ€. Each character can be either a symbolically named character or a numerical value, which is the decimal value of the character to use ๐Ÿ”ค. So if the client wants newlines in strings to be a carriage return followed by a control-d, the client would issue this command:

tag42 SET.EOL CR 4

If the server can't support the combination of characters the client asked for as its end-of-line pattern, it replies with a NO response ๐Ÿ˜ค. That could happen if a server can only generate its own native line feed pattern, plus the CRLF that IMAP uses by default ๐Ÿฅ€.

okay so the server is required to change any length-denoting values, like envelope byte counts, for all future transactions so they match the new eol setting ๐Ÿ’… this change in reported sizes should apply to all generic size fetching keys ๐ŸŽ€ but NOT to the concrete ones like RFC822.SIZE ๐Ÿ™ˆ those need a size measurement in RFC822 format, i.e., with CRLF as the end-of-line convention. literally the whole point is precision โœจ


Justification: this feature exists because clients and servers can totally have end-of-line conventions other than the CRLF that RFC822 specifies ๐Ÿฆ‹ it's not great for IMAP to be linked too closely to RFC822, and picking a different convention could give both clients and servers a real performance boost ๐Ÿš€ because they wouldn't have to keep shuffling text around just to add or remove non-local end-of-line sequences. iconic efficiency energy ๐Ÿ‘‘


Acknowledgements โœจ

This text is based on RFC 1064 by Mark Crispin ๐Ÿซถ

The following people made major contributions to this proposed update to the IMAP2 protocol ๐Ÿ’œ

  • James Rice <Rice@sumex-aim.stanford.edu>
  • Richard Acuff <acuff@sumex-aim.stanford.edu>
  • Bill Yeager <yeager@sumex-aim.stanford.edu>
  • Christopher Lane <lane@sumex-aim.stanford.edu>
  • Bjorn Victor <Bjorn.Victor@docs.uu.se>

Additional input was also received from these legends ๐ŸŒˆ

  • Andrew Sweer <sweer@sumex-aim.stanford.edu>
  • Tom Gruber <Gruber@sumex-aim.stanford.edu>
  • Kevin Brock <Brock@Sumex-Aim.Stanford.Edu>
  • Mark Crispin <MRC@cac.washington.edu>

Security Considerations ๐Ÿ’€

Security issues are not discussed in this memo. ๐Ÿ˜ญ no cap, the security side is just not covered here, so keep that in mind before you go shipping anything based on it ๐Ÿšจ


Author's Address ๐ŸŽ€

James Rice
Stanford University
Knowledge Systems Laboratory
701 Welch Road
Building C
Palo Alto, CA 94304

Phone: (415) 723-8405
EMail: RICE@SUMEX-AIM.STANFORD.EDU

and that's the whole doc, bestie ๐Ÿงš๐Ÿ’–

๐Ÿ“ฆ where this page comes from