Comprehensive Guide to Email Alignment Authentication: SPF, DKIM, rDNS and DMARC records

Author:
phil
Created:
Thursday, August 17th, 2017
Last Updated:
Sunday, January 15th, 2023

Disclaimer: Accessing the information on this page means you agree to the Sites Terms of Service


I've been in the computer industry for quite some time and I'll be the first to admit, I don't know everything. Email has always been a bit of a weak area of expertise and while I had heard about SPF, DKIM and DMARC records, I was oblivious to what they are and what they actually do.

I got an email one day that customers weren't receiving their order confirmation emails from a site I maintain. A few weeks prior, I walked a customer through the email password reset process, only they weren't receiving the password reset email. I chalked it up to the ISP email they were using and forgot about it. But when I got the email that multiple customers weren't receiving their order confirmation emails, I knew there was something amiss so I started looking into it. That's when I stumbled on the need for SPF and DKIM records needed at the very least, to properly align email.

It took me a little while to wrap my head around these protocols and the "official" documentation is the typical "You need this, and here's how to do it" written by people that are really smart, but too stupid to actually make sense except to the 1% of people who think like them. It'd be easier to teach a dog how to train a monkey...

Anywho, we'll walk through each one from the standpoint of being clueless to what they are and why they're needed, and hopefully get you up to speed to better understand how and why to create each one. I won't dive into the specifics of each protocol, only the necessary bits to get you familiarized with making it work.

There is a LOT of information out there on each one, but no one really explains it in a dumb-down manner. That's what I'll try to do. I'm still new to it too as of this writing, so if I get a few things wrong, you'll know why.

What you need to understand about this entire subject is that you are setting these protocols for your domain, so that email will properly align. What this means is that SPF and DKIM are seen as a PASS for your email domain. There are situations when those protocols will show as passing, but they may show as a PASS from a different domain such as an SMTP relay. This looks good at first glance, but digging deeper you'll find that the emails aren't aligning properly and the receiving server might still reject the emails.

Fore-warning: You need to have a basic understanding of DNS. If you don't know anything about DNS, this isn't going to be easy... If you can at least hop on Godaddy or 1and1 or your hosting DNS Zone editor and change an A record or create a CNAME, you'll be fine. Not hard at all.

Common Info

All of the records, SPF, DMARC and DKIM records are setup in the DNS zone of your domain as a TXT record. How each is setup is a bit different from each other, but they are all setup there. That means you have to have access to the authoritative nameserver of your domain. If you use Godaddy to handle all of your domain records, then that's where you set it. If you use a hosting server for the web, and you told Godaddy to give DNS control over to that hosting server (by changing the name servers) then you setup the records over on the hosting server. If you aren't sure, figure out where your name servers are located first.

There are 3rd party server hosting software such as cPanel that have some pretty cool stuff to automatically take care of the DKIM and SPF records of the account on that server (but only that server...). Otherwise, you'll have to set it up manually in the DNS Zone of your hosting software.

SPF Records

SPF stands for Sender Policy Framework. Like you, that meant absolutely nothing to me. What an SPF record does, is tells the recipient email server that an email they just received, is legit "if" it comes from w.x.y.z IP address. This information tells the recipient that the email MUST be somewhat legit, because it came from an IP that is in the SPF record. You have to have access to the DNS Zone records to set the SPF record in the first place, so if you have access to the DNS Zone, the email "MUST" be legit because you manually added an IP address of the mail server who just sent the email. That allows the recipient to have a better trust of the email and gives it a lower spam score on the spam filters.

Let's say your server sends an email without an SPF record. The recipient server looks at it and says: "You just sent me an email from acme.com and the email came from 1.2.3.4 IP address. I have no idea if the IP 1.2.3.4 is actually supposed to send email on behalf of acme.com, so since I can't tell.... eh... we'll throw it to the wolves and protect the user who was supposed to receive it. Or, they might actually pass it through if the content of the email doesn't seem spammy. It can really go either way and it's all up to the receiving email server.

To fix this, you would create an SPF record in the DNS zone for acme.com, to tell the recipient that the email you just sent from IP 1.2.3.4, in fact has permission to send email on behalf of acme.com.

Things to Know

Several things you need to know about formatting and syntax of SPF records.

1) The "Record" is always TXT

2) The "host" can be pretty much anything. In other words, there's no specific host / subdomain parameter (unlike DKIM and DMARC that have specific host parameters). You can use _spf.acme.com, spf1.acme.com, myblocks.acme.com, netblocks.acme.com, _netblocks.acme.com, etc. AS LONG AS the main domains SPF record points to one of these as a domain include (covered later). For example, you need an SPF record on acme.com that lives on acme.com.

3) Always start the record value with v=spf1. (If the protocol gets updated in the future, you'll want to change this...)

4) Always separate the syntax with a space and semi-colons are NOT needed to separate the syntax (unlike dmarc and dkim records which require semi-colons)

5) Even though the SPF is setup and correct, some recipients will still reject your message if rDNS isn't setup (more on this later)

Something else to keep in mind is your hosting environment. Just because your domain is acme.com and the server IP is 1.2.3.4, doesn't mean that's the same IP address your email is coming from. For example, let's say you're on a shared hosting server. There might be 10 IP's on that server, spread out among 300 domains. But, they all use the same outgoing email server, using the IP of the server itself. What can be tricky, is figuring out exactly what that IP is. The easiest way is to send an email to yourself through your website webform, then inspect the headers of the email. It should tell you what the IP address was that sent the email. Gmail is really good about giving you quick access to the headers. If you look at the "original" message, it has a section for SPF and tells you exactly what the IP is that sent the message.

