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

# Custom Domains

> Verify a custom sending domain with TXT, MX, SPF, DMARC, and DKIM records.

Free workspaces send from `@try.gork.email`. To send from your own domain (e.g. `alex@outbound.yourdomain.com`), register it, add the DNS records below, then run verification. All mail flows through AWS SES in `ap-southeast-2`.

<Note>
  Custom domains are a paid feature. Upgrade your workspace before verifying, otherwise inboxes on the domain cannot be provisioned.
</Note>

## 1. Register the domain

<CodeGroup>
  ```bash cURL theme={null}
  curl -X POST https://api.gork.email/v1/domains \
    -H "Authorization: Bearer gork_live_YOUR_KEY" \
    -H "Content-Type: application/json" \
    -d '{"domain": "outbound.yourdomain.com"}'
  ```

  ```typescript TypeScript theme={null}
  const res = await fetch("https://api.gork.email/v1/domains", {
    method: "POST",
    headers: {
      Authorization: `Bearer ${process.env.GORK_API_KEY}`,
      "Content-Type": "application/json",
    },
    body: JSON.stringify({ domain: "outbound.yourdomain.com" }),
  });
  const { data } = await res.json();
  // data.dnsInstructions — add every record below to your DNS zone
  ```

  ```python Python theme={null}
  import os
  import requests

  res = requests.post(
      "https://api.gork.email/v1/domains",
      headers={"Authorization": f"Bearer {os.getenv('GORK_API_KEY')}"},
      json={"domain": "outbound.yourdomain.com"},
  )
  for record in res.json()["data"]["dnsInstructions"]:
      print(record["type"], record["name"], "->", record["value"])
  ```
</CodeGroup>

The response returns `id`, `status: "pending"`, a `verificationToken`, and `dnsInstructions`. Registering the same domain twice returns `domain_already_registered` (409). You can also register from the console under **Settings → Domains**.

## 2. Add DNS records

Add every record from `dnsInstructions` at your DNS provider. Values use the domain `outbound.yourdomain.com` as an example:

| Type  | Host / Name                                  | Value                                                       | Purpose                                                |
| :---- | :------------------------------------------- | :---------------------------------------------------------- | :----------------------------------------------------- |
| TXT   | `_gork-challenge.outbound.yourdomain.com`    | `gork-verification=YOUR_TOKEN`                              | Proves domain ownership                                |
| MX    | `outbound.yourdomain.com`                    | `inbound-smtp.ap-southeast-2.amazonaws.com` (priority `10`) | Routes inbound mail to your agents via SES             |
| TXT   | `outbound.yourdomain.com`                    | `v=spf1 include:amazonses.com ~all`                         | Authorizes SES as a sender (SPF)                       |
| TXT   | `_dmarc.outbound.yourdomain.com`             | `v=DMARC1; p=quarantine; pct=100;`                          | Quarantines spoofed mail (DMARC)                       |
| CNAME | `{token}._domainkey.outbound.yourdomain.com` | `{token}.dkim.amazonses.com`                                | SES Easy-DKIM signature (one CNAME per token returned) |

<Warning>
  The MX record is mandatory: a domain only becomes `verified` once the ownership token **and** the SES MX record both resolve. SPF, DKIM, and DMARC are reported per-check and protect deliverability, but they do not gate verification.
</Warning>

## 3. Verify

DNS propagates slowly — wait a few minutes after adding records, then run verification:

```bash cURL theme={null}
curl -X POST https://api.gork.email/v1/domains/dom_31f9c2ab77d04e19/raw \
  -H "Authorization: Bearer gork_live_YOUR_KEY"
```

The response includes a `verificationReport`:

```json theme={null}
{
  "data": {
    "id": "dom_31f9c2ab77d04e19",
    "domainName": "outbound.yourdomain.com",
    "status": "verified",
    "verificationReport": {
      "isVerified": true,
      "tokenVerified": true,
      "mxVerified": true,
      "spfVerified": true,
      "dkimVerified": true,
      "dmarcVerified": true,
      "records": {
        "txtChallenge": { "expected": "gork-verification=...", "found": ["..."], "matched": true },
        "mx": { "expected": "10 inbound-smtp.ap-southeast-2.amazonaws.com", "found": ["..."], "matched": true },
        "spf": { "expected": "v=spf1 include:amazonses.com ~all", "found": ["..."], "matched": true },
        "dkim": { "expected": "{token}._domainkey... CNAME ...", "found": ["..."], "matched": true },
        "dmarc": { "expected": "v=DMARC1; p=quarantine; pct=100;", "found": ["..."], "matched": true }
      }
    }
  }
}
```

Each entry under `records` shows what was `expected`, what DNS resolvers `found`, and whether it `matched` — use it to pinpoint the failing record instead of guessing.

## Statuses

| Status     | Meaning                                                                   |
| :--------- | :------------------------------------------------------------------------ |
| `pending`  | Token or MX check (or both) has not passed yet                            |
| `verified` | Ownership token and SES MX both resolve; the domain can provision inboxes |

The domain row also carries per-check flags (`mxStatus`, `spfStatus`, `dkimStatus`, `dmarcStatus`) and `verifiedAt`, set the first time verification succeeds. Re-run `POST /v1/domains/{id}/verify` any time after DNS changes.

Provision an inbox on the domain with `POST /v1/inboxes` and `"domain": "outbound.yourdomain.com"`. Using an unverified domain there fails with `domain_not_verified` (400). Remove a domain with `DELETE /v1/domains/{id}`.
