Hoppa till innehållet

Account

Domains

Your account sends only from domains it has verified, and every server of the account can send from them. Verification is two DNS records, added once, and Sendora checks them for you. You never touch your own SPF record.

Before you start

Domains belong to the account. Add and check them in the dashboard under Domains, or through the API with an account key (ak_…). An administrator creates that key under Account › API keys. A server key can only send from the domains, as Keys explains.

Add the domain

The response has the two records to add. Sendora generates a DKIM key pair for the domain when you add it, and the private key never leaves Sendora.

POST /v1/domains
curl -X POST https://api.sendora.se/v1/domains \
  -H "Authorization: Bearer $SENDORA_ACCOUNT_TOKEN" \
  -H "Content-Type: application/json" \
  -d '{
  "domain": "mail.example.se"
}'
import { SendoraAccount } from '@sendora/sdk';

const account = new SendoraAccount({
  token: process.env.SENDORA_ACCOUNT_TOKEN,
});

const domain = await account.domains.create({
  domain: 'mail.example.se',
});

console.log(
  `${domain.returnPath.type} ${domain.returnPath.host} -> ${domain.returnPath.value}`,
);
console.log(
  `${domain.dkim.type} ${domain.dkim.host} -> ${domain.dkim.value}`,
);
import os

from sendora import SendoraAccount

account = SendoraAccount(
    os.environ["SENDORA_ACCOUNT_TOKEN"]
)

domain = account.domains.create(domain="mail.example.se")

for record in (domain.return_path, domain.dkim):
    print(record.type, record.host, "->", record.value)
Response (22 lines)
{
  "domainId": "0d7f6a1e-4c0b-4b7e-9d3c-2a1f5e8b9c01",
  "domain": "mail.example.se",
  "verified": false,
  "createdAt": "2026-09-15T12:00:00.000Z",
  "lastCheckedAt": null,
  "failingSince": null,
  "returnPath": {
    "type": "CNAME",
    "host": "sendora-bounces.mail.example.se",
    "value": "bounces.sendora.se",
    "verified": false,
    "verifiedAt": null
  },
  "dkim": {
    "type": "TXT",
    "host": "sendora-a1b2c3d4._domainkey.mail.example.se",
    "value": "v=DKIM1; k=rsa; p=MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEA…",
    "verified": false,
    "verifiedAt": null
  }
}

Add both records at your DNS provider:

  • returnPath: a CNAME from sendora-bounces.<your domain> to bounces.sendora.se. Bounce reports and feedback-loop reports for your mail arrive there and become events on your messages.
  • dkim: a TXT record under <selector>._domainkey.<your domain> holding the public key. The response gives the selector and the value. Every message is signed with the key, so receivers see your domain vouching for the mail.

The domain may also be a subdomain, such as mail.example.se, which keeps the records away from the rest of your zone. The From address must use a verified domain exactly: verifying mail.example.se does not cover example.se or news.mail.example.se.

Adding a domain the account already has fails with domain_exists, which gives the id of the existing one.

Check the records

Sendora looks the records up on its own: an unverified domain every two minutes, a verified one every day, and one in its warning every hour. To see the result now, ask for a check:

POST /v1/domains/{domainId}/verify
curl -X POST https://api.sendora.se/v1/domains/{domainId}/verify \
  -H "Authorization: Bearer $SENDORA_ACCOUNT_TOKEN"
import { SendoraAccount } from '@sendora/sdk';

const account = new SendoraAccount({
  token: process.env.SENDORA_ACCOUNT_TOKEN,
});

const domain = await account.domains.verify(
  '0d7f6a1e-4c0b-4b7e-9d3c-2a1f5e8b9c01',
);

console.log(
  domain.verified,
  domain.check.returnPath,
  domain.check.dkim,
);
import os

from sendora import SendoraAccount

account = SendoraAccount(
    os.environ["SENDORA_ACCOUNT_TOKEN"]
)

domain = account.domains.verify(
    "0d7f6a1e-4c0b-4b7e-9d3c-2a1f5e8b9c01"
)

