RFC 1064

Interactive Mail Access Protocol: Version 2

๐Ÿ“… published July 1988, from ietf

INTERACTIVE MAIL ACCESS PROTOCOL - VERSION 2 ๐ŸŽ€

Okay bestie, let's start with the title block so you know who's behind this ๐Ÿ’…. This doc is by M. Crispin of SUMEX-AIM, dated July 1988, and it lives in the Network Working Group ๐ŸŒธ. Its status is a standard for the SUMEX-AIM community and a proposed experimental protocol for the Internet community. The title block doesn't list anything it obsoletes or updates, so no drama there โœจ.

Status of this Memo โœจ

So the whole point is a method for workstations to dynamically access mail from a mailbox server (the "repository") ๐Ÿ’Œ. This RFC is a standard for the SUMEX-AIM crowd and a proposed experimental protocol for the wider Internet ๐Ÿฆ‹. Discussion and suggestions for improvement are literally requested, so speak up ๐Ÿซถ. And distribution of this memo is unlimited, no cap ๐ŸŒˆ.

Introduction ๐Ÿฆ‹

Okay so the Interactive Mail Access Protocol, Version 2 (IMAP2) lets a workstation or similar small machine access electronic mail from a mailbox server โœจ. IMAP2 is also the protocol the SUMEX-AIM MM-D (MM Distributed) mail system runs on ๐Ÿงš.

IMAP2 may be thought of as a functional superset of POP2, even though it's different from POP2 (RFC 937) in lots of ways ๐Ÿ’–. The POP2 RFC was used as a model for this one, and there was a good reason: RFC 937 deals with the exact same problem, so it gives us a solid basis for comparison ๐Ÿ’….

Like POP2, IMAP2 is only about accessing stored mail, not posting it ๐Ÿ“ญ. Posting is handled by a mail transfer protocol like SMTP (RFC 821) ๐Ÿ“ฌ. You can also find a comparison with the DMSP protocol of PCMAIL at the end of the "System Model and Philosophy" section ๐Ÿ‘€.

This protocol assumes a reliable data stream, like what TCP or any similar protocol provides ๐Ÿงถ. When TCP is used, the IMAP2 server listens on port 143 ๐Ÿ”ฅ.

System Model and Philosophy ๐Ÿ’œ

Electronic mail is a main way the SUMEX-AIM community talks to each other, and distributed workstations are forcing everyone to rethink how that mail gets managed ๐Ÿซ . With mainframes, you'd receive and process mail on the computer you used most, your "primary host" ๐Ÿ–ฅ๏ธ. But when someone first sits down at an independent workstation, their instinct is to receive mail right there, and lots of vendors built features for exactly that. The problem? It comes with some big disadvantages, bestie:

  1. Workstations (especially Lisp workstations) are designed to give the user at the console full control of everything ๐Ÿ™ƒ. So background tasks, like receiving mail, could be kept from running for long stretches, either because the user is using all of the machine's resources, or because they (maybe by accident) messed with the environment so mail can't come in. That could lead to repeated failed delivery attempts from outside agents ๐Ÿ˜ญ.
  2. If one workstation breaks, its user could be "off the air" for a while, since repairing individual workstations might take ages ๐Ÿ› ๏ธ. With more and more workstations spread through office environments, a quick repair isn't guaranteed, whereas a centralized mainframe is usually fixed pretty soon after it fails.
  3. Keeping track of mailing addresses is harder when each person is tied to a distinct machine ๐Ÿ“‡. Think about juggling tons of postal addresses or phone numbers, especially if an organization doesn't have one address or number that reaches anyone in it. On the ARPANET, you'd remember a name plus one of several "hosts" whose names reflected your organization. That worked when most organizations had only one central host, but it's less satisfying now, unless "host" refers to an organizational entity instead of one particular machine ๐Ÿข.
  4. It's really hard to keep a bunch of heterogeneous workstations working properly with complex mailing protocols ๐Ÿฅด. That makes it tough to move forward as electronic communication progresses and new standards come out. Every system has to handle receiving incoming mail, routing and delivering outgoing mail, formatting, storing, and keeping mailboxes stable across a variety of possible filing and mailing protocols ๐Ÿ˜ต.

So even though a workstation may be seen as an Internet host in the sense that it implements IP, it should not be seen as the entity that contains the user's mailbox ๐Ÿ™…. Instead, a mail server machine (sometimes called a "repository") should hold the mailbox, and the workstation (from here on, the "client") should access the mailbox through mail transactions ๐Ÿ“ฎ. Because the mail server is isolated from direct user manipulation, it can reach high software reliability pretty easily. And as a shared resource, it can reach high hardware reliability, maybe through redundancy ๐Ÿ›ก๏ธ.

