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.
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:
- Add the domain —
POSTto the Domains API:{ "Name": "customerdomain.com", "ReturnPathDomain": "pm-bounces.customerdomain.com" } - Hand the customer their DNS records — the API response contains the values to surface in your own onboarding UI:
DKIMPendingHost(DNS host, TXT type) withDKIMPendingTextValueReturnPathDomain(DNS host, CNAME type) withReturnPathDomainCNAMEValue
- Poll/trigger verification —
PUT https://api.postmarkapp.com/domains/{domainid}/verifyDkimwith 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:
(the hosted-zone suffix varies by region/cell, e.g.{token}._domainkey.customerdomain.com CNAME {token}.dkim.amazonses.com{token}.{cell}.dkim.{region}.amazonses.com; the API returns it asSigningHostedZoneinDkimAttributesso 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.comsubdomain) — mail keeps flowing but loses SPF alignment;RejectMessage: returnMailFromDomainNotVerifiedand 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=sin the DMARC record), the From domain must exactly match the Return-Path domain. From@example.comwith return-path@em1234.example.comfails strict alignment, producing rejections like550 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 defaultem####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, nowww, 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:
- Generate per-customer record set (tokens/selectors namespaced per tenant: SES DKIM tokens, SendGrid
u{userid}.wl{id}targets, Postmarkpm-bouncesCNAME). - Present exact host/type/value tuples in UI + API (CSV download in SES) so the platform can embed them in its own onboarding.
- Poll DNS with an explicit time budget — 48 h (Postmark, SendGrid) to 72 h (SES) — with manual "Verify" retry.
- Notify on state change (SES emails on every MAIL FROM state transition).
- 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
- M3AAWG Sending Domains BCP — the industry-standard framing: three delegation models, subdomain segmentation, migration mechanics
- SPF · DKIM · DMARC / DMARC Deployment — protocol mechanics behind these records
- Sending Infrastructure Practices — subdomain strategy and the four domains in a message
- Content & Design for Deliverability — why link-domain reputation (branded tracking) affects filtering
Sources
- Postmark — Best practices for sending on behalf of your users: https://postmarkapp.com/guides/agencies-sending-on-behalf-of-users
- Postmark — The Postmark Manual: https://postmarkapp.com/manual
- Amazon SES — Authenticating email with DKIM: https://docs.aws.amazon.com/ses/latest/dg/send-email-authentication-dkim.html
- Amazon SES — Easy DKIM: https://docs.aws.amazon.com/ses/latest/dg/send-email-authentication-dkim-easy.html
- Amazon SES — Creating and verifying identities: https://docs.aws.amazon.com/ses/latest/dg/creating-identities.html
- Amazon SES — Using a custom MAIL FROM domain: https://docs.aws.amazon.com/ses/latest/dg/mail-from.html
- Twilio SendGrid — How to set up domain authentication: https://www.twilio.com/docs/sendgrid/ui/account-and-settings/how-to-set-up-domain-authentication
- Twilio SendGrid — How to set up link branding: https://www.twilio.com/docs/sendgrid/ui/account-and-settings/how-to-set-up-link-branding
- Twilio SendGrid — How to use Custom Return Path: https://support.sendgrid.com/hc/en-us/articles/13925777447451-How-to-Use-Custom-Return-Path