Demystifying DMARC: A guide to preventing email spoofing

DMARC can stop spoofed spam and phishing from reaching you and your customers, protecting your information security and your brand. However, complexity and misconceptions deter many organizations from ever deploying it. Part mythbusting , part implementation guide, this post explains the shortcomings of SPF and DKIM, what DMARC is, how to deploy DMARC properly, and how to respond to DMARC reports – all without the need for an additional vendor, thanks to open source software!

Direct link to presentation

Modern email authentication relies on a combination of three standards: SPF, DKIM, and DMARC. These standards help ensure that a message came from a server related to the domain owner and was not spoofed.

Sender Policy Framework (SPF)

SPF was the first widely adopted standard for combating email spoofing. Despite its limitations in preventing spoofing, most email recipients expect you to have it deployed on your domain. For example, Gmail/G-Site/Google will throttle incoming emails from domains that do not have a valid SPF record.

How SPF works

SPF is defined in RFC 7208. It works by checking for a specially formatted DNS TXT record in the domain of the mail from header in the SMTP transaction. This SPF record describes which servers are authorized to send as that domain by using mechanisms to identify authorized IP addresses and hostnames, or even include the SPF records of other domains.

Every SPF record is a TXT record at the root of a domain or subdomain that starts with v=spf1. From there, mechanisms are used to describe mail servers are allowed (or not allowed) to send email as that domain or subdomain. A domain or subdomain can only have one SPF record, but each subdomain can have its own SPF record.

Some mechanisms like a, mx, include, and redirect use additional DNS lookups to work. SPF has a maximum DNS lookup limit of 10, including any included records. Any SPF record that would require more than 10 DNS lookups to resolve is invalid! This is a common mistake to make when deploying SPF.

To work around this limit, send email from different subdomains. Each subdomain needs its own SPF record and has its own set of limits for that record. For example, you could send newsletters from, and invoices from

You might not even need to include every vendor in your SPF records anyway. If the vendor supports DKIM signing, you can rely on that to pass DMARC, even if the sender is not in your SPF record. Just make sure you are using ~all in your SPF record.

Mechanism Description
ip4 Describes an ipv4 address or CIDR block of addresses.
ip6 Describes an ipv6 address or block of addresses.

Describes the servers listed in the mx record of the domain.

Counts towards the DNS lookup limit.

mx The servers listed in the mx records of its own domain The servers listed in the mx records of

Describes the servers listed in the A and/or AAAA records of the domain.

Counts towards the DNS lookup limit.

a The IP addresses listed in the domains’ own A/AAAA records The IP addresses listed in the A/AAA records of

Includes the SPF record from the domain after the colon (it does not include the all modifier, if any)

Counts towards the DNS lookup limit.


Stops processing the SPF record, and continues at the specified domain’s SPF record (including the all modifier!)

Counts towards the DNS lookup limit.


This mechanism is used to construct an arbitrary domain name that is
used for a DNS A record query. It allows for complicated schemes
involving arbitrary parts of the mail envelope to determine what is

Counts towards the DNS lookup limit.

exists = “exists” “:” domain-spec

The <domain-spec> is expanded as per Section 7. The resulting domain name is used for a DNS A RR lookup (even when the connection type is
IPv6). If any A record is returned, this mechanism matches.

Domains can use this mechanism to specify arbitrarily complex
queries. For example, suppose publishes the record:

v=spf1 exists:%{ir}.%{l1r+-}._spf.%{d} -all

The <target-name> might expand to “”. This makes fine-grained
decisions possible at the level of the user and client IP address.

Mechanisms listed in the SPF record have an implicit pass (i.e. +) qualifier in front of them. Possible qualifiers are:

Modifier Name Description
+ pass

A “pass” result means the client is authorized to inject mail with the given identity.

The domain can now, in the sense of reputation, be considered responsible for sending the message. Further policy checks can now proceed with confidence in the legitimate use of the identity.

? neutral A “neutral” result indicates that although a policy for the identity was discovered, there is no definite assertion (positive or negative) about the client.

A “neutral” result MUST be treated exactly like the “none” result; the distinction exists only for informational purposes. Treating “neutral” more harshly than “none” would discourage domain managers from testing the use of SPF records.

With a “none” result, the SPF verifier has no information at all about the authorization or lack thereof of the client to use the checked identity or identities. The check_host() function completed without errors but was not able to reach any conclusion.

~ softfail

A “softfail” result ought to be treated as somewhere between “fail” and “neutral”/”none”.

The domain manager believes the host is not authorized but is not willing to make a strong policy statement.Receiving software SHOULD NOT reject the message based solely on this result, but MAY subject the message to closer scrutiny than normal.


A “fail” result is an explicit statement that the client is not authorized to use the domain in the given identity.

Disposition of SPF fail messages is a matter of local policy.

Most SPF records (except for those that are designed to be included in other SPF records) end with an all modifier. The all modifier consists of the word all with a qualifier in front of it. The all modifier states how emails should be treated that do not match any of the listed mechanisms.

SPF’s weakness: Relying on SMTP headers

It is a common misconception that SPF stops email spoofing. At best, it makes things a tiny bit more difficult on an attacker.

Remember, SPF checks for an SPF record at the domain in the mail from header in the SMTP transaction (also known as the envelope from), not the message from header that the receiving mail client sees, The SMTP transaction are not visible to the end client, even when viewing the message headers.

