Did you know anyone can send an email impersonating your email address? Back in 1971 when ’email’ was invented and later when it was connected to the Internet both email users knew each other.

Since then spammers and other bad actors started to abuse this ‘feature’. And since then some new mechanisms have been added to permit validation around senders authenticity.

SPF DNS records say which mail servers are permitted to send an email for a particular email domain.

DKIM permits an email server to sign/hash key headers in an email. And DKIM DNS records permit a recipient to verify that the email is valid.

DMARC DNS records let you tell email servers that receive emails from your email domain what to do if the SPF and DKIM rules are not followed (e.g. don’t accept the emails, or to send you a report).

TLS is a security option that permits emails between servers an be sent over an encrypted connection (helping to avoid man in the middle attacks).

Email recipients are becoming tougher on senders that don’t implement these mechanisms. Implement these mechanisms to give your emails a higher chance of being seen by their recipients.

On a debian-based distro the setup will look like the following. Note that were we use you would use your own domain name.

Next you will need to configure opendkim. For email servers with just the one email domain you can use something like this:

Domain                  $domain
KeyFile                 /etc/opendkim/mail.private
Selector                mail
Socket                  inet:8892@localhost

For email servers with more than one domain, you will create a couple of files that map each domain to its key.

KeyTable     /etc/opendkim/dkim-keytable
SigningTable refile:/etc/opendkim/dkim-signingtable
<meta charset="utf-8">Socket       inet:8892@localhost
#Domain      comment this out
#Selector    comment this out

You can then create those map files:


for i in $domains; do 
  echo "mail._domainkey.$i $i:mail:/etc/opendkim/mail.private"
done | tee /etc/opendkim/dkim-keytable
# creates lines like:
# is the DNS record name 'mail' is the 'selector',  _domainkey is a hardcoded string you just use, is the domain.   
# says that the mail selector private key is in /etc/opendkim/mail.private
# All the domains in /etc/opendkim/dkim-keytable will be pointed to use the same private key

for i in $domains; do 
  echo "*@$i mail._domainkey.$i"
done | tee /etc/opendkim/dkim-signingtable
# creates lines like:
# *
# is the DNS selector record (and infers the private key to be used).
# * means that opendkim will use this private key for all users on that domain.

# re-set file ownerships
[ -d /etc/opendkim/ ] || mkdir -p /etc/opendkim/ && chown -R opendkim /etc/opendkim/

You can now tell postfix to delegate DKIM stuff to the opendkim service. Something like the following should work well:

milter_default_action = accept
milter_protocol = 2
smtpd_milters = inet:localhost:8892
non_smtpd_milters = inet:localhost:8892

If you don’t have pre-existing values you can set them automatically:

echo "Checking current postfix config for existing settings:"
if postconf | egrep 'milter' ; then
  echo "Existing milter commands.  You would want to manually edit the config."
  echo "Wiring up postfix for opendkim"
  # be a bit forgiving should opendkim fail
  postconf milter_default_action=accept
  postconf milter_protocol=2
  # to match the Socket set in <meta charset="utf-8">/etc/opendkim.conf
  postconf smtpd_milters=inet:localhost:8892
  postconf non_smtpd_milters=inet:localhost:8892
  postconf compatibility_level=2

Restart services and check things are working ok:

postfix reload
systemctl restart opendkim
[ -f <meta charset="utf-8">/var/log/ ] && sleep 10 && tail -n 10 /var/log/

You can now send an email. And the email you send should be signed. You should see a DKIM header in the email like:

DKIM-Signature: v=1; a=rsa-sha256; c=simple/simple;; s=mail;
	t=1629841080; bh=7HNxVOxaCadHB5mfOkjUFQDbJWo7ndcitTqzHa6lAgs=;

The a=rsa-sha256 algorithm is recommended by the current RFC. If a DKIM validation tool gives you a ‘insecure signature algorithm’ warning, you may wish to use the above opendkim-genkey to create a different key.

The h=Date:From:Reply-To:To:Subject:From tells the receiver which email header fields are included in the hash. If one of these headers is changed, the hash would no longer be valid.

While your emails are now signed, recipients cannot verify if they have the correct signature. To do this they need to do a DNS lookup based on the s=mail selector from the header. For the above email they would look up the DNS TXT record for

The DNS entry to add will be per:

cat /etc/opendkim/mail.txt

