DKIM is a sender authentication scheme for signing messages in a way that these messages can be validated by the recipient side. DKIM, which is usually a part of MTA, is based on public-key cryptography therefore the validation process naturally depends on public-private key pair. Signer MTA affixes a digital signature into the message header by “DKIM Signature:” field which will then be used by the verifier side to recover the signer’s public key via DNS and complete the verification.
If DKIM is used, you can absolutely build a positive reputation regarding your domain to help improve delivery but you shouldn’t rely upon it to create an “all emails into Inbox” marvel especially if you have a mass mailing oriented marketing strategy. In terms of authentication, DKIM is one of the serious and highly recommended steps that has to be taken to gratify the growing expectations of huge messaging providers but won’t be the final one.
Although the installation and implementation of DKIM for Postfix slightly differ at variety of *nix types, configuration principles will resemble each other up-and-down. We’ll be implementing it on FreeBSD so let’s get to work by first updating our ports tree if it’s stale.
# portsnap fetch # portsnap update
We’ll use dkim-milter (mail filter) plugin so we have to edit make.conf to compile it to use Postfix port instead of sendmail which is the default option. For further technical info, you may visit http://www.postfix.org/MILTER_README.html
# vi /etc/make.conf
Add the following line into the file;
This setup had been last tested on FreeBSD 8.2-RELEASE at Feb 2011. As dkim-milter has expired and recently it has been removed from the ports tree, we strongly recommend you to read our “Dkim-milter is No Longer Available, How to Use OpenDKIM Instead” guide and consequently move to OpenDKIM.
Navigate to dkim-milter port directory and install the port;
# cd /usr/ports/mail/dkim-milter # make install clean
Copy the sample configuration file as dkim-filter.conf in order to edit it;
# cp /usr/local/etc/mail/dkim-filter.conf.sample /usr/local/etc/mail/dkim-filter.conf # vi /usr/local/etc/mail/dkim-filter.conf
Uncomment KeyList parameter at line 229. We’ll create this file later below to specify our domains that we want to sign.
Travel down to line 489, uncomment and set the socket information with an appropriate port where the filter should listen for milter connections from the MTA;
Our next step is to create separate directories for our email domains in order to store our key pair inside them. Keys will be generated by dkim-genkey tool as two separate files. default.private will hold the RSA private key and default.txt will hold the matching public one in a format that you can insert to your DNS zone file.
# mkdir -p /var/db/dkim/keys/ipsure.com # cd /var/db/dkim/keys/ipsure.com/ # dkim-genkey -r -d ipsure.com
-r Restricts the key for use in e-mail signing only. The default is to allow the key to be used for any service. -d domain Names the domain which will use this key for signing.
-rw------- 1 root wheel 887 Sep 18 10:51 default.private -rw------- 1 root wheel 304 Sep 18 10:51 default.txt
We shall rename these default files to proper subdomain names (selector) which the public key will also be published by. For example if we want to publish the public key under dkim._domainkey.ipsure.com then we’ll set them as;
-rw------- 1 root wheel 887 Sep 18 10:51 dkim -rw------- 1 root wheel 301 Sep 18 17:45 dkim.txt
_domainkey is the standard and the integral part of the whole domain name as the recipient side will particularly query the public key in that manner. But the SELECTOR part is completely up to you and may be whatever you like. Recipient side will find this selector value in your email’s DKIM-Signature: header field.
So I opt dkim as a selector for this implementation and rename the files appropriately.
# mv default.private dkim # mv default.txt dkim.txt
We create our keylist file and append the path of the private key(s) with the relevant domain names one under the other by using “pattern:domain:selector” format.
# touch /var/db/dkim/keylist # vi /var/db/dkim/keylist
We have to enable SMTP-only Milter application inside Postfix configuration file so that milter can handle the emails that arrive via the Postfix server. Insert smtpd_milters parameter into your Postfix main.cf file;
# vi /usr/local/etc/postfix/main.cf
smtpd_milters = inet:localhost:10026
Add the daemon directive to your /etc/rc.conf file in order to set dkim-milter start at system boot time;
# echo 'milterdkim_enable="YES"' >> /etc/rc.conf
Start the dkim-milter;
# /usr/local/etc/rc.d/milter-dkim start
If you get an error such as;
Starting milterdkim. dkim-filter: smfi_opensocket() failed /usr/local/etc/rc.d/milter-dkim: WARNING: failed to start milterdkim
check your log file
# tail -f /var/log/maillog Sep 18 11:05:30 mail dkim-filter: Sendmail DKIM Filter: Unable to bind to port inet:10026@localhost: Address already in use Sep 18 11:05:30 mail dkim-filter: Sendmail DKIM Filter: Unable to create listening socket on conn inet:10026@localhost Sep 18 11:05:30 mail dkim-filter: smfi_opensocket() failed
and change your listening socket port to another one which is not already in use!
# postfix reload
check your logs back again
# tail -f /var/log/maillog Sep 18 11:09:15 nix1 dkim-filter: Sendmail DKIM Filter v2.8.3 starting (args: -l -u mailnull -P /var/run/milterdkim/pid -x /usr/local/etc/mail/dkim-filter.conf)
If everything is ok. then you need to grab the pre-generated TXT record inside dkim.txt and paste it into your DNS zone record (Watch out for the text wraps and missing quotation marks).
# vi /var/db/dkim/keys/ipsure.com/dkim.txt
dkim._domainkey IN TXT "v=DKIM1; g=*; k=rsa; p=MIGfMA0GCSqGSIb3DQ(...)x2ndSUOxbGQhnVbYOD6X49Z9jEtmBJPn1IowIDAQAB"
We may enhance DKIM TXT entries like:
_domainkey.(yourdomain.com). IN TXT "t=y; o=~; r=postmaster@(yourdomain.com)"
t=y means “this domain is currently testing DKIM, verifier side mustn’t treat the messages differently from unsigned e-mails even if the signature fails to be verified”
o=~ means “some e-mails from this domain are signed, some are not”
o=- means “all e-mails from this domain are signed”
r=postmaster@(yourdomain.com) designates responsible e-mail address
After reloading your DNS server it’s time to send a test e-mail to your favorite accounts. If there’s no problem with your setup, you’ll notice an additional “signed-by yourdomain.com” field (click show details) upon receiving the e-mail in your Gmail account. Also a successful DKIM implementation must reveal itself in the message sources;
Authentication-Results: mx.google.com; spf=pass (google.com: domain of firstname.lastname@example.org designates 212.x.x.x as permitted sender) email@example.com; dkim=pass firstname.lastname@example.org
Authentication-Results: mta175.mail.ac4.yahoo.com from=ipsure.com; domainkeys=neutral (no sig); from=ipsure.com; dkim=pass (ok)
But if you face the faulty results in message sources such as;
domainkeys=neutral (no sig); from=ipsure.com; dkim=permerror (no key)
dkim=neutral (bad format) email@example.com
then I can only suggest you to revise your DNS records and check it by using an online tool such as http://dkimcore.org/tools/dkimrecordcheck.html in order to be sure that you’re not breaking something with DNS.
Basically, below NS query should have been giving a healthy response as follows;
# nslookup -q=txt dkim._domainkey.ipsure.com Non-authoritative answer: dkim._domainkey.ipsure.com text = "v=DKIM1\; g=*\; k=rsa\; p=MIGfMA0GCSqGSIb3DQ(...)x2ndSUOxbGQhnVbYOD6X49Z9jEtmBJPn1IowIDAQAB"
Postfix Inside Jails
If you read this topic in search of a solution to your junk folder trouble growing out of your mass mailing strategies, it means that most probably you must be running separate Postfix (and dkim-milter) instances inside multiple jail environments. If you’re doing so, you may notice that the emails originating from your jail(s) are not signed while the ones from the main host are signed perfectly. This is because dkim-filter accepts the jail as an external host due to its different hostname;
# tail -f /var/log/maillog Sep 21 17:45:36 vmta dkim-filter: 439D798BC25 external host vmta.yourdomain.com attempted to send as yourdomain.com Sep 21 17:45:36 vmta dkim-filter: 439D798BC25: no signature data
If you have a such issue, follow the steps below to introduce your jail domain name and/or IP address network as external hosts to dkim-milter in jails.
# cd /usr/local/etc/mail/ # touch InternalHosts.txt # chmod 444 InternalHosts.txt
# vi InternalHosts.txt
# vi /usr/local/etc/mail/dkim-filter.conf
Go to Line 190, uncomment and designate the location of your InternalHosts file;
# /usr/local/etc/rc.d/milter-dkim restart # postfix reload
For further reading about DKIM, visit http://dkim.org
If you’re looking for a complete installation guide of Postfix (Virtual Setup) Dovecot SpamAssassin ClamAV Maia Roundcube (/w MySQL db) on FreeBSD, please see here.