Courier
This page has information about how to use Courier as an IMAP server. Courier also is an MTA, but I'm preferring Exim for that because it's the default MTA on Debian.
Debian packages
This Debian package should pull in all the necessary dependencies
courier-imap-ssl
Make sure that the following packages are on the dependency list:
courier-imap courier-authdaemon
Configuration
Files
courier configuration options are stored in
/etc/courier/imapd /etc/courier/imapd-ssl
Debconf configuration
Debconf asks only one question: "Create directories for web-based administration?"
courier-webadmin
requires that configuration is not kept as a single configuration file, but instead split into directories. I answer "no" to the Debconf question because I don't want to use courier-webadmin
. Also, "no" is already the default answer.
SSL/TLS
Basics
Courier's SSL configuration happens in
/etc/courier/imapd-ssl
IMAP over SSL (IMAPS) works through port 993, whereas TLS can be run over the normal port 143. For years on end I had to keep IMAPS working because I was using the SquirrelMail webmail client, which does not support the STARTTLS command. Fortunately in 2012 I was able to switch to the more modern Roundcube webmail client, which does not suffer the same limitation. So these days I completely disable port 993 (IMAPS):
IMAPDSSLSTART=NO
Instead, I enable TLS with this:
IMAPDSTARTTLS=YES
Notes:
- If necessary, both IMAPS and TLS can be run simultaneously.
- With IMAPS disabled, it's no longer necessary to start/stop
/etc/init.d/courier-imap-ssl
when the configuration changes. In fact, since Debian stretch running this init script yields an error if IMAPS is disabled (in Debian jessie and before the script didn't error out, it simply didn't do anything).
Last but not least, I don't want clear-text communication on port 143, so I restrict connections to TLS-only:
IMAP_TLS_REQUIRED=1
Certificates
IMAPS and TLS both require an X.509 certificate. When courier-imap-ssl
is installed, two self-signed certificates are automatically generated and configured. The certificates are located here:
/etc/courier/imapd.pem /etc/courier/pop3d.pem
If you want to use certificates that are not self-signed, but signed by a concrete Certificate Authority (e.g. Let's Encrypt, CAcert, or you run your own CA), you will want to replace the certificates that were automatically generated by the Debian package. More information about creating certificates and maintaining your own CA can be found on this wiki page.
In order to use your own certificate, you have to change the TLS_CERTFILE
option in /etc/courier/imapd-ssl
. For my "Let's Encrypt" setup I use the following:
TLS_CERTFILE=/etc/letsencrypt/live/herzbube.ch/courier.cert-and-key.unsecure
Important: Unfortunately the file referenced by TLS_CERTFILE
must contain both the certificate and the private key (presumably in that order). At the moment there is no way to configure Courier so that it takes the two pieces of information from two different files. After obtaining a new certificate from "Let's Encrypt", it is therefore necessary to manually stitch together the referenced file with the following commands. During automated renewal these commands are run by a Certbot deploy hook - see the LetsEncrypt page for details.
cd /etc/letsencrypt/live/herzbube.ch cat fullchain.pem privkey.pem >courier.cert-and-key.unsecure
Also important: Because it contains a private key, the file referenced by TLS_CERTFILE
must not be world-readable. The permissions on the file itself are not terribly important, more important is that the folder in which the file is located is not generally accessible.
root@pelargir:~# ls -ld /etc/letsencrypt/live/ drwx--x--- 8 root ssl-cert 4096 Jun 8 01:18 /etc/letsencrypt/live/
If the certificate is signed by a CA (i.e. not self-signed), Courier needs to be able to find the entire certificate chain from the immediate CA who made the signature up to a root certificate. The following configuration snippet tells Courier to look for trusted certificates, either inside a file (file must contain all certificates) or inside a directory (directory must contain the certificates, one per file and hashed using OpenSSL's c_rehash
script):
TLS_TRUSTCERTS=/etc/ssl/certs
Note: Courier logs any problems in this area to the syslog, so have a look in there if you suspect anything.
SNI
If the IMAP server is supposed to work for different domain names, the TLS extension SNI comes into play. The way how Courier implements this is:
- Set TLS_CERTFILE to a base path, e.g.
TLS_CERTFILE=/path/to/imap.key.unsecure
- The concrete certificates must then be stored in files that are formed by appending the domain name to the base path, e.g.
/path/to/imap.key.unsecure.imap.herzbube.ch
- Courier will look up the correct certificate based on the host name advertised during the TLS/SNI exchange
Note: I am not using this approach because I am offering IMAP only on one server, mail.herzbube.ch
.
Custom DH group file
With the advent of the Logjam attack, it has become important to have a DH group file with increased bit size (see Guide to Deploying Diffie-Hellman for TLS). Unfortunately, the Courier IMAP default file is only 768 bits, which is so low that modern clients (notably the iOS mail client app in iOS 9) will refuse to connect to the IMAP server. I have therefore created a new DH group file with 2048 bit that I keep in a shared location so that other services (e.g. Apache) can also use it. See the OpenSSL wiki page for instructions how to create the new file. Here is how to configure Courier to use the file:
TLS_DHPARAMS=/etc/ssl/private/dhparams-2048-bit.pem
Ports
The standard configuration of courier uses the the following ports:
- Port 143 for IMAP2
- Is used for connection by the squirrelmail package (see the SquirrelMail wiki page)
- May also be used for TLS connections
- Port 993 for IMAPS
- May be used as an alternative to TLS
- Port 1143 (or any other port) if
imapproxy
is used
Automatically purge trash folder
By default the trash folder of every user is, on login, purged of messages that have been moved there 7 days (or longer) ago. The setting that does this looks like this:
IMAP_EMPTYTRASH=Trash:7
I don't like this automatic behaviour, so I just disable the setting:
IMAP_EMPTYTRASH=
Mail folder
By default courier stores mail in the so-called Maildir format. This requires that every user has a folder in his or her home directory that corresponds to the Maildir conventions. This folder can be created with the following command:
maildirmake /home/<user>/Maildir
As seen in the above example, the name Maildir should be used, as this is the default name used by courier. The setting that defines the name of a user's mail folder is stored both in /etc/courier/imapd and /etc/courier-imapd-ssl:
MAILDIRPATH=Maildir
Maildir integration with the Debian MTA exim is described on the Exim wiki page.
Note: Newer versions of courier require that the Maildir folder's owner/group is set to the user/user's main group. After upgrading to 0.61.0, courier refused connections for a user whose Maildir folder's group was set to mail.
IMAP Authentication
Clients such as SquirrelMail that authenticate through IMAP actually use Courier's authdaemon (provided by the courier-authdaemon Debian package). This daemon supports several schemes how to authenticate users (e.g. through MySQL or LDAP). The default is to delegate authentication to PAM. See this file for the daemon configuration:
/etc/courier/authdaemonrc
The courier-imap package installs the PAM file
/etc/pam.d/imap
Because the content of this file looks like this:
@include common-auth @include common-account @include common-password @include common-session
The actual authentication method is dependent on the system-wide PAM default authentication method. If the common-* files are changed, for instance, to use pam_ldap instead of pam_unix, this not only sets the authentication method to LDAP for the system console or SSH login prompt, but also for all clients of Courier's authdaemon. Very neat!
See the PAM wiki page for details.
Web administration
Installation
In order to administrate courier via a web browser install the Debian package
courier-webadmin
Documentation can be found here
http://osgiliath/doc/courier-doc/htmldoc/install.html#webadmin
Debconf asks the question whether it should copy /usr/lib/courier/courier/webmail/webadmin to /usr/lib/cgi-bin/courierwebadmin and set the suid bit. I answer this question with "no" and instead create the following symlink:
ln -s /usr/lib/courier/courier/webmail/webadmin /usr/lib/cgi-bin/courierwebadmin.cgi
Note: The extension .cgi is important in my setup because I have configured Apache to recognize only files with this ending as CGI scripts. See section "CGI scripts" on the Apache wiki page for details.
Configuration
Configuration of the package is located in the directory
/etc/courier/webadmin
The password is stored in clear text in password, therefore this file has to be protected with minimal security:
chmod 400 /etc/courier/webadmin/password chown daemon:daemon /etc/courier/webadmin/password
By default courier-webadmin allows only https connections because the password is transmitted in clear text and is then stored in a cookie. This can be circumvented (although it is not recommended!) by saying
touch /etc/courier/webadmin/unsecureok
Usage
Whenever a change is made the link "Install new configuration" in the main menu of courier-webadmin must be clicked. This writes the changes to the configuration files and restarts the courier daemons.
Apple Mail
Apple Mail needs to be configured like this:
- Specify that the account uses SSL for authentication. Apple Mail now sets the port to the default IMAPS port 993. Override this and specify that the account uses port 143 to connect. This tells Apple Mail that it should use TLS to SSL-encrypt the session. I have not tested what happens if the IMAP daemon allows plain-text/non-TLS connections over port 143, but if the daemon requires TLS everything works out beautifully.
- Specify for all special folders that mail is to be stored on the server
- After you connect to the account for the first time, for each of the following special folders select the correct IMAP folder and choose the menu item "Postfach -> Dieses Postfach verwenden für -> <Special folder>". The goal here is to select the same folders that are also used by other IMAP clients, e.g. SquirrelMail or Roundcube.
- Inbox
- Trash
- Sent
- Drafts
- Delete any IMAP folders that Apple Mail has created on its own that are now no longer needed. For instance, Apple Mail will probably have created an IMAP folder "Sent Messages" to act as the special folder "Sent". This is now no longer needed and can be deleted.
IMAP proxy
Install the package
imapproxy
Configuration is located in
/etc/imapproxy.conf
Change the following option:
listen_port 1143
(or set any other port that suits you)
Update all clients (e.g. SquirrelMail, Apple Mail) that connect on the default IMAP port 143 so that they now connect to port 1143.
Managing Maildir folders
References
- The Maildir specs: http://cr.yp.to/proto/maildir.html
- Wikipedia article on the Maildir format: http://en.wikipedia.org/wiki/Maildir
Content of a Maildir folder
When I use a mail client to create a new mailbox folder, the Courier IMAP server creates a corresponding Maildir filesystem folder with the following layout:
osgiliath:/home/patrick/Maildir/.foo# ls -la total 32 drwx------ 6 patrick patrick 4096 Dec 22 16:01 . drwx------ 60 patrick mail 4096 Dec 22 16:03 .. -rw-r--r-- 1 patrick patrick 43 Dec 22 16:01 courierimapacl drwx------ 2 patrick patrick 4096 Dec 22 16:01 courierimapkeywords -rw-r--r-- 1 patrick patrick 86 Dec 22 16:03 courierimapuiddb drwx------ 2 patrick patrick 4096 Dec 22 16:03 cur -rw------- 1 patrick patrick 0 Dec 22 16:01 maildirfolder drwx------ 2 patrick patrick 4096 Dec 22 16:01 new drwx------ 2 patrick patrick 4096 Dec 22 16:03 tmp
The Wikipedia article on the Maildir format gives hints about some of the files and directories:
- The tmp directory is used during message delivery only
- Important: The Courier IMAP server requires that this directory is present. Courier refuses to open the mailbox if the directory is missing. Also see Missing tmp subfolders in the troubleshooting section further down.
- Message delivery places the new message in the new directory
- The mail user agent process finds messages in the new directory it moves them to cur, appending an informational suffix (see below for details)
The maildirfolder file always seems to present and empty. Googling for "maildirfolder" seems to confirm this, although the information cannot be seen as conclusive. Additionally, googled information tells us that the file is specific to Courier IMAP and not generally required by IMAP or the Maildir format.
The courierimap* files/directories obviously belong to the Courier IMAP server. It is difficult to get information about the meaning of those files/directories, but they must certainly be kept in mind when manipulating a Maildir folder, since they may contain metadata about messages being moved around:
- courierimapacl seems to contain folder-specific authorization information and has nothing to do with specific messages
- courierimapkeywords refers to messages, but seems to be populated only under certain (as yet unknown) circumstances; for instance, in a newly created folder with one seen message the directory is completely empty
- courierimapuiddb refers to messages; the file seems to always contain one more line than there are messages in the Maildir folder
- this thread seems to indicate that it is not necessary to update courierimapkeywords and courierimapuiddb even if messages are deleted from the Maildir folder
Looking into the cur directory after it contains a read message reveals the following content:
osgiliath:/home/patrick/Maildir/.foo# l cur total 12 drwx------ 2 patrick patrick 4096 Dec 22 16:03 . drwx------ 6 patrick patrick 4096 Dec 22 16:01 .. -rw-r--r-- 1 patrick patrick 900 Dec 22 16:03 1198335805.M980307P19715V0000000000000307I0007BCE6_0.osgiliath,S=900:2,S
Again, the Wikipedia article cited above helps with the file name format:
- The file name must, of course, be unique
- The algorithm to guarantee uniqueness combines the time, the host name, and a number of pseudo-random parameters
- The informational suffix consists of a colon (to separate the unique part of the filename from the actual information), a '2', a comma and various flags
- The '2' specifies the version of the information that follows the comma; '2' is the only currently officially specified version, '1' being an experimental version (probably used while the Maildir format was under development)
- Specified flags are "P", "R", "S", "T", "D" and "F"
The Maildir specs (http://cr.yp.to/proto/maildir.html) list the purpose of the flags:
- "P" = passed: the user has resent/forwarded/bounced this message to someone else
- "R" = replied: the user has replied to this message
- "S" = seen: the user has viewed this message
- "T" = trashed: the user has moved this message to the trash; the trash will be emptied by a later user action
- "D" = draft: the user considers this message a draft; toggled at user discretion
- "F" = flagged: user-defined flag; toggled at user discretion
- Flags must be stored in ASCII order: e.g., "2,FRS"
Adding messages to a Maildir from an external IMAP account
Summary
Goal: Download all mailboxes and messages from an external IMAP account, then add the data to a local Maildir folder that is accessed via Courier IMAP.
I selected the utility isync
for the task.
isync solution
Install Debian package
isync
The project/package name is "isync", but on the command line the tool to use is
mbsync --config /path/to/file
mbsync
will not run without a configuration file. If the --config
option is not specified, the default config file location is ~/.mbsyncrc
. The syntax of the configuration file is fully described in the mbsync
man page, but it's difficult to understand without an example. The best way to start probably is by making a copy of this sample file:
/usr/share/doc/isync/examples/mbsyncrc.sample
Concepts:
- Store
- A Store defines a collection of mailboxes; basically a folder, either local or remote.
- Channel
- A Channel connects two Stores, describing the way the two are synchronized.
- Account
- An Account describes the connection part of remote Stores, so a server connection can be shared between multiple Stores.
- Group
- A Group aggregates multiple Channels to save typing on the command line.
The following configuration file is suitable for fetching all mailboxes from a single IMAP account:
# ------------------------------------------------------------ # Global configuration section # Values here are used as defaults for any following Channel section that # doesn't specify them. # ------------------------------------------------------------ # Pull changes from master (remote) to slave (local), # All changes are pulled because we don't specify # any type flags (see man page) Sync Pull # Make sure that no messages are deleted Expunge None # Make sure that new mailboxes are automatically created, # but only on the slave. Since we Pull changes only, the # "slave-only" restriction is a bit pointless, but better # safe than sorry. Create Slave # Save all sync states in the directory specified here. # Because we specify a directory we must use a trailing slash (/) SyncState ./mbsyncstate/ # ------------------------------------------------------------ # Stores and channel # ------------------------------------------------------------ MaildirStore local-foo # Because we specify a directory we must use a trailing slash (/) Path ./foo/ # The location of the special mailbox INBOX. By default this # is placed in ~/Maildir, even though we specified "Path" Inbox ./foo/Maildir Trash Trash IMAPStore remote-foo Host imap.mail-ch.ch User someusername Pass secret UseIMAPS yes CertificateFile /etc/ssl/certs/ca-certificates.crt Channel foo Master :remote-foo: Slave :local-foo: # Synchronize all mailboxes. Without this, only INBOX is # synchronized. Pattern * CopyArrivalDate yes
The local folder that this creates must be converted into a format this is suitable for Courier IMAP. I am pretty sure this could be achieved by correctly configuring isync
, however I didn't have the endurance to deal with cryptic man page explanations - or maybe I just don't understand enough IMAP to make sense of those explanations. Anyway, I ended up with a little shell script that performs the necessary conversion. It basically does two things:
- Rename mailbox folders so that they start with a dot and have a common prefix
- Remove the file
.uidvalidity
that is added byisync
but which we don't need when the data is actually added to the finalMaildir
folder
Here is the script:
#!/bin/bash MYNAME="$(basename $0)" MAILBOX_FOLDER_PREFIX=".switchplus" if test $# -ne 1; then echo "Usage: $MYNAME /path/to/mbsync/folder" exit 1 fi MBSYNC_FOLDER="$(readlink --canonicalize-missing --no-newline "$1")" if test $? -ne 0; then echo "Error canonicalizing folder name $MBSYNC_FOLDER" exit 1 fi if test ! -d "$MBSYNC_FOLDER"; then echo "Folder not found $MBSYNC_FOLDER" exit 1 fi CONVERTED_FOLDER="$MBSYNC_FOLDER.converted" if test -d "$CONVERTED_FOLDER"; then echo "Deleted converted folder $CONVERTED_FOLDER" rm -rf "$CONVERTED_FOLDER" if test $? -ne 0; then echo "Error deleting converted folder" exit 1 fi fi mkdir -p "$CONVERTED_FOLDER" if test $? -ne 0; then echo "Error creating converted folder $CONVERTED FOLDER" exit 1 fi cd "$MBSYNC_FOLDER" if test $? -ne 0; then echo "Cannot change working directory to $MBSYNC_FOLDER" exit 1 fi for MAILBOX_FOLDER in *; do if test "$MAILBOX_FOLDER" = "Maildir"; then RENAMED_MAILBOX_FOLDER="$CONVERTED_FOLDER/$MAILBOX_FOLDER_PREFIX" else RENAMED_MAILBOX_FOLDER="$CONVERTED_FOLDER/$MAILBOX_FOLDER_PREFIX.$MAILBOX_FOLDER" fi cp -R "$MAILBOX_FOLDER" "$RENAMED_MAILBOX_FOLDER" if test $? -ne 0; then echo "Error copying mailbox folder $MAILBOX_FOLDER" exit 1 fi if test -f "$RENAMED_MAILBOX_FOLDER/.uidvalidity"; then rm "$RENAMED_MAILBOX_FOLDER/.uidvalidity" if test $? -ne 0; then echo "Error deleting .uidvalidity from $RENAMED_MAILBOX_FOLDER" exit 1 fi fi done echo "Conversion finished: $CONVERTED_FOLDER"
Here's a transcript of all commands that are required to download the data for one IMAP account:
# Setup environment mkdir mbsync cd mbsync vi mbsyncrc # add the configuration snippet above vi convert-to-courier.sh # add the conversion script from above chmod +x convert-to-courier.sh # Download data mkdir foo mbsync --config ./mbsyncrc foo # Massage data. Note: This creates a copy of the downloaded data, # so it may use a lot of diskspace! ./convert-to-courier.sh foo # Move massaged data to final Maildir chown -R localusername:localusergroup foo mv foo/.switchplus* /home/localusername/Maildir
Other IMAP utilities
Searching the package database provides a rather long list of utilities that have something to do with IMAP:
apt-cache search imap
I manually culled the list down to the following interesting looking utilities:
- imapcopy - IMAP backup, copy and migration tool
- Website = http://www.ardiehl.de/imapcopy/index.html
- Simple utility for one-time migration from one IMAP server to another.
- Last release at the time of writing is from June 2009
- isync - IMAP and MailDir mailbox synchronizer
- Website = http://isync.sourceforge.net/
- Synchronizes two IMAP mailboxes. A mailbox can be a Maildir or an IMAP server.
- Supports TLS and is fairly well maintained (at the time of writing the last release is from November 2015)
- larch - tool to copy messages from one IMAP server to another
- Website = https://github.com/rgrove/larch
- Officially unmaintained
- mailsync - Synchronize IMAP mailboxes
- Website = http://mailsync.sourceforge.net/
- Appears to be unmaintained, at the time of writing the last release is from June 2004
- offlineimap - IMAP/Maildir synchronization and reader support
- Website = https://github.com/OfflineIMAP/offlineimap
- Downloads messages from an IMAP server and stores them locally in Maildir format for viewing
- syncmaildir - Sync Mail Dir is a set of tools to synchronize Maildirs
- Website = http://syncmaildir.sourceforge.net/
- Does not work with an IMAP server, instead syncs two Maildirs via SSH
A few more tools that looked interesting, but I didn't look at them any closer
- archivemail - archive and compress or delete your old email
- fdm - fetching, filtering and delivering emails
- fetchmail - SSL enabled POP3, APOP, IMAP mail gatherer/forwarder
- getmail4 - mail retriever with support for POP3, IMAP4 and SDPS
- im - mail/news handling commands and Perl modules
- mailutils - GNU mailutils utilities for handling mail
Diagnostics
In case of trouble, it is difficult to find any useful diagnostic information, because the Courier daemons do not write any useful logfiles (a few things are written to syslog, but not nearly enough). This chapter provides information about diagnostics that I found useful in the past.
Testing TLS connection
This command performs a basic test to see whether or not Courier is set up correctly for TLS:
openssl s_client -connect mail.herzbube.ch:143 -starttls imap
Logging authentication problems
To diagnose authentication problems you can increase the amount of debug logging by changing the following setting in /etc/courier/authdaemonrc
DEBUG_LOGIN=
Manual IMAP session
Things that I have been able to find out about the IMAP dialog:
- IMAP commands are case insensitive. I'm not sure whether this is also true for mailbox names.
- IMAP commands begin with an arbitrary label. You can't just type "select inbox", you must prefix the command like this "mylabel select inbox". Apparently it is customary to use labels of the form "A<nnnn>", where nnnn is the number of the command within the IMAP session.
Authentication
- The configuration I use for Courier does not allow the "login" command, instead I must use the command "authenticate plain"
- This initiates the SASL PLAIN authentication mechanism, which is described in RFC 4616
- First you have to Base64-encode both username and password like this:
echo -en "\0username\0secret" | base64
- The IMAP session snippet then looks like this:
a0001 authenticate plain + AHVzZXJuYW1lAHNlY3JldA== a0001 OK LOGIN Ok.
- This StackOverflow answer explains how SASL PLAIN works in IMAP
Connect to the IMAP server
- Without TLS:
telnet mail.herzbube.ch 143
- With TLS
openssl s_client -connect mail.herzbube.ch:143 -starttls imap
Once connected to the server, here is a simple list of commands that you can send to the server. Server responses are not shown. The session uses SASL PLAIN for authentication (see above for details), selects the main mailbox, retrieves message 12 and then logs out.
a0001 authenticate plain + AHVzZXJuYW1lAHNlY3JldA== a0002 select inbox a0003 fetch 12 full a0005 logout
This Courier tutorial page has a few additional IMAP commands that you can try out.
Network traffic sniffing
As a last resort, you can use Wireshark to observe network traffic details. This only works if you don't use TLS.
tshark -i lo -w capture_file -S -f "src or dst port 143"
Troubleshooting
Permissions on Maildir folder
The Maildir folder in a user's home directory must have the following permissions, otherwise courier drops the connection immediately after a successful login:
osgiliath:~# ls -ld /home/patrick/Maildir drwx------ 55 patrick patrick 4096 Aug 12 01:06 /home/patrick/Maildir
Missing tmp subfolders
Every mailbox must have a tmp
folder. Courier refuses to access a mailbox if that folder is missing. The error message Courier returns varies with the IMAP command you use. For instance:
[...] 6 examine INBOX.Sent 6 NO Unable to open this mailbox. 7 status INBOX.Sent (messages unseen) 7 NO [ALERT] STATUS failed 8 select INBOX.Sent 8 NO Unable to open this mailbox.
Here is a listing of a correctly set up mailbox folder
drwx------ 6 patrick patrick 4096 Jul 12 03:33 . drwx------ 73 patrick patrick 4096 Jul 12 01:10 .. -rw-r--r-- 1 patrick patrick 17 Jul 10 20:21 courierimapacl drwx------ 2 patrick patrick 4096 Jul 12 03:31 courierimapkeywords -rw-r--r-- 1 patrick patrick 47290 Jul 10 20:21 courierimapuiddb drwx------ 2 patrick patrick 77824 Jul 10 20:21 cur -rw-r--r-- 1 patrick patrick 0 Jul 10 20:21 maildirfolder drwx------ 2 patrick patrick 4096 Jul 12 03:31 new drwx------ 2 patrick patrick 4096 Jul 12 03:31 tmp
Here is a nice shell script (adapted from here) that fixes all mailboxes inside a single Maildir:
root@pelargir:~# cat /tmp/fix-maildir.sh #!/bin/bash if test $# -ne 1; then echo "Usage: $(basename $0) /path/to/Maildir" exit 1 fi M="$1" if test ! -d "$M"; then echo "Maildir does not exist: $M" exit 1 fi echo checking $M for d in cur new tmp ; do [ -d "$M/$d" ] || { echo "* Creating $M/$d"; mkdir "$M/$d"; } chown -c --reference "$M" "$M/$d" chmod -c 700 "$M/$d" done find $M -type f -name maildirfolder | while read ; do f=`dirname "$REPLY"` echo " checking $f" for d in cur new tmp ; do [ -d "$f/$d" ] || { echo " * Creating $f/$d"; mkdir "$f/$d"; } chown -c --reference "$f" "$f/$d" chmod -c 700 "$f/$d" done done
IMAP operations timeout
Sometimes, when I attempt to do something in SquirrelMail that affects a lot of messages, I get an error message that looks like this:
ERROR: Connection dropped by IMAP server. Query: COPY 4181,5001:5135,5396,5434,5446,5491,5499,5506,5514,5522,5531,5539,5547,5555,5565,5633,5654,5756,5783,5791,5821,5830:5831,5859:5862,5864:5866,5919 "INBOX.Trash"
In the example above, I tried to delete the last 167 messages from a folder that contains 6167 messages. The end result of the operation was:
- The messages were placed into
.Trash/cur
- The messages were not deleted from
.Junk.ham
The error message refers to a query named "COPY". This prompted me to have a look at RFC 3501 (http://tools.ietf.org/html/rfc3501), the IMAP4rev1 specification. I noticed that the specs do not contain a "MOVE" command. I conclude that in order to implement a move operation, an IMAP client such as SquirrelMail needs to translate the operation into 2 IMAP commands: First a COPY, second a DELETE command. The observed manner of failure of the operation supports this conclusion and suggests the following order of events:
- SquirrelMail initiates the COPY command
- The IMAP server process starts to process the command, but takes a long time
- SquirrelMail times out and displays the error message
- The IMAP server process continues to process the command until it finishes, but never receives the "DELETE" command from SquirrelMail
- The end result displayed by SquirrelMail are the copied messages in the Trash, but the originals still in place in the source folder
So the all-important question is: Why does the IMAP server process take so long to process the COPY command? Too much load on the system? Not enough disk space? Not enough memory?
Things that I have tried without success:
- At first I assumed that imapproxyd had something to do with the problem, but stopping that daemon does not resolve the issue
- Stopping boinc to give imapd all the available processor power also does not help (which seems logical after top revealed that the imapd process does not use any processing power at all)
- Checking the /home filesystem + optimizing the filesystem for directories with many files did not help anything, either
tune2fs -O dir_index /dev/hda7 e2fsck -D /dev/hda7
- Run a manual IMAP session without SquirrelMail as the intermediate to check whether or not SquirrelMail somehow plays a role. Except for the fact that it times out, SquirrelMail cannot be blamed, though: In both sessions copying 167 mails takes about the same time (3 minutes)
Let's watch the system while we repeat the operation from above:
- CPU activity
- top shows that the operation spawns an imapd process running as user "patrick" (the user logged in to SquirrelMail)
- After an initial burst, the imapd process no longer displays any noticeable CPU activity; the other Courier processes never show any activity at all
- top -u patrick continuously displays the imapd process at 0.0% CPU activity, i.e. no CPU activity at all
- The imapd process continues to run long after SquirrelMail reports its "Connection dropped by IMAP server" error; this supports the assumed order of events from further up
- File activity
- Monitoring .Trash/tmp by repeatedly running "ls -l" reveals that the imapd process continuously places files into this directory until it has created files for all the messages requested to be moved
- lsof -r 2 -c imapd lists the open files of the imapd process every 2 seconds. The result shows that the imapd daemon reads a new file from the Junk.ham folder about every 2 seconds. The only variation between samples is the file being read. Sample output:
COMMAND PID USER FD TYPE DEVICE SIZE NODE NAME imapd 7504 patrick cwd DIR 3,7 4096 474209 /home/patrick/Maildir imapd 7504 patrick rtd DIR 3,3 4096 2 / imapd 7504 patrick txt REG 3,5 1297640 33099 /usr/bin/imapd imapd 7504 patrick mem REG 0,0 0 [heap] (stat: No such file or directory) imapd 7504 patrick mem REG 3,5 928628 359813 /usr/lib/libdb-4.3.so imapd 7504 patrick mem REG 3,3 38412 211935 /lib/libnss_files-2.7.so imapd 7504 patrick mem REG 3,5 16540 359921 /usr/lib/libnss_db-2.2.3.so imapd 7504 patrick mem REG 3,3 41876 211863 /lib/libgcc_s.so.1 imapd 7504 patrick mem REG 3,3 149328 211893 /lib/libm-2.7.so imapd 7504 patrick mem REG 3,5 937800 360104 /usr/lib/libstdc++.so.6.0.9 imapd 7504 patrick mem REG 3,3 1356012 211875 /lib/libc-2.7.so imapd 7504 patrick mem REG 3,3 38300 211887 /lib/libcrypt-2.7.so imapd 7504 patrick mem REG 3,5 37232 572333 /usr/lib/courier-authlib/libcourierauth.so.0.0.0 imapd 7504 patrick mem REG 3,5 19940 359983 /usr/lib/libgdbm.so.3.0.0 imapd 7504 patrick mem REG 3,5 30868 360024 /usr/lib/libfam.so.0.0.0 imapd 7504 patrick mem REG 3,3 117344 211806 /lib/ld-2.7.so imapd 7504 patrick 0u IPv6 20663 TCP osgiliath.herzbube.ch:imap2->osgiliath.herzbube.ch:35449 (ESTABLISHED) imapd 7504 patrick 1u IPv6 20663 TCP osgiliath.herzbube.ch:imap2->osgiliath.herzbube.ch:35449 (ESTABLISHED) imapd 7504 patrick 2w FIFO 0,5 1797 pipe imapd 7504 patrick 3u unix 0xd79e9b20 20664 socket imapd 7504 patrick 4w FIFO 0,5 1795 pipe imapd 7504 patrick 5r REG 3,7 10242 531752 /home/patrick/Maildir/.Junk.ham/cur/1167674801.M935872P1602V0000000000000307I00081D28_5012.osgiliath,S=10242:2,S imapd 7504 patrick 6u unix 0xd79e96a0 20680 socket
- Log activity
- No activities in any log files by any IMAP/courier process can be detected
The monitoring activities above confirm some of the facts we already know, but otherwise they provide no real clues. Another attempt: Try to delete the last 314 messages from a different folder than the one I have been exercising so far. The new folder contains 6814 messages. Result: The operation completes blazingly fast in about 5 seconds! Conclusions:
- It cannot be the folder size that causes imapd to run so slow
- Or at least it's not the folder size alone
- The destination folder (Trash) does not affect the outcome of the test
Let's look at the differences between the two folders and hope we get some clues:
osgiliath:/home/patrick/Maildir# ls -la .Junk .Junk.ham .Junk: total 1160 drwx------ 6 patrick patrick 4096 Oct 26 00:25 . drwx------ 60 patrick mail 4096 Dec 22 16:03 .. -rw-r--r-- 1 patrick patrick 43 Oct 26 00:24 courierimapacl drwx------ 2 patrick patrick 32768 Dec 22 21:42 courierimapkeywords -rw-r--r-- 1 patrick patrick 343640 Dec 22 21:25 courierimapuiddb drwx------ 2 patrick patrick 774144 Dec 22 21:42 cur -rw------- 1 patrick patrick 0 Oct 26 00:24 maildirfolder drwx------ 2 patrick patrick 4096 Dec 22 21:45 new drwx------ 2 patrick patrick 4096 Dec 22 21:45 tmp .Junk.ham: total 1024 drwx------ 6 patrick patrick 4096 Oct 26 00:38 . drwx------ 60 patrick mail 4096 Dec 22 16:03 .. -rw-r--r-- 1 patrick patrick 17 Jan 1 2007 courierimapacl drwx------ 2 patrick patrick 4096 Dec 22 14:54 courierimapkeywords -rw-r--r-- 1 patrick patrick 471777 Dec 22 15:19 courierimapuiddb drwx------ 2 patrick patrick 532480 Dec 22 15:19 cur -rw------- 1 patrick patrick 0 Jan 1 2007 maildirfolder drwx------ 2 patrick patrick 4096 Jan 4 2007 new drwx------ 2 patrick patrick 4096 Dec 22 21:42 tmp
Hm, there is a difference in size between the courierimapacl files. Let's look at their content:
osgiliath:/home/patrick/Maildir# cat .Junk/courierimapacl owner aceilrstwx administrators aceilrstwx osgiliath:/home/patrick/Maildir# cat .Junk.ham/courierimapacl owner aceilrstwx
I have no idea why one file contains an additional "administrators" line. Another attempt with the 2 files being the same does not help anything. Another observation is that the courierimapkeywords directories are not of the same size. Comparing their content:
osgiliath:/home/patrick/Maildir# ls -la .Junk/courierimapkeywords .Junk.ham/courierimapkeywords/ .Junk.ham/courierimapkeywords/: total 452 drwx------ 2 patrick patrick 4096 Dec 22 14:54 . drwx------ 6 patrick patrick 4096 Dec 22 22:04 .. -rw-r--r-- 1 patrick patrick 446431 Dec 22 15:19 :list .Junk/courierimapkeywords: total 40 drwx------ 2 patrick patrick 32768 Dec 22 21:42 . drwx------ 6 patrick patrick 4096 Oct 26 00:25 ..
I have learned elsewhere (can't remember the link to the resource) that keywords are not really crucial, so I boldly remove the :list file and make another attempt - Lo and behold! the damn thing suddenly works!!!