James Aylett: DKIM with exim, on Debian

Published at
Tuesday 22nd November, 2016

DKIM is “DomainKeys Identified Mail”, one of a number of technologies designed to let your email flow freely to its intended recipients, even while the world is full of spam. It’s part of something called DMARC, which is an overall statement of how you’re using various email protection technologies.

DMARC is getting increasing amounts of attention these days, within governments and in the private sector. If you implement it correctly, your email is more likely to be delivered smoothly to GMail, Hotmail and AOL among others. This year the UK government moved to using strong DMARC policies, and it’s gradually becoming an accepted part of best practice.

This brief article should give an up to date view of how to set things up if you’re using exim4 on Debian (exim 4.84 on Debian 8 at time of writing). It assumes that you’re comfortable administrating a Debian machine, and in particular that you have at least a basic understanding of exim.

Some background on DKIM

DKIM works in the following way:

Webmail systems like GMail take care of DKIM for you, providing you either use their interface directly, or send your mail out through them. But if you run your own email server, you need to set things up yourself.

DKIM signing for your outgoing email

This is based on an article by Steve Kemp on the Debian Administration website. I’ve simplified the instructions slightly, and corrected what appears to be a single error.

Install the right version of exim4

Debian has two versions of exim: “light” and “heavy”. You’re probably using light, which is the default, but you need heavy for DKIM signing support. You should be able to do the following without any interruptions to email service, because exim configuration is separate from the light and heavy packages:

apt-get install exim4-daemon-heavy
/etc/init.d/exim4 restart
apt-get purge exim4-daemon-light

Generating the keys

We’ll store our cryptographic keys in /etc/exim4/dkim. Except for the first two lines, you can just copy the following straight into a root shell (or make a script out of them if you’re going to be doing this a lot).

DOMAIN you just want to set to the domain part of your email address. SELECTOR will identify your key in the DNS. You’ll want to be able to change keys in future, and one way of making this easy is to use dates.

export DOMAIN=mydomain.com # change this to your own domain!
export SELECTOR=20161122 # a date is good for rotating keys later
cd /etc/exim4
# Ensure the dkim directory exists
test -d dkim || (umask 0027; mkdir dkim; chgrp Debian-exim dkim)
# Generate the private key
OLD_UMASK=`umask`; umask 0037
openssl genrsa -out $DOMAIN-private.pem 1024 -outform PEM
# Extract the public key
openssl rsa -in $DOMAIN-private.pem -out $DOMAIN.pem -pubout -outform PEM
umask $OLD_UMASK; unset OLD_UMASK
chgrp Debian-exim $DOMAIN{-private,}.pem
# Format the public key for DNS use
echo -n 'v=DKIM1; t=y; k=rsa; p=';\
sed '$ { x; s/\n//g; p; }; 1 d; { H; d; }' $DOMAIN.pem

The very last line reads the public key file and converts it into the right format to use as a DNS record. Apart from some stuff at the start, this involves stripping the comment lines at the start and end, and then squashing everything else onto one line, which we do using sed(1).

Note at this point we haven’t placed the key files into /etc/exim4/dkim – they’re still in /etc/exim4. This is because we want to set up the DNS record (so others can verify our signatures) before we start signing using our new private key.

A note about key length: here, we’ve created a 1024 bit private key. You can create a longer one, say 2048 bits, but some DNS hosts have difficulty with the length of record generated (although Google have documented a way round that). I hope that 1024 will continue for some time to be sufficient to avoid compromise, but don’t take my word for it: check for the latest advice you can find, and if in doubt be more cautious. If you need to split a key across multiple DNS records, ensure you test this carefully.

Setting up the DNS record

Now you need to create a DNS record to contain the public key. The last line of the above commands printed out the value of that DNS record, which will start “v=DKIM1; t=y; ...”. The name will be SELECTOR._domainkey.mydomain.com. The type will be TXT (which these days is mostly a general-purpose type for DNS uses that don’t have their own type).