The mail server is the main character here, periodt ๐Ÿ‘‘. It can be used from arbitrary locations, so you can read mail across campus, town, or country, using more and more commonly available clients ๐ŸŒ. The same user may access their mailbox from different clients at different times, and multiple users may access the same mailbox at once ๐Ÿ‘ฏ.

The mail server acts as an interface among users, data storage, and other mailers ๐Ÿงฉ. The mail access protocol is used to retrieve messages, access and change message properties, and manage mailboxes ๐Ÿ—‚๏ธ. That's different from something like Unix mail via NFS, because here the mail access protocol is used for all message manipulations. That isolates the user and the client from any knowledge of how the data storage is used ๐Ÿ”. So the mail server can use its storage in whatever way is most efficient for organizing mail in that particular environment, without having to worry about storage representation compatibility across different machines ๐Ÿ’พ.

The client and server form a macrosystem, where it should be possible to exploit the strong points of both while compensating for each other's weaknesses ๐Ÿ’ช. It's also desirable to allow for a growth path beyond the hoary text-only RFC 822 protocol ๐Ÿฆ•. Unlike POP2, IMAP2 has extensive features for remote searching and parsing of messages on the server ๐Ÿ”. For example, a free text search (optionally in conjunction with other searching) can be run throughout the entire mailbox by the server, with the results made available to the client. The client never has to transfer the entire mailbox and search it itself ๐Ÿ™Œ. And since remote parsing of a message into a structured, standard-format "envelope" is available, a client can display envelope information and implement commands such as REPLY without understanding how to parse RFC 822 headers or anything like that ๐Ÿ’Œ.

On top of that, IMAP2 offers several facilities for managing a mailbox, way beyond the simple "delete message" functionality of POP2 ๐Ÿ—ƒ๏ธ.

In spite of all that, IMAP2 is a relatively simple protocol ๐Ÿฅฐ. Servers should implement the full set of IMAP2 functions, but a simple client can be written that uses IMAP2 in much the same way as a POP2 client ๐ŸŽ€.

IMAP2 differs from the DMSP protocol of PCMAIL (RFC 1056) in a more fundamental manner, because it reflects the different architectures of MM-D and PCMAIL ๐Ÿ—๏ธ. PCMAIL is either an online ("interactive mode") or offline ("batch mode") system ๐Ÿ”. MM-D is primarily an online system, where real-time and simultaneous mail access were considered important โšก.

In PCMAIL, there's a long-term client/server relationship where some mailbox state is preserved on the client ๐Ÿ“ฑ. There's a registration of clients used by a particular user, and the client keeps a set of "descriptors" for each message that summarize that message ๐Ÿ“. The server and client synchronize their states when the DMSP connection starts up. And if a client hasn't accessed the server for a while, the client does a complete reset (reload) of its state from the server ๐Ÿ”„.

In MM-D, the client/server relationship lasts only for the duration of the IMAP2 connection โณ. All mailbox state is maintained on the server, and there's no registration of clients ๐Ÿšซ. The function of a descriptor is handled by a structured representation of the message "envelope," which means the client doesn't need to know anything about RFC 822 parsing ๐Ÿง . There's no synchronization, since the client doesn't remember state between IMAP2 connections. That's not a problem, because the client usually never needs the entire state of the mailbox in a single session, so there isn't much overhead in fetching the state information it needs, as it needs it ๐ŸŒŸ.

There are also some functional differences between IMAP2 and DMSP ๐Ÿง. DMSP has explicit support for bulletin boards, which are only handled implicitly in IMAP2 ๐Ÿ“Œ. DMSP also has functions for sending messages, printing messages, listing mailboxes, and changing passwords, all of which happen outside of IMAP2 ๐Ÿซฅ. DMSP has 16 binary flags, 8 of which are defined by the system ๐Ÿšฉ. IMAP has flag names. Currently there are 5 defined system flag names, plus a facility for some number (30 in the current implementations) of user flag names ๐Ÿ. IMAP2 also has a sophisticated message search facility in the server. It can identify interesting messages based on dates, addresses, flag status, or textual contents, without making the client fetch this data for every message ๐Ÿ”Ž.

It was felt that keeping state on the client is only advantageous in cases where the client is used by a single user, or where there's 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, which were either "new" mail or mail based on some user-selected criteria ๐ŸŽฏ. So IMAP2 was designed to easily identify those "interesting" messages, so the client could fetch the state of those messages and not the ones that weren't "interesting" ๐Ÿ’–.


Part 1 of 5 done! More coming next, bestie โœจ

The Protocol โœจ

