Sending domains and DNS
Verify your own domain for sending - the DKIM, SPF, and DMARC records to publish, and how to check verification status.
Every email you send has a from address, and orboto Mail only sends on
behalf of domains that are verified on your account. Verification is
what lets receiving mail servers (Gmail, Outlook, ...) confirm a message
claiming to be from you@yourdomain.example really was authorized by
that domain's owner - without it, transactional email either gets
rejected outright or lands in spam. This page explains what verification
means and walks through adding your own domain; see
Sending email for the specific
error a send returns when the from domain isn't ready yet.
If your app runs as an orboto SaaS workspace
Nothing to do here. An orboto SaaS workspace connected to orboto Mail
sends from the shared, operator-verified identity noreply@orboto.io -
DKIM, SPF, and DMARC are maintained centrally for that address, so mail
starts flowing the moment you connect with zero DNS work on your side.
See Using orboto Mail from an orboto workspace.
The rest of this page is for a custom domain - your own domain name,
used by a standalone application or a self-hosted orboto instance.
Add a custom domain
curl https://mail.orboto.io/api/v1/sender-domains \
-X POST \
-H "Authorization: Bearer oms_live_your_key_here" \
-H "Content-Type: application/json" \
-d '{ "domain": "yourdomain.example" }'The response includes everything you need to publish:
{
"id": "b7e6c1a0-...",
"domain": "yourdomain.example",
"dkimSelector": "orboto",
"verificationStatus": "pending",
"dkimRecords": [
{
"name": "orboto._domainkey.yourdomain.example",
"type": "TXT",
"value": "v=DKIM1; k=rsa; p=<base64-encoded public key>"
}
],
"spfRequired": "v=spf1 include:spf.orboto.io ~all",
"dmarcRecommended": "v=DMARC1; p=quarantine; rua=mailto:dmarc-reports@dmarc.orboto.io; ruf=mailto:dmarc-reports@dmarc.orboto.io; aspf=r; adkim=r",
"mailFromRecords": [
{ "name": "bounces.yourdomain.example", "type": "MX", "value": "feedback-smtp.eu-central-1.amazonses.com", "priority": 10 },
{ "name": "bounces.yourdomain.example", "type": "TXT", "value": "v=spf1 include:amazonses.com ~all" }
]
}orboto Mail generates a DKIM keypair for you (this is "BYODKIM" - Bring-Your-Own-DKIM: orboto Mail owns the key, you publish only the public half) and keeps the private key encrypted at rest. You never handle key material yourself.
The DNS records to publish
| Record | Type | Name | Value | Purpose |
|---|---|---|---|---|
| DKIM | TXT | orboto._domainkey.yourdomain.example | from dkimRecords[0].value above | Cryptographically signs every message so receivers can verify it wasn't altered in transit and really came from you. |
| SPF | TXT | yourdomain.example (root) | v=spf1 include:spf.orboto.io ~all | Authorizes orboto Mail's sending infrastructure to send as your domain. If you already have an SPF record for other mail (e.g. Google Workspace), add include:spf.orboto.io to the existing record rather than creating a second TXT record - a domain can only have one SPF record. |
| DMARC | TXT | _dmarc.yourdomain.example | from dmarcRecommended above | Tells receivers what to do with mail that fails SPF/DKIM, and where to send aggregate reports. Recommended, not required for verified status. |
| MAIL FROM (Return-Path) | MX | bounces.yourdomain.example | feedback-smtp.eu-central-1.amazonses.com (priority 10) | Points bounce handling at a subdomain you own instead of a shared AWS address, which is what makes SPF alignment (and therefore full DMARC pass) possible. |
| MAIL FROM (Return-Path) | TXT | bounces.yourdomain.example | v=spf1 include:amazonses.com ~all | SPF for the bounce subdomain above. |
Some DNS providers (notably Route 53 and other strict resolvers) reject
a single TXT value longer than 255 bytes. If a record in the API
response includes a valueChunks array alongside value, use the
chunks - each is a separate quoted string inside the same TXT record.
Providers like Cloudflare and Google Cloud DNS accept the long single
value directly and never need this.
If your domain is on Cloudflare, POST /v1/sender-domains/:id/cloudflare-auto-setup
(with a scoped Cloudflare API token in the body) creates every record
above for you automatically instead of pasting them by hand -
GET /v1/sender-domains/:id/cloudflare-detect tells you upfront whether
the domain is on Cloudflare at all. Both are also available as buttons
in the dashboard.
Verifying
DNS changes take time to propagate. Once the records are published, trigger a check:
curl https://mail.orboto.io/api/v1/sender-domains/b7e6c1a0-.../verify \
-X POST \
-H "Authorization: Bearer oms_live_your_key_here"verificationStatus moves through these states:
| Status | Meaning |
|---|---|
pending | Records not detected yet. Re-check after DNS propagation (a few minutes to a few hours, depending on your provider and TTLs). |
verified | DKIM confirmed. Sending from this domain now works. |
temporary-failure | A transient error on the verification side. Re-check again shortly - no action needed on your part. |
failed | Records were published, then removed or changed after the domain had verified. Sending is blocked until you republish and re-verify. |
Only verified domains can be used as the from address on a send -
see the from_domain_not_verified error on the
sending page.
Removing a domain
curl https://mail.orboto.io/api/v1/sender-domains/b7e6c1a0-... \
-X DELETE \
-H "Authorization: Bearer oms_live_your_key_here"This deregisters the sending identity on orboto Mail's side. It does not remove the DNS records from your provider - do that separately if you no longer want them published.
Troubleshooting
| Symptom | Fix |
|---|---|
Still pending after 24 hours | Double-check the DKIM TXT record's name and value were copied exactly - a trailing dot, wrong selector, or truncated value (see the valueChunks note above) is the usual cause. Some registrars also silently drop long TXT values without an error - try valueChunks even if you initially used value. |
verified, then dropped to failed | Something changed the DNS record after it verified - a provider migration, a DNS zone reset, or an accidental edit. Republish the exact record from a fresh GET /v1/sender-domains/:id call (don't reuse an old copy) and verify again. |
409 reserved_domain | The domain (or a subdomain of it) is reserved for orboto's own infrastructure and can't be claimed by a customer account. |
409 domain_already_added | The domain is already on your account - the error includes the existing domain's id; call /verify on that id instead of creating a new one. |
| I have an existing SPF record for other email (Google Workspace, etc.) | Don't add a second SPF TXT record - a domain can only have one. Merge include:spf.orboto.io into your existing SPF record's include: list instead. |
DMARC reports still show failures after verified | Confirm the MAIL FROM records were also published - DKIM alone gives DMARC pass, but full SPF alignment (used as failover if the primary region's DKIM check has a transient issue) needs the bounces.yourdomain.example MX + TXT pair too. |