Usage and Integration
Send transactional emails with Resend and manage newsletter subscriptions with Mailchimp
Learn how to send transactional emails using Resend and manage newsletter subscriptions with Mailchimp.
Sending Transactional Emails
Basic Email
Send a simple transactional email:
import { resend } from '@/lib/resend/resend';
export async function sendWelcomeEmail(to: string, name: string) {
const { data, error } = await resend.emails.send({
from: 'MyApp <hello@myapp.com>',
to,
subject: 'Welcome to MyApp!',
html: `<p>Hello ${name},</p><p>Thank you for joining!</p>`,
});
if (error) throw new Error(error.message);
return data;
}React Email Templates
Create reusable email templates with React:
export interface IWelcomeEmailProps {
name: string;
}
export default function WelcomeEmail({ name }: IWelcomeEmailProps) {
return (
<div>
<h1>Welcome, {name}!</h1>
<p>Thank you for joining MyApp.</p>
<style jsx>{`
div {
font-family: Arial, sans-serif;
}
h1 {
color: #333;
}
`}</style>
</div>
);
}Use the template:
import { resend } from '@/lib/resend/resend';
import WelcomeEmail from '@/emails/WelcomeEmail';
export async function sendWelcomeEmail(to: string, name: string) {
const { data, error } = await resend.emails.send({
from: 'MyApp <hello@myapp.com>',
to,
subject: 'Welcome to MyApp!',
react: <WelcomeEmail name={name} />,
});
if (error) throw new Error(error.message);
return data;
}Using in API Routes
Call email functions from API routes:
import { NextRequest, NextResponse } from 'next/server';
import { sendWelcomeEmail } from '@/lib/email/sendWelcomeEmail';
export async function POST(req: NextRequest) {
try {
const { email, name } = await req.json();
await sendWelcomeEmail(email, name);
return NextResponse.json({ success: true });
} catch (error) {
return NextResponse.json(
{ error: 'Failed to send email' },
{ status: 500 }
);
}
}Newsletter Management
Subscribe Users
Use the provided addContact function to subscribe users:
import { env } from '@/env';
export async function addContact(email: string) {
try {
const res = await fetch(
`${env.NEXT_PUBLIC_SITE_URL}/api/resend/newsletter`,
{
method: 'POST',
next: { tags: ['resend/newsletter'] },
body: JSON.stringify({ email }),
}
);
const json = await res.json();
if (!json.ok) {
throw new Error(json?.message);
}
return res;
} catch (error: any) {
return error;
}
}Newsletter Form
Create a newsletter subscription form:
'use client';
import { useState } from 'react';
import { addContact } from '@/lib/email/addContact';
import { Button } from '@/components/ui/Button';
import { Input } from '@/components/ui/Input';
export function NewsletterForm() {
const [email, setEmail] = useState('');
const [status, setStatus] = useState<'idle' | 'loading' | 'success' | 'error'>('idle');
async function handleSubmit(e: React.FormEvent) {
e.preventDefault();
setStatus('loading');
try {
await addContact(email);
setStatus('success');
setEmail('');
} catch (error) {
setStatus('error');
}
}
return (
<form onSubmit={handleSubmit} className="flex gap-2">
<Input
type="email"
value={email}
onChange={(e) => setEmail(e.target.value)}
placeholder="Enter your email"
required
/>
<Button type="submit" disabled={status === 'loading'}>
{status === 'loading' ? 'Subscribing...' : 'Subscribe'}
</Button>
{status === 'success' && <p className="text-green-600">Subscribed!</p>}
{status === 'error' && <p className="text-red-600">Failed to subscribe</p>}
</form>
);
}API Route Implementation
The newsletter API route handles Mailchimp integration:
import { env } from '@/env';
import { NextRequest, NextResponse } from 'next/server';
import { newsletterSchema } from '@/validationSchemas/newsletterSchema';
export async function POST(req: NextRequest) {
try {
const body = await req.json();
const validationResult = newsletterSchema.safeParse(body);
if (!validationResult.success) {
return NextResponse.json(
{ message: 'Invalid email address', ok: false },
{ status: 400 }
);
}
const { email } = validationResult.data;
const customUrl = `https://${env.MAILCHIMP_API_SERVER}.api.mailchimp.com/3.0/lists/${env.MAILCHIMP_AUDIENCE_ID}/members`;
const response = await fetch(customUrl, {
method: 'POST',
headers: {
Authorization: `Basic ${Buffer.from(`anystring:${env.MAILCHIMP_API_KEY}`).toString('base64')}`,
'Content-Type': 'application/json',
},
body: JSON.stringify({
email_address: email,
status: 'subscribed',
}),
});
if (!response.ok) {
return NextResponse.json(
{ message: 'Failed to subscribe', ok: false },
{ status: response.status }
);
}
return NextResponse.json(
{ message: 'Successfully subscribed!', ok: true },
{ status: 200 }
);
} catch (error) {
return NextResponse.json(
{ message: 'An error occurred', ok: false },
{ status: 500 }
);
}
}Best Practices
Email Sending
- Use descriptive "from" names:
MyApp <hello@myapp.com> - Keep subject lines under 50 characters
- Test emails before sending to users
- Handle errors gracefully with try-catch
- Use React templates for consistent branding
Newsletter Management
- Validate email addresses before subscribing
- Implement rate limiting on signup endpoint
- Provide unsubscribe links in emails
- Handle duplicate subscriptions gracefully
- Show clear success/error messages to users
Security
- Never expose API keys in client-side code
- Keep
.envin.gitignore - Validate all email inputs with Zod schemas
- Use rate limiting to prevent abuse
- Log errors server-side only
Next Steps
- Troubleshooting - Common issues and solutions
How is this guide ?
Last updated on