Transaktionale Emails sind das Rueckgrat jeder SaaS-Anwendung. Ob Willkommens-Email, Passwort-Reset oder Rechnungsversand — Nutzer erwarten schnelle, zuverlässige Zustellung direkt in ihr Postfach.
Resend hat sich 2025/2026 als Developer-first Email-API etabliert: saubere SDK-Dokumentation, React Email Templates, und erstklassige Deliverability.
Mit Claude Code als KI-Coding-Assistent lassen sich Resend-Integrationen in einem Bruchteil der Zeit implementieren. Dieser Guide zeigt den vollstaendigen Stack: von der ersten Email bis zu Webhooks, Batch-Versand und Domain-Konfiguration mit SPF/DKIM/DMARC.
Setup 1. Installation und erste Email
Claude Code kann mit einem einzigen Prompt die komplette Resend-Integration aufsetzen. Starte mit dem Befehl: "Integriere Resend in mein Next.js 14 Projekt mit TypeScript, erstelle einen API-Route-Handler fuer transaktionale Emails".
Installation via npm
# Resend SDK installieren
npm install resend
# Optional: React Email fuer Template-Rendering
npm install @react-email/components react-email
API Key konfigurieren
Den API Key aus dem Resend Dashboard als Umgebungsvariable in .env.local ablegen:
# .env.local
RESEND_API_KEY=re_xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx
# .env.example (fuer das Team — ohne echten Key)
RESEND_API_KEY=re_your_api_key_here
Resend-Client initialisieren
// lib/resend.ts
import { Resend } from 'resend';
if (!process.env.RESEND_API_KEY) {
throw new Error('RESEND_API_KEY ist nicht gesetzt');
}
export const resend = new Resend(process.env.RESEND_API_KEY);
Erste Email senden — API Route Handler
// app/api/send-email/route.ts (Next.js App Router)
import { NextRequest, NextResponse } from 'next/server';
import { resend } from '@/lib/resend';
export async function POST(req: NextRequest) {
const { to, subject, html } = await req.json();
const { data, error } = await resend.emails.send({
from: 'Agentic Movers <noreply@agentic-movers.com>',
to: [to],
subject: subject,
html: html,
});
if (error) {
return NextResponse.json({ error }, { status: 400 });
}
return NextResponse.json({ data }, { status: 200 });
}
Claude Code Prompt-Tipp: "Erstelle einen typsicheren Resend-Wrapper mit Zod-Validierung fuer alle Email-Parameter und automatischem Retry bei Rate-Limits (429)." Claude generiert daraus direkt einen produktionsreifen Handler.
Test-Email aus der CLI senden
# Mit curl testen
curl -X POST http://localhost:3000/api/send-email \
-H "Content-Type: application/json" \
-d '{"to":"test@example.com","subject":"Test","html":"<p>Hallo!</p>"}'
# Oder direkt mit dem Resend-SDK aus Node.js
const { data, error } = await resend.emails.send({
from: 'onboarding@resend.dev', // Test-Absender ohne eigene Domain
to: ['you@example.com'],
subject: 'Hello from Resend!',
html: '<strong>Es funktioniert!</strong>',
});
Wichtig: Im kostenfreien Plan kann nur an die eigene registrierte Email-Adresse gesendet werden. Fuer den Produktionsbetrieb ist eine verifizierte Domain Pflicht — siehe Abschnitt 6 dieser Anleitung.
Templates 2. React Email Templates
React Email ist Resends offizielles Template-Framework. Es erlaubt, Email-Layouts mit React-Komponenten zu bauen, direkt im Browser zu previewing und per render() in HTML umzuwandeln — vollstaendig kompatibel mit allen grossen Email-Clients.
Basis-Template-Struktur
// emails/WelcomeEmail.tsx
import {
Body, Button, Container, Head,
Heading, Html, Preview, Section,
Text, Tailwind, Img,
} from '@react-email/components';
interface WelcomeEmailProps {
userName: string;
loginUrl: string;
logoUrl?: string;
}
export default function WelcomeEmail({
userName, loginUrl, logoUrl,
}: WelcomeEmailProps) {
return (
<Html lang="de">
<Head />
<Preview>Willkommen bei Agentic Movers, {userName}!</Preview>
<Tailwind>
<Body className="bg-gray-50 font-sans">
<Container className="max-w-xl mx-auto py-8 px-4">
{logoUrl && (
<Img src={logoUrl} alt="Logo"
width="120" className="mb-6" />
)}
<Heading className="text-2xl font-bold text-gray-900 mb-2">
Willkommen, {userName}! 🎉
</Heading>
<Text className="text-gray-600 mb-6">
Wir freuen uns, dich an Bord zu haben. Dein Account ist
aktiviert und bereit zur Nutzung.
</Text>
<Section className="text-center my-6">
<Button href={loginUrl}
className="bg-violet-600 text-white px-6 py-3 rounded-lg
font-semibold no-underline">
Jetzt einloggen
</Button>
</Section>
<Text className="text-gray-400 text-sm mt-8">
Du erhältst diese Email, weil du dich bei Agentic Movers
registriert hast. <a href="%unsubscribe_url%">Abmelden</a>
</Text>
</Container>
</Body>
</Tailwind>
</Html>
);
}
Template im Browser pruefen
# React Email Dev-Server starten
npx email dev
# Oeffnet http://localhost:3000 mit Live-Preview aller Templates
# Hot-Reload bei Aenderungen — kein Browser-Refresh noetig
Template rendern und versenden
// lib/send-welcome.ts
import { render } from '@react-email/render';
import { WelcomeEmail } from '@/emails/WelcomeEmail';
import { resend } from '@/lib/resend';
export async function sendWelcomeEmail(
userEmail: string,
userName: string,
) {
const html = await render(
<WelcomeEmail
userName={userName}
loginUrl="https://agentic-movers.com/login"
logoUrl="https://agentic-movers.com/logo.png"
/>
);
return resend.emails.send({
from: 'Agentic Movers <welcome@agentic-movers.com>',
to: [userEmail],
subject: `Willkommen bei Agentic Movers, ${userName}!`,
html,
});
}
Claude Code Workflow: "Erstelle eine React Email Template-Bibliothek mit WelcomeEmail, PasswordReset, InvoiceSent und TrialEnding. Alle Templates sollen eine einheitliche Header/Footer-Komponente teilen und mit TypeScript-Props typisiert sein."
Transaktional 3. Transaktionale Emails
Transaktionale Emails werden durch Nutzer-Aktionen ausgeloest — nicht durch Kampagnen. Sie haben die hoechste Oeffnungsrate und muessen zuverlaessig, schnell und personalisiertankommen. Claude Code hilft, alle Standard-Flows in einer konsistenten Email-Klasse zu buendeln.
Welcome Email
// emails/WelcomeEmail — Props + Versandlogik
await sendWelcomeEmail({
to: 'neue@nutzer.de',
userName: 'Maria',
trialEndDate: new Date(Date.now() + 14 * 24 * 60 * 60 * 1000),
planName: 'Professional',
});
Password-Reset Email
// lib/emails/password-reset.ts
export async function sendPasswordResetEmail({
to, resetToken, expiresInMinutes = 60,
}: PasswordResetParams) {
const resetUrl = `https://agentic-movers.com/reset?token=${resetToken}`;
const html = await render(
<PasswordResetEmail
resetUrl={resetUrl}
expiresInMinutes={expiresInMinutes}
/>
);
return resend.emails.send({
from: 'Agentic Movers <security@agentic-movers.com>',
to: [to],
subject: 'Passwort zuruecksetzen',
html,
headers: {
'X-Priority': '1', // Hohe Prioritaet
},
});
}
Invoice-Sent Email
// lib/emails/invoice.ts
export async function sendInvoiceEmail({
to, customerName, invoiceNumber,
amount, currency, pdfUrl, dueDate,
}: InvoiceEmailParams) {
const html = await render(
<InvoiceEmail
customerName={customerName}
invoiceNumber={invoiceNumber}
amount={formatCurrency(amount, currency)}
dueDate={formatDate(dueDate, 'de-DE')}
downloadUrl={pdfUrl}
/>
);
return resend.emails.send({
from: 'Agentic Movers <billing@agentic-movers.com>',
to: [to],
subject: `Rechnung ${invoiceNumber} — Agentic Movers`,
html,
attachments: [{
filename: `Rechnung-${invoiceNumber}.pdf`,
path: pdfUrl,
}],
});
}
Trial-Ending Reminder
// lib/emails/trial-ending.ts
// Wird 3 Tage vor Trial-Ende per Cron ausgeloest
export async function sendTrialEndingEmail({
to, userName, daysLeft, upgradeUrl,
}: TrialEndingParams) {
const html = await render(
<TrialEndingEmail
userName={userName}
daysLeft={daysLeft}
upgradeUrl={upgradeUrl}
/>
);
return resend.emails.send({
from: 'Agentic Movers <hello@agentic-movers.com>',
to: [to],
subject: `Nur noch ${daysLeft} Tag(e) — jetzt upgraden!`,
html,
tags: [
{ name: 'category', value: 'trial-ending' },
{ name: 'days-left', value: String(daysLeft) },
],
});
}
Best Practice: Resend-Tags (tags-Array) erlauben spaeter die genaue Segmentierung in Analytics. Claude Code prompt: "Fuege allen transaktionalen Emails konsistente Tags hinzu: category, user-segment, trigger-event."
Batch 4. Batch Emails und Audiences
Fuer Newsletter, Produktankuendigungen und Massenbenachrichtigungen bietet Resend resend.batch.send() sowie ein Audiences-System fuer Kontakt-Management — alles ohne externen ESP wie Mailchimp oder SendGrid.
Batch-Versand mit resend.batch.send()
// lib/emails/batch-sender.ts
import { resend } from '@/lib/resend';
import { render } from '@react-email/render';
import { NewsletterEmail } from '@/emails/NewsletterEmail';
export async function sendBatchNewsletter(
subscribers: Array<{ email: string; name: string }>,
subject: string,
content: string,
) {
// Resend Batch-Limit: 100 Emails pro Request
const BATCH_SIZE = 100;
const results = [];
for (let i = 0; i < subscribers.length; i += BATCH_SIZE) {
const chunk = subscribers.slice(i, i + BATCH_SIZE);
const emails = await Promise.all(
chunk.map(async (sub) => ({
from: 'Agentic Movers <newsletter@agentic-movers.com>',
to: [sub.email],
subject,
html: await render(
<NewsletterEmail name={sub.name} content={content} />
),
tags: [{ name: 'type', value: 'newsletter' }],
}))
);
const { data, error } = await resend.batch.send(emails);
results.push({ data, error, chunk: chunk.length });
// Rate-Limit: kurze Pause zwischen Batches
if (i + BATCH_SIZE < subscribers.length) {
await new Promise((r) => setTimeout(r, 1000));
}
}
return results;
}
Audiences — Kontakt-Management
// lib/audiences.ts — Resend Audiences API
import { resend } from '@/lib/resend';
const AUDIENCE_ID = process.env.RESEND_AUDIENCE_ID!;
// Kontakt zur Audience hinzufuegen
export async function addContact({
email, firstName, lastName, subscribed = true,
}: ContactParams) {
return resend.contacts.create({
audienceId: AUDIENCE_ID,
email,
firstName,
lastName,
unsubscribed: !subscribed,
});
}
// Kontakt abmelden (DSGVO-konform)
export async function unsubscribeContact(email: string) {
const contacts = await resend.contacts.list({ audienceId: AUDIENCE_ID });
const contact = contacts.data?.data?.find(c => c.email === email);
if (contact) {
return resend.contacts.update({
audienceId: AUDIENCE_ID,
id: contact.id,
unsubscribed: true,
});
}
}
// Alle Kontakte einer Audience abrufen
export async function listContacts() {
return resend.contacts.list({ audienceId: AUDIENCE_ID });
}
DSGVO-Hinweis: Audiences muessen mit explizitem Opt-in befuellt werden. Stelle sicher, dass jeder Kontakt eine verifizierbare Einwilligung gegeben hat. Resend bietet einen eingebauten unsubscribed-Flag, der bei Batch-Versand automatisch respektiert wird.
Webhooks 5. Webhooks und Email-Events
Resend sendet Webhook-Events fuer jeden relevanten Zustandswechsel einer Email. Mit Claude Code laesst sich ein robuster Webhook-Handler aufsetzen, der Bounces trackt, Spam-Complaints verarbeitet und Delivery-Metriken in die eigene Datenbank schreibt.
Verfuegbare Events
email.sent — Email an SMTP-Server uebergeben
email.delivered — Erfolgreich zugestellt (bestaetigt)
email.delivery_delayed — Zustellung verzoegert (Retry laeuft)
email.bounced — Hard oder Soft Bounce
email.complained — Nutzer hat Spam gemeldet
email.opened — Email geoeffnet (Pixel-Tracking)
email.clicked — Link in der Email geklickt
Webhook-Endpoint mit Signatur-Verifikation
// app/api/webhooks/resend/route.ts
import { NextRequest, NextResponse } from 'next/server';
import { Webhook } from 'svix'; // Resend nutzt Svix fuer Webhooks
const WEBHOOK_SECRET = process.env.RESEND_WEBHOOK_SECRET!;
export async function POST(req: NextRequest) {
const body = await req.text();
const headers = req.headers;
// Svix Signatur-Header
const svixId = headers.get('svix-id');
const svixTimestamp = headers.get('svix-timestamp');
const svixSignature = headers.get('svix-signature');
if (!svixId || !svixTimestamp || !svixSignature) {
return NextResponse.json({ error: 'Missing svix headers' }, { status: 400 });
}
let event;
try {
const wh = new Webhook(WEBHOOK_SECRET);
event = wh.verify(body, {
'svix-id': svixId,
'svix-timestamp': svixTimestamp,
'svix-signature': svixSignature,
}) as ResendWebhookEvent;
} catch {
return NextResponse.json({ error: 'Invalid signature' }, { status: 401 });
}
// Event-Handler
switch (event.type) {
case 'email.delivered':
await handleDelivered(event.data);
break;
case 'email.bounced':
await handleBounce(event.data);
break;
case 'email.complained':
await handleComplaint(event.data);
break;
}
return NextResponse.json({ received: true });
}
Bounce-Handler — Email sperren
// lib/webhooks/handlers.ts
async function handleBounce(data: ResendBounceData) {
const { email_id, to, bounce_type } = data;
// Hard Bounce: Email dauerhaft sperren
if (bounce_type === 'hard') {
await db.emailSuppressions.upsert({
email: to[0],
reason: 'hard_bounce',
emailId: email_id,
suppressedAt: new Date(),
});
await unsubscribeContact(to[0]);
console.warn(`Hard bounce: ${to[0]} gesperrt`);
}
// Soft Bounce: Retry-Counter erhoehen
if (bounce_type === 'soft') {
await db.emailMetrics.increment({
email: to[0],
field: 'soft_bounce_count',
});
}
}
async function handleComplaint(data: ResendComplaintData) {
// DSGVO: Sofort abmelden + in Suppression List aufnehmen
await Promise.all([
unsubscribeContact(data.to[0]),
db.emailSuppressions.upsert({
email: data.to[0],
reason: 'spam_complaint',
}),
]);
}
Svix installieren: npm install svix — Resend verwendet Svix fuer Webhook-Signierung. Die Bibliothek verifiziert Timestamp und HMAC-Signatur, verhindert Replay-Angriffe und prueft Zeitfenster (max. 5 Minuten Abweichung).
Domain 6. Domain-Konfiguration: SPF, DKIM, DMARC
Ohne korrekte DNS-Konfiguration landen Emails im Spam-Ordner. Resend prueft SPF, DKIM und DMARC automatisch und zeigt den Status im Dashboard an. Claude Code kann den Setup-Prozess dokumentieren und bei der Validierung helfen.
Schritt 1: Domain in Resend hinzufuegen
# Resend CLI (falls installiert)
npx resend domains add agentic-movers.com
# Oder via API:
const domain = await resend.domains.create({
name: 'agentic-movers.com',
region: 'eu-west-1', // EU fuer DSGVO-Konformitaet
});
Schritt 2: DNS-Records setzen
Resend liefert nach der Domain-Anlage drei DNS-Eintraege, die beim Hoster eingetragen werden muessen:
| Typ |
Name |
Wert |
TTL |
| TXT |
resend._domainkey |
p=MIGfMA0GCSq... (DKIM Public Key) |
3600 |
| TXT |
@ |
v=spf1 include:amazonses.com ~all |
3600 |
| MX |
send |
feedback-smtp.eu-west-1.amazonses.com (Prio 10) |
3600 |
Schritt 3: DMARC hinzufuegen
# DMARC TXT-Record (beim DNS-Anbieter eintragen)
# Name: _dmarc.agentic-movers.com
# Typ: TXT
# TTL: 3600
## Stufenweise Einführung empfohlen:
# Phase 1: Monitoring (none — kein Blocking)
v=DMARC1; p=none; rua=mailto:dmarc@agentic-movers.com; ruf=mailto:dmarc@agentic-movers.com; pct=100
# Phase 2: Quarantine (nach 2-4 Wochen, wenn Reports OK)
v=DMARC1; p=quarantine; pct=25; rua=mailto:dmarc@agentic-movers.com
# Phase 3: Enforce (nach weiteren 4 Wochen)
v=DMARC1; p=reject; pct=100; rua=mailto:dmarc@agentic-movers.com
Schritt 4: Subdomain als Absender
// Subdomain-Sender fuer bessere Deliverability-Isolation
// Statt: noreply@agentic-movers.com
// Besser: noreply@mail.agentic-movers.com (eigene Reputation)
const senders = {
transactional: 'Agentic Movers <noreply@mail.agentic-movers.com>',
billing: 'Agentic Movers Billing <billing@mail.agentic-movers.com>',
newsletter: 'Agentic Movers News <news@newsletter.agentic-movers.com>',
};
Schritt 5: Domain-Verifizierung pruefen
// DNS-Propagation pruefen (dauert 5 Min bis 48h)
const domains = await resend.domains.list();
console.log(domains.data?.data?.[0].status);
// 'not_started' | 'pending' | 'verified' | 'failed'
# CLI: Schnellcheck mit dig
dig TXT resend._domainkey.agentic-movers.com +short
dig TXT agentic-movers.com +short | grep spf
dig TXT _dmarc.agentic-movers.com +short
Deliverability-Tipp: Teste deine Email-Konfiguration kostenlos mit
mail-tester.com — gibt einen Score von 1-10 und zeigt genau wo noch Probleme sind (SPF alignment, DKIM missing, etc.). Ziel: 9+ fuer optimale Inbox-Platzierung.
Achtung Shared Domains: Resends geteilte Test-Domain onboarding@resend.dev eignet sich NUR fuer lokale Tests. Fuer alle Produktions-Emails MUSS eine eigene verifizierte Domain verwendet werden — sonst riskierst du Deliverability-Probleme fuer alle Resend-Nutzer.
Fazit: Resend + Claude Code = Moderner Email-Stack
Resend ist 2026 der Standard fuer Developer-first Email-Infrastruktur. Die Kombination aus sauberem TypeScript-SDK, React Email Templates, Audiences-Management und robusten Webhooks deckt alles ab, was SaaS-Anwendungen benoetigen — ohne den Overhead grosser ESPs.
Claude Code beschleunigt den Setup erheblich: Template-Generierung, Webhook-Handler mit Signatur-Verifikation, typsichere Wrapper und vollstaendige DNS-Dokumentation entstehen in Minuten statt Stunden. Der entscheidende Vorteil ist die Fehlerfreiheit — KI-generierter Code auf Basis der offiziellen Resend-Doku minimiert Copy-Paste-Fehler bei API-Keys, Header-Namen und Event-Typen.
Quick-Reference: Wichtigste Commands
# Installation
npm install resend @react-email/components @react-email/render svix
# Template-Entwicklung
npx email dev
# Domain-Status pruefen
dig TXT resend._domainkey.yourdomain.com +short
# Test-Email senden (ohne eigene Domain)
await resend.emails.send({
from: 'onboarding@resend.dev',
to: ['your@email.com'],
subject: 'Test',
html: '<p>Hello!</p>',
});
KI-gestuetzte Workflows fuer dein Team
Agentic Movers hilft dir, Claude Code und moderne APIs wie Resend in deinen Entwicklungs-Workflow zu integrieren — von der ersten Email bis zum produktionsreifen System.
Kostenlos 14 Tage testen →