emailmarketing.net

Customer Domain Authentication in ESP Practice

How major ESPs (Postmark, Amazon SES, SendGrid) actually implement customer sending-domain authentication — on-behalf-of models, CNAME-delegated DKIM, custom MAIL FROM subdomains, link branding, verification flows, and customer DNS failure modes.

Operationalesp-operatorsender

How ESPs implement customer sending-domain authentication in the field, drawn from Postmark, Amazon SES, and Twilio SendGrid documentation. This is the practice-level companion to the M3AAWG Sending Domains BCP, which defines the three DNS delegation models (direct, CNAME, NS) in the abstract — every pattern below is a concrete instance of the direct or CNAME model. Protocol mechanics live in SPF, DKIM, and DMARC.

The three "sending on behalf of" models (Postmark)

When a platform or agency sends email for its customers, Postmark identifies three models, trading authentication quality against customer effort:

Model Authentication Customer effort Result
1. Fully aligned customer domain Customer publishes DKIM TXT + Return-Path CNAME in their DNS High — DNS access required; "significant development" or manual work per customer Full alignment; "maximizes your customers' opportunity for reliable delivery"
2. Verified From address only Customer confirms ownership via a verification email; domain not DKIM/Return-Path verified Low — click a link Mail clients display "via" / "on behalf of" tags; sending restricted to the verified address only; not offered by all providers
3. Custom From name on the platform's own domain None on the customer's domain — mail is sent from the platform domain with a customized display name (e.g., "Jane at Howdy") and an independent Reply-To None Weakest branding; risk that "some email clients will aggressively add new contacts… with the wrong email address" — mitigate with display names like "Jane Customer via (vendor)"

Postmark's selection guidance: it "depends on your priorities and how much access your customers allow"; start with one model and expand on customer demand.

Model 1 automated via API (the multi-tenant flow)

Postmark's API flow is the template for programmatic customer-domain onboarding any ESP builds:

  1. Add the domainPOST to the Domains API:
    { "Name": "customerdomain.com", "ReturnPathDomain": "pm-bounces.customerdomain.com" }
    
  2. Hand the customer their DNS records — the API response contains the values to surface in your own onboarding UI:
    • DKIMPendingHost (DNS host, TXT type) with DKIMPendingTextValue
    • ReturnPathDomain (DNS host, CNAME type) with ReturnPathDomainCNAMEValue
  3. Poll/trigger verificationPUT https://api.postmarkapp.com/domains/{domainid}/verifyDkim with the account token.

Postmark quotes up to 48 hours of DNS propagation before DKIM shows verified. Once a domain is verified, the customer can send from any address on that domain — no per-address verification. The custom Return-Path CNAME exists specifically "to meet this requirement for DMARC alignment" (SPF-aligned Return-Path on the customer's domain instead of the ESP's bounce domain).

Sender-signature (per-address) verification

Model 2 in Postmark's UI: enter a From address (+ optional From name, Reply-To); a confirmation email is sent to the address; the owner clicks to activate. A "Personal note" field lets the platform add context to the confirmation email — "helpful if you're sending on behalf of a customer that might not know you're using Postmark for email." Amazon SES has the exact same problem and solves it with custom verification email templates (CreateCustomVerificationEmailTemplate / SendCustomVerificationEmail APIs, up to 50 templates per account, HTML restricted to an allowlist of tags, requires production access): platforms sending via SES on behalf of their customers rebrand the verification email so end users who "never signed up to use Amazon SES directly" aren't confused by AWS branding. Verification links expire after 24 hours in SES; addresses are case-sensitive, domains are not.

Multi-tenant isolation

Postmark recommends one server per client, each with up to 10 message streams (transactional vs broadcast separated per stream; broadcast on subdomains per best practice) — per-customer isolation of statistics, bounces, and suppressions. Bounce handling per model: Bounce Webhooks (transactional) and Subscription Change Webhooks (broadcast) let the platform surface hard bounces to customers in real time; hard bounces can be reactivated via the Suppressions API, but spam-complaint suppressions can only be lifted by Postmark Support.

