The ultimate guide to DMARC
DMARC stands for Domain-based Message Authentication, Reporting (and) Conformance. There are plenty of resources out there but no guide bundling everything you need to know, until now!
In a nutshell
DMARC is a set of standards making it standardized to detect and report abuse of mail systems across providers all over the world.
Since reputation is everything in the mailing world, this is a critical thing to ensure your mail reaches the inbox of the receivers.
Not useful on its own
While DMARC handles all the reporting and compliance stuff, it needs a bit of help from two other things. They are not the main focus of this article, but since they basically don't make sense without each other, I will add them here as well.
SPF (Sender Policy Framework)
Specifies which servers (IP addresses) are allowed to send on behalf of the domain. This means any server trying to send a mail from an IP apart from the ones you specified via DNS will be blocked by the receiving server.
You list all your mail servers, service providers (such AWS SES, Mailchimp, etc.). This is quite flexible and easy to use.
Such a record might look like this:
v=spf1 ip4:22.214.171.124 include:mail-ips.thirdparty.com -all
So let's break this down, we have:
This is the version of the record, currently the only valid value is spf1
Here we allow the mail server 126.96.36.199 to send mails on our behalf
Performs and DNS Lookup which can also add information to our SPF record, only use these from trusted sources (like AWS SES anyway)
Prevents every other sending party not listed beforehand
While this already utilizes a lot of the features, I recommend looking up more information about it on the internet (and there are some excellent generators/validators) out there as well.
DKIM (Domain Keys Identified Mail)
So with SPF we covered who can send mails on our behalf. Now it is also time to ensure the content we are sending is not messed with. The principle is simple, you sign the mails when sending them and add the information to the mails. From receiver side it checks if the mails are signed properly and from your servers. This is a simple asymmetric encryption principle.
The DNS record looks pretty simple for this one:
It consists of two parts:
Version for the DKIM record, currently the only valid value is DKIM1
Contains the public key to use for validating signatures
This is fine, why do I need DMARC?
You implemented SPF, DKIM, and now you are happily sending mails. What could go wrong? — As the world and some humans always tend to be evil and use things for their advantage, people will try to get around your security measures. Or occasionally, a misconfiguration leads to no mails being delivered to the inboxes of the recipients.
This is where DMARC comes in, it specifies how these cases should be handled and where providers can issue reports. To make them also processable by automation (script, analysis) etc. there is also a standardized format that providers should use to tell you what went wrong.
Defining a policy
Policies for DMARC are also published via DNS Records and look like this:
Let's also break this one down:
The version of the DMARC policy, currently the only valid value is DMARC1
The policy to apply to mails that fail SPF and / or DKIM
Valid values are:
- quarantine - send to Junk folder
- reject - don't deliver to user
- none - just report and send to user
In this case it would just report and don't treat the mail otherwise differently, which is especially useful to start using it without making all mails fail to reach the inboxes
The amount in percent to which amount of the traffic to apply the policy to
- rua=mailto:[email protected]
Send all aggregate reports to [email protected] The only valid receiver for reports are mail addresses, and you get a mail with mail deliverability results.
So, everything is in place, we have DKIM, SPF and defined a DMARC policy and set up the “rua field” to get reports, now it's time to get the best of these reports.
But first we need to understand the reports a bit more.
Types of reports
- aggregate report - contains a summary of a specific time interval (depending on the provider)
- failure report - contains a sample of the mail that was sent and some more information (not provided by many providers)
In most cases, the aggregate report is enough and allows you to track how the health of your mail infrastructure is and also get a feeling how many attacks there are. You can also get out of these results if your policy might be too weak and allows an unauthorized server to send mails on your behalf.
The aggregate report has plenty of fields, and it can be a bit confusing at first. Here is a list and a brief description of what to expect:
|report_metadata/org_name||The human readable name of the organization that sent you the report|
|report_metadata/email||Sender mail for report|
|report_metadata/extra_contact_info||Homepage or mail to get in touch with the provider|
|report_metadata/report_id||ID of the report unique for the organization that sent the report|
|report_metadata/date_range/begin||Unix timestamp for the start of the first report result|
|report_metadata/date_range/end||Unix timestamp for the end of the last report result|
|policy_published/domain||The top level domain used for validating your policy|
|policy_published/adkim||Raw DKIM DNS record used for DKIM validation|
|policy_published/aspf||Raw SPF DNS record used for SPF validation|
|policy_published/p||The p field from your DMARC policy|
|policy_published/pct||The pct field from your DMARC policy|
|record/row/source_ip||IP of the sending mail server|
|record/row/count||The amount of mails sent via this server in the given interval|
|record/row/policy_evaluated/disposition||The action that has been taken for your mail (none, rejected, quarantine) - This might differ from what you specified to do|
|record/row/policy_evaluated/dkim||The result of the dkim check (pass/fail)|
|record/row/policy_evaluated/spf||The result of the spf check (pass/fail)|
|record/row/identifiers/headers_from||The domain advertised by the sending mail server|
|record/row/identifiers/envelope_from||Mail address specified as sender by sending server|
|record/row/identifiers/envelope_to||Mail address specified as receiver by sending server|
|record/row/auth_results/dkim/domain||The domain that has been tested against the DKIM policy|
|record/row/auth_results/dkim/result||Result of the SPF check (pass/fail)|
|record/row/auth_results/dkim/selector||Name of the DNS selector wihtout the TLD as specified by the domain field|
|record/row/auth_results/spf/domain||The domain that has been tested against the SPF policy|
|record/row/auth_results/spf/result||Result of the SPF check (pass/fail)|
While all of these should/may be set, never rely on any of these to be exact or even present.
A failure report is basically an email, that might look extremely different depending on the service provider. Most providers out there don't even send them to you.
Since depending on how well known (and used) your mail server is this can be numerous mails (and therefore also cost) think wisely about enabling them.
They are basically a copy of the mail originally sent that failed DKIM and/or SPF.
I haven't found a way yet to automate the analysis of these failure reports, but they are quite handy here and there to get more insights, e.g., on phishing attempts.
Receiving and processing
While there are many service providers out there that provide out of the box solutions, you always have to hand off to some other third party.
Regardless, it totally makes sense to know how to work with reports and how to process them.
These reports may be raw XML as attachment, tar.gz, zip or otherwise archived. But expect some mails to completely fall out of the scope. Some mails are simply sent manually by people trying to break things. But there are also providers simply not complying to the standards.
Implementation on premise (or on your own personal server)
In case you want/need to build this yourself. It is somewhat simple.
The mail address you use for receiving the mail records can be either a piece of code that reacts to incoming mails (e.g., AWS SES + Lambda). You can also create a simple application that connects to the inbox and reads the mails.
The other option is to let it run on a server etc. as a daemon.
There is also a python package / CLI for that!
What I can really recommend in both scenarios is parsedmarc - a python package by Sean Whalem, who did a fantastic job here. It also includes a lot of export options to make use of the data. And if your target is not in the list, you get a standardized output across the reports to route anywhere you like.
This also plays along pretty well with AWS Lambda to create custom CloudWatch Metrics.
Although not in every case you have influence on it (e.g., when using a service provider to send your mails), is that the MAIL FROM, EHLO/HELO domain must also match the domains configured for SPF.
A misconfigured header there can also cause your mails to fail DMARC. So keep this in mind.
You can also find more information about it in RFC7489.
Hopefully, you now have a better understanding of what DMARC takes, why it is useful and how to interpret the results. Furthermore, without needing a dedicated service provider.
Do you miss something or have feedback? You are welcome to leave a comment as always.
Special thanks to @freddieleeman for the feedback on the misunderstanding of failure reports, which I always thought were called forensic reports. Based on his suggestion, I also added the Identifier alignment section.