The inbound-first alternative to Resend
Resend is a sending platform with receiving attached. Inboundr is built for the mail coming in: routing you configure, filtering before delivery, and the whole message in one webhook.
Resend’s documentation and pricing last read 30 July 2026
The short version
- Routing is configuration, not code: an address points at one or more endpoints, so mail can post to your app and forward to a person without a deploy.
- Rules drop unwanted mail before it becomes a request — off your compute bill, out of your database, and out of your agent's context window.
- The whole message arrives in one webhook, bodies included, instead of an event that tells you to go and fetch it.
- Resend is a sending platform with receiving attached. Inbound is the entire product here, and the object model shows it.
A sending platform that also receives
Resend is a sending product. It became popular because sending through it is pleasant, and receiving arrived later as an addition to that platform — mail is stored on arrival, an API reads it back, and webhooks are signed and retried. If your problem is outbound with a few replies coming home, that addition is probably enough.
Inbound is not an addition here. It is the entire product, and that shows up in the object model: domains hold addresses, addresses point at endpoints, endpoints have retry policies, messages belong to threads, and rules run before any of it. When receiving is the feature you are buying, buying it from a product organised around receiving is not a small difference.
Where the two actually differ
Three differences, and they are all architectural rather than featural:
- Routing is configured here and coded there. An address in this product points at endpoints, and an address can have several — post to your app and forward to a person, from the same message. With Resend the receiving domain has one webhook and your handler is the router: the branch on
to, the fan-out, the forwarding, all in code you own and deploy. - Filtering happens before delivery or in your handler. Rules that drop mail on sender, recipient, subject or spam verdict mean the junk never becomes an invocation. Without them, every scraped-address blast is a call to your endpoint that you pay for and then discard.
- The webhook is one round trip or two. Their event is deliberately metadata-only so a large attachment cannot exceed a serverless request limit — a defensible choice. The cost is that the simplest possible handler still makes an API call before it can read the sentence someone wrote.
Routing in code is still available
Nothing forces routing into the console: addresses and endpoints are created through the API, so the whole configuration can live in your repository and be applied from CI. The difference is that changing where mail goes does not require a deploy of your handler — and that an over-broad rule is visible as a list of blocked messages rather than as a branch nobody read.
Side by side
The rows that matter are the ones you would otherwise write code for: routing, filtering, and getting the message in one request instead of two.
| What you need | Inboundr | Resend |
|---|---|---|
| Receive mail on a domain you own | One MX record and one DKIM record on the domain or subdomain you choose, then every address on it resolves, catch-all included. | Either a managed receiving domain they give you, or your own via MX. Their own documentation warns to use a subdomain, since an MX record on the apex takes all mail for it. |
| The parsed message in the webhook body | The email.received payload carries the text and HTML bodies, addresses, threading ids and auth verdicts, plus attachment metadata with fetch links. One request, and your handler has the message. | By design the event carries metadata only — sender, recipients, subject, ids, attachment descriptors. Bodies and attachment content come from a second call to their API. |
| Fetch a message after the fact | Stored on arrival and listable and fetchable over REST for the plan's retention window, so a consumer that was down catches up afterwards. | Also stored on arrival, with a received-emails API and dashboard access, and webhook events can be replayed. A failed endpoint does not lose you the mail. |
| Attachment bytes from an API | Each attachment is stored separately and handed out as a short-lived download link, and there is a get_attachment tool for agents. | A list-and-download API for received attachments, which is the reason their webhook stays metadata-only in the first place. |
| Routing you configure rather than write | An address points at one or more endpoints — webhook, forwarding, or store-only — and a catch-all covers the rest. Changing where mail goes is a console change, not a deploy. | Everything for the receiving domain arrives at one webhook and your handler branches on the recipient. Flexible, and yours to maintain: forwarding to a person is a recipe you implement rather than a destination you pick. |
| Filtering before it reaches your code | Rules match on sender, recipient, subject or spam verdict and drop or divert the message before delivery. Blocked messages are listed, so a rule that is too broad is visible. | No pre-delivery rule engine in the product at the date checked. Unwanted mail reaches your endpoint and you drop it there — which costs an invocation and a decision in your own code. |
| A threaded reply from code | Name the message you are answering and In-Reply-To and References are written for you, with the subject prefixed if it needs it. | Fully supported and documented, but the headers are yours to assemble: set In-Reply-To to the received message id and build the References chain yourself. |
| An agent that works its own inbox over MCP | A hosted MCP server on the same API key, scoped to mail: list, read, thread, send, fetch attachments, and manage filtering rules. | A hosted MCP server covering their whole platform, received mail and attachment downloads included. This is not a gap, and pages that pretend otherwise are out of date. |
| Built around the inbox rather than the send | Domains, addresses, endpoints, threads, rules and retention are the product. Every feature is there because mail arrived. | Receiving is one feature of a sending platform. It is a capable one, but the object model, the meter and the roadmap are all organised around outbound. |
Receive mail on a domain you own
- Inboundr
- One MX record and one DKIM record on the domain or subdomain you choose, then every address on it resolves, catch-all included.
- Resend
- Either a managed receiving domain they give you, or your own via MX. Their own documentation warns to use a subdomain, since an MX record on the apex takes all mail for it.
The parsed message in the webhook body
- Inboundr
- The email.received payload carries the text and HTML bodies, addresses, threading ids and auth verdicts, plus attachment metadata with fetch links. One request, and your handler has the message.
- Resend
- By design the event carries metadata only — sender, recipients, subject, ids, attachment descriptors. Bodies and attachment content come from a second call to their API.
Fetch a message after the fact
- Inboundr
- Stored on arrival and listable and fetchable over REST for the plan's retention window, so a consumer that was down catches up afterwards.
- Resend
- Also stored on arrival, with a received-emails API and dashboard access, and webhook events can be replayed. A failed endpoint does not lose you the mail.
Attachment bytes from an API
- Inboundr
- Each attachment is stored separately and handed out as a short-lived download link, and there is a get_attachment tool for agents.
- Resend
- A list-and-download API for received attachments, which is the reason their webhook stays metadata-only in the first place.
Routing you configure rather than write
- Inboundr
- An address points at one or more endpoints — webhook, forwarding, or store-only — and a catch-all covers the rest. Changing where mail goes is a console change, not a deploy.
- Resend
- Everything for the receiving domain arrives at one webhook and your handler branches on the recipient. Flexible, and yours to maintain: forwarding to a person is a recipe you implement rather than a destination you pick.
Filtering before it reaches your code
- Inboundr
- Rules match on sender, recipient, subject or spam verdict and drop or divert the message before delivery. Blocked messages are listed, so a rule that is too broad is visible.
- Resend
- No pre-delivery rule engine in the product at the date checked. Unwanted mail reaches your endpoint and you drop it there — which costs an invocation and a decision in your own code.
A threaded reply from code
- Inboundr
- Name the message you are answering and In-Reply-To and References are written for you, with the subject prefixed if it needs it.
- Resend
- Fully supported and documented, but the headers are yours to assemble: set In-Reply-To to the received message id and build the References chain yourself.
An agent that works its own inbox over MCP
- Inboundr
- A hosted MCP server on the same API key, scoped to mail: list, read, thread, send, fetch attachments, and manage filtering rules.
- Resend
- A hosted MCP server covering their whole platform, received mail and attachment downloads included. This is not a gap, and pages that pretend otherwise are out of date.
Built around the inbox rather than the send
- Inboundr
- Domains, addresses, endpoints, threads, rules and retention are the product. Every feature is there because mail arrived.
- Resend
- Receiving is one feature of a sending platform. It is a capable one, but the object model, the meter and the roadmap are all organised around outbound.
When Resend is the better choice
- Outbound is the whole of your problem. If you send campaigns and broadcasts and inbound is nothing more than the occasional reply, a sending platform with a receiving feature is the simpler purchase.
- One invoice matters more than the pipeline. If procurement makes a second vendor expensive in a way the engineering does not repay, stay where you are until the inbound side actually hurts.
One round trip or two
The difference is easiest to see in the handler you end up writing. With a metadata-only event, the shape is fetch-then-act:
export async function POST(req: Request) {
const event = await verify(req); // signature check
const id = event.data.email_id;
// The body is not here yet.
const mail = await api.received.get(id); // second call
const text = mail.text;
await handle(text);
}And with the body already in the payload:
{
"event": "email.received",
"email": {
"id": "em_2f9c1a4b7d3e5601",
"threadId": "thr_8b21c0f4a95d",
"messageId": "<CAF9xq2@mail.example.com>",
"from": "customer@example.com",
"to": ["support@yourdomain.com"],
"subject": "Invoice 4021 looks wrong",
"text": "Hi — line 3 is billed twice…",
"html": "<p>Hi — line 3 is billed twice…</p>",
"attachments": [
{ "filename": "invoice-4021.pdf",
"contentType": "application/pdf",
"size": 84213 }
],
"verdicts": { "spam": "PASS", "spf": "PASS", "dkim": "PASS" },
"receivedAt": "2026-07-30T09:14:22.104Z"
}
}Attachments stay out of the request body in both products — sooner or later someone sends a 20 MB PDF — but the body of the message is the thing your handler always needs, and here it is already there. One round trip, one failure mode, one thing to retry.
Multiply that by every message and every cold start: a second API call in the hot path of an inbound webhook is latency you pay on every single email, forever, to read text that had already been parsed before the event was sent.
What each one costs
No price table here, deliberately: both products change their pricing and a stale number is worse than none. Check theirs at the source and ours here. What is worth comparing is the shape of the meter.
- Resend is anchored on sending volume, because that is what the platform is for. Receiving is measured against a meter built for outbound.
- Inboundr is anchored on messages received, with an allowance and opt-in pay-as-you-go past it — the axis your bill should be on when inbound is the workload.
And a cost that never appears on either pricing page: mail you did not want. Filtering before delivery keeps a spam blast off your compute bill as well as out of your database. Every message dropped by a rule is an invocation you never ran, a row you never wrote and a payload your agent never had to read.
Moving a receiving domain across
Both sides are two DNS records, so the cutover is short and reversible if you order it correctly:
- Add the domain or subdomain in the Inboundr console and copy the MX and DKIM records it shows you. Change nothing in DNS yet.
- Create the addresses and endpoints that will replace the branching in your current handler. If your handler dispatches on
totoday, each branch is usually one address pointed at one endpoint. - Publish the DKIM record and wait for verification. This does not affect delivery, so it is safe to do while Resend is still receiving.
- Replace the MX record. Use a low TTL an hour beforehand so resolvers pick the change up in minutes rather than hours.
- Send a test message with an attachment and a reply in a thread. Those are the two paths where an assumption from the old handler usually survives the move.
- Leave the old webhook deployed for a few days. It costs nothing idle, and it is your rollback if something in the payload shape surprises you.
You do not have to move sending
Receiving here and sending wherever you send today is a supported arrangement, and it is the low-risk way to start: nothing about your outbound setup changes, and inbound gets the product built for it.
Questions people ask
Can I receive here and keep sending with Resend?
Yes, and it is a common arrangement. The catch is threading: if you send the reply through another provider, the message ids in your thread come from that provider, so pass the received message’s id into their In-Reply-To header yourself. Doing both sides here is what makes threading automatic, but splitting is not broken — just manual at one seam.
Does Resend really not include the body in the webhook?
Correct at the date checked, and it is a deliberate design rather than an omission: their event carries metadata and attachment descriptors, and bodies come from the received-emails API. It means one predictable small payload instead of one that varies with what a stranger attached.
Which one is better for an AI agent?
Both offer a hosted MCP server, so the question is what sits behind the tools. Inboundr's is an inbox: threads, retained messages, fetchable attachments, and the filtering rules themselves as tool calls — an agent that is drowning in newsletters can write a rule and stop them arriving. Resend's is a platform API an agent can drive, with inbound as one part of it.
Can I use both for receiving, on different domains?
Yes. MX records are per domain, so one subdomain can point here and another there with no interaction between them. That is the cheapest way to evaluate: point a subdomain you do not depend on at us for a week.
What happens to mail if my endpoint is down?
Nothing is lost. The message is stored on arrival, the delivery is retried with backoff, and every attempt is visible in the console with the status your server returned — so “did we get their email?” is a lookup rather than an investigation. It stays fetchable over REST and MCP for the whole of your plan’s retention window.
Claims about Resend were checked against their public documentation on receiving email, replying to received email, their MCP server and their pricing page. Read on 30 July 2026. If something here is out of date, tell us and we will correct it.