Easy-DKIM-style CNAME delegation (Amazon SES)

SES's Easy DKIM is the canonical implementation of the M3AAWG CNAME delegation model for DKIM: the ESP generates and holds the key pair, and the customer publishes CNAMEs so the ESP can rotate keys without further customer action.

  • Customer publishes three CNAME records of the form:
    {token}._domainkey.customerdomain.com  CNAME  {token}.dkim.amazonses.com
    
    (the hosted-zone suffix varies by region/cell, e.g. {token}.{cell}.dkim.{region}.amazonses.com; the API returns it as SigningHostedZone in DkimAttributes so onboarding code should construct {token}.{SigningHostedZone} rather than hard-coding the suffix).
  • Key length: 2048-bit RSA by default, 1024 selectable for DNS providers that can't carry 2048-bit records. Key-length changes are throttled: you can't switch to the length already configured, and no more than one switch per 24 hours (first downgrade to 1024 excepted) — because a key invalidated too quickly breaks verification of in-transit mail.
  • SES watches DNS for up to 72 hours; when all three CNAMEs resolve, the identity flips to Verified and every message from that identity is signed automatically.
  • Domain verification = DKIM verification in SES: proving control of the CNAMEs proves domain ownership; no separate ownership TXT.
  • Inheritance: DKIM configured on a domain applies to all subdomains and all addresses on it; subdomain or email-address identities can override (disable/re-enable) the inherited signing — SES warns that disabling DKIM "risks tarnishing your sender reputation." Settings apply at the most granular verified level (address > lower subdomain > higher subdomain > domain).
  • DKIM is only needed on the From-address domain — not the Return-Path or Reply-To domains.
  • Per-region setup: identities are regional; sending the same domain from multiple AWS regions requires separate verification (and separate DNS tokens) per region — the validation records differ by region. Limit: 10,000 verified identities per region.
  • DEED (Deterministic Easy DKIM) removes that per-region DNS burden: a replica identity in another region inherits the parent region's Easy DKIM signing attributes with no additional DNS setup.

Alternatives on the same spectrum of control:

Option Who holds the private key Customer DNS record Notes
Easy DKIM ESP (SES) 3 CNAMEs into *.dkim.amazonses.com ESP can rotate transparently
BYODKIM Customer supplies the key pair to SES 1 TXT: {selector}._domainkey.domain with p={publicKey} (strip PEM header/footer and line breaks; keep the p= prefix) Key must be RSA 1024–2048 bits, base64/PEM
Manual signing Customer application whatever the customer publishes Sign yourself, send via SendRawEmail

Migration hazard: switching BYODKIM → Easy DKIM leaves a window where mail goes out unsigned while Easy DKIM is pending; SES advises an intermediary step (e.g., a BYODKIM subdomain kept until Easy DKIM verifies) or doing it during downtime. This is the general ESP lesson: never tear down the old signing path before the new one is verified.

Custom MAIL FROM (Return-Path) subdomains (Amazon SES)

By default SES uses a subdomain of amazonses.com as the MAIL FROM domain — SPF passes, but on Amazon's domain, so it can never be SPF-aligned for the customer's DMARC. A custom MAIL FROM domain fixes that. Requirements:

  • Must be a subdomain of the verified identity's parent domain (e.g., bounce.customerdomain.com).
  • Must not be used for anything else: not a subdomain you send from, not one you receive mail on.
  • Records the customer must publish on the MAIL FROM subdomain:
Host Type Value
bounce.customerdomain.com MX 10 feedback-smtp.{region}.amazonses.com (e.g. feedback-smtp.us-east-1.amazonses.com)
bounce.customerdomain.com TXT (SPF) "v=spf1 include:amazonses.com ~all"
  • Exactly one MX record — multiple MX records on the MAIL FROM subdomain make the setup fail. The MX exists so the subdomain can receive the bounce and complaint notifications receivers send to the envelope sender.
  • The SPF record lives on the MAIL FROM subdomain, not the apex — it doesn't need to mirror the apex SPF (cf. SPF: SPF is evaluated against the RFC5321.MailFrom domain).
  • Behavior on MX failure — a per-identity policy choice every ESP should expose:
    • UseDefaultValue: fall back to the ESP's default MAIL FROM (amazonses.com subdomain) — mail keeps flowing but loses SPF alignment;
    • RejectMessage: return MailFromDomainNotVerified and refuse to send — strict, protects alignment guarantees.
  • Setup state machine (SES sends an account notification on every transition):
