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

# Sending Domains and DNS

> Adding a domain, the DNS records to publish for email sending, how each one is confirmed, drift detection, and why we never write DNS for you.

Before you can send a single email you have to prove you own the domain you want
to send from. That proof is a set of DNS records you publish in your own zone.
This page is the whole of it: what to add, where, and how to tell when it worked.

## Why DNS is manual

We never write records in your zone, and we never ask for your registrar
credentials. Your DNS is the control plane for your entire online presence:
handing a vendor write access to it so they can add three CNAMEs is a bad trade,
and it is one you cannot easily undo. We generate the exact records; you publish
them.

This is the one part of setup that needs someone with access to your DNS
provider. Everything after it happens in the app.

## Adding a domain

Sending domains are added on **Admin > Domains**, which is the one page for
every domain the platform uses. Click **Add domain** and you type your root
domain **once**:

<Steps>
  <Step title="Enter your root domain">
    `candidate.com`, not a subdomain. This is the organizational domain
    everything else hangs off.
  </Step>

  <Step title="Pick what it is for">
    Tick any combination of the three uses. **Email** is the sending domain.
    **Link tracking** is the host your click and unsubscribe links use.
    **App** is a branded dashboard hostname. Most people adding email want
    email and link tracking together, so the links in your mail carry your
    domain rather than ours.
  </Step>

  <Step title="Accept or edit the subdomains">
    Each use gets a suggested subdomain, prefilled and editable: `mail.` for
    email, `links.` for tracking, `app.` for the dashboard.
  </Step>

  <Step title="Publish the records">
    One table lists every record for every use you picked. Add them at your DNS
    provider and the page tracks them as they land.
  </Step>
</Steps>

Before it generates anything the dialog runs a **pre-flight check** against the
host you are creating. It names your DNS provider, warns about a conflicting SPF
record, and refuses to continue while there is a hard conflict such as a CNAME on
an apex you also need other records at. This is much cheaper to find out now than
after a failed send.

### Use a subdomain

Send from `mail.candidate.com`, not from `candidate.com` itself. A subdomain
keeps campaign sending reputation separate from the domain your staff email
from, so a bad list cannot damage your day-to-day mail. It is the default the
dialog suggests, and it is the right one for almost everyone.

## The records

Publish all of them. There are six, or seven if we generate a DMARC record for
you.

| Record               | Type    | Host                                  | Value                                                        |
| -------------------- | ------- | ------------------------------------- | ------------------------------------------------------------ |
| DKIM key 1           | `CNAME` | `<token>._domainkey.<sending domain>` | A signing host on our sending infrastructure                 |
| DKIM key 2           | `CNAME` | `<token>._domainkey.<sending domain>` | A signing host on our sending infrastructure                 |
| DKIM key 3           | `CNAME` | `<token>._domainkey.<sending domain>` | A signing host on our sending infrastructure                 |
| Bounce host          | `MX`    | `bounce.<sending domain>`             | Our feedback host, priority `10`                             |
| Bounce SPF           | `TXT`   | `bounce.<sending domain>`             | An SPF record authorizing our sending infrastructure         |
| DMARC                | `TXT`   | `_dmarc.<root domain>`                | `v=DMARC1; p=none; adkim=r; aspf=r` with a reporting address |
| Postmaster ownership | `TXT`   | `<root domain>`                       | `google-site-verification=...`                               |

Four things worth knowing about that table:

* **The bounce host is always `bounce.` under your sending domain.** For
  `mail.candidate.com` it is `bounce.mail.candidate.com`. That pair of records
  is what gives you SPF **alignment**: DKIM alone will authenticate your mail,
  but publishing both is what satisfies the bulk-sender requirements at Gmail
  and Yahoo.
