Architecture

How it's built, and how it fails.

Putting a gateway in front of your email providers adds a hop to a path that matters. This page is the due-diligence answer to that decision: where a message becomes durable, what each failure looks like from your side, where the data boundaries run, and how you leave. It says what is true today — where a claim ends, the page says so.

The path of a message

Your application speaks one of two protocols to Mailway: SMTP (seven ports, TLS required on every one — implicit on 465 and 2465, STARTTLS before login on the rest) or the HTTPS send API. Either way, one rule holds: Mailway never acknowledges a message it hasn't written down. Over SMTP, the 250 reply goes out once the message is written to the ingest node's disk and flushed there (fsync), so it is on the disk itself, not in a memory buffer. Normally within seconds (longer during a burst), it becomes a database record and an object in EU storage. Over the API, the record and the request body are committed to the database before the 202 Accepted returns; the body is archived to object storage once the send runs. If the ingest node cannot write your message down, you get a 451 and the message stays yours.

From there: rules you've defined run against the message, the routing engine picks a provider from the accounts you attached, and a failed attempt moves down your chain — to a provider this message hasn't tried yet five seconds later, to one it has on a widening backoff. What the providers report back — acceptance from every provider; delivery, bounce and complaint from the ones that send delivery events (every supported provider except Gmail and Any SMTP server) — lands on the message's timeline and, if you want it, on your own endpoint as a signed webhook.

your sidemailway · one eu regionyour providers · byokyour appsmtp · httpstlsingress7 smtp portshttps apiingest queue① written ✓② ack · 250 / 202the ack leaves only after the write③ recorded, normally within secondsobject storagecontent · s3 frankfurtdatabaseindex · falkensteinrules · routerpause · tagpick providerprovider 1attempt 1 · 535 ✕provider 3standing by5 sprovider 2attempt 2 · accepted ✓recipientthe last hopdelivery eventsdelivered · bouncedcomplainedall but gmail & smtpthe timelineevery provider attemptyour endpointhmac-signedevidence flows back — signed, at-least-once

① the write, ② the acknowledgment — in that order, always; ③ the two boxes beneath the checkpoint are where the record settles, normally within seconds (over the API, the database record comes before the acknowledgment and the archive after the send). The dashed lane is the evidence path: what your providers report flows onto the message's timeline and, signed, to your endpoint. This page is about what happens when a step of this picture breaks.

Does the gateway become another single point of failure?

Honest framing first: yes, a gateway is a new hop, and a new hop is a new thing that can fail. The design answer isn't to pretend otherwise — it's to make every failure loud, lossless, and cheap to route around.

Nothing is acknowledged before it's written down. If the ingest node cannot write your message to disk, you don't get a 250 — you get a 451 while the message is still yours. For SMTP that means a retry on your side. A mail server keeps the message in its own queue and retries, as SMTP was designed to behave. An app library such as nodemailer, PHPMailer, or Symfony Mailer reports an error instead, so the retry has to come from your code, for example from a job queue with retries. For the API it means a non-2xx and a retry on your side — idempotency keys make those retries safe, so an ambiguous timeout can't become a duplicate send.

The same care on the provider side. A lock lets only one worker send a given mail at a time. If an attempt's answer is lost between Mailway's own servers, Mailway asks for that answer again instead of sending again. If it is lost at the provider (the connection drops or times out after the message went out, or the worker sending it stops), nobody can tell whether the provider took the mail. Mailway records the attempt as unknown and, 5 s later, tries a provider the mail hasn't tried yet; if every provider has been tried, it waits and tries again. That is one of two cases where a recipient can get the mail twice. The other is a send with more recipients than the provider takes in one message (50 on Amazon SES): Mailway sends it in batches, and if one batch fails, the retry sends every batch again. Mailway chooses a possible duplicate over a missing mail, and the mail's timeline shows every attempt.

Where that claim ends. Between the acknowledgment and the database record, an SMTP message lives on one machine's disk — normally for under a second, longer during a burst. Because it is flushed to that disk before the 250, a crash or a power cut loses nothing acknowledged, and if a later step is down, the mail waits on disk and moves on when that step is back. That disk isn't backed up: a disk lost in that window would lose what was on it, and only that. If the disk spool is ever off, the relay falls back to a queue held in memory and written to disk every second, and Mailway's monitoring raises an alert. Once the record exists, every hand-off is retried, and a sweep every five minutes re-queues anything that stalls between hops and reports what it cannot recover. It never invents a record.