This means that an attacker can use SMTP headers to direct the target’s mail server to check a domain that the attacker controls, which contains an authorizing mechanism for the mail server the attacker is using, while spoofing a completely different domain for the target to see in the message from header!

In the example telnet screenshot below, the attacker is able to get the receiving email server to check the SPF record of a domain that the attacker controls (i.e., while spoofing the target’s own domain (i.e. in the message from header, which is the from address that the target user will see.

A screenshot showing how SPF can be bypassed by spoofing the SMTP mail from header
A screenshot showing how SPF can be bypassed by spoofing the SMTP mail from header

This sort of domain mismatch occurs legitimately when a mailbox rule forwards a message from another domain. The message from domain will stay the same, but the SMTP mail from header will contain the domain of the forwarding mail server.

A process graphic that shows how forwarded email fails SPF alignmentDKIM signatures, on the other hand, are part of the message headers, and survive message forwarding. Therefore DKIM alignment is much more critical than SPF alignment.

Example SPF records

Once you know exactly which email services legitimately send as the domain (DMARC reports will tell you), update the SPF record accordingly, and change the ?all modifier to ~all.

SPF record for domains that send emails from their incoming gateways and are missing SPF records

v=spf1 mx ?all

This record explicitly authorized any servers listed in the domain’s MX record, while treating all others as neutral. This is a good temporary SPF record for new domains or newly acquired domains that do not already have a SPF record.

Here are some good examples of SPF records for common cloud email providers:

Office 365

v=spf1 ?all


v=spf1 ?all

Proofpoint Essentials

v=spf1 ?all

SPF record for domains that do not send email (e.g. parked domains)

v=spf1 -all

This record explicitly states that no mail servers are authorized to send email as this domain.

This must be added to all domains that do not send email, inducing parked domains.

DomainKeys Identified Mail (DKIM)

DomainKeys Identified Mail (DKIM) is a email message authentication standard, defined in RFC 6376. Because DKIM authenticates the message headers , rather than the SMTP headers, DKIM authentication survives intact when a message is directly forwarded (e.g. via a mailbox rule).

DKIM message headers

Here’s an example DKIM header

DKIM-Signature: v=1; a=rsa-sha256;; s=s1; c=relaxed/simple; l=1234; t=1117574938; x=1118006938; h=from:to:subject:date; bh=MTIzNDU2Nzg5MDEyMzQ1Njc4OTAxMjM0NTY3ODkwMTI=;b=dzdVyOfAKCdLXdJOc9G2q8LoXSlEniSbav+yuU4zGeeruD00lszZVoG4ZHRNiYzR

Required tags

Tag Value Description
v Signature version
a Signature algorithm (rsa-sha256 should be used)
d The domain where the public key can be found
s The selector pointing to the public key at the domain (an arbitrary string)
h A colon separated list of headers to concatenate when validating the header signature
b The base64-enoded signature hash of the headers listed in the h tag
bh The base64-enoded signature hash of the message body

Optional tags

Tag Value Description
t Signature timestamp in UNIX timestamp format (i.e. the number of seconds from 00:00:00 on January 1, 1970 in the UTC time zone)
x Signature expiration timestamp in UNIX timestamp format (i.e. the number of seconds from 00:00:00 on January 1, 1970 in the UTC time zone)
c canonicalization algorithm: Defines if/how the receiving the receiving mail server should normalize the message to account for slight variations in whitespace and line breaks that could otherwise invalidate the signature.

Relaxed mode is strongly recommended for the header and body canonicalization (i.e. c=relaxed/relaxed).

i Identity/user-agent of the signer
l Number of characters from the beginning of the body to use when calculating the body signature (not recommended because someone could append malicious content)
z Not well defined

The receiving mail server uses the selector (s=) and domain (d=) tags to look up the public key as a DNS TXT record at


In the above signature example, the receiving server would look for the DKIM key at:


DKIM public key records

DKIM public key records are formatted as:

v=DKIM1; k=rsa; p=<public key>;

Lines in DNS TXT records are truncated at 256 characters. If the record is longer, it must be split into separate lines in the same record in order to be valid.

DKIM public key records can be validated for syntax using the DKIM record lookup tool at MX Toolbox.

Recommended tags

Tag Value Description

According to the RFC, this tag is recommended but not required, with an implicit default value of DKIM1.

However, in practice, some recipients don’t follow the RFC exactly, and require this tag to be used anyway. This must be the first tag if used.Your DKIM public key records should start with v=DKIM1;

n Notes: Human-readable notes for administrators reviewing DNS records

Useful for noting which service uses a selector and key.

Required tags

Tag Value Description

Public key data encoded in base64.

Keys must be at least 1024 bytes long.
2048 bit length is strongly recommended.

Optional tags

Tag Value Description
k Key type: Defaults to rsa. Unrecognized key types must be ignored.
h Acceptable hash algorithms: A colon-separated list of hash algorithms that might be used. Defaults to allowing all algorithms. Unrecognized algorithms must be ignored.

Refer to Section 3.3 for a discussion of the hash algorithms implemented by Signers and Verifiers. The set of algorithms listed in this tag in each record is an operational choice made by the Signer.

s Service Type: Defaults to *

A colon-separated list of service types to which this record applies. Verifiers for a given service type must ignore this record if the appropriate type is not listed. Unrecognized service types must be ignored.This tag is intended to constrain the use of keys for other purposes, should use of DKIM be defined by other services in the future.

Currently defined service types are as follows:

Value Value Description
* Matches all service types
email Electronic mail (not necessarily limited to SMTP)
t Flags: A colon-separated list of flags

Defaults to no flags

Flag Flag Description
y This domain is testing DKIM. Verifiers must not treat messages from Signers in testing mode differently from unsigned email, even if the signature fails to verify. Verifiers may wish to track testing mode results to assist the Signer.

Any DKIM-Signature header fields using the i= tag must have the same domain value on the right-hand side of the @ in the i= tag and the value of the d= tag.

That is, the i= domain must not be a subdomain of d=.

Use of this flag is recommended unless subdomaining is required.

Notes in DKIM key records

The DKIM selector (subdomain) is chosen by the vendor and is often non-descriptive. You can use an arbitrary string in the n (i.e., notes) tag in the DKIM record to make a note of the vendor’s name, so you know which DKIM key is used by which vendor as you audit your DNS records.

For example, if “matketingco” asked you to publish the following DKIM TXT record: TXT "p=base64Key"

You should create the record this way instead: TXT "v=DKIM1; n=marketingco; k=rsa; p=base64Key"

DKIM key rotation

It is generally recommended to rotate DKIM keys once per month, or at least after you suspect that the DKIM private key has been compromised. Most email/marketing services will handle key rotation for you when you configure your domains for DKIM, but some almost never rotate their keys.

Unlike web and email certificates, the domain/email address is not part of the PKI. DKIM does not use certificates.. The domain is listed in the d= header tag.Therefore, you do not need a separate public/private key pair for each domain.

You should create two key pairs, and store the public keys under two different selectors, for example: TXT "v=DKIM1; k=rsa; p=<public key>;" TXT "v=DKIM1; k=rsa; p=<a different public key>;"

With CNAME records, your other domains can use the same selectors and keys: CNAME CNAME

Third party services will often have you authorize their DKIM keys on your domains using CNAME records and will then validate that those records exist before signing email, so they can handle key changes for you.

If you are using your own keys, it is up to you to manage them, preferably using automation. Start by signing all of your emails using the first selector. When it is time to rotate the keys, sign all outgoing email using the s2 sector. After a week of not using the key at the s1 selector, replace the key at the s1 selector.

When it is time to rotate keys again, start using the s1 selector exclusively, wait a week, then replace they key at the s2 selector with a new key, so it will be ready for the next rotation.

Unless a key is known to have been compromised, it is important to wait a week (i.e., 7 days) before replacing it, as some receiving mail servers will cache the public key at a given selector for up to a week.

Using this ping-pong key rotation scheme, you ensure that email is always signed with a valid, secure key.

  1. Start exclusively signing with the other selector.
  2. Wait 7 days.
  3. Replace the key at the old selector so it is ready for the next rotation.
  4. Go to step 1.

DKIM’s weakness: arbitrary d= values

Without DMARC, the d= value in a DKIM signature header is not required to match the same domain that the user sees in the message From header. An attacker can place a valid DKIM signature header in an email with a d= value that points to a domain the attacker controls, allowing DKIM to pass while still spoofing the from address to the user.

Domain-based Message Authentication, Reporting, and Conformance (DMARC)

Domain-based Message Authentication, Reporting, and Conformance (DMARC) is defined in RFC 7489. DMARC ensures that the SPF and DKIM authentication mechanisms actually authenticate against the same base domain that the end user sees.

In order to be useful, a DMARC DNS record must be published by a domain owner, and email recipients must honor this record, including its enforcement policy, and at least send back aggregate reports if requested by the domain owner.

A message passes a DMARC check by passing DKIM or SPF, as long as the related indicators are also in alignment with the message’s from address.

Passing The signature in the DKIM header is validated using a public key that is published as a DNS record of the domain name specified in the signature The mail server’s IP address is listed in the SPF record of the domain in the SMTP envelope’s mail from header.
Alignment The signing domain aligns with the base domain in the message from header. The domain in the SMTP envelope’s mail from header aligns with the base domain in the message’s from header.

DKIM alignment is more important than SPF, because only DKIM remains aligned when a message is forwarded via a mailbox rule.

DMARC reports

DMARC has two report types: aggregate and forensic. email recipients that honor DMARC send these reports back to domain owners in emails sent to addresses listed in the domain’s DMARC record. There reports contain very useful information for debugging message alignment and identifying malicious spoofing campaigns.

Report type Description
Compressed XML files sent at least once per day by recipient domains to the URIs listed in the rua DMARC tag. Records number of messages sent from an IP address, and the SPF and DKIM status. These reports are sent regardless of a success or failure, so that domain owners have a view of all mail authentication of messages appearing to be from their domain.
An email with an email that failed the DMARC check attached (RFC 822/.eml format) sent to the URIs listed in the ruf DMARC tag. These can be very useful for DMARC troubleshooting and phishing investigations. However, most email recipients do not send forensic reports, or may only supply the message headers for privacy reasons.

DMARC policies

DMARC requires domain owners to set a policy (p=) tag in their DMARC record. This policy tells recipients how they should react to an email that appears to come from that domain based on the message from header but does not pass DMARC alignment.

Policy Description
none The Domain Owner requests no specific action be taken regarding delivery of messages. Use this first to ensure your messages are DMARC compliant before switching to quarantine or reject.
quarantine The Domain Owner wishes to have email that fails the DMARC mechanism check be treated by Mail Receivers as suspicious. Depending on the capabilities of the Mail Receiver, this can mean “place into spam folder”, “scrutinize with additional intensity”, and/or “flag as suspicious”.
reject The Domain Owner wishes for Mail Receivers to reject email that fails the DMARC mechanism check. Rejection SHOULD occur during the SMTP transaction.

Even if a domain has a DMARC policy set to p=none, mail services may still display warnings to their users in the event of a DMARC failure, as shown in this screenshot of a valid email from a retail credit service, displayed in ProtonMail and Gmail.

A screenshot of ProtonMal showing a DMARC failure warning

A creenshot of a DMARC failure warning in Gmail

Authentication-Results headers

As an email gateway evaluates SPF, DKIM, and DMARC, it adds the Message-Authentication headers to the email. Users and administrators can use these headers to determine which checks passed or failed, and why.

In the example above, the mail server added the following headers to the email:

Authentication-Results:; dmarc=fail (p=none dis=none) header.from=[redacted].com
Authentication-Results:; spf=pass smtp.mailfrom=noreply_[redacted]_portal=[redacted]
Authentication-Results:; dkim=none

Email headers are added and read from the bottom to the top.

First, the server notes that the message has not been DKIM signed.

Then, SPF is checked, with a SMTP mail from header value of noreply_[redacted]_portal=[redacted], and SPF passed. A address was used so that Salesforce can keep track of bouncebacks, and avoid sending to invalid email addresses in the future. SPF passed.

Finally, DMARC is checked, which fails, because the message is not DKIM signed, and the base of the SMTP mail from domain used by SPF ( does not match the base domain in the message from header ([redacted].com). dis=none (short for message disposition) indicates that the message was still delivered, because the mail server noted that [redacted].com has a DMARC policy of p=none.

The retail credit service should resolve the DMARC failures by configuring Salesforce to DKIM sign the messages, and then publish the DKIM public key as a DNS TXT record on [redacted].com.

Note: If you route your incoming email from one gateway service to another, such as from an IronPort to Office 365, by the time an email reaches a user’s mailbox, the information from Office 365 in the Authentication-Results header will always show that SPF and DMARC passed, since the IronPort is authorized to send as your domains when messages are forwarded to Office 365. The results of the original IronPort check that occurs before the message reaches Office 365 are stored in the Authentication-Results-Original header.

Policy records

DMARC policy records are placed at a TXT record at the _dmarc subdomain. Subdomains of the TLD/base domain automatically inherit this DMARC policy record, or they can have their own record at their own _dmarc subdomain.

Here is an example DMARC policy record TXT "v=DMARC1; p=none; rua=mailto:[email protected]; ruf=mailto:[email protected]"

Required tags:

Tag Description
v DMARC version (e.g., v=DMARC1)
p DMARC policy

Recommended tags

These tags tell recipients where and how to send reports.

Tag Description
rua A comma separated list of mailto: address to send aggregate reports to

A comma separated list of mailto: address to send forensic reports to

You might not want to include this tag if you are in an industry that sends sensitive information, especially if you are automatically processing reports. This could cause sensitive emails to be saved in ELK or other storage areas if the messages fail DMARC.

If a recipient receives a sensitive email that fails DMARC, that email could be sent back to your reporting inbox and archived in your DMARC report processing tool.


Default is 0

Provides requested options for generation of failure reports. Report generators MAY choose to adhere to the requested options. This tag’s content MUST be ignored if a “ruf” tag is not also specified. The value of this tag is a colon-separated list of characters that indicate failure reporting options.

Option Option Description
0 Generate a DMARC failure report if all underlying authentication mechanisms fail to produce an aligned “pass” result.
1 Generate a DMARC failure report if any underlying authentication mechanism produced something other than an
aligned “pass” result.
d Generate a DKIM failure report if the message had a signature
that failed evaluation, regardless of its alignment. DKIM-
specific reporting is described in RFC 6651.
s Generate an SPF failure report if the message failed SPF
evaluation, regardless of its alignment. SPF-specific
reporting is described in RFC 6652.

Recipients are only obligated to send reports to the first two rua and ruf addresses. They might not send to any additional address listed.

Not recommended tags

Tag Description
sp Default mirrors the p tag’s value

Sets the policy for all subdomains. Setting this tag could allow the spoofing of any arbitrary subdomain.

Add a separate policy record for each subdomain as needed instead.


Default is 100

Sets the percentage of mail to apply the DMARC policy to. Set p=none when testing instead to ensure all mail is treated equally


Default is relaxed (r)

In relaxed mode, the Organizational Domains of both the DKIM-authenticated signing domain (taken from the value of the “d=” tag in the signature) and that of the RFC 5322 From domain must be equal if the identifiers are to be considered aligned.


Default is relaxed (r)

In relaxed mode, the SPF-authenticated domain and RFC5322 From domain must have the same Organizational Domain. In strict mode, only an exact DNS domain match is considered to produce Identifier Alignment.


A list separated by colons of one or more report formats as requested by the Domain Owner to be used when a message fails both SPF and DKIM tests to report details of the individual failure.

Only “afrf” (the auth-failure report type) is currently supported in the DMARC standard.


Default is 86400

Indicates a request to Receivers to generate aggregate reports separated by no more than the requested number of seconds. DMARC implementations MUST be able to provide daily reports and SHOULD be able to provide hourly reports when requested. However, anything other than a daily report is understood to be accommodated on a best-effort basis.

Authorization records

If an email address in rua or ruf has a different base domain than the domain of the policy record, an authorization record must be added to the base domain of the email address to indicate that it accepts reports about that domain. For example, if [email protected] also needed to accept reports for, the poly record for would look like this: TXT "v=DMARC1; p=none; rua=mailto:[email protected]; ruf=mailto:[email protected]"

Because is a different base domain than, the following record needs to be added to to indicate that it accepts reports about TXT "v=DMARC1"

Deployment steps

  1. Configure email gateways to honor DMARC records and send aggregate DMARC reports.
  2. Inventory domains.
  3. Deploy SPF.
  4. Deploy DKIM.
  5. Set up mailbox for receiving DMARC reports.
  6. Deploy DMARC DNS records.
  7. Monitor incoming DMARC reports.
  8. Adjust SPF, DKIM signing, and DMARC policies as needed.

Calendar invites forwarded by Outlook violate DMARC

Calendar events from DMARC protected domains forwarded by outsiders using Outlook will fail DMARC.  Unfortunately, unlike a normal forwarded email, calendar events forwarded using Outlook are “sent on behalf of” the meeting organizer. Instead of using the address of the person who forwarded the email in the from header, Outlook uses the address of the meeting organizer.  The address of the person who did the forwarding is placed in the Sender header, which DMARC does not use.

A screenshot of a draft forward of a calendar event in Microsoft Outlook

If the domain of the meeting organizer has an enforced DMARC policy (i.e., p=quarantine, or p=reject), and the recipient mail server honors DMARC, the message will not be delivered, because DMARC does not allow an unauthorized mail server (i.e., the forwarding mail server) to send an email as the organizer’s domain.

This is a known problem with Outlook that Microsoft has so far not addressed. In the meantime, tell anyone who wants to forward calendar events to do so by clicking on the three dots, and clicking Forward as Attachment, instead of clicking on the usual Forward button.

A screenshot showing how to forward a calendar invite as an attachment in Outlook

On Outlook for macOS, calendar events must be forwarded by clicking on Message> Forward as Attachment in the Menu Bar.

A screenshot of the Forward as attachment menu item in Outlook for macOS


How can I check a DKIM signature?

Send an email to a Gmail account. They have a nice UI that shows the DKIM status of a message.

A screenshot showing how DKIM signature alignment can be verified using Gmail's UI
A screenshot showing how DKIM signature alignment can be verified using Gmail’s UI

What if a third-party sender can’t support DMARC?

  1. Some vendors don’t know about DMARC yet; ask about SPF and DKIM/email authentication.
    Check if they can send through your email relays instead of theirs.
  2. Do they really need to spoof your domain? Why not use the display name instead?
  3. Worst case, have that vendor send email as a specific subdomain of your domain (e.g. [email protected]), and then create separate SPF and DMARC records on, and set p=none in that DMARC record.

Do not alter the p or sp values of the DMARC record on the Top-Level Domain (TLD) – that would leave you vulnerable to spoofing of your TLD and/or any subdomain.

Further reading on this problem.

How can I get more forensic reports?

Often, you will find a service that sends email that passes SPF alignment, but not DKIM alignment, but you might not know which email workflow has the problem, because you won’t get many forensic reports, since at SPF is aligned.

Try setting fo=1 in your DMARC policy record.

By default, fo is implicitly set to 0. DMARC failure/forensic reports are only sent if all authentication mechanisms (i.e., SPF and DKIM) fail to produce an aligned “pass” result.

Setting fo=1 in the DMARC policy record will provide forensic/failure reports if any authentication mechanisms fail.

This is noisy, but very useful for troubleshooting DKIM when SPF is passing, Remove the fo tag, or set it to 0 once troubleshooting is complete.

What about mailing lists?

When you deploy DMARC on your domain, you might find that messages relayed by mailing lists are failing DMARC, most likely because the mailing list is spoofing your from address, and modifying the subject, footer, or other part of the message, thereby breaking the DKIM signature.

Mailing list best practices

Ideally, a mailing list should forward messages without altering the headers or body content at all. Joe Nelson does a fantastic job of explaining exactly what mailing lists should and shouldn’t do to be fully DMARC compliant. Rather than repeat his fine work, here’s a summary:


  • Retain headers from the original message.
  • Add RFC 2369 List-Unsubscribe headers to outgoing messages, instead of adding unsubscribe links to the body.
    List-Unsubscribe: <>
  • Add RFC 2919 List-Id headers instead of modifying the subject.
    List-Id: Example Mailing List <>

Modern mail clients and webmail services generate unsubscribe buttons based on these headers.

Do not

  • Remove or modify any existing headers from the original message, including From, Date, Subject, etc.
  • Add to or remove content from the message body, including traditional disclaimers and unsubscribe footers.

In addition to complying with DMARC, this configuration ensures that Reply and Reply All actions work like they would with any email message. Reply replies to the message sender and Reply All replies to the sender and the list.

Even without a subject prefix or body footer, mailing list users can still tell that a message came from the mailing list, because the message was sent to the mailing list post address, and not their email address.

Configuration steps for common mailing list platforms are listed below.

Mailman 2

Navigate to General Settings, and configure the settings below

Setting Value
from_is_list No
first_strip_reply_to No
reply_goes_to_list Poster
include_rfc2369_headers Yes
include_list_post_header Yes
include_sender_header No

Navigate to Non-digest options, and configure the settings below:

Setting Value
scrub_nondigest No

Navigate to Privacy Options> Sending Filters, and configure the settings below:

Setting Value
dmarc_moderation_action Accept
dmarc_quarentine_moderation_action Yes
dmarc_none_moderation_action Yes

Mailman 3

Navigate to Settings> List Identity

Make Subject prefix blank.

Navigate to Settings> Alter Messages

Configure the settings below:

Setting Value
Convert HTML to plaintext No
Include RFC2369 headers Yes
Include the list post header Yes
Explicit reply-to address  
First strip reply-to No
Reply goes to list No munging

Navigate to Settings> DMARC Mitigation

Configure the settings below

Setting Value
DMARC mitigation action No DMARC mitigations
DMARC mitigate unconditionally No

Create a blank footer template for your mailing list to remove the message footer. Unfortunately, the Postorius mailing list admin UI will not allow you to create an empty template, so you’ll have to create one using the system’s command line instead, for example:

touch var/templates/lists/

Where the list ID, and en is the language.

Then restart mailman core.


If a mailing list must go against best practices and modify the message (e.g., to add a required legal footer), the mailing list administrator must configure the list to replace the from address of the message (also known as munging) with the address of the mailing list, so they no longer spoof email addresses with domains protected by DMARC.

Configuration steps for common mailing list platforms are listed below.

Mailman 2

Navigate to Privacy Options> Sending Filters, and configure the settings below

Setting Value
dmarc_moderation_action Munge From
dmarc_quarentine_moderation_action Yes
dmarc_none_moderation_action Yes


Message wrapping could be used as the DMARC mitigation action instead. In that case, the original message is added as an attachment to the mailing list message, but that could interfere with inbox searching, or mobile clients.

On the other hand, replacing the from address might cause users to accidentally reply to the entire list, when they only intended to reply to the original sender.

Choose the option that best fits your community.

Mailman 3

In the DMARC Mitigations tab of the Settings page, configure the settings below:

Setting Value
DMARC mitigation action Replace From: with list address
DMARC mitigate unconditionally No


Message wrapping could be used as the DMARC mitigation action instead. In that case, the original message is added as an attachment to the mailing list message, but that could interfere with inbox searching, or mobile clients.

On the other hand, replacing the From address might cause users to accidentally reply to the entire list, when they only intended to reply to the original sender.

Choose the option that best fits your community.


LISTSERV 16.0-2017a and higher will rewrite the from header for domains with a DMARC quarantine or reject policy.

Some additional steps are needed for Linux hosts.

DMARC deployment guides

SPF and DMARC record validators

  • checkdmarc – A Python module and CLI tool I wrote to validate and parse SPF and DMARC records
  • trustymail – By DHS; checks for compliance with BOD 18-01, including SPF, DMARC, and STARTTLS
  • DNS Checker – Check DNS propagation worldwide

DMARC report processing services

DMARC adoption

DMARC compliant services


Payment and CRM solutions for non-profits

Constant Contact


Cvent planner supports alignment via SPF and DKIM.

Add the following to your SPF record:

Contact Cvent support to set up DKIM signing as your domain.


Elastic Email

Reasonably priced, fully DMARC compliant marketing and transactional email.

GlobalCert SecureMail Gateway


Healthcare talent management SaaS. Contact support and let them know that you need SPF and DKIM set up for DMARC alignment.


Good option if a full Customer Relationship Management (CRM) platform is needed.


Full-featured email marketing

Add to your SPF record.


Transactional email service used by IBM Phytel (see separate entry below) and others.

Add to your SPF record.


Extremely cheap bulk marketing email; extremely expensive transactional email.


A MailChimp add-on service for transitional email



Email and SMS marketing.


Marketing automation

OnSolve Mir3

Mass notification system for employees, contractors, students, etc.

Mir3 supports DKIM alignment via DKIM.

Contact your Mir3 account manager to have them set up DKIM signing/email whitelabeling.

Phytel (sent via JangoSMTP)

IBM Phytel is used by healthcare providers to send appointment reminders and other information to their patients. Emails are relayed through JangoSMTP.

Add to your SPF record.

Contact IBM Phytel support and ask them to configure DKIM signing.

Safe Pay Services

A payment processor that supports DMARC alignment via SPF and DKIM.

Add to your SPF record.

Contact support for details.

Salesforce Marketing Cloud



Not as cheap as Elastic Email, but cheaper than SendGrid and Mandrill, with options for SMS.


B2C medical billing

According to Simplee support as of 2019-05-23, in order to support DKIM signing, they need to purchase a domain authentication package from Salesforce, with the cost passed on to the customer, and have the Simplee customer delegate a domain or subdomain to Salesforce via NS records:


Costs include:

  • One-time setup fee: $350 for Simplee to cover implementation and setup costs
  • Annual Fee: $1,500 per year per domain (pass-through expense via Salesforce) + $39 Salesforce Purchase Order Fee

For for information, contact Simplee support at

Symantec MessageLabs

Services that must use your SMTP relays to be fully DMARC compliant

Incompatible services

Some services do not do any DKIM signing, or use their own domain came in the DKIM d= tag, making the signature unaligned with the message from address domain they are spoofing.

There are different two ways to work around this problem, each with its own benefits and drawbacks:

  1. Have the vendor send emails from their domain instead of yours
  2. Configure the service to use a specific subdomain of your domain in the message from address. Then, create a separate DMARC record with p=none under that specific subdomain.

By having a service send as its own domain, you loose branding in the from email address, but it will not cause additional complexity or risk.

Publishing a DMARC p=none policy on a specific subdomain allows spoofing of that specific subdomain, without weakening DMARC enforcement for other subdomains, or the top level domain. This allows you to keep your domain in the from address, but also opens up that specific subdomain to spoofing from anyone.

UL PureSafety

DKIM signing as customer domains is not currently supported by UL PureSafety OHM.
Most outbound email notifications in OHM are configured by the customer, including the From address they will be sent with. The user(s) should go through the screens where they have set them to various customer addresses and change them to a generic address, such as “[email protected].” They should also update the Body of each email template to include appropriate contact information.


Volgistics does not currently support DKIM signing, so the account administrator will need to complete the following steps to configure Volgistics to send email as

  1. Choose Setup from the menu in the account
  2. Expand Messages
  3. Click the “Ground Rules” link
  4. In the “From address” section, select the “Use [email protected] as the from address (recommended)” option
  5. Click the Save button

Bonus steps

These steps aren’t required to deploy DMARC, but they can help to make your email more secure.

Verify TLS

TLS ensures that messages are encrypted on their way to your mail servers. STARTTLS allows email clients to upgrade from a plan text connection to an encrypted one.

To check STARTTLS, run:

openssl s_client -connect -starttls smtp

To check the standard secure SMTP port, run:

openssl s_client -connect
You can also check SMTP TLS using MX Toolbox or Check TLS.
checkdmarc also checks for TLS and STARTTLS.

Brand Indicators for Message Identification (BIMI)

Brand Indicators for Message Identification (BIMI) is an emerging standard that some mail applications/services are starting to follow (currently only Yahoo, with more services throughout 2019) . When a mail client uses BIMI, it first checks to see if the message passed DMARC alignment. If the DMARC policy is set to enforcement (i.e. p=quarentine or p=reject) and DMARC alignment has passed, the mail/webmail client then checks for a BIMI assertion record at the message from domain. This record points the client to a SVG file publicly hosted on a web server, which is then displayed in the client UI, next to the message from information.

Screenshots of an email with and without BIMI in Outlook webmail

To set up BIMI, host a SVG graphic file at a publicly accessible HTTPS URL, then add a BIMI assertion TXT DNS record like this one. TXT "v=BIMI1; l="

You can validate a BIMI record and logo format at the Mailkit BIMI inspector, which also gives you nice previews of what your BIMI logo would look like in a mail client.
What is currently missing is a way to validate that an entity using a domain actually owns the rights to use a logo, so BIMI isn’t widely used yet. In May 2018, Valimail, Google, and Standcore published a draft standard for solving this problem by authenticating BIMI logos using certificates, similar to how Certificate Authorities (CAs) work for SSL certificates today, but there isn’t a public timeline for when this might be adopted for BIMI and/or Google. Currently, Yahoo is the only major mail provider showing BIMI logos out of the box.
Microsoft has their own non-BIMI beta process for validating and displaying logos called Business Profiles.
if you would like more information about BIMI, email [email protected]; or if you are a customer of Aguri, Return Path, or Valimail (Who are members of the AuthIndicators Working Group responsible for the BIMI standard), contact their support for more information.

30 thoughts on “Demystifying DMARC: A guide to preventing email spoofing”

  1. Hello Sean, first of all I’d like to thank you for your parsedmarc implementation, which is what brought me here. Is there a palce where I could ask for some help about it? I’m trying to test it at my working place, but I can’t send properly the results to Elasticsearch/Kibana. I don’t want to bother you with trivial questions, because I feel I’m a bit incompetent on this topic. Maybe a community help would be more appropriate.

    • Ok, I’ve installed everything from scratch using pypy3 3.5 virtualenv (which is currently compatible with Python 3.5.3) on my Ubuntu 18.04.1 server… and everything works just fine. I thinks it’s possible that Python 3.6.7 (which comes with Ubuntu 18.04.1) it’s not fully compatible with parsedmarc package. Again, thank you very much for this useful tool.

  2. As I browse material touting DMARC, it’s often mentioned that DMARC allows vendors to send mail without getting flagged as spam. Based on what I’ve read there and what is hinted at above, is then a requirement for DMARC compliance that a vendor must have DKIM keys from my domain and/or be included in my SPF records, PLUS he must use my domain as his FROM addresses?

    Trying to figure out what distinguishes a DMARC-compliant vendor from a non-compliant one. I have a vendor who is on the list, but they say they do not support DMARC. Their mail process ultimately puts their own domain in the FROM header, and I’m not sure they can modify this. But as I read it, that will be a non-starter for DMARC regardless of SPF or DKIM.

    • As long as the vendor can DKIM sign as your domain, their email will work fine with DMARC, even if the vendor does not know that. 🙂

  3. Whao….This is the most extensive explanation of email authentication in one single article. Good work.
    Question: Which is what lead me here. Can I set my Dmarc policy to reject/quarantine, if I only have SPF and no DKIM (I use GFI which doesn’t support DKIM at this time).
    If yes will this Dmarc record cause my mails to have issues?
    v=DMARC1; p=none; rua=mailto:[email protected]; ruf=mailto:[email protected]; fo=1:s; aspf=r

  4. Thanks Sean. Was planning to change to p=quarantine but not anymore. Will turn off DMARC totally for now and just rely on SPF only, since i do not have DKIM.

  5. When reading about the mailing lists I wondered if the suggested
    “do: Retain headers from the original message”
    also referred to the envelope from (“Return-Path”). Looking at the article you linked ( it is not the case. The list is recommended to represent itself as the new return-path.

    Reading the original article the recommendation was also to “add a Sender header to indicate their relay role”. Did you leave this out for a reason or are the suggested setup actually doing so? Even if RFC5322 seems to allow multiple Sender addresses it didn’t seem to be valid usage. Adding Sender headers might be bad practice if there is one already (e.g. if an email is sent through multiple layers of lists) and I don’t see it as a very useful thing for the recipient either. Would you agree?

    While commenting I would also mention that “Sean Whalen April 12, 2019 at 3:26 ” reply to “Rick Koch” seems a bit simplified.
    “As long as the vendor can DKIM sign as your domain, their email will work fine with DMARC,” relies on the fact that DMARC is ok with either SPF or DKIM passing. The alignment requirement for DKIM is however the header FROM field.

    “Their mail process ultimately puts their own domain in the FROM header,” says Rick and I would say that changes the answer quite a bit. They are in that case not sending emails from Rick’s domain at all and they should not sign with his key. Right? It should require them to handle their spam reputation themselves.

  6. Hi, this guide was really helpful!
    I was wondering, I have set this up accordingly on my office 365 instance. I have noticed though that mails send from shared mailbox (so basically using send-as) do not get dkim-signed.
    Is that a to be expected behavior?

  7. Turns out, that effective dkim activation on office365 might be delayed differently from one domain to another, even if activated at the same time. That’s why, mails from a shared mailbox (with a different domain) were not signed.

  8. We’re finding that with the Mailman 2 settings as recommended here, mail going to people with forwarded accounts (their uni address is in the list and forwards to their gmail address) is being rejected.

  9. Firstly thanks for a great guide very well explained.

    I have a question about SPF records and enabling DMARC with the p=none policy.

    If I only have SPF enabled, the receiving server can lookup my SPF record and determine the list of authorised servers, and if receiving an email from a server not on my list, will reject or quarantine that email (I understand the limitation of Domain matching on the mailfrom field of course).

    If I then enable DMARC (after enabling DKIM on my servers of course, or in this case Office 365) and set the policy to p=none initially, will the receiving server then record a fail on the SPF record if not sent from an authorised server, but deliver the email anyway as the DMARC policy is set to none?

  10. In the Authorization records example this line: TXT “v=DMARC1”

    should have the last underscore be a period. TXT “v=DMARC1”

  11. Hi sean

    My third party sender is trying to charge alot of money for this using sub domains. and sending my emails through their platform

    Is there an alternative way of doing this?


  12. This is the best article on email DMARC I have found so far. Your article has answered almost all of my questions except for one. I have a question about email delivery based on two scenarios:

    Scenario 1: A company does not have any SPF/DKIM/DMARC records published.
    Scenario 2: A company has an SPF record published and a DMARC record with p=none but does not have DKIM configured.

    If a company moves from scenario 1 to scenario 2 there will be some legit emails that do not match the SPF record. Are those legit emails at any addition risk of not being delivered than when there were no SPF/DKIM/DMARC records published?

  13. I have deployed ParseDMARC but not receiving any emails. Its listed in the features :

    “Optionally email the results”

    Is there any configurations to switch on the reporting on emails.

    I have all required SMTP settings in the configuration file.

    • Thanks! I’m honestly not very familiar with Medium, other than reading a few posts. What would be the advantage of posting there instead of here? At least here I get a tiny bit of ad revenue. 😋

  14. Hi Sean,

    This is by far the most well-articulated, robust but concise documentation I can find ANYWHERE on the internet for SPF, DKIM, and DMARC. I have bookmarked this.

    However, I still can’t fully figure out DKIM alignment with CNAME record implementation.

    We have a vendor that uses mailgun and sends emails as our domain with [email protected]. I tried having them put “” in their TXT DKIM record, but it still signs emails as “” and not “”

    Their record has this name: “” and this value ” k=rsa;; p=blahblahblah”

    I tried putting this matching txt record in our DNS, but as “smtp._domainkey” instead. Still no dice.

    Do I instead need to create a CNAME record called “smtp._domainkey” and point it at
    the current signer “”?

    Thank you!

  15. As many others have commented, this article remains a great service to the community. Thanks.

    Finding services to analyze the reports seems a minefield, though. Even wiht a few domains to monitor, getting a zipped xml file regularly for each domain is an incredible nuisance. What recommendations do you have to tame this automatic self-spamming behavior of getting DMARC reports?


Leave a Comment

This site uses Akismet to reduce spam. Learn how your comment data is processed.