Domains and suppressions
Domains
A space sends only from domains it has verified through DNS. Set up your domain explains each record.
The domain object
{
"id": "6e7f8a9b-0c1d-4e2f-3a4b-5c6d7e8f9a0b",
"domain": "acme.com",
"status": "VERIFIED",
"checks": { "dkim": "OK", "mailFrom": "OK", "dmarc": "OK", "tracking": "OK" },
"records": [
{ "purpose": "DKIM", "type": "CNAME", "name": "abc123._domainkey.acme.com", "value": "abc123.dkim.amazonses.com", "priority": null, "status": "OK", "optional": false },
{ "purpose": "DKIM", "type": "CNAME", "name": "def456._domainkey.acme.com", "value": "def456.dkim.amazonses.com", "priority": null, "status": "OK", "optional": false },
{ "purpose": "DKIM", "type": "CNAME", "name": "ghi789._domainkey.acme.com", "value": "ghi789.dkim.amazonses.com", "priority": null, "status": "OK", "optional": false },
{ "purpose": "MAIL_FROM", "type": "MX", "name": "bounce.acme.com", "value": "feedback-smtp.eu-west-3.amazonses.com", "priority": 10, "status": "OK", "optional": false },
{ "purpose": "MAIL_FROM", "type": "TXT", "name": "bounce.acme.com", "value": "v=spf1 include:amazonses.com ~all", "priority": null, "status": "OK", "optional": false },
{ "purpose": "DMARC", "type": "TXT", "name": "_dmarc.acme.com", "value": "v=DMARC1; p=none;", "priority": null, "status": "OK", "optional": false },
{ "purpose": "TRACKING", "type": "CNAME", "name": "link.acme.com", "value": "track.kulamail.com", "priority": null, "status": "OK", "optional": false },
{ "purpose": "GOOGLE_POSTMASTER", "type": "TXT", "name": "acme.com", "value": "…", "priority": null, "status": "PENDING", "optional": true }
],
"trackingDomain": "link.acme.com",
"mailFromDomain": "bounce.acme.com",
"verifiedAt": "2026-10-17T09:42:00Z",
"lastCheckedAt": "2026-10-17T09:42:00Z",
"nextCheckAt": "2026-10-18T09:42:00Z",
"lastError": null,
"ramp": { "stage": 0, "dailyCap": 1050, "sentToday": 0, "uncapped": false },
"postmasterStatus": "PENDING",
"postmasterError": null,
"createdAt": "2026-10-17T09:30:00Z"
}
| Field | Meaning |
|---|---|
status | PENDING (checks in progress), VERIFIED (all four checks pass: the domain can send), FAILED (checks gave up after 7 days; verify again once fixed) |
checks | Each check is PENDING, OK or FAILED |
records | What to publish at your DNS provider. name is fully qualified. The optional GOOGLE_POSTMASTER record lets Kula read Gmail's spam rate and never blocks sending |
ramp | The warm-up: today's marketing cap for this domain and how much of it is used |
List domains
GET /v1/domains
Every domain of the space, oldest first.
Add a domain
POST /v1/domains
Adds a domain and returns the records to publish.
acme.com or mail.acme.com. Public mailbox domains (gmail.com, outlook.com…) are refused.curl https://api.kulamail.com/v1/domains \
-H "Authorization: Bearer ml_your_api_key" \
-H "Content-Type: application/json" \
-d '{ "domain": "acme.com" }'
Returns 201 with the domain object, status: "PENDING".
| Status | Code | When |
|---|---|---|
| 400 | invalid_domain | Not a valid domain name |
| 400 | public_mailbox_domain | A public mailbox provider such as gmail.com |
| 409 | domain_taken | The domain is already added to this space or used by another one |
Kula checks the records automatically: every 15 minutes for the first 3 hours, then hourly for a day, then every 6 hours up to 7 days. A verified domain is checked again every day; if a record disappears, sending from it stops until it is back.
Get a domain
GET /v1/domains/{id}
Verify a domain
POST /v1/domains/{id}/verify
Checks the records now, for example right after publishing them. Returns the domain with the result.
curl -X POST https://api.kulamail.com/v1/domains/6e7f8a9b-0c1d-4e2f-3a4b-5c6d7e8f9a0b/verify \
-H "Authorization: Bearer ml_your_api_key"
Delete a domain
DELETE /v1/domains/{id}
Answers 204. Emails can no longer be sent from this domain.
Suppressions
Addresses Kula won't email. Bounces and suppressions explained.
| Reason | Added when | Blocks |
|---|---|---|
HARD_BOUNCE | The address does not exist | Every email, from every space (global: true). Cannot be removed |
SOFT_BOUNCE | 3 failed deliveries in a row | Marketing from this space |
COMPLAINT | The person marked an email as spam | Marketing from this space |
MANUAL | You added it | Marketing from this space |
Sending a transactional email to a suppressed address answers status: "SUPPRESSED" and sends nothing.
The suppression object
{
"id": "8a9b0c1d-2e3f-4a5b-6c7d-8e9f0a1b2c3d",
"email": "old-address@example.com",
"reason": "HARD_BOUNCE",
"detail": "550 5.1.1 The email account that you tried to reach does not exist",
"global": true,
"sourceMessageId": "8f6c2a1e-3b4d-4e5f-9a0b-1c2d3e4f5a6b",
"createdAt": "2026-10-12T16:20:00Z"
}
List suppressions
GET /v1/suppressions
Newest first.
0.{
"items": [ { "id": "8a9b0c1d-…", "email": "old-address@example.com", "reason": "HARD_BOUNCE", "…": "…" } ],
"page": 0,
"size": 50,
"total": 37
}
Suppress an address
POST /v1/suppressions
Adds a MANUAL suppression: the address receives no more marketing from this space, for example after an opt-out received outside Kula.
curl https://api.kulamail.com/v1/suppressions \
-H "Authorization: Bearer ml_your_api_key" \
-H "Content-Type: application/json" \
-d '{ "email": "ada@example.com" }'
Returns 201 with the suppression object.
Remove a suppression
DELETE /v1/suppressions/{id}
Answers 204. A global hard bounce cannot be removed. Remove a complaint only if the person explicitly asked to receive your emails again.