What becomes even more tricky, is cloud hosting services. Since the hosting isn't contained to any one single server, it can be spread out among all sorts of IP addresses and figuring THAT out can be a bit tedious. For example, I helped a client out who was on bluehost.com. For whatever reason, using bluehosts spf record threw up an error that there were too many DNS lookups, so I decided to condense their list to create my own. I had to dig into their SPF records to find the list of IPs that they specify and only add those IPs to my own SPF record. Sometimes, you'll get lucky if you're on a decent hosting platform and you can simply just point to their pre-defined spf record. Other hosting providers, probably don't make that information easy to find or they have a really bad SPF record because they didn't set it up properly.

Getting the Basics

Overall, SPF records are easy to deal with. You either point to an IP address or you include a domain that has IP addresses setup.

Imagine being in the DNS zone editor for acme.com with the IP 1.2.3.4. You would create an SPF record to look something like this:

v=spf1 ip4:1.2.3.4 ~all

The "Host" would be @ and the Record would be a TXT. (the @ means acme.com on some hosting providers like Godaddy. Just know that you need to point back to acme.com)

DomainRecordHostValue
acme.comTXT@v=spf1 ip4:1.2.3.4 ~all

What if acme.com IS the IP for the email server?
There's a option you can add to make things super easy. It's simply adding an a to the list. If acme.com is IP 1.2.3.4, you don't need to add ip4:1.2.3.4. Just add a.

v=spf1 a ~all

This says: "look at the public IP address of acme.com".

What if I use the same IPs that are associated with my MX records?
There's an option you can add to look at the mx records for the domain. This usually isn't needed because a lot of times, the MX records will be different than the outgoing server IP in most cases. Even if you had a server running at your home, you'd probably be fine with just using the a option because incoming and outgoing are both on the same server. Either way, you can simply set the mx option as follows:

v=spf1 mx ~all

If you wanted the MX and the primary domain, you would set it like this:

v=spf1 a mx ~all

Ok, but what if I have a bunch of outgoing email servers on different IPs?
Simple. Just list them out, separating each new ip with ip4:

v=spf1 ip4:1.2.3.4 ip4:5.6.7.8 ~all

What if my IP is ipv6?
Just change the ip4: to ip6 and you're golden :-)

Ok, but what if my server has a LOT of IPs?
This depends... Are the IP's all on the same subnet? If so, you can simply add the subnet mask to the end of the ip4: or ip6:

v=spf1 ip4:1.2.3.4/24 ip6:2000:6000:4000::/36 ~all

If the IP's aren't on the same subnet and they're scattered all over the place, it might be time to wrap them into their own SPF record. You can totally have multiple SPF records that chain into each other. You usually want to start with the top most SPF and use that one to daisy chain down into other records. This is where it gets interesting...

What if I don't need an IP, I need a domain because I was told by my email provider to use something like _spf.acme.com
Hold your horses!! We'll get there... Keep reading...

Wrapping SPF Records

Let's say you control 5 different domains on 5 different hosting servers. Each has it's own IP. They're YOUR servers that YOU control, so you trust them and know that each one is totally legit. BUT, you don't want to keep track of IPs for each and every server, to deal with the SPF records for each domain. Choose a domain that you would consider to be the primary domain of them all. Usually, you'll have a domain that kind of "houses" all of the other domains. Use that primary domain to create an SPF record that houses the IP addresses of all the mail servers for the other domains. (This same concept will work if you use 3rd party email services like mail-chimp, or a CRM like salesforce. They generally provide their SPF records for you to point to.)

Let's say the main company is acme.com and acme.com owns the subsidiaries acme-bricks.com, acme-steel.com, acme-wood.com, acme-stone.com etc, and each domain has it's own email server, therefore IP address.

acme.com 1.2.3.4
acme-bricks.com 2.2.2.2
acme-steel.com 3.3.3.3
acme-wood.com 4.4.4.4
acme-stone.com 5.5.5.5

You would create an SPF record on acme.com to look like this:

v=spf1 ip4:1.2.3.4 ip4:2.2.2.2 ip4:3.3.3.3 ip4:4.4.4.4 ip4:5.5.5.5 ~all

Now acme.com houses the IP addresses for each of the different servers, therefore they're all legit. The next thing we need to do, is tell the OTHER domains, to point THEIR SPF record over to acme.com. So instead of adding the IP address in the SPF for each and every domain, you can set it in one place, acme.com and if the email server IP changes for any given domain, you only have to change it on acme.com because all of the other domains point to acme.com.

This is accomplished by using the include: option for the other domains. So effectively the SPF record for each domain would look like this:

acme.com TXT v=spf1 ip4:1.2.3.4 ip4:2.2.2.2 ip4:3.3.3.3 ip4:4.4.4.4 ip4:5.5.5.5 ~all
acme-bricks.com TXT v=spf1 include:acme.com ~all
acme-steel.com TXT v=spf1 include:acme.com ~all
acme-wood.com TXT v=spf1 include:acme.com ~all
acme-stone.com TXT v=spf1 include:acme.com ~all

