Maildir and qmail-pop3d worksheet

For scalability, we are going to arrange for exim to deliver all local mail in Maildir format. This creates a subdirectory called "Maildir" in the user's home directory, which in turn contains three subdirectories: new, cur and tmp. Messages are written into tmp, moved to new when delivery is complete, and moved to cur when read. Each message has a long filename based on the hostname and the time of day.

Because each message is stored in a separate file, it is much faster for the pop3 daemon to start up every time a user connects. It also allows for safe delivery onto a shared (NFS) disk backend.

Remember: when creating new "E-mail" accounts on your system, you probably don't want your users to actually be able to login to Unix using ssh or telnet. To disable this, create their accounts with a nonexistent shell.

# pw useradd username -m -s /nonexistent

1. Reconfigure exim for Maildir local delivery

Edit /usr/exim/configure, find the local_delivery transport and modify it as follows:

local_delivery:
  driver = appendfile
  directory = $home/Maildir
  maildir_format
  delivery_date_add
  envelope_to_add
  return_path_add
# group = mail
# mode = 0660

Optionally you could add further parameters to this transport which let you impose quotas on your users, for example to limit all users to 10 megabytes of storage each:

  maildir_tag = ,S=$message_size
  quota_size_regex = ,S=(\d+)
  quota = 10M
  quota_warn_threshold = 90%

Remember to HUP your exim daemon. Now test out your new configuration by delivering to some local account on your machine:

$ /usr/exim/bin/exim -bt localuser
localuser@hostnn.t1.ws.afnog.org
  router = localuser, transport = local_delivery
$ /usr/exim/bin/exim localuser
Here is a test
.
$ cd /home/localuser/Maildir
$ ls
cur     new     tmp
$ ls new
102078119.7969.hostnn.t1.ws.afnog.org,S=426
$ cat new/*
Return-path: <root@hostnn.t1.ws.afnog.org>
...
Here is a test

Note: once you have changed to Maildir delivery, you will find that your MUA (which looks in /var/mail) will no longer see your incoming mail. How to fix this depends on your MUA. For example:

mutt
In /usr/local/etc/Muttrc put:
set spoolfile="~/Maildir/"

2. Compile and install qmail-pop3d

qmail is an entire MTA in its own right, but we will just be using its pop3 daemon because it supports Maildir format. It is lightweight and robust.

We will just build the parts of qmail we are interested in. A small patch enables some logging of POP3 accesses, otherwise no logging is done at all.

Starting in your home directory:

$ tar -xvzf /path/to/file/qmail-1.03.tar.gz
$ cd qmail-1.03
$ patch -p1 </path/to/file/qmail-log.patch
$ make qmail-pop3d
$ make qmail-popup
$ su
Password: <root password>
# cp qmail-pop3d qmail-popup /usr/local/libexec/
# exit

$ cd ..
$ tar -xvzf /path/to/file/checkpassword-0.90.tar.gz
$ cd checkpassword-0.90
$ make
$ su
Password: <root password>
# cp checkpassword /usr/local/libexec/
# exit
$ cd ..

3. Edit /etc/inetd.conf

Put all of the following on one line in /etc/inetd.conf, changing host1.t1.ws.afnog.org to your hostname

pop3  stream  tcp  nowait  root  /usr/local/libexec/qmail-popup qmail-popup
        host1.t1.ws.afnog.org /usr/local/libexec/checkpassword
        /usr/local/libexec/qmail-pop3d Maildir

Send a HUP to inetd:

# killall -HUP inetd      (same as 'killall -1 inetd')

Note that FreeBSD's inetd limits any particular services to being invoked no more than 256 times per minute. To raise this you use the -R flag, e.g. in /etc/rc.conf put:

inetd_flags="-wW -R 0"

This system is very modular. qmail-popup gets the USER and PASS from the remote client; in turn it runs checkpassword which checks the username/password are valid and sets the home directory; this in turn runs qmail-pop3d which executes POP3 commands.

This example uses checkpassword which looks up accounts in /etc/passwd, but qmail-pop3d can be used in virtual hosting environments simply by replacing checkpassword with an alternative program.


4. Test pop3 access

POP3 should now be functioning. Test it with a good username/password, and also a good username/bad password (to check that it is rejected).

$ telnet localhost 110
Trying 127.0.0.1...
Connected to localhost.
Escape character is '^]'.
+OK <2055.988915136@host1.t1.ws.afnog.org>
user username
+OK
pass password
+OK
stat
+OK 12 17584
retr 1
+OK
... message
quit
+OK
Connection closed by foreign host.

If you applied the logging patch, you should also find log messages:

# tail /var/log/maillog
May  3 18:40:24 noc qmail-popup: POP3 login successful for brian from 127.0.0.1