# DMARC Record Generator

Generate a DMARC TXT record for _dmarc.<domain> from structured choices: policy (none, quarantine, reject), subdomain policy sp, non-existent subdomain policy np, rua/ruf report addresses (mailto URIs with optional size limits), adkim/aspf alignment, failure options fo, and the legacy pct and ri tags. Validates every value, lists the external report-authorization TXT records needed when reports go to another domain, and returns a four-step rollout from p=none to p=reject. Pure calculation, no DNS queries.

**Not for:** Checking a published DMARC record (use dmarc_check).

- Tool id: `dmarc-generator`
- Category: email
- Execution: pure
- MCP tool `dmarc_generate` at https://lookupowl.com/mcp
- REST `GET https://lookupowl.com/api/v1/tools/dmarc-generator` (or POST a JSON body)
- OpenAPI: https://lookupowl.com/api/openapi.json

## Input

| Field | Type | Required | Default | Description |
|---|---|---|---|---|
| `domain` | string | yes |  | The domain to protect, e.g. example.com (the record is published at _dmarc.<domain>). URLs, e-mail addresses and Unicode names are reduced to the ASCII domain. max length 253 |
| `policy` | "none" \| "quarantine" \| "reject" | no | `"none"` | What receivers should do with mail that fails DMARC: none (monitor only), quarantine (spam folder), reject (refuse). |
| `subdomainPolicy` | "none" \| "quarantine" \| "reject" | no |  | sp=: policy for subdomains. Defaults to the main policy when omitted. |
| `nonexistentPolicy` | "none" \| "quarantine" \| "reject" | no |  | np=: policy for non-existent subdomains (DMARCbis; older receivers ignore it). |
| `rua` | string[] | no |  | Where to send daily aggregate reports: addresses or mailto: URIs, optionally with a size limit (mailto:a@example.com!10m). max 10 items |
| `ruf` | string[] | no |  | Where to send failure (forensic) reports. Most large providers no longer send them. max 10 items |
| `adkim` | "r" \| "s" | no |  | DKIM alignment: r relaxed (default) or s strict. |
| `aspf` | "r" \| "s" | no |  | SPF alignment: r relaxed (default) or s strict. |
| `pct` | integer | no |  | Legacy (RFC 7489) percentage of failing mail the policy applies to. Removed in DMARCbis but still honoured by major providers. min 0, max 100 |
| `fo` | string | no |  | Failure-report options: any of 0, 1, d, s (for example "1" or "0:s"). Only matters with ruf. max length 16 |
| `ri` | integer | no |  | Legacy (RFC 7489) aggregate report interval in seconds (default 86400). Removed in DMARCbis. min 1, max 4294967295 |
| `testing` | boolean | no | `false` | DMARCbis testing mode (t=y): tells receivers you are still rolling out. |

## Output

Results are wrapped in an envelope: `tool`, `version`, `requestId`, `data`, `summary`, `meta` (cache status, timing), `permalink`. `data` has these fields:

| Field | Type | Description |
|---|---|---|
| `domain` | string |  |
| `host` | string | TXT record name: _dmarc.<domain>. |
| `record` | string |  |
| `length` | integer | min -9007199254740991, max 9007199254740991 |
| `chunks` | string[] |  |
| `zoneLine` | string |  |
| `tags` | object[] |  |
| `valid` | boolean |  |
| `issues` | object[] |  |
| `externalAuthorizations` | object[] | TXT records the receiving domain must publish before it can accept reports for your domain. |
| `rollout` | object[] | A staged path from monitoring to full enforcement. |
| `notes` | string[] |  |

## Examples

### Start by monitoring

```json
{"domain":"example.com","policy":"none","rua":["dmarc-reports@example.com"],"testing":false}
```

```bash
curl 'https://lookupowl.com/api/v1/tools/dmarc-generator?domain=example.com&policy=none&rua=dmarc-reports%40example.com&testing=false'
```

Web page: https://lookupowl.com/dmarc-record-generator?q=example.com&rua=dmarc-reports%40example.com

### Quarantine with strict alignment and a reporting vendor

```json
{"domain":"example.org","policy":"quarantine","subdomainPolicy":"reject","rua":["mailto:abc123@dmarc.vendor.net"],"adkim":"s","aspf":"s","testing":false}
```

```bash
curl 'https://lookupowl.com/api/v1/tools/dmarc-generator?adkim=s&aspf=s&domain=example.org&policy=quarantine&rua=mailto%3Aabc123%40dmarc.vendor.net&subdomainPolicy=reject&testing=false'
```

Web page: https://lookupowl.com/dmarc-record-generator?q=example.org&adkim=s&aspf=s&policy=quarantine&rua=mailto%3Aabc123%40dmarc.vendor.net&subdomainPolicy=reject

### Full reject policy

```json
{"domain":"example.net","policy":"reject","nonexistentPolicy":"reject","rua":["dmarc@example.net"],"ruf":["forensic@example.net"],"fo":"1","testing":false}
```

