Email DNS & SPF merge
Add MX, SPF, DKIM and DMARC records with a domain connection. SPFM merges your SPF mechanisms into the published record, so the domain keeps one SPF record.
Connecting a domain points web traffic at your product. Many customers also
want email on that domain (Google Workspace, Microsoft 365, Zoho). Email
records (MX, TXT for SPF/DKIM/DMARC) can ride the same
apply rail as the web records: you
include them in the records array of POST /v1/connections/{id}/apply, or the
customer adds them by hand in the manual flow.
The one email-specific hazard the engine handles for you is SPF: a domain
must have exactly one v=spf1 record, so blindly writing a second one silently
breaks mail. That's what the SPFM meta-record is for.
SPF merge (SPFM)
Instead of a raw TXT, apply an SPFM record with the mechanisms you need. At
write time the engine reads any SPF TXT already published at that host and
merges your mechanisms into it, deduped, with a single terminal all, and
the existing record's qualifier preserved (a merge never loosens the policy):
existing: v=spf1 include:mailgun.org ~all (already published)
SPFM add: include:_spf.google.com
→ written: v=spf1 include:mailgun.org include:_spf.google.com ~allIf nothing is published yet, the SPFM record is materialized into a fresh
v=spf1 … ~all TXT. The merge is refused (error spf_merge_failed) when the
result would exceed 10 DNS-lookup mechanisms or 255 characters. This append-never-clobber behavior is applied for both
Rail B (API-token apply) and the automatic rails.
Provider records (reference)
| Provider | Typical records |
|---|---|
| Google Workspace | MX smtp.google.com, SPF include:_spf.google.com, DKIM google._domainkey TXT, DMARC |
| Microsoft 365 | MX <domain>.mail.protection.outlook.com, autodiscover CNAME, SPF include:spf.protection.outlook.com, DKIM selector1/2 CNAMEs, DMARC |
| Zoho (US data center) | MX mx/mx2/mx3.zoho.com, SPF include:zoho.com, DKIM TXT, DMARC |
| Zoho (EU data center) | MX mx.zoho.eu (Zoho's zoho.eu mail hosts), SPF include:spf.zoho.eu, DKIM TXT, DMARC |
Zoho's SPF include depends on the data center that holds the mailbox. When
CustomDomain™ fills in a domain's mail provider SPF include itself, it reads the
domain's MX records: hosts under zoho.com or zohomail.com get
include:zoho.com, hosts under zoho.eu get include:spf.zoho.eu, and Zoho's
other data centers (such as mx.zoho.in) get no include rather than a guessed
one.
MX records
MX records route inbound mail to the provider's servers and carry a numeric
priority (lower = preferred). Set it with the record's priority field; it
is honored for MX and SRV and ignored for other types. Most providers publish
a single MX (e.g. Google's smtp.google.com at priority 1); a few publish a
ranked set (Zoho's mx.zoho.com / mx2 / mx3 at 10 / 20 / 50).
Mark the MX records essential: true to flag them as required for the
connection, since mail is down without them. The flag is stored on the record;
the poller does not treat it differently from other records today:
{ "type": "MX", "host": "@", "value": "smtp.google.com", "priority": 1, "essential": true }DKIM & DMARC
- DKIM keys are generated in the provider's admin console (unique per
domain), so they can't be derived; add the provider's
selector._domainkeyrecord as given. The widget's DKIM step groups records flaggedpurpose: "dkim"onto a dedicated screen (enableDkim). - DMARC should start at
p=none(monitor only). After confirming legitimate mail passes DKIM/SPF, tighten toquarantine, thenreject.
Full email setup in one apply
MX, SPF (as SPFM), DKIM, and DMARC can all ride a single
POST /v1/connections/{id}/apply records array alongside the web records. The
engine merges the SPFM mechanism into any existing SPF and writes the rest
as-is:
{
"credential": { "token": "<scoped-provider-token>" },
"records": [
{ "type": "MX", "host": "@", "value": "smtp.google.com", "priority": 1, "essential": true },
{ "type": "SPFM", "host": "@", "value": "include:_spf.google.com" },
{ "type": "TXT", "host": "google._domainkey", "value": "v=DKIM1; k=rsa; p=MIGf..." },
{ "type": "TXT", "host": "_dmarc", "value": "v=DMARC1; p=none; rua=mailto:[email protected]" }
]
}The same set can also be applied by the automatic rails (OAuth / one-click
setup), which carry an email-full template that emits these records grouped
for the widget's email screen (MX, an SPFM merge, a DKIM CNAME and a
DMARC TXT). The one-click catalog also ships the records split across
single-purpose templates (email-mx, email-spf, email-dkim, and
email-dmarc) so a provider can apply just one piece. The email-dkim template
writes a CNAME (<selector>._domainkey pointing at the target your mail
provider hosts), not a TXT. Either way the SPFM
merge and MX priority behave identically.
These templates take your mail provider's settings as variables, never records,
and each is checked before a link is signed: mxHost, spfInclude and
dkimTarget are public hostnames (not IP addresses or internal names),
dkimSelector is one DNS label, and dmarcRua is one email address, with a
mailto: prefix accepted and no other DMARC tags. A value of another shape is
refused with 400 invalid_request (-32602 from the MCP server's add-email).
See Template variables.
Pre-flight:
POST /v1/domains:checkreportsspf_override_supportand returns anyrecord_conflicts(includingspf-mergeclashes) it observes in public DNS, so you can warn the customer before writing anything.
Bring your own records
Connect a domain with records only you know, such as email (SES, Workspace) and verification tokens, and see what such a connection does and does not get.
Managed DNS
Point a domain's nameservers at CustomDomain™ once and every later record is written for you. How DNS hosting works, the API and the limits.