How to Setup DomainKeys Identified Mail (DKIM) with Postfix and FreeBSD

If your mail is always ending up in the "Junk" folder, perhaps it's time to take a look at DomainKeys Identified Mail (DKIM). DKIM is an email authentication framework (or protocol) that tries to minimize the SPAM problem. Your email server will sign every outgoing message with a cryptographic private key. Your DNS server is setup with TXT record in the email's domain that contains a matching public key. The receiving end will take the two keys, and determine if they are a match, thus authenticating your email server.

It's not as complicated as it sounds, and thankfully, open source solutions have come along way, making the implementation very straight forward.

Requirements

  • Tested with FreeBSD 7.0 or later
  • Postfix 2.5 or later installed and running
  • BIND 9.0 or later installed and running
  • Your Domain, Email, and DNS are working properly
  • Your ports tree is up to date

Install The Software

First we need to tell the "make" program to compile dkim-milter using Postfix instead of the default "Sendmail" option. Do this by adding the following line into the "/etc/make.conf" file. The following example uses FreeBSD's default editor named Easy Editor. Make sure you are root before trying to continue.

Open /etc/make.conf with Easy Editor:

edit /etc/make.conf

Add the following to the end of the file:

WITH_POSTFIX=yes

Make the addition as shown above press the ESC key on the keyboard, select "Leave Editor" then save and close the file when prompted. Or if you prefer the GUI, you could achieve the same result with WinSCP on Windows.

Go to the "dkim-milter" port directory and "make install" the port.

cd /usr/ports/mail/dkim-milter
make install

It should take a few minutes to compile and install the software.

Configure dkim-milter

The port installs a sample configuration file in "/usr/local/etc/mail/dkim-filter.conf.sample". We will make a copy of the file so we can edit it to our liking.

cp /usr/local/etc/mail/dkim-filter.conf.sample /usr/local/etc/mail/dkim-filter.conf
edit /usr/local/etc/mail/dkim-filter.conf

Most of the work has been done for us, we only need to go through the file and adjust a few items. Locate the entry named "KeyList" around line 229 and un-comment it. It should read like this:

KeyList		/var/db/dkim/keylist

The "keylist" file is where we will specify the domains we want to sign, the selector used, and the private keys used to sign them with. More on that later.

Scroll all the way down to (nearly) the bottom of the file at about line 489 and un-comment the "Socket" parameter. To keep things simple, we will use an INET socket on the loopback device with port 10026, or any other available port number you prefer. The line should be similar to the following:

Socket			inet:10026@localhost

Save and close the file.

Generate Domain Keys

The next step is to generate the private and public key pairs for your domain(s). We will store these keys in the "/vat/db/dkim/keys/domain.tld" folder as "default" for the private key and "default.txt" for the public key that gets used in the DNS server. To generate the keys we will use the handy-dandy "dkim-genkey" program.

Replace "domain.tls" with your email domain name. If you host multiple domains, repeat these commands for each domain you wish to enable the feature on.

mkdir -p /var/db/dkim/keys/domain.tld
cd /var/db/dkim/keys/domain.tld
dkim-genkey -r -d domain.tld
mv default.private default

Now we add these keys into the "/var/db/dkim/keylist" file. Create the file and open it up in your favor editor.

touch /var/db/dkim/keylist
edit /var/db/dkim/keylist

Each line of the file follows a simple format, "pattern:domain:selector". The "pattern" is almost always going to be "*@domain.tld", the "domain" field is self explanatory. However, the "selector" can be elusive as this field sets up 2 options.

DKIM allows you to have multiple keys for a domain, the selector "chooses" which one to sign outgoing mails with. The "selector" field acts as both the path to the key file and the name of the selected key (which is used later on in DNS). We created all our initial keys in a file named "default" for each domain. You could have named it anything, and you could create additional keys/files for each domain under a different file name. Each file name is the name of the "selector".

For our example, add the following line to "/var/db/dkim/keylist". Remember to replace "domain.tld" with your domain. If you have multiple domains add one line for each domain.

*@domain.tld:domain.tld:/var/db/dkim/keys/domain.tld/default

The line above tells dkim-milter to sign all emails for the domain.tld domain with the private key located in "/var/db/dkim/keys/domain.tld/default" using the selector named "default".

Save and close this file when done.

Configure Postfix

Here we link dkim-milter to Postfix, it's done with a single line.

Open your "/usr/local/etc/postfix/main.cf" file:

edit /usr/local/etc/postfix/main.cf

Add the line as shown below.

smtpd_milters = inet:localhost:10026

Save and close the file.

Enable and Start the Software

In FreeBSD, you have to tell the operating system to allow dkim-milter to run as a service. Edit your "/etc/rc.conf" file as shown.

edit /etc/rc.conf

Add the following Line, then save and close the file.

milterdkim_enable="YES"

Start up the dkim-milter service (or daemon), reload the postfix configuration, and monitor the logs for any errors.

/usr/local/etc/rc.d/milter-dkim start
postfix reload
tail -f /var/log/maillog

If all goes well, hit CTRL+C to exit out of the log file viewer.

Add DNS Records

This last step assumes you are using BIND on FreeBSD. If you use alternate DNS management software (provided by your ISP or hosting), please consult it's documentation on how to add a TXT record to your domain.

This is the glue that ties it all together. Without a DNS record, your DKIM setup is completely non-functional.

the TXT record that you will add is conveintly pre-generated for you in "/var/db/dkim/keys/domain.tld/default.txt". Copy the entire contents of that file, and paste at the end of your zone records file. I find that Webmin is very helpful when managing the BIND DNS server.
You should have something similar to the following:

domain.tld.	IN	SOA	ns.domain.tld. root.domain.tld. (
1125170171
10800
3600
604800
38400 )
domain.tld.         IN NS ns.domain.tld.
mail.domain.tld. IN A 123.156.189.123
ns.domain.tld.         IN A 123.156.189.124

default._domainkey IN TXT "v=DKIM1; g=*; k=rsa; p=00EBAQUAA4GNADCBiQKXXXXXXXXXXXXXXX...." ; ----- DKIM default for domain.tld

Save the records file and reload your zone information using the "rndc reload" command.

rndc reload domain.tld

Notice the name of the selector in the TXT record "default._domainkey...". For each key file (aka "selector") located in "/var/db/dkim/keys/domain.tld/" and "/var/db/dkim/keylist", you will have a corresponding DNS TXT record. Having the ability to use multiple keys and "select" one, improves security.

Send an Email

You're all set!

Send your self a test email then look at the message source code. You'll see a header named "DKIM-Signature:", this verifies that everything is working properly on the mail server's end.

Send your self a test email to a gmail account, open the message in gmail and view the message details. Look for the field "signed-by domain.tld" where "domain.tld" is your domain name. This verifies that everything is functional.