Skip to main content
import { createClient } from "@mailsai/sdk";

const client = createClient(); // reads MAILS_API_KEY

const result = await client.domains.create(
  "mail.acme.com",
);
console.log(result);
{
  "id": "dom_01JZXE8S0U2W4Y6A8C0E2G4J6L",
  "domain": "mail.acme.com",
  "status": "pending",
  "provider": "ownmetal",
  "dns_records": [
    {
      "type": "TXT",
      "host": "dkim._domainkey.mail.acme.com",
      "value": "v=DKIM1; k=rsa; p=MIIBIjANBgkq…",
      "purpose": "dkim",
      "required": true,
      "verified": false,
      "instruction": "Add this record exactly as shown."
    },
    {
      "type": "TXT",
      "host": "mail.acme.com",
      "value": "v=spf1 ip4:15.204.67.226 ~all",
      "purpose": "spf",
      "required": false,
      "verified": false,
      "instruction": "If you already publish an SPF.",
      "merge_token": "ip4:15.204.67.226"
    },
    {
      "type": "TXT",
      "host": "_dmarc.mail.acme.com",
      "value": "v=DMARC1; p=none; rua=mailto:dmarc@mail.acme.com",
      "purpose": "dmarc",
      "required": false,
      "verified": false,
      "instruction": "Only if you have no DMARC record today. If you already publish one, KEEP IT — never lower an existing p=quarantine or p=reject to p=none. Point rua at a mailbox you control."
    }
  ],
  "fail_reason": null,
  "last_check_at": null,
  "verified_at": null,
  "created_at": "2026-07-24T10:30:00.000Z"
}

Add a custom send domain

Registers a bring-your-own sending domain (paid plans).
POST/v1/domainsscope · manage
import { createClient } from "@mailsai/sdk";

const client = createClient(); // reads MAILS_API_KEY

const result = await client.domains.create(
  "mail.acme.com",
);
console.log(result);
{
  "id": "dom_01JZXE8S0U2W4Y6A8C0E2G4J6L",
  "domain": "mail.acme.com",
  "status": "pending",
  "provider": "ownmetal",
  "dns_records": [
    {
      "type": "TXT",
      "host": "dkim._domainkey.mail.acme.com",
      "value": "v=DKIM1; k=rsa; p=MIIBIjANBgkq…",
      "purpose": "dkim",
      "required": true,
      "verified": false,
      "instruction": "Add this record exactly as shown."
    },
    {
      "type": "TXT",
      "host": "mail.acme.com",
      "value": "v=spf1 ip4:15.204.67.226 ~all",
      "purpose": "spf",
      "required": false,
      "verified": false,
      "instruction": "If you already publish an SPF.",
      "merge_token": "ip4:15.204.67.226"
    },
    {
      "type": "TXT",
      "host": "_dmarc.mail.acme.com",
      "value": "v=DMARC1; p=none; rua=mailto:dmarc@mail.acme.com",
      "purpose": "dmarc",
      "required": false,
      "verified": false,
      "instruction": "Only if you have no DMARC record today. If you already publish one, KEEP IT — never lower an existing p=quarantine or p=reject to p=none. Point rua at a mailbox you control."
    }
  ],
  "fail_reason": null,
  "last_check_at": null,
  "verified_at": null,
  "created_at": "2026-07-24T10:30:00.000Z"
}

Body Parameters

domainstringrequired

The domain to send from, such as mail.acme.com, 4 to 253 characters, lowercased and without a trailing dot. A name that is not a valid hostname, is under mails.ai, or is already added to any workspace is refused with 400.

Returns the DNS records to create at your registrar — records-only verification, no nameserver changes. Agents whose address is on a VERIFIED custom domain send under their own identity instead of the shared workspace subdomain. A domain that is already added, to this workspace or to another, is refused with 400 duplicate_resource.

Response

idstring

Domain id (dom_…).

domainstring

The custom sending domain, lowercased.

statusstring

pending → records issued; verifying → checks in progress; verified → agents on this domain send under their own identity; failed → 20 verify calls in a row did not pass. Not final: a failed domain is still re-checked automatically (less often the longer it fails, at most a day apart) and verifies by itself once its records resolve; verify still checks at once, and the count starts over on success or after a day without a verify call.

One of: pending, verifying, verified, failed

providerstring

Backing sending infrastructure for this domain.

dns_recordsobject[]

The records to create at your DNS host. Each record's verified says whether the last check found it, and every required one must be found for the domain to verify.

Show propertiesHide properties
typestring

DNS record type to create.

One of: TXT, CNAME, MX

hoststring

Fully-qualified record host/name to create at your DNS provider.

valuestring

Exact record value. Copy verbatim.

purposestring

What the record is for: dkim (the key that signs your mail), return_path (the bounce address), spf and dmarc (your domain's sender policy), tracking (link tracking), or ownership (any other record the sending provider asks for, such as proof you control the domain).

One of: spf, dkim, dmarc, return_path, tracking, ownership

requiredboolean

Required records gate verification; optional ones improve deliverability/reporting.

verifiedboolean

Whether the record was observed in DNS on the last check.

instructionstring

How to create this record, word for word from the provider. For SPF and DMARC it says when to merge the value into a record the domain already publishes instead of replacing it, because replacing one can break the domain's existing mail.

merge_tokenstring

The part to add to an existing record when merging (for SPF, e.g. ip4:…). A merged SPF record that contains it verifies.

fail_reasonstring | null

Why the last verification did not pass, when it didn't.

last_check_atstring | null

When the records were last checked: by a verify call, by the automatic re-checks of unverified domains, or by the daily re-check of verified ones. Null before the first check.

verified_atstring | null

When the domain first verified. Null until then, and cleared again when the daily re-check of verified domains (06:40 UTC) finds a required record gone.

created_atstring

When the domain was added (UTC).

Was this page helpful?