```bash
curl 'https://lookupowl.com/api/v1/tools/dmarc-generator?domain=example.net&fo=1&nonexistentPolicy=reject&policy=reject&rua=dmarc%40example.net&ruf=forensic%40example.net&testing=false'
```

Web page: https://lookupowl.com/dmarc-record-generator?q=example.net&fo=1&nonexistentPolicy=reject&policy=reject&rua=dmarc%40example.net&ruf=forensic%40example.net

## Web pages

- https://lookupowl.com/dmarc-record-generator

## Limits and caching

- Cost: 1 unit for a live lookup, 1 unit for a cached one. Budgets are per network and published in the `RateLimit` response headers.
- Cache: results are kept for 86400 s.
- Timeout: 1 s.

## Related tools

- [DMARC Record Checker](https://lookupowl.com/tools/dmarc-checker.md): Look up and validate a domain's DMARC policy, report addresses and alignment settings.
- [SPF Record Generator](https://lookupowl.com/tools/spf-generator.md): Build a valid SPF record from your mail providers and IP addresses, with a lookup-limit check.
- [SPF Record Checker](https://lookupowl.com/tools/spf-checker.md): Check a domain's SPF record, count its DNS lookups against the limit of 10 and find errors.

## Guide: DMARC record generator

Roll out DMARC safely: start by watching, then tighten step by step.

### What you get

Enter your domain and a few choices, and the generator gives you the DMARC record to publish, the same record as a ready-made zone-file line (the plain-text format DNS servers store records in) and a four-step plan that leads from monitoring to `p=reject`. If your reports go to a mailbox on another domain, it also gives you the authorisation record that domain has to publish. Every value is checked first, so a mistake comes back as a message instead of a broken record.

A DMARC record is a TXT entry at `_dmarc.yourdomain` made of tags such as `p`, `rua` and `adkim`. The generator follows DMARCbis (RFC 9989), so it supports `np` and the testing flag `t`. It still writes the older `pct` and `ri` tags if you ask for them, because large providers still honour them.

The generator makes no DNS requests, so it does not look at your current record. Your choices go to our server, which builds the record. They are not part of our routine logs and are held in memory for at most a day. On the website, Google Analytics also records what you enter, as the [privacy policy](https://lookupowl.com/privacy) explains.

### How to roll out DMARC step by step

1. **Monitor with p=none**: Publish `v=DMARC1; p=none; rua=mailto:you@example.com`. Receivers send reports but still deliver everything. Keep it for a few weeks, and make each real sender pass SPF or DKIM with your domain.
2. **Quarantine a slice**: The plan then sets `p=quarantine; pct=25`, so about a quarter of failing mail goes to spam. `pct` is a legacy tag that large providers still honour. A receiver that has dropped it quarantines all failing mail, so start this step only when you are ready for that.
3. **Quarantine everything**: Remove `pct`. Every failing message now goes to spam. Keep reading the reports for legitimate mail that gets caught.
4. **Finish at reject**: When the reports show only unwanted mail failing, set `p=reject`. Keep the report address active, because new senders appear over time.

Under DMARCbis the testing flag `t=y` replaces `pct` as the way to test a new policy. It asks receivers to treat your policy one step more gently while you test, so quarantine acts like none and reject acts like quarantine. The plan does not use it, but you can switch it on under More options. The four plan records keep your report addresses, alignment and failure options. They leave out `sp`, `np` and `t`, so add those yourself at the step where you want them.

Publish each record as a TXT record at `_dmarc.example.com`, then confirm it with the [DMARC checker](https://lookupowl.com/dmarc-checker).

> **In Claude, ChatGPT or Cursor** Connect the LookupOwl MCP server and ask: “Draft a DMARC record for example.com that sends reports to dmarc@example.com.” The assistant calls `dmarc_generate` and returns the record and the rollout plan.

### Choosing the options

| Option | What to choose | Why |
|---|---|---|
| Policy `p` | `none` first, then `quarantine`, then `reject`. The form starts on `none`. | It gives you time to find senders you forgot. |
| Subdomain policy `sp` | Leave it empty to follow `p`, or choose `reject` if your subdomains should not send mail. | Attackers like unused subdomains. |
| Non-existent subdomain policy `np` | `reject`, even while `p` is still softer. | No real mail comes from names that do not exist. Receivers that only know RFC 7489 ignore it. |
| Aggregate reports `rua` | A mailbox you will read, or the address a reporting service gives you. Up to 10 addresses. | Reports are daily XML files from many receivers. |
| Failure reports `ruf` | Usually leave it empty. | Most large providers do not send them, and they can contain parts of messages. |
| Alignment `adkim` / `aspf` | Leave both on Default, which means relaxed. The generator then leaves the tags out. | Relaxed lets `mail.example.com` align with `example.com`. Strict needs an exact match. |
| Failure options `fo` | Only with `ruf`. `1` asks for a report when any check fails. | The default, `0`, asks only when every check fails. |
| Percentage `pct`, interval `ri` | `pct` only as a short rollout aid. Skip `ri`. | DMARCbis removed both. Large receivers send daily reports whatever `ri` says. |
| Testing mode `t` | Switch it on while you test a stricter policy. | It asks receivers to be one step gentler. It does nothing with `p=none`. |

> **Reports to another domain** If a `rua` address is on a different domain, that domain must publish a TXT record at `yourdomain._report._dmarc.otherdomain` with the value `v=DMARC1`. The generator shows the exact name and value, but the record goes into the other domain's DNS, not yours. Reporting services normally publish it for you. Addresses on your own domain or its subdomains do not need it.

### Mistakes to avoid

- **Enforcing too early.** A sender you forgot starts landing in spam or bouncing before you notice.
- **Sending reports to your personal inbox.** A busy domain can receive hundreds of report emails a day. Use a dedicated mailbox or a reporting service.
- **Forgetting third-party senders.** Newsletters, billing, support and CRM tools must sign with your domain (custom DKIM) or use your domain as their bounce address (the return path).
- **Publishing two records.** Receivers discard both. Edit the existing TXT record at `_dmarc` instead.
- **Using the wrong host name.** Some DNS panels add the zone name themselves, so enter just `_dmarc`, not `_dmarc.example.com`. Paste the value without quotes, because most panels add them.
- **Weakening subdomains by accident.** An `sp` softer than `p` leaves subdomains easier to forge. Leave `sp` out so they follow `p`.
- **Skipping SPF and DKIM.** DMARC needs one of them to pass with alignment. Build your [SPF record](https://lookupowl.com/spf-record-generator) and turn on DKIM at your mail provider.

### How the record is built

The generator accepts a domain, a URL, an email address or the name `_dmarc.example.com` and reduces it to the domain. It checks the policy values, the report addresses, the alignment modes, the failure options and the legacy numbers. It adds `mailto:` to a bare address, drops duplicates and writes the tags in a fixed order: `v`, `p`, `sp`, `np`, `pct`, `rua`, `ruf`, `adkim`, `aspf`, `fo`, `ri`, `t`. A value longer than 255 bytes is also shown as several quoted strings, because a single DNS string cannot be longer. The same function runs behind the REST API and the MCP server.

```text
_dmarc.example.com. 3600 IN TXT "v=DMARC1; p=none; rua=mailto:dmarc-reports@example.com"
```

### Standards

- **RFC 9989**: DMARCbis, published in May 2026. It defines the current tags, including `np`, `psd` and `t`, and replaces RFC 7489.
- **RFC 9990** and **RFC 9991**: the aggregate and failure report formats.
- **RFC 7489**: the earlier specification, which still defines `pct`, `rf` and `ri`.
- **RFC 7208** and **RFC 6376**: SPF and DKIM, whose results DMARC combines.

### Frequently asked questions

**How do I create a DMARC record?**

Enter your domain, keep the policy on `none` and add a report address. Copy the generated value into a TXT record named `_dmarc` in your DNS, then check it with the [DMARC checker](https://lookupowl.com/dmarc-checker). The generator builds new records only. If you already have one, use the checker to read it, then edit the existing record instead of adding a second.

**What is the safest DMARC policy to start with?**

Use `p=none` with a `rua` address. It changes nothing about delivery, and the reports show you which systems send as your domain. You can fix those senders before you enforce anything. Without a `rua` address, `p=none` teaches you nothing, so always set one.

**How long should I stay on p=none?**

Long enough to see every legitimate sender, usually two to four weeks. Allow a full month if you have invoicing or reminder systems that only mail now and then. Move on when the reports show your real mail passing, and the only failures left are mail you do not recognise.

**What email address should I use for rua?**

Use one you will actually process. For a small domain a dedicated mailbox is fine. For a busy one, use a DMARC reporting service that gives you an address and turns the XML into readable charts. If the address is on another domain, that domain must authorise it, and the generator shows the record it needs.

**Is the pct tag still needed?**

No. DMARCbis removed it, and the testing flag `t` takes over its job. Large providers still honour `pct`, so it works for a gradual rollout today. Treat it as a stepping stone, and finish the rollout with plain `quarantine` and `reject`.

**Do subdomains need their own record?**

Not usually. A subdomain without a record follows the parent's, using `sp` if you set it. Add a record at the subdomain only when it needs a different policy. Set `np=reject` on the parent to block mail from subdomains that do not exist.

**How long until DMARC takes effect?**

Usually within an hour, once resolvers drop the answer they cached before. Receivers look the record up as they process mail and may keep it for the record's TTL, the number of seconds a resolver may cache it. The zone-file line from the generator uses 3600, which is one hour. Reports usually start to arrive within a day or two.
