Multi-record and email records
Sessions that need several DNS records (CNAME plus ownership proof, apex A/AAAA, SPF/DKIM/DMARC): what each connect path does and how email records verify.
POST /api/v1/sessions has always taken records as an array, and the guided-manual and Cloudflare one-click paths have always written and verified every record in it. What changed in September 2026 is the Domain Connect one-click path: it used to express exactly one record, and now applies whole record sets, provided the set matches one of the templates DoDomain publishes. This page is the honest map of what each path does with a multi-record session, and how email records are verified.
The shapes that get one-click on Domain Connect
Domain Connect providers apply pre-approved templates, never arbitrary record lists. DoDomain publishes five (the JSON lives in docs/domain-connect/templates); a session gets the one-click button when its records (in any order, every one of them) fill exactly one template:
| Template | Records the session sends | Notes |
|---|---|---|
custom-subdomain-cname | one CNAME at a non-apex host | served by Cloudflare, Glauca HexDNS and Vercel (apply proven on all three), and by Domain Chief, NameSilo, Simply.com and Danego DNS (apply not yet proven) |
domain-verification | one TXT at _dodomain-challenge whose value starts with dodomain-verify= | served by the same seven; apply proven on Cloudflare and Glauca HexDNS, not yet proven on the other five |
custom-subdomain-cname-with-verification | the CNAME above plus the ownership TXT at _dodomain-challenge under the same host (_dodomain-challenge.app.acme.com for app.acme.com) | the "A/CNAME + TXT" pattern most custom-domain products use; served by Cloudflare, Domain Chief, Glauca HexDNS, NameSilo, Simply.com and Danego DNS (not Vercel); apply proven on Cloudflare (2026-09-26) and Glauca HexDNS (2026-10-22), not yet proven on the other four |
apex-a-with-verification | one A at @, optionally one AAAA at @, plus the ownership TXT at _dodomain-challenge | the apex path, never a CNAME (see Apex domains); served by the same six as the row above, apply proven on Cloudflare (2026-09-26) and Glauca HexDNS (2026-10-23), not yet proven on the other four |
email-authentication | any subset of: an SPF TXT at @ with exactly one include:, one DKIM record at <selector>._domainkey (CNAME or TXT), a DMARC TXT at _dmarc | applied group by group; never MX; served by the same six, apply proven for every group on Cloudflare (2026-09-26) and Glauca HexDNS (2026-10-22), not yet proven on the other four |
A session that matches none of them still works: it takes the guided-manual path (every provider) or Cloudflare one-click (Cloudflare zones), both of which handle any combination of the accepted record types (A, AAAA, CNAME, TXT, MX, SRV, CAA, and NS below the root). A session that includes SRV, CAA or NS is never offered Domain Connect one-click, since no template carries those types.
More templates are prepared for those sessions. No provider serves them yet, so today these sessions keep the paths above; the one-click button appears only where a provider serves the template a session needs. email-sending covers a full sending setup in one consent (SPF, up to three DKIM records, DMARC, and the MAIL FROM subdomain's MX and SPF), website covers up to four A and two AAAA addresses with www, a wildcard and the certificate challenge CNAME, and site-verification adds third-party ownership tokens (Google, Microsoft 365 and others). A universal template, dns-records, takes any other combination of the five record types; it is offered to DNS providers directly and is not in the public template registry.
Served is not proven
The three multi-record templates are in the Domain Connect template registry, and Cloudflare (to
every customer since 2026-09-25), Domain Chief, Glauca HexDNS, NameSilo, Simply.com and Danego DNS
serve them. Vercel serves only the two single-record templates. On Cloudflare all three were
applied and verified for real on 2026-09-26, including the SPF merge into an existing SPF record;
on Glauca HexDNS custom-subdomain-cname-with-verification and every email-authentication group
were applied and verified on 2026-10-22, and apex-a-with-verification on 2026-10-23, so all five
are proven there; on Domain Chief, NameSilo, Simply.com and Danego DNS they are served, apply not
yet proven. The same goes for the two single-record templates on Domain Chief, NameSilo,
Simply.com and Danego DNS, and for domain-verification on Vercel, where custom-subdomain-cname
was proven on 2026-10-20. State of Domain Connect
measures this nightly. A provider only applies a template it has onboarded; on any provider that
has not, a multi-record session on a Domain Connect zone shows the manual records and verifies
them exactly like tier 3. The dashboard's Domain preflight tool probes each template against a
zone's provider and reports onboarded / not onboarded / not probed per template, so you never have
to guess.
What each connect path does with several records
| Path | Multi-record sessions |
|---|---|
| Cloudflare one-click (tier 1) | Writes every record through the user's OAuth grant, reads each back from Cloudflare, and finalizes only when every one matches. Unchanged. |
| Domain Connect one-click (tier 2) | Compiles the whole set into one template and one provider approval; the provider writes every record; DoDomain then re-verifies each record against the zone's authoritative nameservers before the session is verified. A redirect back is never proof on its own. |
| Guided manual (tier 3) | Lists every record with copy buttons, checks each one independently, and shows found / not found yet per record. A session is verified only when all records are found. Unchanged. |
Partial progress is reported honestly: after a check, the hosted page shows 2/3 found and marks exactly which record is still missing, with what is actually published at that name when something is there but does not match.
Email records: how verification reads them
Ownership tokens are compared byte for byte, case-sensitively; that is the whole point of a token. Email policies are not tokens, and comparing them byte for byte would fail the healthy outcome. Verification therefore reads the three email record types by their meaning:
- SPF (
TXTat@,v=spf1 …). A zone may hold only one SPF record: two of them is a permanent error that fails every sender (RFC 7208 §3.2). So the correct result of "addinclude:_spf.yourproduct.com" is the zone's existing SPF record now containing that mechanism, which is exactly what Domain Connect'sSPFMmerge does and what a user does by hand. Verification passes when every mechanism your session asked for is present in the publishedv=spf1record; the terminal~all/-allis the zone owner's choice and is not compared. One caveat for one-click applies: a provider'sSPFMmerge may rewrite that qualifier when it rebuilds the record (one provider has told us its merge always lands on~all), so if your product depends on a strict-all, read the published record back rather than assuming it survived the merge. When an SPF record exists but lacks your mechanism, the hosted page says so and tells the user to edit that record rather than add a second one. The page also warns when the published record makes more than 10 DNS lookups on its own terms (the RFC 7208 evaluation limit): a warning beside a found record, never a verification failure. - DKIM (
CNAMEorTXTat<selector>._domainkey). A CNAME is compared like any hostname. A keyTXTis compared tag by tag:vandkfall back to their RFC 6376 defaults when the provider omits them, and the key inp=is compared with whitespace removed, because long keys come back split across strings. - DMARC (
TXTat_dmarc). Compared tag by tag: the published record must bev=DMARC1and carry every tag your session asked for with the same value (p=,rua=, and so on); report addresses are compared as sets. Extra tags the zone owner adds are not a mismatch. A_dmarcrecord with a different policy is reported as a different value; waiting will not change it.
Request them the way you would document them for a customer:
{
"domain": "acme.com",
"records": [
{ "type": "TXT", "host": "@", "value": "v=spf1 include:_spf.yourproduct.com ~all" },
{ "type": "CNAME", "host": "yp1._domainkey", "value": "yp1.dkim.yourproduct.com" },
{
"type": "TXT",
"host": "_dmarc",
"value": "v=DMARC1; p=none; rua=mailto:dmarc@yourproduct.com"
}
]
}MX is deliberately manual
Sessions may include MX records and every path verifies them (exchange and priority), but the
Domain Connect one-click path never writes one: a wrong MX write black-holes a domain's mail the
moment it propagates, and a connect session knows nothing about the domain's existing mail
routing. If your product receives mail on the customer's domain, the MX stays a manual record,
verified against authoritative DNS like every other, and watched by the monitor afterwards.
Constraints worth designing around
- One
include:per SPF session. The Domain Connect template merges exactly one mechanism, so a session whose SPF value carries more (ip4:,a, a secondinclude:) is entered by hand. Keep your SPF footprint to a single include host you control. The free SPF record checker parses a domain's record, walks its includes, and counts the DNS-querying terms against RFC 7208's limit of ten, worth running against a customer's domain before adding your include to it, since a record already at the limit willpermerrorthe moment yours lands. The SPF 10-lookup limit lists what the includes common email vendors document actually cost, measured. - One DKIM selector per session. Providers that rotate between two or three selectors (Microsoft 365, Amazon SES) need one session per selector for one-click, or the manual path for all of them at once.
- Byte-exact prefixes. For one-click, a DKIM
TXTmust start withv=DKIM1;and a DMARCTXTwithv=DMARC1;(with the space): the template fixes that prefix and appends the rest. Other spellings still work on the manual and Cloudflare paths. - The ownership TXT sits under the host for
custom-subdomain-cname-with-verification:host: "_dodomain-challenge"on a session forapp.acme.comverifies at_dodomain-challenge.app.acme.com. An ownership TXT at the zone apex pairs withdomain-verificationon its own. - Apex sessions never get a CNAME.
apex-a-with-verificationwritesA/AAAA; Cloudflare's Domain Connect implementation rejects theAPEXCNAMErecord type outright, and the Cloudflare one-click (OAuth) path remains the more capable option on Cloudflare zones.
Nothing about the API shape changed for any of this: records[] is the same array it always was, and the SDKs are untouched.