print(
    domain.verified,
    domain.check.return_path,
    domain.check.dkim,
)
Response (26 lines)
{
  "domainId": "0d7f6a1e-4c0b-4b7e-9d3c-2a1f5e8b9c01",
  "domain": "mail.example.se",
  "verified": true,
  "createdAt": "2026-09-15T12:00:00.000Z",
  "lastCheckedAt": "2026-09-15T12:10:00.000Z",
  "failingSince": null,
  "returnPath": {
    "type": "CNAME",
    "host": "sendora-bounces.mail.example.se",
    "value": "bounces.sendora.se",
    "verified": true,
    "verifiedAt": "2026-09-15T12:10:00.000Z"
  },
  "dkim": {
    "type": "TXT",
    "host": "sendora-a1b2c3d4._domainkey.mail.example.se",
    "value": "v=DKIM1; k=rsa; p=MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEA…",
    "verified": true,
    "verifiedAt": "2026-09-15T12:10:00.000Z"
  },
  "check": {
    "returnPath": "ok",
    "dkim": "ok"
  }
}

check says what each lookup found:

checkMeaning
okThe record is there with the right value.
missingThere is no record.
mismatchA record is there with another value.
dns_errorThe resolver got no trustworthy answer, for example because DNSSEC validation failed.

The domain is verified once both records have been seen.

When a record goes missing

A verified domain rides out DNS trouble rather than stopping at the first failed lookup:

  • A dns_error changes nothing. The resolver could not answer, which says nothing about your records, so the domain stays as it was.
  • A record found missing or mismatch starts a 24-hour warning. The domain stays verified and keeps sending, failingSince says when the warning began, Sendora looks the records up every hour, and your account’s administrators are mailed.
  • Any check that finds both records ends the warning.
  • A check 24 hours or more after failingSince that still misses a record ends the verification. Your administrators are mailed again, and mail from the domain is refused with from_domain_not_verified until both records are back. Once they are, the next check finds them within minutes.

A DNS move is the usual cause. Publish both records at the new provider before you switch, and the domain never enters its warning.

SPF, DKIM and DMARC

  • SPF is satisfied by the return-path domain, sendora-bounces.<your domain>, whose records Sendora keeps. It aligns with your domain under DMARC’s relaxed mode.
  • DKIM signs with your domain, through the key above, so it aligns strictly.
  • DMARC is your own record, _dmarc.<your domain>. Both signals align, so a policy of p=quarantine or p=reject is safe for mail sent through Sendora. Sendora does not create or change your DMARC record.

List and remove domains

GET /v1/domains
curl https://api.sendora.se/v1/domains \
  -H "Authorization: Bearer $SENDORA_ACCOUNT_TOKEN"
import { SendoraAccount } from '@sendora/sdk';

const account = new SendoraAccount({
  token: process.env.SENDORA_ACCOUNT_TOKEN,
});

const { domains } = await account.domains.list();

for (const domain of domains) {
  console.log(
    domain.domain,
    domain.verified ? 'verified' : 'waiting for DNS',
  );
}
import os

from sendora import SendoraAccount

account = SendoraAccount(
    os.environ["SENDORA_ACCOUNT_TOKEN"]
)

listed = account.domains.list()

for domain in listed.domains:
    if domain.verified:
        print(domain.domain, "verified")
    else:
        print(domain.domain, "waiting for DNS")
Response (26 lines)
{
  "domains": [
    {
      "domainId": "0d7f6a1e-4c0b-4b7e-9d3c-2a1f5e8b9c01",
      "domain": "mail.example.se",
      "verified": true,
      "createdAt": "2026-09-15T12:00:00.000Z",
      "lastCheckedAt": "2026-09-15T12:10:00.000Z",
      "failingSince": null,
      "returnPath": {
        "type": "CNAME",
        "host": "sendora-bounces.mail.example.se",
        "value": "bounces.sendora.se",
        "verified": true,
        "verifiedAt": "2026-09-15T12:10:00.000Z"
      },
      "dkim": {
        "type": "TXT",
        "host": "sendora-a1b2c3d4._domainkey.mail.example.se",
        "value": "v=DKIM1; k=rsa; p=MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEA…",
        "verified": true,
        "verifiedAt": "2026-09-15T12:10:00.000Z"
      }
    }
  ]
}

Removing a domain refuses mail from it at once and discards its key. Adding it again creates a new key and new records.