Years ago, I always felt that creating a functioning mail server was a project full of pitfalls and speedbumps. Luckily OpenBSD makes the configuration of a working mail server relatively easy. However, creating a working server is only one piece of the puzzle. DNS must also be properly configured to help ensure that your emails actually reach their destinations. This article highlights some of the lessons I learned while creating the mail server for this domain.
What I learned is that there are five things that must be configured in DNS that assist with destination email servers identifying you as sending legitimate emails, and not spam. In no particular order of importance:
- Reverse DNS
- MX record itself
The first one, reverse DNS, is rather simple. The PTR record for your mail server’s IP should match the A record for your mail server. Here is a good site to read if you want to learn more about reverse DNS. But what you need to know is that the primary use of rDNS is to map a hostname to an IP. See below for an example.
$ host findelabs.com findelabs.com has address 22.214.171.124
Now if we try a reverse lookup on 126.96.36.199, we should see the findelabs.com.
$ host 188.8.131.52 184.108.40.206.in-addr.arpa domain name pointer findelabs.com.
Now this is configured multiple ways on for each VPS. Since I use Vultr, I will include simply instructions below.
- Log in to my.vultr.com
- Go to your mail server
- Click on the settings tab
- Within the public network table, click on the reverse dns field
- Edit the reverse dns field to match the domain of the IP
After setting that field to your server’s hostname, the reverse DNS should begin resolving shortly.
The MX Record
For this example, I will again use the findelabs domain. For my mail server, I use a separate server for mail than I use for serving this site, which I would recommend. This both helps with spreading the workload, as well as adding another wall between servers intruders would have to break.
Luckily configuring DNS for the MX server itself is pretty simple. First you should create an A record for the mail server itself, then create an MX record for that mail server under the root domain, with the data entry pointing to mail.findelabs.com.
I’ll stick with my domain as an example for this one. First you create a simple A record for your mail server:
$ host mail.findelabs.com mail.findelabs.com has address 220.127.116.11
Then create an MX record under the root domain for mail.findelabs.com:
$ host -t mx findelabs.com findelabs.com mail is handled by 10 mail.findelabs.com.
The Sender Policy Framework (SPF) record is a TXT record created under the root domain. This record’s job is to notify the whole internet who is authorized to send emails on behalf of your domain. When mail servers receive mail from your domain, if the sender does not match that of the SPF record, the email will fail the SPF check on mail servers, and may take some sort of action against the email. If you have a specific mail server dedicated to sending mail, you would include its IP in the SPF record.
There are a couple field that are required in an SPF record. The first is the version of SPF record, which currently is the only version recognized.
The second field is called the mechanism, which can contain the following options in order to identify authorized mail servers:
A: A domain name which has an address record (A or AAAA) IP4: An IPv4 address IP6: An IPv6 address MX: Resolve the domain's MX record if it exists PTR: If the reverse DNS of the sender's IP matches that the domain, succeed EXISTS: This is a strange on, and rarely used. If the given domain name resolves to any address, succeed no matter what INCLUDE: Includes another domain that can send emails on your domain's behalf
Finally, the ending of the SPF record should be -all, to indicate that all emails that fail the SPF record checks are not allowed to send emails addressed from the domain.
I personally chose to use IPv4 as the mechanism to define authorized mail servers for findelabs.com. The SPF record for my domain is shown below:
$ host -t txt findelabs.com findelabs.com descriptive text "v=spf1 ip4:18.104.22.168 -all"
That’s about as simple as you can get for an SPF record. The required SPF version, along with the IP allowed to send emails from the domain findelabs.com, ended with -all to indicate that any emails sent from findelabs.com not from the IP 22.214.171.124 should be rejected or marked as spam. Though technically the SPF could simply be “v=spf1 mx -all”, and accomplish the same.
While the SPF record in DNS lists authorized mail servers for a domain, DKIM is a method for for authenticating emails sent from a mail server. The simplified explanation for the DKIM process is shown below:
- Domain owner creates an RSA key pair
- The public key is published in DNS as a DKIM TXT record
- The sending email server uses the pre-generated RSA private key to sign outgoing emails
- The receiving mail server checks signatures in emails received from the domain against the public key in DNS
We won’t go over the process of setting up DKIM on the outgoing mail server, since that is beyond the scope of this article, but we will show what a proper DKIM TXT record should look like. The TXT record is composed of three parts; the version tag, the key type tag, and finally the public key itself. Currently there is only one version of DKIM, so the correct tag should be “v=DKIM1”. The key type for most applications is RSA, which makes the tag be “k=rsa”. Finally, the public key itself is declared with “p=MIGfMA0GC…".
Also, to note, the DKIM TXT record is setup with a subdomain in the form of “._domainkey”. The selector is simply a way to differentiate different DKIM keys that could be used be your domain. In most our case, we use default as the selector. This will matter when the DKIM signing processes is configured on the sending email server.
The whole DKIM TXT record for this domain is shown below:
$ host -t txt default._domainkey.findelabs.com default._domainkey.findelabs.com descriptive text "v=DKIM1\; k=rsa\; p=MIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQCsPekGSQpjQvIGtiI1Fit8vYMNeqZNtNfly4od2e9fTTcUA7me/NTsUFbmvz9G1bDAzA4gpygQDFOAR+uPa0wT4/6+pQpYPhp5Oe358P1XaXmi2VyYLCYzndEIjnXTfg0mvrWNEX+j0nGYO0fzxRTvAAvlet2Q634jVrjG5Bfq1wIDAQAB"
The last piece of the puzzle has to do with what servers receiving emails from your domain should do with emails that fail either the SPF or DKIM checks. This is called the DMARC policy, and there are three policies available currently: none, quarantine, and reject. This is a required field within the DMARC TXT record, along with the DMARC version, which also is currently at version 1.
The three DMARC policy are outlined briefly below:
none: do nothing with emails that fail SPF or DKIM checks quarantine: place emails that fail SPF or DKIM checks in quarantine, which typically means the junk folder reject: reject emails at the smtpd level that fail SPF or DKIM checks. This means that it would never reach the intended recipient's account
There are also a number of optional flags one can set within a DMARC TXT record, but we will only talk about two of them in any detail. But you can read about the whole list here.
The two optional values I would like to discuss are pct and rua. A brief overview is shown below:
pct: The percentage of emails that should have actions taken against rua: Reporting URI of aggregate reports. Basically an email to send reports to
Going into more detail, the percentage flag is designed to be used with either the quarantine or reject policies. For example, if you were to create a DMARC TXT record with the flags “p=reject pct=20”, this would mean that 20% of emails failing SPF and/or DKIM checks would be rejected, but allow 80% through.
DMARC settings are advised to be rolled out slowly, starting with the “none” policy, and slowly working your way up to 100% reject. This is recommended so that you can ensure that your emails are indeed passing checks on remote servers. Once you are confident that emails are getting passed through checks, update the policy to the quarantine policy at a lower percentage, and slowly increase the percentage over time. Finally, once you are even more confident that no random emails are failing checks, apply the reject policy.
Here is an example DMARC policy in DNS:
$ host -t txt _dmarc.example.com _dmarc.example.com descriptive text "v=DMARC1\; p=none\; rua=mailto:firstname.lastname@example.org"
The subdomain for the DMARC TXT record must be _dmarc. This record simply states that email servers receiving emails from example.com should do nothing with emails that fail checks, and should send all DMARC reports to email@example.com.
Hopefully this article helps you understand a little better how DNS interacts heavily with emailing in today’s internet, in a constant and endless battle against spam. I also have a simple ansible role I use to create my mail servers on OpenBSD, which can be viewed here.
Has been tested on OpenBSD 6.5