When an email is sent through acme-bricks.com, the recipient looks at the SPF record which says: "Hey, go look at acme.com for legit servers". So it looks at the TXT SPF record for acme.com which has 2.2.2.2. It's legit! And passes the email through.

You do need to be careful when crafting these types of SPF records though because you can only have 10 DNS lookups per record. If there are too many lookups, the recipient might reject the email.

Let's look at another situation, where you have domains to other email providers, such as Mailchimp for mass email, or Google Workspace for primary email but you also have your own hosting server that sends email through the website. This isn't very many things to keep track of so they would all fit nicely inside a single SPF record, but let's say you're a neat freak and want an SPF record that ONLY holds domains and another SPF record that ONLY holds IP addresses. You would create 3 total TXT records for this, one top one to house the bottom two:

Here's an example

_spf.acme.com

  • _netblocks.acme.com
  • _netdns.acme.com

You would first create an SPF record inside the _spf.acme.com that points to the two lower SPF records:

v=spf1 include:_netblocks.acme.com include:_netdns.acme.com ~all

Then, you setup the respective IP's or domains within each of the bottom spf records:

_netblocks.acme.com
v=spf1 ip4:1.2.3.4 ~all

_netdns.acme.com
v=spf1 include:_spf.mailchimp.com include:_spf.google.com

From here, you set the acme.com SPF record to look at _spf.acme.com, so you can still point your other domains to the central spot include:acme.com:

acme.com
v=spf1 include:_spf.acme.com ~all

So, if acme.com is pointing to _spf.acme.com and _spf.acme.com is pointing to _netblocks & _netdns, when you point acme-bricks.com to acme.com, it then inherits everything that is housed within acme.com (_spf _netblocks & _netdns).

Yup, it's confusing... That's why you need a tool to help you visualize it.

DMARCIAN has a freaking fantastic tool that shows all of the links for an SPF record and they will tell you if you have too many lookups.

https://dmarcian.com/spf-survey/

Take a look at their tool against google.com: https://dmarcian.com/spf-survey/google.com

SPF and Subdomains

There might be times when you need to deal with different SPF records on different subdomains. There's a catch: Is the subdomain a CNAME or an A record?

If the subdomain is a CNAME of the primary domain, meaning it is using the same IP as the primary domain, then it will automatically include the SPF record for the primary domain.

Let's use the examples docs.acme.com and api.acme.com

docs.acme.com is a CNAME of acme.com so it points to the SPF record for acme.com and you don't need to change anything.

However, api.acme.com is an A record with it's own IP. In this case, you will need to create a new TXT record for api.acme.com and give it an SPF record. This record can easily just point to the acme.com SPF record or if you need something completely different, it can have it's own unique values.

Example

api A 1h 4.5.6.7
api TXT 1h v=spf1 a include:spf.acme.com ~all

SPF and SMTP Relays

I'll be honest and say that SMTP relays are a bit foreign to me, but from my understanding, you can route all of your email through an SMTP relay and the email will use the relays SPF record to authenticate the message. However, for proper alignment (different from authentication) you still need to add an SPF record that points to the SMTP relay service IP in your own domain DNS records.

SPF Macros

If you want a more advanced way of controlling SPF records, you can use what is called DNS SPF macros that are designed to somewhat automate the lookup process dynamically. This is something that is out of the scope of this article, but here are a few places to read up on the topic:

https://www.jamieweb.net/blog/using-spf-macros-to-solve-the-operational-...
https://duo.com/labs/tech-notes/detecting-phishing-with-spf-macros
https://www.cisco.com/c/en/us/support/docs/security/email-security-appli...

Additional Reading

Google
https://support.google.com/a/answer/33786?hl=en

Dmarcian
https://dmarcian.com/spf-syntax-table/

OpenSPF
http://www.open-spf.org/
http://www.open-spf.org/SPF_Record_Syntax
http://www.open-spf.org/FAQ/Common_mistakes

Misc
https://blog.mailtrap.io/spf-records-explained/

Reverse DNS (rDNS)

Reverse DNS is a little talked about aspect of email deliverability. It doesn't have anything to do with alignment and the 3 main protocols which is probably why most folks don't talk about it. But just because you setup the SPF records and your email IPs are all passing, doesn't necessarily mean your email is going to be accepted by the recipient. Some email providers, such as Comcast, will explicitly REJECT any and all mail that doesn't have Reverse DNS properly setup.

So, what is Reverse DNS?
Reverse DNS is the backwards looking IP for a Domain, known as a Pointer or PTR record. It's the primary domain associated with a specific IP. For example, you can look at acmemail.com and see 1.2.3.4 or you can look at acme-bricks.com and see 1.2.3.4. But if you look backwards at what's on 1.2.3.4, you will see: acme.com which is considered the "primary domain" for IP 1.2.3.4. Even though other domain IP's point to 1.2.3.4, they aren't the primary domain when looking back at 1.2.3.4, acme.com is the primary.

It basically boils down to this:
If acme.com is the "primary domain", then acme.com should point to 1.2.3.4 and 1.2.3.4 should point back to acme.com.

You can only have a single primary domain associated with an IP address, and going both forward and backwards must match.

Here's a simple scenario, given acme.com is the primary domain:

acmemail.com points to 1.2.3.4 which points to acme.com which also points to 1.2.3.4. The reverse DNS for acme.com matches, therefore anything sent from acmemail.com will pass.

Let's say you have a situation where acmemail.com points to 1.2.3.4 but looking back at 1.2.3.4 points to someserver.com. When looking forward at someserver.com, it points to 6.7.8.9 but looking at 6.7.8.9 points to whoknows.net. The rDNS doesn't ever match.

The easiest way to find out what the reverse dns is on an IP is to do a ping command with the -a switch on an IP address. (Windows computers)

ping -a 1.2.3.4

This should output:

Pinging acme.com [1.2.3.4] with 32 bytes of data:
Reply from 1.2.3.4: bytes=32 time=47ms TTL=55
Reply from 1.2.3.4: bytes=32 time=47ms TTL=55
Reply from 1.2.3.4: bytes=32 time=47ms TTL=55
Reply from 1.2.3.4: bytes=32 time=49ms TTL=55

Ping statistics for 1.2.3.4:
    Packets: Sent = 4, Received = 4, Lost = 0 (0% loss),
Approximate round trip times in milli-seconds:
    Minimum = 47ms, Maximum = 49ms, Average = 47ms

Two Types of Reverse DNS with Email

When you're dealing with email, there are two types of Reverse DNS you need to consider:

1) The reverse lookup of the sending server (The IP of the "Received from:" header of the email)

This is the server domain that physically sent the email.

When a server sends out an email, it sends out headers that tell the recipient what it is and what to do with it. Within those headers, is the IP address of server that sent the email. If the IP doesn't match the domain the email came from, then the message is rejected. Here's what the header would look like:

Received: from acme.com (acmemail.com. [1.2.3.4])

Sometimes the sending server is the same domain as the email sent, but usually it's different. For example if you send an email through MailChimp, the Received: from will show Mailchimps domains and IPs. Mailchimp servers sent the email on your behalf and their server IP rDNS need to be legit.

2) The reverse lookup of the email domain

This is the domain that the email was sent from.

When a recipient receives an email, it looks at the email domain that sent it and does a reverse lookup on the domain to find the IP. It then does a forward lookup on the domain to see what the IP is. If the two don't match, meaning acme.com -> 1.2.3.4 and 1.2.3.4 -> someserver.com but someserver.com going forward points to 6.7.8.9, the message is rejected.

The only place to change your reverse DNS or PTR record as they are called, is through your ISP. It is very rare that you will have control over the domain for the reverse lookup address. Usually you must call the ISP that owns the IP. Some hosting companies, give you access through their billing interface to change it yourself. It just depends.

One nice thing about the actual reverse dns lookup, is that the domains don't have to match each other. Like the example above, if acme.com sent the email from IP 1.2.3.4, as long as when you ping the host that is found on IP 1.2.3.4 (in this case acmemail.com) points to 1.2.3.4, then it's a match. This is how you get around shared hosting. The actual reverse DNS isn't as picky as the reverse lookup on the email IP header, which does have to be an exact match between the IP and the sending domain.

What if I can't specify the IP address my email comes from for the email headers?
Well, that basically means it's time to make a decision:

1) Know that email will get rejected if sent to certain providers.

If you're going to send email out through your webserver to a single email address, such as collecting contact forms generated on the website, then chances are you're fine as long as the email address isn't rejecting based off the rDNS. (So, you can't use Comcast as the email your contact forms go to.) This is bad though, if you have an e-commerce website and you want ALL of your customers to receive their order confirmation emails.

2) Upgrade your hosting to a VPS or equivalent service that will allow you to set the outgoing IP address.

If you move over to a VPS or Dedicated server, you can then set the outgoing IP address to match the domain. cPanels WHM has the option to "Send mail from account’s dedicated IP address" in the EXIM configuration. If you're the only person handling the box, turn this on and forget about it.

I've learned through experience that companies like Hostgator, will NOT turn this type of feature on or enable it on the server. I tried contacting them and their response was that they couldn't do it because the email "routes through too many internal gateways". Their fix? Upgrade hosting to a VPS. Pretty lame if you ask me considering it has nothing to do with the "routing" of the email, but rather the server that sent the originating email.

DKIM Records

DKIM records are a public / private signing method between the sender and the recipient. There's lots of technobabble about how it works, why it works, when it works etc and I'm not going to go into that... All you need to know is that the DKIM record authenticates your domain against a public / private signing key pair. You send a message with the DKIM info and the recipient takes a look at the key and does a check against your domains DKIM record. Then it does a lookup to make sure the matches and if so, passes the email through. It's like getting a ticket to a movie and handing that ticket over to the ticket guy. Sure, anybody can have a ticket they purchased at any time, but the job of the ticket taker is to make sure the info on the movie ticket matches the list of movies that are currently playing. If not, you aren't getting in.

At first glance, DKIM looks pretty easy. There aren't many pieces to the syntax and for the most part, everyone says to "copy and paste". Don't let that fool you though. You need to understand some things about DKIM, especially if you plan to run in a cPanel type of environment.

