Friday, May 15, 2026

OpenSMTPD Is The Mail Server For The Future

OpenSMTPD profile image, see https://www.opensmtpd.org/
Image credit: the OpenSMTPD project

© 2026 Peter N. M. Hansteen

The SMTP mail server for the 21st century and onwards is OpenSMTPD, which is developed as an integral part of OpenBSD, but available in a portable variety too.

It was one of those things that I had fully intended to do years ago, but I only got around to actually doing once there was a definite deadline to get it done.

The time has come, as OpenBSD 7.9 will leave the exim package behind, and exim users will need to find a replacement before upgrading. This article describes my transition to OpenBSD's own OpenSMTPD mail server.


OpenBSD 7.9 will leave the exim package behind, and exim users will need to find a replacement.

OpenSMTPD (smtpd) is in the base system.


When OpenSMTPD was first introduced in the OpenBSD base system in OpenBSD 4.6 in October 2009, I had already been running a mail service for some years.

At the time I still found it convenient to keep using exim as the real mail server, protected by OpenBSD spamd in the incoming signal path and with a combination of spamassassin and clamav for content filtering.

It seemed quite tempting to me to play around with at the new smtpd at the time, but the initial version of the new mail server was not yet considered quite ready for prime time.


Note: This piece is also available without trackers but classic formatting only here.

The pace of development was quite hectic in the early years, and by the time smtpd replaced the classic sendmail as the default mail server in OpenBSD with the November 2014 OpenBSD 5.6 release, I had just completed the third edition of The Book of PF and I was interested, but the writing had been quite a drain on my energy.

And of course, the mail server setups I had running for myself and friends I thought of as complex enough that moving to something else would require quite some preparation and testing. So I would leave looking into the new mail server software properly for another day, soon to come, I was sure.

An Old Setup, Maintained With Much Love and Care

There are some hints of what that setup did (and still does) in the 2012 piece In The Name Of Sane Email: Setting Up OpenBSD's spamd(8) With Secondary MXes In Play - A Full Recipe (also tracked, prettified), but the main features are:

  • Two (originally three) separate sites, each with their own domains, where the other site(s) provide secondary MX duty for the other(s), each with a spamd-instrumented OpenBSD machine as the Internet-facing part of the mail setup
  • The OpenBSD machines perform spamd greylisting and greytrapping, but also provide content filtering on behalf of another set of domains with their own, not necessarily Internet-exposed, mail servers that receive the filtered mail relayed to them by the Internet-facing mail services.

This setup, with OpenBSD spamd in a greylisting and greytrapping setup in front and content filtering as the second stage before finally relaying to the protected mail hosts, worked well enough that we simply kept the systems running with only routine system and package upgrades and minor adjustments to configurations as needed.

In short, domains to be served came and went, but the spamd, exim and clamav+spamassassin combination stayed, on the ever reliable OpenBSD platform.

Time To Move On, Wait, Then Finally ...

Over the years, there were several episodes with medium to severe security flaws discovered in the exim codebase, but the OpenBSD package was generally well maintained and fixes tended to appear within a reasonable time.

From time to time OpenBSD developers and port maintainers discussed dropping support and removing exim from the package system, but it was only in early 2026 it finally happened.

OpenBSD 7.9 will ship without an official exim package.

So it was finally time for even this holdout to move to something else.

And Of Course, A False Start

Other OpenBSD users had kept telling me how good OpenSMTPD had become, so I decided now was the time, so I dug out some old notes and started experimenting.

Those old notes turned out to be utterly useless, and for a reason: The OpenSMTPD 6.4 release was the result of a major code overhaul that also changed important parts of the smtpd.conf syntax.

Unfortunately a majority of the third party guides out there that turn up early in search results still use the old syntax, and as a consequence, are useless, at least to users on OpenBSD or other platforms that have kept their code reasonably in sync. A useful rule of thumb is, if you find yourself reading an OpenSMTPD guide that is dated before 2020, do yourself a favor and move on to something newer.


If you find yourself reading an OpenSMTPD guide is dated before 2020, do yourself a favor and move on to something newer.

