Resend Setup
Set up Resend for transactional emails like password resets.
Step 1: Install the package
bun add resendbun add resendbash
Step 2: Add environment variables
Add to your .env.local:
RESEND_API_KEY="re_your_api_key"
RESEND_FROM_EMAIL="Your App <noreply@yourdomain.com>"RESEND_API_KEY="re_your_api_key"
RESEND_FROM_EMAIL="Your App <noreply@yourdomain.com>"env
Get your API key from resend.com/api-keys.
Step 3: Create the resend config
Create src/lib/resend/config.ts:
import { z } from "zod";
import { validateConfig, type PreValidate } from "../common/validate-config";
const ResendConfigSchema = z.object({
apiKey: z.string("RESEND_API_KEY must be defined."),
fromEmail: z.string().default("Acme <onboarding@resend.dev>"),
});
export type ResendConfig = z.infer<typeof ResendConfigSchema>;
const config: PreValidate<ResendConfig> = {
apiKey: process.env.RESEND_API_KEY,
fromEmail: process.env.RESEND_FROM_EMAIL,
};
export const resendConfig = validateConfig(ResendConfigSchema, config);import { z } from "zod";
import { validateConfig, type PreValidate } from "../common/validate-config";
const ResendConfigSchema = z.object({
apiKey: z.string("RESEND_API_KEY must be defined."),
fromEmail: z.string().default("Acme <onboarding@resend.dev>"),
});
export type ResendConfig = z.infer<typeof ResendConfigSchema>;
const config: PreValidate<ResendConfig> = {
apiKey: process.env.RESEND_API_KEY,
fromEmail: process.env.RESEND_FROM_EMAIL,
};
export const resendConfig = validateConfig(ResendConfigSchema, config);typescript
Step 4: Create the Resend client
Create src/lib/resend/client.ts:
import { Resend } from "resend";
import { resendConfig } from "./config";
export const resend = new Resend(resendConfig.apiKey);import { Resend } from "resend";
import { resendConfig } from "./config";
export const resend = new Resend(resendConfig.apiKey);typescript
Step 5: Create the send helper
Create src/lib/resend/send.ts:
import { resend } from "./client";
import { resendConfig } from "./config";
type SendEmailParams = {
to: string | string[];
subject: string;
react: React.ReactElement;
from?: string;
};
export async function sendEmail({ to, subject, react, from }: SendEmailParams) {
const { data, error } = await resend.emails.send({
from: from ?? resendConfig.fromEmail,
to: Array.isArray(to) ? to : [to],
subject,
react,
});
if (error) {
throw new Error(`Failed to send email: ${error.message}`);
}
return data;
}import { resend } from "./client";
import { resendConfig } from "./config";
type SendEmailParams = {
to: string | string[];
subject: string;
react: React.ReactElement;
from?: string;
};
export async function sendEmail({ to, subject, react, from }: SendEmailParams) {
const { data, error } = await resend.emails.send({
from: from ?? resendConfig.fromEmail,
to: Array.isArray(to) ? to : [to],
subject,
react,
});
if (error) {
throw new Error(`Failed to send email: ${error.message}`);
}
return data;
}typescript
Usage
import { sendEmail } from "@/lib/resend/send";
await sendEmail({
to: "user@example.com",
subject: "Welcome!",
react: <WelcomeEmail name="John" />,
});import { sendEmail } from "@/lib/resend/send";
await sendEmail({
to: "user@example.com",
subject: "Welcome!",
react: <WelcomeEmail name="John" />,
});typescript
Create email templates
Email templates are React components. Create them in src/lib/auth/emails/ for auth-related emails:
// src/lib/auth/emails/forgot-password.tsx
interface ForgotPasswordEmailProps {
resetLink: string;
}
export function ForgotPasswordEmail({ resetLink }: ForgotPasswordEmailProps) {
return (
<div>
<h1>Reset Your Password</h1>
<p>Click the link below to reset your password:</p>
<a href={resetLink}>Reset Password</a>
<p>If you did not request a password reset, please ignore this email.</p>
</div>
);
}// src/lib/auth/emails/forgot-password.tsx
interface ForgotPasswordEmailProps {
resetLink: string;
}
export function ForgotPasswordEmail({ resetLink }: ForgotPasswordEmailProps) {
return (
<div>
<h1>Reset Your Password</h1>
<p>Click the link below to reset your password:</p>
<a href={resetLink}>Reset Password</a>
<p>If you did not request a password reset, please ignore this email.</p>
</div>
);
}typescript
File Structure
src/lib/resend/
config.ts # Environment validation
client.ts # Resend client instance
send.ts # Email sending helper
src/lib/auth/emails/
forgot-password.tsx # Password reset templatesrc/lib/resend/
config.ts # Environment validation
client.ts # Resend client instance
send.ts # Email sending helper
src/lib/auth/emails/
forgot-password.tsx # Password reset template