RFC 2683

IMAP4 Implementation Recommendations

๐Ÿ“… published September 1999, from ietf

IMAP4 Implementation Recommendations ๐Ÿ“ฌโœจ

RFC 2683 ๐ŸŽ€ Network Working Group, Request for Comments: 2683

Okay, let's start with the basics, bestie. This doc was written by B. Leiba from the IBM T.J. Watson Research Center ๐Ÿ’ผ, and it's labelled Informational ๐Ÿง  (so it's a "here's some useful advice" doc, not a binding standard). It's dated September 1999 ๐Ÿ—“๏ธ. It doesn't list anything it obsoletes or updates, so it's a standalone glow-up ๐Ÿ’….


Status of this Memo

This memo gives information to the Internet community. It is not a standard of any kind, and distribution is unlimited ๐ŸŒธ.

Copyright (C) The Internet Society (1999). All Rights Reserved. ๐Ÿ”’

1. Abstract โœจ

Okay, so IMAP4, which is defined in [RFC-2060], is a seriously rich protocol for building clients and servers that store, fetch, and manage email ๐Ÿ’Œ. Because it has so many features and so many ways to implement them, you're constantly making trade-offs and having to think through issues when you design these things ๐Ÿคฏ. This document lays those issues out and makes recommendations so the end products play nicely together. Interoperability is the whole vibe ๐Ÿซถ.

2. Conventions used in this document ๐ŸŽ€

In the examples, C: marks lines sent by a client connected to a server, and S: marks lines sent by the server to the client ๐Ÿ’ฌ.

Here's the thing: the words "must", "must not", "should", "should not", and "may" have specific meanings in this doc ๐Ÿง . Their meaning is a little different from what RFC 2119 says, so we are NOT putting them in all caps. Here's what each one means:

  • must ๐Ÿ’ช: the action described is necessary to ensure interoperability. Don't ignore this recommendation.
  • must not ๐Ÿšซ: the action described will almost certainly hurt interoperability. Don't ignore this recommendation either.
  • should โœ…: the action described is strongly recommended, and it will boost interoperability or usability. Don't ignore it unless you've thought about it really carefully.
  • should not ๐Ÿ™…: the action described is strongly recommended against, and it might hurt interoperability or usability. Same deal, don't ignore it without careful thought.
  • may ๐Ÿฆ‹: the action described is an acceptable implementation choice. It isn't a recommendation either way. This word is here to point out a choice that might not be obvious, or to show what existing implementations have picked.

3. Interoperability Issues and Recommendations ๐Ÿ’–

3.1. Accessibility ๐Ÿ”‘

This section covers the issues around accessing servers and server resources. The big topics are data sharing and keeping client/server connections alive ๐Ÿ”—.

3.1.1. Multiple Accesses of the Same Mailbox ๐Ÿ“ฆ

Okay, the big flex of IMAP4 is that, unlike POP3, it lets you have multiple simultaneous access to a single mailbox ๐Ÿ™Œ. You could read mail from your client at home while the office client is still connected. Or the help desk crew can all work out of the same inbox and see the same pile of questions ๐Ÿง‘โ€๐Ÿ’ป. BUT, and this is important, bestie: NO SERVER IS GUARANTEED TO SUPPORT THIS ๐Ÿ˜ฌ. If you're picking an IMAP server and this matters to you, make sure the server you install, in the configuration you actually use, supports it.

If you're designing a client, you must not assume you can access the same mailbox more than once at a time ๐Ÿšจ. That means:

  1. you must handle gracefully the failure of a SELECT command if the server refuses the second SELECT,
  2. you must handle reasonably the severing of your connection (see "Severed Connections", below) if the server chooses to allow the second SELECT by forcing the first off,
  3. you must avoid making multiple connections to the same mailbox in your own client (for load balancing or other such reasons), and
  4. you must avoid using the STATUS command on a mailbox that you have selected (with some server implementations, the STATUS command has the same multiple-access problems as the SELECT and EXAMINE commands).

A further note about STATUS ๐Ÿ’…: the STATUS command is sometimes used to check a non-selected mailbox for new mail. This mechanism must not be used to check for new mail in the selected mailbox. Section 5.2 of [RFC-2060] specifically forbids this in its last paragraph ๐Ÿ™…โ€โ™€๏ธ. Also, since STATUS takes a mailbox name, it's an independent operation and doesn't work on the selected mailbox. Because of that, the info it returns isn't necessarily in sync with the selected mailbox state ๐ŸŒ€.

3.1.2. Severed Connections ๐Ÿ”Œ

A client/server connection can get severed for one of three reasons: the client severs it, the server severs it, or outside forces beyond the control of both the client and the server sever it (a phone line dropping, for example) ๐Ÿ“ž๐Ÿ’€. Clients and servers both have to deal with all of these situations.

When the client wants to sever a connection, it's usually because it's finished the work it needed to do on that connection ๐Ÿ. The client should send a LOGOUT command, wait for the tagged response, and then close the socket. But here's the tea โ˜•: even though that's what the protocol design intends, there isn't universal agreement. Some folks argue that sending LOGOUT and waiting for the two responses (an untagged BYE and a tagged OK) is wasteful and unnecessary, and that the client can just close the socket. The server should interpret a closed socket as the client logging out ๐Ÿคทโ€โ™€๏ธ. The counterargument is that an explicit client logout is really useful for cleanup, problem determination, and the like. Without it, the server has no way to tell the difference between "closed socket because of log out" and "closed socket because communication was disrupted" ๐Ÿ˜ต. If something goes wrong in the client/server interaction, a client that routinely ends sessions by breaking the connection without a LOGOUT makes it a lot harder to figure out what happened ๐Ÿ•ต๏ธโ€โ™€๏ธ.

Because of this disagreement, server designers must be aware that some clients might close the socket without sending a LOGOUT โš ๏ธ. Either way, whether or not a LOGOUT was sent, the server should not implicitly expunge any messages from the selected mailbox ๐Ÿ—‘๏ธโŒ. If a client wants the server to do that, it must send a CLOSE or EXPUNGE command explicitly. No sneaky expunges allowed ๐Ÿ™…โ€โ™€๏ธ.

When the server wants to sever a connection, it's usually because of an inactivity timeout, or because something has changed the state of the mail store in a way the server can't communicate to the client ๐Ÿ›‘. The server should send an untagged BYE response to the client and then close the socket. Sending that untagged BYE before severing lets the server send a human-readable explanation of the problem, which the client may then log, display to the user, or do both (see section 7.1.5 of [RFC-2060]) ๐Ÿ’ฌ.

Now, inactivity timeouts are a bit of a hot topic ๐Ÿ”ฅ. Unlike POP, which is designed for a client to connect, grab mail, and log out, IMAP's design encourages long-lived, mostly inactive client/server sessions ๐Ÿ˜ด. As the number of users grows, this can eat up a lot of server resources, especially with clients that keep sessions open for mailboxes the user has already finished with ๐ŸงŸ. To fix that, a server may implement an inactivity timeout, unilaterally closing a session (after first sending an untagged BYE, as noted above). Some server operators have reported dramatic performance improvements after doing this ๐Ÿ“ˆ. As specified in [RFC-2060], if such a timeout is done, it must not happen until at least 30 minutes of inactivity โฐ. The reason for this rule is to stop clients from spamming commands (like NOOP) at the server every few seconds just to avoid a too-early timeout ๐Ÿ™„. If the client knows the server may not time out the session for at least 30 minutes, then the client doesn't need to poll at intervals more frequent than, say, 25 minutes ๐Ÿ˜Œ.

3.2. Scaling ๐Ÿ“ˆ

IMAP4 has a lot of features built for scalability, as mail stores get bigger and more numerous ๐Ÿ—๏ธ. Large numbers of users, mailboxes, and messages, plus really huge messages, all need some thought to handle efficiently ๐Ÿ’ช. This document won't get into the administrative issues of having lots of users, but it will look at everything else ๐Ÿ‘€.

3.2.1. Flood Control ๐ŸŒŠ

There are three situations where a client can make a request that results in a very large response, too large for the client to reasonably handle ๐Ÿฅต. Those are: there are a great many mailboxes available, there are a great many messages in the selected mailbox, or there's a very large message part. The danger is that the end user gets stuck waiting while the server sends (and the client processes) an enormous response ๐Ÿ˜ฉ. In all of these cases, there are things a client can do to reduce that danger โœ….

There's also the case where a client can flood a server by sending an arbitrarily long command ๐ŸŒช๏ธ. We'll talk about that issue too, in this section.

3.2.1.1. Listing Mailboxes ๐Ÿ“‚

Some servers present Usenet newsgroups to IMAP users ๐Ÿ“ฐ. Newsgroups, and other hierarchical mailbox structures like them, can be super numerous but may only have a few entries at the top level ๐ŸŒณ. Also, some servers are built on mail stores that can, without the server knowing, have circular hierarchies. That means it's possible for "a/b/c/d" to resolve to the same file structure as "a", which would then mean "a/b/c/d/b" is the same as "a/b", and the hierarchy never ends ๐ŸŒ€๐Ÿ˜ฑ. In that case, the LIST response will be unlimited.

Clients that'll have trouble with this are the ones that use:

C: 001 LIST "" *

to get the mailbox list. Because of this, clients should not use an unqualified "*" like that in the LIST command ๐Ÿ™…โ€โ™€๏ธ. A safer approach is to list each level of the hierarchy individually. That lets the user traverse the tree one limb at a time, like this:

C: 001 LIST "" %
S: * LIST () "/" Banana
S: * LIST ...etc...
S: 001 OK done

and then:

C: 002 LIST "" Banana/%
S: * LIST () "/" Banana/Apple
S: * LIST ...etc...
S: 002 OK done

Using this technique, the client's UI can give the user full flexibility without choking on the massive reply to "LIST *" ๐ŸŽ‰.

Of course, it's still possible that the reply to:

C: 005 LIST "" alt.fan.celebrity.%

could be thousands of entries long, and unfortunately, there's nothing the client can do to protect itself from that ๐Ÿ’€. This hasn't been a notable problem yet ๐Ÿคž.

Servers that may export circular hierarchies (any server that directly presents a UNIX file system, for instance) should limit the hierarchy depth to prevent unlimited LIST responses ๐Ÿ›ก๏ธ. A suggested depth limit is 20 hierarchy levels ๐Ÿ”ข.

3.2.1.2. Fetching the List of Messages ๐Ÿ’…

okay so when a client selects a mailbox, the server tells it how many messages are in there with a count in the untagged EXISTS response ๐Ÿ“ฌ. And bestie, that number can be HUGE. In that case it might be unwise to do this:

C: 004 FETCH 1:* ALL

to fill up the user's view of the mailbox ๐Ÿ™ˆ. A really good way to dodge that is to batch the requests, like this:

C: 004 FETCH 1:50 ALL
S: * 1 FETCH ...etc...
S: 004 OK done
C: 005 FETCH 51:100 ALL
S: * 51 FETCH ...etc...
S: 005 OK done
C: 006 FETCH 101:150 ALL
...etc...

With this method, another command like FETCH 6 BODY[1] can be slipped in whenever it's needed, and the client won't get its access to the server blocked by a storm of FETCH replies ๐ŸŒŠ. (You could even flip it around and grab the LAST 50 messages first, then the 50 before those, and so on ๐Ÿ”„.)

And as a smart upgrade, a well designed client that's ready for very large mailboxes will not automatically fetch data for all messages AT ALL ๐Ÿง โœจ. Instead, it only fills in the user's view as the user actually sees it. It might pre-fetch some selected info, then grab everything else as the user scrolls down to it. For example, to select only the messages starting with the first unseen one:

C: 003 SELECT INBOX
S: * 10000 EXISTS
S: * 80 RECENT
S: * FLAGS (\Answered \Flagged \Deleted \Draft \Seen)
S: * OK [UIDVALIDITY 824708485] UID validity status
S: * OK [UNSEEN 9921] First unseen message
S: 003 OK [READ-WRITE] SELECT completed
C: 004 FETCH 9921:* ALL
... etc...

If the server doesn't return an OK [UNSEEN] response, the client may use SEARCH UNSEEN to get that value ๐Ÿ”.

This mechanism is great as a default presentation, but it only works well if the default message order is acceptable ๐Ÿ™ƒ. A client may want to show different sort orders to the user (by subject, by date sent, by sender, and so on). In that case, lacking a SORT extension on the server side, the client WILL have to retrieve all message descriptors ๐Ÿ˜ฌ. A client that offers this should not do it by default, and it should tell the user what it costs to pick this option for large mailboxes ๐Ÿ’ธ.

3.2.1.3. Fetching a Large Body Part ๐ŸŽฌ

This one is basically the same vibe as the message list. In the BODYSTRUCTURE response, the client knows the size, in bytes, of the body part it plans to fetch. Say it's a 70 MB video clip ๐Ÿ“น. The client can use partial fetches to grab the body part in pieces, so it avoids the nightmare of an uninterruptible 70 MB literal coming back from the server ๐Ÿ˜ญ:

C: 022 FETCH 3 BODY[1]<0.20000>
S: * 3 FETCH (FLAGS(\Seen) BODY[1]<0> {20000}
S: ...data...)
S: 022 OK done
C: 023 FETCH 3 BODY[1]<20001.20000>
S: * 3 FETCH (BODY[1]<20001> {20000}
S: ...data...)
S: 023 OK done
C: 024 FETCH 3 BODY[1]<40001.20000>
...etc...

3.2.1.4. BODYSTRUCTURE vs. Entire Messages ๐Ÿง

Okay, so FETCH BODYSTRUCTURE is needed to figure out how many body parts there are, and therefore whether a message has "attachments" ๐Ÿ“Ž. That's why clients often just use FETCH FULL to fill up the user's view. The perk is that the client can show a paperclip icon (or something similar) next to the normal message summary. BUT this comes at a serious cost with some server setups ๐Ÿ˜ฉ. Parsing what's needed to generate the FETCH BODYSTRUCTURE response can be way more time-consuming than what FETCH ENVELOPE needs. So the client developer should think about this before deciding if the paperclip is worth the performance hit, especially with big mailboxes โš–๏ธ.

Some clients skip FETCH BODYSTRUCTURE and use FETCH BODY[] (or the equivalent FETCH RFC822) to grab the entire message, then do the MIME parsing on the client side ๐Ÿงฉ. This can give the client a bit more flexibility in some areas (like getting at header fields that aren't returned in the BODYSTRUCTURE and ENVELOPE responses). But it can cause severe performance problems, because it forces every body part to transfer even when the user only wants to see some of them ๐Ÿข. Picture a user on a modem reading a small text message with a huge ZIP file attached. They'd probably rather read the text now and save the ZIP for later ๐Ÿ“ฆ. So a client should not normally retrieve entire messages, and it should retrieve message body parts selectively ๐ŸŽฏ.

3.2.1.5. Long Command Lines ๐Ÿ“

Sometimes a client ends up building a super long command line while trying to be efficient about asking the server for info ๐Ÿ™ƒ. This usually happens when a client builds a message set from the selected messages and doesn't realise that contiguous blocks of messages can be grouped into a range. Imagine a user selects all 10,000 messages in a large mailbox, then unselects message 287. The client could build that message set as 1:286,288:10000. But a client that can't handle ranges might list each message individually and build 1,2,3,4, [and so on] ,9999,10000. Add that to the fetch command and you get a command line that's almost 49,000 octets long ๐Ÿ’€. And honestly, you can build one that's even longer.

A client should limit the length of the command lines it generates to approximately 1000 octets (including all quoted strings but not including literals) ๐Ÿช„. If the client can't group things into ranges to keep the command within that length, it should split the request into multiple commands. It should also use literals instead of long quoted strings to keep the command length down.

For its part, a server should allow for a command line of at least 8000 octets ๐Ÿซถ. That's plenty of leeway for accepting reasonable command lengths from clients. And if a command doesn't end within the server's maximum accepted command length, the server should send a BAD response to it ๐Ÿšซ.

3.2.2. Subscriptions ๐Ÿ”–

The client isn't the only one that can get flooded ๐ŸŒŠ. The end user may need some flood control too. IMAP4 gives that control in the form of subscriptions. Most servers support the SUBSCRIBE, UNSUBSCRIBE, and LSUB commands, and lots of users narrow down a huge list of mailboxes by subscribing to the ones they usually want to see ๐Ÿ‘€. So clients should give the user a way to see only subscribed mailboxes. A client that never uses the LSUB command takes a big usability feature away from the user ๐Ÿ˜ค. Of course, the client wouldn't want to hide the LIST command completely, because the user needs a way to choose between LIST and LSUB. The usual way to do this is a setting like "show which mailboxes?: [] all [] subscribed only" โœ….

3.2.3. Searching ๐Ÿ”Ž

IMAP SEARCH commands can get really troublesome (aka slow) on mailboxes with tons of messages ๐ŸŒ. So let's put a few things in perspective.

The flag searches should be fast. The flag searches (ALL, [UN]SEEN, [UN]ANSWERED, [UN]DELETED, [UN]DRAFT, [UN]FLAGGED, NEW, OLD, RECENT) are things clients use for their own purposes. For example, some clients use SEARCH UNSEEN to find unseen mail, and SEARCH DELETED to warn the user before expunging messages โšก.

Other searches, especially the text searches (HEADER, TEXT, BODY), are started by the user rather than by the client itself ๐Ÿ™‹. So somewhat slower performance can be tolerated, since the user knows the search is happening and probably knows it might take a while โณ. A smart server might use dynamic indexing to speed up commonly used text searches ๐Ÿง .

The client may allow other commands to be sent to the server while a SEARCH is in progress. But at the time of this writing, there's little or no server support for parallel processing of multiple commands in the same session ๐Ÿ™ˆ. (And see "Multiple Accesses of the Same Mailbox" above for a description of the dangers of trying to work around this by doing your SEARCH in another session ๐Ÿ˜ฌ.)

Another word about text searches ๐Ÿ’ฌ: some servers are built on database back-ends with indexed search capabilities, and they may return search results that don't match the IMAP spec's "case-insensitive substring" requirements. Those servers are violating the protocol, but there's little harm in the violation as long as the results are only used in response to a user's request ๐Ÿคทโ€โ™€๏ธ. Still, developers of these servers should be aware that they ARE violating the protocol, should think carefully about that behaviour, and must be certain that their servers respond accurately to the flag searches, for the reasons outlined above ๐Ÿšจ.

In addition, servers should support CHARSET UTF-8 [UTF-8] in searches ๐ŸŒ.

3.3 Avoiding Invalid Requests ๐Ÿšซ

IMAP4 gives servers ways to tell clients in advance what is and isn't permitted in some situations ๐Ÿ”ฎ. Clients should use these features to avoid sending requests that a well designed client would know are invalid. This section explains that in more detail.

3.3.1. The CAPABILITY Command ๐ŸŽ€

All IMAP4 clients should use the CAPABILITY command to find out what version of IMAP and what optional features a server supports ๐Ÿงพ. The client should not send IMAP4rev1 commands and arguments to a server that doesn't advertise IMAP4rev1 in its CAPABILITY response. Similarly, the client should not send IMAP4 commands that no longer exist in IMAP4rev1 to a server that doesn't advertise IMAP4 in its CAPABILITY response. An IMAP4rev1 server is NOT required to support obsolete IMAP4 or IMAP2bis commands (though some do, so don't let that fact lull you into thinking it's valid to send such commands to an IMAP4rev1 server ๐Ÿ™…โ€โ™€๏ธ).

A client should not send commands to probe for the existence of certain extensions ๐Ÿ•ต๏ธโ€โ™€๏ธ. All standard and standards-track extensions include CAPABILITY tokens that indicate their presence. All private and experimental extensions should do the same. Clients that take advantage of them should use the CAPABILITY response to figure out whether they may be used ๐Ÿ’….

3.3.2. Don't Do What the Server Says You Can't ๐Ÿ™…โ€โ™€๏ธ

A lot of the time, the server will tell the client something, in response to a command, about what can and can't be done with a particular mailbox ๐Ÿ‘‚. The client should pay attention to this info and should not try to do things it's been told it can't do.

Examples:

  • Do not try to SELECT a mailbox that has the \Noselect flag set.
  • Do not try to CREATE a sub-mailbox in a mailbox that has the \Noinferiors flag set.
  • Do not respond to a failing COPY or APPEND command by trying to CREATE the target mailbox if the server doesn't respond with a [TRYCREATE] response code.
  • Do not try to expunge a mailbox that has been selected with the [READ-ONLY] response code.

3.4. Miscellaneous Protocol Considerations ๐Ÿงฉ

Here we describe a bunch of important protocol-related issues. Misunderstanding these has caused a lot of interoperability problems in IMAP4 implementations ๐Ÿ˜ต. One general thing is that every implementer should be certain to take note of, and understand, section 2.2.2 and the preamble to section 7 of the IMAP4rev1 spec [RFC-2060] ๐Ÿ“š๐Ÿซถ.

3.4.1. Well Formed Protocol ๐Ÿ’…

Okay bestie, we cannot stress this enough ๐Ÿ˜ญ you have to follow the protocol grammar strictly. The spec is super rigid, so do not assume you can add blank space for "readability" if none is called for ๐Ÿ™…โ€โ™€๏ธ Keep in mind that there are parsers out there that will crash if there are protocol errors ๐Ÿ’€ and there are clients that will report every parser burp to the user ๐Ÿ™ˆ And honestly? Information that cannot be parsed is information that is lost ๐Ÿฅบ So be careful when you generate protocol messages โœจ and see "A Word About Testing", below.

Also, the string in the INTERNALDATE response is NOT an RFC-822 date string. It is not in the same format as the first string in the ENVELOPE response ๐Ÿ‘€ Most clients will actually accept an RFC-822 date string in the INTERNALDATE response, so it's super easy to miss this in your interoperability testing. But it will cause a problem with some clients, so be sure to generate the correct string for this field ๐ŸŽ€

3.4.2. Special Characters ๐Ÿฆ‹

Certain characters, currently the double-quote and the backslash, may not be sent as-is inside a quoted string. These characters MUST be preceded by the escape character if they are in a quoted string, or else the string MUST be sent as a literal. Both clients and servers MUST handle this, both on output (they MUST send these characters properly) and on input (they MUST be able to receive escaped characters in quoted strings). Example:

C: 001 LIST "" %
S: * LIST () "" INBOX
S: * LIST () "\\" TEST
S: * LIST () "\\" {12}
S: "My" mailbox
S: 001 OK done
C: 002 LIST "" "\"My\" mailbox\\%"
S: * LIST () "\\" {17}
S: "My" mailbox\Junk
S: 002 OK done

Note that in the example the server sent the hierarchy delimiter as an escaped character in the quoted string, and sent the mailbox name containing embedded double-quotes as a literal ๐Ÿงš The client used only quoted strings, escaping both the backslash and the double-quote characters. So iconic ๐Ÿ’–

The CR and LF characters MAY be sent ONLY in literals. They are not allowed, even if escaped, inside quoted strings ๐Ÿšซ

And while we're talking about special characters: the IMAP spec, in the section titled "Mailbox International Naming Convention", describes how to encode mailbox names in modified UTF-7 [UTF-7 and RFC-2060]. Implementations MUST adhere to this in order to be interoperable in the international market ๐ŸŒ and servers SHOULD validate mailbox names sent by the client and reject names that do not conform.

As for special characters in userids and passwords: clients MUST NOT restrict what a user may type in for a userid or a password. The formal grammar specifies that these are "astrings", and an astring can be a literal. A literal, in turn, can contain any 8-bit character. Clients MUST allow users to enter all 8-bit characters here, and MUST pass them, unchanged, to the server (being careful to send them as literals when necessary) ๐Ÿซถ In particular, some server configurations use @ in user names, and some clients do not allow that character to be entered. This creates a severe interoperability problem ๐Ÿ˜ค

3.4.3. UIDs and UIDVALIDITY ๐ŸŒธ

Servers that support existing back-end mail stores often have no good place to save UIDs for messages ๐Ÿ˜ฉ Often the existing mail store will not have the concept of UIDs in the sense that IMAP has: strictly increasing, never re-issued, 32-bit integers. Some servers solve this by storing the UIDs in a place that's accessible to end users, which means the users might delete them. Others solve it by re-assigning UIDs every time a mailbox is selected.

The server SHOULD maintain UIDs permanently for all messages if it can. If that's not possible, the server MUST change the UIDVALIDITY value for the mailbox whenever any of the UIDs may have become invalid. Clients MUST recognize that the UIDVALIDITY has changed, and MUST respond to that condition by throwing away any information they have saved about UIDs in that mailbox. There have been many problems in this area when clients have failed to do this. In the worst case it will result in loss of mail when a client deletes the wrong piece of mail by using a stale UID ๐Ÿ’€

It seems to be a common misunderstanding that "the UIDVALIDITY and the UID, taken together, form a 64-bit identifier that uniquely identifies a message on a server". This is absolutely NOT TRUE ๐Ÿ›‘ There is no assurance that the UIDVALIDITY values of two mailboxes be different, so the UIDVALIDITY in no way identifies a mailbox. The ONLY purpose of UIDVALIDITY is, as its name indicates, to give the client a way to check the validity of the UIDs it has cached. While it is a valid implementation choice to put these values together to make a 64-bit identifier for the message, the important concept here is that UIDs are not unique between mailboxes. They are only unique WITHIN a given mailbox.

Some server implementations have attempted to make UIDs unique across the entire server. This is inadvisable, because it limits the life of UIDs unnecessarily. The UID is a 32-bit number and will run out in reasonably finite time if it's global across the server. If you assign UIDs sequentially in one mailbox, you will not have to start re-using them until you have had, at one time or another, 2**32 different messages in that mailbox. In the global case, you will have to reuse them once you have had, at one time or another, 2**32 different messages in the entire mail store. Suppose your server has around 8000 users registered (2**13). That gives an average of 2**19 UIDs per user. Suppose each user gets 32 messages (2**5) per day. That gives you 2**14 days (16000+ days, or about 45 years) before you run out. That may seem like enough, but multiply the usage just a little (a lot of spam, a lot of mailing list subscriptions, more users) and you limit yourself too much ๐Ÿ“‰

What's worse is that if you have to wrap the UIDs, and thus have to change UIDVALIDITY and invalidate the UIDs in the mailbox, you have to do it for EVERY mailbox in the system, since they all share the same UID pool ๐Ÿ˜ฑ If you assign UIDs per mailbox and you have a problem, you only have to kill the UIDs for that one mailbox ๐Ÿ™Œ

Under extreme circumstances (and this is extreme, indeed), the server may have to invalidate UIDs while a mailbox is in use by a client. That is, the UIDs that the client knows about in its active mailbox are no longer valid. In that case, the server MUST immediately change the UIDVALIDITY and MUST communicate this to the client. The server MAY do this by sending an unsolicited UIDVALIDITY message, in the same form as the one sent in response to the SELECT command. Clients MUST be prepared to handle such a message, and the possibly coincident failure of the command in process. For example:

C: 032 UID STORE 382 +Flags.silent \Deleted
S: * OK [UIDVALIDITY 12345] New UIDVALIDITY value!
S: 032 NO UID command rejected because UIDVALIDITY changed!
C: ...invalidates local information and re-fetches...
C: 033 FETCH 1:* UID
...etc...

At the time of writing this document, the only server known to do this does so only under the following condition: the client selects INBOX, but there is not yet a physical INBOX file created. Nonetheless, the SELECT succeeds, exporting an empty INBOX with a temporary UIDVALIDITY of 1. While the INBOX remains selected, mail is delivered to the user, which creates the real INBOX file and assigns a permanent UIDVALIDITY (that is likely not to be 1). The server reports the change of UIDVALIDITY, but as there were no messages before, no UIDs have actually changed. All the client has to do is accept the change in UIDVALIDITY ๐Ÿฅณ

Alternatively, a server MAY force the client to re-select the mailbox, at which time it will obtain a new UIDVALIDITY value. To do this, the server closes this client session (see "Severed Connections" above), and the client then reconnects and gets back in sync. Clients MUST be prepared for either of these behaviours ๐Ÿฆ‹

We do not know of, nor do we anticipate the future existence of, a server that changes UIDVALIDITY while there are existing messages. But clients MUST be prepared to handle this eventuality, just in case ๐Ÿซฃ

3.4.4. FETCH Responses ๐Ÿ“

When a client asks for certain information in a FETCH command, the server MAY return the requested information in any order, not necessarily in the order that it was requested. Further, the server MAY return the information in separate FETCH responses, and MAY also return information that was not explicitly requested (to reflect to the client changes in the state of the subject message). Some examples:

C: 001 FETCH 1 UID FLAGS INTERNALDATE
S: * 5 FETCH (FLAGS (\Deleted))
S: * 1 FETCH (FLAGS (\Seen) INTERNALDATE "..." UID 345)
S: 001 OK done

(In this case, the responses are in a different order. Also, the server returned a flag update for message 5, which wasn't part of the client's request ๐Ÿ‘€)

C: 002 FETCH 2 UID FLAGS INTERNALDATE
S: * 2 FETCH (INTERNALDATE "...")
S: * 2 FETCH (UID 399)
S: * 2 FETCH (FLAGS ())
S: 002 OK done

(In this case, the responses are in a different order and were returned in separate responses ๐Ÿงฉ)

C: 003 FETCH 2 BODY[1]
S: * 2 FETCH (FLAGS (\Seen) BODY[1] {14}
S: Hello world!
S: )
S: 003 OK done

(In this case, the FLAGS response was added by the server, since fetching the body part caused the server to set the \Seen flag ๐Ÿ‘‘)

Because of this characteristic, a client MUST be ready to receive any FETCH response at any time, and SHOULD use that information to update its local information about the message to which the FETCH response refers. A client MUST NOT assume that any FETCH responses will come in any particular order, or even that any will come at all ๐Ÿ’… If, after receiving the tagged response for a FETCH command, the client finds that it did not get all of the information it requested, the client SHOULD send a NOOP command to the server. That gives the server an opportunity to send any pending EXPUNGE responses to the client (see [RFC-2180]) โœจ

3.4.5. RFC822.SIZE โœจ

okay so some back-end mail stores keep messages in a canonical form instead of holding onto the original MIME format ๐Ÿ’…. That means the server has to reassemble the message into a MIME stream whenever a client asks for something like RFC822 or BODY[] (the entire message) ๐ŸŽ€. ngl it also might mean the server has no convenient way to know the RFC822.SIZE. so often that server literally has to build the MIME stream just to count it, then toss the stream and only report the size ๐Ÿ’€.

lowkey, some servers have chosen to estimate the size instead of computing it precisely ๐Ÿฆ‹. An estimate is great for showing an approximate size to the user and for flood control considerations (q.v.) ๐ŸŒธ. BUT the client must not use that estimate for things like allocating buffers, because those buffers might end up too small to hold the actual MIME stream ๐Ÿ˜ญ. Instead, a client should use the size that's returned in the literal when you fetch the data ๐Ÿซถ.

The protocol requires that the RFC822.SIZE value returned by the server be EXACT ๐Ÿ”ฅ. Estimating the size is a protocol violation, and server designers must be aware that, even though the performance savings can be tempting, this practice will cause some clients to fail in various ways ๐Ÿ’€. If possible, the server should compute the RFC822.SIZE for a particular message once, and then save it for later retrieval ๐Ÿ“. If that's not possible, the server must compute the value exactly every time. Incorrect estimates do cause severe interoperability problems with some clients ๐Ÿ˜ค.

3.4.6. Expunged Messages ๐Ÿงš

If the server allows multiple connections to the same mailbox, it's often possible for messages to be expunged in one client unbeknownst to another client ๐Ÿ‘€. Since the server is not allowed to tell the client about these expunged messages in response to a FETCH command, the server may have to figure out how to return information about an expunged message ๐Ÿค”. There was extensive discussion about this issue, and the results of that discussion are summarized in [RFC-2180]. See that reference for a detailed explanation and for recommendations ๐Ÿ“š.

3.4.7. The Namespace Issue ๐ŸŒˆ

Namespaces are a very muddy area in IMAP4 implementation right now (see [NAMESPACE] for a proposal to clear the water a bit) ๐Ÿซ . Until the issue is resolved, the important thing for client developers to understand is that some servers provide access through IMAP to more than just the user's personal mailboxes. In fact, the user's personal mailboxes may be "hidden" somewhere in the user's default hierarchy ๐Ÿ™ˆ. The client, therefore, should provide a setting where the user can specify a prefix to be used when accessing mailboxes. If the user's mailboxes are all in "~/mail/", for instance, then the user can put that string in the prefix โœจ. The client would then put the prefix in front of any name pattern in the LIST and LSUB commands:

C: 001 LIST "" ~/mail/%

(See also "Reference Names in the LIST Command" below.) ๐Ÿ’œ

3.4.8. Creating Special-Use Mailboxes ๐ŸŽ€

It may seem at first that this is part of the namespace issue, but it is not, and it's only indirectly related to it ๐Ÿ™ƒ. A number of clients like to create special-use mailboxes with particular names. Most commonly, clients with a "trash folder" model of message deletion want to create a mailbox named "Trash" or "Deleted". Some clients want to create a "Drafts" mailbox, an "Outbox" mailbox, or a "Sent Mail" mailbox. And so on ๐Ÿ—‘๏ธ. There are two major interoperability problems with this practice:

  1. different clients may use different names for mailboxes with similar functions (such as "Trash" and "Deleted"), or may manage the same mailboxes in different ways, causing problems if a user switches between clients, and
  2. there is no guarantee that the server will allow the creation of the desired mailbox.
The client developer is, therefore, well advised to consider carefully the creation of any special-use mailboxes on the server. Further, the client must not require such mailbox creation. That is, if you do decide to do this, you must handle gracefully the failure of the CREATE command and behave reasonably when your special-use mailboxes do not exist and cannot be created ๐Ÿšจ.

In addition, the client developer should provide a convenient way for the user to select the names for any special-use mailboxes. This lets the user make these names the same in all clients used and put them wherever the user wants them ๐Ÿ’–.

3.4.9. Reference Names in the LIST Command โœจ

okay so this one confuses EVERYONE, both client and server devs, and I totally get why ๐Ÿ˜ญ The reference name is meant to work like a cd (change directory) command on Unix, PC DOS, Windows, and OS/2. The mailbox name gets read the same way a filename would if you'd already cd'd into the directory named by the reference. Like in Unix:

> cd /u/jones/junk
> vi banana        [file is "/u/jones/junk/banana"]
> vi stuff/banana  [file is "/u/jones/junk/stuff/banana"]
> vi /etc/hosts    [file is "/etc/hosts"]

bestie, the problems have been messy ๐Ÿ’€ First, some IMAP servers are built on Unix or PC file systems, but lots of others aren't, and file system rules just don't make sense for them. Second, some servers show the underlying file system to clients, while others only let you touch your personal mailboxes or some other limited set of files, so file-system-style semantics mean less. Third, the IMAP spec says the reference name is "implementation-dependent," so server implementations ended up handling it in wildly different ways ๐Ÿ™ƒ

These recommendations come from a lot of real operational experience, and the goal is to maximize interoperability ๐Ÿ’…

Server implementations must implement the reference argument in a way that matches the intended "change directory" operation as closely as possible. As a minimum, the reference argument may be prepended to the mailbox name (while suppressing double delimiters; see the next paragraph). Even servers that don't offer a way to break out of the current hierarchy (see "breakout facility" below) must provide a reasonable implementation of the reference argument, as described here, so that they will interoperate with clients that use it ๐Ÿซถ

Servers that prepend the reference argument to the mailbox name should insert a hierarchy delimiter between them, and must not insert a second one if one is already present:

C: A001 LIST ABC DEF
S: * LIST () "/" ABC/DEF   <=== should do this
S: A001 OK done

C: A002 LIST ABC/ /DEF
S: * LIST () "/" ABC//DEF     <=== must not do this
S: A002 OK done

On the client side, the reference argument is mainly used to build a "breakout facility," which lets the user directly access a mailbox outside the "current directory" hierarchy ๐Ÿฆ‹ Client implementations should have an operational mode that doesn't use the reference argument. That's so they can interoperate with older servers that didn't implement the reference argument properly. Giving users a breakout facility is a great idea, but clients that don't plan to offer one should not use the reference argument at all โœจ

Client implementations should always put a trailing hierarchy delimiter on the reference argument. Why? Some servers prepend the reference argument to the mailbox name without inserting a delimiter, while others do insert one if it isn't already there. A client that adds the delimiter will work with both kinds of server, which is so clean ๐Ÿงš

Client implementations that include a breakout facility should let the user choose whether or not to use a leading hierarchy delimiter on the mailbox argument. The reason is that handling a leading delimiter also varies from server to server, and even between different mailstores on the same server ๐Ÿ™ˆ On some servers, a leading hierarchy delimiter means "discard the reference argument" (which is the intended breakout facility), like this:

C: A001 LIST ABC/ /DEF
S: * LIST () "/" /DEF
S: A001 OK done

On other servers, the two get catenated and the extra delimiter is thrown away, like this:

C: A001 LIST ABC/ /DEF
S: * LIST () "/" ABC/DEF
S: A001 OK done

Client implementations must not assume the server supports a breakout facility, but they may give the user a way to use one if it's available. Any breakout facility should be exported to the user interface. Also, there may be other "breakout" characters besides the hierarchy delimiter (UNIX filesystem servers are likely to use a leading "~", for instance), and how those get interpreted is server-dependent ๐Ÿ‘‘

3.4.10. Mailbox Hierarchy Delimiters ๐ŸŒˆ

Picking the hierarchy delimiter is a tricky decision for a server, with several things to juggle. What characters do users expect to see? What characters can they type in if the delimiter needs to be entered by the user (or is required to be)? And what character can be used as the delimiter, given that the chosen character can't be used anywhere else in a mailbox name? ๐Ÿคฏ

Some interfaces show users the hierarchy delimiters or let them type qualified mailbox names that include them, so server implementations should use delimiter characters that users generally expect to see as name separators. The most common ones are "/" (as in Unix file names), "" (as in OS/2 and Windows file names), and "." (as in news groups). There isn't much to choose between these apart from what users might expect or what the underlying file system (if there is one) dictates. One thing to keep in mind about "" is that it's also a special character in the IMAP protocol ๐Ÿ‘€ Other hierarchy delimiter characters are permissible, but A DESIGNER IS WELL ADVISED TO STAY WITH ONE FROM THIS SET unless the server is intended for special purposes only. Implementers might be tempted by characters like "-", "_", ";", "&", "#", "@", and "!", but they should think about the surprise to the user, and about the effect on URLs and other external specifications (since some of these characters have special meanings there) ๐Ÿ˜ฌ

Also, a server that uses "" (and the clients of such a server) must remember to escape that character in quoted strings or to send literals instead. Literals are recommended over escaped characters in quoted strings to stay compatible with older IMAP versions that didn't allow escaped characters in quoted strings (but check the grammar to see where literals are allowed) ๐ŸŽ€

C: 001 LIST "" {13}
S: + send literal
C: this\%\%\%\h*
S: * LIST () "\\" {27}
S: this\is\a\mailbox\hierarchy
S: 001 OK LIST complete

In any case, a server should not use normal alphanumeric characters (like "X" or "0") as delimiters. A user would be SO surprised to find out that "EXPENDITURES" was actually a two-level hierarchy ๐Ÿ’€ A server also shouldn't use characters that are non-printable, or that are difficult or impossible to type on a standard US keyboard. Control characters, box-drawing characters, and characters from non-US alphabets all fall into that bucket. Using them causes interoperability problems that are best avoided ๐Ÿ™…โ€โ™€๏ธ

The UTF-7 encoding of mailbox names raises its own question: what happens to the hierarchy delimiters in encoded names? Do we encode each level and separate them with delimiters, or do we encode the whole fully qualified name, delimiters and all? For IMAP, the answer is the former: encode each hierarchy level separately, and insert delimiters between them. This makes it especially important not to pick a hierarchy delimiter that could be confused with IMAP's modified UTF-7 [UTF-7 and RFC-2060] encoding โญ

To repeat: a server should use "/", "", or "." as its hierarchy delimiter. Using any other character is likely to cause problems and is STRONGLY DISCOURAGED ๐Ÿšซ

3.4.11. ALERT Response Codes ๐Ÿšจ

The protocol spec is super clear about what to do with ALERT response codes, but lots of clients break the rule anyway, so it needs saying again. The spec says: "The human-readable text contains a special alert that must be presented to the user in a fashion that calls the user's attention to the message." That should be clear enough, but I'm going to repeat it: Clients must present ALERT text clearly to the user ๐Ÿ“ฃ

3.4.12. Deleting Mailboxes ๐Ÿ—‘๏ธ

The protocol doesn't guarantee that a client can delete a mailbox that isn't empty. On some servers it's allowed, and it's actually way faster than the alternative of deleting all the messages from the client ๐Ÿƒโ€โ™€๏ธ If the client wants to take advantage of this, it must be ready to fall back on the other method in the event that the faster one fails. Also, a client should not try to delete the mailbox it has selected. It should close that mailbox first, because some servers don't permit deleting the selected mailbox ๐Ÿ™…โ€โ™€๏ธ

That said, a server should permit the deletion of a non-empty mailbox. There's little reason to hand that work off to the client. Plus, forbidding it would stop someone from deleting a mailbox that for some reason can't be opened or expunged, and that could lead to denial-of-service problems ๐Ÿ˜ค

Here's an example:

[User tells the client to delete mailbox BANANA, which is
currently selected...]
C: 008 CLOSE
S: 008 OK done
C: 009 DELETE BANANA
S: 009 NO Delete failed; mailbox is not empty.
C: 010 SELECT BANANA
S: * ... untagged SELECT responses
S: 010 OK done
C: 011 STORE 1:* +FLAGS.SILENT \DELETED
S: 011 OK done
C: 012 CLOSE
S: 012 OK done
C: 013 DELETE BANANA
S: 013 OK done

3.5. A Word About Testing ๐Ÿงช

Since the whole point of IMAP is interoperability, and interoperability can't be tested in a vacuum, the final recommendation of this treatise is, "Test against EVERYTHING." ๐Ÿ’… Test your client against every server you can get an account on. Test your server with every client you can get your hands on. Lots of clients offer limited test versions on the Web for downloading. Plenty of server owners will give serious client developers guest accounts for testing, so contact them and ask ๐Ÿ™Œ NEVER assume that because your client works with one or two servers, or because your server does fine with one or two clients, you'll interoperate well in general ๐Ÿ˜ญ

Also, in addition to everything else, be sure to test against the reference implementations: the PINE client, the University of Washington server, and the Cyrus server ๐Ÿฆ‹

For more info, check out these URLs:

4. Security Considerations ๐Ÿ”

This document describes the behaviour of clients and servers that use the IMAP4 protocol, so it has the same security considerations as described in [RFC-2060]. Those considerations are no joke, so take them seriously ๐Ÿฅบ๐Ÿ”ฅ

5. References ๐Ÿ“š

okay so this is the bibliography bit, and it's giving librarian realness ๐Ÿ“š๐Ÿ’… every source the doc leans on gets listed here with all its details, no skipping, bestie

[RFC-2060] Crispin, M., "Internet Message Access Protocol - Version 4rev1", RFC 2060, December 1996. ๐Ÿฆ‹

[RFC-2119] Bradner, S., "Key words for use in RFCs to Indicate Requirement Levels", BCP 14, RFC 2119, March 1997. ๐Ÿ’œ this one is the BCP 14 key words thing, the reason the capital MUSTs and SHOULDs mean what they mean ๐Ÿ”ฅ

[RFC-2180] Gahrns, M., "IMAP4 Multi-Accessed Mailbox Practice", RFC 2180, July 1997. ๐ŸŒธ

[UTF-8] Yergeau, F., " UTF-8, a transformation format of Unicode and ISO 10646", RFC 2044, October 1996. ๐ŸŒˆ note the little extra space before UTF-8 in the title, that's just how the original spelled it โœจ

[UTF-7] Goldsmith, D. and M. Davis, "UTF-7, a Mail-Safe Transformation Format of Unicode", RFC 2152, May 1997. ๐Ÿงš

[NAMESPACE] Gahrns, M. and C. Newman, "IMAP4 Namespace", Work in Progress. ๐Ÿ“ this one's still a draft, so no RFC number yet, iykyk ๐Ÿ™ˆ

6. Author's Address ๐ŸŽ€

Barry Leiba IBM T.J. Watson Research Center 30 Saw Mill River Road Hawthorne, NY 10532

Phone: 1-914-784-7941 EMail: leiba@watson.ibm.com

Barry's the author who signed off on this one, so if you ever need to reach out about it, these are the details, periodt ๐Ÿ’–

Copyright (C) The Internet Society (1999). All Rights Reserved.

This document and translations of it may be copied and furnished to others, and derivative works that comment on or otherwise explain it or assist in its implementation may be prepared, copied, published and distributed, in whole or in part, without restriction of any kind, provided that the above copyright notice and this paragraph are included on all such copies and derivative works. However, this document itself may not be modified in any way, such as by removing the copyright notice or references to the Internet Society or other Internet organizations, except as needed for the purpose of developing Internet standards in which case the procedures for copyrights defined in the Internet Standards process must be followed, or as required to translate it into languages other than English.

The limited permissions granted above are perpetual and will not be revoked by the Internet Society or its successors or assigns.

This document and the information contained herein is provided on an "AS IS" basis and THE INTERNET SOCIETY AND THE INTERNET ENGINEERING TASK FORCE DISCLAIMS ALL WARRANTIES, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO ANY WARRANTY THAT THE USE OF THE INFORMATION HEREIN WILL NOT INFRINGE ANY RIGHTS OR ANY IMPLIED WARRANTIES OF MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE.


Acknowledgement ๐Ÿซถ

Funding for the RFC Editor function is currently provided by the Internet Society. ๐Ÿ’…

๐Ÿ“ฆ where this page comes from