The Task At Hand: The Analysis

But to the problem at hand. The setup I was setting out to convert, was one that needed to accommodate

  • Inbound mail for users in the local domains, where we are the primary mail exchanger
  • Inbound mail for users in the domains where we are the secondary mail exchanger
  • Inbound mail for the users in the domains where we are the primary public-facing mail exchanger, but where we actually only relay after greylisting and filtering
  • Outbound mail from the local domains
  • Outbound mail from networks we have chosen to trust enough to relay for

The mail exchanger (MX) records for all domains involved were already in place, as was other relevant DNS information such as SPF, DKIM and DMARC records. TLS certificates and a regime for maintaining them was already in place, using LetsEncrypt tools.

That analysis converted to smtpd.conf logic would be:

  • We keep the existing /etc/mail/aliases file, the formats are compatible
  • OpenSMTPD conveniently has tables, which can be either simple lists or key-value pairs. Our tables are:
    • domains_local lists the domains we receive mail for to handle locally
    • relay-for_domains lists the domains we only filter for, then relay to
    • domain_relays is the list of domains and their final destination mail exchangers as list of key-value pairs
    • relay_from_ips is the list of IP addresses and networks we allow relaying for

Now The Actual Implementation

So I set to work from that specification, and at the end of that afternoon I had reached the conclusion that

  • setting up for TLS was the easiest, with simple pki statements
  • listen statements actually do the work in very limited space
  • routing to local delivery and forwarding is easy with a combination of action and match rules
  • for filtering, clamav had not actually been of much use to my users (no Windows users among them), and that the filtering options that made use of spamassassin for the back end were either not functional or I was too dense to make any sense of them.
    I ended up testing a modern alternative, rspamd, which is available via the OpenBSD package system.
  • dkimproxy looked like a good candidate for signing outgoing messages, so I tested that for a while, but on the advice of Martijn van Duren, I switched to dkimsign, which is available on OpenBSD as the package opensmtpd-filter-dkimsign.

In addition to smtpd, which is already in base, this configuration requires the packages opensmtpd-filter-dkimsign and opensmtpd-filter-rspamd.

Installing both via pkg_add have the packages pull in all required dependencies.

With the prerequisites in place,

disable and stop exim
doas rcctl disable exim && doas rcctl stop exim

disable and stop clamav
doas rcctl disable clamav && doas clamav stop clamav

disable and stop spamassassin
doas rcctl disable spamassassin && doas rcctl stop spamassassin

At some point, you should remove the packages with

doas pkg_delete packagename

and follow the steps outlined in the package delete message.

Don't remove the exim configuration, though, until you have copied the useful parts across to your new /etc/mail/smtpd.conf.

I ended up with this configuration (lightly edited for brevity)

---- /etc/mail/smtpd.conf
table aliases file:/etc/mail/aliases

table domains_local {
"bsdly.com",
"bsdly.eu",
"bsdly.net",
"bsdly.no",
"bsdly.org",
"bsdly.se",
"nxdomain.no",
# plus a lot of other domains, elided here for brevity
}

table relay_for_domains {
"nuug.no",
"blug.linux.no"
# again more domains in the real smtpd.conf, left out here
}

table domain_relays {
"nuug.no" = "smtp://mx1.nuug.no",
"blug.linux.no" = "smtp://mail.lamasti.net"
# again more domains in the real smtpd.conf, left out here
}

table relay_from_ips {
127.0.0.1
::1
# The rest are fictional, RFC5737 and RFC3849
192.0.2.0/24
198.51.100.0/24
203.0.113.0/24
2001:DB8::/32
}

filter "rspamd" proc-exec "filter-rspamd"
filter dkimsign_rsa proc-exec "filter-dkimsign -d bsdly.net -s x -k /etc/mail/dkim/private.rsa.key" user _dkimsign group _dkimsign

pki skapet.bsdly.net cert "/etc/mail/certificate.pem"
pki skapet.bsdly.net key "/etc/mail/privkey.pem"

listen on socket