State Sending behavior SES action
Pending fallback setting probe DNS for the MX for 72 h; else → Failed
Success custom MAIL FROM used continuous re-checking of the MX
TemporaryFailure fallback setting probe for 72 h; → Success or Failed
Failed fallback setting probing stops; customer must restart setup

The continuous re-check plus TemporaryFailure state is the practice pattern: customer DNS records disappear (zone migrations, provider switches) after initial verification, so verification must be a monitor, not a one-time gate.

SES also supports address labels/VERP on verified identities (sender+label@domain works without extra verification) for bounce attribution.

Automated domain authentication + link branding + custom return path (SendGrid)

SendGrid bundles the whole delegation package under "domain authentication," with an Automated Security toggle that chooses between the M3AAWG CNAME model (ON) and direct model (OFF):

Automated security ON (CNAME delegation — default)

Host Type Value Purpose
em1234.customerdomain.com CNAME u1234567.wl123.sendgrid.net mail/bounce subdomain — return-path + SPF resolution delegated to SendGrid
s1._domainkey.customerdomain.com CNAME s1.domainkey.u1234567.wl123.sendgrid.net DKIM key 1
s2._domainkey.customerdomain.com CNAME s2.domainkey.u1234567.wl123.sendgrid.net DKIM key 2 (rotation spare)
_dmarc.customerdomain.com TXT v=DMARC1; p=none; starter DMARC record

SendGrid maintains the targets: SPF changes (e.g., new sending IPs) and DKIM rotation propagate automatically with no customer DNS edits. Constraint: "If your DNS provider doesn't accept underscores in CNAME records, you can't use Automated Security."

Automated security OFF (direct records)

Host Type Value
em1234.customerdomain.com MX mx.sendgrid.net.
em1234.customerdomain.com TXT v=spf1 include:sendgrid.net ~all
m1._domainkey.customerdomain.com TXT k=rsa; t=s; p=MIG…
_dmarc.customerdomain.com TXT v=DMARC1; p=none;

The customer now owns updates — any ESP-side IP/key change requires manual customer DNS edits. This trade (auto-propagation vs. underscore-in-CNAME support) is exactly the direct-vs-CNAME tradeoff in the M3AAWG BCP.

Custom return path

  • Default bounce subdomain is em#### (four random alphanumerics); Advanced Settings let the customer choose the label (e.g., bounces.customerdomain.com) — but only at initial setup; an existing domain authentication can't be edited into a custom return path (delete and recreate).
  • Why it matters: with strict SPF alignment (aspf=s in the DMARC record), the From domain must exactly match the Return-Path domain. From @example.com with return-path @em1234.example.com fails strict alignment, producing rejections like 550 5.7.26 Unauthenticated email from domain.com is not accepted due to domain's DMARC policy. A custom return path lets From and Return-Path share the same subdomain. (Under relaxed alignment the default em#### subdomain already aligns organizationally — see DMARC.)
  • SendGrid warns the generated CNAME "may overwrite existing DNS records" at the same name — check for collisions before publishing.

Custom DKIM selector

Default selectors are s1/s2 (or legacy s). A custom three-character alphanumeric selector (e.g., org, 001) covers two cases: authenticating the same domain more than once (multiple SendGrid accounts/subusers on one brand domain), and avoiding selector collisions with other services already using s on that domain — the multi-ESP-on-one-domain reality of selector hygiene.

Link branding (branded tracking domains)

