foxcpp/maddy: a single Go daemon that replaces Postfix, Dovecot, OpenDKIM and more
✉️ Composable all-in-one mail server.
At a glance
- What is it?
- Maddy bundles SMTP, IMAP and the authentication protocols around them into one binary with one config format. It is a good fit for small operators who want fewer moving parts, and a poor fit for anyone who needs a mature IMAP server today.
- Who is it for?
- Adopt maddy if you run a small number of domains, want one config file and one process instead of a Postfix plus Dovecot plus OpenDKIM stack, and can live with IMAP storage marked beta. Do not adopt it if you depend on IMAP features that Dovecot has had for years, or if you need a documented rollback path between releases; the README does not document one.
- Can I use it commercially?
- Yes, with conditions. GPL-3.0 is a copyleft licence: if you distribute software that includes it, you must release that software's source code under the same licence. Running it internally without distributing it does not trigger that obligation.
- Is it still maintained?
- Yes. The repository last received commits 14 days ago.
- What is it written in?
- Mainly Go, according to GitHub's language statistics.
Answers come from the project's GitHub data, last synced on September 30, 2026, and from our analysis. They are not legal advice.
Editorial analysis
What maddy replaces, and for whom
The README is direct about the target: maddy "implements all functionality required to run a e-mail server." That means acting as an MTA to send mail over SMTP, acting as an MX to accept it, storing messages, and serving them over IMAP. On top of that it implements DKIM, SPF, DMARC, DANE and MTA-STS, the auxiliary protocols the README calls "mandatory to keep email reasonably secure." The stated goal is to replace Postfix, Dovecot, OpenDKIM, OpenSPF and OpenDMARC "with one daemon with uniform configuration and minimal maintenance cost."
That framing tells you who this is for. If you have ever assembled a mail stack from four packages, each with its own config syntax, its own reload semantics and its own idea of where a socket lives, the appeal is obvious. One process, one config file, one set of logs. The audience is the small operator: a handful of domains, a few hundred mailboxes at most, someone who would rather read one configuration reference than five.
The README also states the boundary plainly. IMAP storage is "beta", and it says that if you want "stable and feature-packed" IMAP you may want Dovecot instead, while noting maddy "still can handle message delivery business." That sentence is the most important one in the document. It splits the product in two: the delivery side, which the project presents as ready, and the storage and access side, which it does not.
One binary, modules wired together by config
The repository layout shows the architecture. The top level holds maddy.go, config.go, directories.go, signal.go and systemd.go, with platform variants such as directories_docker.go, signal_nonposix.go and systemd_nonlinux.go. Below that sit cmd/, framework/, internal/ and docs/. The config parser and the process lifecycle live at the root, which is consistent with the project's claim that configuration is uniform across the whole daemon.
Functionality is split into modules that the config file connects. The go.mod file lists the protocol libraries those modules are built on: github.com/emersion/go-smtp for SMTP, github.com/emersion/go-imap for IMAP, github.com/emersion/go-msgauth for DKIM and the other message authentication work, blitiri.com.ar/go/spf for SPF, github.com/foxcpp/go-mtasts for MTA-STS, and github.com/caddyserver/certmagic for certificate management. DNS providers are pulled in through the libdns family, with separate modules for Cloudflare, DigitalOcean, Gandi, Hetzner, Google Cloud DNS, Alibaba DNS and others. That list is the clearest evidence of how automatic certificate issuance is meant to work: maddy talks to whichever DNS API you configure rather than requiring you to place TXT records by hand.
Storage is the piece that changes the character of a deployment. go.mod includes github.com/foxcpp/go-imap-sql, a SQL-backed IMAP store, alongside drivers for MySQL (github.com/go-sql-driver/mysql) and PostgreSQL (github.com/lib/pq), plus github.com/johannesboyne/gofakes3, an S3 fake used for testing. So the IMAP backend is not a bespoke on-disk format but a SQL database, which is why the project can be packaged as a single binary and still persist mailboxes. The trade-off is that your mail store is now a database you must back up, tune and keep running.
Installing maddy and running it from the container image
The repository ships a Dockerfile, and it is the shortest path to a working instance because it also supplies a starter config. The build stage copies maddy.conf.docker into the image as /data/maddy.conf, compiles the binary with the docker build tag plus any tags passed through ADDITIONAL_BUILD_TAGS, and the final stage keeps only the binary and that config. The resulting container declares its ports and a volume:
EXPOSE 25 143 993 587 465
VOLUME ["/data"]
ENTRYPOINT ["/bin/maddy", "-config", "/data/maddy.conf"]
CMD ["run"]Those five ports are worth reading carefully before you start: 25 is SMTP for inbound mail, 587 is submission, 465 is SMTP over implicit TLS, 143 is IMAP and 993 is IMAP over implicit TLS. The ENTRYPOINT already points at /data/maddy.conf, so mounting a volume at /data and editing that file is the intended workflow. The CMD is "run", which means starting the container without arguments starts the server rather than printing help.
In practice you build the image and start it with the config mounted, then edit the config to match your domain. The repository does not document an install command for a host system; the README points to the setup tutorial at maddy.email/tutorials/setting-up/ for that. What the repository does show is the build script, build.sh, which takes --builddir, --destdir and --tags arguments, and the fact that the Docker build invokes it as:
./build.sh --builddir /tmp --destdir /pkg/ --tags "docker ${ADDITIONAL_BUILD_TAGS}" build installThat line is the reference for a manual build. The --tags value matters because optional functionality is compiled in or left out at build time, so a binary built without the tag you need will reject the corresponding config directive. If you are packaging maddy for a distribution, that flag is the first thing to get right.
Where maddy is the wrong tool
The IMAP beta label is not a formality. The README says it outright, and it recommends Dovecot for anyone who wants a stable, feature-packed IMAP implementation. If your users rely on server-side search, complex folder semantics, shared mailboxes or any of the long tail of IMAP extensions, you are choosing a project that has told you it is not finished in that area. Treat maddy as a delivery server that happens to expose IMAP, not as a Dovecot replacement, until that line in the README changes.
There is a second limitation that follows from the single-daemon design. Because maddy handles inbound SMTP, outbound SMTP, IMAP and the authentication protocols in one process, a fault or a misconfiguration in any one of them affects all of them. A stack built from Postfix and Dovecot lets you restart the IMAP server without touching mail delivery. With maddy, the process is the unit. That is the cost of the uniform configuration the project advertises, and it is a real one for anyone who has learned to isolate failures by service.
The third constraint is operational rather than architectural. The repository does not document a rollback procedure for a release, and nothing in the repository describes what happens to a SQL-backed mail store when you move between versions. A mail server is the one piece of infrastructure where an upgrade that goes wrong is expensive, so the absence of a documented downgrade path is something to resolve before you put real mailboxes on it, not after.
How maddy differs from running Postfix with Dovecot
The obvious alternative is the stack maddy names in its own README: Postfix for SMTP, Dovecot for IMAP and delivery, OpenDKIM for signing, plus separate SPF and DMARC tooling. The difference is not feature parity, it is where the complexity lives.
With Postfix and Dovecot you get two long-lived daemons, each with a configuration language and a large body of documentation, and you wire them together with LMTP or a maildir on shared storage. Configuration is spread across main.cf, master.cf, dovecot.conf and a set of include directories, and each component can be restarted and reasoned about on its own. The integration points are the risk: a mismatch between the Postfix transport map and the Dovecot LMTP socket is a classic failure, and it is a failure that spans two projects.
maddy inverts that. The integration is inside one process and one config file, so there is no socket to mismatch and no second config syntax to learn. The price is that maddy is younger, its IMAP is beta, and there is no equivalent of the twenty years of operational folklore that surrounds Postfix. You are also relying on one project to keep up with protocol changes across SMTP, IMAP, DKIM, SPF, DMARC, DANE and MTA-STS at once. The recent release history suggests the maintainer is doing that, but it is a wider surface for a smaller team than any single component of the traditional stack.
Maintenance, releases and the GPL-3.0 licence
The last push to the repository was on 2026-09-16, and the most recent releases are v0.9.5 on 2026-05-23, v0.9.4 on 2026-04-30 and v0.9.3 on 2026-04-12. The v0.9.3 release is labelled [SECURITY], which tells you that security fixes arrive as releases rather than as a separate channel, so tracking versions is the maintenance work. The version number is still 0.9.x, which is consistent with the README's beta label on IMAP and with a project that expects configuration to move between minor releases.
The upgrade cost has two parts. The binary itself is a single Go executable, so replacing it is trivial; the config and the storage are not. Config directives are tied to build tags, as the Docker build line shows, so an upgrade that adds a module may require a rebuild with an extra tag rather than just a new binary. And because mailboxes live in SQL via go-imap-sql, any schema change between versions lands on your database. The repository does not document a migration procedure, so back up the database before you replace the binary.
The licence is GPL-3.0, per the COPYING file at the repository root. For an operator running maddy on their own infrastructure, that is a non-issue. It matters if you intend to ship maddy inside a product or modify it and distribute the result, because the GPL's source-availability terms attach to distribution. Running it as a service for your own users is not distribution. This is a description of the licence's scope, not legal advice; if you plan to redistribute a modified maddy, talk to someone qualified.
Editorial conclusion
Adopt maddy if you run a small number of domains, want one config file and one process instead of a Postfix plus Dovecot plus OpenDKIM stack, and can live with IMAP storage marked beta. Do not adopt it if you depend on IMAP features that Dovecot has had for years, or if you need a documented rollback path between releases; the README does not document one. Before committing, read the setup tutorial at maddy.email, build the binary with the tags you actually need, and check that the storage backend you intend to use matches what your distribution package was compiled with.
Frequently asked questions
What is maddy?
maddy is an all-in-one mail server written in Go. It sends and receives mail over SMTP, stores messages and serves them over IMAP, and implements DKIM, SPF, DMARC, DANE and MTA-STS, with the stated goal of replacing Postfix, Dovecot, OpenDKIM, OpenSPF and OpenDMARC with one daemon and one configuration format.
Is maddy's IMAP stable enough to use?
The README labels IMAP storage as beta and says that if you want a stable and feature-packed implementation you may want to use Dovecot instead. It adds that maddy can still handle message delivery, which suggests treating it as a delivery server first.
How do I install maddy?
The repository provides a Dockerfile that builds the binary and installs maddy.conf.docker as /data/maddy.conf, with the container entrypoint running /bin/maddy -config /data/maddy.conf. The README links to a setup tutorial at maddy.email/tutorials/setting-up/ for host installation.
Which ports does the maddy container expose?
The Dockerfile declares EXPOSE 25 143 993 587 465, covering SMTP on 25, IMAP on 143, IMAP over implicit TLS on 993, submission on 587 and SMTP over implicit TLS on 465.
What licence is maddy released under?
The repository carries a COPYING file and the project is licensed under GPL-3.0. That affects redistribution of modified versions rather than running the server for your own users.
Official sources
Add this badge to your README
If you maintain this project, the badge below links readers to this analysis and shows its maintenance status from the daily GitHub snapshot. Paste the markdown into your README; add ?metric=license or ?metric=stars to the image URL for a different field.
[](https://hysenlabs.com/projects/foxcpp-maddy)