When you really need E-mail delivered – Signing your mail using Domain Keys/DKIM

comments

So you’ve started sending email from your site/application, your application is doing well and you are now sending more e-mail daily. With this comes the fun of finding out that most of the email you now send ends up stuck in your customers spam filters – how did this happen? You aren’t a Nigerian scammer, and people opted-in to hear from you! At this point signing your mail may be the next step.

imageI recently wrote a post on What good developers should know about sending mail, where i talked through the basics that all developers need to know about sending email before they simply start talking to SendMail or fire up an instance of SmtpClient.

My post covered a few things you should make sure you do when sending email through code:

  • Send email from a real email address (hey it may sound crazy but people might want to reply…?)
  • Never send mail from a domain you do not control (that’s what reply-to is there for…)
  • Make sure your mail server’s forward and reverse DNS records are configured properly and match their HELO/EHLO greeting.
  • Setup an SPF record/Sender ID DNS record for server authentication.

If you are in the category of large sender, have stumbled onto the fact that a spammer used to use your IP address for nefarious means, or simply are having issues with the delivery rates of the mail you send out, one way you can add an extra tick of approval to the mail that you send is to sign your email using Domain Keys and DKIM.

Let’s take a look at how you would do this.

Domain Keys and DKIM - A brief history

The very problem you are currently facing – your recipients being unable to validate the email you send them are from you is not a new one. Different fields on technology have faced this problem before the general development community mostly knew about it – in areas such as the Medical Industry, Defense and Engineering.

When faced with wanting a way to validate email without the hassle of using encryption and having to download the senders public PGP key, the people at Cisco developed a solution called Identified Internet Email that was aimed at allowing the sending party to verify the authenticity of a sender by investigating the senders DNS records (think encryption without the need for secrecy).

Yahoo, faced with the ever growing amount of spam on its Yahoo Mail platform loved this idea and wanted to take it a step further. This lead Yahoo Mail’s Mark Delany to develop DomainKeys to help verify the authenticity of a sender using a private key stored in the email and public key stored in a TXT record in sender’s DNS.

DomainKeys was then superseded by a combination of Domain Keys and Identified Internet Email called DKIM (Domain Key Identified Mail). Domain Keys are thought of by the people of internet land (quite literally, the Internet Engineering Task Force) to be superseded but still supported for legacy sake. Luckily DKIM uses the same key storage, and just stores it’s email header differently.

Example Domain Key and DKIM Email Header

DKIM-Signature: v=1; a=rsa-sha1; c=relaxed/relaxed;
 d=diaryofaninja.com; h=From:To:Subject;
 q=dns/txt; s=mailserver01; t=1321412507; bh=/53LpyJkzBXKAnLlbntG4C24JqY=;
 b=Im2WP82Ra+/rdZ6Rw1KtqbvnBMULshiwLI6mgDTkPekRFNBqhHZROFimt+XhhsUD/2S6RKvzkOfjS3e5+1WBXZOnf85NPA6gnPSZbutH2va+s9/XjPFx9fHDy8Kb0wpd
DomainKey-Signature: a=rsa-sha1; c=simple; d=diaryofaninja.com;
 h=From:To:Subject; q=dns; s=mailserver01;
 b=dqE0DZWbSEUZ7ZrfRe5M5cJJlzMPgKEJdb3VTPIoHxtCrmWESR+XeFGQl5YRStfXqcc8oGE/ZbdaIsK3Ov9pBdMbVlxYvIHNXK7G4iIHE8mfms/OA/QkWwpwi9/HV/ep;

Getting it up and running on your servers

So you’ve decided to take the plunge and setup signed mail for your application.

Before you proceed you need:

  • Access to the DNS configuration for your domain name (we’ll be adding some new TXT records)
  • Either access to your mail server or the ability to change your site’s code.

Generating signing keys

The first thing you’ll need to do is generate a set of private and public encryption keys that will be used to sign your email. I am a Microsoft developer by trade so i am running on Windows – to generate DKIM keys I use Open SSL.

Download Open SSL (if you don’t already have it you’ll also need the Visual C++ 2011 Redistributable installed from here).

Open a command prompt window and run the following commands (with the domain name you are generating keys for filling in the blanks)

openssl genrsa -out rsa.private.{your domain name goes here} 768

openssl rsa -in rsa.private.{your domain name goes here} -out rsa.public.{your domain name goes here} -pubout -outform PEM

I have taken the liberty of writing a little batch file that takes your domain name as a parameter and runs these for you (an easy to use idiot proof solution).

@ECHO off
IF EXIST rsa.private.%1 GOTO keys_already_exist
 
REM Execute OpenSSL and request that it generates a 768 long private key 
openssl genrsa -out rsa.private.%1 768

