Using DKIM in Exim

Since Exim 4.70, DKIM (DomainKeys Indentified Mail – RFC4871) has been supported by default.

The current implementation supports signing outgoing mail, as well as verifying signatures in incoming messages, using the acl_smtp_dkim ACL. By default, DKIM signatures are verified as new messages come in, though no action is taken unless you’ve implicitly configured rules in the DKIM ACL.

After installing Exim (>= 4.70), you should see debug logs for incoming mail from servers that have DKIM signatures setup- they look like:

DKIM: s=gamma c=relaxed/relaxed a=rsa-sha256 [verification succeeded]
Verifying Incoming Mail

By default, Exim does not filter any mail based on the validity of the DKIM signature- it’s up to you to add ACL rules to control what happens when you receive messages with “bad” signatures.

First add an ACL section for the DKIM processing; this should be included with your other ACL statements:

acl_smtp_dkim = acl_check_dkim

Next, after the “begin acl”, section, add your DKIM ACL section, and by default, accept all messages in this ACL:



Now you need to decide what kind of rules you want to setup- you probably don’t want to put a rule that applies to all domains- though, if the company went to the trouble of adding DKIM signatures to their e-mail, you’d hope they’d get it right, and not publish invalid public keys.

For now, let’s add a simple rule for gmail; google knows what they’re doing, so their systems should be setup correctly:


	# check the DKIM signature for gmail
	deny 	message 	= Common guys, what's going on?
		sender_domains 	=
		dkim_signers 	=
		dkim_status 	= none:invalid:fail


You can add as many rules, for whatever domains you want in this ACL.

Signing Outgoing Mail

Now that you’re checking incoming mail, you probably want to sign mail coming out of your system. This is a relatively easy process, that I’ve broken down into three steps:

Step1– Generate a private and public key to sign your messages; you can do this easily with openssl:

#openssl genrsa -out dkim.private.key 1024

Then extract the public key from the private key:

#openssl rsa -in dkim.private.key -out dkim.public.key -pubout -outform PEM

Step2– Configure the Exim remote-smtp transport to sign outgoing messages, using your new private key. You’ll need to pick a domain and a selector for this process.

When remote SMTP servers validate your DKIM signatures, they simply do a DNS look up, based on the selector and your domain- the domain needs to (obviously) be a valid domain you own, that you can add DNS entries to, and the selector can be any string you want. So, for example, using the domain “”, and the selector “x”, you would add to the remote_smtp transport in Exim:

        driver = smtp
        dkim_domain =
        dkim_selector = x
        dkim_private_key = dkim.private.key
        dkim_canon = relaxed

This tells Exim to sign any outbound e-mail, using the domain, the selector “x”, and the private key we just generated. The dkim_canon = relaxed, sets the canonicalization method to use when signing messages. DKIM supports “simple” and “relaxed” algorithms- to understand the difference, see section 3.4 of the DKIM RFC.

Step3– add your DKIM public key to your DNS.

The DKIM public key generated above is advertised to other SMTP servers, using a DNS TXT record. In DNS for the domain, add a new TXT record:   TXT v=DKIM1; t=y; k=rsa; p=<public key>

Where “x” is the selector you used above, and <public key> is the public key data (minus the key header/footer text).

When setup correctly, your DKIM text record should look something like this:

# host -t txt descriptive text "v=DKIM1\; t=y\; k=rsa\; p=MIGfMA0GCS

(lines breaks were added for readability- your entry should be one continuous line)

This DNS record is referred to as the “selector” record; you need to also setup a “policy” record. The policy record is your domains policy for domain keys- you should start with something like: t=y; o=~;

The t=y specifies that you are in test mode and this should be removed when you are certain that your domain key setup is functioning properly. The “~” in the o=~ specifies that some of the mail from your domain is signed, but not all. You could also specify o=- if all of the mail coming from your domain will be signed.

Once you have all of that in-place,  restart Exim, and send out a message using the remote-smtp transport. You should now see a DKIM-Signature: header listed in the message headers, which lists your domain (as d=), and selector (as s=), as well as a signature for this e-mail, which can be validated against your public DKIM key, that you’ve published in DNS.

