Listing Mailboxes

How to list mailboxes is one of the most confusing problems with IMAP. When you're implementing your solution, keep this in mind all the time:

This basically means that you should avoid using "*" LIST wildcard. Instead show only the mailboxes that user has expressed interest in. Most clients show mailboxes as a tree structure. Typically you begin by displaying only the toplevel mailboxes:

1 LIST "" %

If some of the mailboxes have children (see the children section below), get a list of them only after user has opened that hierarchy in the tree:

2 LIST "" work/%

Don't expand automatically the whole tree. That's even worse than executing LIST "" *.

LIST reply is very loosely defined. It may be very much out of order. It may even contain duplicates. Here's an example reply for LIST "" *:

* LIST (\UnMarked) "." ""
* LIST (\Marked) "." "foo"
* LIST () "." "baz"
* LIST (\UnMarked \NoSelect) "." "baz"
* LIST () "." "a.b.c"

Hierarchy separators

All the toplevel mailboxes in a namespace have the same separator. So a single LIST command can never return different separators, with the exception of INBOX which is a special case. INBOX exists in a namespace of its own, so it (and its children) may have a different separator than the rest of the mailboxes. You rarely see this though, except as a NIL separator for INBOX with UW-IMAP.

If you need to know the hierarchy separator, you should get it from a non-INBOX LIST reply if you've already done LIST. If you don't see any non-INBOX mailboxes or you don't need to do LIST for any other reason, you can get the separator for default namespace with:

1 LIST "" ""
* LIST (\Noselect) "/" ""
1 OK

If you want to get it for other namespaces, use:

1 LIST #shared/ ""
* LIST (\Noselect) "/" "#shared/"
1 OK

Some clients cache the hierarchy separator forever. This has problems if the server configuration is changed (e.g. server software changed). Try to avoid this problem.

Mailbox separator can also be backslash ('\') character. Make sure you use it correctly:

1 LIST "" "%\\%"
* LIST () "\\" "hello\\world"
1 OK
2 SELECT "hello\\world"

Mailbox names

Mailbox names are in modified UTF-7 format as specific by the IMAP RFC. Display and create mailboxes using UTF-7. However existing mailbox names might already be wrong, so try not to break if you see 8bit characters. You should try to show them as UTF-8 (future IMAP RFCs might move to using UTF-8), or if the name isn't valid UTF-8 show them any way you want.

When parsing the LIST replies, remember that mailbox names may also be literals. This is perfectly legal:

1 list "" %
* LIST () "/" {7}
1 OK


If server capabilities contain CHILDREN or LIST-EXTENDED, you might see \HasChildren and \HasNoChildren flags in LIST replies. It's not required however that these are listed unless you explicitly request them with LIST-EXTENDED. So if don't see either of them, you can't assume anything about its children state. Note that \NoInferiors implies \HasNoChildren.

If you don't know the children state, there's a simple way to find out. Try to list its children to see if it returns anything:

1 LIST "" box/%

If you see any replies, it has children, otherwise it doesn't. Note that mailbox names may also contain "%" and "*" characters. Doing the above LIST command for a mailbox named "*" wouldn't be very nice, so you should replace "*" with "%" in mailbox names when LISTing them:

1 LIST "" %
* LIST () "/" INBOX
* LIST () "/" "*foo"
1 OK
2 LIST "" "%foo/%"
* LIST () "/" "*foo/child"
2 OK

If you want to know children status for all root mailboxes and the children flags weren't returned for LIST "" %, you can use:

1 LIST "" %/%

If server supports LIST-EXTENDED, you can force it to return children flags:



If server advertises NAMESPACE extension, you should show all the namespaces. However don't list their contents unless user explicitly opens the namespace. For example an initial mailbox tree view could look something like:

Only if user expands #shared or #news you should try to list their contents. You might even allow users to hide some namespaces entirely. For example UW-IMAP exports different mailbox drivers as namespaces, so if user isn't interested of using them, they're just taking extra space on screen.

Some servers list namespace prefixes as part of mailboxes in the default namespace, as well as allow a single LIST command to span across multiple namespaces. This is because many clients don't support namespaces, so this makes the non-default namespaces visible for such clients. This however isn't a preferred server behavior, so your client shouldn't rely on this, but your client shouldn't get confused either if it sees LIST reply with a namespace prefix.

A server that doesn't show namespace prefixes with LIST:

* NAMESPACE (("" "/")) NIL (("#public/" "/"))
1 OK
2 LIST "" %
* LIST () "/" INBOX
2 OK

A server that does show namespace prefixes with LIST:

* NAMESPACE (("" "/")) NIL (("Public mailboxes/" "/"))
1 OK
2 LIST "" %
* LIST () "/" INBOX
* LIST (\NoSelect) "/" "Public mailboxes"
2 OK

In the latter case you could just ignore the returned "Public mailboxes" LIST reply. However if it doesn't have a \NoSelect flag, it's possible that such mailbox really does exist in the default namespace. Its children would then exist in the "Public mailboxes" namespace.


Subscriptions are meant to be used as some kind of bookmarks for mailboxes. If your server had a million mailboxes, the user would probably want to know only about a few of them. User would subscribe those few ones and the client would display only them as the mailbox list in normal operation.

Some clients subscribe automatically to all mailboxes when logging in for the first time. This is the worst kind of subscription abuse there is. Never subscribe to mailboxes you didn't create yourself. It's also questionable if you should subscribe to mailboxes you did create yourself. Your "create mailbox" user interface should perhaps have a checkbox "Subscribe this mailbox also".

You should handle subscription lists similarly to listing mailboxes with LIST, just instead of LIST use LSUB command. LIST-EXTENDED LIST command also supports listing subscriptions. Although it's not horribly bad to use "*" wildcard for LSUB, try to avoid it anyway. The user might still be subscribed to lots of mailboxes and it's a waste of bandwidth to list mailboxes which aren't visible.

User Interface

Many clients implement subscriptions by having a "Show only subscribed mailboxes" option in settings. Mailboxes can be subscribed and unsubscribed using a special subscriptions dialog. Although this works, it's not necessarily the best possible user interface. If you ever want to temporarily access an unsubscribed mailbox it takes a lot of work to temporarily subscribe and then unsubscribe again.

Another problem with subscriptions is that if they're lost from the server (e.g. server software replaced), users are in complete panic because they no longer see their mailboxes. A good user interface would prevent this panic by indicating in some way that there are unsubscribed mailboxes.

One possible user interface would allow easily switching between subscribed and all mailboxes. For example the UI could look like:

Where opening the last unsubscribed mailboxes would show all of the ones not already visible (with the number of such mailboxes). Or if there are no unsubscribed mailboxes, this entry simply wouldn't be visible.

Marked vs. Unmarked

LIST replies may contain \Marked and \UnMarked. The IMAP RFC specifies them as "interesting" and "uninteresting" mailboxes. \Marked mailboxes usually have a non-zero RECENT message count, and \UnMarked have a zero RECENT message count. This isn't necessarily true though.

None: ClientImplementation/MailboxList (last edited 2016-04-23 00:27:36 by 82-181-77-11)