resellerhq

DMARC record parser

Paste a DMARC record you are drafting and read every tag in it, with the syntax a receiver would discard it for.

Paste the whole TXT value. Quotes, a record name or a whole "IN TXT" line are fine — they are stripped before parsing. Nothing is looked up or stored.

Result

Nothing pasted yet

Paste a DMARC TXT value and every tag in it is explained as you type.

What this is

This DMARC record parser takes the TXT value you paste — a record you are drafting, or one a vendor sent you that nobody has published yet — and explains every tag in it, naming the syntax errors that would make a receiver throw the whole record away. No domain, and no lookup.

A DMARC record is a semicolon-separated list of tag=value pairs, and RFC 7489 section 6.3 registers eleven of them. Two are compulsory and have to come in order: "v=DMARC1" first, then "p". The other nine have defaults, which is why a short record and a long one can ask for very nearly the same thing — and why a tag nobody set still has an effect worth reading.

Most of what goes wrong in a draft is not the policy but the grammar around it: a tag name with a typo, a report address written as a bare email address, a percentage with a "%" after it, a word where a single letter belongs. A receiver does not write back about any of that. It either applies a default you did not choose or discards the record entirely, and both look identical from the outside.

How to read the result

The table lists all eleven tags whether or not this record sets one, so the defaults are visible rather than implied: what is beside "adkim" when you never wrote an "adkim" tag is what a receiver will actually use. An unregistered tag name is listed under them, separately, because a receiver ignores it entirely.

A fail means a receiver would either discard the record or quietly substitute a default — the text is wrong, not just unwise. A warn means the record is valid and does less than it looks like it does: monitoring only, a percentage that enforces nothing, a reporting tag with nowhere to report to. An info is the tag explained, including the ones you left out.

Common mistakes

  • Treating a record that parses here as a record that is live — This reads text, not DNS. A draft can be perfect in the box and absent from your domain, or a different record can already be published at the same name — which is worse, because the old one is what receivers act on.
  • Writing a report address as a bare email address — A DMARC report destination is a URI, not an address: "dmarc@example.com" on its own is not one, and RFC 7489 section 6.3 has a receiver ignore a URI whose scheme it does not support. The reports simply never start arriving.
  • Spelling a single-letter value out as a word — Alignment is "r" or "s", not "relaxed" or "strict", and failure options are "0", "1", "d" and "s". A spelt-out value is not in the grammar, so the tag falls back to its default and the record is looser than it reads.
  • Expecting an error when a tag name is misspelt — RFC 7489 section 6.3 requires receivers to ignore a tag they do not recognise. "policy=reject" is not a complaint anywhere — it is a record with no policy at all, which is a very quiet way to enforce nothing.

Questions

Why must a DMARC record start with v=DMARC1?

RFC 7489 section 6.3 says the "v" tag must be the first tag in the list and its value must match "DMARC1" precisely, and section 6.6.3 has a receiver discard any record that does not start that way. A record with the tags in a different order is not a lenient parse away from working — it is ignored.

Is the semicolon at the end of a DMARC record a mistake?

No. The grammar in RFC 7489 section 6.4 ends with an optional separator, so a trailing semicolon is part of the record format. This tool says so explicitly, because several checkers report it as an error and people then edit a working record to silence them.

Can this tell me whether my DMARC record is actually published?

No, and that is the point of a parser rather than a checker: it makes no DNS query at all, so it can only judge the text you pasted. To see what is live at "_dmarc." plus your domain, including whether two records are published at once, use the DMARC checker instead.

What does pct=0 actually do?

Nothing, in practice. Zero is inside the range RFC 7489 section 6.3 allows, but the sampling rule in section 6.6.4 only selects a message when a random number under 100 is below the percentage, which never happens at zero — so "p=reject; pct=0" behaves exactly like "p=none".

Which tags can a DMARC record carry?

Eleven, per RFC 7489 section 6.3: v and p are required, and sp, pct, rua, ruf, adkim, aspf, fo, ri and rf are optional with defaults. Anything else is an extension nobody has registered, and a receiver is required to ignore it rather than report it.

Sources

Every fixed value this page gives you comes from the provider’s own documentation. These pages change, so each one says the day it was last read here.

Resell mailbox licences for the domains you just checked, under your own brand.

Get started

API example

Example request
curl -X POST https://163-123-236-68.sslip.io/api/tools/dmarc-record-parser \
  -H "Content-Type: application/json" \
  -d '{"record":"v=DMARC1; p=reject; rua=mailto:dmarc@example.com; ruf=mailto:forensics@example.com; fo=1; adkim=s; aspf=s"}'