okay so IMAP2 is basically a back-and-forth of client commands and server responses, with server data sprinkled in between ๐Ÿ’ฌ. and the iconic part: unlike most Internet protocols, these are tagged ๐Ÿท๏ธ. every command starts with a unique identifier, usually a short alphanumeric thing like the gensyms a Lisp programmer would generate (think A0001, A0002, etc.). that's the tag. the server replies with the same tag, so you always know which command a response belongs to ๐ŸŽ€. the server can also send any amount of "unsolicited data" ๐Ÿฆ‹, which gets the special reserved tag *. and there's one more reserved tag, +, which we'll get to later ๐Ÿ‘€

the server must be listening for a connection ๐ŸŽง. when a connection opens, the server sends an unsolicited OK response as a greeting and then just waits for commands. once commands come in, it acts on them and responds, often with data mixed in ๐Ÿ“

the client opens a connection, waits for that greeting, then sends a LOGIN command with a user name and password as arguments to establish authorization ๐Ÿ”. after an OK from the server, it sends SELECT to get into the mailbox it wants. the default mailbox is called INBOX, and that name is reserved and doesn't depend on the operating system the server runs on ๐Ÿ“ฅ. generally the server will send a list of valid flags, the number of messages, and the number of messages that arrived since last access as unsolicited data, followed by an OK. the client can leave that mailbox and open a different one with another SELECT ๐Ÿ—‚๏ธ

reading mailbox info is done with FETCH commands ๐Ÿ‘€. the actual data comes back through the unsolicited data mechanism, so honestly FETCH is more like poking the server to include the data you want along with whatever else it wants to send to you ๐Ÿซถ. there are three major categories of data you can fetch.

the first category is the stuff tied to a message as an entity in the mailbox ๐Ÿ“ฆ. there are currently three items: the "internal date", the "RFC 822 size", and the "flags". the internal date is the date and time the message was placed in the mailbox. the RFC 822 size is subject to deletion in the future; it's the size in bytes of the message, expressed as an RFC 822 text string. current clients only use it as part of a status display line. the flags are a list of status flags associated with the message (more on those below). you can grab all of the first category at once with the macro-fetch word FAST, which expands to (FLAGS INTERNALDATE RFC822.SIZE) โšก

the second category is the composition and delivery info: things like the message sender, recipient lists, message-ID, subject, etc. ๐Ÿ’Œ this is the info stored in the message header in RFC 822 format, and it's traditionally called the "envelope". [Note: this should not be confused with the SMTP (RFC 821) envelope, which is strictly limited to delivery information.] IMAP2 defines a structured and unambiguous representation for the envelope that's particularly nice for Lisp-based parsers ๐Ÿงš. a client can use the envelope for operations like replying and never have to worry about RFC 822 at all. envelopes are discussed in more detail 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 present RFC 822 based IMAP2 defines three items: RFC822.HEADER, RFC822.TEXT, and RFC822 (the latter being the two former appended together in a single text string). fetching RFC822 is equivalent to getting the RFC 822 representation of the message as stored in the mailbox, with no filtering or processing at all ๐Ÿ“œ

typically, a client will 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 particular message, it'll FETCH RFC822.TEXT to get the message body. a more primitive client could, of course, just FETCH RFC822 ร  la POP2-type functionality ๐Ÿฆ•

the client can alter certain data (presently only the flags) with a STORE command ๐Ÿ”ฅ. for example, a message is deleted from a mailbox by a STORE command that includes the \DELETED flag as one of the flags being set ๐Ÿ—‘๏ธ

other client operations 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) ๐Ÿ”

the client ends the session with the LOGOUT command ๐Ÿ‘‹. the server returns a BYE followed by an OK.

A Typical Scenario

        Client                          Server
        ------                          ------
                                    {Wait for Connection}
    {Open Connection}        -->
                                <-- * OK IMAP2 Server Ready
                                    {Wait for command}
    A001 LOGIN Fred Secret   -->
                                <-- A001 OK User Fred logged in
                                    {Wait for command}
    A002 SELECT INBOX        -->
                                <-- * FLAGS (Meeting Notice \Answered
                                             \Flagged \Deleted \Seen)
                                <-- * 19 EXISTS
                                <-- * 2 RECENT
                                <-- A0002 OK Select complete
                                    {Wait for command}
    A003 FETCH 1:19 ALL      -->
                                <-- * 1 Fetch (......)
                                        ...
                                <-- * 18 Fetch (......)
                                <-- * 19 Fetch (......)
                                <-- A003 OK Fetch complete
                                    {Wait for command}
    A004 FETCH 8 RFC822.TEXT -->
                                <-- * 8 Fetch (RFC822.TEXT {893}
                                        ...893 characters of text...
                                <-- )
                                <-- A004 OK Fetch complete
                                    {Wait for command}

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

Conventions

