We use tracking cookies to understand how you use the product and help us improve it. For more information on how we store cookies, read our  privacy policy.

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:

lib/email/sendWelcomeEmail.ts
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:

emails/WelcomeEmail.tsx
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:

lib/email/sendWelcomeEmail.ts
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:

app/api/auth/welcome/route.ts
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:

lib/email/addContact.ts
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:

components/NewsletterForm.tsx
'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:

app/api/resend/newsletter/route.ts
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 .env in .gitignore
  • Validate all email inputs with Zod schemas
  • Use rate limiting to prevent abuse
  • Log errors server-side only

Next Steps

How is this guide ?

Last updated on