Account
More ways to use this page
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.
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 fromsendora-bouncesto.<your domain> bounces. Bounce reports and feedback-loop reports for your mail arrive there and become events on your messages..sendora .se dkim: a TXT record under<selector>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.._domainkey .<your domain>
The domain may also be a subdomain, such as mail, which keeps the records away from the rest of your zone. The From address must use a verified domain exactly: verifying mail does not cover example or news.
Adding a domain the account already has fails with domain_, 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:
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:
check | Meaning |
|---|---|
ok | The record is there with the right value. |
missing | There is no record. |
mismatch | A record is there with another value. |
dns_ | The 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_changes nothing. The resolver could not answer, which says nothing about your records, so the domain stays as it was.error - A record found
missingormismatchstarts a 24-hour warning. The domain staysverifiedand keeps sending,failingSincesays 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
failingSincethat still misses a record ends the verification. Your administrators are mailed again, and mail from the domain is refused withfrom_until both records are back. Once they are, the next check finds them within minutes.domain_ not_ verified
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, whose records Sendora keeps. It aligns with your domain under DMARC’s relaxed mode..<your domain> - DKIM signs with your domain, through the key above, so it aligns strictly.
- DMARC is your own record,
_dmarc. Both signals align, so a policy of.<your domain> p=quarantineorp=rejectis safe for mail sent through Sendora. Sendora does not create or change your DMARC record.
List and remove 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.