In a lot of DNS control panels, and in most DNS server zone files, you don’t need to include your domain itself, so you’ll just need to add something like:

SELECTOR._domainkey TXT v=DKIM1; t=y; ...  from above

Configuring exim

Exim on Debian already has suitable configuration to create DKIM signatures; it just needs configuring appropriately. We can do this by adding lines to (or creating) the /etc/exim4/exim4.conf.localmacros file, which is read in immediately before the main configuration file. We want the following:

# DNS selector for our key.
DKIM_SELECTOR = 20161122

# Get the domain from the outgoing mail.
DKIM_DOMAIN = ${lc:${domain:$h_from:}}

# The file is based on the outgoing domain-name in the from-header.
DKIM_FILE = /etc/exim4/dkim/DKIM_DOMAIN-private.pem

# If key exists then use it, if not don't.
DKIM_PRIVATE_KEY = ${if exists{DKIM_FILE}{DKIM_FILE}{0}}

Once you’ve added these lines, you should restart exim (service exim4 restart or similar).

There are three important macros here (the fourth, DKIM_FILE, is just to avoid duplication and potential errors in configuration):

So this configuration says, simply: if there’s a file /etc/exim4/dkim/*DOMAIN*-private.pem for the domain I’m sending from, then DKIM sign that email using the key in that file and the given selector.

Note that this can be different for every email. If you know that you’ll only ever send email from one domain for this server, then you can simplify this configuration even further. However, in practice I’ve always run mail servers for multiple domains, and it’s easy enough to set this up from the beginning.

All the domains you send from that support DKIM will use the same selector, but you could replace that with a lookup to be able to vary things if you wanted. (Similarly, you could include the DKIM_SELECTOR in the DKIM_FILE, which could make rotating keys easier in future.)

And enabling DKIM signatures

All the configuration is in place, but the key files aren’t in /etc/exim4/dkim, so let’s move them into place.

mv /etc/exim4/$DOMAIN*.pem /etc/exim4/dkim

Checking this works

mail-tester.com provides a simple way to test things like DKIM setup. Go to the site, and it’ll give you an email address. Send an email to it from your server, and it’ll show you a useful report on what it saw. DKIM is in the “authenticated” section, along with SPF, DMARC and some other details.

If this didn’t work, then you need to go digging. The first thing to look for is in the exim mainlog (/var/log/exim4/mainlog). If you have a line like this:

2016-11-21 18:21:27 1c8tDb-0003IV-NR DKIM: signing failed (RC -101)

then you have some work to do to figure out what went wrong. (-101 is PDKIM_ERR_RSA_PRIVKEY, which you can chase through the code to find that it means exim_rsa_signing_int() returned an error, but that’s not helpful on its own.)

What you want to do is to raise exim’s logging verbosity. You can do this with another line in the local macros file:

MAIN_LOG_SELECTOR = +all

This macro is used as the default for log_selector, which Exim documents in a detailed if largely unhelpful fashion. +all should throw a lot more detail into your mainlog that will help you figure out what’s going on.

Rotating your keys

You are advised to “rotate” your DKIM keys (ie generate new ones, get them into the DNS and then start using them for signing) regularly; I suggest either every three or six months. (Three months conveniently matches the refresh period for Let’s Encrypt certificates.)

In order to do that, you basically do the same thing as above: first you create the new keys, and add the public key as a new DNS record using a new selector. Then you want to wait long enough for that DNS record to appear (which depends on how your DNS hosting works, but usually a few minutes is enough for a completely new record). Then you can move the new key files into place and flip the selector in your exim configuration (don’t forget to restart exim).

This is the point where putting the selector into the filename can help; you can move the files into place first, then flip the selector and restart exim to start using the new keys.

What next?

Once you have DKIM set up, you probably want to add in SPF. Once that’s there, you can tie them together into a public policy using DMARC. Google has a support article on adding a DMARC record, including advice on gradual rollouts.

If the steps in this article don’t work for you, please get in touch so I can update it!