TL;DR: Resend is an email-sending service with a simple API. Instead of configuring your own email server (like hand-delivering every letter yourself), you make one API call and Resend handles delivery, bounce tracking, and spam compliance. AI tools love it because the code is minimal — one import, one function call, emails sent.
Why AI Coders Need to Know This
Almost every real app needs to send email at some point. Welcome messages when someone signs up. Password reset links. Order confirmations. Invoice receipts. The moment your project goes from "cool demo" to "thing people actually use," email enters the picture.
Here is what usually happens: you are building with Claude or Cursor, your app is coming together nicely, and you type something like "add email confirmation when a user registers." The AI generates a block of code that imports something called resend, creates an instance with an API key, and calls a send method. If you have never heard of Resend before, you are now staring at code that looks straightforward but will not work until you complete a few setup steps the AI probably did not mention.
The gap between "AI generated this code" and "emails are actually arriving in inboxes" is where most vibe coders get stuck. The code itself is usually correct. The setup around it — the API key, the domain verification, the "from" address — is where things fall apart. This guide closes that gap.
Think of it like plumbing in a new build. The pipes are right, the connections look good, but nothing flows until the water main is turned on and the inspector signs off. Resend is the plumbing for email. The code is the pipes. This article is about turning the water on.
Real Scenario
You are building a SaaS app — maybe a client portal, a booking tool, or a simple project tracker. Users can sign up. You want them to get a welcome email the moment they create an account. So you tell your AI:
Prompt I Would Type
Send a welcome email when someone signs up. Use Resend.
Include their name in the email and a link to their dashboard.
Make the email look professional — not plain text.
Within seconds, the AI generates two things: an API route that fires off the email using Resend, and a React Email template that defines what the email looks like. Let us walk through exactly what it produces.
What AI Generated
Here is the typical code AI produces. First, the email-sending logic — usually inside an API route or a server action:
// app/api/send-welcome/route.ts (or similar server-side file)
import { Resend } from 'resend';
import WelcomeEmail from '@/emails/welcome';
const resend = new Resend(process.env.RESEND_API_KEY);
export async function POST(request) {
const { name, email } = await request.json();
const { data, error } = await resend.emails.send({
from: 'Your App <welcome@yourdomain.com>',
to: email,
subject: `Welcome aboard, ${name}!`,
react: WelcomeEmail({ name }),
});
if (error) {
return Response.json({ error }, { status: 400 });
}
return Response.json({ message: 'Email sent', id: data.id });
}
And second, the React Email template that controls what the email actually looks like in someone's inbox:
// emails/welcome.tsx
import {
Html, Head, Body, Container,
Heading, Text, Button, Preview
} from '@react-email/components';
export default function WelcomeEmail({ name }) {
return (
<Html>
<Head />
<Preview>Welcome to Your App, {name}!</Preview>
<Body style={{ backgroundColor: '#f6f9fc', padding: '40px 0' }}>
<Container style={{
backgroundColor: '#ffffff',
padding: '40px',
borderRadius: '8px',
maxWidth: '560px'
}}>
<Heading style={{ fontSize: '24px', color: '#1a1a1a' }}>
Welcome, {name}!
</Heading>
<Text style={{ fontSize: '16px', color: '#4a4a4a' }}>
Thanks for signing up. Your account is ready to go.
Click below to head to your dashboard.
</Text>
<Button
href="https://yourapp.com/dashboard"
style={{
backgroundColor: '#0070f3',
color: '#ffffff',
padding: '12px 24px',
borderRadius: '6px',
fontSize: '16px',
textDecoration: 'none'
}}
>
Go to Dashboard
</Button>
</Container>
</Body>
</Html>
);
}
This looks like a lot of code, but it breaks down into two simple jobs: one file sends the email, the other file designs the email. Let us understand each piece.
Understanding Each Part
Think of sending email through Resend like using a certified mail service. You write the letter (the template), fill out the shipping label (from, to, subject), and hand it to the service (Resend's API). They handle the truck, the route, the delivery confirmation, and the "return to sender" if the address is bad. Here is each piece of that process:
The API Key — Your Account Credentials
The line new Resend(process.env.RESEND_API_KEY) creates a connection to your Resend account. The API key is like your account number at the mail service — it tells Resend who you are and which domain you are authorized to send from.
This key is stored as an environment variable (process.env.RESEND_API_KEY), which means it lives outside your code in a .env file or your hosting platform's settings. You never put API keys directly in your source code. If someone finds your Resend key, they can send emails as you — and that is a fast way to get your domain blacklisted for spam.
To get your API key: sign up at resend.com, go to the API Keys section, and create one. Copy it into your .env file like this:
# .env (in your project root — never commit this file)
RESEND_API_KEY=re_123abc456def789ghi
The "From" Address — Who the Email Comes From
The from field ('Your App <welcome@yourdomain.com>') is the sender address that appears in the recipient's inbox. This is not just a label — it has to be an address on a domain you have verified with Resend.
This is the number one place things break. AI will generate from: 'welcome@yourdomain.com' using a placeholder domain. If you run this without verifying your actual domain, Resend will reject the request. More on this in the "What AI Gets Wrong" section below.
For testing, Resend provides a sandbox address: onboarding@resend.dev. You can send from this address — but only to your own email address (the one you signed up with). It is a test lane, not a production solution.
The "To" and "Subject" — The Destination and Label
These are straightforward. The to field is the recipient's email address — usually pulled from your database or the signup form. The subject is the email subject line. AI often uses template literals (the backtick strings with ${name}) to personalize the subject with the user's name.
One thing to know: to can also accept an array of email addresses if you need to send to multiple recipients: to: ['user@example.com', 'admin@example.com'].
The React Email Template — What the Email Looks Like
The react property points to a React Email component. React Email is a companion library (separate from Resend but made by the same team) that lets you design email templates using React components instead of wrestling with raw HTML tables.
Why does this matter? Email HTML is notoriously awful. Every email client (Gmail, Outlook, Apple Mail) renders HTML differently. React Email handles the cross-client compatibility for you, outputting HTML that looks consistent everywhere. You write clean components; it generates the messy-but-compatible HTML behind the scenes.
If you do not want to use React Email, that is fine. You can send plain HTML instead:
await resend.emails.send({
from: 'Your App <welcome@yourdomain.com>',
to: email,
subject: 'Welcome!',
html: '<h1>Welcome!</h1><p>Thanks for signing up.</p>'
});
React Email is the upgrade path — think of it as the difference between framing with rough lumber versus using pre-engineered trusses. Both hold up the roof, but one is faster and more reliable at scale.
What AI Gets Wrong
The code AI generates for Resend is usually syntactically correct. The problems are almost always in the setup and configuration that surround the code. Here are the four most common traps:
1. Unverified Domain (The #1 Killer)
AI will generate a from address like notifications@myapp.com — but Resend will reject every email unless you have verified myapp.com in your Resend dashboard. Verification means adding DNS records (specifically TXT and CNAME records) to your domain's DNS settings to prove you actually own it.
Think of it like getting a business license before you can send certified mail. The post office will not deliver certified letters from a business that is not registered. Same principle.
This is not a one-click process. You need to:
- Go to Resend dashboard → Domains → Add Domain
- Enter your domain (e.g.,
myapp.com) - Copy the DNS records Resend gives you
- Add those records in your domain registrar (Namecheap, Cloudflare, GoDaddy, etc.)
- Wait for DNS propagation (usually minutes, sometimes hours)
- Click "Verify" in Resend
AI almost never mentions this step. It generates the code and moves on as if the domain is already set up.
2. Missing or Hardcoded API Key
Sometimes AI will write new Resend('re_your_api_key_here') with a placeholder string right in the code. This does two things wrong: it does not work (the placeholder is not a real key), and it sets a bad pattern of hardcoding secrets into source files.
The correct approach is always process.env.RESEND_API_KEY, with the actual key stored in a .env file that is listed in your .gitignore. If you push a real API key to GitHub, Resend may automatically revoke it for security reasons — and you will need to generate a new one. Read more about this in our guide on environment variables.
3. Hitting Sandbox Limits Without Realizing It
If you are using the test address (onboarding@resend.dev), you can only send to the email address associated with your Resend account. If you try to send to a test user like testuser@gmail.com, it will fail silently or return an error. AI does not know which email you signed up with, so it cannot warn you about this limitation.
The free tier also has a daily limit of 100 emails and a monthly limit of 3,000. If you are testing a loop that sends emails to every user in a seed database, you can burn through your daily limit in seconds.
4. Wrong "From" Address Format
The from field supports two formats:
// Just the email (works but looks generic in inbox)
from: 'welcome@yourdomain.com'
// Display name + email (looks professional)
from: 'Your App Name <welcome@yourdomain.com>'
AI sometimes generates the format with angle brackets incorrectly, or uses an email address from a domain that does not match your verified domain. If your verified domain is myapp.com but the code says from: 'hello@myapp.io', it will fail. The domain in the "from" address must exactly match a verified domain in your Resend account.
How to Debug Resend Issues
When emails are not sending, here is the exact sequence to follow. Work through these in order — most problems get caught in the first three steps.
Step 1: Check the Resend Dashboard
Log in to resend.com and go to the Emails tab. Every email you attempt to send appears here with a status: delivered, bounced, complained, or failed. If nothing appears at all, the API call is not reaching Resend — your problem is in the code or the API key.
Step 2: Verify Your API Key
Make sure your .env file contains the correct key and that your app is actually reading it. A quick test:
// Temporary debug line — remove before deploying!
console.log('Resend key starts with:', process.env.RESEND_API_KEY?.slice(0, 6));
// Should print: "Resend key starts with: re_123" or similar
If it prints undefined, your environment variable is not being loaded. Common causes: you forgot to install dotenv, the .env file is in the wrong directory, or your framework has its own way of loading env vars (Next.js uses .env.local, for instance).
Step 3: Check Domain Verification
In the Resend dashboard, go to Domains. Your domain should show a green "Verified" badge. If it shows "Pending," the DNS records have not propagated yet. If it shows "Failed," the records are wrong — double-check each one against what Resend provided.
Step 4: Log the Full Error Response
Resend returns detailed error messages. Make sure you are logging them:
const { data, error } = await resend.emails.send({ /* ... */ });
if (error) {
console.error('Resend error:', JSON.stringify(error, null, 2));
// Common errors:
// "Missing API key" — env var not loaded
// "Validation error" — bad from address or unverified domain
// "You can only send to your own email" — sandbox limitation
}
Step 5: Test with the Sandbox First
Before troubleshooting your domain, confirm the basic flow works using the sandbox:
await resend.emails.send({
from: 'onboarding@resend.dev',
to: 'your-signup-email@gmail.com', // Must be YOUR email
subject: 'Test from Resend',
html: '<p>If you see this, Resend is working.</p>'
});
If this works but your domain does not, the issue is domain verification. If this also fails, the issue is your API key or network connectivity.
Step 6: Ask AI for Help (With Context)
If you are still stuck, copy the exact error message and give it to your AI with full context. A good prompt looks like this:
Debug Prompt
I'm using Resend to send emails in my Next.js app.
I get this error: [paste exact error]
My domain is verified in Resend dashboard: yes/no
I'm using the sandbox address: yes/no
Here's my send code: [paste code]
What's wrong?
Giving AI the full picture — not just "emails aren't working" — cuts your debugging time dramatically. Check out our full guide on debugging AI-generated code for more techniques.
Resend vs. the Alternatives
You might wonder why AI does not just use SMTP, Nodemailer, SendGrid, or any of the other email options. Here is the quick comparison:
| Option | What It Is | Why AI Picks (or Skips) It |
|---|---|---|
| Raw SMTP / Nodemailer | Direct email protocol — like hand-delivering letters yourself | Requires server config, port management, authentication setup. More code, more failure points. AI avoids it. |
| SendGrid | Established email API service (owned by Twilio) | Heavier SDK, more boilerplate. Works great but produces more code. AI sometimes generates it for larger projects. |
| Postmark | Transactional email service focused on deliverability | Excellent service but less common in AI training data. AI rarely suggests it unprompted. |
| Resend | Modern email API — certified mail service for developers | Minimal code, clean API, popular in modern tutorials. AI loves it because the code is compact and readable. |
Resend is not objectively "better" than all alternatives. SendGrid has more features for marketing email. Postmark has industry-leading deliverability. But for the kind of transactional email that AI typically generates — welcome messages, password resets, notifications — Resend hits the sweet spot of simplicity and reliability.
The Complete Setup Checklist
Here is every step from zero to working emails, in order. Bookmark this and work through it the first time AI generates Resend code for you:
- Create a Resend account at resend.com
- Generate an API key in the dashboard (API Keys → Create)
- Add the key to your
.envfile asRESEND_API_KEY=re_yourkey - Make sure
.envis in.gitignore— check before you commit - Install the package:
npm install resend(see our npm guide if this is new) - Test with sandbox: send from
onboarding@resend.devto your own email - Verify your domain: add DNS records from Resend dashboard to your domain registrar
- Wait for verification (check dashboard — green badge means good to go)
- Update the "from" address in your code to use your verified domain
- Test with a real recipient — send to a different email address you control
If you do these ten steps before running the AI-generated code, you will avoid roughly 90% of the issues vibe coders hit with email.
Bonus: Tracking Email Delivery with Webhooks
Once basic sending works, you might want to know what happens after the email leaves Resend. Did it get delivered? Did it bounce? Did the user open it? Resend supports webhooks — automated notifications sent back to your app when email events occur.
You can set up webhooks in the Resend dashboard to get notified on:
- email.delivered — the recipient's mail server accepted it
- email.bounced — the address does not exist or rejected the email
- email.opened — the recipient opened the email (not always reliable)
- email.clicked — the recipient clicked a link in the email
- email.complained — the recipient marked it as spam
This is an intermediate topic — you do not need webhooks to get started. But knowing they exist helps when you ask AI "how do I know if my emails are actually being delivered?" and it starts generating webhook handler code.
What to Learn Next
Now that you understand what Resend does and how to set it up, here are the natural next steps for expanding your knowledge:
- What Is an API? — Resend is an API-based service. Understanding APIs in general helps you work with every cloud service, not just email.
- What Are Environment Variables? — Deep dive into how
.envfiles work, why secrets belong there, and how different frameworks load them. - What Are Webhooks? — Learn how Resend (and other services) send data back to your app when events happen.
- What Is npm? — If
npm install resendis still mysterious, start here for the full package management picture. - How to Debug AI-Generated Code — A systematic approach to figuring out why code AI gave you is not working.
Frequently Asked Questions
Is Resend free to use?
Resend has a free tier that includes up to 3,000 emails per month and 100 emails per day. That is plenty for side projects, MVPs, and early-stage apps. You only need a paid plan when you are sending at higher volume, want a dedicated IP address, or need advanced features like custom tracking domains. Most vibe coders will stay comfortably on the free tier for months.
What is the difference between Resend and Nodemailer?
Nodemailer is a Node.js library that sends email using SMTP — the raw protocol that email servers speak. You need to configure an SMTP server, manage port numbers, handle TLS certificates, and deal with delivery issues yourself. Resend is a cloud service with an API — you make one call and it handles all the infrastructure. The analogy: Nodemailer is driving your own delivery truck. Resend is hiring a certified mail service. Both get the letter there, but one requires a lot less from you.
Why does AI generate Resend instead of other email services?
AI models favor Resend because its API is minimal and produces compact, readable code. One import, one constructor, one function call — done. Older services like SendGrid or Mailgun have larger SDKs with more setup steps and configuration objects. More code means more chances for AI to introduce subtle errors. Resend is also heavily represented in modern Next.js and React tutorials, which are well-represented in AI training data.
Do I need to verify a domain to use Resend?
For testing only, you can use the sandbox address onboarding@resend.dev to send to your own email. But to send emails to real users, yes — you must verify a domain you own. This involves adding DNS records (TXT and CNAME) that Resend provides to your domain registrar. It proves ownership and prevents anyone from impersonating your domain. Think of it like registering a business before you can send certified mail — the post office needs to know you are legit.
Can I use Resend without React Email?
Absolutely. React Email is an optional companion library for building email templates with React components. If you do not need fancy templates, you can pass a plain html string to the Resend send method instead of a react component. AI tends to generate React Email because it produces cleaner, more maintainable templates — but for a simple notification or password reset, a plain HTML string works perfectly fine.