Introduction
Lately my mail server started to get refusals of emails from large mailing systems like AOL, Yahoo etc.
I can’t blame them for trying to minimize the SPAMS to their clients.
Although using an approved relay service is a good solution,
if you want to take care of it yourself here is OpenDKIM at the rescue.

Principle
The mail server sends an email with an individual domain key in the mail header. The receiving server checks the key in the header against the one in the DNS record of the sender’s domain. If they match the email is seen as legitimate email.

References
These instructions are inspired from the helpful site http://blog.tjitjing.com/index.php/2012/03/guide-to-install-opendkim-for-multiple-domains-with-postfix-and-debian.html and expanded with a script. They relate only to the installation of the standard Debian Squeeze version.

Installation of DKIM
The standard Debian Squeeze version of openDKIM is about 2 years old but works well. If you want to install the latest version though you could get it from compile it yourself at http://packages.debian.org/source/squeeze/opendkim.

1.Install the Debian Squeeze openDKIM package
apt-get install opendkim
or if in Debian Wheezy
1.Install the Debian Wheezy openDKIM and its tools package
apt-get install opendkim opendkim-tools

2. Edit /etc/opendkim.conf
Content:
KeyTable /etc/opendkim/KeyTable
SigningTable /etc/opendkim/SigningTable
ExternalIgnoreList /etc/opendkim/TrustedHosts
InternalHosts /etc/opendkim/TrustedHosts
# Optional - To show more information in logs
LogWhy yes

3. Create the config directories and files
mkdir -p /etc/opendkim/keys
touch /etc/opendkim/KeyTable
touch /etc/opendkim/SigningTable
touch /etc/opendkim/TrustedHosts

4. Edit /etc/opendkim/TrustedHosts
Note: Here you enter all domains, hostnames and/or ip’s / Subnets that should be handled by OpenDKIM.
Don’t forget localhost.
Content example:
127.0.0.1
localhost
x.253.204.64
x.253.204.32/27

5. Edit /etc/default/opendkim
Uncomment this line:
SOCKET="inet:12345@localhost" # listen on loopback on port 12345

6. Edit /etc/postfix/main.cf
Add the following lines
milter_default_action = accept
milter_protocol = 6
smtpd_milters = inet:127.0.0.1:12345
non_smtpd_milters = inet:127.0.0.1:12345

Note: In the above configuration I use 127.0.0.1 instead of ‘localhost’ to prevent the following warning in the logs.
warning: connect to Milter service inet:localhost:12345: Connection refused
The reason being that in Wheezy Postfix sees the IPv4 and IPv6 of ‘localhost’ and tries 2 times in which the try at IPv6 fails with this warning.

6. Edit /etc/postfix/master.cf
Add the following option ‘,no_milters‘ at the end of the line: eg.
127.0.0.1:10025 inet n - n - - smtpd
# .... Here I didn't show all the options which are irrelevant for this issue.....
-o receive_override_options=no_header_body_checks,no_unknown_recipient_checks,no_milters

7. Generating individual domain keys and configuring OpenDKIM for per domain.
Principle:
I order for Postfix/OpenDKIM to send/verify a key in each email’s header for which DKIM should be used, the following needs to be done per domain:
– Create a domain private key and configure OpenDKIM so it adds(outgoing) or verify the key(incoming) in the email’s header.
– Generate a domain key and add it to the Free-Text DNS record of the domain.

Here you have 2 choices:
– The easy method(using a script like the one below)
– The hard method(Manually)

The easy method

1. Run this script which generates the DKIM Key and configures OpenDKIM for each domain given.
Command: add_domains_opendkim <DomainName> [DomainName] [DomainName] …..
DomainName should be the root domain (without the www)
eg.
add_domains_opendkim example.com example.de example2.com

