How to get DKIM and DomainKeys working with Postfix on RHEL 5 / CentOS 5 using OpenDKIM and dk-milter 21


Before proceeding with this tutorial, and at the risk of possibly overstating what is obvious to some, I want to make three things clear:

  1. DomainKeys and DKIM are not the same thing. They are two different methods of signing and verifying email.
  2. DomainKeys is now an outdated technology (the nicer sounding technical term is an “historical protocol”). Although some mailers may still sign their mail with DomainKeys, the technology has been abandoned and is no longer being developed. Basically, you no longer need it.
  3. DKIM (which stands for DomainKeys Internet Mail) is the new standard, and is therefore the method I recommend for those looking to sign outgoing and/or verify incoming emails.

I’ve already written an easy-to-follow tutorial explaining how to use OpenDKIM to set up DKIM on a RHEL or CentOS server running the Postfix mail server. It gets lots of comments, most of them positive, and the most common one being:

“Thanks, I got DKIM working. Now how do I get DomainKeys working, too?”

My usual reply is:

“You don’t have to. DomainKeys is outdated. DKIM is the new standard. You won’t get any extra credit from receiving mail servers for using both, so you can just use OpenDKIM and you’re good to go.”

However, that same question keeps getting asked… so I’ve reluctantly decided to write this follow-up tutorial for those who just can’t sleep at night unless they have DomainKeys working.

Again, DomainKeys is an outdated standard, so under no circumstances would I ever recommend using only DomainKeys to sign your outgoing mail. Eventually, it will go the way of the Dodo. But, if you really, really, REALLY want to use DomainKeys, then the only way you should even consider doing do is to first set up DKIM using OpenDKIM (by following the steps in my earlier tutorial), and then set up DomainKeys by re-using and relying on as much of of your DKIM installation as possible.

Before you start

This tutorial assumes the following:

  • You are running a “modern” RedHat-compatible Linux distro (RHEL 5, CentOS 5, Fedora, etc). I was running CentOS 5.5 when I did this.
  • You are running Postfix 2.3.3 or better (do postconf -d mail_version to check).
  • You have already set up DKIM using OpenDKIM as explained in my earlier tutorial. I make updates to that tutorial from time to time, so it’s a good idea to read through it again just to compare your configuration to make sure it’s up to date.
  • Your Postfix configuration is  currently working and successfully signing outgoing mail using DKIM (this is very important – you don’t want to troubleshoot two or three programs at once).
  • 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 just used su – root.

Of course, these steps will most likely work with slighter earlier or slightly later versions of RHEL/CentOS and/or Postfix. I used CentOS 5.5 and Postfix 2.8 to get this working on my system.

Set up DKIM first

I know I sound like a broken record, but to use this tutorial, you must already have OpenDKIM running on your system using the configuration explained in my earlier tutorial, because much of configuration of DomainKeys in this tutorial relies on file locations and settings from my DKIM tutorial. If your configuration is different, and you still choose to follow this tutorial, you do so at your own peril. :)

Download and install dk-milter

After you’ve got DKIM installed and working with OpenDKIM per my other tutorial, you’re ready to install dk-milter, which provides DomainKeys support. We’ll be using dk-milter version 1.0.2-1, which was the final version before the project was abandoned.

IMPORTANT: Do not confuse the dk-milter package with the dkim-milter package. dkim-milter is for DKIM, and it’s the antecedent to the OpenDKIM program. I recommend OpenDKIM because it’s much easier to set up, more flexible, and better supported, which is why it’s the I only method I use. dk-milter is for DomainKeys only.

TopDog Software has been kind enough to build RPMs for both the 32-bit and 64-bit versions of RHEL 5 / CentOS 5.

UPDATE: As of February 2011, the RPMs provided by TopDog Software are no longer available. Not to sound repetitive, but this should come as no surprise as DomainKeys is a deprecated and outdated technology, which has been completely replaced by DKIM, so these files are going to be harder and harder to find. A Google search of the filenames might help, and a visitor named Sooraj has posted a comment about building your own RPMs from dk-milter source files. To help in your search, the filenames for the final 32-bit and 64-bit RPMs were: dk-milter-1.0.2-1.i386.rpm and dk-milter-1.0.2-0.x86_64.rpm. You can also download the source code from the original dk-milter SourceForge page. Beyond that, you’re on your own. Good luck!

Presuming you can find (or build) an RPM for dk-milter, install the appropriate one for your system with either:

