2024-06-21
The IMAP LIST command as it interacts with client prefixes in Dovecot
Good IMAP clients will support the notion of a prefix the client puts on IMAP paths under some name. When I've written about this in the past (cf) I've been abstract about how it worked at the level of IMAP commands, and in particular at the level of the IMAP LIST command, which lists (some of) your folders and mailboxes. The IMAP LIST command is special here because it has two basic arguments, which in RFC 9051 are vaguely described as 'the reference name' and 'the mailbox name with possible wildcards'. This probably makes sense to IMAP experts who understand the difference, but for the rest of us it gets a bit confusing.
(The reason it's confusing is that other IMAP commands involving mailboxes (such as 'SELECT') only have a single argument, and also LIST reports folders and mailboxes as single arguments. This makes it a bit mysterious why LIST has two basic arguments, and how you're supposed to ask for things like 'please list all folders under X'. Or, if you're a system administrator reading Dovecot event logs, it makes it hard to know if a client is behaving badly or is just unusual.)
In particular, you might ask where an IMAP client puts its client
prefix in a LIST command. The answer is that it depends on the
IMAP client, as we discovered recently during some testing. If the
client prefix is 'IMail/
' and the client wants to know all of
your folders and mailboxes, some clients will send:
x LIST "IMail/" "*"
Other IMAP clients will send:
x LIST "" "IMail/*"
As I have experimentally verified, Dovecot 2.3.16 will accept
wildcards in either LIST
argument, although this may not be
something RFC 9051
requires. In a basic LIST syntax (the two-argument form I've given
above), a second argument of "" has a special purpose and needs to
be avoided (unless you want the information it provides). On Dovecot,
you can write 'LIST "IMail/*" "%"
' if you want to put all the
heavy wildcard lifting into the first argument.
(Dovecot will let you play special tricks this way. Suppose that
you want to find a mailbox called 'Barney' and you know it's somewhere
in your mail hierarchy; then you can ask for 'LIST "*" "Barney"
'
and get just it. I suspect no actual IMAP clients attempt to do
this.)
In our logs, we see recursively wildcarded IMAP LIST commands (ie,
ones using the '*' wildcard operator) with a first argument
that both includes and omits a trailing slash, that is we see clients
generate both 'LIST "mail" "*"
' and 'LIST "mail/" "*"
'. For
the recursive wildcard I think this gets you the same result, but
there is a difference between them when you use '%':
a LIST "Imap-List-Test" "%" * LIST (\Noselect \HasChildren) "/" Imap-List-Test a OK List completed (0.001 + 0.000 secs). a LIST "Imap-List-Test/" "%" * LIST (\Noselect \HasChildren) "/" Imap-List-Test/One a OK List completed (0.001 + 0.000 secs).
Given this, if I was writing an IMAP client program that used LIST and had a non-blank first argument, I would always put the trailing slash on (technically I think this is the folder separator, which doesn't have to be '/' but always is for us).
(I'm not going to write an actual mail reader, but I do sometimes need to write IMAP tests and similar automated things.)
PS: I'm sure that this is all familiar ground to IMAP mavens but we dip into this area only occasionally and I want to write this down for future use before it falls out of my head again.
(We're currently looking at IMAP client prefixes and how clients handle them for reasons well outside the scope of this entry.)