RFC 2683
IMAP4 Implementation Recommendations
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 Notice
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:
- you must handle gracefully the failure of a SELECT command if the server refuses the second SELECT,
- 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,
- you must avoid making multiple connections to the same mailbox in your own client (for load balancing or other such reasons), and
- 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
\Noselectflag set. - Do not try to CREATE a sub-mailbox in a mailbox that has the
\Noinferiorsflag 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:
- 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
- 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:
- IMAP Products and Sources:
http://www.imap.org/products.html - IMC MailConnect:
http://www.imc.org/imc-mailconnect
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 ๐
7. Full Copyright Statement โญ
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
- ietf: rfc2683 1999-09
- ๐ girlified by claude-haiku-5-5 on : a language model's rewrite of the original, under its terms