listen on all port 25 tls pki skapet.bsdly.net filter "rspamd"
listen on all port 465 smtps pki skapet.bsdly.net filter "rspamd"
listen on all port submission tls pki skapet.bsdly.net

action "local_mail" mbox alias <aliases>
action "relay_domain" relay domain <domain_relays> filter "rspamd"
action "outbound" relay filter dkimsign_rsa

match from local for local action local_mail
match from any for domain <domains_local> action local_mail
match from any for domain <relay_for_domains> action relay_domain
match from src <relay_from_ips> for any action outbound
match from local for any action outbound
----

The specific domain names and IP addresses will be different for the secondary site, as it will for any configuration you will set up.

After some logs and messages observation, I also ended up with minor modifications to the rspamd config,

---- /etc/rspamd/local.d/actions.conf
reject = 10; # final reject
discard = 15;
add_header = 6; # mark spam
greylist = null; # do not greylist, we have spamd for that

# Custom action (referenced by force_actions), no own threshold
phishing = {
flags = ["no_threshold"];
}
----

That is the entire configuration. With the somewhat longer list of domains and networks, the net length of my configuration now is

$ grep -vc \# /etc/mail/smtpd.conf
104

104 lines, while the previous exim config with comment lines stripped out ran to

$ grep -vc \# /etc/exim/configure
380

380 lines.

The smtpd.conf configuration is readable on par with pf.conf, with similar readability features.

At any time after installing the packages and disabling the previous services, enable and start the new services.

To (re)enable smtpd as the default mail server after running with exim, run

$ doas /usr/local/sbin/exim-disable

to restore /etc/mailer.conf to its original state.

If all else fails, you can easily retrieve a pristine version from the OpenBSD CVS.

To enable the new services, run

$ doas rcctl enable smptpd && doas rcctl start smtpd
$ doas rcctl enable redis && doas rcctl start redis
$ doas rcctl enable rspamd && doas rcctl start rspamd

You should see activity fairly soon by monitoring /var/log/maillog, such as

$ tail -n 500 -f /var/log/maillog

When you are satisfied that mail flows in and out and is relayed where you want it to, it is safe to remove the exim, clamav and spamassassin packages and follow the instructions in the pkg_delete messages to free up some space.

And yes, considerably more complicated configurations are possible, especially in the filtering department.

But I was pleasantly surprised at both how simple the transistion has proven to be and the prospect for having truly maintenance and enhancement friendly setup going forward.

The transition process has showed me that OpenSMTPD product is solid, like the wider OpenBSD environment. Making OpenSMTPD the default mail server software was no doubt one of those extremely good decisions the OpenBSD project has made, and even latecomers like myself applaud the decision.

OpenSMTPD and OpenBSD both are characterized by their developers' ability to not only learn from earlier iterations of development of the operating system and the mail server component, but also to come up with new, and some times radically different, approaches to known problems that result in a more secure and more useable product. To my mind, this is the mail server and the operating system for the future.

If you are interested in setting up smtpd with more filters or other ones, quite a few are available, including such things as opensmtpd-filter-dnsbl, which pulls in DNS blocklists from the sources you specify.

OpenSMTPD is available on a wide variety of platforms, including various Linux distributions and BSDs such as FreeBSD via its -portable variety.

I have kept this configuration rather minimal, mostly because in my experience, the greylisting and greytrapping spamd is a very efficient and low maintenance outer shield for any mail service. If you are interested greytrapping, the infrequently updated Eighteen Years of Greytrapping - Is the Weirdness Finally Paying Off? (also tracked, prettified) provides more reading material via its numerous links than you could reasonably take in during even a long evening.

If you would rather have a book that covers more networking topics with OpenBSD and FreeBSD as the platform, and includes a fairly extensive treatment of spamd, The Book of PF, now in its fourth edition, is for you.

Good night and good luck!

I want to thank Martijn van Duren for useful advice while working on this article.


OpenSMTPD is the Mail Server for the Future is © 2026 Peter N. M. Hansteen (published 2026-05-15)
You might also be interested in reading selected pieces via That Grumpy BSD Guy: A Short Reading List (also here).