How to create DKIM keys and use them with PhpMailer

Djaho
5 min readJul 18, 2020

--

I was setting up an email service as part of our project and had to make sure that the emails which are being sent from our server will be accepted by email providers and delivered to the clients’ mailboxes.
As you probably already know, delivering an email to the client’s mailbox can be a though one. The first thing you want to do is correctly set up all the authentication methods, so the email providers will know that the emails they receive from you were actually sent by you. These are mostly SPF, DKIM and reverse DNS records.
The other part is a bit more complicated one: building an IP reputation of your mail server. But I will only focus on DKIM records today.

So, DKIM record is basically a txt DNS record with your public key. The public key is being used to check if the signature which is appended to your email really was created by you and that the email content was not tampered with.

How to create a DKIM keypair?

The best way to create a DKIM keypair is to use the openssl utility. In my case, I used it on an Ubuntu machine.

Here are the two command lines which you can use to generate a 2048 bit password protected private key file and a (non-password protected) public key file.

openssl genrsa -aes256 -passout pass:YOUR-PASSWORD -out key.private 2048
openssl rsa -in key.private -pubout > key.public

The private key will be saved to a key.private file and the public key will be saved to the key.public file.

If you are a Windows and Putty user (like myself), you probably wanted to generate the key using PuttyGen. Well, you won’t be able to generate a correct keypair (at least not to my knowledge). I tried various formats (including OpenSSH) but none of them was good enough to be used in DKIM signature. The mail providers never accepted my public key. The only signature that worked was the one generated by the openssl utility. But maybe someone knows how to generate one with PuttyGen (feel free to let us know in comments).

Your public key file will have a content similar to this one:

— — -BEGIN PUBLIC KEY — — -
MINBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAzWsw1US9EaVmE9UciNZr
XrxPzYOXSklocqj46DtnenLjGNDoSY7TjdGhSDobHiRCvvGLXoGHJxpII9hZUahXU
6+umSmFh+VNVJiHvL3BHKeaH4SYIcpgCrLkkiVOacu+CHhyDvk0EGFKUtfaIteL0
tsSlULGadAERUXpWyGcYuAgQKKu0zwhi0CvQtG2dOqz+mDz1fWRVH8yKlS12SNzc
G+gJij2+E8O0ZhBjIW5ODg5mFxq7zfP3ljM3gNRFTkPTcc1QhMp534/B1rKbR+Pa
iLnDhKJ0Z+OoiHgyiAAy+qCorfDTWMZoOYHwYeo62TpyOBIi+93DYwxX+2pwuJtZ
UQDDAQAB
— — -END PUBLIC KEY — — -

How to publish a public key?

Add a new txt record for your domain with a desired selector. The selector is a combination of any alphanumeric characters which you use to let the mail providers know which public key should they use when validating the authenticity of your email.

The name of the record has to be composed like this:

DESIRED-SELECTOR._domainkey.yourdomain.com

The _domainkey part is a standard keyword for identifying the DKIM records.

The text record value should look like this (make sure to remove the new lines from the public key):

v=DKIM1; k=rsa; p=MINBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAzWsw1US9EaVmE9UciNZrXrxPzYOXSklocqj46DtnenLjGNDoSY7TjdGhSDobHiRCvvGLXoGHJxpII9hZUahXU6+umSmFh+VNVJiHvL3BHKeaH4SYIcpgCrLkkiVOacu+CHhyDvk0EGFKUtfaIteL0tsSlULGadAERUXpWyGcYuAgQKKu0zwhi0CvQtG2dOqz+mDz1fWRVH8yKlS12SNzcG+gJij2+E8O0ZhBjIW5ODg5mFxq7zfP3ljM3gNRFTkPTcc1QhMp534/B1rKbR+PaiLnDhKJ0Z+OoiHgyiAAy+qCorfDTWMZoOYHwYeo62TpyOBIi+93DYwxX+2pwuJtZUQDDAQAB

After you publish the public key, try to validate it with an online validator.
I used the one on dmarcanalyzer.com. I am NOT affiliated with them, but they do provide a good tool.

How to sign emails with DKIM in PhpMailer?

PhpMailer is capable of signing the outgoing emails with DKIM keys. You just have to let it know:
- the domain from which you are sending the email,
- private key file,
- DKIM selector you want to use,
- passphrase for the private key (leave empty if you didn’t protect the private key),
- and the email address from which you are sending the email.

Here is a sample configuration (assuming you have the key.private file in the same folder as from which you are executing the script):

$mail = new PHPMailer\PHPMailer\PHPMailer(true);

$mail->IsMail();
$mail->CharSet = ‘UTF-8’;
$mail->Encoding = ‘base64’;

$mail->DKIM_domain = ‘yourdomain.com’;
$mail->DKIM_private = dirname(__FILE__).’/key.private’; // Make sure to protect the key from being publicly accessible!
$mail->DKIM_selector = ‘YOUR-SELECTOR’;
$mail->DKIM_passphrase = ‘YOUR-PASSWORD’;
$mail->DKIM_identity = $mail->From;

Make sure to protect your private key!

Protecting the private key file is the crucial step here. If anyone gets access to your private key file, they could start impersonating your email service and sending the emails in your name.
That is something you were trying to avoid in the first place.

You have a few options on how to protect the private key file:

Protect it with a password.

The openssl commands in this tutorial assume that you want to protect your private key with a password, so you probably already did this.
This is the easiest way to protect your private key. However, you should still limit access to the key file itself by using one of the methods described below. The password protection will be your last line of defense in case someone actually manages to get hands on your private key file!

Limit access with .htaccess file.

This is a quite elegant solution of protecting your private key file in Apache or Litespeed web servers. You can place the key file in a dedicated publicly accessible directory on your web server and then just limit the access to it. For example, you can place your public and private key file in a /dkim directory and then protect it with this line in .htaccess file:

RewriteRule dkim/* — [F,L,NC]

This will return a 403 forbidden message to anyone who wants to access anything in your dkim folder (including your keys).
The F flag (forbidden) restricts access, the L means that this is the last rule which will be evaluated and NC means that the whole rule is case insensitive.

Change user permissions on the key files.

You can set the permissions on Linux based servers to only allow access to the keys to specific users. However, if you will want to send emails from your web server, you will have to give access to the user who is running your webserver. And by giving it such permissions, the server will be able to also serve this key to the public.
This option is probably usable if you send the email from a crontab where you can define which user will run the script.

Put it in the folder outside of your web server’s access scope.

Apache usually only has access to the public_html folder and it is quite similar with other web servers. So placing it outside of it will probably prevent it from serving it to the public. However, you probably also won’t be able to access it when sending the email with PhpMailer. So this one is probably a no-go for most of us.

That’s it. You have successfully set up the DKIM record for your domain.
Try to send a few emails to Gmail and check what it says about DKIM signature by viewing the email source. It should give you a PASS score :)

--

--