* **The DMARC record is omitted entirely if your root domain already publishes
  one.** We will not ask you to add a second `_dmarc` record, because two of
  them is a permanent error that breaks the policy you already have. Your
  existing policy is inherited and satisfies alignment on its own. See
  [DMARC progression](/help/email/campaigns-and-deliverability#dmarc) for moving
  an existing policy forward.
* **DMARC and Postmaster records go on the ROOT domain**, not the sending
  subdomain. Everything else goes on the sending subdomain. This is the single
  most common place to get it wrong.
* **The Postmaster record has no value at first.** It stays blank until Google
  issues a token, usually within minutes. Publish it once the value appears. It
  is optional: nothing about your sending depends on it, and it only unlocks
  reporting. See [Google Postmaster Tools](/help/email/google-postmaster-tools).

## How each record is confirmed

A record is not done because we saw it once. Seeing a record in DNS proves it
resolves; it does not prove the service that needs it has accepted it. So every
record has a **confirming signal** beyond our own lookup, and the capability it
belongs to turns on only when that signal fires:

| Record                     | Confirmed by                                                       |
| -------------------------- | ------------------------------------------------------------------ |
| The three DKIM CNAMEs      | Our sending infrastructure reporting DKIM as verified              |
| The bounce MX and SPF pair | Our sending infrastructure reporting the bounce domain as verified |
| DMARC                      | Our own DNS lookup, since nothing else consumes it                 |
| Postmaster ownership       | Google confirming the token                                        |

The practical effect: a DKIM record that resolves perfectly but has not yet been
accepted upstream shows as **Verifying**, not Active. That is not a bug, and the
usual fix is to wait a few minutes.

### Per-record status

Each row in the table carries its own state, so you can see exactly which record
is holding things up rather than staring at one domain-level "pending":

| State           | Meaning                                              |
| --------------- | ---------------------------------------------------- |
| **Not started** | Nothing seen yet.                                    |
| **Pending**     | We are looking and have not found it.                |
| **Verifying**   | Found in DNS, waiting on the confirming signal.      |
| **Active**      | Confirmed. Done.                                     |
| **Changed**     | Was working, and no longer matches. See drift below. |
| **Failed**      | Verification was abandoned.                          |

### Verify now

**Verify now** on the domain's row re-checks immediately rather than waiting for
the next scheduled poll. It works in **every** state, which is the useful part:
on a pending domain it pushes verification forward, and on an active domain it
re-checks a record that may have been removed, so a broken record surfaces on
demand instead of silently breaking your links.

Use it after publishing records rather than refreshing the page repeatedly. If
you hit it many times in a few minutes you may be rate limited; wait a moment and
try again.

## Drift detection

DNS records get deleted. A zone gets migrated, a provider gets changed, someone
tidying up removes a CNAME they did not recognize. Without detection, the first
you would hear of it is a campaign that stopped authenticating.

Active domains are re-checked on a schedule, and a record that no longer matches
is flagged as **Changed**, with its capability downgraded until it is fixed.
Drift is declared in two cases, deliberately not one:

* **Immediately**, when your zone is serving a **different value**. Someone
  edited the record, which is not ambiguous.
* **On the second consecutive miss**, when the record is simply not found. A
  single lookup failure is usually a resolver hiccup or mid-propagation, not a
  deleted record, and flapping a healthy domain to broken and back helps nobody.

The counter resets the moment the record is seen again.

## When verification stalls

In rough order of how often each one turns out to be the cause:

1. **The record went in the wrong zone.** Added at the root when it belonged on
   the sending subdomain, or the reverse. DMARC and Postmaster go on the root;
   DKIM and the bounce pair go on the sending subdomain.
2. **The registrar appended the domain to an already-complete host name**,
   producing `x._domainkey.mail.candidate.com.candidate.com`. Many DNS UIs add
   the zone for you. If yours does, enter only the part before your domain.
3. **A proxy is on.** A record set to "proxied" rather than "DNS only" is
   rewritten in the answer, so what we see is not what you published.
4. **It has not propagated yet.** Usually minutes, occasionally longer if the
   old record had a long TTL.

## Domain statuses

| Status              | Meaning                                                                    |
| ------------------- | -------------------------------------------------------------------------- |
| **Pending records** | Records generated; publish them.                                           |
| **Verifying**       | Records found, waiting on confirming signals.                              |
| **Active**          | Confirmed. The domain can carry sender identities and send.                |
| **Failed**          | Verification was abandoned. Delete the domain and re-add it to start over. |
| **Suspended**       | Sending has been stopped on this domain. Contact support.                  |

## Deleting a domain

A domain with live sender identities on it cannot be deleted; the request
returns `409 CONFLICT`. Remove or move the identities first. This is deliberate:
deleting the domain out from under an active identity would break sending
mid-campaign rather than at the moment you asked for it.

## Over the API

```bash theme={null}
curl -X POST https://api.politicalcomms.com/v1/email/domains \
  -H "X-API-Key: pc_live_..." \
  -H "Content-Type: application/json" \
  -d '{"domain": "mail.example.org"}'
```

The response carries `dns_records`. Publish them, then poll
`GET /v1/email/domains/{id}` until `status` is `active`. Full request and
response shapes are in the [API reference](/api-reference/introduction).

## What comes next

Once the domain is active, create a
[sender identity](/help/email/campaigns-and-deliverability#sender-identities) on
it. A domain by itself cannot send; the identity is the From address, and it
carries the physical address and disclaimer that go in every footer.
