# E-Mails mit Next.js senden

> Senden Sie E-Mails aus Route Handlers und Server Actions von Next.js mit dem Node.js-SDK von Emailit, halten Sie den API-Schlüssel auf dem Server und verifizieren Sie Webhooks.

Diese Anleitung zeigt, wie Sie E-Mails aus einer Next.js-App mit dem SDK `@emailit/node` senden, sowohl aus einem Route Handler als auch aus einer Server Action, und wie Sie Emailit-Webhooks verifizieren. Die Beispiele verwenden den App Router; der Pages Router folgt am Ende des Abschnitts zum Senden.

## Voraussetzungen

- Next.js 14 oder neuer. Das SDK erfordert Node.js 18 oder neuer.
- Eine [verifizierte Versanddomain](/de/docs/domains/add-a-domain/), zum Beispiel `acme.com`.
- Ein [API-Schlüssel](/de/docs/developers/api-keys/). Ein reiner Sende-Schlüssel, der auf Ihre Domain beschränkt ist, genügt.
- Solange Ihr Workspace keinen [Produktionszugang](/de/docs/workspaces/production-access/) hat, können Sie nur an die Konto-E-Mail-Adressen von Workspace-Mitgliedern senden.

## SDK installieren

```bash
npm install @emailit/node server-only
```

`server-only` lässt den Build fehlschlagen, wenn eine Client-Komponente das Modul importiert, das Ihren Schlüssel enthält.

## API-Schlüssel konfigurieren

Legen Sie den Schlüssel für die Entwicklung in `.env.local` und für die Produktion in den Umgebungsvariablen Ihres Hosters ab (zum Beispiel in den Projekteinstellungen von Vercel):

```bash title=".env.local"
EMAILIT_API_KEY=secret_••••••••••••••••••••••••••••••••
EMAILIT_WEBHOOK_SECRET=whsec_••••••••
```

> **Schlüssel nie im Browser offenlegen:** Versehen Sie diese Variablen nicht mit dem Präfix `NEXT_PUBLIC_` und rufen Sie Emailit nicht aus Client-Komponenten auf. Alles mit dem Präfix `NEXT_PUBLIC_` landet im JavaScript-Bundle, das jeder Besucher lesen kann.

Erstellen Sie einen Client in einem reinen Server-Modul:

```typescript title="lib/emailit.ts"

```

Das SDK hat noch keine TypeScript-Deklarationen. Wenn der Compiler sich beschwert, fügen Sie eine Deklarationsdatei hinzu:

```typescript title="types/emailit.d.ts"
declare module '@emailit/node';
```

## Aus einem Route Handler senden

Ein Route Handler ist der richtige Ort für Versände, die Ihr eigenes Frontend oder andere Dienste auslösen. Dieser Handler für ein Kontaktformular sendet an eine feste interne Adresse, sodass Besucher ihn nicht nutzen können, um beliebigen Personen E-Mails zu schicken:

```typescript title="app/api/contact/route.ts"

  const { email, message } = await request.json();

  if (typeof email !== 'string' || typeof message !== 'string' || !email.includes('@')) {
    return Response.json({ error: 'Invalid input' }, { status: 400 });
  }

  try {
    const sent = await emailit.emails.send({
      from: 'Acme website <website@acme.com>',
      to: 'support@acme.com',
      reply_to: email,
      subject: 'New contact form message',
      text: message,
    });
    return Response.json({ id: sent.id });
  } catch (error) {
    console.error(error);
    return Response.json({ error: 'Could not send the message' }, { status: 502 });
  }
}
```

Rufen Sie ihn im Browser mit `fetch('/api/contact', { method: 'POST', body: JSON.stringify(data) })` auf. Der Schlüssel verlässt nie den Server.

## Aus einer Server Action senden

Server Actions laufen auf dem Server und können den Client daher direkt verwenden:

```typescript title="app/signup/actions.ts"
'use server';

  const email = formData.get('email');
  if (typeof email !== 'string' || !email.includes('@')) return;

  // Create the account here, then send the welcome email.
  await emailit.emails.send({
    from: 'Acme <hello@acme.com>',
    to: email,
    template: 'welcome',
    variables: { email },
  });
}
```

```tsx title="app/signup/page.tsx"

  return (
    <form action={signUp}>
      <input type="email" name="email" required />
      <button type="submit">Create account</button>
    </form>
  );
}
```

`template` akzeptiert einen Vorlagen-Alias oder eine `tem_`-ID; siehe [Vorlagen](/de/docs/templates/). Server Actions sind öffentliche Endpunkte; validieren Sie deshalb die Eingaben und ergänzen Sie vor dem Senden Ihren üblichen Schutz vor Bots und Missbrauch.

### Pages Router

