Resend Isn’t Just ‘SendGrid with Better UX’: What I Discovered Building a Batch Email System in 2026
Today I learned I’d been using Resend at half capacity for months.
I had it integrated for transactional emails — registration confirmations, password resets, invoices. It worked well, the API is clean, and the free tier of 3,000 emails/month covers any early-stage project. All good.
But when I tried building a notification system that sends to user segments — campaigns, alerts, product updates — I ran into a reality that nobody documents well: Resend has a batch architecture that’s fundamentally different from sending emails one by one.
And if you don’t understand it from the start, you’ll build something that seems to work locally and breaks in production.
The Limit Nobody Mentions in Tutorials
Resend’s Batch API has a hard maximum of 50 recipients per call.
Seems low, right? But it’s a deliberate design decision. It’s not an arbitrary restriction — it’s the difference between a system you process in controlled queues versus a for loop that blows your rate limit and leaves you with no sending capacity for minutes.
The trap is that many devs, when they discover resend.batch.send(), do this:
The right approach is to process in chunks:
Simple, but critical.
Idempotency Keys: The Superpower Nobody Uses
This is where Resend truly starts differentiating itself from other APIs.
Idempotency keys are one of those features you don’t understand the value of until you get burned. The scenario: you have a Next.js Server Action that fires a confirmation email. The user clicks twice in a row, or there’s a network retry, or your worker queue processes the same job twice.
Result: the user gets the same email twice. Seems like a small bug, but in contexts like payment confirmations or critical alerts, it’s a real problem.
The solution:
With this key, even if the same endpoint gets called 10 times with the same orderId, Resend will send the email exactly once. The rest of the calls return the same result without triggering a new send.
This eliminates an entire category of duplicate bugs that in other APIs you’d have to handle yourself with deduplication logic in the database.
Natural Language Scheduling: The Feature That Blew My Mind
Another thing I discovered late: Resend allows scheduling sends with natural language.
It also accepts ISO 8601 if you prefer precision:
For scheduled newsletters or digests, this eliminates the need for an external queue system for simple cases. You don’t need Inngest or BullMQ just to say “send this tomorrow at 9am”.
Test Mode Secrets Almost Everyone Ignores
Before talking about webhooks, here’s something that would have saved me a lot of time in staging: Resend’s special test emails.
delivered@resend.dev→ simulates a successful deliverybounced@resend.dev→ simulates a bounce
This way you can test your bounce handling logic without contaminating real lists or risking your domain reputation.
Webhooks: Closing the Event Loop
A batch system without webhooks is incomplete. Resend emits events for each email state:
email.sentemail.deliveredemail.openedemail.clickedemail.bouncedemail.complained
In a Next.js Route Handler:
Important: always verify the webhook signature. It’s the most common mistake I see in code reviews — webhook endpoints without signature verification are a real attack vector.
The Pricing Trap That Requires an Architectural Decision
One detail to be clear on from the start: Resend distinguishes between transactional emails (covered in the free tier) and marketing (requires a paid plan for high volumes and dedicated IPs).
If your use case mixes both from the beginning — product notifications plus newsletters — architect the queues and senders separately from day one. Changing this later is more costly than setting it up correctly from the start.
Dedicated IPs come into play when you consistently exceed 500 emails/day. Before that volume, Resend’s shared IPs have good reputation and you don’t need to worry.
Checklist to Avoid the Deliverability Rabbit Hole
Before going to production with any sending volume, verify these three DNS records:
- SPF → authorizes which servers can send on behalf of your domain
- DKIM → cryptographic signature that verifies email authenticity
- DMARC → policy for what to do when SPF or DKIM fail
Resend has a decent domain verification guide, but if your emails start landing in spam, DMARC is the first place to look. Most deliverability problems I see in other devs’ projects are p=none in DMARC — which basically means “do nothing if something fails”.
Start with p=quarantine from the beginning.
What I Changed in My Stack After All This
The short version: Resend isn’t just a cleaner email API. It’s an architecture designed for developers building products with React and Next.js, with primitives (idempotency, scheduling, batch with controlled chunks) that eliminate entire categories of bugs.
But you need to understand its limits — the 50-recipient batch limit isn’t a bug, it’s a guardrail — and its less visible features to truly leverage it.
If you already have Resend integrated for transactional and you’re scaling to campaigns: set up webhooks from day one, use idempotency keys in any flow that could be retried, and decide now whether you need dedicated IPs before volume makes that decision for you.