these terms get used in a meta-sense in the syntax spec below, so let's get them down first ๐Ÿ“

  • 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 IMAP2 is a STRING ๐Ÿงถ, which can be an ATOM, a QUOTED-STRING (a sequence of CHARACTERs inside double-quotes), or a LITERAL. a literal consists 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's a special consideration (see the "+ text" response below) ๐Ÿซฃ

another important field is the SEQUENCE ๐Ÿ”ข, which identifies a set of messages by consecutive numbers from 1 to n, where n is the number of messages in the mailbox. a sequence can be a single number, a pair of numbers delimited by a colon (meaning 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

here's the whole cast of commands and responses at a glance ๐Ÿ’…

  Commands                            ||      Responses
  --------                            ||      -------
  tag NOOP                            ||      tag OK text
  tag LOGIN user password             ||      tag NO text
  tag LOGOUT                          ||      tag BAD text
  tag SELECT mailbox                  ||      * message_number data
  tag CHECK                           ||      * FLAGS flag_list
  tag EXPUNGE                         ||      * SEARCH sequence
  tag COPY sequence mailbox           ||      * BYE text
  tag FETCH sequence data             ||      * OK text
  tag STORE sequence data value       ||      * NO text
  tag SEARCH search_program           ||      * BAD text
                                      ||      + text

tag NOOP ๐Ÿ’ค

okay so NOOP is literally the chillest command ever ๐Ÿ˜Œ it returns an OK to the client, and by itself it doesn't do anything. โœจ Certain things MAY happen as side effects though. For example, servers that implicitly check the mailbox for new mail MAY do that check when NOOP shows up. The main vibe is the client checking if the server is still alive ๐Ÿซถ and letting it know the client is still around, which matters for servers with inactivity autologout timers.

tag LOGIN user password ๐Ÿ”‘

LOGIN is how the client introduces itself to the server ๐Ÿ’… It identifies the user and carries the password that proves it's really them. The server uses that info to decide who gets into which mailboxes, so it's giving security guard energy ๐Ÿ›ก๏ธ

EXAMPLE: A001 LOGIN SMITH SESAME logs in as user SMITH with password SESAME. ๐ŸŽ€

tag LOGOUT ๐Ÿ‘‹

LOGOUT is the "I'm done, bye bestie" command ๐Ÿฅน The server sends an unsolicited BYE response first, then the tagged OK, and then it closes the connection. Iconic exit, no notes.

tag SELECT mailbox ๐Ÿ“ฌ

SELECT picks which mailbox you want to work in. The server MUST check that the user actually has permission to read that mailbox, because nobody gets to snoop ๐Ÿ™ˆ Before the server sends its OK, it MUST send an unsolicited FLAGS response and an unsolicited <n> EXISTS response. These tell the client which flags this mailbox uses (just the system flags if it has no special ones) and how many messages are in it. It is RECOMMENDED that the server also send an unsolicited <n> RECENT response, which is super helpful for clients that like to show how many new messages you have ๐Ÿ“ฉ

You're allowed to send multiple SELECT commands in one session. When you do, the mailbox you had open gets deselected first, so no double-dipping ๐Ÿ“

INBOX is the default mailbox for SELECT. It's a special reserved name that means "the primary mailbox for this user on this server" ๐Ÿ  Every other mailbox name depends on the operating system. As of writing, it's basically the filename path of the mailbox file on the servers being used right now.

EXAMPLE: A002 SELECT INBOX selects the default mailbox. ๐Ÿ’–

tag CHECK ๐Ÿ”

CHECK forces a check for new messages and a rescan of the mailbox for internal changes. This is for implementations that let several people read and write the same mailbox at once (TOPS-20 is the example here) ๐Ÿงš It is RECOMMENDED that servers also do periodic implicit checks for new mail on their own. The server SHOULD send an unsolicited <n> EXISTS response before it returns an OK to the client โœจ

tag EXPUNGE ๐Ÿ—‘๏ธ

EXPUNGE permanently deletes every message that has the \DELETED flag set in its flags, so it's the "for real this time" button ๐Ÿ’€ Before the OK, the server sends an unsolicited <n> EXPUNGE response for each message it removes, so you know exactly which one went. Here's the glow-up part: every later message gets its number knocked down by 1. So if the last 5 messages in a 9-message mail file get expunged, you'll see 5 "* 5 EXPUNGE" responses. Very dramatic, very real ๐Ÿ˜ญ

For mailbox integrity and server/client sync, it is RECOMMENDED that the server does an implicit check right before the expunge starts and again once it's done ๐Ÿซถ Also, if the server lets multiple people access the same mail file at once, it MUST lock that file for exclusive access while the expunge is happening. No sharing during the big delete moment, periodt ๐Ÿ”’

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

tag COPY sequence mailbox ๐Ÿ“‹

COPY duplicates the specified message(s) into a destination mailbox โœจ If that destination doesn't exist yet, the server SHOULD create it. Before the OK, the server SHOULD send an unsolicited <n> COPY response for each message it copies. Also, a copy SHOULD set the \SEEN flag on every message that copied successfully, as long as the user has write access to that mailbox ๐Ÿ‘€

EXAMPLE: A003 COPY 2:4 MEETING copies messages 2, 3, and 4 into the mailbox "MEETING" ๐Ÿฆ‹

COPY is not allowed if the user doesn't have write access to the destination mailbox. ๐Ÿ™…โ€โ™€๏ธ

tag FETCH sequence data ๐Ÿ“ฅ

FETCH is how you grab data about a message out of the mailbox ๐ŸŽ The data items can be a single atom or an S-expression list. Totally your call ๐Ÿ’… These are the data items you can currently fetch:

  • ALL ๐ŸŒˆ is a macro equivalent to (FLAGS INTERNALDATE RFC822.SIZE ENVELOPE).
  • ENVELOPE ๐Ÿ’Œ is the message's envelope. The server builds it by parsing the RFC 822 header into its component parts and filling in any missing fields with defaults.
  • FAST โšก is a macro equivalent to (FLAGS INTERNALDATE RFC822.SIZE).
  • FLAGS ๐Ÿšฉ are the flags set on this message. This MAY include these system flags:
\RECENT    Message arrived since
            last read of this mail
            file
\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 ๐Ÿ•ฐ๏ธ is the date and time the message was written to the mailbox.
  • RFC822 ๐Ÿ“„ is the whole message in RFC 822 format.
  • RFC822.HEADER ๐Ÿงพ is the RFC 822 format header of the message.
  • RFC822.SIZE ๐Ÿ“ is how many characters the message has when expressed in RFC 822 format.
  • RFC822.TEXT ๐Ÿ“ is the text body of the message, minus the RFC 822 header.

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

tag STORE sequence data value ๐Ÿ–Š๏ธ

STORE changes the data attached to a message in the mailbox ๐Ÿ’ซ These are the data items it can store:

  • FLAGS ๐Ÿ” replaces the flags on the message with the argument, which is in flag list format.
  • +FLAGS โž• adds the flags in the argument to the message's flag list.
  • -FLAGS โž– removes the flags in the argument from the message's flag list.

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

EXAMPLE: A003 STORE 2:4 +FLAGS (\DELETED) marks messages 2, 3, and 4 for deletion. ๐Ÿ—‘๏ธ

tag SEARCH search_criteria ๐Ÿ”Ž

SEARCH digs through the mailbox for messages that match a set of criteria. The unsolicited SEARCH <1#number> response from the server is a list of the messages that match all the criteria together (that's the AND function, bestie) ๐Ÿง  These are the criteria you can currently use:

  • ALL ๐ŸŒ means every message in the mailbox. It's the default starting criterion for ANDing.
  • ANSWERED โœ… means messages with the \ANSWERED flag set.
  • BCC string ๐Ÿซฃ means messages with the specified string in the envelope's BCC field.
  • BEFORE date โช means messages whose internal date is earlier than the specified date.
  • BODY string ๐Ÿ“– means messages with the specified string somewhere in the message body.
  • CC string ๐Ÿ“ฃ means messages with the specified string in the envelope's CC field.
  • DELETED ๐Ÿ—‘๏ธ means messages with the \DELETED flag set.
  • FLAGGED ๐Ÿšฉ means messages with the \FLAGGED flag set.
  • KEYWORD flag ๐Ÿท๏ธ means messages with the specified flag set.
  • NEW ๐Ÿ†• means messages that have the \RECENT flag set but not the \SEEN flag. This is functionally the same as "RECENT UNSEEN", so it's just a shortcut.
  • OLD ๐Ÿ•ธ๏ธ means messages that don't have the \RECENT flag set.
  • ON date ๐Ÿ“… means messages whose internal date is exactly the specified date.
  • RECENT ๐ŸŒธ means messages with the \RECENT flag set.
  • SEEN ๐Ÿ‘๏ธ means messages with the \SEEN flag set.
  • SINCE date โฉ means messages whose internal date is later than the specified date.
  • SUBJECT string ๐Ÿท๏ธ means messages with the specified string in the envelope's SUBJECT field.
  • TEXT string ๐Ÿ’ฌ means messages that contain the specified string.
  • TO string ๐Ÿ“ฎ means messages with the specified string in the envelope's TO field.
  • UNANSWERED โŒ means messages without the \ANSWERED flag set.
  • UNDELETED ๐Ÿซถ means messages without the \DELETED flag set.
  • UNFLAGGED ๐Ÿณ๏ธ means messages without the \FLAGGED flag set.
  • UNKEYWORD flag ๐Ÿ™… means messages without the specified flag set.
  • UNSEEN ๐Ÿ™ˆ means messages without the \SEEN flag set.

EXAMPLE: A003 SEARCH DELETED FROM "SMITH" SINCE 1-OCT-87 returns the message numbers for every deleted message from Smith that landed in the mail file since October 1, 1987. ๐Ÿ“†๐Ÿ’

Responses โœจ

okay so responses are how the server talks back to you. there are two kinds: tagged ones answer a specific command you sent (they carry that command's tag), and untagged ones are the server just saying something, marked with * or +. let's go ๐Ÿ’…

tag OK text ๐Ÿ’–

this means the command with that tag finished successfully ๐ŸŽ‰ the text is one line of human-readable stuff that's super useful in a protocol telemetry log when you're debugging ๐Ÿ”

tag NO text ๐Ÿ™ˆ

this means the command with that tag did not finish successfully ๐Ÿ˜ฌ the text is one line of human-readable text that the client probably should show the user in an error report ๐Ÿšจ

tag BAD text ๐Ÿ›

this means the client sent faulty protocol, so the bug is on the client's side ๐Ÿ™ƒ the text is one line of human-readable text that should be recorded in any telemetry as part of a bug report to the client's maintainer ๐Ÿง‘โ€๐Ÿ’ป

* number message_data ๐Ÿ’ซ

this one shows up as a result of several different commands. 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 read ๐Ÿ“ฅ
  • EXPUNGE โ€” the specified message number has been permanently removed from the mailbox ๐Ÿ—‘๏ธ the next message in the mailbox (if there is one) takes over that message number ๐Ÿ”ข
  • STORE data โ€” basically the same as FETCH, except it happens as a result of a STORE command ๐Ÿ”
  • FETCH data โ€” the main way data about a message gets sent back to the client ๐ŸŽ the data comes in a Lisp-like S-expression property list form. the current properties are:
    • ENVELOPE โ€” an S-expression format 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 format list describing an electronic mail address ๐Ÿ“ง its fields go in this order: personal name, source-route (a.k.a. the at-domain-list in SMTP), mailbox name, and host name.
      • any field of an envelope or address that doesn't apply gets shown as the atom NIL ๐Ÿซฅ also, the server must default the reply-to and sender fields from the from field. the client isn't expected to know to do that, so the server handles it ๐Ÿ™Œ
    • FLAGS โ€” an S-expression format list of the flags set for this message ๐Ÿšฉ it may include these system flags:
      • \RECENT โ€” the message arrived since this mail file was last read ๐Ÿ†•
      • \SEEN โ€” the message has been read ๐Ÿ‘€
      • \ANSWERED โ€” the message has been answered ๐Ÿ’ฌ
      • \FLAGGED โ€” the message is "flagged" for urgent or special attention โญ
      • \DELETED โ€” the message is "deleted" for removal by a later EXPUNGE ๐Ÿ’€
    • INTERNALDATE โ€” a string with the date and time the message was written to the mailbox ๐Ÿ—“๏ธ
    • RFC822 โ€” a string expressing the whole message in RFC 822 format ๐Ÿ“œ
    • RFC822.HEADER โ€” a string expressing the RFC 822 format header of the message ๐Ÿท๏ธ
    • RFC822.SIZE โ€” a number showing how many characters the message has in RFC 822 format ๐Ÿ“
    • RFC822.TEXT โ€” a string with the text body of the message, leaving out the RFC 822 header ๐Ÿ“

* FLAGS flag_list ๐Ÿšฉ

this one comes back as a result of a SELECT command ๐ŸŽฏ the flag list is the set of flags (at a minimum, the system-defined flags) that apply to this mailbox. any flags beyond the system flags depend on the server implementation ๐Ÿ› ๏ธ

* SEARCH number(s) ๐Ÿ”Ž

this shows up as a result of a SEARCH command โœจ the number(s) point to the messages that match the search criteria. each number is delimited by a space, e.g., "SEARCH 2 3 6" ๐ŸŽ€

* BYE text ๐Ÿ‘‹

the server is about to close the connection ๐Ÿšช the text is a line of human-readable text that the client should display to the user in a status report. this can be sent as part of a normal logout sequence, or as a panic shutdown announcement by the server ๐Ÿšจ some servers also use it to announce an inactivity autologout โฐ

* OK text โœ…

this one just means the server is alive ๐Ÿ’š the client doesn't need to do anything special about it. right now it's only used by servers at startup, as a greeting that says they're ready to accept the first command ๐Ÿซถ the text is human-readable and may be logged in protocol telemetry ๐Ÿ“Š

* NO text ๐Ÿ˜ต

this is an operational error at the server that can't be traced back to any protocol command ๐Ÿงฏ the text should be logged in protocol telemetry for the maintainer of the server and/or the client. no known server currently sends this response ๐Ÿคทโ€โ™€๏ธ

* BAD text ๐Ÿšจ

this is a protocol error at the server that can't be traced back to any protocol command ๐Ÿ•ต๏ธ the text should be logged in protocol telemetry for the maintainer of the server and/or the client. this usually means the client has a protocol synchronization problem, so checking the protocol telemetry is advised to figure out the cause ๐Ÿ”

+ text ๐ŸŽ€

this means 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 spots an error in a command, it can just toss the rest of the line ๐Ÿ—‘๏ธ but it can't do that for commands with literals, since a literal can be arbitrarily long, and the server might not even be expecting one. so this mechanism keeps the client from sending a literal until the server definitely expects it, which keeps everyone in sync ๐Ÿค

in actual practice this is rarely encountered ๐Ÿ™ˆ the only client command likely to contain a literal is LOGIN. picture a server that validates the user before checking the password. if the password has "funny" characters and so gets sent as a literal, and the user is invalid, an error happens before the password is ever parsed ๐Ÿ˜ญ

there's no such sync protection for literals sent from the server to the client, for performance reasons ๐ŸŽ๏ธ any sync problems in that direction would come from a bug in the client or server, not from some operational problem ๐Ÿž


Sample IMAP2 session ๐ŸŽž๏ธ

the following is a transcript of an actual IMAP2 session ๐Ÿ“ผ server output is marked with "S:" and client output with "U:". where lines were too long to fit in this document, the line got continued on the next line, preceded by a tab ๐ŸŒธ

   S:      * OK SUMEX-AIM.Stanford.EDU Interim Mail Access Protocol II
                   Service 6.1(349) at Thu, 9 Jun 88 14:58:30 PDT
   U:      a001 login crispin secret
   S:      a002 OK User CRISPIN logged in at Thu, 9 Jun 88 14:58:42 PDT,
                   job 76
   U:      a002 select inbox
   S:      * FLAGS (Bugs SF Party Skating Meeting Flames Request AI
                   Question Note \XXXX \YYYY \Answered \Flagged \Deleted
                   \Seen)
   S:      * 16 EXISTS
   S:      * 0 RECENT
   S:      a002 OK Select complete
   U:      a003 fetch 16 all
   S:      * 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")) (("Larry Fagan" NIL "FAGAN"
               "SUMEX-AIM.Stanford.EDU")) (("Larry Fagan" NIL "FAGAN"
               "SUMEX-AIM.Stanford.EDU")) ((NIL NIL "rindflEISCH"
               "SUMEX-AIM.Stanford.EDU")) NIL NIL NIL
               "<12403828905.13.FAGAN@SUMEX-AIM.Stanford.EDU>"))
   S:   a003 OK Fetch completed
   U:   a004 fetch 16 rfc822
   S:   * 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:   )
   pa004 OK Fetch completed
   U:   a005 logout
   S:   * BYE DEC-20 IMAP II server terminating connection
   S:   a005 OK SUMEX-AIM.Stanford.EDU Interim Mail Access Protocol
                   Service logout

