Menu
Back to Blog
1 min read
Automatisierung

Email Automation mit Resend & React Email

Moderne Email Automation. React Email Templates, Resend API, Transactional Emails und Email Sequenzen.

Email AutomationResendReact EmailTransactional EmailEmail TemplatesNodemailer
Email Automation mit Resend & React Email

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

npm install @react-email/components react-email resend
// 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 (
    <Html>
      <Head />
      <Preview>Willkommen bei unserer Plattform, {userName}!</Preview>

      <Body style={main}>
        <Container style={container}>
          <Img
            src="https://example.com/logo.png"
            width="120"
            height="40"
            alt="Logo"
            style={logo}
          />

          <Section style={content}>
            <Text style={heading}>Willkommen, {userName}! 👋</Text>

            <Text style={paragraph}>
              Vielen Dank für Ihre Registrierung. Bitte bestätigen Sie Ihre
              E-Mail-Adresse, um alle Funktionen nutzen zu können.
            </Text>

            <Button style={button} href={verificationUrl}>
              E-Mail bestätigen
            </Button>

            <Text style={paragraph}>
              Oder kopieren Sie diesen Link in Ihren Browser:
            </Text>

            <Text style={link}>{verificationUrl}</Text>
          </Section>

          <Hr style={hr} />

          <Section style={footer}>
            <Text style={footerText}>
              © 2026 Unser Unternehmen. Alle Rechte vorbehalten.
            </Text>
            <Link href="https://example.com/unsubscribe" style={footerLink}>
              Abmelden
            </Link>
          </Section>
        </Container>
      </Body>
    </Html>
  );
}

// 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

// 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 <noreply@example.com>',
    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 <security@example.com>',
    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 <orders@example.com>',
    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 <news@example.com>',
    to: r.email,
    subject: 'Unser Newsletter',
    react: NewsletterEmail(r.data)
  }));

  return resend.batch.send(emails);
}

Email Sequenzen (Drip Campaigns)

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<string, any>
) {
  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 <team@example.com>',
    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

// 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
// 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(/<html/);
    expect(html).toMatch(/<\/html>/);
  });
});

Webhook Handling (Delivery Status)

// 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