For more information, see the Exim DKIM page, or the DKIM RFC.


Once you’ve set everything up, you can test your DKIM (and SPF and SenderID, etc) install, by using the validation service.

Just send an e-mail to, and it will auto-respond with a validation report


I’ve updated this to use a key length of at least 1024 bits, otherwise it’s possible to crack the DKIM key, and fake it to show that your email is valid. This came to light largely because of an article about how Google was using a 512 bit key and a “hacker” factored the key, and spoofed emails to the Google founders:

I previously listed a key length of 768, which is significantly harder to break than a 512 bit key, but just to be safe, use 1024 or better yet, 2048.

49 thoughts on “Using DKIM in Exim

  1. Marcel

    Thanks for the info. This is the first complete description that I found on the net which is really understandable.

    Theres a small and easily detectable spelling error in acl_check_dkim however:
    sender_domain =
    should really be
    sender_domains =

    What I am still looking for now is a real-live validation test. seems to be down, so except seeing that a dkim sig. is included I cannot yet check if the signature is really fully valid.

  2. mike Post author


    Thanks for the pointing out that mistake Marcel.

    As far as the live validation; has a similar auto-reply service; just send to; their system also validates SPF, Sender-ID, and a few other things.



  3. Marcel

    Yup, found it as well in thee meantime. All working nicely now. Only one listserver sometimes breaking the signature, but all other messages seem to work perfect.

    One thing to add is that one should perhaps also add an AuthorDomainSigningPolicy record:


    as a text record containing “dkim=all” to indicate one signs all messages. Other option would be “dkim=unknown” to indicate only some mail is signed (for testing that is probably recommended).

  4. Jim

    Thanks for an excellent explanation. Please forgive my newbie question. I have multiple domains sending mail from the same server. Should there be a separate entry for each in the Exim configure file. How should they look?

  5. mike Post author


    You don’t necessarily have to setup something different per domain- you can sign all your outbound e-mail from the same domain/selector.

    If you wanted to have a different config, based on the domain of the sender address, you could technically do a lookup based on the sender domain, and return values for each of the dkim_domain, dkim_selector and dkim_private_key values.

    Then you could store these values in a lookup db, or SQL database by sender domain.

    So as a quick (un-tested) example, you could do something like this:

    driver = smtp
    dkim_domain = $sender_address_domain
    dkim_selector = x
    dkim_private_key = ${lookup pgsql{select key from dkim where domain = ${quote_pgsql:$sender_address_domain}}{$value}}
    dkim_canon = relaxed

    Which would use a common selector of “x”, the domain of the sender e-mail, and a SSL key looked up from a PostgreSQL database by domain.

  6. Beau

    Thanks a bunch for this great tutorial. I have a couple questions though. For starters, I’m on Debian and Nginx and I installed exim with this command: “apt-get -t lenny-backports install exim4” which installed version 4.71. I then followed your tutorial for signing emails but my emails still don’t get signed. Step 1 seems to have gone off without a hitch as I can verify that both those files now exist and have data that looks right.

    I added the following lines to /etc/exim4/conf.d/transport/30_exim4-config_remote_smtp under driver = smtp:
    dkim_domain =
    dkim_selector = whizbang-dkim
    dkim_private_key = /dkim.private.key
    dkim_canon = relaxed

    And restarted exim. I then added the txt record to my domain as you instructed. The problem is that my emails don’t seem to be getting signed. I’ve tried looking at the raw headers and sending emails to six different rotator services and I’m quite positive my emails aren’t getting signed. So my questions are:

    1) Is there something I need to do to turn signing on besides adding those lines to that file?
    2) What is the “selector”? Is it just some random word that has to be in both the header and the txt record?
    3) Is dkim_private_key just the path to the dkim public key on my server? That’s what I’m assuming it is.

    Thanks a bunch!

  7. mike Post author


    Hey Beau,

    I’m not 100% familiar with the Debian install; it seems to break the file up into components- usually I install from source and have just one big configure file- but this looks like the right spot.

    1) That should be all you need to at least sign out-going messages.

    2) Yup, the selector is just a random word that is specified in your config; it uses this word to do the DNS lookup against your domain- most of the time it’s kept really short (like a single character), but as long as it’s a valid hostname, it’s fine.

    3) Yes, that’s the full path to the private key; so in your example, your private key would have to be in /- is that correct? maybe it’s not signing your e-mails because it can’t find the key?

    Also, have you confirmed that messages are being sent through exim? can you see messages coming in/out in your main exim log file?


  8. Pingback: Exim smarthost with DKIM

  9. John

    Hi Mike,

    Thanks for this great topic, I did that but I got permerror (key failed) for dkim and no sig for domainkeys.

    Authentication-Results:; domainkeys=neutral (no sig);; dkim=permerror (key failed)

    DKIM-Signature: v=1; a=rsa-sha256; q=dns/txt; c=relaxed/relaxed;; s=x; h=Content-Transfer-Encoding:Content-Type:MIME-Version:Message-ID:Date:Subject:To:From; bh=dZwg0roqeT4Z81/Gk6beBXednOetUVdfKD0HSi0smMw=; b=iwjc2Fu7aQAZ3nSb9Asu1DaPh27Lut0Ig2xEZ9FS5Frwnq57fJa8Vo4iaOKu/RokAIDVtgMUtZoh0JyBlpG18yJJILwuPO4ORzstS/fP9EGxfyLZBDZLtcSQOFRhc/dr;

    DKIM check details:
    Result: permerror (invalid key: error reading public key: 3071417264:error:0D07209B:asn1 encoding routines:ASN1_get_object:too long:asn1_lib.c:142:;3071417264:error:0D068066:asn1 encoding routines:ASN1_CHECK_TLEN:bad object header:tasn_dec.c:1281:;3071417264:error:0D07803A:asn1 encoding routines:ASN1_ITEM_EX_D2I:nested asn1 error:tasn_dec.c:380:Type=X509_PUBKEY;)

    May you please guide me how to fix.

  10. Bryan Henderson

    The instructions need to say something about placement of the file “dkim.private.key”. As the example is written, the file gets placed in whatever is the current directory when you run ‘openssl’ and it isn’t clear how Exim finds it, since the remote_smtp definition doesn’t have an absolute path.

  11. mike Post author

    Right- well- the file can be put wherever you want;

    the dkim_private_key option takes either the RSA key inline, or, if it starts with a /, then the full path to the file.

    Whatever path, obviously, needs to be accessible by the user executing the remote_smtp transport.


  12. Keith Wellman

    I’d love to pay you to setup DKIM on my server to sign outgoing messages because these instructions are useless for someone who doesn’t really understand in depth how to use command lines and exim.

    I’ve completed step 1. Generating a key using Open SSL… that part was easy to figure out…

    Step 2…
    Configure EXIM… wtf… where? What file? You give the text err command (not sure if it’s something I need to actually add to a file and if so what file is it, or if it’s a series of commands).

    Step 3 should be easy as well as I know how to go into WHM and edit my dns record BUT I don’t really understand how to actually get the public key I generated in step 1 (I simply used the command line to generate it.

    I DO NOT get most of this stuff but I can follow directions and I can understand it vaguely.


  13. Flo

    Is there a way to sign only ‘some’ outgoing mails?
    like authenticated smtp users or if the ‘from’ header matches a specific domain?

    Btw.: Here is how i threat incoming mail, might be interesting for someone looking for an example:


    # add a header to every message
    add_header = :after_received:X-CDC-DKIM: signer=”$dkim_cur_signer” status=”$dkim_verify_status” reason=”$dkim_verify_reason”
    log_message = CDC-DIKM: signer=”$dkim_cur_signer” status=”$dkim_verify_status” reason=”$dkim_verify_reason”

    # defer temporary problems
    dkim_status = invalid
    log_message = CDC-DIKM: Deferred
    message = Failed to validate DIKM Signature, problem may be temporary.

    # deny fakes
    dkim_status = fail
    message = DIKM Signature invalid.
    log_message = CDC-DIKM: Failed

    # accept the rest (correctly signend or unsigned)

  14. mike Post author

    Hey Keith,

    step 2- The main exim config file (it’s literally called “configure”) is the file you’re looking for- it’s exact location can vary depending on your OS- I install exim from source, and always put mine in /usr/local/exim/configure; most linux distros will likely put it in /etc- I would just try looking for some docs that indicates where it is, or just do a search on your machine.

    step 3- the public key file is just a plain text file that you can open with any text editor; so use a command line text editor (or cat or more it on the command line), or simply download the file using FTP (or whatever you have) and open it up in a text editor

    There will be a leading a trailing title (BEGIN/END certificate) that you need to cut out for your DNS record- and then the key is broken up into multiple lines- what you need to do, is turn this into one long line for your DNS entry.

    (I think some BIND implementations can take this in multiple lines, but I’m not sure what you’re running)

    Let me know if that helps,


  15. BasicBaer

    I agree with the rest, simple explanation, nearly all necessary information.

    But it might be a good idea to add the hint, that the DNS entry containing the public key MUST start with the v= field, else validation fails. Just cost me half a day banging my head against this damn problem 🙂

    (Yes, I know, the RFC states it very clearly)

  16. mike Post author

    Yup- good point- I can see that being a pain if you missed that-



  17. Ellert

    Thanks for this writeup. It helped me to get dkim to work in exim.
    To test you can use
    /usr/sbin/exim -v
    Subject: dkimtest

    I got this error there somewhere
    DKIM: signing failed (RC -101)

    I guessed this was a problem with the generated key.
    I used this to make a new keypair:
    openssl genrsa -out private.key 1024
    openssl rsa -in private.key -pubout -out public.key

    For the rest i followed your recept. And then it worked.

  18. GMO

    Looks like I’m almost there. Can you tell me why I’m not getting a signature “domainkeys=neutral (no sig)”? Looks like dkim passed though.

    Authentication-Results:; domainkeys=neutral (no sig);; dkim=pass (ok)

    DKIM-Signature: v=1; a=rsa-sha256; q=dns/txt; c=simple/simple;; s=x; h=From:Message-Id:Date; bh=70yYafhTML7Wlue1K9LneDU8xUBRS7VyKI/lrGFlzyg=; b=UdWSZWWuwAciNYGKLcewIIDVgx8zvHQvPARGIxkyhMCbAaG+tRvgGNkrZehMBSqjCpFMsINwesmtIQ8fnFN+5vzv0+SQ9PPw7LkVO8bK5zMW/9/Hx5AupMqCb4GEQJdQ;

  19. mike Post author


    Not sure- but if you posted your config,, and the output from dig for your key, I could look-


  20. Pingback: Configurer un serveur pour ne plus être considéré spam. | Geek De Vie | Le manuel de la vie 2.0 !

  21. Chris

    I am looking to do this as well but our server is running Exim 4.69 I believe. I’m still a bit confused about the DKIM keys. We have hosted Google Apps email that is signing dkim but our server also sends out some emails from our content management system. Would our server have it’s own private dkim key or can it use the same key google apps is using? Such a noob, sorry.

  22. David

    @Chris, I just want to point something quickly, 8 or so months ago I was hit by a zero-day exploit that affected version 4.69. I’d suggest upgrading as soon as possible, as the exploit is out in the wild and automated.

    @Mike, thanks for this excellent tutorial.

  23. Pierre Kerchner

    Important to mention for Step2 (Outbound)

    exim can be in the single config file mode.

    So it doesn’t help to change /etc/exim4/conf.d/transport/30_exim4-config_remote_smtp

    So you need to work von /etc/exim4/exim4.conf.template

    Life is too complex 😉

  24. Greg

    Hi all,

    Fantastic tuto, thanks very much for it. I run a single server on Linux Centos, and followed your tuto to set everything up. I restardted exim at the end.

    My exim.conf looks like this:
    driver = smtp
    dkim_selector = mail
    dkim_private_key = /usr/local/cpanel/etc/exim/dkim.key
    dkim_canon = relaxed

    my DNS record shows this: : v=DKIM1; g=*; k=rsa; p=MIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQDJOouIS9zVNj9QHkWGRrtEhd86Haff/KoTAU9VQN1D+1XIknsWBZTUNXMcihXVJ4fwnktcaG+1UTX5KfqRqIkaxqHVVtUon+mfCGyiOXlXM8mCONxl8PuhBH7bt/OF/ew9WhCQELiQdpmuu6Hl2lPi1vEKPPFRgV5gMMBbYT3zQIDAQAB

    When I send an email to check-auth, I get the following result:

    DKIM check details:
    Result: neutral (message not signed)
    ID(s) verified:

    NOTE: DKIM checking has been performed based on the latest DKIM specs
    (RFC 4871 or draft-ietf-dkim-base-10) and verification may fail for
    older versions. If you are using Port25’s PowerMTA, you need to use
    version 3.2r11 or later to get a compatible version of DKIM.

    Not too sure what I’m doing wrong.. HELP !! It seems the message is not signed at all ?


  25. mike Post author

    Hey Greg,

    Off hand the only things I can think of are:

    1) can exim read the /usr/local/cpanel/etc/exim/dkim.key file? does the user that exim runs as, have permission to the directory and to the dkim.key file?

    2) I would double check that the dkim.key file was generated properly

    3) run a test in debug mode (exim -d ) and see if you see any references to dkim, and if you see any errors.


  26. Greg

    Hi Mike,

    Thanks for taking the time to look into this.

    1) I checked permissions and my dkim.key seems to have the same as the other files on the server, and was created by the same user, so I think it should be ok. Having said that, I’m not too sure what foolproof metod I could use to rule out this first point.
    2) I have regenerated the key to make sure it’s been generated ok.
    3) I’ve run a test and it kinds of look ok. I cna send you a txt file with the result or post it here if you want?

    I tried again to email check-auth but although I do get a domainkey-signature, I don’t see the dkim one.
    One thing I noticed is that in the exim.conf file, the domainkey params are in the “dk_remote_smtp” section, whilst the dkim is in the “remote_smtp” section. Not sure that if that helps or not..

    Thanks for your help, it’s much appreciated.

  27. Pingback: Playing around with Exim, Spamassassin, DKIM and SPF |

  28. Jon

    When running exim in debug mode, should you see the reference to dkim under the Authenticators: near the top?

    Authenticators: cram_md5 cyrus_sasl dovecot plaintext spa

  29. Jon

    I do see it under the Support sections:

    Support for: crypteq iconv() IPv6 PAM Perl Expand_dlfunc TCPwrappers OpenSSL Content_Scanning DKIM Old_Demime Experimental_SPF Experimental_SRS

    Still getting signing failures
    2012-04-30 12:46:08 1SOtjf-0007WF-EY DKIM: signing failed (RC -101)

  30. mike Post author

    I don’t think it should show up under Authenticators; DKIM isn’t an authentication method.


  31. Jon

    I have been banging my head on this. Here is what I get from running the following command:
    /usr/sbin/exim -d -r “” -odf

    PDKIM >> Hashed body data, canonicalized >>>>>>>>>>>>>>>>>>>>>>>>>>>>>
    d{CR}{LF}PDKIM <<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<> Hashed header data, canonicalized, in sequence >>>>>>>>>>>>>>
    PDKIM <<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<> Signed DKIM-Signature header, canonicalized >>>>>>>>>>>>>>>>>
    PDKIM <<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<
    PDKIM [] hh computed: 15525e51535f45caea0668d70b115c21e89beeada4f652aae48fb7beca8c9788
    DKIM: signing failed (RC -101)

    Any help would be greatly appreciated. Thanks Mike.

  32. mike Post author

    Hey Jon,

    The error: “DKIM: signing failed (RC -101)”

    is the error code PDKIM_ERR_RSA_PRIVKEY (from src/pdkim/pdkim.h)

    /* Function success / error codes */
    #define PDKIM_OK 0
    #define PDKIM_FAIL -1
    #define PDKIM_ERR_OOM -100
    #define PDKIM_ERR_RSA_PRIVKEY -101
    #define PDKIM_ERR_RSA_SIGNING -102
    #define PDKIM_ERR_LONG_LINE -103

    and is only returned in one place – in src/pdkim/pdkim.c

    /* Perform private key operation */
    if (rsa_parse_key(&rsa, (unsigned char *)sig->rsa_privkey,
    strlen(sig->rsa_privkey), NULL, 0) != 0) {

    So it looks like there is a problem parsing the RSA key that you generated for Exim.

    This could be because the key generation failed, or because exim doesn’t have access to the file (file permissions).

    I would start by trying to re-generate your certificates.


  33. Lothar

    | #openssl genrsa -out dkim.private.key 768
    The key length should be at least 1024, otherwise the keys may be easily broken and the DKIM system subverted.

  34. kishan

    Having trouble in setting
    Canonicalization relaxed/relaxed
    Canonicalization relaxed/simple
    in PMTA …. Do you know where i can find the setting for DKIM in PMTA as there is no file like opendkim.conf in my server

  35. Mike Maurice

    I was under the impression that the domain registrar has to have a DS record set up with DKIM after you do all the steps you indicated.

  36. mike Post author

    Hey Mike,

    No- DS records are used for DNSSEC- it’s the “Delegation Signer” record- it’s not involved with DKIM.


  37. Pingback: Setting up Exim4 Mail Transfer Agent with Anti-Spam, Greylisting and Anti-Malware | Michael FranzlMichael Franzl

  38. Pingback: Mailserver mit Exim4 und Dovecot | Interoberlin

  39. Mark Elkins

    You *need* to specify a full pathname for dkim_private_key – or you’ll get an error “DKIM: signing failed (RC -101)” – which is not descriptive to me at all.

    Please change the example from:
    dkim_private_key = dkim.private.key
    to something like:
    dkim_private_key = /etc/exim/dkim.private.key

    And mention putting the key into the /etc/exim directory

  40. Pingback: Emails auf einem eigenem vServer empfangen | Matthias Bock's Blog

  41. Dean

    Hi Mike,

    Have you attempted to configure Exim to check DKIM for any domain which has it configured, rather than on a case per case basis?

    So far I have only been able to enable it globally, such that domains without DKIM always fail verification. I haven’t yet been able to set out how to tell Exim to to the look up and then act if needed.

    Any feedback appreciated.


  42. mike Post author

    Hey Dean,

    So do you mean any domain that has a DKIM signature configured in DNS?

    If the exim DKIM check fails, it’ll fill in the $dkim_verify_reason var, and will set it to “pubkey_unavailable” if the domain doesn’t have a published public key. I suppose if you wanted to do the DNS check first, before exim tries, you could make a call out to a script- one way would be to use perl_startup and call out to a script, and then you could pass the domain, it could do a DNS lookup, and return a value back to exim. If the value indicates that it does not have a public key in DNS, then you could call dkim_disable_verify.

    That might be more work than just letting the DKIM process go through, and then checking the result. Though, you could then reject messages that do have public keys, but that aren’t signed.


  43. mkurz

    Hi Mike,

    in your post you write:
    …you need to also setup a “policy” record. The policy record is your domains policy for domain keys- you should start with something like: t=y; o=~;

    As far as I know this is used in the deprecated DomainKeys specification – but not in the newer DKIM specification.
    There is no such thing in the RFC4871. It seems you have this information from the outdated RFC4870.
    People shoudl DMARC for this functionality now – or am I wrong?

    Thanks for the post,

  44. Pingback: Dkim Exim Cpanel | +ADw-/title+AD4-Hacked By TURKHACKTEAM.ORG Putin, knowingly and willfully planned airplane attack and the citizen on death. This has caused you to be you’re a traitor. Now the citizens of nationalist feelings of the Russian People

  45. Pingback: Playing around with Exim, Spamassassin, DKIM and SPF »

Leave a Reply

Your email address will not be published. Required fields are marked *