DKIM Test Message

Installing OpenDKIM RPM via Yum with Postfix or Sendmail (for RHEL / CentOS / Fedora) 145


For those who want or need to compile and install OpenDKIM from the source code, you can follow the instructions I wrote in this article.

If you’re looking for the fastest and easiest way to get OpenDKIM running on a RedHat or CentOS system, I currently maintain the OpenDKIM package in the Fedora and EPEL repositories. This article will help you install the RPMs and then configure OpenDKIM with Postfix or Sendmail.

DomainKeys Identified Mail (DKIM) is the up-to-date replacement system for the now obsolete DomainKeys email authentication system. For general information about DKIM, check out http://www.dkim.org/. For more information about the OpenDKIM project, check out http://www.opendkim.org/.

Before you start

This tutorial assumes the following:

  • You are running a “modern” RedHat-compatible Linux distro (RHEL 5/6/7, CentOS 5/6/7, Fedora, etc).
  • You are running a milter-aware MTA, such as Postfix 2.3.3 or newer (do postconf -d mail_version to check) or Sendmail.
  • Your Postfix or Sendmail configuration is currently working (this is very important – you don’t want to troubleshoot two programs at once).
  • If you’re using Postfix, Sendmail is turned off (do service sendmail status to verify).
  • If you’re using Sendmail, Postfix is turned off (do service postfix status to verify).
  • The necessary commands in this tutorial are done as root. If you don’t know what that means, then you probably shouldn’t be doing this. You may be able to get away with just using sudo, but I wanted to make sure I didn’t run into any path issues, so I do it as root.

Install OpenDKIM with Yum

If you’re running Fedora 14 (or newer) or RHEL/CentOS 5 (or newer) then you can use Yum to quickly install OpenDKIM (RHEL/CentOS users must have the EPEL repositories enabled). Just do:

yum install opendkim

This will download and install OpenDKIM with all the default configuration options included below.

For those who like getting their hands dirtier, you can manually download one of my RPMs or even build your own RPM from my Source RPM, which are all available through the Fedora BuildSystem.

Generate keys for signing

Now you’re getting to the fun part. You need to generate a private and a public key (called a keypair) for each of the domains for which you wish to sign mail. The private key is stored away from prying eyes on your server, while the public key gets published in your domain’s DNS records so that receiving mail servers can verify your DKIM-signed mail.

As of version 2.10.1-2 of the OpenDKIM package, the RPM no longer auto-generates a default set of keys on initial start-up. However, immediately following installation, you can run the following as a privileged user to generate a default set of keys in in /etc/opendkim/keys/ using your server’s domain name and the selector name “default. This script will also set the proper ownership and permissions for your default keys:

opendkim-default-keygen

If you want to sign outgoing mail for additional virtual hosts, or use a different selector name than then default, or change any other options, it’s very easy to generate your own keys manually. But if you’re happy with the default keys, you can move on to the next step.

Before building your keys manually, decide what the name of your selector will be. A selector is a unique keyword associated with both keys (public and private), included in all DKIM signatures, and published in via your DNS records. For simplicity, I use the word default as my default selector. Feel free to choose something different, but if you do, you’ll need to use it consistently throughout your setup. Also, while this should go without saying, you should use your mail domain instead of example.com throughout the following steps.

Manually create your keys with:

mkdir /etc/opendkim/keys/example.com
/usr/sbin/opendkim-genkey -D /etc/opendkim/keys/example.com/ -d example.com -s default
chown -R root:opendkim /etc/opendkim/keys/example.com
chmod 640 /etc/opendkim/keys/example.com/default.private
chmod 644 /etc/opendkim/keys/example.com/default.txt

You can do a man opendkim-genkey if you’re interested in what additional options are available when creating your keys. In this example, I used the -D (directory) option, the -d (domain) option, and the -s (selector) options. That’s all you need to get this going.

Edit the configuration files

