# 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.

Source: emailmarketing.net — https://emailmarketing.net/learn/esp-operations/customer-domain-authentication

If you run an ESP, every customer who wants to send from their own domain has to publish DNS records that you issue, and your platform has to verify those records and keep checking them. Postmark, Amazon SES and Twilio SendGrid document how they do this, and their implementations are described below.

The [M3AAWG Sending Domains BCP](https://emailmarketing.net/learn/industry-best-practices/m3aawg-sending-domains) defines three models of DNS delegation (direct, CNAME and NS) in general terms. Every pattern below is a concrete case of the **direct** or the **CNAME** model. The protocols themselves are explained in [SPF](https://emailmarketing.net/learn/authentication/spf), [DKIM](https://emailmarketing.net/learn/authentication/dkim) and [DMARC](https://emailmarketing.net/learn/authentication/dmarc).

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

When a platform or agency sends email for its customers, Postmark identifies three models. Each trades the quality of authentication against the effort asked of the customer:

| Model | Authentication | Customer effort | Result |
|---|---|---|---|
| 1. Fully aligned customer domain | The customer publishes a DKIM TXT record and a Return-Path CNAME in their DNS | High. DNS access is required, with "significant development" or manual work for each customer | Full alignment, which "maximizes your customers' opportunity for reliable delivery" |
| 2. Verified From address only | The customer confirms ownership through a verification email. The domain is not verified for DKIM or Return-Path | Low: click a link | Mail clients show "via" or "on behalf of" labels. Sending is restricted to the verified address. Not all providers offer it |
| 3. Custom From name on the platform's own domain | None on the customer's domain. Mail is sent from the platform's domain with a customized display name (for example, "Jane at Howdy") and a separate Reply-To | None | The weakest branding, with the risk that "some email clients will aggressively add new contacts… with the wrong email address". Reduce the risk with display names such as "Jane Customer via (vendor)" |

Postmark's advice on choosing is that it "depends on your priorities and how much access your customers allow". Start with one model and add others as customers ask for them.

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

Postmark's API flow is a template for the automated onboarding of customer domains that any ESP builds:

1. **Add the domain** with a `POST` to the Domains API:
   ```json
   { "Name": "customerdomain.com", "ReturnPathDomain": "pm-bounces.customerdomain.com" }
   ```
2. **Give the customer their DNS records.** The API response contains the values to show in your own onboarding interface:
   - `DKIMPendingHost` (DNS host, **TXT** type) with `DKIMPendingTextValue`
   - `ReturnPathDomain` (DNS host, **CNAME** type) with `ReturnPathDomainCNAMEValue`
3. **Poll or trigger verification** with `PUT https://api.postmarkapp.com/domains/{domainid}/verifyDkim` and the account token.

Postmark quotes **up to 48 hours** of DNS propagation before DKIM shows as verified. Once a domain is verified, the customer can send from **any address on that domain**, with no verification of individual addresses. The custom Return-Path CNAME exists specifically "to meet this requirement for [DMARC](https://emailmarketing.net/learn/authentication/dmarc) alignment": it puts an SPF-aligned Return-Path on the customer's domain instead of the ESP's bounce domain.

### Sender-signature (per-address) verification

This is Model 2 in Postmark's interface. You enter a From address (and optionally a From name and Reply-To), a confirmation email is sent to that address, and the owner clicks to activate it. A **"Personal note" field** lets the platform add context to the confirmation email, which is "helpful if you're sending on behalf of a customer that might not know you're using Postmark for email."

Amazon SES has exactly the same problem and solves it with **custom verification email templates** (the `CreateCustomVerificationEmailTemplate` and `SendCustomVerificationEmail` APIs, up to 50 templates per account, HTML limited to an allowlist of tags, and production access required). Platforms that send through SES for their customers rebrand the verification email, so that end users who "never signed up to use Amazon SES directly" are not confused by AWS branding. In SES, verification links expire after **24 hours**. Addresses are case-sensitive, and domains are not.

### Multi-tenant isolation

Postmark recommends **one server for each client**, each with up to **10 message streams** (transactional and broadcast mail in separate streams, with broadcast on subdomains as best practice). This keeps each customer's statistics, bounces and suppressions separate. For bounce handling, Bounce Webhooks (transactional) and Subscription Change Webhooks (broadcast) let the platform show hard bounces to customers in real time. Hard bounces can be reactivated through the Suppressions API, but **only Postmark Support can lift suppressions caused by spam complaints**.

## Easy-DKIM-style CNAME delegation (Amazon SES)

SES's Easy DKIM is the standard implementation, for DKIM, of the [M3AAWG CNAME delegation model](https://emailmarketing.net/learn/industry-best-practices/m3aawg-sending-domains#2-cname-delegation--preferred-by-esps). The ESP generates and holds the key pair, and the customer publishes CNAME records so that the ESP can rotate keys without any further action from the customer.

- The customer publishes **three CNAME records** of this form:
  ```
  {token}._domainkey.customerdomain.com  CNAME  {token}.dkim.amazonses.com
  ```
  (The suffix of the hosted zone varies by region and cell, for example `{token}.{cell}.dkim.{region}.amazonses.com`. The API returns it as `SigningHostedZone` in `DkimAttributes`, so onboarding code should build `{token}.{SigningHostedZone}` rather than hard-code the suffix.)
- Key length: **2048-bit RSA by default**, with 1024 available for DNS providers that cannot hold 2048-bit records. Changes of key length are limited. You cannot switch to the length already configured, and you can make no more than **one switch every 24 hours** (except for the first downgrade to 1024), because a key that is invalidated too quickly breaks verification of mail still in transit.
- SES watches DNS for **up to 72 hours**. When all three CNAME records resolve, the identity becomes Verified and every message from that identity is signed automatically.
- **In SES, verifying the domain and verifying DKIM are the same step.** Proving control of the CNAME records proves ownership of the domain, and no separate ownership TXT record is needed.
- **Inheritance**: DKIM configured on a domain applies to all its subdomains and all addresses on it. Identities for a subdomain or an email address can override the inherited signing by disabling it or enabling it again. SES warns that disabling DKIM "risks tarnishing your sender reputation." Settings apply at the most specific verified level: an address takes precedence over a lower subdomain, which takes precedence over a higher subdomain, which takes precedence over the domain.
- DKIM is needed only on the **domain of the From address**, not on the Return-Path or Reply-To domains.
- **Setup for each region**: identities belong to a region. Sending the same domain from several AWS regions requires separate verification (and separate DNS tokens) in each region, because the validation records differ by region. The limit is 10,000 verified identities per region.
- **DEED (Deterministic Easy DKIM)** removes the need for DNS records in each region. A replica identity in another region inherits the Easy DKIM signing attributes of the parent region with **no additional DNS setup**.

Other options offer different levels of control:

| Option | Who holds the private key | Customer DNS record | Notes |
|---|---|---|---|
| Easy DKIM | ESP (SES) | 3 CNAMEs into `*.dkim.amazonses.com` | The ESP can rotate keys without the customer noticing |
| BYODKIM | The customer gives the key pair to SES | 1 TXT: `{selector}._domainkey.domain` with `p={publicKey}` (strip the PEM header, footer and line breaks, and keep the `p=` prefix) | The key must be RSA **1024–2048 bits**, in base64 or PEM |
| Manual signing | Customer application | Whatever the customer publishes | Sign the mail yourself and send it with `SendRawEmail` |

**Migration hazard**: switching from BYODKIM to Easy DKIM leaves a window in which mail goes out **unsigned** while Easy DKIM is pending. SES advises an intermediate step (for example, keeping a BYODKIM subdomain until Easy DKIM is verified) or making the switch during downtime. The general lesson for ESPs is to never remove 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. The requirements:

- It must be a **subdomain** of the parent domain of the verified identity (for example, `bounce.customerdomain.com`).
- It must **not** be used for anything else: not a subdomain you send from, and not one you receive mail on.
- The customer must publish these records on the MAIL FROM subdomain:

| Host | Type | Value |
|---|---|---|
| `bounce.customerdomain.com` | MX | `10 feedback-smtp.{region}.amazonses.com` (for example `feedback-smtp.us-east-1.amazonses.com`) |
| `bounce.customerdomain.com` | TXT (SPF) | `"v=spf1 include:amazonses.com ~all"` |

- **Exactly one MX record.** Several MX records on the MAIL FROM subdomain make the setup fail. The MX record exists so that the subdomain can receive the bounce and complaint notifications that receivers send to the envelope sender.
- The SPF record goes on the **MAIL FROM subdomain**, not on the apex, and it does not need to copy the apex SPF record (compare [SPF](https://emailmarketing.net/learn/authentication/spf): SPF is evaluated against the RFC5321.MailFrom domain).
- **Behavior when the MX record fails** is a policy choice for each identity, and every ESP should offer it:
  - `UseDefaultValue`: fall back to the ESP's default MAIL FROM (a subdomain of `amazonses.com`). Mail keeps flowing but loses SPF alignment.
  - `RejectMessage`: return `MailFromDomainNotVerified` and refuse to send. This is strict, and it protects the alignment guarantee.
- **Setup states** (SES sends an account notification at every change of state):

| State | Sending behavior | SES action |
|---|---|---|
| Pending | Fallback setting | Checks DNS for the MX record for 72 h; otherwise moves to Failed |
| Success | Custom MAIL FROM used | Keeps re-checking the MX record |
| TemporaryFailure | Fallback setting | Checks for 72 h, then moves to Success or Failed |
| Failed | Fallback setting | Checking stops, and the customer must start the setup again |

The continuous re-checking and the TemporaryFailure state show the practice to follow. Customer DNS records disappear after the first verification (during zone migrations or changes of DNS provider), so verification must be ongoing monitoring, not a one-time gate.

SES also supports **address labels (VERP)** on verified identities (`sender+label@domain` works without extra verification) for attributing bounces.

## Automated domain authentication, link branding and custom return path (SendGrid)

SendGrid puts the whole delegation package under "domain authentication", with an **Automated Security** switch that chooses between the M3AAWG CNAME model (on) and the direct model (off).

### Automated security ON (CNAME delegation, the default)

| Host | Type | Value | Purpose |
|---|---|---|---|
| `em1234.customerdomain.com` | CNAME | `u1234567.wl123.sendgrid.net` | Mail and bounce subdomain. The return path and SPF resolution are 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 (spare for rotation) |
| `_dmarc.customerdomain.com` | TXT | `v=DMARC1; p=none;` | Starter DMARC record |

SendGrid maintains the targets, so SPF changes (for example, new sending IP addresses) and DKIM rotation take effect automatically, with no edits to the customer's DNS. One constraint applies: "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 is now responsible for updates, and any change of IP address or key on the ESP's side requires the customer to edit their DNS by hand. This trade-off, between automatic updates and the need for DNS that accepts underscores in CNAME records, is exactly the difference between the direct and CNAME models in the [M3AAWG BCP](https://emailmarketing.net/learn/industry-best-practices/m3aawg-sending-domains#dns-setup-three-delegation-models).

### Custom return path

- The default bounce subdomain is `em####` (four random letters and digits). Advanced Settings let the customer choose the label (for example, `bounces.customerdomain.com`), but **only at initial setup**. An existing domain authentication cannot be edited to use a custom return path; delete it and create it again.
- Why it matters: with **strict SPF alignment** (`aspf=s` in the DMARC record), the From domain must exactly match the Return-Path domain. A From address `@example.com` with a return path `@em1234.example.com` fails strict alignment and causes rejections such as `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 at the organizational level; see [DMARC](https://emailmarketing.net/learn/authentication/dmarc).)
- SendGrid warns that the generated CNAME "may overwrite existing DNS records" with the same name, so check for collisions before publishing.

### Custom DKIM selector

The default selectors are `s1` and `s2` (or the older `s`). A custom alphanumeric selector of **three characters** (for example, `org` or `001`) covers two cases. The first is authenticating the same domain more than once (several SendGrid accounts or subusers on one brand domain). The second is avoiding collisions with other services that already use the selector `s` on that domain, which is the everyday reality of several ESPs on one domain described in [selector hygiene](https://emailmarketing.net/learn/authentication/dkim).

### Link branding (branded tracking domains)

Without link branding, tracked links and open-tracking pixels point to `sendgrid.net`. "Spam filters and inbox providers look at the links within email messages" and score the reputation of the link domain, so link domains that do not match the sender reduce trust. Link branding publishes **CNAME pairs** such as `url1234.customerdomain.com → <sendgrid target>`, so that tracking URLs are on the customer's domain. A custom label can replace the automatically generated subdomain. Requirements and pitfalls:

- **TLS certificate**: "Add a TLS certificate to the domain or subdomain that serves your links". Branded links must serve HTTPS. In practice, ESPs put a CDN or proxy in front of the tracking host to terminate TLS for customer hostnames.
- Cloudflare users must turn on "Flatten CNAME at root" for setups at the root of the domain.
- Link branding depends on the plan (Email API Pro and above, or Marketing Campaigns Advanced and above), and domains pinned to the EU have regional restrictions.
- Branded links created before 2015 cannot be modified; delete them and create them again (the same applies to domains authenticated before 2015).

### SendGrid scope rules and limits

- Authenticate the **root domain only** (`example.com`, with no `www` and no protocol). Sending is then allowed from that domain, but "**subdomains don't inherit authentication permissions**". This is the opposite of the SES model of inheritance, so check each vendor's behavior rather than assume it.
- Up to **3,000 authenticated domains and 3,000 link brandings** for each user, and also for each subuser.
- Verification: add the records, then click **Verify**. Propagation can take "up to 48 hours". Verification can partly succeed when one record in the set is wrong. If the domain is still not verified after 48 h, contact support.

## DNS verification flows: the common shape

Across all three vendors, every ESP implements the same flow:

1. **Generate** a set of records for each customer, with tokens or selectors specific to each tenant (SES DKIM tokens, SendGrid `u{userid}.wl{id}` targets, Postmark's `pm-bounces` CNAME).
2. **Present** the exact host, type and value of each record in both the interface and the API (SES also offers a CSV download), so that the platform can embed them in its own onboarding.
3. **Poll DNS** within an explicit time budget, from 48 h (Postmark, SendGrid) to 72 h (SES), with a manual "Verify" button to retry.
4. **Notify** the customer when the state changes (SES sends an email at every change of MAIL FROM state).
5. **Keep monitoring** after success (SES keeps re-checking the MX record, and SendGrid pushes changes to record values through the CNAME records). Verification is continuous, not a one-time event.

## Common customer DNS failure modes

These causes of "records added but never verifies" are documented by the vendors, and are worth building into any ESP's troubleshooting interface:

| Failure mode | Symptom | Fix |
|---|---|---|
| **The DNS provider appends the domain automatically** (documented by SendGrid for GoDaddy, Route 53 and Namecheap; SES documents the general case) | `em123.example.com` is stored as `em123.example.com.example.com` | Enter only the host part (`em123`), or end the value with a trailing dot to mark it as fully qualified |
| **Underscores rejected in record names** | DKIM records (`x._domainkey…`) cannot be created | The underscore is mandatory. Escalate to the DNS provider's support (SES), or with SendGrid fall back to Automated Security OFF (its TXT and MX records need no underscore in a CNAME) |
| **An extra leading underscore is added** | `_abc123._domainkey.domain.com` instead of `abc123._domainkey.domain.com` | Use record names exactly as issued. `_domainkey` is the only label with an underscore in Easy DKIM CNAME records |
| **Confusing field names in DNS interfaces** | Values in the wrong fields | "Name" or "host" may be labeled Host or Hostname, and "Record value" may be labeled Points to or Result (SES) |
| **MX priority entered incorrectly** | MAIL FROM never verifies | In most DNS interfaces, the `10` preference goes in a separate field, not in the hostname value |
| **Several MX records on the bounce subdomain** | SES custom MAIL FROM setup fails | Use exactly one MX record on the MAIL FROM subdomain |
| **Quotation marks on TXT values** | The SPF TXT record is rejected or ends up with double quotes | Some providers require the quotes, and some forbid them (SES) |
| **Leftover PEM text in BYODKIM keys** | The `p=` value is invalid | Remove the `-----BEGIN/END-----` lines and all line breaks, to leave a single unbroken string |
| **Records for the wrong region** | Verified in one AWS region, not in another | SES validation records differ by region. Verify again in each region (or use DEED) |
| **CNAME collision** | An existing record with the same name is silently overwritten or blocks the new one | Audit the zone before publishing CNAME records issued by the ESP (SendGrid warning) |
| **`www.` included at setup** | Domain verification "won't succeed" | Enter `example.com`, never `www.example.com` (SES) |
| **Impatience** | The records are correct but still pending | Allow the propagation budget, 48 h (Postmark and SendGrid) or 72 h (SES), before treating the setup as failed |

## Related articles

- [M3AAWG Sending Domains BCP](https://emailmarketing.net/learn/industry-best-practices/m3aawg-sending-domains), the industry framing: three delegation models, subdomain segmentation and migration
- [SPF](https://emailmarketing.net/learn/authentication/spf)
- [DKIM](https://emailmarketing.net/learn/authentication/dkim)
- [DMARC](https://emailmarketing.net/learn/authentication/dmarc)
- [DMARC Deployment](https://emailmarketing.net/learn/authentication/dmarc-deployment)
- [Sending Infrastructure Practices](https://emailmarketing.net/learn/operations/sending-infrastructure-practices), on subdomain strategy and the four domains in a message
- [Content & Design for Deliverability](https://emailmarketing.net/learn/operations/content-and-design-for-deliverability), on why the reputation of link domains (branded tracking) affects filtering
