Inboxes · September 29, 2026

DMARC Policy for an Autonomous Email Sender

DMARC for AI agent senders: why a fresh agent subdomain should start at p=reject, when that flips, and what sp, np and alignment actually cover.

Most DMARC guides give the same schedule: publish p=none, read aggregate reports for a few weeks, move to p=quarantine, read more reports, and only then publish p=reject. For a company domain with a decade of mail servers, CRMs and forgotten invoicing tools behind it, that schedule is sound. For an agent that sends from a subdomain created last Tuesday, it is weeks in which anyone can put the agent’s address in a From: header and the domain owner has asked receivers to do nothing about it.

This piece argues for DMARC for AI agent senders at p=reject from the first message on a dedicated subdomain, gives the record tag by tag, and lists the cases where the recommendation flips. It is about policy only. Publishing the ownership, SPF, DKIM and MX records for the subdomain is covered in running agent email on a subdomain.

One limit first. Custom domains on this product require a paid plan, and paid plans cannot be bought yet. Today every live inbox sends from agents.emailforagents.ai, a domain the platform operates, so its DMARC record is the platform’s to set, not yours. Everything below applies to a subdomain you control and send from through another provider today; the product-specific sections describe what this code does once a domain is attached, which no one can do yet.

DMARC for AI agent senders: why the monitoring phase protects nothing

Monitoring mode exists to find senders you forgot about, and a new subdomain has none to find. That is not an interpretation; it is the stated reason. RFC 9989, the Proposed Standard published in May 2026 that obsoletes RFC 7489 and RFC 9091, explains in section 5.1.5 that the reason for starting at p=none “is to ensure that nothing’s been missed in the initial SPF and DKIM deployments”, because a domain owner “can overlook a server here or be unaware of a third-party sending agreement there.”

Apply that to agents.example.com on the day you create it. There is no server to overlook, because no server has ever sent as that name. There is no third-party agreement, because nobody else knows the name exists. The complete list of legitimate sources is the one you are configuring right now.

Meanwhile the monitoring phase has a real cost. RFC 9989 section 5.4 says discovered p=none policies “MUST NOT modify existing mail handling processes.” During those weeks the agent is introducing a brand-new address to suppliers, customers and other agents, all learning to trust a name that is, by the owner’s own declaration, unprotected.

Reports do not require monitoring mode. A rua tag works identically at p=reject. You still receive the aggregate XML from every receiver that sends it, and anything unexpected shows up there. The only difference is that its mail was refused while you looked.

This is a deliberate departure from mainstream advice, not a restatement of it. Microsoft’s DMARC setup guide for Microsoft 365, checked on 29 September 2026, tells you to start even a low-volume subdomain with few sources at p=none, then step through quarantine with pct increments. Its only immediate v=DMARC1; p=reject; is for parked domains that never send. A fresh agent subdomain sits between those cases: it will send, but through exactly one path you can enumerate.

On this product that path is enumerable in code, not just in principle. An inbox on a custom domain cannot be created until ownership, sending and receiving are all ready, or it fails with HTTP 422 domain_not_ready. Sending is ready only when the provider reports the domain verified and every SPF and DKIM record, at least one of each, is verified. So nothing sends from your subdomain before a DKIM key for it is verified.

The record to publish, tag by tag

Publish one TXT record at _dmarc under the agent hostname. For a subdomain whose DKIM key the console shows at <selector>._domainkey.agents.example.com:

_dmarc.agents.example.com.  TXT  "v=DMARC1; p=reject; adkim=s; rua=mailto:dmarc-reports@example.com"

Check it from a shell before and after, and confirm there is exactly one:

dig +short TXT _dmarc.agents.example.com
dig +short TXT _dmarc.example.com

Both specifications discard your policy if more than one DMARC record comes back for the name. An RFC 7489 receiver then applies no DMARC at all; an RFC 9989 receiver keeps walking and applies whatever the parent publishes. Either way a leftover template record silently replaces your p=reject.

TagValueWhy
vDMARC1Required, and must come first
prejectNothing legitimate to protect with a softer value
adkims, if the key is under the hostnameThe signing domain is the hostname itself; strict refuses signatures from the parent or sibling names
aspfomit (defaults to r)The bounce address is on a child name, so strict SPF alignment can never pass
ruaa mailbox you readYour only view of what receivers saw
spomitRead only if this name ends up as the organizational domain; see below
pct, tomitTesting knobs; see below

