blog · git · desktop · images · contact & privacy · gopher

Replaced POP3 with rsync over SSH

POP3 was the mail protocol of my choice – since forever. It’s as simple as that: I don’t want my mail server to store mails for a longer period of time. It’s just supposed to temporarily hold new mail until I fetch it. POP3 allows me to do just that. I like to keep my servers on the internet “stupid”. I don’t want them to be the primary storage of important data. I want to be able to simply throw them away and re-install them using config management tools.

While I do have multiple clients (but no smartphone), I still don’t need IMAP, nor do I wish to use it. I distribute mail locally once I fetched it via POP3. I do that by … storing them in a Git repo, which eventually gets pulled by some other client:

Yes, it’s a little arcane. I don’t know a single other person who does it this way. Still, it works very well for me and I’m using this approach for almost eight years now.

There are three main reasons for me to do this:

Ditching POP3

I recently reinstalled my server because I switched from Arch Linux to OpenBSD. That’s a different story and still somewhat experimental. So far, I’m very happy with OpenBSD.

OpenBSD comes with OpenSMTPD in its base system. I use it, I like it. There is no POP3 daemon, though, nor an IMAP daemon. The OpenSMTPD guys suggest to use Dovecot. That’s a good server, but I already used it in the past and I wanted to try something new. Plus, it’s not included in the base system.

rsync is not in the base system, either, but I need it anyway.

So … why not fetch mail via rsync over SSH?

Using properties of the Maildir layout

The Maildir layout is simple, yet powerful:

└── user
    └── Maildir
        ├── cur
        ├── new
        └── tmp

Each mail is its own file. Existing mail is stored in “cur”. The interesting part is how new mail gets added to the system.

A unique file name is chosen. It often contains the PID handling the request and a timestamp. That new file is created in “tmp”. It stays in that directory while data is being written to it. Once finished, it will be moved to “new”.

Renaming files usually is an atomic operation. Meaning, if there is a file in “new”, it’s a complete mail – not some partially written file.

It’s easy to verify in OpenSMTPD’s source code that mail delivery actually happens this way:

Starting at line 117 in delivery_maildir.c.

This means I can install a cronjob on my clients to regularly fetch all files in “new” via rsync over SSH.

Granted, rsync breaks with the atomicity. It copies the file to the client and removes it afterwards. If two clients were to retrieve mail at the same time, duplicates might occur. On the other hand, this happened before with POP3 as well, which is why I never retrieve mail on two clients simultaneously. This is done by having the cronjob ping all other clients and abort if there’s an answer. This works well enough. (And it works because all of my clients are on the local network or I’m on the road with my laptop with no machines running at home.)


There is more than one Maildir on my server. Actually, there are 17 at the moment. As they are all independent, it’s trivial to run multiple rsync clients simultaneously. One for each mailbox.

Fetching all 17 boxes takes about a second. A lot faster than my previous POP3 setup.

Not comparing with IMAP here, though. It works differently it often has support for “push”.


Of course, this only works because I have SSH access anyway and because I use Maildirs on my clients. Have fun doing this with Thunderbird or with a smartphone.

It’s another peculiarity of my setup. I wonder if anybody out there uses this as well.