Mit dem Pages Router senden Sie stattdessen aus einer API-Route:

```typescript title="pages/api/contact.ts"

  if (req.method !== 'POST') return res.status(405).end();
  const sent = await emailit.emails.send({
    from: 'Acme website <website@acme.com>',
    to: 'support@acme.com',
    subject: 'New contact form message',
    text: String(req.body.message ?? ''),
  });
  res.status(200).json({ id: sent.id });
}
```

## Alternativ per SMTP senden

Wenn Sie bereits Nodemailer verwenden, konfigurieren Sie es in einem Route Handler oder einer Server Action mit dem Emailit-Relay (SMTP erfordert die Node.js-Runtime, nicht die Edge-Runtime):

```typescript title="lib/mailer.ts"

  host: 'smtp.emailit.com',
  port: 587,
  secure: false,
  requireTLS: true,
  auth: { user: 'emailit', pass: process.env.EMAILIT_API_KEY },
});
```

Rufen Sie dann `await mailer.sendMail({ from, to, subject, html })` auf. Serverless-Funktionen öffnen bei den meisten Aufrufen eine neue SMTP-Verbindung; auf Vercel und ähnlichen Plattformen ist die API daher meist schneller. Siehe [SMTP-Einstellungen](/de/docs/smtp/settings/).

## Webhooks empfangen

[Erstellen Sie einen Webhook](/de/docs/webhooks/set-up/), der auf `https://your-app.com/api/webhooks/emailit` zeigt. Der Handler muss die Signatur anhand des unveränderten Bodys verifizieren; lesen Sie ihn deshalb vor dem Parsen mit `request.text()`:

```typescript title="app/api/webhooks/emailit/route.ts"

type EmailitEvent = {
  event_id: string;
  type: string;
  data: { object: Record<string, unknown> };
};

function isValid(rawBody: string, signature: string | null, timestamp: string | null) {
  if (!signature || !timestamp) return false;
  const age = Math.abs(Math.floor(Date.now() / 1000) - Number(timestamp));
  if (!Number.isFinite(age) || age > 300) return false;
  const expected = createHmac('sha256', process.env.EMAILIT_WEBHOOK_SECRET!)
    .update(`${timestamp}.${rawBody}`)
    .digest('hex');
  const a = Buffer.from(expected);
  const b = Buffer.from(signature);
  return a.length === b.length && timingSafeEqual(a, b);
}

  const rawBody = await request.text();
  const valid = isValid(
    rawBody,
    request.headers.get('x-emailit-signature'),
    request.headers.get('x-emailit-timestamp'),
  );
  if (!valid) return new Response('Invalid signature', { status: 401 });

  // Each request carries an array of up to 100 events.
  const events = JSON.parse(rawBody) as EmailitEvent[];
  for (const event of events) {
    if (event.type === 'email.bounced') {
      // Flag event.data.object.to in your database.
    }
  }

  return new Response(null, { status: 200 });
}
```

Geben Sie innerhalb von 30 Sekunden einen `2xx`-Status zurück; bei anderen Antworten wird die Anfrage wiederholt. Siehe [Anfragesignatur](/de/docs/webhooks/request-signature/) und [Event-Typen](/de/docs/webhooks/event-types/).

## Tipps für den Produktivbetrieb

- **Versand auf dem Server halten.** Nur `lib/emailit.ts`, Route Handlers und Server Actions sollten mit dem Schlüssel arbeiten. `server-only` erzwingt das beim Build.
- **Den Client nie den Absender wählen lassen.** Hinterlegen Sie `from` fest im Code und übernehmen Sie `to` nur dann aus dem Browser, wenn es die eigene Adresse des angemeldeten Nutzers ist.
- **Öffentliche Endpunkte schützen.** Begrenzen Sie die Anfragerate von Kontaktformularen und Registrierungsaktionen und ergänzen Sie ein CAPTCHA, wenn Bots sie finden. Jede E-Mail kostet Credits und zählt gegen Ihre [Versandlimits](/de/docs/limits/).
- **Variablen pro Umgebung setzen.** Verwenden Sie getrennte Schlüssel für Preview- und Produktions-Deployments, damit Sie einen widerrufen können, ohne den anderen zu beeinträchtigen.

## Nächste Schritte

  - [Anleitung für Node.js](/de/docs/frameworks/nodejs/): Fehlerbehandlung und Nodemailer im Detail.
  - [E-Mails per API senden](/de/docs/email-api/send-email/): Anhänge, Planung und Tracking.
  - [Vorlagen](/de/docs/templates/): E-Mails einmal gestalten und per Alias senden.
  - [API-Schlüssel](/de/docs/developers/api-keys/): Scopes, Domain-Beschränkungen und Rotation.

---
Quelle: https://emailit.com/de/docs/frameworks/nextjs/