If I can get anything to stick in your head, like really pound it in there, I want you to make sure you know and understand that you MUST have a unique key for each email server, and each domain. "What's that mean?" Let's say for example, you have two domains and need email on 1) a Webserver with a contact form 2) Email through Zoho or G Suite and 3) MailChip for email lists. This adds 3 different email servers (SMTP) into the mix and you have your two domains for each server, so you would need 6 different key pairs. Each server, must have the private key loaded onto the server per domain so when the request comes in on the public key, the server can send the response that says "Yup, that's legit!". Unless YOU have direct control over the root access of the various servers, you aren't setting up a DKIM key... Fortunately, the good email platforms, already have key generators setup on their end and all you have to do is generate the key and create the new DNS TXT record. This means you don't have to come up with your own key pair, then try to get MailChip to use YOUR key... They already provide you with one and have it stored in the right place on the server to make it easy for you.

While we're on the topic of having the 3 different services and say, 2 domains, hopefully you can kind of see why you need 6 unique DKIM keys. You can't exactly get Google or MailChip to use your own generated private key and they aren't going to just go off and give you their private key... Because it's private... and that's the whole point...!!!! So that means one part of the key pair is stored on the server, the other part of the key pair is stored in your DNS TXT record, and this is multiplied across each and every top-level domain and sub-domain that needs email signing.

Ok. I think we're good. Hopefully... Because now you need to understand how this impacts a lot of 3rd party hosting companies. Which can get a bit confusing, unless you've read this whole explanation, and since I make mud look clear as mud, you'll be good to go after this.

cPanel Instruction & Other "Hosting Made Easy" Platform Info

When I first started messing with DKIM records, I honestly thought you generated your own key, put the public key info out in the TXT record and somehow, because you generated a key, the other side (whichever that may be) would automajically pull the private key out of thin air. Yeah, it doesn't work that way... That private key has to be somewhere and usually, it's automatically generated on your website hosting platform. For you. Easy Peasy. Or is it... ? You'll find that some hosting providers don't provide the ability to enable DKIM. They've got you on a super old setup that doesn't even expose email authentication. If that's the case, seriously, go find a new hosting provider. Your current one isn't worth the money you're paying them.

I'm going to discuss cPanel because it's what I'm familiar with. Hopefully I give enough insight that can help you on non-cPanel platforms.

cPanel, a few years back, introduced the ability to enable DKIM globally for your entire account, from the cPanel interface (Email -> Authentication). This enables DKIM on all of the the domains for your account which is super awesome because it creates the private key and stores it for you in the background, then takes it a step further and adds the necessary TXT records into it's local DNS system on the server. This can be super good, if you're using the hosting platforms nameservers, but it can be super-duper confusing if you're hosting your nameservers elsewhere.

If you pointed your nameservers to the hosting server, you're golden. Sit back and relax because your emails are now being signed (assuming nothing else went wrong)! You can basically forget everything blow this point (for the DKIM stuff) and bask in the fact that you can remain blissfully ignorant. Yes, I'm jealous.

However... and this is a big HOWEVER, if you're using the nameservers elsewhere, on say... Godaddy, you have some work to do. I'm going to assume you have half a brain to figure out what I'm about to say, since you're hosting the nameservers elsewhere. cPanel did the heavy lifting for you and generated both keys and stored the private key and they even went so far as to update it's local DNS records for your account. Great. From here, it could get a bit fuzzy. You might be able to access the DNS Zone Editor to pull the public key out, you might not. It all depends on whether your hosting provider gives you access to the "Advanced Zone Editor". If you DO have access to it, then you can basically copy and paste the key and be done with it. But if you don't have access to it through the interface, you'll have to SSH into the server, dive into the directory /var/named and view the DNS zone .db file for each and every domain to pull out the TXT record so you can enter it on your domain registrar or nameserver. This is assuming you have access to the /var/named file... You may not have the permission to open it.

In other words, you'll have to go find the public key that resides on your hosting server, so you can use it to create the record on your nameserver provider.

Things to Know

1) The "Record" is always TXT

2) The host must always have a minimum of _domainkey before the main domain. (ex: _domainkey.acme.com) or sub-domain(s) (ex: _domainkey.blog.acme.com)

3) Always start the record value with v=DKIM1;

4) DKIM record syntax is always separated with a semi-colon ; and left off of the very last syntax option.

5) You "may" need to escape the semi-colon depending on your DNS editor. (probably not though...) For example k=rsa\;

6) Not all DNS providers are the same!! Some providers may require you to separate the key, within the record. This can be done by quoting the various pieces to create 255 characters between the first set of quotes, then finishing the last part of the record off with the second set of quotes. I'll explain this a bit later.

7) Some DNS providers might have buggy front-end or backend software! This translates to mean that even though you enter in a correct DKIM record (Bluehost) a 2048 bit key doesn't get translated to the backend DNS server software properly, or the DNS server software is outdated and doesn't understand how to chunk the value. In the case of Bluehost, chunking the key value did absolutely nothing... It's a problem on their end though.

Getting the Basics

Adding DKIM records are, for the most part, pretty easy. You have the statement that tells what the protocol is designated with v, the key type designated with k and the key itself designated by p.

Let's put it all together:

v=DKIM1; k=rsa; p=MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAkArcXi9GwuT2Hm0VO/bDU58BFhmaol1Wv+lAgx+fcKGyF+dQHhB63A0+UBW6nyiejCelMjPU5LpcSGKUTfCmIpG3eSF3nSONz6lDIQYeujnzifXy9nvei25g26Jrtme3q5POoSv6RMpEyHieMfVglZbazasyrOszRUxmRTrZZud6msDiVuSwrSPA1tT80olSUX5V9LWYxVjLcj5SYe7PRoHD5iyjmfioLUgAo/IznpXpnf9tIgr8kwAqFFV4/EzxTbh6/vV1sa5qSVZprhdZHBFLbWj4iMOESghXhOVZV1U4WLIa+l/abAlklAXn6sxo4aGkKCIvVtYTZecslXVwIDAQAB