You’re getting really close now. You need to create and/or edit four files:

  1. /etc/opendkim.conf – OpenDKIM’s main configuration file
  2. /etc/opendkim/KeyTable – a list of keys available for signing
  3. /etc/opendkim/SigningTable – a list of domains and accounts allowed to sign
  4. /etc/opendkim/TrustedHosts – a list of servers to “trust” when signing or verifying

On install, the RPM package should have created a simple /etc/opendkim.conf file on your system. Because signed outbound mail could get flagged as Spam if sent before your DNS DKIM text records are properly set up, the default operating mode set by this file is verification only (v). This means that order to sign outgoing mail, you’ll have to comment, uncomment, and configure some additional options in the configuration file. Use your favorite text editor to open /etc/opendkim.conf and make it look like this:

## CONFIGURATION OPTIONS

# Specifies the path to the process ID file.
PidFile /var/run/opendkim/opendkim.pid

# Selects operating modes. Valid modes are s (signer) and v (verifier). Default is v.
Mode    sv

# Log activity to the system log.
Syslog  yes

# Log additional entries indicating successful signing or verification of messages.
SyslogSuccess yes

# If logging is enabled, include detailed logging about why or why not a message was
# signed or verified. This causes a large increase in the amount of log data generated
# for each message, so it should be limited to debugging use only.
#LogWhy yes

# Attempt to become the specified user before starting operations.
UserID  opendkim:opendkim

# Create a socket through which your MTA can communicate.
Socket  inet:[email protected]

# Required to use local socket with MTAs that access the socket as a non-
# privileged user (e.g. Postfix)
Umask   002

# This specifies a file in which to store DKIM transaction statistics.
#Statistics              /var/spool/opendkim/stats.dat

## SIGNING OPTIONS

# Selects the canonicalization method(s) to be used when signing messages.
Canonicalization        relaxed/simple

# Domain(s) whose mail should be signed by this filter. Mail from other domains will
# be verified rather than being signed. Uncomment and use your domain name.
# This parameter is not required if a SigningTable is in use.
Domain                  example.com

# Defines the name of the selector to be used when signing messages.
Selector                default

# Gives the location of a private key to be used for signing ALL messages.
#KeyFile                 /etc/opendkim/keys/default.private

# Gives the location of a file mapping key names to signing keys. In simple terms,
# this tells OpenDKIM where to find your keys. If present, overrides any KeyFile
# setting in the configuration file.
KeyTable                 refile:/etc/opendkim/KeyTable

# Defines a table used to select one or more signatures to apply to a message based
# on the address found in the From: header field. In simple terms, this tells
# OpenDKIM how to use your keys.
SigningTable                 refile:/etc/opendkim/SigningTable

# Identifies a set of "external" hosts that may send mail through the server as one
# of the signing domains without credentials as such.
ExternalIgnoreList      refile:/etc/opendkim/TrustedHosts

# Identifies a set internal hosts whose mail should be signed rather than verified.
InternalHosts           refile:/etc/opendkim/TrustedHosts

You can do man opendkim.conf for more information on each of the options in this file.

Uncomment the Domain option (and include your actual domain name), the KeyTable, SigningTable, ExternalIgnoreList, and InternalHosts options. Also, since you’ll be using a KeyTable, you can comment the KeyFile option.

Next, you’ll need to create the three text files that you just uncommented in your config file. First, using your favorite text editor, create an /etc/opendkim/KeyTable file that looks like this:

default._dkim.example.com example.com:default:/etc/opendkim/keys/example.com/default.private

The KeyTable file tells OpenDKIM where to find your keys. Each entry in the KeyTable file is a single line for each key location (for example, all of the text in the above example should be on a single line in your file). If you’re going to use multiple keys (to sign mail for virtual domains with different keys, for example), you’ll need to create a separate line in the KeyTable file for each domain, like this:

default._dkim.example.com example.com:default:/etc/opendkim/keys/example.com/default.private
default._dkim.example2.com example2.com:default:/etc/opendkim/keys/example2.com/default.private

Next, you need to create or edit the /etc/opendkim/SigningTable file. A default version of this file should have been installed in /etc/opendkim when you installed the RPM, so just uncomment the following line (or edit the file to include this line) so it reads:

