| name | resend-integration |
| description | Set up Resend email integration with newsletters, contact forms, and booking systems. Use when implementing email functionality with Resend Audiences, segments, topics, webhooks, and multi-domain accounts. |
Resend Integration
Complete guide for integrating Resend email services into Next.js applications with proper Audiences setup.
When to Use
- Setting up newsletter signups
- Adding contact form email notifications
- Implementing booking/calendar email confirmations
- Configuring email forwarding via webhooks
- Managing multi-domain Resend accounts
Resend Audiences Architecture
Resend has ONE audience per account. Use these features to organize:
| Feature | Purpose | Visibility |
|---|
| Contacts | Individual subscribers | - |
| Properties | Custom data fields (domain, source, company) | Internal |
| Segments | Internal groupings for targeting | Internal |
| Topics | User-facing email preferences | User can manage |
| Broadcasts | Campaign sending with auto-unsubscribe | - |
Multi-Domain Strategy
For accounts with multiple domains, tag contacts with properties:
await resend.contacts.create({
email,
properties: {
domain: "example.com",
source: "newsletter",
},
segments: [{ id: SEGMENT_ID }],
topics: [{ id: TOPIC_ID, subscription: "opt_in" }],
});
Implementation
1. Shared Utility (lib/resend.ts)
import { Resend } from "resend";
export const resend = new Resend(process.env.RESEND_API_KEY);
const SEGMENT_NEWSLETTER = process.env.RESEND_SEGMENT_NEWSLETTER;
const SEGMENT_LEADS = process.env.RESEND_SEGMENT_LEADS;
const TOPIC_NEWSLETTER = process.env.RESEND_TOPIC_NEWSLETTER;
type ContactSource = "newsletter" | "booking" | "contact";
interface CreateContactOptions {
email: string;
firstName?: string;
lastName?: string;
company?: string;
source: ContactSource;
subscribeToNewsletter?: boolean;
}
export async function createContact({
email,
firstName,
lastName,
company,
source,
subscribeToNewsletter = false,
}: CreateContactOptions) {
const segments: { id: }[] = [];
(source === && ) {
segments.({ : });
} ((source === || source === ) && ) {
segments.({ : });
}
: { : ; : | }[] = [];
(subscribeToNewsletter && ) {
topics.({ : , : });
}
: <, > = {
: ,
source,
};
(company) properties. = company;
{ data, error } = resend..({
email,
: firstName || ,
: lastName || ,
: ,
...(.(properties). > && { properties }),
...(segments. > && { segments }),
...(topics. > && { topics }),
});
(error?.?.()) {
{ : , : };
}
{ data, : , error };
}
(): <> {
{
{ data } = resend..({ email });
!!data;
} {
;
}
}
2. Newsletter Route (/api/newsletter)
import { NextResponse } from "next/server";
import { resend, createContact, contactExists } from "@/lib/resend";
export async function POST(request: Request) {
const { email } = await request.json();
if (!email) {
return NextResponse.json({ error: "Email is required" }, { status: 400 });
}
if (await contactExists(email)) {
return NextResponse.json(
{ error: "already_subscribed", message: "You're already subscribed!" },
{ status: 409 },
);
}
const { error } = await createContact({
email,
source: "newsletter",
subscribeToNewsletter: true,
});
if (error) {
const message = typeof error === "object" && error
? (error { : }).
: ;
statusCode = error === && error
? (error { : }).
: ;
.({ : message }, { : statusCode });
}
resend..({
: ,
: [email],
: ,
: ,
});
.({ : });
}
3. Frontend Duplicate Handling
const response = await fetch("/api/newsletter", {
method: "POST",
headers: { "Content-Type": "application/json" },
body: JSON.stringify({ email }),
});
const data = await response.json();
if (response.status === 409) {
toast.info("You're already subscribed!");
return;
}
if (!response.ok) {
throw new Error(data.error);
}
toast.success("Thanks for subscribing!");
4. Booking/Contact Form (Create Lead)
Add contact creation without blocking the main flow:
createContact({
email,
firstName,
lastName,
company,
source: "booking",
}).catch((err) => console.error("Failed to create contact:", err));
5. Inbound Email Forwarding
For receiving emails via subdomain (e.g., mail.example.com):
Webhook handler (/api/webhooks/resend):
case "email.received":
const forwardTo = process.env.EMAIL_FORWARD_TO?.split(",").map(e => e.trim());
if (!forwardTo?.length) return;
await resend.emails.send({
from: "Forwarded <forwarded@example.com>",
to: forwardTo,
replyTo: event.data.from,
subject: `[Fwd] ${event.data.subject}`,
html: `
<div style="padding: 16px; background: #f5f5f5;">
<p><strong>From:</strong> ${event.data.from}</p>
<p><strong>To:</strong> ${event.data.to?.join(", ")}</p>
</div>
<hr/>
${event.data.html || event.data.text}
`,
attachments: event.data.attachments,
});
break;
Environment Variables
RESEND_API_KEY=re_xxxxx
RESEND_SEGMENT_NEWSLETTER=seg_xxxxx
RESEND_SEGMENT_LEADS=seg_xxxxx
RESEND_TOPIC_NEWSLETTER=top_xxxxx
EMAIL_FORWARD_TO=email1@example.com,email2@example.com
Resend Dashboard Setup
IMPORTANT: Create these in the dashboard BEFORE deploying code that uses them.
Create Properties
Properties must exist before the API can use them.
- Go to Audiences → Properties tab
- Create these properties:
domain (text) - For multi-domain account filtering
source (text) - How contact signed up (newsletter, booking, contact)
company (text) - Optional company name
Create Segments
- Go to Audiences → Segments
- Create "project-newsletter" segment
- Create "project-leads" segment
- Copy IDs to env vars
Create Topics
- Go to Audiences → Topics
- Create topic (e.g., "Project Newsletter")
- Defaults to: Opt-in (subscribers must explicitly opt in)
- Visibility: Public (visible on preference page) or Private
- Copy ID to env var
Email Receiving (Subdomain)
To receive emails without conflicting with existing email (e.g., Google Workspace):
-
DNS: Add MX record for subdomain
- Name:
mail
- Content:
inbound-smtp.us-east-1.amazonaws.com
- Priority: 10
-
Resend: Enable receiving for mail.yourdomain.com
-
Webhook: Point to your /api/webhooks/resend endpoint
Broadcasts
Use Resend dashboard for sending newsletters:
- Go to Broadcasts → Create
- Select segment to target
- Use personalization:
{{{FIRST_NAME|there}}}
- Include unsubscribe:
{{{RESEND_UNSUBSCRIBE_URL}}}
- Send or schedule
Common Patterns
Sender Addresses
Use consistent from addresses:
noreply@domain.com - Automated notifications
contact@domain.com - Contact form
booking@domain.com - Calendar invites
forwarded@domain.com - Forwarded inbound emails
Team Notifications
Send internal notifications to a subdomain address that forwards:
to: ["info@mail.domain.com"]