DKIM is supported by most common mail providers, including Yahoo, Google and Outlook.com.
Basically DKIM means digitally signing all messages on the server to verify the message actually was sent from the domain in question and is not spam or phishing (and has not been modified).
- The sender's mail server signs outgoing email with the private key.
- When the message arrives, the receiver (or his server) requests the public key from the domain's DNS and verifies the signature.
This ensures the message was sent from a server whose private key matches the domain's public key.
For more info see RFC 6376
Install the package.
The main configuration file for the signing service is
- Copy/move the sample configuration file
/etc/opendkim/opendkim.confand change the following options:
Domain example.com KeyFile /path/to/keys/server1.private Selector myselector Socket inet:8891@localhost UserID opendkim
- Socket address is the one specified in
/etc/postfix/main.cf. This is what
# For use by dkim milter smtpd_milters = inet:localhost:8891 non_smtpd_milters = $smtpd_milters milter_default_action = accept
- To generate a secret signing key, you need to specify the domain used to send mails and a selector which is used to refer to the key. You may choose anything you like, see the RFC for details, but alpha-numeric strings should be OK:
$ opendkim-genkey -r -s myselector -b 2048 -d example.com
- Sometimes mails get reformatted on their way (e.g. tab exchanged for spaces), rendering the DKIM signature invalid. To prevent trivial reformatting in header and body destroying trust, there is Canonicalization, a policy stating how strict formatting is to be conserved. Available settings are simple for no reformatting allowed and relaxed for some reformatting allowed. For details see . These can be set individually for header and body:
... Canonicalization relaxed/simple ...
This example allows some reformatting of the header but not in the message body. Default settings for openDKIM are simple/simple.
- Other configuration options are available. Make sure to read the documentation.
- Enable and start the
opendkim.service. Read Daemons for more information.
Add a DNS TXT record with your selector and public key. The correct record is generated with the private key and can be found in
myselector.txt in the same location as the private key.
myselector._domainkey IN TXT "v=DKIM1; k=rsa; s=email; p=...................."
There are several other switches available for the record (see RFC4871), the most interesting might be the
t=y which enables testing mode, signaling a checking receiver that the mail must not be treated differently from an unsigned mail, regardless of the state of the signature.
Check that your DNS record has been correctly updated:
host -t TXT myselector._domainkey.example.com
You may also check that your DKIM DNS record is properly formated using one of the DKIM Key checkers available on the web.
Either add the following lines to
If you plan to integrate DKIM and DMARC you can use the following lines instead (via unix sockets):
non_smtpd_milters = unix:/run/opendkim/opendkim.sock, unix:/run/opendmarc/dmarc.sock smtpd_milters = unix:/run/opendkim/opendkim.sock, unix:/run/opendmarc/dmarc.sock
Or change smtpd options in
smtp inet n - n - - smtpd -o smtpd_client_connection_count_limit=10 -o smtpd_milters=inet:127.0.0.1:8891 submission inet n - n - - smtpd -o smtpd_enforce_tls=no -o smtpd_sasl_auth_enable=yes -o smtpd_client_restrictions=permit_sasl_authenticated,reject -o smtpd_sasl_path=smtpd -o cyrus_sasl_config_path=/etc/sasl2 -o smtpd_milters=inet:127.0.0.1:8891
sendmail.mc file and add the following line, after the last line starting with
sendmail.cf file with:
# m4 /etc/mail/sendmail.mc > /etc/mail/sendmail.cf
And then restart the
sendmail.service. Read Daemons for more details.
If you are providing mail server service to multiple virtual domains on the same server, you will need to modify the basic configuration as below:
Provide these directives in
KeyTable refile:/etc/opendkim/KeyTable SigningTable refile:/etc/opendkim/SigningTable ExternalIgnoreList refile:/etc/opendkim/TrustedHosts InternalHosts refile:/etc/opendkim/TrustedHosts
/etc/opendkim/keys/domain1.com/. One seperate folder for each domain. Otherwise you will receive “dkim: FAILED, invalid (public key: not available)” error message with DKIM email test.
Create the following two files to tell opendkim where to find the correct keys. You can use the same key for all the domains or generate a key for each domain. Make changes to match your settings. Add more lines as needed.
myselector._domainkey.example1.com example1.com:myselector:/etc/opendkim/myselector.private myselector._domainkey.example2.com example2.com:myselector:/etc/opendkim/myselector.private ...
*@example1.com myselector._domainkey.example1.com *@example2.com myselector._domainkey.example2.com ...
/etc/opendkim/TrustedHosts file tells opendkim who to let use your keys. This is referenced by the
ExternalIgnoreList directive in your conf file. Opendkim will ignore this list of hosts when verifying incoming mail.
And, because it is also referenced by the
InternalHosts directive, this same list of hosts will be considered “internal,” and opendkim will sign their outgoing mail. Don't forget to change
<server_ip> with your server's IP:
127.0.0.1 ::1 localhost <server_ip> hostname.example1.com example1.com hostname.example2.com example2.com ...
Change ownership of all files to opendkim:
# chown -R opendkim:mail /etc/opendkim
Add a DNS TXT record with your selector and public key for each of the domains.
You can now restart opendkim.
The default configuration for the OpenDKIM daemon is less than ideal from a security point of view (all those are minor security issues):
- The OpenDKIM daemon does not need to run as
rootat all (the configuration suggested earlier will have OpenDKIM drop
rootprivileges by itself, but systemd can do this too and much earlier).
- If your mail daemon is on the same host as the OpenDKIM daemon, there is no need for localhost tcp sockets and unix sockets may be used instead, allowing classic user/group access controls.
- OpenDKIM is using the
/tmpfolder by default whereas it could use its own folder with additional access restrictions.
The following configuration files will fix most of those issues (assuming you are using Postfix) and drop some unnecessary options in the systemd service unit:
BaseDirectory /var/lib/opendkim Domain example.com KeyFile /etc/opendkim/myselector.private Selector myselector Socket local:/run/opendkim/opendkim.sock Syslog Yes TemporaryDirectory /run/opendkim UMask 002
[Unit] Description=OpenDKIM daemon After=network.target remote-fs.target nss-lookup.target [Service] Type=forking User=opendkim Group=postfix ExecStart=/usr/bin/opendkim -x /etc/opendkim/opendkim.conf RuntimeDirectory=opendkim RuntimeDirectoryMode=0750 [Install] WantedBy=multi-user.target
/etc/postfix/main.cf accordingly to make Postfix listen to this unix socket:
smtpd_milters = unix:/run/opendkim/opendkim.sock non_smtpd_milters = unix:/run/opendkim/opendkim.sock
Error: "milter-reject: END-OF-MESSAGE from localhost"
Most likely the Postfix milter protocol is set wrong in
# Postfix ≥ 2.6 milter_protocol = 6 # 2.3 ≤ Postfix ≤ 2.5 milter_protocol = 2
While you are about to fight spam and increase people's trust in your server, you might want to take a look at Sender Policy Framework, which basically means adding a DNS Record stating which servers are authorized to send email for your domain.