rpm -Uvh dk-milter-1.0.2-1.i386.rpm

or

rpm-Uvh dk-milter-1.0.2-0.x86_64.rpm

Modify the default dk-milter configuration

The RPM you installed copied the necessary binaries and default configuration files for dk-milter. However, we won’t be using the default settings. Because you already chose a selector, created keys, and set up your DNS records when you set up OpenDKIM, we can re-use the same selector, keys, and DNS records in dk-milter with a few simple modifications.

Remember your selector

When you configured OpenDKIM, you already decided the name of your selector. Your selector is a unique keyword that is associated with both keys (public and private), included in all the signatures, and is published in your DNS records. For simplicity, I chose the word default as my default selector in the OpenDKIM tutorial, and will do the same here. If you chose something different, remember to use it consistently in this tutorial, too. It just needs to be the same as the one you used with OpenDKIM.

Also, while this should go without saying, you should also use your mail domain instead of example.com throughout the following steps.

Edit the dk-milter configuration file

Use your favorite text editor to open the default dk-milter configuration file, which is located at /etc/sysconfig/dk-milter. By default, all the values in that file are commented out, meaning that unless you change them now, dk-milter will use the settings from its init script when it starts up.

Uncomment and edit the necessary lines in the file so that it appears as follows:

# Default values
#
USER="opendkim"
PORT="inet:10035@localhost"
SIGNING_DOMAIN="example.com"
SELECTOR_NAME="default"
KEYFILE="/etc/opendkim/keys/${SIGNING_DOMAIN}/${SELECTOR_NAME}"
SIGNER=yes
VERIFIER=no
CANON=simple
REJECTION="bad=r,dns=t,int=t,no=a,miss=r"
EXTRA_ARGS="-h -l -D -i /etc/opendkim/TrustedHosts"
SYSCONFIG="/etc/sysconfig/dk-milter"
MILTER_GROUP="opendkim"

# User configuration
#
#PORT0="inet:10034@localhost"
#SIGNER0=no
#PORT1="inet:10035@localhost"
#VERIFIER1=no
#...

Notice that we’re referencing the opendkim user and group on lines 3 and 14 of this file, because the directory and private key you previously set up for DKIM is owned (and can only be read by) the opendkim user and group.

Also notice on line 12 that we’re re-using the /etc/opendkim/TrustedHosts file you set up for OpenDKIM. This is comparable to the InternalHosts directive in your OpenDKIM configuration file. You’re telling dk-milter that these domains are internal (with the -i flag), so it’s OK to sign their outgoing mail.

Finally, notice that I left the User configuration settings on lines 16-22 commented out. You can delete them if you want, since we won’t need them for this implementation.

Edit your Postfix configuration

Since you already added lines to your Postfix main.cf file to tell Postfix how to interact with OpenDKIM, you can just add the milter information for dk-milter to the end of those same lines. Find the lines in your Postfix main.cf that look like this:

smtpd_milters = inet:localhost:8891
non_smtpd_milters = inet:localhost:8891

and edit them to look like this:

smtpd_milters = inet:localhost:10035, inet:localhost:8891
non_smtpd_milters = inet:localhost:10035, inet:localhost:8891

Notice that I put the milter info for dk-milter first and for OpenDKIM last. This actually determines the order of each milter’s headers in your outgoing mail (the first shall be last and the last shall be first). I recommend using this order, which places the DKIM signature above the DomainKeys signature in your outgoing email. That way, the receiving mailer will parse the DKIM information (the newer protocol) first.

Start dk-milter and restart Postfix

You’re ready to fire things up. Start dk-milter with:

service dk-milter start

You should get a message that says:

