> ## Documentation Index
> Fetch the complete documentation index at: https://developers.telnyx.com/llms.txt
> Use this file to discover all available pages before exploring further.

# Email Domains & DKIM

> Register, verify, and manage sending domains with the Telnyx Email API — DNS records (SPF, DKIM, DMARC, MX, ownership), domain health, DKIM signing, status lifecycle, and reputation.

Manage the sending domains that authenticate your email with the Telnyx Email API. This guide covers registering a domain, publishing the DNS records Telnyx generates for you, verifying them, reading domain health, how DKIM signing works, and the settings you can change after a domain is verified.

All requests use the production base URL `https://api.telnyx.com/v2` and an `Authorization: Bearer ***` header.

## Why domain verification

Every email you send is authenticated by the receiving server against three DNS standards:

* **SPF** — confirms Telnyx is an authorized sender for your domain.
* **DKIM** — proves the message body and headers weren't altered in transit, using a cryptographic signature keyed to a DNS record you publish.
* **DMARC** — tells receivers what to do when SPF or DKIM alignment fails (report, quarantine, or reject).

Without these records, recipient providers flag your mail as spam or reject it outright. Telnyx generates the exact DNS records you need for every domain you register, so you only have to copy them to your DNS provider.

## Custom vs shared domains

Telnyx provides two kinds of sending domains:

|                                 | Custom domain                                                             | Shared domain                                         |
| ------------------------------- | ------------------------------------------------------------------------- | ----------------------------------------------------- |
| Owned by                        | Your account (BYOD)                                                       | Telnyx (system account)                               |
| DNS setup                       | Required — you publish the 5 records                                      | None — Telnyx publishes them                          |
| Visible in `GET /email_domains` | Your domains only                                                         | Yes, visible to **all** accounts (`"type": "shared"`) |
| Readable by any account         | No — only the owner                                                       | Yes                                                   |
| Mutable (PATCH/DELETE/verify)   | Yes — by the owning account                                               | No — read-only for non-owners                         |
| From address                    | Any local-part on your domain                                             | `onboarding@<shared-domain>` only                     |
| Recipients                      | Any valid recipient (trial accounts: account owner's verified email only) | Account owner's verified email address only           |

Shared domains are a restricted zero-setup onboarding resource: they're verified at provisioning time and need no DNS setup, but the `from` address must be `onboarding@<shared-domain>` and every recipient must match the account owner's verified email address. Use a custom domain for arbitrary recipients, your own `from` address, and control over sender authentication and domain reputation.

<Callout type="warning">
  **Trial accounts** are restricted to the account owner's verified email address as the recipient regardless of domain type — registering and verifying a custom domain does not lift the restriction. Sends to any other recipient are rejected with `403` and code `10007`. Upgrade the account to send to arbitrary recipients.
</Callout>

<Callout type="warning">
  Shared domains are **read-only** for accounts that don't own them. A `PATCH`, `DELETE`, or `POST …/verify` on a shared domain you don't own returns `403` with error code `10008`.
</Callout>

## Register a domain

Register a custom sending domain with `POST /email_domains`. Only `domain` is required; the optional fields configure inbound routing, your DMARC policy, and tracking:

```bash curl theme={null}
curl -X POST https://api.telnyx.com/v2/email_domains \
  -H "Content-Type: application/json" \
  -H "Authorization: Bearer ***" \
  -d '{
    "domain": "example.com",
    "inbound_enabled": false,
    "dmarc_policy": { "p": "none", "rua": "mailto:dmarc@telnyx.com" },
    "tracking": {
      "open_tracking": true,
      "click_tracking": true,
      "unsubscribe_tracking": true
    }
  }'
```

| Field             | Type           | Default   | Notes                                                                                                                                      |
| ----------------- | -------------- | --------- | ------------------------------------------------------------------------------------------------------------------------------------------ |
| `domain`          | string         | —         | Required. Must be a domain you control; public email providers, disposable domains, IP addresses, and single-label hostnames are rejected. |
| `inbound_enabled` | boolean        | `false`   | Enable inbound routing. When `true`, the MX record becomes required for verification.                                                      |
| `dmarc_policy`    | object \| null | `null`    | Your DMARC policy. Omit or `null` for the advisory default. See [DMARC record](#dns-records).                                              |
| `tracking`        | object         | see below | Open, click, and unsubscribe tracking toggles. Stored on the account's sending profile — see the callout below.                            |

A new domain starts with `status: "pending"` and `usable_for_sending: false`. Telnyx generates a DKIM key and the five DNS records at create time, and a background verification worker runs shortly after — but you'll still need to publish the records first.

<Callout type="tip">
  The effective tracking defaults for a new domain are `open_tracking: false`, `click_tracking: false`, and `unsubscribe_tracking: true`. Open and click tracking are opt-in; one-click unsubscribe (RFC 8058) is on by default because Gmail and Yahoo bulk-sender rules require it. See the [Send Email](/docs/messaging/email/send-email) guide for what each toggle does.
</Callout>

<Callout type="warning">
  **Tracking is scoped to the sending profile, not to the domain.** Tracking settings are stored on your account's default sending profile, which every domain on the account shares. Supplying `tracking` at registration therefore only succeeds for the **first** domain on an account — once a default profile exists, `POST /email_domains` with `tracking` is rejected with a validation error telling you to use `PATCH /email_domains/{id}` instead.
</Callout>

## DNS records

Every domain gets five DNS records. Fetch them with `GET /email_domains/{domain_id}/dns_records` and publish them at your DNS provider:

```bash curl theme={null}
curl https://api.telnyx.com/v2/email_domains/{domain_id}/dns_records \
  -H "Authorization: Bearer ***"
```

Each record in the response has `host`, `value` (what to publish), `actual_value` (what Telnyx last observed in DNS), `record_type`, `priority`, `required`, and `status`.

| # | Purpose   | Type | Host                             | Value                                           | Priority | Required             |
| - | --------- | ---- | -------------------------------- | ----------------------------------------------- | -------- | -------------------- |
| 1 | Ownership | TXT  | `<domain>`                       | `telnyx-domain-verification=<domain_id>`        | —        | ✅ yes                |
| 2 | SPF       | TXT  | `<domain>`                       | `v=spf1 include:spf.telnyx.com ~all`            | —        | recommended          |
| 3 | DKIM      | TXT  | `<selector>._domainkey.<domain>` | `v=DKIM1; k=rsa; p=<base64 public key>`         | —        | ✅ yes                |
| 4 | MX        | MX   | `<domain>`                       | `mx.telnyx.com`                                 | 10       | when inbound enabled |
| 5 | DMARC     | TXT  | `_dmarc.<domain>`                | `v=DMARC1; p=none; rua=mailto:dmarc@telnyx.com` | —        | recommended          |

<Callout type="info">
  The required records are **ownership** and **DKIM** — plus **MX** when `inbound_enabled` is true (`mx` shows `not_required` when inbound is off). **SPF** and **DMARC** are recommended (marked `required: false`) but strongly advised for deliverability — omitting them won't block verification, but recipient providers will treat your mail less favorably.
</Callout>

**What each record does:**

* **Ownership** — proves you control the domain. The value contains the domain's `id`.
* **SPF** — authorizes Telnyx's mail servers to send on your domain's behalf. If you send through multiple providers, add the `include:spf.telnyx.com` directive to your existing SPF record rather than creating a second one (multiple SPF records invalidate each other).
* **DKIM** — publishes the public key that corresponds to Telnyx's DKIM signing key. The host uses the DKIM selector (default `telnyx1`).
* **MX** — directs inbound mail to Telnyx. Required only when `inbound_enabled` is `true`; shows `not_required` in the health check when inbound is off.
* **DMARC** — the advisory default is `p=none` (monitor only) with aggregate reports sent to `mailto:dmarc@telnyx.com`. You can publish a stronger policy (`p=quarantine` or `p=reject`) — Telnyx verifies any valid `v=DMARC1` record, not just its own recommended value.

## Verify and the status lifecycle

Once you've published the DNS records, trigger verification:

```bash curl theme={null}
curl -X POST https://api.telnyx.com/v2/email_domains/{domain_id}/verify \
  -H "Authorization: Bearer ***"
```

The response returns the updated domain. A `200` does not by itself mean success — the same `200` can report `verified`, `pending` (records not yet observed), or `failed` (a required record is missing or wrong). Only `"status": "verified"` means all required records passed and the domain is usable for sending.

### Status values

A domain's `status` field can be one of:

| Status      | Meaning                                                                                     | Can send? | Can receive (inbound)?                      |
| ----------- | ------------------------------------------------------------------------------------------- | --------- | ------------------------------------------- |
| `pending`   | Records not yet verified (or some still propagating).                                       | No        | No                                          |
| `verified`  | All required records pass; DKIM signing material is available.                              | Yes       | Yes, if `inbound_enabled` and MX verified   |
| `failed`    | A required record (ownership or DKIM — and MX if inbound-enabled) is missing or wrong.      | No        | No                                          |
| `degraded`  | Was verified, but a required record has since failed.                                       | No        | Only if `usable_for_inbound` remains `true` |
| `suspended` | Blocked by Telnyx (e.g. for policy or abuse reasons). Admin-only — no public API sets this. | No        | No                                          |

<Callout type="info">
  `verifying` is a reserved value in the status enum but is never assigned by any production code path. Verification is synchronous: `POST /verify` returns the domain already resolved to `verified`, `failed`, or `pending`. Don't write client logic that waits for `verifying`.
</Callout>

<Callout type="info">
  **`degraded` is a soft failure.** A degraded domain was once verified but a **required** record has since failed — Telnyx's drift monitor re-checks verified domains periodically and transitions them to `degraded` when a previously-passing required record now fails. Only ownership and DKIM (plus MX when inbound is enabled) are marked required, so only those can degrade a domain; drift on the optional SPF or DMARC records is a deliverability warning that does not by itself affect sendability. A degraded domain **cannot send**. It can receive inbound mail only when inbound is enabled and the response still reports `usable_for_inbound: true`. Fix the DNS records and re-verify to return to `verified`.
</Callout>

The drift monitor only re-checks domains in `verified` or `degraded` status. When a degraded domain's records recover, it's automatically transitioned back to `verified`. The lifecycle events `email_domain.verified`, `email_domain.degraded`, and `email_domain.suspended` are emitted to configured webhooks on each transition.

## Domain health

For a compact, health-focused view, use `GET /email_domains/{id}/health`:

```bash curl theme={null}
curl https://api.telnyx.com/v2/email_domains/{id}/health \
  -H "Authorization: Bearer ***"
```

```json theme={null}
{
  "data": {
    "id": "6a09cdc3-8948-47f0-aa62-74ac943d6c58",
    "record_type": "email_domain_health",
    "status": "verified",
    "usable_for_sending": true,
    "usable_for_inbound": false,
    "verification": {
      "ownership": "verified",
      "spf": "verified",
      "dkim": "verified",
      "dmarc": "missing_optional",
      "mx": "not_required"
    },
    "checked_at": "2026-05-31T12:00:00Z"
  }
}
```

The `verification` object shows the per-record status: `verified`, `failed`, `pending`, `not_required` (e.g. MX when inbound is off), or `missing_optional` (SPF/DMARC when the optional record is absent).

<Callout type="tip">
  Use `GET /health` for dashboards and monitoring — it's lighter than the full domain object (no nested `dns_records` or `dkim` detail). Use `GET /email_domains/{id}` when you need the actual DNS record values to publish or the DKIM selector.
</Callout>

## DKIM

DKIM (DomainKeys Identified Mail) lets receivers verify that a message wasn't altered after it was sent. Telnyx signs every outgoing message with the domain's active DKIM private key; the recipient looks up the corresponding public key in your DNS at `<selector>._domainkey.<domain>`.

* **Algorithm:** `rsa-sha256`
* **Key length:** 2048-bit RSA
* **Selector:** `telnyx1` (the default; appears in the DKIM record's host)
* **DNS record value:** `v=DKIM1; k=rsa; p=<base64-encoded DER public key>`

The active key is reflected on the domain object in `dkim`:

```json theme={null}
"dkim": {
  "selector": "telnyx1",
  "algorithm": "rsa-sha256",
  "key_length": 2048,
  "active": true,
  "rotated_at": null
}
```

### Key management

<Callout type="info">
  DKIM keys are generated and managed **server-side by Telnyx**. A 2048-bit RSA key pair is created when you register the domain, the private key never leaves Telnyx, and the matching public key is published in the DKIM DNS record you copy to your provider. There is no customer-facing key rotation endpoint — the public API exposes no route to rotate, revoke, or replace a DKIM key.
</Callout>

The `dkim.rotated_at` field reflects the active key's revocation timestamp and is `null` for a normal active key. If you need a key replaced, contact Telnyx support.

## Domain settings

Update mutable settings with `PATCH /email_domains/{id}`:

```bash curl theme={null}
curl -X PATCH https://api.telnyx.com/v2/email_domains/{domain_id} \
  -H "Content-Type: application/json" \
  -H "Authorization: Bearer ***" \
  -d '{
    "inbound_enabled": true,
    "dmarc_policy": { "p": "reject", "rua": "mailto:dmarc@example.com" },
    "tracking": {
      "open_tracking": false,
      "unsubscribe_tracking": true
    }
  }'
```

| Field             | Notes                                                                                                                                                                                                                                                                                   |
| ----------------- | --------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| `inbound_enabled` | Toggles inbound routing. Enabling it makes the MX record required for verification.                                                                                                                                                                                                     |
| `dmarc_policy`    | Updates the recommended `_dmarc` TXT record value and resets its verification to `pending` — republish the record and re-verify. Omit/`null` for the advisory default.                                                                                                                  |
| `tracking`        | Open, click, and unsubscribe tracking. Explicit values — including `false` — always override the defaults. **Scoped to the sending profile:** the setting is stored on the account's default profile, so a change made through one domain applies to every domain sharing that profile. |

The `domain` itself, `status`, `account_id`, and `profile_id` are not settable via `PATCH`. Reputation fields are also rejected on the public API — they're computed internally (see [Reputation](#reputation)).

### Delete a domain

```bash curl theme={null}
curl -X DELETE "https://api.telnyx.com/v2/email_domains/{domain_id}?force=true" \
  -H "Authorization: Bearer ***"
```

Verified or degraded domains require `force=true`; pending or failed domains can be deleted without it. A `suspended` domain can be deleted without `force`. A successful deletion returns `204 No Content`; no domain body is returned.

<Callout type="warning">
  Deleting a shared domain you don't own returns `403` (code `10008`).
</Callout>

## Troubleshooting

### Verification fails to reach `verified`

If `POST /verify` returns a domain that's still `pending` or `failed`, check the `verification` map and the `dns_records` array:

* **Propagation delay** — DNS changes can take minutes to hours to propagate. Wait and retry. The `actual_value` field shows what Telnyx last observed; if it's `null`, the record hasn't been seen yet.
* **Wrong host format** — publish the record under the exact `host` shown (e.g. `telnyx1._domainkey.example.com` for DKIM, not `_domainkey.example.com`). Don't append your domain to an already-fully-qualified host.
* **Missing required records** — ownership and DKIM must verify (plus MX if `inbound_enabled`). SPF and DMARC are optional but recommended.
* **SPF with multiple providers** — if you already have an SPF record, merge the `include:spf.telnyx.com` directive into it. Two SPF records invalidate each other.
* **DMARC** — Telnyx verifies any valid `v=DMARC1` record, so a custom policy (e.g. `p=reject` with your own `rua`) verifies fine. A malformed record reports `failed`.

### Recovering from `degraded`

A `degraded` domain was verified but its DNS drifted. To recover:

1. Fetch the records: `GET /email_domains/{id}/dns_records`.
2. Compare each record's `value` (expected) against `actual_value` (observed) — any `status: "failed"` record has drifted.
3. Correct the record at your DNS provider.
4. Re-verify: `POST /email_domains/{id}/verify`. On success the domain returns to `verified`.

The drift monitor also re-checks degraded domains periodically and will auto-recover them once DNS matches.

<Callout type="info">
  A `suspended` domain cannot be recovered via verification — the verifier short-circuits and won't unsuspend. Suspension is an admin action; contact Telnyx support if your domain is suspended.
</Callout>

## Reputation

Each domain response includes a `reputation` object computed by Telnyx from your sending behavior:

```json theme={null}
"reputation": {
  "band": "good",
  "breakdown": {},
  "computed_at": "2026-07-05T00:00:00Z"
}
```

| Field         | Description                                                                                                              |
| ------------- | ------------------------------------------------------------------------------------------------------------------------ |
| `band`        | Reputation band — e.g. `excellent`, `good`, `warn`, `poor`, or `insufficient_data` (for senders below the volume floor). |
| `breakdown`   | Component scores contributing to the band.                                                                               |
| `computed_at` | When the reputation was last calculated. `null` if not yet computed.                                                     |

Reputation is read-only on the public API — it's updated internally via a daily computation job, not via `PATCH`. A domain in the `poor` band will have sending suspended with a `reputation_suspended` (429) error; see the [Send Email](/docs/messaging/email/send-email) guide for error details.
