There are a lot of instructions on the web for installing and configuring DKIM but they vary considerably and many have errors. There also can be gotchas and this article details one of them. Ubuntu 14.04 with Postfix 2.11 are used.
For Ubuntu start by installing DKIM
apt-get install opendkim opendkim-tools
Postfix uses Milter (mail filter) as one method for integration with other applications. OpenDKIM and Postfix will need to communicate information between them. Milter supports two methods for communication: Unix sockets and TCP ports. Most instructions use TCP. The port number selected should not conflict with any in the list in the above link nor should it conflict with any ports in use on the server. To use a TCP port in /etc/opendkim.conf add
Socket inet:8891@localhost
In /etc/default/opendkim
SOCKET="inet:8891@localhost"
For Postfix, edit /etc/postfix/main.cf
smtpd_milters = inet:localhost:8891 non_smtpd_milters = inet:localhost:8891
If smtpd_milters or non_smtpd_milters are already being used then combine the lines with a comma and a space separating the values.
The next step is to generate the keys. Here we will be assuming multiple domains are on the server. There are a lot of variations on the flags recommended and some are wrong. While details can be found in the man page
man opendkim-genkey
reading through every option takes some time. The common flags that appear are -t, -r, -s, -d and -D so we will focus on them. The flag -t will add a tag that indicates to those verifying the email that DKIM is in testing mode. This should certainly not be used for production. The flag -r restricts the use of the key for e-mail signing only. Since it is not going to be used for anything else this does not seem necessary. The -D flag outputs the generated files to the directory that follows the flag. This may be useful but is not as clear as changing to the directory so we start by creating directories and then generate the keys. If you get an error generating a key then make sure you are executing the command with sudo.
mkdir -p /etc/opendkim/keys/example.com cd /etc/opendkim/keys/example.com opendkim-genkey -s dkim -d example.com
The -d flag is followed by the domain for the key (example.com should be replaced with your domain). These three commands are repeated for each domain. This should automatically include subdomains unless the -S flag is used. The -s flag is followed by the selector. The selector specifies which key for that domain should be used and appears in several places in the configuration. Common values for selectors are "default" (which is the default if it is not specified), "mail" and "dkim." While it does not make a difference as long as it is consistent here we are going to use "dkim" because it will be clearer where the selector appears. Once this is done then change the owner of these files.
chown -R opendkim:opendkim /etc/opendkim/
There are two files that are generated for each domain. These two files are dkim.key and dkim.txt (where the selector appears as part of the file name). The first file contains the key while the second one contains the information that needs to be placed in a text record in DNS. Generally the name should be the first thing in the txt file (dkim._domainkey); note the appearance of the selector again. The value should be the information in parenthesis. Check for documention for your webhost on whether the quotes are needed and other details. The value includes the public key.
Now we finish editing /etc/opendkim.conf. We need to add four lines that refer to three files and some other settings to the line we already added.
Syslog Yes UMask 002 OversignHeaders From AutoRestart Yes AutoRestartRate 10/1h Canonicalization relaxed/simple ExternalIgnoreList refile:/etc/opendkim/TrustedHosts InternalHosts refile:/etc/opendkim/TrustedHosts KeyTable refile:/etc/opendkim/KeyTable SigningTable refile:/etc/opendkim/SigningTable LogWhy Yes Mode sv PidFile /var/run/opendkim/opendkim.pid SignatureAlgorithm rsa-sha256 Socket inet:8891@localhost SyslogSuccess Yes UserID opendkim:opendkim
Lines with refile refer to regular expression files. These files consist of each line containing a pattern and a value separated by whitespace. If AutoRestart on failures is used then a loop can be created that can cause problems. AutoRestartRate of 10/1h limits the restarts to 10 in one hour. The default for SignatureAlgorithm is rsa-sha256 with a fallback of rsa-sha1. Specifying rsa-sha256 prevents the fallback. LogWhy and SyslogSuccess are for debugging and should be removed later. For more information on these settings use manpages.
man opendkim.conf
Now create /etc/opendkim/KeyTable.
dkim._domainkey.example.com example.com:dkim:/etc/opendkim/keys/example.com/dkim.private
where example.com should be replaced by your domain and the line repeated for each domain. Then create /etc/opendkim/SigningTable.
*@example.com dkim._domainkey.example.com
where example should be replaced by your domain and the line repeated for each domain. Then create the third file /etc/opendkim/TrustedHosts.
127.0.0.1 localhost *.example.com <ip address>
where each domain and IP address is listed.
Edit /etc/postfix/main.cf and add to the lines added earlier so it looks like the following.
# OpenDKIM milter_default_action = accept milter_protocol = 6 smtpd_milters = inet:localhost:8891 non_smtpd_milters = inet:localhost:8891
Some instructions use a protocol of 2 and others use 6. According to the Milter readme for Postfix 2.6 or greater milter_protocol should probably be 6 and for Postfix 2.3 to 2.5 use a milter_protocol of 2. To find the Postfix version
postconf -d | grep mail_version
Once the configuration is completed then restart the two services.
service opendkim start service postfix restart
The keys can be tested using
opendkim-testkey -d example.com -s dkim -v -v -v
which should have an output similar to
opendkim-testkey: using default configfile /etc/opendkim.conf opendkim-testkey: checking key 'dkim._domainkey.example.com opendkim-testkey: key OK
If you get a message that the key is not secure then this probably can be fixed by checking file and directory permissions.
Send an email to another account and check the headers for the DKIM signature. This is where things went awry. Sometimes the emails are signed and sometimes not. It almost seemed random. Also, an error consistently showed up.
Authentication-Results:mail.example.com; dkim=permerror (bad message/signature format)
Several days of changing settings, reading manpages and searching the internet went nowhere. The log files seemed to be missing anything indicating success but also nothing that jumped out. Finally the somewhat obscure message was found amongst all the messages:
mail opendkim[24436]: 733502C67C: can't determine message sender; accepting
Searching on this message I came across Postfix opendkim and missing From header. Another person that had sunk several days into figuring out this problem. Removing unnecessary headers can avoid exposing information and protect privacy but breaks DKIM. Looking in /etc/postfix/main.cf
# Getting rid of unwanted headers. See: https://posluns.com/guides/header-removal/ header_checks = regexp:/etc/postfix/header_checks
Comment out the header_checks or look in /etc/postfix/header_checks for a line like
/^Received:/ IGNORE
and remove it. It is also possible to use a REPLACE instead of IGNORE instead of removing the line but that will not be covered here.
Restart Postfix and try to send another email. Now the mail log shows
mail opendkim[24436]: CE46C2C67C: DKIM-Signature field added (s=dkim, d=example.com)
The signature appears in the email and we finally get
Authentication-Results: mail.example.com (amavisd-new); dkim=pass (1024-bit key) header.d=example.com
It seems that the issue with header_checks would be fairly common and many people as a result have either spent a great deal of time or given up installing DKIM.
Now that our email looks okay we can perform an additional check of both DKIM and Sender Policy Framework (SPF) by sending an email to check-auth@verifier.port25.com. A reply should be received back with the results of the test.