*@example.com default._dkim.example.com

The SigningTable file tells OpenDKIM how to use your keys, as in which senders should use which selectors for their signatures. In the above example, I’m saying that everyone (*) sending mail from the server “example.com” should use the selector named “default.” Again, for multiple domains and/or users, you’ll need multiple lines, like this:

*@example.com default._dkim.example.com
[email protected] default._dkim.example2.com
[email protected] default._dkim.example2.com

In that example, everyone (*) sending mail from the server “example.com” can sign mail and should use the selector named “default.” But only Bob and Doug can sign mail for “example2.com” (also using a selector named default). It’s important to note that the * wildcard symbol will only work if the SigningTable option uses the refile: prefix before the filename (see the opendkim.conf documentation for more details).

Next, create an /etc/opendkim/TrustedHosts file that looks like this:

127.0.0.1
hostname1.example1.com
hostname2.example1.com
example1.com
hostname1.example2.com
hostname2.example2.com
example2.com

The TrustedHosts file tells OpenDKIM who to let use your keys. Because it’s referenced by the ExternalIgnoreList directive in your conf file, OpenDKIM will ignore this list of hosts when verifying incoming mail. And, because it’s also referenced by the InternalHosts directive, this same list of hosts will be considered “internal,” and OpenDKIM will sign their outgoing mail.

IMPORTANT: Make sure you list the IP address for localhost (127.0.0.1) in the TrustedHosts file or OpenDKIM won’t sign mail sent from this server. If you have multiple servers on the same network that relay mail through this server and you want to sign their mail as well, they must be listed in the TrustedHosts file. Put each entry on its own line. An entry can be a hostname, domain name (e.g. “example.com”), IP address, an IPv6 address (including an IPv4 mapped address), or a CIDR-style IP specification (e.g. “192.168.1.0/24”).

It should also go without saying (but I’ll say it anyway) that if you’re planning to sign outgoing mail for remote hosts, your mail server should have been previously configured to allow relaying for those hosts.

Using OpenDKIM with SQL Datasets

For more advanced configurations that are using SQL datasets on a systemd-based server (if you don’t know what this means, then don’t worry — this doesn’t apply to you), the opendkim service may not start after a reboot — and you won’t get any error or warning message to help figure out why.

To solve this, you’ll need to tell systemd to start the opendkim service after the database servers by referencing your database unit file(s) in the “After” section of the OpenDKIM unit file.

For example, if using both MariaDB and PostgreSQL, in /usr/lib/systemd/system/opendkim.service change:

After=network.target nss-lookup.target syslog.target

to:

After=network.target nss-lookup.target syslog.target mariadb.service postgresql.service

Thanks to George Notaras for finding this issue and suggesting the workaround.

Edit your MTA configuration

Now you’re ready to tell your MTA about OpenDKIM.

Postfix Users:

Telling Postfix about OpenDKIM is easy. Just add the following lines to your Postfix main.cf file:

smtpd_milters           = inet:127.0.0.1:8891
non_smtpd_milters       = $smtpd_milters
milter_default_action   = accept

If you’re running a version of Postfix prior to 2.6, you may need to add:

milter_protocol   = 2

See http://www.postfix.org/MILTER_README.html#version for more info.

Don’t restart Postfix yet! You need to have OpenDKIM running first, or you’ll get errors in your maillog.

Sendmail Users:

Edit the .mc configuration file that was used to build your current sendmail.cf file. Add the following line:

