Reply in-thread
One call sets From, To, the
Re: subject, and the threading headers for you.Webhooks
Subscribe to
inbound_received to be pushed every arriving message instead of polling.Enable receiving on a domain
Receiving is opt-in per domain. Flip it on with a single PATCH; the response carries the MX record you need to publish. The domain must already be added to your account and verified for sending.PATCH /v1/domains/{id}/receiving
verified stays false and real mail will not route to you — but simulation works regardless.
200 OK
Publish the one MX record
Add a singleMX record at your domain’s apex (or the subdomain you want to receive on), pointing at Drin’s inbound host at priority 10. That is the whole DNS change — there is no second record and nothing to rotate. In the dashboard, DNS hosts that support Domain Connect can write this MX record for you after you enable receiving.
DNS record
GET /v1/domains/{id}/receiving (or drin.domains.getReceiving(id)) — once the record resolves, verified flips to true.
Create an inbox address
A domain can route to many addresses. Create an inbox for each one you want to receive at —support@, billing@, or a dedicated address for an agent. Only mail addressed to an inbox you own is accepted; everything else is rejected at ingest.
POST /v1/inboxes
201 Created
drin.inboxes.list(), or narrow to one domain with drin.inboxes.listByDomain(domainId). Deleting an inbox is refused with 409 conflict while it still holds messages, so the audit trail can’t be erased.
Read the conversation as a thread
A thread is the unit you read from. Drin groups every message that belongs to the same conversation — both directions — and orders them oldest to newest. An inbound question and the outbound answer you sent back live in one list, so an app or an agent sees the full exchange without stitching events together.GET /v1/threads
GET /v1/threads returns a page of thread summaries ({ data, nextCursor }). Pass inboxId to scope the feed to one receive address, or omit it for every inbox. To read the messages, fetch one thread by id:
GET /v1/threads/{id}
GET /v1/threads/{id}
direction (inbound / outbound), status, addresses, occurredAt timestamp, and repliesToMessageId when it was sent as a reply. Fetch the rendered body or parsed attachments of any message with GET /v1/emails/{id}/body and /attachments.
Get pushed every arrival: inbound_received
Polling threads is fine for a cron loop, but the responsive path is a webhook. Subscribe to theinbound_received event and Drin POSTs you a signed payload the moment a message lands — with the new message id and thread id so you can fetch the conversation and reply.
inbound_received delivery
Always verify the signature. Every delivery is signed with a
Drin-Signature header. Verify it before trusting the body — the SDK does it in one call. See the webhooks guide for the scheme and drin.webhooks.verify().Test the whole loop with zero DNS [#simulate]
You shouldn’t have to send a real email from Gmail to test your inbound integration.POST /v1/inbound/simulate synthesizes a delivery to one of your inboxes, runs the full ingest pipeline, threads it, and fires your webhook — exactly like a real arrival. The persisted row is flagged test_mode, so it is excluded from metrics, quotas, and billing, and it works even before your MX record resolves.
POST /v1/inbound/simulate
to must resolve to an inbox you own. Supply html, text, or both — the response returns the synthesized message id, its thread, and the ids of the webhook deliveries it triggered, so a test can assert your endpoint actually received the event.
202 Accepted
Create a test inbox
POST /v1/inboxes for an address like support@yourdomain.com. No DNS required for simulation.Fire a synthetic delivery
POST /v1/inbound/simulate — your endpoint receives a signed, test_mode event identical in shape to a real one.Reply in one call
Threading headers, From, To, and the
Re: subject are all derived from the parent message — see how.