Keep SPF alignment relaxed. The sending provider behind this product puts the envelope sender on a subdomain: Resend’s documentation states that “by default, Resend uses the send subdomain for the Return-Path address”, and the domain-creation request this product makes sets no custom return path. A captured message from the platform shows the result: the Return-Path is an address at send.agents.emailforagents.ai, while the From: is at agents.emailforagents.ai. Under relaxed alignment those share an organizational domain and align. Under aspf=s they never do, which silently removes SPF as a second route to a DMARC pass. That second route matters on direct delivery: if the DKIM signature fails on a message that came straight from the provider, aligned SPF still carries it.

Strict DKIM alignment is safe only if the signing domain is the hostname. DKIM looks up its key at selector._domainkey.<d=>, so the host of the DKIM record the provider issues tells you the d= value. The platform’s own key is published at resend._domainkey.agents.emailforagents.ai, so signatures made with it carry d=agents.emailforagents.ai, an exact match for its From: domain. If the DKIM record you are handed sits anywhere else, leave adkim at its relaxed default.

Skip pct and t. RFC 9989 removes pct (Appendix A.6; the tag registry now lists it as historic), because values other than 0 and 100 were applied inconsistently, and adds t=y as the testing flag. Neither behaves uniformly in 2026. An RFC 7489 receiver ignores unknown tags, so it ignores t=y and applies your full p; an RFC 9989 receiver does not process pct. A hedge that some receivers ignore is not a hedge. Microsoft’s guide still calls RFC 7489 the exhaustive description of the record; on a sender with one source there is nothing to sample anyway.

What a subdomain record does not cover

A record at _dmarc.agents.example.com governs mail whose From: domain is exactly agents.example.com, and nothing below it. The isolation boundary is real: a subdomain’s own record overrides whatever the parent says, including its sp, so the agent’s policy does not depend on the company’s. But two kinds of neighbouring name fall outside it.

The first is the bounce host. send.agents.example.com exists, since it carries the SPF and MX records the provider needs, and it is a perfectly good From: domain for someone who wants to impersonate the agent. It has no DMARC record of its own. The second is any fabricated deeper name, such as billing.agents.example.com.

Where those names find their policy depends on which DMARC the receiver implements.

Either way, if the parent publishes a record, the parent decides for those names. Two practical consequences:

  1. Publish a second record for the bounce host. _dmarc.send.agents.example.com with v=DMARC1; p=reject costs one TXT record. Nothing legitimate uses that name in a From: header, and it does not disturb alignment for your real mail.
  2. If you control the parent, add np=reject there. It closes fabricated names under every subdomain without touching the policy on subdomains that exist, which is usually the part of a company zone nobody wants to change this quarter. Receivers that do not yet implement np fall back to the parent’s sp, or its p.

Do not rely on sp=reject in the agent record to cover deeper names. RFC 7489 says sp “will be ignored for DMARC records published on subdomains of Organizational Domains”, and RFC 9989 keeps the rule, with one exception: if the parent publishes no DMARC record, the tree walk makes agents.example.com the organizational domain for its children and its sp and np apply. An RFC 7489 receiver gives those names no DMARC evaluation at all, so the parent record is the one that works everywhere.

When the recommendation flips

The p=reject default rests on one premise: you know every sender of the name. Where that premise fails, so does the recommendation.

SituationStart atReason
New label; only the agent platform sends; agent mails individualsp=rejectNothing for monitoring to discover
The label already sends through a helpdesk, CRM or bulk toolp=none with ruaThe discovery phase has something to discover; or pick a fresh label
The agent posts to mailing lists or open discussion groupsp=quarantine, or restrictSee the next section
You are tempted to set aspf=sLeave it relaxedThe bounce address is on send., so SPF alignment can only fail
The DKIM record is not under the agent hostnameLeave adkim relaxedStrict alignment would fail every signature
The parent has p=none and no npp=reject on the agent name, and fix the parent if you canThe agent name is protected; its neighbours are not
The agent sends from agents.emailforagents.aiNothing to publishThe platform owns that record

The second row is the one people talk themselves out of. “We only use it for the agent” is often true of intent and false of history. Before publishing p=reject on a name you did not create this week, look for old SPF includes, DKIM selectors or third-party verification records at it. Each is a sender monitoring mode exists to find. If the list is long, a new label such as agent-mail.example.com is cheaper than the audit.

The last row is today’s actual situation. As of 29 September 2026, dig TXT _dmarc.agents.emailforagents.ai returns v=DMARC1; p=none; rua=mailto:support@agents.emailforagents.ai; adkim=r; aspf=r; ri=86400. Say it plainly: the platform does not follow this article’s advice. Its name has one sending path and a DKIM key under the hostname, which is exactly the case argued for p=reject above, and it still publishes p=none, so it asks receivers to do nothing about mail that forges an agent’s address. You cannot change that record, and nothing here promises when it will change. The agent email threat model lists it as an open gap in sender impersonation.

