quickstart
Send your first email in three steps: verify a domain, create an API key, send.
1 · add and verify your domain
In the dashboard, add your domain. You get exactly two CNAME records to publish — no MX changes, no SPF edits, nothing vendor-specific. Once DNS propagates, hit verify (we also re-check automatically every 10 minutes).
2 · create an API key
Create a key with sending_access scope for your app. It's shown once — store it as an environment variable.
3 · send
curl -X POST https://app.mailway.prevue.click/api/emails \
-H "Authorization: Bearer mw_..." \
-H "Content-Type: application/json" \
-d '{
"from": "You <hello@yourdomain.com>",
"to": ["someone@example.com"],
"subject": "hello from mailway",
"html": "<p>it works!</p>",
"text": "it works!"
}'Node (any fetch-capable runtime):
const res = await fetch("https://app.mailway.prevue.click/api/emails", {
method: "POST",
headers: {
Authorization: `Bearer ${process.env.MAILWAY_API_KEY}`,
"Content-Type": "application/json",
},
body: JSON.stringify({
from: "You <hello@yourdomain.com>",
to: ["someone@example.com"],
subject: "hello from mailway",
html: "<p>it works!</p>",
}),
});
const { id } = await res.json(); // poll GET /emails/{id} for the timelinetest without a real inbox
Send to delivered@simulator.mailway.dev, bounced@simulator.mailway.dev or complained@simulator.mailway.dev — delivery, bounce and complaint flows run end to end (including suppressions and webhooks) without touching a real mailbox.
idempotency
Pass an Idempotency-Key header on sends. Same key + same body within 24h returns the original response; same key + different body returns a 409. Safe to retry, safe for agents.
scheduling
{ "scheduled_at": "2026-09-01T09:00:00Z", ... } // cancel via POST /emails/{id}/cancel