Implementation Discussion โœจ

okay so SUMEX has already finished an IMAP2 client for Xerox Lisp machines, written in a hybrid of Interlisp and CommonLisp, and they're beta-testing a client for TI Explorers that's written entirely in CommonLisp ๐Ÿ’ป. They also finished a portable IMAP2 client protocol library module in C ๐Ÿซถ. Add a small main program (mostly the user interface) and a TCP/IP driver, and that library became a rudimentary remote system mail-reading program under Unix ๐ŸŒธ. The first production use is going to be part of a MacII client that's still in development โœจ.

SUMEX 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 needs no special action or setup from the user ๐ŸŽ€. The INBOX under TOPS-20 is the user's MAIL.TXT ๐Ÿ“ฌ. It also supports multiple simultaneous access to the same mailbox, including simultaneous access between the IMAP2 server and MM-20 ๐Ÿ‘‘. The 4.2/3 BSD Unix server requires that the user use mail.txt format, which is compatible only with SRI MM-32 or Columbia MM-C ๐Ÿ™ˆ. It only allows simultaneous read access, so write access has to be exclusive ๐Ÿ”’.

The Xerox Lisp client and DEC-20 server have been in production use for over a year, and the Unix server went into production a few months ago ๐Ÿฅน. IMAP2 has been used to reach mailboxes at remote sites from a local workstation via the Internet ๐ŸŒ. For example, from the Stanford local network, the author has read his mailbox at a Milnet site ๐Ÿฆ‹.

