Receipts, codes and resets

The mail your product sends
from the call to the outcome

Your app posts a message and OpenEmail sends it from your own domain. Every call sits against the key that made it, and every send has an outcome to read.

Your code
templateorder-receipt
idempotency-keyorder_10482
202msg_9f2c7a14Sent once
Your endpointhooks.acme.dev
email.sentmsg_9f2c7a14
email.deliveredmsg_9f2c7a14
email.openedmsg_9f2c7a14

The call answers with a message id. Every event your endpoint hears carries that same id.

Where it starts

What this looks like today.

The mail comes out of your code

Receipts, sign-up codes and password resets are sent by your backend, not typed by a person.

After the send, nothing comes back

A customer says the code never arrived, and there is no delivery record to check it against.

One shared key, no call record

Every service sends with the same secret, and nothing shows which call failed or when.

How it works

Running in four steps.

  1. 01

    Verify your domain

    Publish the records shown in settings, and the domain turns green once they line up.

  2. 02

    Issue a scoped key

    Limit the key to the addresses and domains it may send from, and cap what it can reach with a role.

  3. 03

    Post the message

    One call names the template, its values and the recipient, and a retry cannot send it twice.

  4. 04

    Take the webhook, read the log

    Your endpoint hears every event by message id, and the log shows delivered, bounced or failed.

What it runs on

The parts doing the work.

It runs on a documented API with scopable keys, a typed SDK, webhooks to your endpoint, versioned templates, and the records that stand behind your sending domain.

REST API

A documented HTTP API with issuable, scopable, revocable keys.

/threads?query=invoice
{ "threads": 12 }
Same mailbox, whether a person or a program is holding it.
Typed SDKs

A TypeScript client first, then the rest.

/threads?query=invoice
{ "threads": 12 }
Same mailbox, whether a person or a program is holding it.
Webhooks

Tell your endpoint when mail arrives, instead of making you poll.

/threads?query=invoice
{ "threads": 12 }
Same mailbox, whether a person or a program is holding it.
Templates

A body written once, versioned, and sent many times: from the composer, from your own code, or by an agent.

IntroInvoiceFollow-up
Hi Sarah, good to meet you at
Verified sender

A mark beside the sender when the sending domain’s published records line up.

receipts@stripe.com
SPFDKIMDMARC
verified sender
DMARC policy

A starter p=none record, printed to copy or written by a sync, never tightened for you.

TXT_dmarc.acme.com

v=DMARC1; p=none; rua=…

Optionalwatch only
Tracking on your own domain

Tracked links and the open pixel on a subdomain you choose, such as links.yourdomain.com, instead of the OpenEmail address.

See when mail you sent was opened

Whether a message you sent has been opened, when, how many times and which of its links were followed. On unless you turn it off, and plain about the readings it cannot get.

In practice

Every piece, walked through.

Four shorter pages walk the route: sending from your code, reading the call log, what happened after the send, and mail inside a test run, which is still to come.

Mail from your app

Send receipts, codes and resets from your own code, and hear back when they land.

templateorder-receipt
202msg_9f2c7a14
email.sentmsg_9f2c7a14
email.deliveredmsg_9f2c7a14
email.openedmsg_9f2c7a14
Watch your integration

Every call a key made, every webhook you sent, with the code and the timing.

oe_live_7f20Rotated
GET/emails20061 ms
POST/emails429send_quota_exceeded
Test your signup mail
Soon

Give each test run its own address and read the mail it receives.

signup-02@acme.com
Confirm your email730915
signup-01@acme.com418204
signup-02@acme.com730915
Watch what happens after send

See what happened to every send, and keep dead addresses out of the next one.

Delivered129
Bounced3
Blocked[email protected]Held back

Questions

Asked before signing up.

What stops a retry sending the same email twice?

One call names the template, its values and the recipient, and a retry of it cannot send twice. The call answers with a message id, and every event your endpoint hears carries that same id.

Can I see what happened after the send?

Yes. Each send reads as delivered, bounced, complained or failed, by day, source and sending address, and the request log holds the method, path, status code and duration for every call a key made.

Is there an SDK for my language?

Not yet, in most cases. The typed client is TypeScript first and the others follow, so for now every other language calls the documented HTTP API directly.

Nearby

Other jobs for the same mailbox.

Your product gets the mail

Every ticket, record or customer can have its own address. Mail sent there reaches your endpoint as a signed event, and your code answers as that address.

Ticket 8123ticket-8123@in.yourapp.com
Ticket 8124ticket-8124@in.yourapp.com
Toticket-8123@in.yourapp.com
Fromticket-8123@in.yourapp.comSame address
Hand the inbox to software

Give an agent an address of its own and a key scoped to what it may do. It reads, labels, drafts and sends, and every call it makes is logged.

listThreadsgetThreadsearchMailsendEmail
Everything you send

Write it once as a template. Send it from the composer, from your own code or on a day you pick, then read what happened after.

Hi{{firstName}}Omar
Read the update
130Sent42Opened9Clicked

Your inbox,
on your own terms.

Email infrastructure for businesses, AI, agents and personal email. Built for scale, privacy and control. Everything email should have had from day one.

OpenEmail

Email infrastructure for businesses, AI, agents and personal email. Built for scale, privacy and control. Everything email should have had from day one.

© 2026 OpenEmail. All rights reserved.