REM Now Execute OpenSSL and generate a public key from the private one created above
openssl rsa -in rsa.private.%1 -out rsa.public.%1 -pubout -outform PEM
ECHO.
echo Files created for %1
ECHO.

GOTO finished_key_gen

:keys_already_exist

ECHO.
ECHO Keys for the domain name %1 have not been created because the files already exist.
ECHO Please delete your keys before trying again.
ECHO.

:finished_key_gen

Save this to a file name generate-dkim.bat and then run it by simply typing:

generate-dkim my-domain-name.com

Once you’ve run Open SSL you should have two files, a private key and a public key. The public key will go in your DNS as a TXT record and you will use the private key to sign outgoing mail using DKIM.

Adding the keys to your DNS

Both Domain Keys and DKIM use the same procedure for storing your public signing keys:

  • A base DNS record that lets people know whether you sign all your email or just some of it, along with a contact address for bad mail.
  • Any number of “selectors” or different keys. This allows you to have different keys for different mail servers, rotate keys year-to-year or any other requirement you could think of that would require more than one public key to exist at a time.

The public key you have created in Open SSL will look similar to:

-----BEGIN PUBLIC KEY-----
MHwwDQYJKoZIhvcNAQEBBQADawAwaAJhANWCczM6lXpTDUpoAbKPOuUN7fI9b0Lk
H9BZv/ikUrEqm6FWuBKZk2AHDH7nAVvh8pqICfVpKNSFNiZIarbDOZFL3HyDyFE1
LSDTpiWQAli1+aTH7pJnvH1NR6wTaFYCfQIDAQAB
-----END PUBLIC KEY-----

Before you put this in your DNS you will need to remove the header and footer from the file (i.e. “-----BEGIN PUBLIC KEY-----“), and remove any line breaks from the string.

A Modified public key:

MHwwDQYJKoZIhvcNAQEBBQADawAwaAJhANWCczM6lXpTDUpoAbKPOuUN7fI9b0LkH9BZv/ikUrEqm6FWuBKZk2AHDH7nAVvh8pqICfVpKNSFNiZIarbDOZFL3HyDyFE1LSDTpiWQAli1+aTH7pJnvH1NR6wTaFYCfQIDAQAB

Then use this to create your DNS TXT records.

Example Domain Keys or DKIM DNS records

Base record – tells people whether all your mail is signed or not and who to send bad mail too:

_domainkey.mycompany.com IN TXT "o=~\; r=helpdesk@mycompany.com"

A “Selector” record - a domain can have multiple public keys at a time, and they are separated by different sub-domains or “selectors” – the example shows how you can split this by giving each mail server its own key:

mailserver01._domainkey.mycompany.com IN TXT "k=rsa\; p={DomainKey/DKIM public key goes here}" 

Sending DomainKey/DKIM Email (through code)

Once you have setup your DNS you’ll want to send signed email – one way to do this is using code during the send process of your application (remember when you abstracted all your email functionality into a helper class? this is the time is all pays of…)

As i am a .Net developer i look for .Net solutions – there are many, many DKIM implementations in other languages if you are not a .Net kind of guy/gal, Google is your friend here.

My favourite implementation is a project called DKIM.Net on GitHub as its free, supports both DomainKeys and DKIM, and will get you up and running with minimal fuss or code-smell.

var privateKey = PrivateKeySigner.LoadFromFile(Server.MapPath("~/rsa.private.mydomain.com"));
var DnsSelector = "mailserver01";
var dkimSigner = new DkimSigner(privateKey, "mywebsite.com", DnsSelector, new string[] { "From", "To", "Subject" });
var domainkey = new DomainKeySigner(privateKey, "mywebsite.com", DnsSelector, new string[] { "From", "To", "Subject" });
        
MailMessage msg = new MailMessage();
msg.To.Add("me@mycompany.com");
msg.Subject = "DKIM test message";
msg.Body = "Hello world";
msg.From = new MailAddress("my-signed@email-address.com");
        
msg.DomainKeySign(domainkey);
msg.DkimSign(dkimSigner);

new SmtpClient().Send(msg);

If using an Open Source free library puts the fear of {INSERT NAME OF DEITY} in you, there are a number of commercial .Net products that are just as nice to use (but cost money, obviously):

Mailbee.net from AfterLogic

Mail.dll from Lesnikowski

CAVEAT:

If you are planning on using Simple rather than Relaxed DKIM signing, conducting your email signing through code can often make your signing fail as your mail server may add a new/different Date header after you send your email to it that may cause the signature of your e-mail to become invalidated (because it was signed using a different header – one with a different/earlier date).

Sending DomainKey/DKIM Email (using your mail server)

The other way you can implement the signing of outgoing mail is to employ the Domain Key/DKIM signature as the mail goes out the door – using your SMTP/mail server to do the signing.

