I've been using Mail-In-A-Box for quite some time now, and while it's served me well for quite a while, I feel like it's time to get more involved in managing my personal infra.

Gratitude for Mail-in-a-box

Joshua Tauberer has done an incredible job of making a self-hosted email server affordable and accessible, updating the project to incoporate the latest protocols and generally inspiring confidence that upgrades will JustWork(tm). He's been incredibly generous with his time, and I doubt I would have gone down this path without the high quality of work he's painstakingly lavished on this project for so many years. In many ways, he represents the finest traditions of open source.

Things I Dislike about Mail-in-a-box

TLS problems Maybe it's just me, but I can't seem to resolve this symlink loop issue that takes down my server either every 24hrs or every 3 months, depending. Newer versions of Mail-in-a-box use MTA-STS which means that I must fix TLS issues immediately or I can't even read already delivered email messages. Once you combine that with rate limits at LetsEncrypt, you have an amazing recipe for chronic downtime.

Limited tests and an ambivalent attitude towards continuous integration means I can't contribute back proof that my problem is fixed while keeping the existing functionality working. Also, it just means maintainers spend a ton of energy manually testing everything.

Email usability problems There are 2 big problems here: (1) addresses are only auto-suggested during email authoring if they are manually added to the address book, and (2) the calendar integration isn't google calendar friendly. Specifically, if someone sends me an invite to an event, and I click "yes", the event won't appear on my calendar. This makes it hard to coordinate with others.

Backup and Monitoring The builtin monitoring tool, Munin can't be configured to send alerts without forking the project or hacking the code. Personally, I've not worked with Munin much in my day job and would rather use something like telegraf + influxcloud, or grafana cloud, etc. Additionally, it could just be me, but I've never been able to get duplicity working and so I effectively have no backups.

Unconfigurable The project is very upfront about this:

Please note that the goal of this project is to provide a simple, turn-key solution. There are basically no configuration options and you can’t tweak the machine’s configuration files after installation.

This is a great way to structure a project to maximize the chances someone can install and use this software, even as a novice to the world of email infrastructure (like myself). Its very beginner friendly and it minimizes differences between users so that the commmunity can help each other as much as possible.

But for me as a professional software engineer, it's limiting to have a rich ecosystem of plugins for Roundcube or other applications just out of reach.

Monolithic Architecture Because Mail-in-a-box tries to completely takeover and run self-contained and unconfigurable on a single VM, everything about it becomes a spof. Now, your DNS server is also your monitoring endpoint, your LDAP, your webmail client, and your email server. You can't use tools like Kubernetes to do bin packing and run other things on the box. You also can't leverage your experience with terraform or ansible to configure things.

Things I love about Mail-in-a-box

The builtin status checks are incredible! The forums and community is really active. All various applications fit nicely together. Upgrading Mail-in-a-Box generally means pulling in new features, bugfixes, and security enhancements without much effort on my part.

A new kind of Mail-in-a-box

So, what if we wanted to make a personal email server that modular instead monolithic? What if we created a series of containers that could be deployed together in a known-good configuration, or extracted individually and reused in other projects? What if such a project had behavioral tests and a modern CI pipeline? That would be a project I'd be proud to put my name on.

Proposed Architecture

Since we're looking at supporting IMAP and SMTP protocols, we'll need a layer-4 load-balancer/reverse proxy/gateway thingie. SMTP and IMAP protocols have a kind of banter going on, where clients and servers send one or more lines to each other over a persistent TCP connection. If bots could chat, this would basically be that kind of protocol.

C: <open connection>
S:   * OK IMAP4rev1 Service Ready
C:   a001 login mrc secret
S:   a001 OK LOGIN completed
C:   a002 select inbox
S:   * 18 EXISTS
S:   * FLAGS (\Answered \Flagged \Deleted \Seen \Draft)
S:   * 2 RECENT
S:   * OK [UNSEEN 17] Message 17 is the first unseen message
S:   * OK [UIDVALIDITY 3857529045] UIDs valid
S:   a002 OK [READ-WRITE] SELECT completed
C:   a003 logout
S:   * BYE IMAP4rev1 server terminating connection
S:   a003 OK LOGOUT completed

Since managing LetsEncrypt via Mail-In-A-Box has a been weak spot for me, ideally we'd use ZeroSSL (another free ACME server with higher rate limits). Even better, let's do TLS termination at the load balancer and separate encryption concerns from IMAP/SMTP stuff.

To keep things modular and friendly to clustering solutions, we'll want to manage sets of stateless docker containers separately for SMTP and IMAP bits and bobs, have a service discovery solution that integrates with the load balancer, let the load balancer manage the TLS certs, and some kind of cluster manager schedule the SMTP and IMAP workloads. We also need a stateful store of email data (mbox? mail queue? things like that I think) and some way to specific users and their credentials. Finally, we want to make sure we can build and test the clusters ability to send/receive email in a CI pipeline, and monitoring hooks to integrate with standard tools. Now we're cooking!

Next Steps

My plan is to write up my steps towards making this cluster a reality! Next stop, get postfix working.