Notes on running your own email server

because I’m a masochist.

last modified on



A lot of the pain of running an email server is magic DNS records, which are needed to not be rejected as spam. They are:


The MX record is used to list the mail servers for a given domain, along with a priority. There can be multiple servers, ranked by priority. Other servers will direct mail toward these servers, and they are also used for SPF. For example:

@  IN  MX  10
@  IN  MX  20


Sender Policy Framework is a magic DNS record for an email domain that describes which servers are allowed to send email as that domain. It has a dedicated SPF DNS record, but TXT is recommended for backward compatibility. The field is of the form v=spf1 {query}, where the query has positive (default, optional +) and negative (-) matches for associated a & mx records, specific ip4 and ip6 ranges, and the ability to include SPF records from other domains. For example, the following allows the servers with MX records for this domain, and denies everything else:

@  IN  TXT  "v=spf1 mx -all"
@  IN  SPF  "v=spf1 mx -all"


Domain-based Message Authentication, Reporting and Conformance is a magic DNS record that can set various policies for an email domain. The DNS record is a TXT record set at the _dmarc subdomain of the email domain, e.g. for It can do various things, but for the sake of setting up an MVP self-hosted email, it can almost all be skipped. For example, the following creates a DMARC record with a policy (p) of none:

_dmarc  IN  TXT  "v=DMARC1; p=none"


DomainKeys Identified Mail is an email signing protocol to validate that an email did in fact come from an approved server. The protocol works by signing outbound email with a named private key, and checked against a corresponding public key published as a DNS record. This name is called the selector, and is published as a TXT DNS record for a subdomain {selector}._domainkey of the email domain, e.g. for There can be multiple keys, to support key rotation and multiple sending machines. For example, the following lists an old key, a new key for a main email server, and a key for a backup email server, using keys generated by opendkim-genkey and elided for brevity:

main20170105._domainkey    IN  TXT  "v=DKIM1; k=rsa; p=..."
main20210501._domainkey    IN  TXT  "v=DKIM1; k=rsa; p=..."
backup20210501._domainkey  IN  TXT  "v=DKIM1; k=rsa; p=..."

Complete example

To send & receive email for from a server

@                IN  MX   10
@                IN  TXT  "v=spf1 mx -all"
@                IN  SPF  "v=spf1 mx -all"
_dmarc           IN  TXT  "v=DMARC1; p=none"
srv1._domainkey  IN  TXT  "v=DKIM1; k=rsa; p=…"


To check that this is all set up correctly, you can use