Click-tracked links and open-tracking pixels otherwise point at sendgrid.net; "spam filters and inbox providers look at the links within email messages" and score the link domain's reputation, so mismatched link domains hurt trust. Link branding publishes CNAME pairs such as url1234.customerdomain.com → <sendgrid target> so tracking URLs live on the customer domain; a custom label can replace the auto-generated subdomain. Requirements and gotchas:

  • TLS certificate: "Add a TLS certificate to the domain or subdomain that serves your links" — branded links must serve HTTPS (in practice ESPs front the tracking host with a CDN/proxy that terminates TLS for customer hostnames).
  • Cloudflare users must enable "Flatten CNAME at root" for root-level setups.
  • Plan-gated (Email API Pro+ / Marketing Campaigns Advanced+); EU-pinned domains have regional restrictions.
  • Branded links created before 2015 can't be modified — delete and recreate (same for pre-2015 authenticated domains).

SendGrid scope rules and limits

  • Authenticate the root domain only (example.com, no www, no protocol); sending is then permitted from that domain — but "subdomains don't inherit authentication permissions" (the opposite of SES's inheritance model; per-vendor behavior must be checked, not assumed).
  • Up to 3,000 authenticated domains and 3,000 link brandings per user and per subuser.
  • Verification: add records → click Verify; propagation "up to 48 hours"; partial verification is possible when one record of the set is wrong; unverified after 48 h → support.

DNS verification flows: the common shape

Across all three vendors the flow every ESP implements is:

  1. Generate per-customer record set (tokens/selectors namespaced per tenant: SES DKIM tokens, SendGrid u{userid}.wl{id} targets, Postmark pm-bounces CNAME).
  2. Present exact host/type/value tuples in UI + API (CSV download in SES) so the platform can embed them in its own onboarding.
  3. Poll DNS with an explicit time budget — 48 h (Postmark, SendGrid) to 72 h (SES) — with manual "Verify" retry.
  4. Notify on state change (SES emails on every MAIL FROM state transition).
  5. Keep monitoring after success (SES continuously re-checks the MX; SendGrid auto-propagates record-value changes through the CNAMEs) — verification is continuous, not one-shot.

Common customer DNS failure modes

Field-documented causes of "records added but never verifies," worth encoding in any ESP's troubleshooting UI:

Failure mode Symptom Fix
Provider auto-appends the domain (GoDaddy, Route 53, Namecheap documented by SendGrid; SES documents the generic case) em123.example.com stored as em123.example.com.example.com Enter only the hostname part (em123), or terminate the value with a trailing dot to mark it fully qualified
Underscores rejected in record names DKIM records (x._domainkey…) can't be created The underscore is mandatory; escalate to the DNS provider's support (SES), or with SendGrid fall back to Automated Security OFF (TXT/MX records need no underscore in CNAMEs)
Extra leading underscore added _abc123._domainkey.domain.com instead of abc123._domainkey.domain.com Use record names exactly as issued; _domainkey is the only underscore label in Easy DKIM CNAMEs
Field-name confusion in DNS UIs Values in the wrong slots "Name/host" may be labeled Host/Hostname; "Record value" may be Points to/Result (SES)
MX priority mishandled MAIL FROM never verifies The 10 preference is a separate field in most DNS UIs, not part of the hostname value
Multiple MX records on the bounce subdomain SES custom MAIL FROM setup fails Exactly one MX on the MAIL FROM subdomain
Quotation marks on TXT values SPF TXT rejected or double-quoted Some providers require the quotes, some forbid them (SES)
PEM artifacts in BYODKIM keys p= value invalid Strip -----BEGIN/END----- lines and all line breaks; single unbroken string
Wrong-region records Verified in one AWS region, unverified in another SES validation records differ per region; re-verify per region (or use DEED)
CNAME collision Existing record at the same name silently overwritten or blocked Audit the zone before publishing ESP-issued CNAMEs (SendGrid warning)
www. included at setup Domain verification "won't succeed" Enter example.com, never www.example.com (SES)
Impatience Records correct but still pending Propagation budgets: 48 h (Postmark/SendGrid), 72 h (SES) before treating as failed

Related

#esp-operations#domain-delegation#cname#dkim#custom-return-path#mail-from#link-branding#dns-verification#on-behalf-of#dmarc-alignment#multi-tenant