# Email Automation mit Resend & React Email **Meta-Description:** Moderne Email Automation. React Email Templates, Resend API, Transactional Emails und Email Sequenzen. **Keywords:** Email Automation, Resend, React Email, Transactional Email, Email Templates, Nodemailer, SMTP --- ## Einführung Email bleibt der wichtigste Kommunikationskanal. Mit **React Email** und **Resend** werden Email-Templates zu First-Class React Components – testbar, typsicher und versioniert. --- ## Email Stack 2026 ``` ┌─────────────────────────────────────────────────────────────┐ │ MODERN EMAIL STACK │ ├─────────────────────────────────────────────────────────────┤ │ │ │ Template Layer: │ │ ├── React Email (JSX → HTML) │ │ ├── MJML Alternative │ │ └── Tailwind Email Support │ │ │ │ Delivery Layer: │ │ ├── Resend (Developer-First) │ │ ├── SendGrid │ │ ├── Postmark │ │ └── AWS SES │ │ │ │ Features: │ │ ├── Transactional (Welcome, Reset, etc.) │ │ ├── Marketing (Newsletters) │ │ ├── Sequences (Drip Campaigns) │ │ └── Webhooks (Delivery Status) │ │ │ └─────────────────────────────────────────────────────────────┘ ``` --- ## React Email Setup ```bash npm install @react-email/components react-email resend ``` ```typescript // emails/welcome.tsx import { Html, Head, Preview, Body, Container, Section, Text, Button, Img, Hr, Link } from '@react-email/components'; interface WelcomeEmailProps { userName: string; verificationUrl: string; } export default function WelcomeEmail({ userName, verificationUrl }: WelcomeEmailProps) { return ( Willkommen bei unserer Plattform, {userName}! Logo
Willkommen, {userName}! 👋 Vielen Dank für Ihre Registrierung. Bitte bestätigen Sie Ihre E-Mail-Adresse, um alle Funktionen nutzen zu können. Oder kopieren Sie diesen Link in Ihren Browser: {verificationUrl}