So where do you get the key?
If you read upto this point, you'll know that keys are generally provided by your various hosting or email providers. If you know how, you can generate your own key and add it to your server, but otherwise, I don't recommend going that route.

The _domainkey Policy Route

When adding the DKIM record, it's very similar to the SPF record. You use a TXT record to hold the information, but instead of pointing the host to the main domain (@), you need to have _domainkey as the host. It's like a CNAME record or subdomain.

For example:

DomainRecordHostValue
acme.comTXT_domainkeyv=DKIM1; k=rsa; p=MIIBIjANBgkqhkiG9....... (the rest of the key)

This would end up looking something like _domainkey.acme.com TXT v=DKIM1; k=rsa; p=MIIBIjANBgkqhkiG9....... (the rest of the key)

Some websites will state that you can simply use _domainkey as the host and while this may be true, you're actually supposed to use a selector at the beginning of the host to designate a specific record. _domainkey is the "Policy Record" where the selector is the "Selector Record".

Ok, what does that mean?
If you want to tell the recipient what kind of policy YOU want for your signed emails, you use the _domainkey without a selector with a value of v=DKIM1 o=~ or v=DKIM1 o=-. This tells the the recipient that "o=~" SOME of the emails are signed by acme.com or "o=-" ALL emails are signed by acme.com. If you don't use the policy record (the _domainkey without a selector) then it just defaults to "o=~". I've got a handful of domains without the policy record and it's signing emails just fine...

The Selector Record

Selector are added to the beginning of the _domainkey, followed with a period.

It looks like this:

[selector]._domainkey and put together with the domain, it ends up like [selector]._domainkey.acme.com.
That doesn't really give a good realworld, so let's call our selector dkim for simplicity. It would look like this:

dkim._domainkey.acme.com

The selector can be anything that is alphanumeric. I'm not sure if it can be uppercase or not, but I'd stick with lowercase personally and I'm not sure if it can start with a number... From what I've seen though, the number comes at the end of the selector, such as dkim1 or key2.

So, let's say you setup your selector to be key1, the record would end up looking something like this:

key1._domainkey.acme.com TXT v=DKIM1; k=rsa; p=MIIBIjANBgkqhkiG9....... (the rest of the key)

Now that you've got a decent understanding about the keys, let's talk about separating the keys to fit within the TXT record. Some providers like Godaddy, will let you enter the full key record because they split it up for you on the backend. RFC for the TXT records dictates that you can only have 255 characters maximum, which means harder-to-use domain providers, will want you to separate the key with quotes.

Here, it's easier if I just show you:

"v=DKIM1; k=rsa; p=MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEA3wneU8W5M72g3ZJy4qG4QU2y+yiYbCTDZ09wAYAD4qlQWAmc15fFJEYTgIWkvmcro1VEYGKEVbUXhDQHCwFPBFuLlKvS7D8uRhO746FhwK0frmxg0j0f8Sx5EWh0q5QCw6OktqmKFLLzZ5KUunyAaoOWCWLEbIonDfRs/iNIOsc3MJHaHs/Egrgwkdd" "QVZGsSVS41gDAyPdxml/7bkWwsHYgaiLdIcSg3vvAjpSk5mDZIxzyOPIYMRfqmhVeziw0dBjP0fXbtj/f7VeIK+TXcvW64j9qPncBHM9yToGqvqNzCE5roZZNAucieEXM+wCwEsgLvmeMJfAMvExUpDSinwIDAQAB;"

So "v=DKIM1; k=rsa; p=MIIBIjANBgkqhkiG9w0BAQ...[+215 more characters = 255]" "[the rest of the key]...xUpDSinwIDAQAB;"

By separating with quotes, then a space between groups, you essentially create line break within the DNS system with each block containing upto 255 characters. (because DNS servers are smart enough to figure THAT out, but not when to count to 255 and separate them automatically...)

That's it with DKIM keys. They're really pretty simple to implement, just an absolute headache if you don't know "I need the public key from each and every one of my service providers! DKIM Generators won't do squat for me unless I'm a superguru! And I need a different DKIM key for each and every domain!" If you can't tell, I hit my head against the email wall for about a week trying to sort this out...

DKIM and SMTP Relays

DKIM and SMTP relays can get a bit interesting. I'm fuzzy on the details, but SMTP relays have the ability to authenticate the messages they send, with themselves. Instead of the DKIM showing as authenticating from YOUR domain, it shows it authenticating with the relays domain.

On the front end, this might seem fine, but on the backend it still doesn't properly authenticate that the email is originating from your domain. Many of the DMARC analyzers will show the message DKIM as passing because at the end of the day, all they're looking for is a DKIM that passes. But if you have a super strict incoming server that is looking for a DKIM that is authenticating from your domain, it might get blocked even though the message has a proper DKIM in place by the relay.

