HTTP API

A small API with a complete record.

Send over HTTP with idempotency keys and batches; every response correlates to a timeline, the archive, and webhooks.

POST /v1/send answers 202 with the mail's id before any provider is contacted. From there an API mail takes the same path as SMTP mail: rules, routing, failover, the timeline, and the archive, which keeps the JSON request Mailway accepted. The response is the start of the record, not the end of the send.

Sends can be scheduled up to 72 hours ahead, routed per request, and correlated end to end: the id in the response is the same id in the console, in webhook events, and on the public viewer. Full request and response shapes live in the API reference, and the machine-readable contract is the OpenAPI specification — generate a typed client from it, or hand it to your coding agent.

HTTP API

Just POST it

The same pipeline — failover, timeline, archive — behind one JSON endpoint, for stacks where SMTP is awkward. Send with a fetch(), get back the same mail ID you'll see in the console, the public viewer, and the webhooks.

Keys that say what they are

mw_test_… drives the sandbox, mw_live_… is production. No guessing which environment you just emailed.

Retries that can't double-send

Put an Idempotency-Key on the request and retry as hard as you like — a repeated key returns the original send instead of a duplicate.

Batch without the mystery

Up to 100 messages per request, answered with a 207 and a per-message status — you know exactly which ones made it.

Limits that negotiate

Hit the rate limiter and the 429 carries Retry-After; hit the daily cap and its 429 says it resets at 00:00 UTC; hit a quota and the 402 names which one in a machine-readable error code.

Read the HTTP API docs →

live on api.mailway.net · sandbox on api.mailway.dev

POST /v1/send
curl https://api.mailway.net/v1/send \
-H "Authorization: Bearer mw_live_…" \
-H "Idempotency-Key: invoice-2042-receipt" \
-d '{
"from": "billing@yourapp.com",
"to": "customer@gmail.com",
"subject": "Invoice #2042",
"html": "<h1>Paid…",
"routing": { "strategy": "fallback" }
}'
HTTP/2 202 · accepted
{
"id": "m.01k8w9x3qf7r2tn5vbhc4jm6pd",
"status": "queued",
"paused": false,
"routing": { "provider": null, "strategy": "fallback" }
…
}
Developers

No SDK.
That's a feature.

It's standard SMTP — Nodemailer, smtplib, Laravel's mailer, ActionMailer and net/smtp already speak it fluently. Nothing to install today, nothing to rip out later. Prefer HTTP? The HTTP API comes with bearer auth, idempotency keys, and batch send.

  • Change one config block. Ship. That was the migration.
  • TLS on every connection — STARTTLS and implicit TLS.
  • Staging that can't email your customers — point it at smtp.mailway.dev and everything is captured, nothing is delivered until you explicitly release it.
All 7 SMTP ports open — more than any provider in the matrix below
:25:587:465:2525:2587:2465:588

GCP blocks port 25 outright. DigitalOcean blocks 25, 465 and 587 outbound. The alternate ports mean your app sends from wherever it happens to run.

Read the SMTP relay docs →
// Nodemailer — zero changes to your send logic
const transporter = nodemailer.createTransport({
host: "smtp.mailway.net",
port: 587,
auth: {
user: process.env.MAILWAY_USER,
pass: process.env.MAILWAY_PASS,
},
});

Your mailer config has
one block to change

Mailway is in private beta, and we onboard teams one at a time. Leave your email and we'll send your invite when it's your turn.

read the docs meanwhile →

join the waitlist — mailway.net

Your invite, one email away.

Mailway is in private beta, and we onboard teams one at a time. Leave your email and your invite arrives when it's your turn.