Sadly if you are using the IIS SMTP server or Exchange to send your mail there is no out of the box support for DKIM or Domain Keys, so because of this my preferred approach is to install and configure a separate locked down (not accessible outside of the local box etc.) version of hMailserver (free) on a non-standard port. hMailServer is light weight and allows you to easily setup DKIM signing for outgoing mail with zero changes to your applications code.

image
A screenshot of hMailServer’s Administration console.

There are also a number of commercial software packages that allow you to use DKIM on Windows Server:

ThinkDKIM for IIS SMTP
(an IIS SMTP plugin allowing DKIM for $199 per server).

EA DomainKeys/DKIM for IIS SMTP Server and Exchange Server from AdminSystem 
(a IIS SMTP/Exchange Plugin for $299 per server).

Smarter Mail  by SmartTools
(a fully functional enterprise mail server replacement – they additionally offer a free version of their product).

PowerMTA from Port 25
(a fully featured mail server/email delivery platform).

Almost there - Testing your DomainKey/DKIM signed email

Once you have configured all of the above and want to actually test that everything is working as it should, you’ll want to know of some easy ways to test the whole thing is working:

Gmail

Gmail is by far the easiest option to testing the DKIM and Domain Key signing of your emails as they add the validation results for incoming email to the header of every email they receive. To access this simply send an email to your Gmail account, open the email and select “Show original” from the options list.

Example of the header GMAIL puts on your email:

Authentication-Results: 
spf=neutral (google.com: 10.10.10.10 is neither permitted nor denied by best guess record for domain of my-website-domain.com) 
dkim=pass header.i=@my-website-domain.com
DKIM-Signature: v=1; a=rsa-sha1; c=relaxed/relaxed;
 d=my-website-domain.com; h=From:To:Subject;
 q=dns/txt; s=mailserver01; t=1321412507; bh=/53LpyJkzBXKAnLlbntG4C24JqY=;
 b=Im2WP82Ra+/rdZ6Rw1KtqbvnBMULshiwLI6mgDTkPekRFNBqhHZROFimt+XhhsUD/2S6RKvzkOfjS3e5+1WBXZOnf85NPA6gnPSZbutH2va+s9/XjPFx9fHDy8Kb0wpd
DomainKey-Signature: a=rsa-sha1; c=simple; d=my-website-domain.com;
 h=From:To:Subject; q=dns; s=mailserver01;
 b=dqE0DZWbSEUZ7ZrfRe5M5cJJlzMPgKEJdb3VTPIoHxtCrmWESR+XeFGQl5YRStfXqcc8oGE/ZbdaIsK3Ov9pBdMbVlxYvIHNXK7G4iIHE8mfms/OA/QkWwpwi9/HV/ep;

Port 25

Port25 offers a really cool service in the form of its email report service.

If you send an email to check-auth@verifier.port25.com they will reply with a report on the email you’ve sent them.

They take this one step further by allowing you to specify the reply email check-auth-jsmith=yourdomain.com@verifier.port25.com (example shows jsmith@yourdomain.com getting the report)

Alternative to all this additional work

If you have read this far you may be feeling that you’ve got a considerable amount of work ahead of you/behind you just to get this additional functionality out the door. You aren’t far from the truth, but if you’re even reading this post you are probably at the point where the additional work is well worth it or just plain-old “has to be done” in order to get your mail delivered to peoples inboxes.

Alternatively, If you want to have all this additional functionality without the leg work and don’t mind paying for it there is always the option of outsourcing the job of sending your application’s email to a third-party.

A number of relatively cost-effective start-ups have sprung up to serve this very need;

SendGrid (options starting at FREE for 200 emails a month) <- have used this service and they are awesome

PostageApp (options starting at $9/month for 9,000 emails)

Pros/Cons to outsourcing your email sending:

Pros

  • Sleep easy knowing that your email delivery problems are keeping someone else up and night.
  • Usually setting it up and trailing their services simply require you changing your outgoing SMTP server address (setup with no fuss).

Cons

  • These services often delivery email using a generic domain name ({random-Guid}@sendgrid.me) not your website’s domain name (however they usually offer upgrades to make this happen for an additional charge)
  • You still have to setup your DNS for their services to be “recognised” as being able to send from your domain.
  • Additional cost that can be FREE if you simply put in some effort.
  • You don’t have full control of the send end-to-end (this might make you/your sysadmin boss unhappy).

Summary

Signing your outgoing email with DKIM and Domain Keys will not save the manatees, tie your shoe laces, or make you “lose 10 pounds in just 24 hours” but it will make your email recipients (and their mail servers on their behalf) trust your email’s authenticity a lot more, and inturn help you stay out of peoples e-mail Junk/Spam folder. You may think it’s simply easier to outsource your mail sending to someone like SendGrid – either way, if you are having delivery issues and need to have your email delivered, signing your email is definitely a step in the right direction.