Quickstart
From nothing to a delivered email.
Three things have to be true before a message can go out: a verified sending domain, an API key with the right scope, and a recipient who isn't suppressed. This page walks through the first two.
1. Verify a sending domain
Use a subdomain per purpose: mail.example.com for transactional mail, news.example.com for campaigns. Mailbox providers score reputation per domain, so keeping them apart is what stops a campaign's complaint rate affecting password reset delivery.
Two records are optional and marked optional: true: an MX on the subdomain so replies arrive in Conversations, and a link. CNAME for click tracking. Publish the CNAME and, once its certificate is issued, links in mail from that subdomain are rewritten to link.mail.example.com/c/…, a click is recorded, and the recipient is redirected. Links stay on your name throughout; nothing goes through a SendRaven domain. A bare URL in the text is turned into a link first, so it is tracked too. Add data-track="off" to an anchor to leave one link alone.
Adding a domain returns the DNS records to publish. GET /v1/domains then shows each record beside what is resolving now, so a stuck verification tells you which record is missing rather than just failing.
The bounce subdomain is verified by SES separately, and later. mail_from.status is pending while SES polls the MX record, which can take up to 72 hours after the record appears; active once the Return-Path is on your domain. A domain is verified and sends fine before then. The Return-Path is amazonses.com meanwhile, so SPF aligns with Amazon rather than you, and DMARC passes on DKIM. If SES gave up before the MX existed the status is failed, and the next check restarts verification once the record resolves.
2. Send
Always pass an Idempotency-Key, a new one for each message. If the request times out, retrying with the same key and the same body returns the original result instead of delivering a second copy, which matters more here than in most APIs, because the duplicate lands in someone's inbox. A retry that arrives while the first request is still running waits up to 8 seconds for the first to finish and then returns its response (or, if the first failed, runs itself); only if the first is still running after that does it answer 409 idempotency_in_progress; wait a moment and retry again. Reusing a key with a different body answers 422 idempotency_key_reused and sends nothing.
3. Watch what happened
GET /v1/emails/{id} returns the message with its full event timeline: send, delivery, bounce, complaint, open, click. This is the call to reach for when someone asks why an email didn't arrive.
Runnable examples
CommonNinja/sendraven-examples has the whole round trip as code you can run: send, list threads awaiting a reply, read one, reply in the same thread and verify signed webhooks, in Node and Python. It also has a support inbox triaged by Claude over the MCP server with every reply held for approval, and an OpenAI Agents follow-up agent. Each one was run against the production API before it was published, and each README shows that run's output.