Forwarding, mailing lists and the agent in a thread

Plain forwarding is not a reason to back off p=reject; mailing lists that edit messages are. The difference is which authentication survives.

When a recipient’s mailbox forwards your agent’s message somewhere else, the final hop comes from the forwarder’s IP, so SPF fails. DKIM usually survives, because the body and signed headers arrive unchanged. RFC 9989 section 7.4 turns this into a requirement: domains publishing p=reject “MUST NOT rely solely on SPF to secure a DMARC pass and MUST apply valid DKIM signatures.” Sending on this product cannot become ready without a verified DKIM record. Note also what reject is: a request. Section 5.4 says receivers SHOULD NOT reject solely because of it, and many weigh it with their own analysis.

Mailing lists are different. A list that adds a subject tag or a footer breaks the DKIM signature, and the list server is not in your SPF. Most list software now rewrites the From: to the list’s own address, which RFC 9989 describes as firmly established; a list that does not delivers copies that fail DMARC, and p=reject asks subscribers’ receivers to refuse them. The same section says domains that “host users who might post messages to mailing lists SHOULD NOT publish” p=reject, and warns that rejections can get the list’s other subscribers unsubscribed by the list software’s own bounce handling.

That clause was written for domains full of people, who join lists unpredictably. An agent’s recipients are decided by code and a model, which you can constrain. So the choice is explicit:

ARC helps only where the final receiver has chosen to trust the intermediary that sealed the message. That is their decision, not a record you can publish.

What the domains API checks, and what it never reads

This product does not read, check, require or suggest a DMARC record. That is a statement about source, not an omission from the docs. What it does report is in the custom domains reference. Here is each of the four endpoints.

The resolver interface the domain code uses has two methods, MX and TXT, and neither is ever pointed at a _dmarc name. A missing DMARC record will not hold a domain in pending, and a broken one will not be reported. Check your own with dig.

# Requires a live project on a paid plan, which cannot be bought yet.
curl -s "https://api.emailforagents.ai/v1/projects/$EFA_PROJECT_ID/domains/$EFA_DOMAIN_ID" \
  -H "Authorization: Bearer $EFA_API_KEY" |
  jq '{ownership_status, sending_status, receiving_status,
       records: [.records[] | {type, host, purpose, status, provider_record_kind}]}'

The one domain event is domain.updated. It fires when a domain is attached, after every ownership check, and after every provider readiness check. Every payload carries domain_id and mutates_customer_dns: false. The attach and ownership events add ownership_status, the attach event also adds receiving_mode and migration_consent, and the readiness event carries all three statuses. None mentions DMARC. There is no domain.verify event; that string names the background job that re-checks domains.

One ordering detail matters if you drive setup from events. When an explicit check asks the provider to restart verification, sending_status drops back to pending after the readiness event has gone out, and no second event follows; a failed background re-check does the same. Treat domain.updated as a signal to GET the domain, not as its state.

Checking the first message end to end

A published record is a claim. The first real message is the evidence. Send one from the agent to a mailbox you control at a large provider, open the raw headers, and find the Authentication-Results line the receiver added. For a correctly configured agents.example.com it should read along these lines:

Authentication-Results: mx.receiver.example;
  dkim=pass header.d=agents.example.com;
  spf=pass smtp.mailfrom=send.agents.example.com;
  dmarc=pass header.from=agents.example.com

header.d equal to header.from means strict DKIM alignment holds. smtp.mailfrom on send. is why aspf stays relaxed. If something is wrong you get a rejection or a junk copy instead of a pass, and a failure in your own test mailbox, before the agent has written to anyone who matters, is the cheapest DMARC failure you will ever get.

Then give the aggregate reports a week. On an isolated agent subdomain they should be boring: one source, aligned, passing. Anything else is either a forgotten sender, meaning the name was not as fresh as you thought, or someone using the agent’s name who has just been refused.

None of this is a delivery result. A passing DMARC evaluation is the entry fee for being judged on reputation and content, not a verdict: a 550 5.7.1 bounce can still arrive on perfectly authenticated mail, and why agent email lands in spam covers the filtering that happens after authentication passes. For where DMARC sits among everything else an agent inbox needs, see email for AI agents and the agent inbox overview.


Keep reading

All guides · Documentation · Inboxes