If Mailway is unreachable, nothing is silently lost. A message that never got its acknowledgment was never Mailway's: it is still with your app. A mail server, or a job queue with retries, tries it again on its own, so the outage only delays it. An app that sends inline gets an error, and the mail is lost unless your code tries again. Either way, the failure shows on your side the moment it starts. status.mailway.net shows whether Mailway is up right now; an independent monitoring service runs the checks.

Accepted mail rides out provider failures. Once a message is stored, a provider outage triggers the failover chain: the error is classified (a provider-side failure is not a bad address: a permanent reject on a single-recipient send ends the attempts instead of trying the next door, and the hard bounces and complaints your provider reports back put the address on the suppression list), attempts walk your chain with retries, and a message that exhausts every option is stamped with an explicit exhausted state you can see and act on in the console. There is no state where mail sits invisible.

One region, said plainly. Mailway runs on its own virtual servers in one EU region today — Hetzner Cloud, Falkenstein, Germany. There is no multi-region failover claim on this page because there is no multi-region failover — when that exists, it will be written here, and not before.

Durability & recovery

Two stores carry your mail. Message content lives in object storage in the EU (AWS S3, Frankfurt), replicated across facilities by the storage layer itself. The metadata and index — what the console searches, what the timeline renders — live in a MySQL database on Mailway's own server in Falkenstein, Germany. For SMTP mail both are written normally within seconds of the acknowledgment; over the API the database record comes first and the archive follows the send.

The database ships nightly encrypted backups off the primary machine, with binary logs retained between snapshots for point-in-time recovery. Restores are rehearsed, not assumed — a backup that has never been restored is a hope, not a plan.

Deletion is policy, never accident: retention follows your plan, expiry runs on schedule, and what your plan retains stays readable for as long as it says.

Failure semantics, surface by surface

SMTP submission fails
A temporary failure returns a 4xx. A mail server requeues the message and retries on its own schedule; an app library reports an error, so your code has to retry (see retrying after a 451). Permanent rejections (bad auth, malformed message) return 5xx with a specific code. Nothing that wasn't acknowledged is Mailway's to lose.
API submission fails
Non-2xx with one documented error envelope — branch on error.code. Retrying a single send with the same Idempotency-Key returns the original send, never a duplicate; throttling responses carry Retry-After. The whole contract is machine-readable at /openapi.yaml.
A provider attempt fails
The error is classified before anything is retried: provider-side failures walk the failover chain; a permanent reject on a single-recipient send stops instead of trying the next provider, and the bounces and complaints providers report back go to the suppression list. Every provider attempt — including the failed ones — is on the message's timeline.
Everything fails
A message that spends every retry on every eligible provider is stamped exhausted — a visible verdict with a retry action, not a mail quietly stuck in "pending".
Your webhook endpoint is down
Deliveries are at-least-once with a backoff ladder (six attempts over roughly nine hours); an endpoint that keeps failing for 24 hours is disabled rather than hammered, and you re-enable it when it's healthy. Dedupe keys are documented.
The recipient's server is the problem
Provider-accepted is not delivered, and Mailway never blurs the two. Recipient-side outcomes surface as delivery events where the provider reports them (every supported provider except Gmail and Any SMTP server); where a provider doesn't, the timeline says "accepted" and stops — it never rounds up.

Trust boundaries

Mailway ingests, processes, and stores your mail in its EU region. The onward path follows the providers you connect — a message handed to your US provider account goes where your provider takes it; that choice stays yours, stated plainly rather than hidden behind an EU badge.

BYOK means the boundaries stay clean: your provider credentials are stored encrypted, scoped to your team, and used only to send what you configured. Your mail never rides a shared Mailway sending account, and your DNS — SPF, DKIM, DMARC — lives at your provider, untouched. Mailway is not in your authentication path, which is half of why leaving is cheap (next section). Sub-processors, encryption specifics, and the disclosure policy live on the trust page.

If you leave

Rollback is a first-class scenario, not a fine-print one. Because the provider accounts are yours, reverting to a direct provider connection over SMTP is the same kind of change that adopting Mailway was: one mailer configuration block — host, port, credentials. An app on Mailway's HTTP API has to call its provider's own API again, because Mailway's send endpoint has its own request format. There is no DNS to migrate and no reputation to rebuild. Your archived mail stays readable for its retention window, with raw source downloadable per message; a bulk export of a whole project doesn't exist yet.

What this page doesn't claim

No multi-region high availability — one EU region today. No delivery guarantees: delivery is decided by the recipient's server. No inbox-placement promises — evidence, not assurances. If a sentence on this page stops being true, the sentence changes; that's the maintenance contract this page ships with.

See the failure story moving in the interactive demo, put a real message through in the five-minute quickstart, or go deeper on trust & security. Questions a page can't answer: ask us directly.

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.