You want email to trigger your backend. Someone forwards a lead, an invoice, or a support ticket, and your API picks it up as clean JSON. Simple to describe; surprisingly painful to ship from scratch.
This guide covers the two real paths to get there:
- The hand-rolled path — wire up an inbound email provider (SES, Postmark, Mailgun, Resend), write a parser, deal with retries and format drift yourself.
- The shortcut — use a dedicated email-to-API service that handles all of that and gives you JSON-to-webhook in a few minutes.
Both are valid. Here's what each one actually requires.
The hand-rolled path
Roughly six things you'll need to build:
1. Receive the email
You need an inbound email provider that converts incoming SMTP traffic into webhooks. The big ones:
- AWS SES Inbound — cheapest at scale, gnarliest to set up (MX records → SES rules → S3 or Lambda → your API).
- Postmark Inbound — clean dev experience, parsed JSON webhook out of the box, modest pricing.
- Mailgun Routes — mature, dev-friendly, well-documented.
- Resend Receiving — newest entrant, simple API, integrated with their sending side.
- SendGrid Inbound Parse — works, dated dashboard.
You'll set up MX records on a subdomain (e.g. in.yourapp.com), point them at the provider, configure a webhook URL on your backend, and verify their signature on each request.
2. Verify the webhook signature
Don't skip this. Every provider signs their webhooks; if you don't verify the signature, anyone who knows your webhook URL can POST fake "emails" to your API. Each provider has its own scheme (HMAC with a shared secret, usually).
3. Pull the email body
Most providers send the parsed body in the webhook payload. Some (like Resend Receiving) send a small event and you fetch the full message by ID — adds an extra request but keeps the webhook payload small.
4. Parse the fields out
This is where most projects die. Your options:
- Regex — fine for one fixed sender format. Breaks the day someone changes their template.
- Templates / rules — better than regex, still per-format. You spend the rest of your career maintaining templates.
- An LLM call — describe the JSON shape you want, send it the email body, parse the response. Tolerates format drift. Costs ~$0.001–0.01 per email depending on model.
If you go the LLM route yourself, expect to also write: prompt management, JSON schema validation against the LLM output, retry logic when the model returns malformed JSON, cost-tracking, and a way to test without hitting the live API.
5. Deliver the JSON to your destination
POST it to your real API. Now you need retries (your API is occasionally down), dead-letter handling (so failed deliveries don't disappear silently), idempotency (so you don't process the same email twice when a webhook retries), and a way to manually replay failures.
6. The held-message pen
What happens when an email comes in for an inbox you haven't set up yet? Or for a sender not on the allowlist? Or when your destination API has been down for an hour? You need a holding pen and an admin UI to inspect, retry, or discard.
If all six pieces sound like a weekend project, you're underestimating it. Real production builds of this take 2–4 weeks for a senior engineer, plus ongoing maintenance every time a sender changes format.
The shortcut
Use a service that bundles all six. MailToAPI is built specifically for this: forward an email, describe the JSON shape you want, get a webhook POSTed to your API. Each processed email run uses one credit, and replaying the same run after a fix does not double-charge.
Setup, end to end
- Sign up at mailtoapi.app. You get 5 free email runs, no credit card.
- Create an inbox. Describe the JSON shape you want (e.g.
name,email,phone,intent— each typed as string / number / boolean / date / enum, required or optional). Set the destination URL where the JSON should be POSTed. Optionally restrict which senders are allowed. - You get an address like
[email protected]. Forward a test email to it. - Receive the JSON on your destination URL.
Receiving the webhook (Express)
import express from 'express';
const app = express();
app.use(express.json());
app.post('/api/leads', (req, res) => {
const lead = req.body;
// { name: 'Ada Lovelace', email: 'ada@example.com', ... }
// save to your DB, fire a notification, whatever
res.status(200).json({ ok: true });
});
app.listen(3000);
Receiving the webhook (Hono)
import { Hono } from 'hono';
const app = new Hono();
app.post('/api/leads', async (c) => {
const lead = await c.req.json();
// { name: 'Ada Lovelace', email: 'ada@example.com', ... }
return c.json({ ok: true });
});
export default app;
That's the whole integration on your side. No parser maintenance, no signature verification, no custom retry UI. MailToAPI records the run timeline, destination response, and extracted JSON so you can debug failures and replay the same run after a fix.
When to build it yourself vs use a service
Build your own when:
- You're at very high volume (hundreds of thousands of emails / day) and want infrastructure control
- You already have inbound email plumbed (SES + Lambda is already running for something else) and just need to add parsing
- You're parsing a single fixed format from a single sender and an LLM call is overkill
- Compliance requires no third-party processing of email bodies
Use a service when:
- You want this working today, not in 2-4 weeks
- Email formats vary across senders
- You want held-message inspection and manual replay out of the box
- You'd rather pay per delivery than write a custom retry / dead-letter pipeline
- You want an AI agent (Claude / GPT) to set up the inbox for you via API
If you want to try the shortcut, the free trial gets you to your first delivered JSON in about 5 minutes.
