Platform

Custom email domains

By default your agent's email lives on a Caspian address. Bring your own subdomain and it sends and receives as kernel@agents.example.com instead, DKIM-signed as your domain. You register the subdomain, add a few DNS records, and connect once it verifies.

!

Use a dedicated subdomain (e.g. agents.example.com), never your root domain. Root domains are rejected, and pointing an active mail domain at Caspian would disrupt your existing email.

How it works

1. Register the subdomain

add_domain() registers the subdomain and returns its id plus the DNS records you need to add.

register.py
from caspian_sdk import CommClient

client = CommClient()

domain = client.add_domain("agents.example.com")
print("Domain id:", domain["id"])
print("Status:", domain["status"])          # "pending" until DNS verifies

for record in domain["dns_records"]:
    # three DKIM CNAMEs + one MX
    print(record["type"], record["name"], "->", record["value"])
register.ts
import { CommClient } from "caspian-sdk";

const client = new CommClient();

const domain = await client.addDomain("agents.example.com");
console.log("Domain id:", domain.id);
console.log("Status:", domain.status);         // "pending" until DNS verifies

for (const record of domain.dns_records as any[]) {
  // three DKIM CNAMEs + one MX
  console.log(record.type, record.name, "->", record.value);
}
!

A root domain such as example.com is rejected. Pass a subdomain you control and that isn't already handling mail.

2. Add the DNS records

Add every record exactly as returned at your DNS provider. You get four in total:

TypePurposeCount
CNAMEDKIM signing keys: authenticate outbound mail as your domain3
MXRoutes inbound mail for the subdomain to Caspian1

Prefer a bulk import? The full zone file is available for the domain id:

curl -s https://api.trycaspianai.com/v1/domains/{id}/zone-file \
  -H "Authorization: Bearer $COMM_API_KEY"

3. Poll until active

DNS changes take time to propagate. Poll get_domain(id) until status is active before connecting.

verify.py
import time

while True:
    d = client.get_domain(domain["id"])
    if d["status"] == "active":
        print("Domain verified.")
        break
    print("Still", d["status"], "- waiting for DNS...")
    time.sleep(15)
verify.ts
while (true) {
  const d = await client.getDomain(domain.id);
  if (d.status === "active") {
    console.log("Domain verified.");
    break;
  }
  console.log("Still", d.status, "- waiting for DNS...");
  await new Promise((r) => setTimeout(r, 15000));
}

Propagation is out of Caspian's hands; it depends on your DNS provider's TTLs. Verification usually completes within minutes but can take longer.

4. Connect email on your domain

Once the domain is active, connect email with domain= to put the address on your domain, and username= to pick the exact local part.

agent.py
inbox = client.connect_email(
    domain="agents.example.com",
    username="kernel",
)
print(inbox["address"])              # kernel@agents.example.com
agent.ts
const inbox = await client.connectEmail({
  domain: "agents.example.com",
  username: "kernel",
});
console.log(inbox.address);          // kernel@agents.example.com

Outbound mail is now DKIM-signed as your domain, and replies route back through your handler like any other channel. username= works only on custom domains, and a taken local part returns a 409.

List your domains

list_domains() returns every domain registered under your project, with each one's current status.

for d in client.list_domains():
    print(d["domain"], d["status"])
for (const d of await client.listDomains()) {
  console.log(d.domain, d.status);
}

Next steps

Email channel →
Connect an inbox, handle replies, threading.