Starting DomainKeys milter (dk-filter #0):     [  OK  ]

If you get an error message, 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 tutorial. Then try starting up dk-milter again.

Once dk-milter starts successfully, restart Postfix with:

service postfix restart

If everything looks good, you may want to consider running chkconfig on dk-milter to make sure it starts when you reboot:

chkconfig --level 2345 dk-milter on

Modifying DNS records

While DomainKeys (via dk-milter) will rely on the same DNS information as DKIM (via OpenDKIM) for selector information, there is one minor addition and one minor change you need to make to your domain’s DNS records to support the older DomainKeys protocol.

First, you need to add a TXT Record to your zone file that reads:

_domainkey.example.com IN TXT "t=y; o=~"

The _domainkey TXT record is slightly comparable to the _adsp TXT record you added when setting up DKIM. It basically publishes your DomainKeys policies. The t=y means the domain is in test mode, so only use this setting while you’re testing things out. Once you’ve verified it works, remember to change it to t=n. The o=~ means that some emails from this domain will be signed, but not all. A setting of o=- means that every email from this domain will be signed, and that a messages origin should be in doubt if it comes from this domain unsigned. For now, the safest setting is o=~.

Second, you need to edit the TXT file for your selector and remove the v=DKIM1; and g=*; arguments, as these sometimes cause issues for a few mail servers when they attempt to validate the older DomainKeys.

Testing Things Out

As always, 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 dk-milter starts (or restarts), you should see lines like:

dk-filter[19535]: Sendmail DomainKeys Filter v1.0.2 starting (args: -u opendkim-milt -p inet:10035@localhost -d /etc/mail/dkim/trusted-hosts -s /etc/mail/domainkeys/keylist -S default -b sv -c simple -C bad=r,dns=t,int=t,no=a,miss=r -h -l -D -k -i /etc/mail/dkim/trusted-hosts -P /var/run/dk-filter0.pid)

Unlike OpenDKIM, dk-milter doesn’t log anything when you send a mail that gets successfully signed, so 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  Brandon Checketts’ Email Validator gives an error message in the DomainKeys field that reads:

Unable to verify signature
  granularity does not match address

That probably means the g=*; setting from your selector’s DNS TXT record is either still in your record or that the record is being cached by Brandon’s server. Wait an hour and then try again.

If you have a Gmail account, you can also send a signed message there for a quick and easy test. I like to click the Show Original link (under the Reply drop-down on the right) to see the signed headers. You should see headers for DKIM as well as DomainKeys.

The one result that everyone seems to want is this reply from the verifier.port.25.com test:

==========================================================
Summary of Results
==========================================================
SPF check:          pass
DomainKeys check:   pass
DKIM check:         pass
Sender-ID check:    pass
SpamAssassin check: ham

If you get that result, then congratulations – you’re signing mail with DKIM and DomainKeys. Sure, it’s a little redundant, but apparently overkill is just your style. :)

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

  • http://www.tai.ro alex

    I disagree with you regarding the need of DomainKeys: they are needed as long as Yahoo uses them. That’s why you got those questions about it over and over. Nice that you listened them.

    • http://www.stevejenkins.com/ Steve Jenkins

      I appreciate the candor of your comment, Alex. Still, regardless of who chooses to use DomainKeys, until I see documentation (or empirical evidence from tests I run myself) that signing an outgoing message with both DomainKeys and DKIM even slightly increases the likelihood of deliverability vs. signing with only DKIM, I won’t be convinced. If you (or anyone else reading this) has links to such documentation, I’d appreciate the link so that I can adjust my opinion. :)

  • http://www.tai.ro alex

    Ah, is not really difficult to see an evidence – just send 20 emails to yahoo accounts and probably half of them arrives into spam boxes. Unfortunately not even DomainKeys will guarantee a good delivery when dealing with Yahoo. This is THE ONLY reason I would ever recommend DomainKeys.

    • http://www.stevejenkins.com/ Steve Jenkins

      I find that sender reputation and feedback loop participation are key factors when delivering to Yahoo. But the biggest impact is from following their published postmaster guidelines and throttling your delivery attempts per connection to no more than 20. One of my businesses delivers 1MM+ email messages per month using Postfix and signed only with DKIM (along with proper SPF config), most of which go to Yahoo subscribers and we see excellent deliverability rates. But if DomainKeys works for you, then that’s great. :)

  • Sooraj

    Hi Steve,
    This is a wonderful tutorial. I liked it very much.

    http://www.topdog-software.com/oss/dk-milter/dk-milter-1.0.2-1.i386.rpm is not available anymore and i couldn’t find any rpm else where. But, i came across with this :
    http://kmlinux.fjfi.cvut.cz/~vokac/activities/milter/dk-milter-1.0.0-0.src.rpm
    So, to install this rpm. first you need to build it and building requires “rpmbuild”.
    so you need to run `yum install rpmbuild` first
    Next run : `rpm -ivh dk-milter-1.0.0-0.src.rpm’.
    If this shows an error (it might in CentOS), just create a directory `/usr/src/redhat/SOURCES`.
    Then, navigate to “/usr/src/redhat/SPECS” directory.
    Next run, `rpmbuild -bb –target noarch dk-milter.spec`
    Then navigate to /usr/src/redhat/RPMS/noarch/, go for the final install here:
    `rpm -Uvh dk-milter-1.0.0-0.noarch.rpm`
    After this, one can continue from your Blog Post.

    Thanks again for this tutorial.

  • Arya

    So for those who lacks linux technical knowledge or just too lazy to self-build the RPM or *BOTH* (such as me for example)

    Here you go
    http://www.mediafire.com/?09nmd6s4hcdg97l

    Of course I’m not the one who made this. 😉

  • cvlad

    Hi, Mr. Jenkins,
    When I was looking for a solution for my problem, I just found a thread here http://lists.opendkim.org/archive/opendkim/users/2011/03/0924.html, where you said you fixed a similar problem.
    My problem is that dkim is signing messages twice, and I kindly ask you to help me fix it, if you have the time.
    You could contact me by email, if it suits you.
    Thank you a lot,

    • http://www.stevejenkins.com/ Steve Jenkins
      • cvlad

        Thank you for the quick answer. I followed the no_milters tip. I tested and still have two signatures on email. I must say that dkim is not mentioned in my amavisd configuration, but is setup in postfix’s main.conf like this:

        milter_default_action = accept
        milter_protocol = 2
        smtpd_milters = inet:localhost:8891
        non_smtpd_milters = inet:localhost:8891

        Would be wiser to setup dkim inside amavis , instead ?

        • http://www.stevejenkins.com/ Steve Jenkins

          I don’t like the DKIM signing in Amavis (it’s never as up-to-date with the DKIM specs as OpenDKIM is). If you’ve already done the no_milters step, post your issue on the OpenDKIM-users mailing list. I bet it’s solved within the day. :)

  • cvlad

    Thank you very much

  • Pingback: qed.kgb.ro » opendkim and yahoo()

  • http://www.byteindia.com Vijay

    this is really helpful. I have been struggling to send emails from my blog and some email hosts were rejecting the emails like crazy.

  • Thomas

    hello Steve,
    I followed your tutorial about dkim and domain keys and I thank you. Everything works well after a lot of work: I added ‘MaximumSignedBytes 512′ in file ‘/etc/opendkim.conf’ to make it work also with long messages (problem found in yahoo) However, I cannot figure how to set the same option in dk-milter (/etc/sysconfig/dk-milter), which still does not work with long messages in yahoo, while with short it’s ok. Also, the suggested rpm ‘dk-milter-1.0.2-0.x86_64.rpm’ does not work with ‘CANON’ other than ‘simple’. — So at the time I get ‘domainkeys=fail (bad sig); …dkim=pass (ok)’ only with not short messages : any idea? thanks
    Thomas

  • Daniel

    Hello Steve

    Just wondering if you can point me into the right direction to compile/install senderid-milter on a CentOS 6 64 bit system. The compilation dies at some point and I can’t find anything useful to fix the problem. I can’t find any RPM/SRPMs either … Thanks,

    Daniel

    • http://www.stevejenkins.com/ Steve Jenkins

      Are you looking to verify SenderID for incoming mail in your MTA? You don’t need a milter to send. The sender does it all through DNS text records.

      • Daniel

        You’re right, thanks Steve for clarifying the matter for me.

        Daniel

  • http://worldwidedatasystem.com Thiyagarajan

    Shutting down all DomainKeys milter (dk-filter): [FAILED]
    Cleanup for DomainKeys milter (dk-filter #0):
    Starting DomainKeys milter (dk-filter #0): dk-filter: smfi_opensocket() failed

  • Muhammed Thaha K

    # service dk-milter start
    chgrp: cannot access `inet:10035@localhost': No such file or directory
    chmod: cannot access `inet:10035@localhost': No such file or directory

  • http://focusquality.net hicham

    hello
    Thanks for this tutorial, it’s work perfectly. i have installed DKIM and domainkey. but can you help me to edit DK-milter.conf to use list key and domains of DKIM.
    Note: i have setup multi keys,domains in DKIM

  • Vijay

    Hello, My sincere thanks to Steve Jenkins for this tutorial
    and Sooraj’s comment on how to build RPM from source. Everything is
    working fine but i would like to know how do i sign multiple
    domains with dk-milter? Please find the compiled RPM
    -dk-milter-1.0.2-1.el6.i686.rpm , with the below link,
    https://docs.google.com/file/d/0BxyLHCYPNcEUM1RaaThYTkVQTlU/edit