Resend vs SendGrid vs Brevo: Transactional Email APIs 2026
Resend vs SendGrid vs Brevo: Transactional Email APIs 2026
TL;DR
Transactional emails — order confirmations, password resets, notifications — need reliable delivery, not a mailing list platform. Resend is the developer-first newcomer built by former Vercel engineers — it's the only provider with first-class React Email integration, a clean API, and a generous free tier designed for indie hackers and startups. SendGrid (Twilio) is the enterprise standard — built for massive volume (billions of emails per month), IP warming, dedicated IPs, and complex deliverability needs; it's the safe choice for high-volume production. Brevo (formerly Sendinblue) is the EU-first alternative — GDPR-native, servers in Europe, affordable pricing, and both transactional and marketing email in one platform. For startups and developers: Resend. For high-volume enterprise: SendGrid. For GDPR-compliance and EU data residency: Brevo.
Key Takeaways
- Resend free tier: 3,000 emails/month, 100/day — generous for early-stage apps
- SendGrid delivers 100 billion+ emails per month — highest volume capacity
- Brevo stores all data on EU servers — important for GDPR-regulated businesses
- Resend is the only provider built around React Email — templates as JSX components
- SendGrid requires IP warming for dedicated IPs — 30-60 day process for new domains
- Brevo includes marketing email + SMS + transactional in one platform (SendGrid is transactional-only for developers)
- All three have Node.js SDKs with TypeScript support
Why Transactional Email Providers Exist
Sending email directly (SMTP from your server) results in poor deliverability:
Direct SMTP issues:
- New server IP → spam filters flag it as unknown sender
- No feedback loops → you don't know when recipients report spam
- Bounces damage your IP reputation silently
- No DKIM/DMARC management → authentication failures
Email API providers solve:
- Shared or dedicated IP reputation with warm history
- Bounce/spam tracking and automatic unsubscribe
- DKIM signing and DMARC alignment
- Delivery analytics and debugging
Resend: Developer-First Email API
Resend was founded by the team behind Vercel's email infrastructure. It's built around the idea that email should feel like any other API — clean, predictable, and well-documented.
Installation
npm install resend
# Optional: React Email templates
npm install react-email @react-email/components
Basic Email Sending
import { Resend } from "resend";
const resend = new Resend(process.env.RESEND_API_KEY);
// Send a simple text email
const { data, error } = await resend.emails.send({
from: "Acme <onboarding@acme.com>", // Must be from your verified domain
to: ["user@example.com"],
subject: "Welcome to Acme!",
html: "<h1>Welcome!</h1><p>Thanks for joining Acme.</p>",
text: "Welcome! Thanks for joining Acme.", // Plain text fallback
});
if (error) {
console.error("Email failed:", error);
return;
}
console.log("Email ID:", data?.id); // Store for tracking
React Email Templates
// emails/welcome.tsx — React Email component
import {
Html,
Head,
Body,
Container,
Heading,
Text,
Button,
Hr,
Link,
Preview,
} from "@react-email/components";
interface WelcomeEmailProps {
userName: string;
loginUrl: string;
}
export function WelcomeEmail({ userName, loginUrl }: WelcomeEmailProps) {
return (
<Html>
<Head />
<Preview>Welcome to Acme — let's get you started</Preview>
<Body style={{ backgroundColor: "#f6f9fc", fontFamily: "sans-serif" }}>
<Container style={{ maxWidth: "560px", margin: "0 auto", padding: "20px" }}>
<Heading style={{ color: "#333", fontSize: "24px" }}>
Welcome, {userName}!
</Heading>
<Text style={{ color: "#555", lineHeight: "1.6" }}>
Thanks for signing up for Acme. Your account is ready and waiting.
</Text>
<Button
href={loginUrl}
style={{
backgroundColor: "#5469d4",
color: "#ffffff",
padding: "12px 20px",
borderRadius: "6px",
display: "inline-block",
textDecoration: "none",
}}
>
Get Started →
</Button>
<Hr style={{ borderColor: "#e6ebf1", margin: "20px 0" }} />
<Text style={{ color: "#999", fontSize: "12px" }}>
If you didn't create an account, you can ignore this email.
</Text>
</Container>
</Body>
</Html>
);
}
// api/send-welcome.ts — Send React Email template
import { Resend } from "resend";
import { render } from "@react-email/render";
import { WelcomeEmail } from "@/emails/welcome";
const resend = new Resend(process.env.RESEND_API_KEY);
export async function sendWelcomeEmail(userId: string, email: string, name: string) {
const html = await render(
WelcomeEmail({
userName: name,
loginUrl: `https://app.acme.com/login?userId=${userId}`,
})
);
const { data, error } = await resend.emails.send({
from: "Acme <welcome@acme.com>",
to: [email],
subject: `Welcome to Acme, ${name}!`,
html,
});
if (error) throw new Error(`Email failed: ${error.message}`);
return data?.id;
}
Batch Sending
// Send up to 100 emails per batch request
const { data, error } = await resend.batch.send([
{
from: "Acme <notify@acme.com>",
to: "user1@example.com",
subject: "Your weekly report",
html: "<p>Your stats for this week...</p>",
},
{
from: "Acme <notify@acme.com>",
to: "user2@example.com",
subject: "Your weekly report",
html: "<p>Your stats for this week...</p>",
},
]);
Webhooks for Delivery Tracking
// api/webhooks/email.ts — Track delivery events
import type { NextApiRequest, NextApiResponse } from "next";
export default async function handler(req: NextApiRequest, res: NextApiResponse) {
const event = req.body;
switch (event.type) {
case "email.sent":
console.log("Email sent:", event.data.email_id);
break;
case "email.delivered":
console.log("Email delivered to:", event.data.to);
break;
case "email.bounced":
// Mark user's email as invalid in your database
await markEmailBounced(event.data.to);
break;
case "email.complained":
// User reported as spam — unsubscribe them
await unsubscribeUser(event.data.to);
break;
case "email.opened":
await trackEmailOpen(event.data.email_id);
break;
case "email.clicked":
await trackLinkClick(event.data.email_id, event.data.click.link);
break;
}
res.status(200).json({ received: true });
}
SendGrid: Enterprise-Grade Volume
SendGrid (Twilio) powers email for Airbnb, Spotify, Uber, and other high-volume senders. It's built for reliability at massive scale with granular deliverability controls.
Installation
npm install @sendgrid/mail
Basic Usage
import sgMail from "@sendgrid/mail";
sgMail.setApiKey(process.env.SENDGRID_API_KEY!);
await sgMail.send({
to: "user@example.com",
from: {
email: "noreply@acme.com",
name: "Acme",
},
subject: "Order Confirmation #12345",
text: "Your order has been confirmed.",
html: "<strong>Your order has been confirmed.</strong>",
// Tracking settings
trackingSettings: {
clickTracking: { enable: true },
openTracking: { enable: true },
},
// Custom data attached to this email (for webhook events)
customArgs: {
orderId: "12345",
userId: "user_abc",
},
});
Dynamic Templates
// SendGrid Dynamic Templates — template defined in SendGrid dashboard
// Uses Handlebars syntax: {{name}}, {{#if condition}}...{{/if}}
await sgMail.send({
to: "user@example.com",
from: "orders@acme.com",
templateId: "d-xxxxxxxxxxxxxxxxxxxx", // Template ID from SendGrid dashboard
dynamicTemplateData: {
first_name: "Alice",
order_id: "12345",
items: [
{ name: "Widget A", price: "$29.99", quantity: 2 },
{ name: "Widget B", price: "$49.99", quantity: 1 },
],
total: "$109.97",
tracking_url: "https://track.example.com/12345",
},
});
Sending to Multiple Recipients
// Personalized emails at scale
const messages = users.map((user) => ({
to: user.email,
from: "newsletter@acme.com",
templateId: "d-yyyyyyyyyyy",
dynamicTemplateData: {
name: user.name,
plan: user.plan,
usage: user.currentUsage,
limit: user.usageLimit,
},
customArgs: { userId: user.id },
}));
// Send all in a single API call (up to 1,000 personalizations)
await sgMail.send(messages);
Event Webhooks
// SendGrid calls your webhook for delivery events
export async function handleSendGridWebhook(events: SendGridEvent[]) {
for (const event of events) {
switch (event.event) {
case "delivered":
await db.emailLogs.update({
where: { messageId: event.sg_message_id },
data: { deliveredAt: new Date(event.timestamp * 1000) },
});
break;
case "bounce":
await handleBounce(event.email, event.reason);
break;
case "spamreport":
await handleSpamReport(event.email);
break;
}
}
}
Brevo: EU-First Email Platform
Brevo (formerly Sendinblue) combines transactional email with marketing tools in one platform, with EU data residency and GDPR-native design.
Installation
npm install @getbrevo/brevo
Basic Transactional Email
import * as Brevo from "@getbrevo/brevo";
const transactional = new Brevo.TransactionalEmailsApi();
transactional.setApiKey(
Brevo.TransactionalEmailsApiApiKeys.apiKey,
process.env.BREVO_API_KEY!
);
const email = new Brevo.SendSmtpEmail();
email.subject = "Order Confirmation";
email.htmlContent = "<h1>Your order is confirmed!</h1>";
email.sender = { name: "Acme", email: "orders@acme.com" };
email.to = [{ email: "user@example.com", name: "Alice" }];
email.params = { orderId: "12345" };
const response = await transactional.sendTransacEmail(email);
console.log("Message ID:", response.body.messageId);
Template-Based Sending
// Brevo templates created in the dashboard
await transactional.sendTransacEmail({
to: [{ email: "user@example.com", name: "Alice" }],
templateId: 12, // Numeric template ID from Brevo dashboard
params: {
FIRST_NAME: "Alice",
ORDER_ID: "12345",
ITEMS: [
{ name: "Widget A", price: "€29.99" },
],
TOTAL: "€29.99",
},
sender: { name: "Acme", email: "orders@acme.com" },
});
Feature Comparison
| Feature | Resend | SendGrid | Brevo |
|---|---|---|---|
| Free tier | 3,000/mo, 100/day | 100/day (Forever) | 300/day |
| Paid pricing | $20/mo for 50k | $19.95/mo for 50k | $25/mo for 60k |
| React Email | ✅ Native | ❌ (Handlebars) | ❌ (drag-drop) |
| EU data residency | ❌ (US) | ❌ (US) | ✅ EU servers |
| GDPR features | Basic | Basic | ✅ GDPR-first |
| Marketing email | ❌ | Separate product | ✅ Included |
| IP warming | Shared pool | Manual (dedicated) | Shared/dedicated |
| Dedicated IPs | ❌ | ✅ | ✅ |
| Deliverability tools | Basic | ✅ Advanced | Good |
| TypeScript SDK | ✅ | ✅ | ✅ |
| Webhook events | ✅ | ✅ | ✅ |
| API design | ✅ Modern REST | Good (older) | Good |
| Volume capacity | Medium | ✅ Billions/month | Large |
When to Use Each
Choose Resend if:
- You're building a startup or indie product and want the fastest path to working email
- React Email for type-safe, component-based templates is appealing
- Clean modern API design matters more than enterprise feature breadth
- Volume is under ~500k emails/month
Choose SendGrid if:
- You're at high volume (millions+ of emails per month) and need proven deliverability at scale
- Dedicated IPs with full IP warming control is required
- You need deep integration with Twilio for SMS + email in one platform
- Advanced deliverability analytics and ISP feedback loops are needed
Choose Brevo if:
- EU data residency is a compliance requirement (GDPR, financial services, healthcare)
- You want transactional email + marketing campaigns + SMS in one account
- Affordable pricing for mid-volume senders in Europe
- You need a complete CRM/marketing platform alongside email sending
Methodology
Data sourced from official pricing pages for all three providers (as of February 2026), developer documentation, and community reviews on r/webdev, Hacker News, and the Indie Hackers community. Deliverability comparisons from third-party email testing services (Mail-Tester, GlockApps reports). React Email integration verified against official Resend documentation.
Related: Resend vs Nodemailer vs Postmark for Node.js email library comparison, or Novu vs Knock vs Courier for full notification infrastructure including in-app and push.