Setting up SPF and DKIM for email on Bytemark Symbiosis

June 27, 2013

EDIT 17-February-2016: Please DO NOT use these instructions to configure your server for SPF and DKIM. Bytemark Symbiosis now supports this out of the box - please see the following documentation for more information:


I’ve been setting up a new phpBB forum for my homebrew club (LAB) over the last week or so and one of the main problems I found was that all the emails from the forum were going straight to spam in email services such as Gmail. Not very useful when that’s one of the first forms of interaction with the user (activating their account via email).

Thankfully there are ways to make your emails less spammy, (that I never knew about until earlier this week) - SPF (Sender Policy Framework) for letting email recipients know which servers/domains are valid sources of email for your domains; and DKIM (DocumentKeys Indentified Mail) for signing emails sent from your servers using public/private key pairs. These to techniques combined should stop emails being sent to spam automatically (It worked for me, but YMMV).

I run the LAB site on a Bytemark VM using their Symbiosis server set-up. This is basically Debian Linux with a bunch of (automatic) scripts to make setting up new domains, DNS and email as simple as possible - I really like this as it lets me not have to care too much about this stuff. But, out of the box, the emails are not setup with SPF or signed via DKIM - this is in their feature backlog, but it’s not in place yet. So… here are the quick pitted notes of how I set this up for the domains on my server and the sites that I got the information from.

NOTE: This is for a single Bytemark Symbiosis VM running multiple sites handling everything - DNS, email, web server etc. using the stock Symbiosis setup (I’ve not modified any of the base system).


The first (and most simple) thing to set-up was SPF as this is achieved by adding a DNS entry that verifies where emails for this domain name can be sent from.

All this involved was adding the following line to the bottom of the tinydns configuration file for my domain (~/londonamateurbrewers.co.uk/config/dns/londonamateurbrewers.co.uk.txt):


This says that email is only allowed to be sent from the mx. subdomain - exactly what I want. This line was generated by the SPF tool on http://anders.com/projects/sysadmin/djbdnsRecordBuilder/#SPF by simply entering the following information:

I then forced the DNS entry to be propagated to Bytemark’s DNS servers with the following command (or you could just wait 15 minutes for it to happen automatically):

sudo /usr/sbin/symbiosis-dns-generate –upload

Finally, I used http://tools.bevhost.com/spf/, to verify that SPF was set-up correctly for the domain.


Next up was the slightly more complicated DKIM. This involves DNS additions and signing outgoing emails with public/private key pairs. I take no credit whatsoever for solving this one - I knocked together the information from the various different sources in the references section below.

So, first up, we need to generate the keys using openssl, move them to the right location, and ensure they have the right permissions:

cd $HOME
openssl genrsa -out rsa.private 1024
openssl rsa -in rsa.private -out rsa.public -pubout -outform PEM
sudo mv rsa.p /etc/exim4/
cd /etc/exim4/
sudo chown Debian-exim:root rsa.p

Now we have to copy the public key info into DNS. This involves inserting the following line into the tinydns configuration file, (below the SPF entry), and pasting in YOUR public key just after the p=


Again, I then forced a DNS update to take place:

sudo /usr/sbin/symbiosis-dns-generate –upload

Finally, we have to tell Exim (the mail transport agent on Symbiosis servers) to sign emails with this key…

First, create a file called /etc/exim4/dkim_senders and add in the following content (one line for each domain you wish to send singned emails):

*@londonamateurbrewers.co.uk: londonamateurbrewers.co.uk

Now to edit /etc/exim4/symbiosis.d/20-routers/10-dnslookup to look like this:

  # This router routes addresses that are not in local domains by doing a DNS
  # lookup on the domain name. The exclamation mark that appears in “domains = !
  # +local_domains” is a negating operator, that is, it can be read as “not”. The
  # recipient’s domain must not be one of those defined by “domainlist
  # local_domains” above for this router to be used.
  # If the router is used, any domain that resolves to or to a loopback
  # interface address ( is treated as if it had no DNS entry. Note
  # that is the same as, which is commonly treated as the
  # local host inside the network stack. It is not, the default route.
  # If the DNS lookup fails, no further routers are tried because of the no_more
  # setting, and consequently the address is unrouteable.

  debug_print = “R: dnslookup_dkim for $local_part@$domain”
  driver = dnslookup
  domains = ! +local_domains
  senders = lsearch*@;/etc/exim4/dkim_senders
  transport = remote_smtp_dkim
  same_domain_copy_routing = yes
  # ignore private rfc1918 and APIPA addresses
  ignore_target_hosts = : : :\
               : : :\

dnslookup: debug_print = “R: dnslookup for $local_part@$domain” driver = dnslookup domains = ! +local_domains transport = remote_smtp same_domain_copy_routing = yes # ignore private rfc1918 and APIPA addresses ignore_target_hosts = : : :\ : : :\ no_more

And then /etc/exim4/symbiosis.d/30-transports/10-remote-smtp to look like this:

# This transport is used for delivering messages over SMTP connections.

  debug_print = “T: remote_smtp_dkim for $local_part@$domain”
  driver = smtp
  dkim_domain = ${lookup{$sender_address}lsearch*@{/etc/exim4/dkim_senders}}
  dkim_selector = key1
  dkim_private_key = /etc/exim4/rsa.private
  dkim_canon = relaxed
  dkim_strict = false
  #dkim_sign_headers = DKIM_SIGN_HEADERS

  debug_print = “T: remote_smtp for $local_part@$domain”
  driver = smtp

Now run the following commands to copy these config changes across and restart Exim:

cd /etc/exim4/
sudo make
sudo /etc/init.d/exim4 restart

That’s should be about it, now all you have to do is test it out using this tool.