Will give you a DNS entry like the following:

mail._domainkey	IN	TXT	( "v=DKIM1; h=sha256; k=rsa; "
	  "D+wYgK6i/bFt3N7Hprv8U5s/+1snACXoUh5+WJR95w1zY/vIiecN8is/2Ue9gl4UdiDqFnfGGtEbrprmCtgVL4AdYtk3HhFmENUj39hbOcLX2hs5oi/cmaM+9Kq6xlrmZChTvs2QIDAQAB" )  ; ----- DKIM key mail for

v=DKIM1 just marks it as a DKIM DNS entry. h=sha256; k=rsa indicates the hashing algorithm used. And the p field gives the public key. Since some DNS servers have a limit on record sizes the key is split into a few quote delimited strings.

You could add the DNS entry with a name of (or your domain).

Now is an opportune time to add an SPF record, which lets recipients check which mail servers they should accept emails from. To do this you will need to know which servers are permitted to send for your email domain. Will it be a webserver? Plus a dedicated mail server? Perhaps you have 3rd party tools like sendgrid?

Then add the SPF record, e.g. for create a DNS record for of:

v=spf1 a mx -all

v=spf1 is a marker that this is an SPF record. a will match if the sender resolves to a sender’s address. mx if that sender matches one of the domain’s email (MX) servers will match if the send resolves to an IP address. Another common match is IP4.

Next, add a DMARC DNS record for example This is an instruction to receivers to send reports on whether emails they receive from email addresses in your domain match your SPF/DKIM settings.

v=DMARC1; p=none; adkim=r; sp=none; pct=100; ri=86400;;

The _dmarc in the DNS record name is the location that DMARC record is expected.

  • v=DMARC1 tags the DNS record as a DMARC entry.
  • p=none sets the policy to apply to email that fails the DMARC test. Valid values can be ‘none’, ‘quarantine’, or ‘reject’.
  • adkim=r sets the alignment mode for DKIM. Indicates whether strict or relaxed DKIM Identifier Alignment mode is required by the Domain Owner. Valid values can be ‘r’ (relaxed) or ‘s’ (strict mode).
  • sp=none sets the sub-domain policy (Requested Mail Receiver policy) for all subdomains. Valid values can be ‘none’, ‘quarantine’, or ‘reject’.
  • pct=100 sets the percentage of messages from the Domain Owner’s mail stream to which the DMARC policy is to be applied. Valid value is an integer between 0 to 100.
  • ri=86400 sets the reporting Interval (in seconds) is a request to Receivers to generate aggregate reports separated by no more than the requested number of seconds.
  • sets the addresses to which aggregate feedback is to be sent. Comma separated plain-text list of DMARC URIs.
  • tells the receiver to send forensic reports for each failure
  • fo=0 is the failure reporting option default and will result in a failure report being sent if both SPF and DKIM mechanisms fail to get a ‘pass’. fo=1 will result in a failure report if either of the mechanisms fail.

After you have created this record you will get daily emails from the likes of gmail and yahoo telling you things like which emails are sending emails from your domain. And pass/fail results for DKIM and SPF. You can do this to check your changes are working OK.

If you have DMARC setup on one domain (say with an rua/ruf feedback address to go to another domain (say to you would need to let DMARC reporters know it is OK to email that other domain. They do this by checking a DNS record on the other domain. They will check a DNS name of and expect a value of v=DMARC1

You should now be able to do an end-to-end test. Try emailing something to a gmail email address.

The TLS setting made above should now result in gmail showing a security padlock in the email header drop down saying ‘security: Standard encryption (TLS)’

If you click on the vertical …. ‘More’ button you can see a Show Original option. That should then report:

SPF:	PASS with IP Learn more
DKIM:	'PASS' with domain Learn more
DMARC:	'PASS' Learn more

If those results are PASSING, and after you are happy with the DMARC results you get after a period of time you may wish to revise your SPF and DMARC records.

The SPF record above has ~all (tilde all) which means that if there is no match the email should be accepted, but flagged as bad. -all (minus all) means to reject emails with no match.

The DMARC record could also be changed from p=none to p=reject.

Congratulations. Recipients can now verify you sent the email.


  • A person with DNS access can affect delivery of emails.
  • DMARC, DKIM, and SPF are hints to a receiver about when to accept or reject emails, and when to report about passes/fails. They are hints and no receiver is compelled to enforce them.