The importance of a certain anti-spam-method is not always easy to measure: with DKIM, the DomainKeys Identified Mail, it gets harder again.

What DKIM is about should best be explained by different sites:

That being said, DKIM is simplified a solution to ensure that a given already signed message is verifiable being sent from the server mentioned in the message. The method relies on asymmetrics cryptography with the public key being deployed as a DNS record.

A pair of private and public keys is generated with a given “selector” and a domain name. The public key is stored in a TXT record in the form of “$selector._domainkey.$domain”, the private key should not be exposed to the public ;-). With said private key, messages are signed. The signature may then be later verified using the public key from DNS.

DKIM is not a solution to identify a certain given message as spam, but to ensure the verifiable upstream of a message. This allows to identify Phishing mails using the orginal sender domain (like, etc.), as they cannot use the correct DKIM keys.

On Debian Wheezy with Postfix as a MTA, OpenDKIM as a milter is the preferred way. There are other solutions like using amavisd-new or dkim-filter as well, but those did pose other problems, especially when using multiple domains on one server.

Amavis requires a different key for each domain, so the deployment for new domains is complicated.

With OpenDKIM, multiple domains on a single server may be signed with only one selector.

This blogpost does rely on the following external sources. Please visit the pages for additional information, if required:

The domain used for signing the mails is the same as the hostname of Postfix (“$myhostname”). The selector contains the (short) hostname and the current year (to allow the yearly change of the signing key as well as a verification of old signatures after the change), resulting in my case in:


The required steps to fully enable DKIM signatures when sending messages are the following:

  • install the packages:
    aptitude install opendkim opendkim-tools
    1. create the folders for storing the configuration files and some statistics with the appropriate permissions:
      mkdir /etc/opendkim /var/log/opendkim
      chmod 0700 /etc/opendkim /var/log/opendkim
      chown opendkim:opendkim /etc/opendkim /var/log/opendkim
    2. In /etc/default/opendkim, change the listener socket:
    3. Change or add the configuration directives in /etc/opendkim.conf:
      Syslog yes
      SyslogSuccess yes
      LogWhy yes
      UMask 002
      KeyFile /etc/opendkim/dkim.key
      Selector OURSELECTOR
      OversignHeaders From
      AutoRestart yes
      Background yes
      Canonicalization relaxed/relaxed
      DNSTimeout 5
      Mode sv
      SignatureAlgorithm rsa-sha256
      SubDomains no
      Statistics /var/log/opendkim/dkim-stats
      KeyTable /etc/opendkim/dkim-keytable
      SigningTable refile:/etc/opendkim/dkim-signingtable
      ExternalIgnoreList refile:/etc/opendkim/TrustedHosts
      InternalHosts refile:/etc/opendkim/TrustedHosts

      The value for the “Selector”-Parameter should be changed to your needs, as described above!
      Note the “refile:”-specification of the filename. Without this, OpenDKIM would treat the given “datastet” as a single Key-Value-store. With “refile:”, the key is treated as a regular expression, allowing the use of wildcards.

    4. The content of /etc/opendkim/TrustedHosts is pretty straight forward: list all hosts, which mail gets signed in any case. Only localhost (or at least not external network) should be specified!

      Mail sent from a SASL authenticated connection will be signed anyway.

    5. next up, we create the actual KeyTable. This file contains each selector/domain we want to use with the actual location of the corresponding private key:

      Again, use the selector and the domainname previously specified!

    6. OpenDKIM uses the SigningTable in /etc/opendkim/dkim-signingtable to find the selector for a given sender address. As stated before, with “refile:” in the main configuration file, we are now able to use wildcards. OpenDKIM now signs every outgoing message with our single selector:
    7. Our configuration for OpenDKIM is now almost complete. The only missing part is the actual public/private key. The key is generated using OpenSSL and has a length of 1024 bit (I tried longer keys of 2048 bit, which could not be verified afterwards):
      openssl genrsa -out /etc/opendkim/dkim.key 1024
      openssl rsa -in /etc/opendkim/dkim.key -out /etc/opendkim/rsa.public -pubout -outform PEM

      OpenSSL does not embed any information as in X.509-certificates, so the key is independent of any certain host. Also, it does not need to be signed by a CA, as it isn’t a certificate at all 🙂

    8. To ensure proper permissions, we set read-only permissions and change the owner:
      chown opendkim:opendkim /etc/opendkim/dkim.*
      chmod 0600 /etc/opendkim/dkim.*
    9. The public key, stored in /etc/opendkim/rsa.public, has now be published as a TXT record. The format of this record is the following:
      "v=DKIM1; p=$PUBLICKEY"

      The placeholder “$PUBLICKEY” has to be replaced by the contents of the public key, without the first and last line and without any line breaks.
      How to actually create the DNS record is beyond this tutorial 🙂
      To verify the entry, I’d like to use “dig”:

      # dig +short -t TXT
      "v=DKIM1\; p=MIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQC6+19du037xwYRo0vVckAQcpi9A3sGpcfxZEo5zNarCmcsOIZyf0Chek7BYOoLGbOqwvWy26o3ByJwriHK2x1NMu4tS/DUO5PmO1zy/y432L3VoBfmAjT20NxFEvRCxNuQYYS1SthpFnOdRLmGbdqNXY37MI/2+Oa2hVn40Bi1NwIDAQAB"
    10. As a final step, Postfix has to connect to OpenDKIM when new messages should be delivered. The main configuration file, /etc/postfix/, gets some new entries:
      # DKIM
      milter_default_action = accept
      milter_protocol = 2
      smtpd_milters = inet:localhost:8891
      non_smtpd_milters = inet:localhost:8891

      Make sure to specify the same inet-socket as in /etc/default/opendkim!

    11. after a restart of the involved daemons (namely OpenDKIM and Postfix), new messages by OpenDKIM will appear in the syslog:
      Jan  1 02:31:10 opendkim[22680]: 9F95E4037C: DKIM-Signature header added (s=hermes2014,

      OpenDKIM signs every message submitted using auth credentials and additionally all messages received from trusted hosts.

    12. OpenDKIM also verifies incoming messages with DKIM signatures:
      Jan 1 02:31:44 opendkim[22680]: 0B2A94037B: [] not internal
      Jan 1 02:31:44 opendkim[22680]: 0B2A94037B: not authenticated
      Jan 1 02:31:44 opendkim[22680]: 0B2A94037B: DKIM verification successful

      SpamAssassin uses the signatures as well. As DKIM itself does not ensure proper spam/antispam, SA only uses larger scores if the verification of the signature fails.

    13. For Amavis, just insert one additional configuration directive, e.g. in /etc/amavis/conf.d/50-user:
      $enable_dkim_verification = 1;

      There is a single drawback of the described method: GMail and probably others will display the domain of the DKIM signature (here: ““) to the recipients:

display of DKIM domain at GMail

If this poses an issue, each domain should receive an individual DKIM key – but makes this page obsolete 🙂

At the end, some additional remarks:

  • Individual signing keys should be preferred anyway, if possible!
  • Multiple signatures in a single mail are not a problem. Open-DKIM logs those as well.
  • OpenDKIM supports reading data from MySQL, if the binary is compiled against the corresponding libraries. With this, new signing domains may be added dynamically and thus reducing the overhead when new domains are added. Unfortunately, this was not used for the Debian packages.
  • DKIM should be combined with Author Domain Signing Practices (ADSP) and Authorized Third-Party Signers (ATPS), which will be part of another article.

Next Post Previous Post