© 2026 Unser Unternehmen. Alle Rechte vorbehalten. Abmelden
); } // Styles const main = { backgroundColor: '#f6f9fc', fontFamily: '-apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, sans-serif' }; const container = { backgroundColor: '#ffffff', margin: '0 auto', padding: '20px 0', maxWidth: '600px' }; const logo = { margin: '0 auto 20px', display: 'block' }; const content = { padding: '0 40px' }; const heading = { fontSize: '24px', fontWeight: 'bold', color: '#1a1a1a', marginBottom: '20px' }; const paragraph = { fontSize: '16px', lineHeight: '26px', color: '#484848' }; const button = { backgroundColor: '#5046e5', borderRadius: '8px', color: '#ffffff', fontSize: '16px', fontWeight: 'bold', textDecoration: 'none', textAlign: 'center' as const, display: 'block', padding: '14px 24px', margin: '20px 0' }; const link = { color: '#5046e5', fontSize: '14px', wordBreak: 'break-all' as const }; const hr = { borderColor: '#e6ebf1', margin: '20px 0' }; const footer = { padding: '0 40px' }; const footerText = { fontSize: '12px', color: '#9ca299' }; const footerLink = { color: '#9ca299', fontSize: '12px' }; ``` --- ## Resend Integration ```typescript // lib/email.ts import { Resend } from 'resend'; import WelcomeEmail from '@/emails/welcome'; import PasswordResetEmail from '@/emails/password-reset'; import OrderConfirmationEmail from '@/emails/order-confirmation'; const resend = new Resend(process.env.RESEND_API_KEY); // Single Email senden export async function sendWelcomeEmail( to: string, userName: string, verificationUrl: string ) { const { data, error } = await resend.emails.send({ from: 'Unser Team ', to, subject: `Willkommen, ${userName}!`, react: WelcomeEmail({ userName, verificationUrl }) }); if (error) { console.error('Email send error:', error); throw error; } return data; } // Password Reset export async function sendPasswordResetEmail( to: string, resetUrl: string ) { return resend.emails.send({ from: 'Sicherheit ', to, subject: 'Passwort zurücksetzen', react: PasswordResetEmail({ resetUrl }) }); } // Order Confirmation mit Anhang export async function sendOrderConfirmation( to: string, order: Order, invoicePdf: Buffer ) { return resend.emails.send({ from: 'Shop ', to, subject: `Bestellbestätigung #${order.id}`, react: OrderConfirmationEmail({ order }), attachments: [ { filename: `Rechnung-${order.id}.pdf`, content: invoicePdf } ] }); } // Batch Send export async function sendBulkEmails( recipients: Array<{ email: string; data: any }> ) { const emails = recipients.map(r => ({ from: 'Newsletter ', to: r.email, subject: 'Unser Newsletter', react: NewsletterEmail(r.data) })); return resend.batch.send(emails); } ``` --- ## Email Sequenzen (Drip Campaigns) ```typescript import { Queue, Worker } from 'bullmq'; import IORedis from 'ioredis'; const connection = new IORedis(process.env.REDIS_URL!); const emailQueue = new Queue('email-sequences', { connection }); // Sequence Definition interface EmailSequence { id: string; name: string; steps: Array<{ delay: number; // Millisekunden template: string; subject: string; }>; } const onboardingSequence: EmailSequence = { id: 'onboarding', name: 'Onboarding Sequence', steps: [ { delay: 0, template: 'welcome', subject: 'Willkommen bei uns!' }, { delay: 24 * 60 * 60 * 1000, // 1 Tag template: 'getting-started', subject: 'Erste Schritte' }, { delay: 3 * 24 * 60 * 60 * 1000, // 3 Tage template: 'tips', subject: '5 Tipps für den Einstieg' }, { delay: 7 * 24 * 60 * 60 * 1000, // 7 Tage template: 'feedback', subject: 'Wie gefällt es Ihnen?' } ] }; // Sequence starten async function startEmailSequence( userId: string, email: string, sequenceId: string, userData: Record ) { const sequence = getSequenceById(sequenceId); if (!sequence) throw new Error(`Sequence ${sequenceId} not found`); // Sequence State speichern await db.emailSequenceState.create({ data: { userId, sequenceId, currentStep: 0, status: 'active' } }); // Jobs für jeden Step einplanen for (let i = 0; i < sequence.steps.length; i++) { const step = sequence.steps[i]; await emailQueue.add( 'send-sequence-email', { userId, email, sequenceId, stepIndex: i, template: step.template, subject: step.subject, userData }, { delay: step.delay, jobId: `${userId}-${sequenceId}-${i}` } ); } } // Worker für Sequence Emails const worker = new Worker('email-sequences', async (job) => { const { userId, email, sequenceId, stepIndex, template, subject, userData } = job.data; // Prüfen ob Sequence noch aktiv const state = await db.emailSequenceState.findFirst({ where: { userId, sequenceId } }); if (state?.status !== 'active') { console.log(`Sequence ${sequenceId} for user ${userId} is not active, skipping`); return; } // Email senden const EmailComponent = getEmailTemplate(template); await resend.emails.send({ from: 'Unser Team ', to: email, subject, react: EmailComponent(userData) }); // State updaten await db.emailSequenceState.update({ where: { id: state.id }, data: { currentStep: stepIndex + 1 } }); console.log(`Sent sequence email: ${template} to ${email}`); }, { connection }); // Sequence abbrechen async function cancelEmailSequence(userId: string, sequenceId: string) { // State updaten await db.emailSequenceState.updateMany({ where: { userId, sequenceId }, data: { status: 'cancelled' } }); // Pending Jobs entfernen const jobs = await emailQueue.getJobs(['delayed', 'waiting']); for (const job of jobs) { if (job.data.userId === userId && job.data.sequenceId === sequenceId) { await job.remove(); } } } ``` --- ## Email Preview & Testing ```typescript // email-preview.ts (Development) import { render } from '@react-email/render'; import WelcomeEmail from '@/emails/welcome'; // HTML Preview generieren const html = render(WelcomeEmail({ userName: 'Max Mustermann', verificationUrl: 'https://example.com/verify?token=abc123' })); console.log(html); // React Email Dev Server // package.json { "scripts": { "email:dev": "email dev --port 3001" } } // Dann: npm run email:dev // Browser: http://localhost:3001 ``` ```typescript // Email Testing mit Jest import { render } from '@react-email/render'; import WelcomeEmail from '@/emails/welcome'; describe('WelcomeEmail', () => { it('renders with correct user name', () => { const html = render(WelcomeEmail({ userName: 'Test User', verificationUrl: 'https://example.com/verify' })); expect(html).toContain('Test User'); expect(html).toContain('Willkommen'); }); it('includes verification link', () => { const html = render(WelcomeEmail({ userName: 'Test User', verificationUrl: 'https://example.com/verify?token=123' })); expect(html).toContain('https://example.com/verify?token=123'); }); it('has valid HTML structure', () => { const html = render(WelcomeEmail({ userName: 'Test User', verificationUrl: 'https://example.com/verify' })); expect(html).toMatch(//); }); }); ``` --- ## Webhook Handling (Delivery Status) ```typescript // app/api/webhooks/resend/route.ts import { NextRequest, NextResponse } from 'next/server'; import { Webhook } from 'svix'; const webhookSecret = process.env.RESEND_WEBHOOK_SECRET!; export async function POST(request: NextRequest) { const payload = await request.text(); const headers = { 'svix-id': request.headers.get('svix-id')!, 'svix-timestamp': request.headers.get('svix-timestamp')!, 'svix-signature': request.headers.get('svix-signature')! }; const wh = new Webhook(webhookSecret); let event: any; try { event = wh.verify(payload, headers); } catch (err) { return NextResponse.json({ error: 'Invalid signature' }, { status: 400 }); } // Event Type handling switch (event.type) { case 'email.sent': await handleEmailSent(event.data); break; case 'email.delivered': await handleEmailDelivered(event.data); break; case 'email.opened': await handleEmailOpened(event.data); break; case 'email.clicked': await handleEmailClicked(event.data); break; case 'email.bounced': await handleEmailBounced(event.data); break; case 'email.complained': await handleEmailComplained(event.data); break; } return NextResponse.json({ received: true }); } async function handleEmailBounced(data: any) { // Email-Adresse als ungültig markieren await db.user.update({ where: { email: data.to }, data: { emailStatus: 'bounced' } }); } async function handleEmailComplained(data: any) { // Spam-Beschwerde: User aus Listen entfernen await db.user.update({ where: { email: data.to }, data: { marketingOptIn: false } }); } ``` --- ## Fazit Moderne Email Automation braucht: 1. **React Email**: Component-basierte Templates 2. **Resend**: Developer-First API 3. **Sequences**: Automatisierte Drip Campaigns 4. **Webhooks**: Delivery Tracking Email als Code – testbar, typsicher, versioniert. --- ## Bildprompts 1. "Email template components assembling like Lego blocks, React Email concept" 2. "Email sequence timeline with automated sends, drip campaign visualization" 3. "Delivery status tracking with checkmarks, email analytics dashboard" --- ## Quellen - [React Email Documentation](https://react.email/) - [Resend Documentation](https://resend.com/docs) - [Email Accessibility Guidelines](https://www.emailonacid.com/blog/article/email-development/email-accessibilty-in-2019/) - [Can I Email](https://www.caniemail.com/)