I mentioned earlier that I don't have a lot of experience with SMTP relays, so I may not have all of my facts straight, but if you want 100% reliability with your messages, you need to find the DKIM key's that are provided by your SMTP relay service that are tied to your domain and add those into your DNS records. That way you don't ever have to worry about the recipients incoming email server bouncing the message because the DKIM isn't coming from your domain.

So, even though you may not need to set your domains DKIM through an SMTP relay, you should still set the DKIM for your domain through the SMTP relay. A good SMTP relay service will guide you through the DNS records they require in order for your emails to have 100% deliverability through them.

Additional Info

Validators
https://dmarcian.com/dkim-inspector/
https://www.mail-tester.com/spf-dkim-check
https://mxtoolbox.com/dkim.aspx
http://dkimcore.org/tools/keycheck.html

Documentation
http://www.dkim.org/
http://www.dkim.org/info/dkim-faq.html

DMARC Records

DMARC records are basically an authentication blowback mechanism. If an email gets rejected by a recipient because it doesn't have SPF or DKIM setup, usually the recipient server will just discard the message as spam and won't notify anyone about it. DMARC fixes this by telling the recipient "Hey, if you're going to throw it away, at least send it over to my email so I can look at why you threw it away."

Using an email within the DMARC isn't necessary to keep track of the rejects, but it helps give you a much better understanding of what's happening to your email when you get a customer calling up complaining because they "never received an order confirmation letter."

DMARC is designed as a way to prevent hackers from spoofing your domain and sending email on your behalf, without you knowing about it. The DMARC record gives YOU the control, to tell the recipient what to do with the email if the SPF and(or) DKIM don't pass. It pretty much says that if SPF fails or DKIM fails, then quarantine or reject the email. Quarantine leaves the decision up to the recipients spam filters, but this can be seen AS spam and they might block you over time. Reject on the other hand, flat out denies the message. Eventually, telling the recipient to "reject" email is the ultimate goal of where you want your email setup to be.

Things to Know

1) The "Record" is always TXT

2) The "host" must always have _dmarc at the minimum, before the main domain. (ex: _dmarc.acme.com)

3) Always start the record value with v=DMARC1;

4) Like DKIM record values, the DMARC record values must be separated by a semi-colon ; except for the last item in the value.

You can setup a single domain email, that spans across multiple domains. I'll explain this in a bit.

Getting Started

DMARC records are just like SPF and DKIM records. They live within TXT records. While there's a handful of syntax options you can choose from, there's really only 3 syntax you need to worry about to make it pass, with the 4th being an optional setting:
1) The protocol version: v | Which is currently DMARC1 -> v=DMARC1
2) What to do with it: p | Options are none (do nothing), reject (dumps it), or quarantine (sends holds onto it for a while for further investigation by the sender)
3) Where to send it: rua | MUST have mailto: -> rua=mailto:authreports@acme.com
4) How often to report: pct | is a percentage of email to send to the reporting email, for example p=75 is 75% percent of the email gets sent back for review.

Diving In

Like the DKIM record, you have to use a specialized "host" to designate it as a dmarc, which is _dmarc

Put together with the domain and you end up with:
_dmarc.acme.com

Pretty simple.

DomainRecordHostValue
acme.comTXT_dmarcv=DMARC1; p=quarantine; rua=mailto:authreports@acme.com

When you look at it in the editor, you get something like:

_dmarc.acme.com TXT v=DMARC1; p=quarantine; rua=mailto:authreports@acme.com

One Email, Multiple Domains

So let's say you control 5 different domains. (we'll refer back to the acme.com domains in the SPF Records area) You want each domain, to send all rejected email, back to mailauth@acme.com. It's totally possible, but it requires a special host be setup within the DNS of the primary email domain, in this case acme.com.

You first setup all of the DMARC records on the various domains, for example:
_dmarc.acme.com TXT v=DMARC1; p=quarantine; rua=mailto:authreports@acme.com
_dmarc.acme-bricks.com TXT v=DMARC1; p=quarantine; rua=mailto:authreports@acme.com
_dmarc.acme-steel.com TXT v=DMARC1; p=quarantine; rua=mailto:authreports@acme.com
_dmarc.acme-wood.com TXT v=DMARC1; p=quarantine; rua=mailto:authreports@acme.com
_dmarc.acme-stone.com TXT v=DMARC1; p=quarantine; rua=mailto:authreports@acme.com

Next, you need to add a pointer for each of the extra domains, back to acme.com with a record that uses the domain, with ._report, with ._dmarc. Notice there's a period before ._report and a period before ._dmarc. They're subdomains, so they must be treated as such.

So, for acme-bricks.com, your host should look something like this:
acme-bricks.com._report._dmarc.acme.com

so-on and so-forth:
acme-bricks.com._report._dmarc.acme.com
acme-steel.com._report._dmarc.acme.com
acme-wood.com._report._dmarc.acme.com
acme-stone.com._report._dmarc.acme.com

The value for these, is super easy. Just add the protocol to the value. You end up with it looking like this:

RecordHostValue
TXTacme-bricks.com._report._dmarcv=DMARC1
TXTacme-steel.com._report._dmarc.acme.comv=DMARC1
TXTacme-wood.com._report._dmarc.acme.comv=DMARC1
TXTacme-stone.com._report._dmarc.acme.comv=DMARC1

Additional Info

Validation
There are quite a few validators out there, but my favorite is:
http://www.valimail.com/dmarc/domain-checker#/

