This is a quick guide to setup DKIM and DMARC records on your postfix-based ubuntu email server. I followed closely a guide from Julian Kunkel and am reproducing many steps from his post here. Despite the fact that he wrote his guide because he found some typos in other guides, his guide also had some.
I’ve been doing work on already working Ubuntu server (xenial, 16.04) with working postfix which I setup using that ArsTechnica article.
In the instructions I will use the placeholder <DOMAIN> for a full qualified domain such as emanat.si. You have to decide about a selector to use which basically provides means to use multiple keys, I use <SELECTOR> as placeholder, in my case, it is “mail”. <EMAIL> is an email where you like to receive errors (in case of DMARC).
Install DKIM tools:
1 |
# apt install opendkim opendkim-tools |
Create public/private key pairs:
1 2 3 |
# mkdir /etc/dkimkeys/<DOMAIN> # cd /etc/dkimkeys/<DOMAIN> # opendkim-genkey -t -s <SELECTOR> -d <DOMAIN> |
Example:
1 |
# opendkim-genkey -t -s mail -d emanat.si |
Configure opendkim, edit /etc/opendkim.conf (emacs/nano):
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 |
Syslog yes UMask 0002 OversignHeaders From TrustAnchorFile /usr/share/dns/root.key Canonicalization relaxed/relaxed ExternalIgnoreList refile:/etc/opendkim/TrustedHosts InternalHosts refile:/etc/opendkim/TrustedHosts KeyTable refile:/etc/opendkim/KeyTable SigningTable refile:/etc/opendkim/SigningTable Selector mail LogWhy Yes PidFile /var/run/opendkim/opendkim.pid Socket local:/var/spool/postfix/opendkim/opendkim.sock SyslogSuccess Yes TemporaryDirectory /var/tmp UserID opendkim:opendkim |
Create/edit /etc/opendkim/KeyTable – this file is basically a list of references to the key files, formated as follows:
1 |
<SELECTOR>._domainkey.<DOMAIN> <DOMAIN>:<SELECTOR>:/etc/dkimkeys/<DOMAIN>/<SELECTOR>.private |
For example:
1 |
mail._domainkey.emanat.si emanat.si:mail:/etc/dkimkeys/emanat.si/mail.private |
Create/edit /etc/opendkim/SigningTable which defines the patterns for which email to use which key, it is a list:
1 |
*@<DOMAIN> <SELECTOR>._domainkey.<DOMAIN> |
For example:
1 |
*@emanat.si mail._domainkey.emanat.si |
In the /etc/opendkim/
there should also be a file TrustedHosts
with only text “127.0.0.1
” (without quotes) inside.
Now secure the files:
1 2 3 |
# chown -R opendkim:opendkim /etc/dkimkeys/ # chown -R opendkim:opendkim /etc/opendkim/ # chmod -R 700 /etc/dkimkeys/ |
Restart the opendkim service and check status:
1 2 |
# systemctl restart opendkim.service # systemctl status opendkim.service |
Setup the public key in DNS, modify the DNS, add a TXT entry as follows:
- Name: <SELECTOR>._domainkey
- example: mail._domainkey
- Value: the contents between (” and “) in the file /etc/dkimkeys/<DOMAIN>/<SELECTOR>.txt,
- example v=DKIM1; h=sha256; k=rsa; p=MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAxfxhoZwKV1gahzMYv2tvEVBtAFo8LgW/8GolHibkiCGqD7urRnUPUPj/RF72mkwz/RdX+o8XTAJKgGvw5eo9g6z3DPql1xKcZEbpcUSnGbpIGQODmnNEqixaScrlEVmgtjHJsm9++Upp4RRRo7309Zlvzh4bmIfVzubwNG3umYzuf6ct/RT1xyRLWXLh5LtOa/xBNfRhCoGjxlgufu9CUqQe9af8J3MY6t2PR63XUOxwwGNBrNAlGTKw8KDc9OKn/eYCOBM4XrWjwiAR3dIVQJPT3FfSKqZ2BrBmRVg0jUiwE0j7AB+wLN/Ixsbp/ByyprcnVDFyNiXzOhr17mVOMQIDAQAB
Test it with
1 |
$ dig mail._domainkey.emanat.si TXT |
Note that DNS updates may take a while depending on your TIL and provide. You should see the public key from above in the ANSWER SECTION.
Now setup postfix to utilize the installed opendkim, edit /etc/postfix/main.cf so it should look something like:
1 2 3 4 |
milter_default_action = accept milter_connect_macros = j {daemon_name} v {if_name} _ non_smtpd_milters = $smtpd_milters smtpd_milters = unix:/spamass/spamass.sock unix:/opendkim/opendkim.sock |
Restart postfix with
1 |
# systemctl reload postfix.service |
DMARC
DMARC includes a simple DNS change similar to SPF and DKIM. Add a TXT entry as follows
- Name: _dmarc
- Value: v=DMARC1; p=none; rua=mailto:<EMAIL>; ruf=mailto:<EMAIL>
- example:
v=DMARC1; p=none; rua=mailto:postfix@emanat.si; ruf=mailto:postfix@emanat.si
- This policy (
p=none
) will allow debugging, instructing that emails shall be send by mail servers providing status information about accepted and failes messages. Once everything works the policy can (should) be changed to “quarantine” or “reject” to tell every email server to reject emails that appear to stem from your domain but are not signed.
Test DNS again with dig:
1 |
$ dig _dmarc.emanat.si TXT |
Testing
Check that opendkim finds the publicly announced keys:
1 |
# opendkim-testkey -d <DOMAIN> -s <SELECTOR> -v -v -v |
Example:
1 2 3 4 5 |
# opendkim-testkey -d emanat.si -s mail -v -v -v opendkim-testkey: using default configfile /etc/opendkim.conf opendkim-testkey: checking key 'mail._domainkey.emanat.si' opendkim-testkey: key not secure opendkim-testkey: key OK |
Check correct config from outside using these online tools:
- https://www.dmarcanalyzer.com/dkim/dkim-check/
- https://dmarcian.com/dkim-inspector/
- https://mxtoolbox.com/domain/
- https://www.mail-tester.com/ (3 tries per day!)
Also try sending an email to some big email provider (like, khm, gmail) and look at the source (‘original message’).
Once everything works, you may want to remove the “ruf” property from the DNS _dmarc TXT field to reduce the number of messages you receive about failed delivery. You may also want to change the DMARC policy to “reject”. This minimizes the risk that email addresses from your server are spoofed and your domain is classified as source of spam…
More domains
To add more domains, these are the steps:
- create folder in /etc/dkimkeys/<DOMAIN>, and move into it
- generate keys with something like
opendkim-genkey -t -s mail -d <DOMAIN>
- add to /etc/opendkim/KeyTable something like
mail._domainkey.emanat.si emanat.si:mail:/etc/dkimkeys/emanat.si/mail.private
and /etc/opendkim/SigningTable something like*@emanat.si mail._domainkey.emanat.si
- edit DNS records to add a TXT entry with name:
mail._domainkey
and value the contents of between (” and “) in the file /etc/dkimkeys/main.txt - also add another TXT entry with name:
_dmarc
and value: “v=DMARC1; p=none; rua=mailto:postfix@emanat.si
” (change value after p= to quarantine or reject sometime soon) - test:
1 2 3 |
$ dig mail._domainkey.emanat.si TXT $ dig _dmarc.emanat.si TXT # opendkim-testkey -d <DOMAIN> -s <SELECTOR> -v -v -v |