Point your MX records at MXcatch and every message sent to your domain arrives at your endpoint as signed JSON — parsed, decoded, and with attachments already extracted.
Receiving email programmatically has three well-worn options, and all of them cost more than they first appear.
Running your own SMTP server means owning spam filtering, TLS, greylisting, MIME parsing and the operational reality of a service that anyone on the internet can connect to. It is a genuinely hard surface to keep healthy, and it is rarely the problem you set out to solve.
Polling IMAP is the shortcut most people take. It works until it doesn't: you inherit connection limits, flaky mailbox state, races between workers marking messages as read, and a latency floor set by your polling interval. Debugging "why did this message get processed twice" at 2am is a rite of passage nobody needs.
Zapier or Make gets you moving in an afternoon and then meters you per task. Fine for a hundred messages a month; painful at ten thousand, and you are still one vendor away from your own data.
MXcatch is the SMTP server. It accepts the connection, handles TLS, parses the MIME tree, decodes the subject and body, extracts attachments to object storage, and then makes one HTTPS POST to you with the result.
Your side of the contract is a single endpoint that verifies a signature and returns 200.
// X-MXcatch-Signature: sha256=a1b2c3... { "event": "email.received", "id": 48213, "received_at": "2026-08-29T09:14:02+00:00", "from": { "address": "notify@stripe.com", "name": "Stripe" }, "to": "billing@acme.com", "subject": "Invoice paid", "text": "Your subscription has been renewed.", "attachments": [{ "name": "receipt.pdf", "size": 49152, "sha256": "9f8e7d...", "url": "https://ams3.digitaloceanspaces..." }] }
$raw = file_get_contents('php://input');
$expected = 'sha256=' . hash_hmac('sha256', $raw, $secret);
if (! hash_equals($expected, $_SERVER['HTTP_X_MXCATCH_SIGNATURE'] ?? '')) {
http_response_code(401);
exit;
}
Node and Python equivalents are in the webhook reference, along with the full field-by-field schema.
support@ becomes a ticket, with the Message-ID and threading headers available in headers for reply matching.Deliveries are at-least-once. A 2xx acknowledges; anything else — including a timeout — schedules a retry, five attempts over roughly 45 minutes with widening gaps.
Because a response can be lost after your side has already committed, key your processing on the id field, which is stable across retries of the same message. And acknowledge fast: do the real work in a background job rather than holding the request open, or you will collect retries for messages you have already handled.
If you are currently on Cloudflare Email Routing, webhooks mean writing and maintaining a Worker. On Mailgun Routes you get a webhook, but as multipart form fields on a plan priced for outbound sending you may not need. ImprovMX forwards mail but does not do webhooks at all.
X-MXcatch-Signature header: an HMAC-SHA256 of the raw body, keyed with your secret. Verification is a few lines in any language — see the webhook reference.to field.Free forever for one domain. No card, no trial clock.
Create your free account