This specification doesn't formally define any size restrictions, but the DEC-20 server has the following limitations ๐Ÿ“:

  • 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

Nobody has run up against any of these yet, and honestly many of them are way bigger than what most current user mail reading programs handle ๐Ÿ’–.

There are several perks to the scheme of tags and unsolicited responses ๐Ÿงš. First, the infamous synchronization problems of SMTP and similar protocols just don't happen with tagged commands. A command isn't considered satisfied until a response with the same tag shows up โœ…. Tagging lets the server send any amount of other responses (the "unsolicited" data) without the client ever losing synchronization. Compare that to the headaches FTP or SMTP clients have with continuation, partial completion, and commentary reply codes ๐Ÿ’€.

Another perk is that a non-lockstep client implementation is possible ๐Ÿƒ. The client can send a command and hand off the handling of server responses to a different process, which signals the client when the tagged response comes in. In certain circumstances, the client could even have more than one command outstanding ๐Ÿ”ฅ.

Here's some tea โ˜•: synchronization problems can happen with literals if the literal isn't recognized as one. Thankfully those cases are pretty rare, so a special "+" tag response was introduced to handle the few that could happen ๐Ÿซ . The proper way to fix this in all cases is probably moving toward a record-oriented architecture instead of the text stream model TCP provides ๐Ÿง .