INPUT_MAIL_FILTER(`opendkim', `S=inet:[email protected]')

Then build and install a new sendmail.cf. If you don’t know how to build and install a sendmail.cf file, a quick Web search should shove you in the right direction. Explaining how to do that is beyond the scope of these instructions. I will, however, remind you that backing up your current sendmail.cf file is a good idea before you attempt any modifications.

Start OpenDKIM and restart your MTA

It’s time to fire things up! Assuming you’re using bash, do:

hash -r

to rehash your shell so you can find the init script.

Depending on whether your system uses SysV or systemd, start OpenDKIM with either:

service opendkim start

or

systemctl start opendkim

On SysV systems, you should get a message that says:

Starting OpenDKIM Milter:     [  OK  ]

However, if you get an error message such as:

Starting OpenDKIM Milter: opendkim: /etc/opendkim.conf: configuration error at line 6: unrecognized parameter

don’t freak out. You probably just mistyped something in one of the config files. Go to the line number of the file listed, and check your work against the example(s) in this article. Then try starting up OpenDKIM again.

On a systemd system, you can verify that OpenDKIM started properly with:

systemctl status opendkim

You should get something like:

opendkim.service - DomainKeys Identified Mail (DKIM) Milter
   Loaded: loaded (/usr/lib/systemd/system/opendkim.service; enabled)
   Active: active (running) since Tue 2015-03-24 10:29:56 MDT; 46s ago
     Docs: man:opendkim(8)
           man:opendkim.conf(5)
           man:opendkim-genkey(8)
           man:opendkim-genzone(8)
           man:opendkim-testadsp(8)
           man:opendkim-testkey
           http://www.opendkim.org/docs.html
  Process: 6403 ExecStart=/usr/sbin/opendkim $OPTIONS (code=exited, status=0/SUCCESS)
 Main PID: 6404 (opendkim)
   CGroup: /system.slice/opendkim.service
           ââ6404 /usr/sbin/opendkim -x /etc/opendkim.conf -P /var/run/opendkim/opendkim.pid

Mar 24 10:29:56 hostname.example.com systemd[1]: Started DomainKeys Identified Mail (DKIM) Milter.
Mar 24 10:29:56 hostname.example.com opendkim[6404]: OpenDKIM Filter v2.10.1 starting (args: -x /etc/opendkim.conf -P /var/run/opendkim/opendkim.pid)

Once you’ve confirmed OpenDKIM has started, restart your MTA. Postfix users should refresh Postfix with:

postfix reload

and Sendmail users should do:

service sendmail restart

If everything looks good, set OpenDKIM to auto-start on boot. SysV users should do:

chkconfig opendkim on

and systemd users should do:

systemctl enable opendkim

Adding DNS Records

Now that your mail server is signing outgoing mail and verifying incoming mail, you’ll need to put some information in your DNS records to tell other mail servers how your keys are set up, and provide the public key for them to check that your mail is properly signed. Do:

cat /etc/opendkim/keys/example.com/default.txt

The output should look something like this:

default._dkim IN TXT ( "v=DKIM1; k=rsa; "
          "p=MIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQDHY7Zl+n3SUldTYRUEU1BErHkKN0Ya52gazp1R7FA7vN5RddPxW/sO9JVRLiWg6iAE4hxBp42YKfxOwEnxPADbBuiELKZ2ddxo2aDFAb9U/lp47k45u5i2T1AlEBeurUbdKh7Nypq4lLMXC2FHhezK33BuYR+3L7jxVj7FATylhwIDAQAB" )  ; ----- DKIM default for example.com

If you manage your own DNS or have full access to your domain’s zone file, you’ll need to paste the entire contents of the default.txt file at the bottom of your domain’s zone file. If you’re using a web interface to manage your zone file, be careful that the long lines of the public key don’t wrap and create line-feed characters (or fix them if they do). Otherwise, your public key won’t work.

If you’re using a web-based DNS interface (like GoDaddy or CloudFlare), the Name of the TXT record would  default._dkim and the Value of the TXT record would be everything from the first quote to the last quote (starting with “v=). You can ignore the parentheses, semi-colon, and comments at the end. In the above example, what you’d paste in as the value would be:

"v=DKIM1; k=rsa; "
          "p=MIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQDHY7Zl+n3SUldTYRUEU1BErHkKN0Ya52gazp1R7FA7vN5RddPxW/sO9JVRLiWg6iAE4hxBp42YKfxOwEnxPADbBuiELKZ2ddxo2aDFAb9U/lp47k45u5i2T1AlEBeurUbdKh7Nypq4lLMXC2FHhezK33BuYR+3L7jxVj7FATylhwIDAQAB"

If you’re using some other third-party DNS provider, follow their instructions for adding a new TXT Record.

And, as long as you’re messing with your domain’s zone file, now might be a good time to ensure that you already have a valid SPF Record in place. Having both DKIM and SPF in place will increase your chances of having your outgoing mail successfully delivered.

Testing Things Out

As I mentioned in my troubleshooting tips, the best way to see that everything is working on the server side is to keep an eye on your /var/log/maillog file. Do a:

tail -f /var/log/maillog

When OpenDKIM starts (or restarts), you should see lines like:

opendkim[4397]: OpenDKIM Filter: mi_stop=1
opendkim[4397]: OpenDKIM Filter v2.10.1 terminating with status 0, errno = 0
opendkim[27444]: OpenDKIM Filter v2.10.1 starting (args: -x /etc/opendkim.conf)

When you send a mail that gets successfully signed, you should see:

opendkim[22254]: 53D0314803B: DKIM-Signature header added

The best way to check that your signed mail is being authenticated and that your DNS records are properly set up is to use one of the free testing services. My favorites are:

Each of these will tell you if things are working properly, and give you some pointers on troubleshooting if needed.

If you have a Gmail account, you can also send a signed message there for a quick and easy test. address Here’s what a signed message in Gmail will look like:

DKIM Test Message

Look, Ma! My emails have DKIM Signatures!

The signed by: line tells you that the message has been verified as signed by the sender (you may need to press the show details link near the top of the message to see it). I like to click the Show Original link (under the Reply drop-down on the right) to see the signed headers in all their glory. 🙂

Troubleshooting Tips

Tip 1: The best advice I can give when troubleshooting any mail issues (including OpenDKIM) is to start a second shell session in another window and do:

tail -f /var/log/maillog

while you’re starting, stopping, and/or restarting OpenDKIM and your MTA. This allows you to see more details about any errors in your configuration.

Tip 2: If OpenDKIM is starting properly and logging to your mail log, but your outgoing mail isn’t getting signed, the first thing to check is whether the default operating mode is still set to the default verification only (v) instead of sign and verify (sv) in /etc/opendkim.conf. Change the Mode to sv, restart OpenDKIM, and try sending your test message again.

Tip 3: To get the most verbose information from OpenDKIM, make sure the LogWhy option in your /etc/opendkim.conf file is uncommented and set to Yes. If your outgoing mail isn’t getting signed and you want to know why, this should tell you.

Tip 4: If you can’t get things working on your own, I recommend subscribing to the OpenDKIM-Users discussion list at http://lists.opendkim.org/. It’s a low-traffic list with very helpful and friendly members (including me!) who are happy to nudge you in the right direction.

Automating Configuration and Key Generation for Multiple Domains

If you’re hosting a large number of domains, generating keys and editing all the appropriate files can be time-consuming. The following script was submitted by a reader (Almir Duarte Jr.) to help speed up the process. Use at your own risk.

Further reading

  • DKIM.org – the official site for DomainKeys Identified Mail
  • OpenDKIM Project Site – the program I used to get DKIM working
  • Sendmail DKIM – a detailed article from Eland Systems about DKIM. They use the dkim-milter package, upon which OpenDKIM is based. I much prefer the newer OpenDKIM, but this article explains DKIM very well and has some good tips.
  • Mail-DKIM and DKIM-proxy – my first experiments with DKIM were with these tools. I never got it working quite right, but there’s lots of good info there.
  • OpenSPF.org – not technically related to DKIM, but it’s another spam-fighting technique that you should be using if you’re sending email
  • My OpenDKIM GitHub repo – if you’d like to mess with the SPEC file or patches that I use to create the OpenDKIM package in the Fedora & EPEL repos, knock yourself out! Please fork the “develop” branch and submit your pull requests there, as the “master” is intended only for release versions.

Good luck! Please post in the comments with your successes, questions, or suggestions.