Wildcards and DKIM and DMARC, oh my!

If you’re an ESP with small customers you may have looked at the recent Google / Yahoo requirements around DMARC-style alignment for authentication and panicked a bit.

Don’t impersonate Gmail From: headers. Gmail will begin using a DMARC quarantine enforcement policy, and impersonating Gmail From: headers might impact your email delivery.



For direct mail, the domain in the sender’s From: header must be aligned with either the SPF domain or the DKIM domain. This is required to pass DMARC alignment.

So everyone who’s using their gmail address to send bulk mail is going to have to stop doing that within the next few months if they still want their mail to be delivered.

For any ESP customer that already has, or can be convinced to buy, a domain for their web presence maybe they can be persuaded to switch to using that – though even if they can, onboarding 100,000 technically naive users in three months seems like it could be a nightmare, even if you already have excellent onboarding automation in place and plenty of spare customer support bandwidth.

But what about all the other users, who don’t have a domain already or who can’t manage to bring that domain to their ESP for authentication – they may not even have access to their DNS zone, it may all be managed by their web host?

As an ESP we could just send all those customers emails from our own domain, or a dedicated domain just for those customers (halp-i-haz-no-domain.com is available for registration; you’re welcome). But that’s obviously a terrible idea from a domain reputation issue, quite apart from our customers losing any vestige of branding.

How about subdomain-per-customer? All our users probably have a login username already, it’s probably unique and branded. So our ESP, SausageMail, can set up subdomains of wurst.com for each customer. If we default that to <username>.wurst.com we can deploy that without any cooperation from each customer, and we can offer to change the string we use there if they want to.

Tasty sausages, and for no narratively justified reason, a leek.
Tasty sausages from our butcher

What do we need for each customer subdomain? We want to use it in the RFC 5322 From: header, and we want either DKIM or SPF to align with it. That means that we’d like an MX record for it, whether it points at a mailserver that forwards it to the customer, or an autoresponder or a blackhole. It’d be nice to have DMARC p=none set up for it too.

For DMARC-style alignment there’s no need for the authentication domain to match the domain in the 5322 From: exactly – it just needs to share a common organizational domain. That’ll typically mean that the authentication domain will be the parent domain (wurst.com) or a sibling subdomain to that in the 5322 From: (e.g. authentication.wurst.com). That means that we can avoid using a per-customer domain in the return path for SPF authentication, and avoid having to publish a customer-specific DKIM public key.

That’s great, because while wildcard MX records are simple and widely supported (they’re the main thing wildcard DNS records have been used for historically) wildcard TXT records risk tickling obscure bugs (e.g. wildcard TXT records mean that if an ISP asks for a DKIM public key they’ll get that key, and also DMARC records and vice-versa).

For the DMARC policy record itself we can take advantage of the way a DMARC record set for the organizational domain (wurst.com) will apply to all subdomains by default.

So you could do this:

*.wurst.com                 MX 10 reply-handler.sausagemail.com
bounces.wurst.com           MX 10 bounce-handler.sausagemail.com
bounces.wurst.com           TXT "v=spf1 include:_spf.sausagemail.com"
a._domainkey.pool.wurst.com TXT "v=DKIM1 p=..."
b._domainkey.pool.wurst.com TXT "v=DKIM1 p=..."
_dmarc.wurst.com            TXT "v=DMARC1 p=none ..."

(This isn’t a validly formatted zone file – it’s missing trailing periods, TTLs and classes – so don’t just paste it into your nameserver.)

Because of how DNS wildcards work MX queries for bounces.wurst.com will point at your bounce handler, while MX queries for anything_else.wurst.com will point at your reply handler.

Then for every mail you send for this sort of customer you use a From: header that looks like this …

From: "Customer's Pretty Name" <userid@userid.wurst.com>

… and you DKIM sign it using d=pool.wurst.com and you use bounces.wurst.com as the return path. Every mail will be sent from a valid, customer-specific, email address. It will have valid SPF authentication, and be validly DKIM signed. Both DKIM and SPF authentication domains will align with the 5322 From: header. And it’ll have a valid DMARC p=none.

If your existing customer authentication infrastructure is based on CNAMEs rather than TXT records (and it probably is) then you can set up DNS more like this:

*.wurst.com                 MX 10 reply-handler.sausagemail.com
bounces.wurst.com           MX 10 bounce-handler.sausagemail.com
bounces.wurst.com           TXT "v=spf1 include:_spf.sausagemail.com"
ssg1._domainkey.pool.wurst.com CNAME k1._domainkey.sausagemail.com
ssg2._domainkey.pool.wurst.com CNAME k2._domainkey.sausagemail.com
_dmarc.wurst.com               TXT "v=DMARC1 p=none ..."

Is this perfect? No. You’re sharing the same authentication domain across all of these customers which means that they will, to some degree, share domain reputation as well as their IP reputation. Not entirely, as large providers are very good at distinguishing mailstreams from different customer even if they share authentication domains. In a perfect world you’d use giant generated zone files, or a “stunt” DNS server to use customer_id.wurst.com as the authentication domain. But this isn’t a perfect world, and using a shared authentication domain for these customers is probably good enough, and will allow them to comply with mailbox provider requirements – and to do so in a way that seems to follow the spirit of the requirements, not just the letter.

I wrote about the better approach, using a stunt DNS server to synthesize all the DNS records needed, here.

This isn’t that scary to do, and can probably be implemented with only slight changes to your existing infrastructure. You’ve got about three months to go.

Related Posts

Some Microsoft thoughts

Right at the end of January, Microsoft appears to have made couple of changes to how they’re handling authentication. The interesting piece of this is that, in both cases, Microsoft is taking authentication protocols and using them in ways that are slightly outside the spec, but are logical extensions of the spec.

Read More

Are they using DKIM?

It’s easy to tell if a domain is using SPF – look up the TXT record for the domain and see if any of them begin with “v=spf1”. If one does, they’re using SPF. If none do, they’re not. (If more than one does? They’re publishing invalid SPF.)
AOL are publishing SPF. Geocities aren’t.
For DKIM it’s harder, as a DKIM key isn’t published at a well-known place in DNS. Instead, each signed email includes a “selector” and you look up a record by combining that selector with the fixed string “._domainkey.” and the domain.
If you have DKIM-signed mail from them then you can find the selector (s=) in the DKIM-Signature header and look up the key. For example, Amazon are using a selector of “taugkdi5ljtmsua4uibbmo5mda3r2q3v”, so I can look up TXT records for “taugkdi5ljtmsua4uibbmo5mda3r2q3v._domainkey.amazon.com“, see that there’s a TXT record returned and know there’s a DKIM key.
That’s a particularly obscure selector, probably one they’re using to track DKIM lookups to the user the mail was sent to, but even if a company is using a selector like “jun2016” you’re unlikely to be able to guess it.
But there’s a detail in the DNS spec that says that if a hostname exists, meaning it’s in DNS, then all the hostnames “above” it in the DNS tree also exist (even if there are no DNS records for them). So if anything,_domainkey.example.com exists in DNS, so does _domainkey.example.com. And, conversely, if _domainkey.example.com doesn’t exist, no subdomain of it exists either.
What does it mean for a hostname to exist in DNS? That’s defined by the two most common responses you get to a DNS query.
One is “NOERROR” – it means that the hostname you asked about exists, even if there are no resource records returned for the particular record type you asked about.
The other is “NXDOMAIN” – it means that the hostname you asked about doesn’t exist, for any record type.
So if you look up _domainkey.aol.com you’ll see a “NOERROR” response, and know that AOL have published DKIM public keys and so are probably using DKIM.
(This is where Steve tries to find a domain that isn’t publishing DKIM keys … Ah! Al’s blog!)
If you look up _domainkey.spamresource.com you’ll see an “NXDOMAIN” response, so you know Al isn’t publishing any DKIM public keys, so isn’t sending any DKIM signed mail using that domain.
This isn’t 100% reliable, unfortunately. Some nameservers will (wrongly) return an NXDOMAIN even if there are subdomains, so you might sometimes get an NXDOMAIN even for a domain that is publishing DKIM. shrug
Sometimes you’ll see an actual TXT record in response – e.g. Yahoo or EBay – that’s detritus left over from the days of DomainKeys, a DomainKeys policy record, and it means nothing today.

Read More