Authenticating Your Mailserver With SPF and DKIM
I recently did a video on setting up an email server, with Postfix for SMTP and Dovecot for IMAP, which you can check out here. Now this much isn’t enough since you want to make sure no one can spoof your domain and/or tamper with the content of your E-mails. This is where SPF (Sender Policy Framework) and DKIM (DomainKeys Identified Mail) come to the rescue.
What are SPF and DKIM?
SPF is used to limit which servers are allowed to send emails from your domain. It protects your domain against domain spoofing. Even if you don’t use E-mail on your domain, I recommend using SPF to specify that you won’t be sending any emails from this particular domain, so no one can spoof your domain and pretend to be you while sending emails.
DKIM can be used to sign the emails with a key pair (where the public key is added to your domain’s TXT records) so your E-mails’ contents cannot be tampered with. OpenDKIM is an open source implementation of DKIM, we will be setting up OpenDKIM in this tutorial (because I have a natural urge to use anything which has “open” in its name)
Setting up SPF for outgoing emails on your domain
You need to add a TXT record to your domain containing the SPF syntax. the SPF record should always start with the SPF version number you are using.
For me it is
v=spf1. Then, you can add all the SPF “mechanisms” that need to be evaluated in order to identify the E-mail.
Most of the time you just need one or two mechanisms, which are
(you don’t need all of them, it’s kinda overkill)
mxmeans the email is legit if it comes from a server which is in the MX Records of this domain
mx:your-domain.tldmeans the email is legit if it comes from a server which is in the MX Records of your-domain.tld
ip4:ipv4_addressmeans the email is legit if the sending server has this particular IPv4 address
ip6:ipv6_addressmeans the email is legit if the sending server has this particular IPv6 address
You can prepend any of these with
- to reject emails which meet this condition (by default it accepts the ones passing this condition); You can use
-all to make sure
all the other unauthorised emails don’t pass the SPF test.
So this is what a valid SPF record would look like:
v=spf1 mx -all
Now I did say using all of these at ones is pretty overkill, but here is what mine looks like:
v=spf1 mx ip4:126.96.36.199 ip6:2400:8904::f03c:93ff:feac:ca67 mx:m.vidhukant.xyz -all
I don’t think using many mechanisms is a bad thing, so you can just copy mine and replace the IP4 and IP6 addresses with your server’s IP4 and IP6 addresses. Which is enough for most usecases. To apply this SPF record just add a TXT record to your root domain. It should look like this:
NOTE: If you are using multiple domains for a single mail server, you should use the exact same SPF record for all the domains.
If you don’t plan to use E-mail with any of your domains, set the SPF record to
ALWAYS add this to your root domain since it tells every receiving server that this domain doesn’t
send E-mails and if you receive one that means it’s probably malicious.
This website has all of the other info about structuring an SPF record.
Setting up DKIM (OpenDKIM)
Install the necessary packages
apt install opendkim opendkim-tools
The OpenDKIM config file located at
/etc/opendkim.conf should look like this:
Syslog yes SyslogSuccess yes Canonicalization relaxed/simple Mode sv SubDomains no OversignHeaders From Socket local:/var/spool/postfix/opendkim/opendkim.sock PidFile /var/run/opendkim/opendkim.pid AutoRestart yes AutoRestartRate 10/1M Background yes DNSTimeout 5 SignatureAlgorithm rsa-sha256 UserID opendkim UMask 002 KeyTable /etc/opendkim/key.table SigningTable refile:/etc/opendkim/signing.table ExternalIgnoreList /etc/opendkim/trusted.hosts InternalHosts /etc/opendkim/trusted.hosts TrustAnchorFile /usr/share/dns/root.key
This is what works for me on Debian 11. The data files for OpenDKIM will be stored in
/etc/opendkim/. If you want to store them anywhere else,
InternalHosts parameters in
Setting up the Signing Table
Make a list of all the domains you want to handle E-mails for, and add them to
/etc/opendkim/signing.table like this:
Replace both occurances of example.tld to your domain name, and mail to whichever subdomain sends emails.
mail._domainkey.example.tld would act
as the DKIM selector for example.tld
If you have any other subdomain set up for the mail server (for example I have
m.vidhukant.xyz while the standard would be
replace “mail” with that.
You can add as many domains you want, But don’t add domains which won’t be sending emails.
Setting up the Key Table
/etc/opendkim/key.table and add lines for each domain like this:
Add one line like this for all the domains added to the signing.table file, replace
Decide a short name for the private key for this domain,
/etc/opendkim/keys/example.private in this example holds the private key for
You should decide different names for each domain you’re adding and remember that name, you will need that later.
Setting up the Trusted Hosts
/etc/opendkim/trusted.hosts file and add these contents:
127.0.0.1 ::1 localhost hostname hostname.example.tld *.example.tld
Replace hostname with your server’s hostname (defined in
/etc/hostname), and example.tld with your domain. If you have more than one domain,
you can append those to the file prepended with a
*., just like in
No need to add another entry for
hostname.example.tld, just append
*.yourdomain.tld to the file as many times (for as many domains) you want.
Set file permissions
Make sure opendkim user has access to the required files/directories:
chmod u=rw,go=r /etc/opendkim.conf chown -R opendkim:opendkim /etc/opendkim chmod -R go-rwx /etc/opendkim/keys
Generating the keys
Run this command, replacing example.tld with your domain name, and mail with the subdomain for email:
opendkim-genkey -b 2048 -h rsa-sha256 -r -s mail -d example.tld -v mv /etc/opendkim/mail.private /etc/opendkim/keys/example.private mv /etc/opendkim/mail.txt /etc/opendkim/keys/example.txt
Replace “example” in the
example.txt files with the short name you entered for the domain in the
Repeat this step for all the domains if you have multiple of them!
NOTE: Never share the contents of the generated “.private” files!
systemctl restart opendkim
Add the TXT Records
Read the contents of the TXT file generated by
The output would be something like this:
mail._domainkey IN TXT ( "v=DKIM1; h=sha256; k=rsa; " "p=MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAxzNTZydyFiNljq/Md1cXNEqemKDk9CKhZGHSzEH6x0zxtdcv5ROzaytJ4OsatDOdk+Pygkj6Qq9PiLCc3HlWPTcvMEs+M8YvRergTATFNoAmXLXvpbi+DD0oXAsbz2dM/klObY9OSNlJqFpzmGjgRbtSnvCbot8Smg5LreCjmkuHo/sxyynRHGwRHUM6jokm2YGIGATZBIVqtS" "jM418Gtxx9MZUbwcQTlchk1hSQgbXlAAl5tagle3bq/2GwrwrdaghRH750qLjnBQhzdFnH+GjHTmRl2drQ/2zG1L0GlufipZ1UkWulidox2RtIykv2VxDlBYb77G4PAiiJsSar+wIDAQAB" ) ; ----- DKIM key mail for example.tld
Carefully delete everything outside the parenthesis (including the parenthesis) and join all three lines into one. Now, remove all the quotes and also the whitespaces between line 2 and 3, so both lines get merged into one, without any space between them.
The result should look like this:
v=DKIM1; h=sha256; k=rsa; p=MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAxzNTZydyFiNljq/Md1cXNEqemKDk9CKhZGHSzEH6x0zxtdcv5ROzaytJ4OsatDOdk+Pygkj6Qq9PiLCc3HlWPTcvMEs+M8YvRergTATFNoAmXLXvpbi+DD0oXAsbz2dM/klObY9OSNlJqFpzmGjgRbtSnvCbot8Smg5LreCjmkuHo/sxyynRHGwRHUM6jokm2YGIGATZBIVqtSjM418Gtxx9MZUbwcQTlchk1hSQgbXlAAl5tagle3bq/2GwrwrdaghRH750qLjnBQhzdFnH+GjHTmRl2drQ/2zG1L0GlufipZ1UkWulidox2RtIykv2VxDlBYb77G4PAiiJsSar+wIDAQAB
This is your public key for DKIM.
Now go to your DNS editor, click on Add TXT Record, the hostname should be
mail._domainkey or whatever the first few characters the original example.txt showed.
In the value field copy and paste the public key. Make sure there are no errors.
Configuring postfix to use OpenDKIM
Set up postfix to process outgoing E-mails with OpenDKIM
postconf -e "milter_default_action = accept" postconf -e "milter_protocol = 6" postconf -e "smtpd_milters = local:opendkim/opendkim.sock" postconf -e "non_smtpd_milters = local:opendkim/opendkim.sock"
Add this to your
/etc/default/opendkim file to set the socket for postfix
And then create the socket directory
mkdir /var/spool/postfix/opendkim chown opendkim:postfix /var/spool/postfix/opendkim
Testing if DKIM is working
Wait for the DNS records to propagate (shouldn’t take long!) and send an email with your SMTP server, on the receiving end, your email client should have an option
to “view source” or “show email headers”, open that, you should see a
DKIM-Signature: field there.
You can now send a test email to a GMail account, and on the GMail web app you can view the email’s source. It will show detailed information about your DKIM and SPF setup. GMail is by far the best test to verify that your authentication mechanisms (SPF, DKIM, etc) are working properly.
Use DMARC to tell receiving servers how to handle your email
Domain-based Message Authentication, Reporting and Conformance, short for DMARC can be used to specify a set of instructions for the receiving email servers on how
to handle the email. You can use it to specify which authentication mechanism (SPF, DKIM or both) is in place, what to do with emails which fail authentication
(you can reject, send, or quarantine them), how to check the
From: field of the email. It can also be used by receiving servers to report back to your own server,
in case any of the checks fail.
All DMARC records start with
v=DMARC1, and the
p= field would specify what to do with emails that fail the SPF or the DKIM test.
p= can have these three values:
- none: do nothing
- quarantine: quarantine the email (e.g send it to the spam folder)
- reject: reject the incoming email
It is best to use
p=none while testing your SPF and DKIM records, after that you can choose between
You can also optionally use
rua=mailto:your_email to get DMARC fail reports to your email. Just replace
your_email with your E-mail.
You can specify multiple E-mail addresses seperated with a comma.
Here’s what an example DMARC record should look like:
v=DMARC1; p=quarantine; rua=mailto:firstname.lastname@example.org
Add this to your domain’s TXT records and set the hostname to
_dmarc and you should be good to go!
Use this DKIM test to test your SPF, DKIM and DMARC configuration.