Unsolicited data needs its own moment ๐Ÿซถ. Unlike most protocols, where the server just does the client's bidding, an IMAP2 server has a semi-autonomous role. By sending "unsolicited data," the server is basically sending a command to the client: update and/or extend the client's (incomplete) model of the mailbox with new information ๐Ÿ“จ. So a "fetch" is really just a request asking the server to include the desired data in whatever unsolicited data it sends anyway, and the server's acknowledgement of the "fetch" is a statement that all the requested data has been sent ๐Ÿ“ฆ.

On the implementation side ๐Ÿ› ๏ธ, the client may keep a local cache of data from the mailbox. This cache is incomplete, and it starts out empty. A listener processes all the unsolicited data and updates the cache based on it. When a tagged response arrives, the listener unblocks the process that sent the tagged request ๐Ÿ”“.

When a mailbox is opened, unsolicited data from the server might show up ๐Ÿ“ฌ. The first piece is the number of messages, and that's used to size the cache. Sending a new "number of messages" unsolicited data message re-sizes the cache, and that's how newly arrived mail is handled ๐Ÿ’Œ. If the client tries to access information from the cache, it'll hit empty spots, which trigger "fetch" requests. The request goes out, some unsolicited data including the answer flows back, and then the "fetch" response unblocks the client ๐Ÿฆ‹.

