--- title: "Revisiting my email server in 2022" firstLetter: "R" date: 2022-07-25T10:56:53+02:00 draft: false --- # More than two years have passed since my first post about [setting up an email server in 2020 with OpenSMTPD and Dovecot](/blog/2020/email-server/) and [its sequel](/blog/2020/email-server-extras/). Since then, my server been going strong, with a few minor hiccups along the way. In this post, I'll explain some of the changes I made. This assumes you've followed the preceding guides: the configuration snippets given here should be interpreted as modifications to those guides, *not* as complete setups! Last updated on 2022-09-12. ## More about DMARC When I wrote my original guide, I didn't properly understand how DMARC works: I misinterpreted it as an optional wrapper around SPF and DKIM. But oh God, I was wrong. Simon Andrews' article "[I figured out how DMARC works, and it almost broke me](https://simonandrews.ca/articles/how-to-set-up-spf-dkim-dmarc)" showed me the ugly truth, and I highly recommend reading it. Briefly, DMARC does two arguably unrelated things. Firstly, DMARC provides a way to diagnose issues with your SPF and DKIM configurations, in the form of reports that get sent to the `ruf=` and/or `rua=` email address(es) you put in the DNS record. Without this, there's no way of knowing why your emails are getting marked as spam. Secondly, it improves the trustworthiness of SPF and DKIM by enforcing *alignment*. This means something slightly different for SPF and DKIM, and boils down to fixing a glaring issue: * For some reason, in vanilla SMTP, it turns out that the email's `From:` header doesn't need to agree with the address in the SMTP `MAIL FROM` command; in other words, the server can claim a different sender that what's written in the message's header. SPF only verifies the former (i.e. it takes the domain in `MAIL FROM`), so one SMTP server can impersonate another. * An email's DKIM signature header states the domain of the signing server with the `d=` tag, but, once again, that doesn't need to agree with the `From:` header's domain. DKIM doesn't look at the latter, so an SMTP server can validly sign impersonated messages. DMARC's alignment refers to checking whether the domains match up for SPF and DKIM, thus ensuring that an SMTP server can't pretend to be someone else. It sounds obvious, but nope, apparently it wasn't before DMARC was made. ## DKIMproxy To add DKIM signatures to my messages, I switched from Rspamd to [DKIMproxy](http://dkimproxy.sourceforge.net/). ### Motivation To sign outgoing emails for DKIM, my original guide used Rspamd --- an unusual choice, since it's a spam filter designed to act on *incoming* messages. Later, in the [sequel](/blog/2020/email-server-extras/) to that guide, I needed some ugly workarounds to compensate for Rspamd's "smartness" when I tried to play around with authentication schemes in OpenSMTPD. Clearly, this wasn't ideal. However, the reason I cut my losses and switched to another DKIM signer was actually a bug in MXToolBox' [deliverability tool](https://mxtoolbox.com/deliverability). It appears that no matter what you do, this tool claims that your email's signature fails validation. I'm not the first to notice this issue: see e.g. [this question](https://serverfault.com/questions/1005818/dkim-validating-but-mxtoolbox-reports-as-dkim-signature-not-verified) on Server Fault. Other tools like the [DKIM validator](https://dkimvalidator.com/) say that my DKIM signatures are correct. There aren't many open-source alternatives out there for DKIM signing: the only ones I know of are [OpenDKIM](http://www.opendkim.org/) and DKIMproxy. The former is a so-called "milter", meaning it can only interact with MTAs via the milter API, which is only supported by [Sendmail](https://www.proofpoint.com/us/products/email-protection/open-source-email-solution) and [Postfix](https://www.postfix.org/). Since we're using OpenSMTPD, our only option is DKIMproxy, which consists of two daemons: `dkimproxy.out` to sign outgoing mail, and `dkimproxy.in` to verify incoming mail. We just need the former; Rspamd is still convenient for handling the latter's functionality. ### DKIM settings Let's start by disabling Rspamd's DKIM signer in `/etc/rspamd/local.d/dkim_signing.conf`: ```sh enabled = false; ``` Then configure `dkimproxy.out` as follows in `/etc/dkimproxy/dkimproxy_out.conf`. If you placed your DKIM public key in a TXT DNS record for `._domainkey.example.com.`, and stored your private key in `/path/to/dkim/private.key`, then: ```sh # Receive emails on 10027, sign them, and forward them to 10028 listen 127.0.0.1:10027 relay 127.0.0.1:10028 # Settings for email signing domain example.com signature dkim(c=relaxed/relaxed,a=rsa-sha256) keyfile /path/to/dkim/private.key selector ``` Here, `rsa-sha256` is the signature algorithm (this is the best available, because DKIM is ancient), and `relaxed/relaxed` is the so-called *canonicalization* method, which is applied before signing and verification, to prevents failures if e.g. the email's whitespace gets changed in transit. ### OpenSMTPD settings OpenSMTPD needs to send all outbound mail through `dkimproxy.out`. In `/etc/smtpd/smtpd.conf`, we tell it that all emails coming from the MUA must be relayed through `localhost:10027`, and then, after DKIM signing, picked up again on `localhost:10028`: ```sh # Outbound listen on eth0 port 465 smtps pki "example.com" auth tag "TRUSTED" listen on eth0 port 587 tls-require pki "example.com" auth tag "TRUSTED" action "SIGN" relay host "localhost:10027" match from any tag "TRUSTED" for any action "SIGN" listen on lo port 10028 tag "SIGNED" action "SEND" relay srs match from any tag "SIGNED" for any action "SEND" ``` The tag name `TRUSTED` reflects that only messages from trusted (i.e. authenticated) MUAs should be signed. After signing, emails get the tag `SIGNED`, and are sent to their destination as usual. ## SMTP relay Instead of sending my emails directly to their destinations, I now send them to an SMTP relay server, which then passes them on to their actual destinations. ### Motivation Large email providers such as Google, Microsoft and Yahoo manage many user accounts, so for them it makes sense to keep track of IP-based sender reputations. For example, if a number of low-quality emails are sent from a single IP to many of the accounts they manage, it's cheaper to simply blacklist that IP entirely at the MTA level, rather than passing each message through a computationally-intensive spam filter. But, as usual, Microsoft has to ruin everything with their draconic policies. In a stroke of genius, someone there decided to blindly ban IPs, seemingly in blocks belonging to VPS providers. One day, I tried to send an email to an Outlook-based account, and OpenSMTPD reported it had been unable to make the delivery, because Microsoft had thrown an error: To their credit, they seem to be offering a way out. This approach is reasonable: preventively ban high-risk IP ranges, and allow "trustworthy" servers at the owner's request. I got error 5.7.511, asking me to send an email to a support address. If you're lucky, you may have a different error, and get the opportunity to use the slick [delist portal](https://sender.office.com/) instead. The URL in the bounce message links to [this list](https://go.microsoft.com/fwlink/?LinkId=526653) of error codes. I confess, I never actually bothered to forward the message to the provided address: my initial email was time-sensitive, so I couldn't afford to wait for Microsoft's response. Also, their customer support's stellar reputation precedes them, so I chose to use my time more wisely. Even if they would've resolved it nicely, there's nothing preventing Microsoft (or any other provider) from breaking my deliverability again in the future. Instead, I opted for a compromise. As a result of providers' IP reputation systems, a whole new business has appeared: SMTP relays. They offer to take the issue out of your hands: you send your emails through their servers, and they do their best to deliver them to large providers. SMTP relays are mostly used for sending marketing emails in bulk, but are also useful to avoid small-scale problems as described above. There are many SMTP relay services to choose from, at various prices. Using an SMTP relay results in more reliable delivery of your messages to large providers, but an obvious concern is privacy: the relay server can read all your outgoing emails (but not incoming), so you'll have to trust the service you choose. But it's no worse than using a major provider, and if you're sending sensitive material, why use email in the first place? Personally, I use [SMTP2GO](https://www.smtp2go.com/), but I can't say how good they are; do your own research. ### OpenSMTPD settings Once you've chosen an SMTP relay service, let's say `relay.com`, and set up your account, they'll let you create credentials to use their SMTP servers. Suppose these credentials are `` and ``, create a file `/etc/smtpd/relaypw` with contents: ```sh