DMARC Creator
I ran across an awesome tool that will walk you through the steps of creating your own DMARC record:
https://dmarcguide.globalcyberalliance.org

Tags & Purpose

Tag Name
Purpose
Requirement
Sample
Options List
Default
v
Protocol version
Required
v=DMARC1
DMARC1
n/a
p
Policy for organizational domain
Required
p=quarantine
none | quarantine | reject
n/a
sp
Policy for subdomains of the original domain
Optional
sp=reject
none | quarantine | reject
(uses p tag setting)
pct
Percentage of messages subjected to filtering
Optional
pct=20
[0 - 100]
(anything between 0 and 100)
100
fo
Failure reporting options (report if:)
Optional
(only applies if ruf is set)
1
0 (all "pass" failed)
1 (any "pass" failed)
d (signature failed)
s (spf failed)
0
ruf
Reporting URI for forensic reports
Optional
(any valid email address)
n/a
rua
Reporting URI of aggregate reports
Optional
(any valid email address)
n/a
ri
Seconds between requested aggregate reports
Optional
‭259200‬
[0 - 4294967295]
(anything between 0 and 4294967295)
86400 (24 hrs)
adkim
Alignment mode for DKIM
Optional
adkim=s
r (relaxed) | s (strict)
r
aspf
Alignment mode for SPF
Optional
aspf=r
r (relaxed) | s (strict)
r

Documentation

https://tools.ietf.org/html/rfc7489
https://dmarc.org/2015/08/receiving-dmarc-reports-outside-your-domain/
https://dmarc.org/wiki/FAQ

DMARC Analyzing

Once you have your SPF record, DKIM signing, Reverse DNS and DMARC in place, the next step is to sign up for a DMARC aggregator website that you send all of your DMARC emails to. These services do charge for larger volumes of email, but the benefit is that you don't have to weed through 15+ emails every day with a zip file containing an un-formatted XML file. DMARC Analyzer for example, will put everything together into graphs and gives you a MUCH better idea of what you email is actually doing which is part of the whole point of DMARC records in the first place.

After you begin collecting data, you'll start noticing what your emails are doing. If they are failing or not aligning, check out Agari.com for some details on how to fix those problems: https://www.agari.com/identifier-alignment/

In a situation I ran across, DMARC was failing when sending email to a group email through Google's G Suite. The domain was an alias domain on the G Suite account, so it didn't make sense why it was failing when everything else (SPF & DKIM) were correct. This led me to the agari.com site I mentioned above, which mentions that the "From Domain" address must match. Oddly, G Suite would NOT send the email from domain as the alias on the group, only on the main account domain, causing the failure. I decided to look THAT up and it led me to a serverfault.com answer that describes the problem and fix exactly: https://serverfault.com/questions/779730/why-dont-my-domains-messages-to...

Google Groups will only rewrite the From: header when the DMARC policy of the original sender (you in this case) is set to reject or quarantine.

With DMARC/p=none, DKIM isn't rewritten when sending to a group, but because DMARC is set to "none", it doesn't matter that the group will break DKIM from the point of view of delivery and spam detection - it will still get delivered properly. Unfortunately, it does make it look confusing if you're monitoring your deployment.

In order to see the correct behavior you can switch to p=quarantine and monitor the delivery. Please tell me if there is anything else I can assist you with, I'll be glad to follow up.

I did indeed have the p=none set because I was in the beginning stages of testing the email DMARC rates, so the next step would be a quarantine and eventually reject.

Additional Resources

Post Comment

Comments

Hi Phil,

You spoke of your struggles with BlueHost for one of your clients. I'm with Bluehost and was able to set up my SPF records, but I'm struggling to enable DKIM for my domain. I reached out to support and they simply told me they don't set up DKIM for their customers and just told me to visit http://www.dkim.org/... Did you manage to set it up for your customer finally? If so, can you share how you did it?

Hey Nick,

I hate to say it, but I honestly don't remember exactly what the outcome was. (I've slept since then) I want to say the client did get BlueHost to comment on the issue, but I can't remember if they were able to set it up, or if he was told that they don't support it at this time but it was in the works... I'm pretty sure it was the latter.

Considering that the DKIM protocol began around 2004 and was finalized to be the protocol it is today in 2011, I'm going to throw it out there and say that: "Any hosting company that doesn't offer DKIM signing as part of their hosting platform, isn't worth using."

Hosting companies that use the true cPanel platform and let you control everything through the actual cPanel interface, should already be setup to offer DKIM as long as you have access to the "Advanced DNS Zone Editor". Companies like BlueHost or MediaTemple want you to use their own in-house DNS GUI and DKIM isn't really on their radar.

The fact that the customer support at BlueHost sent you over to dkim.org, goes to show how clueless they are about how it actually works. The private keys MUST be setup on the originating server and tied to the email portion of that server.

Given the importance of email authentication, it is flabbergasting how many website and email hosting companies, aren't even setup for it. Intuit's online Quickbooks for example, a billion dollar company, doesn't even offer DKIM keys for when a customer sends an invoice on behalf of their domain.

I wish I had better news for you on the matter, but unfortunately, my ultimate recommendation is to dump BlueHost. I tried to talk my client into moving somewhere else, but wasn't successful :-/

Thanks for your reply. Really loved the article by the way. It was the most succinct summary I could find on e-mail authentication.