If you've studied demand-paged virtual memory operating system design, this will feel super familiar ๐Ÿ’œ. It's very similar to page-fault handling on a demand-paged system, and honestly that comparison is iconic ๐Ÿ‘‘.


Formal Syntax ๐Ÿ“

The syntax specification below uses augmented Backus-Naur Form (BNF) notation as specified in RFC 822, with one exception: the delimiter used with the "#" construct is a single space (SP) and not a comma ๐ŸŽ€.

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

   addr_adl        ::= nil / string

   addr_host       ::= nil / string

   addr_mailbox    ::= nil / string

   addr_name       ::= nil / string

   check           ::= "CHECK"

   copy            ::= "COPY" SP sequence SP mailbox

   data            ::= ("FLAGS" SP flag_list / "SEARCH" SP 1#number /
                       "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_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"

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

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

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

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

   login           ::= "LOGIN" SP userid SP password

   logout          ::= "LOGOUT"

   mailbox         ::= "INBOX" / string

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

   msg_recent      ::= "RECENT"

   msg_num         ::= NUMBER

   nil             ::= "NIL"

   noop            ::= "NOOP"

   password        ::= string
   recent_flag     ::= "\RECENT"

   ready           ::= "+" SP text_line

   request         ::= tag SP (noop / login / logout / select / check /
                       expunge / copy / fetch / store / search) CRLF

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

   search          ::= "SEARCH" SP 1#("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")

   select          ::= "SELECT" SP mailbox

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

   store           ::= "STORE" SP sequence SP store_att

   store_att       ::= ("+FLAGS" SP flag_list / "-FLAGS" SP flag_list /
                       "FLAGS" SP flag_list)

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

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

   tag             ::= atom

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

   userid          ::= string

Acknowledgements ๐Ÿซถ

Huge shout-out to Bill Yeager and Rich Acuff, who both contributed invaluable suggestions while IMAP2 evolved from the original IMAP ๐Ÿ’–. The SUMEX IMAP2 software was written by Mark Crispin (DEC-20 server, Xerox Lisp client, C client), Frank Gilmurray (Common Lisp client), Christopher Lane (Xerox Lisp client), and Bill Yeager (Unix server) ๐Ÿ‘‘. Any mistakes or flaws in this IMAP2 protocol specification are, however, strictly my own ๐Ÿ™ˆ.

๐Ÿ“ฆ where this page comes from