Introduction

mailstein sends email: transactional messages from your application, and broadcasts to a list. It also receives email, so replies land somewhere you can read and answer.

There are four ways in, and they all reach the same API:

HTTP https://app.mailstein.com/api/v1
TypeScript npm install mailstein
Python pip install mailstein
CLI npx -y mailstein-cli

Send your first email

Three things have to be true before mail leaves the building: you have an API key, you have a domain, and the domain's DNS records are published. The quickstart does all three in order.

curl -X POST https://app.mailstein.com/api/v1/emails \
  -H "Authorization: Bearer $MAILSTEIN_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{
    "from": "hello@yourdomain.com",
    "to": "someone@example.com",
    "subject": "Hello",
    "html": "<p>It works.</p>"
  }'

What is here

Authentication — keys, and what each kind can do.

Errors, pagination, rate limits and idempotency — the four things every integration hits, and the four worth reading before you write any code.

Domains — DNS, verification, and why mail from an unverified domain does not arrive.

Templates and broadcasts — reusable bodies, and sending to a list rather than a person.

Suppressions — who mailstein refuses to email on your behalf, and why that is a feature.

Webhooks — being told what happened, and verifying that it was us who told you.

API reference — every endpoint, generated from the running API.

A note on this documentation

The reference is generated from the same OpenAPI description the server publishes, so it cannot drift from what is deployed. The specification is at /openapi.json if you would rather point your own tooling at it.

Where something is not built yet, this documentation says so rather than describing it in the future tense.

Something here wrong or missing? It is generated from the running API — tell us and we will fix the source.