Script: /root/bin/add_domains_opendkim
Content:
#!/bin/bash
# Authors: Pierre Burri-Wittke/Michel Bisson
# 9. March 2013
# Purpose: Generates DNS-Txt keys and configures OpenDKIM for one or multiple domains
#===========================================
# Verifying the entries
if [ "$#" -lt 1 ]; then
echo "ERROR: Wrong number of parameters"
echo "Usage: add_domains_opendkim [DomainName] ....."
echo "eg. add_domains_opendkim example.com example.de example2.com"
exit 1
fi
#
# Checking if OpenDKIM is installed and if yes creating the necessary data directory
if ! [ -d /etc/opendkim ]; then
echo "ERROR: The package OpenDKIM is not installed. Install it and rerun this command."
exit 2
else
mkdir -p /etc/opendkim/keys
fi
#
# Verifying the given domains and skip them if errors or already configured
for domain ; do
# Check the mail handling resolving
if ! (host $domain | grep -q 'is handled by'); then
echo "Domain $domain doesn't resolve well. Skipping"
echo "Output:"
host $domain
#
# Check if the domain is already configured in openDKIM
elif (grep -q "$domain default._domainkey.$domain" /etc/opendkim/SigningTable); then
echo "Domain $domain is already configured in /etc/opendkim/SigningTable. Skipping"
elif (grep -q "$domain default._domainkey.$domain" /etc/opendkim/KeyTable); then
echo "Domain $domain is already configured in /etc/opendkim/KeyTable. Skipping"
#
# All ok, then generate the key and configure OpenDKIM
else
mkdir /etc/opendkim/keys/$domain
echo " "
echo "Generate the keys..."
cd /etc/opendkim/keys/$domain
opendkim-genkey -r -d $domain
chown opendkim:opendkim default.private
ls -l /etc/opendkim/keys/$domain
#
echo " "
echo "Adding following lines in /etc/opendkim/KeyTable & /etc/opendkim/SigningTable"
echo " default._domainkey.$domain $domain:default:/etc/opendkim/keys/$domain/default.private"
echo "default._domainkey.$domain $domain:default:/etc/opendkim/keys/$domain/default.private" >> /etc/opendkim/KeyTable
echo " $domain default._domainkey.$domain"
echo "$domain default._domainkey.$domain" >> /etc/opendkim/SigningTable
echo " "
#
echo "-------------------- TODO ----------------------"
echo "Now copy the record below in your DNS (until the end of the domain! Do not include lines with '***')"
echo "DNS: Free Text Entries/freier Textentraege of domain "
echo " "
echo "*** $domain *** ---------------------------"
cat /etc/opendkim/keys/$domain/default.txt
echo "*** $domain *** ---------------------------"
result=true
fi
done
#
# Restart OpenDKIM if at least one new domain was registered in OpenDKIM
echo " "
if $result ; then /etc/init.d/opendkim restart ; fi

Now the hard Method…Manual

1. Generate key
(example here with domain: domain.com)
mkdir -p /etc/opendkim/keys/mydomain.com
cd /etc/opendkim/keys/mydomain.com
opendkim-genkey -r -d mydomain.com
chown opendkim:opendkim default.private

2. Add domain to KeyTable /etc/opendkim/KeyTable
nano /etc/opendkim/KeyTable
Add line:
default._domainkey.mydomain.com mydomain.com:default:/etc/opendkim/keys/mydomain.com/default.private
3. Add domain to SigningTable /etc/opendkim/SigningTable
nano /etc/opendkim/SigningTable
Add line:
mydomain.com default._domainkey.mydomain.com
4. Display the DNS key
cat /etc/opendkim/keys/mydomain.com/default.txt

Restarting OpenDKIM:
/etc/init.d/opendkim restart

Note: In OpenDKIM 2.0.1 domain names are case sensitive (supposed to be fixed from 2.3.1 but I have not tested).
This means that in the above example an email from info@mydomain.com will be signed, but an email from info@MyDomain.com will not be signed.
The workaround is to add one extra entry for MyDomain.com to SigningTable.

The DNS entry

Whether you are using the easy way (script) or the manual way you still have to enter the key in DNS manually for each domain.
This key, displayed by the above script or by the step 4 in manual mode, is a single line and looks like this:
default._domainkey IN TXT "v=DKIM1; g=*; k=rsa; p=MIGfMA0GCSqGSIb3DQEBAQUAA4....long hash.......PBODxsDCEJwHEyFpQIDAQAB" ; ----- DKIM default for mydomain.comYou need to enter the full line in a Free Text record of the domains DNS.

Note 1: Together with SPF authentication(http://www.openspf.org/SPF_Record_Syntax) this should present a very good email authentication method.

Note 2: Although the OpenDKIM configuration file offers the possibility of authenticating sub domains senders(SubDomains yes), in this version it doesn’t seem to work at all. For example, when a mail is sent from a system user in the mail server, it will be identified as user@mail.server.com and not user@server.com for which DKIM is configured. I don’t know if this feature is working in the newer versions though.

Verifying the DKIM DNS record

Example for the domain ‘itmatrix.eu’
Command:
dig default._domainkey.itmatrix.eu TXT
Result:
.......
;; ANSWER SECTION:
default._domainkey.itmatrix.eu. 600 IN TXT "v=DKIM1\; k=rsa\; p=MIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQC/H98o5XmzkUtnvvtZ0+T64xsKNYsWXOXLi0xkQdqK0tq18CV0rZT1+uCqQmov/uoS/RgxE5omvNuzFJR8zt4WPHORGe+UeZr9h0q/eEntmIhx9Sg1vWREKeZcDw0sUMzZRMN0/GrjVdZYKH89vfJeL0awtqkQ4h8Sbonbwh3u2QIDAQAB"
.......