Example response
{
  "tool": "dmarc-record-parser",
  "input": {
    "record": "v=DMARC1; p=reject; rua=mailto:dmarc@example.com; ruf=mailto:forensics@example.com; fo=1; adkim=s; aspf=s"
  },
  "result": {
    "verdict": {
      "tone": "success",
      "headline": "A valid DMARC record: p=reject",
      "summary": "A receiver that honours this rejects failing mail outright. That is what this text asks for; whether it is published anywhere is a separate question."
    },
    "findings": [
      {
        "id": "nothing-was-looked-up",
        "severity": "info",
        "title": "Nothing here was looked up",
        "detail": "This reads the text in the box and makes no DNS query at all, so it can tell you whether the record is written correctly but not whether it is published, or whether something else is published instead. The DMARC checker answers that for a domain."
      },
      {
        "id": "subdomains-inherit-the-policy",
        "severity": "info",
        "title": "Subdomains follow the same policy",
        "detail": "There is no \"sp\" tag, and RFC 7489 §6.3 says that when it is absent the \"p\" policy MUST be applied for subdomains too. Leaving it out is not a gap: mail claiming to be from any subdomain is already covered by \"p=reject\"."
      },
      {
        "id": "external-reports-need-authorisation",
        "severity": "info",
        "title": "An outside report address needs its own record",
        "detail": "If a report address is on a different domain from the one publishing this record, RFC 7489 §7.1 requires that other domain to publish \"<your-domain>._report._dmarc.<their-domain>\" agreeing to receive them, or a receiver skips the address. A pasted value does not say which domain publishes it, so that cannot be checked here."
      },
      {
        "id": "failure-reporting-options-set",
        "severity": "info",
        "title": "Failure reports are asked for specifically",
        "detail": "\"fo=1\" picks which failures earn a report, from the four values RFC 7489 §6.3 defines. §6.3 also says report generators MAY choose to adhere to the requested options, so this is a request rather than a setting."
      },
      {
        "id": "forensic-reports-requested",
        "severity": "info",
        "title": "This record asks for forensic reports",
        "detail": "A \"ruf\" address asks receivers for per-message failure reports, which can carry parts of a real message — RFC 7489 §6.3 notes a receiver generates none at all without the tag, and whether any receiver sends them to you is their decision, not something the record settles."
      },
      {
        "id": "strict-alignment-requested",
        "severity": "info",
        "title": "Strict alignment is asked for on DKIM and SPF",
        "detail": "In strict mode RFC 7489 §6.3 requires the DKIM and SPF domain to match the From domain exactly, so mail signed or sent as a subdomain stops aligning and starts failing DMARC. It is worth confirming every sender uses the exact domain first."
      },
      {
        "id": "record-is-valid-dmarc",
        "severity": "pass",
        "title": "This text is a valid DMARC record",
        "detail": "It starts with \"v=DMARC1\" and carries a \"p\" tag, which is what RFC 7489 §6.3 requires of a policy record, and every tag in it matches §6.4's grammar. A receiver that honours this rejects failing mail outright."
      },
      {
        "id": "policy-will-be-enforced",
        "severity": "pass",
        "title": "Failing mail is asked to be refused",
        "detail": "A receiver that honours this rejects failing mail outright. RFC 7489 §6.3 says that applies to this domain and to its subdomains, unless an \"sp\" tag sets a different one for them."
      }
    ],
    "parts": [
      {
        "kind": "record",
        "title": "The record, as a receiver reads it",
        "value": "v=DMARC1; p=reject; rua=mailto:dmarc@example.com; ruf=mailto:forensics@example.com; fo=1; adkim=s; aspf=s",
        "note": "Publish this as a TXT record at \"_dmarc.\" plus your domain, not at the domain itself.",
        "at": {
          "name": "_dmarc",
          "type": "TXT"
        }
      },
      {
        "kind": "table",
        "title": "Every tag, explained",
        "columns": [
          "Tag",
          "In this record",
          "What it means"
        ],
        "mono": [
          0,
          1
        ],
        "rows": [
          [
            "v",
            "DMARC1",
            "The record is DMARC version 1 — the only version there is."
          ],
          [
            "p",
            "reject",
            "A receiver that honours this rejects failing mail outright."
          ],
          [
            "sp",
            "(not set — subdomains follow \"p\")",
            "The policy applied to subdomains instead of \"p\"."
          ],
          [
            "pct",
            "(not set — default 100)",
            "The percentage of failing mail the policy is applied to; the rest gets one level lighter."
          ],
          [
            "rua",
            "mailto:dmarc@example.com",
            "Where daily aggregate reports about this domain are sent."
          ],
          [
            "ruf",
            "mailto:forensics@example.com",
            "Where per-message forensic reports are sent, if the receiver supports them."
          ],
          [
            "adkim",
            "s",
            "Strict: the DKIM signature’s domain must match this domain exactly."
          ],
          [
            "aspf",
            "s",
            "Strict: the SPF domain must match this domain exactly."
          ],
          [
            "fo",
            "1",
            "Which failures earn a forensic report: \"0\" only when everything failed, \"1\" when anything did, \"d\" for a broken DKIM signature, \"s\" for a failed SPF check (RFC 7489 §6.3)."
          ],
          [
            "ri",
            "(not set — default 86400)",
            "How many seconds apart aggregate reports are asked for. Daily is the default and the only interval a receiver must support (RFC 7489 §6.3)."
          ],
          [
            "rf",
            "(not set — default \"afrf\")",
            "The format asked for in forensic reports; \"afrf\" is the only one RFC 7489 §6.3 supports."
          ]
        ],
        "note": "Every tag RFC 7489 §6.3 defines is listed, set or not — a tag this record leaves out takes the default shown beside it."
      }
    ],
    "limits": [
      "No lookup is made. This says whether the text is valid DMARC, not whether it is live: a record that parses here still does nothing until it is published at \"_dmarc.\" plus your domain, and something different may be published there already. Check that with the DMARC checker.",
      "A report address on a domain other than the one publishing the record has to be authorised by that other domain (RFC 7489 §7.1). A pasted value does not say which domain publishes it, so that cannot be checked here either.",
      "The record states what you are asking receivers to do. It cannot say how much of your own legitimate mail would fail the policy — only an aggregate report from a real mail stream shows that."
    ]
  }
}

Related tools

Email authentication

DMARC checker

Read a DMARC record in plain words, and see exactly what a receiver does with mail that fails.

Email authentication

DMARC record generator

Build a DMARC record step by step, from monitoring through to full enforcement.

Email authentication

SPF checker

Check an SPF record for the faults that silently break it, and count every DNS lookup it costs.

Email authentication

Email authentication report

See SPF, DKIM, DMARC and MX for one domain together, with the fixes in the order to do them.