Zum Inhalt springen
Doku

Anleitung

Eingehende E-Mails mit Webhooks verarbeiten

Abonnieren Sie mit einem Webhook das Event email.received, verifizieren Sie jede Anfrage und rufen Sie dann Body, Header und Anhänge jeder empfangenen Nachricht per API ab.

Aktualisiert am 1. Okt. 2026

Diese Anleitung zeigt, wie Sie in Ihrem eigenen Code auf empfangene E-Mails reagieren. Emailit benachrichtigt Ihren Endpunkt mit einem Event email.received, und Ihr Code ruft die vollständige Nachricht per API ab. Die Beispiele verifizieren die Signatur, verarbeiten Batches von Events, laden Anhänge herunter und überspringen Duplikate.

Voraussetzungen

  • Eingehende E-Mails sind eingerichtet, und eine Testnachricht erscheint im Tab Incoming.
  • Ein API-Schlüssel mit Full Access. Mit Schlüsseln mit Sending Only lassen sich E-Mail-Inhalte nicht lesen. Siehe API-Schlüssel.
  • Ein öffentlicher HTTPS-Endpunkt, der POST-Anfragen annimmt. Für die lokale Entwicklung nutzen Sie einen Tunnel wie ngrok oder Cloudflare Tunnel.

So funktioniert der Ablauf

Der Webhook teilt Ihnen mit, dass eine Nachricht angekommen ist. Er enthält weder Body noch Anhänge. Das hält die Anfragen klein, und Sie rufen Inhalte nur ab, wenn Sie sie brauchen.

email.received (one event in the request array)
{
  "event_id": "evt_2xGk9Tb4QmF6wN2cJpR7uZsE1kD",
  "type": "email.received",
  "object": {
    "id": "em_2xGk9Rz2NcV7bL4pWqH8sYdT5fA",
    "object": "email",
    "from": "ada@example.com",
    "to": "support@inbound.acme.com",
    "subject": "Question about order 1042",
    "created_at": "2026-10-01T09:14:05.317000+00:00"
  },
  "data": {
    "object": {
      "id": "em_2xGk9Rz2NcV7bL4pWqH8sYdT5fA",
      "object": "email",
      "from": "ada@example.com",
      "to": "support@inbound.acme.com",
      "subject": "Question about order 1042",
      "created_at": "2026-10-01T09:14:05.317000+00:00"
    }
  }
}

Verwenden Sie data.object.id mit E-Mail abrufen, um die geparste Nachricht zu erhalten:

GET /v2/emails/em_2xGk9Rz2NcV7bL4pWqH8sYdT5fA (abridged)
{
  "object": "email",
  "id": "em_2xGk9Rz2NcV7bL4pWqH8sYdT5fA",
  "type": "inbound",
  "status": "received",
  "from": "ada@example.com",
  "to": "support@inbound.acme.com",
  "subject": "Question about order 1042",
  "message_id": "<CAF3x1@mail.example.com>",
  "headers": {
    "From": "Ada Lovelace <ada@example.com>",
    "Reply-To": "ada@example.com",
    "Date": "Thu, 01 Oct 2026 09:14:02 +0000"
  },
  "body": {
    "text": "Hi, my order hasn't arrived yet...",
    "html": "<p>Hi, my order hasn't arrived yet...</p>"
  },
  "attachments": [
    {
      "filename": "receipt.pdf",
      "content_type": "application/pdf",
      "size": 48213,
      "content_id": null,
      "content_disposition": "attachment",
      "content": "JVBERi0xLjcKJcfsj6IK..."
    }
  ]
}

Das Feld content eines Anhangs ist Base64-kodiert. Header-Namen behalten ihre ursprüngliche Groß- und Kleinschreibung, und wenn ein Header mehrfach vorkommt (etwa Received), wird nur der letzte Wert behalten. Wenn Sie nur einen Teil der Nachricht brauchen, nutzen Sie die spezifischeren Endpunkte: Body abrufen, Anhänge auflisten oder Roh-MIME abrufen für die Originalquelle.

Webhook erstellen

  1. Webhook hinzufügen. Öffnen Sie Email APIWebhooks, wählen Sie Add webhook, geben Sie einen Namen und die URL Ihres Endpunkts ein und wählen Sie Create.

  2. Secret kopieren. Der Dialog zeigt das Webhook-Secret (whsec_…) einmalig an. Speichern Sie es als EMAILIT_WEBHOOK_SECRET in der Umgebung Ihrer App.

  3. Nur email.received abonnieren. Deaktivieren Sie im Tab Settings des Webhooks die Option All events, wählen Sie unter Emails das Event email.received und wählen Sie Save.

In den Tarifen Pro, Business und Custom können Sie einen Payload-Filter hinzufügen, damit der Webhook nur E-Mails für bestimmte Adressen erhält, zum Beispiel wenn to auf @inbound.acme.com endet.

Handler schreiben

Jeder Anfrage-Body ist ein JSON-Array mit bis zu 100 Events. Der folgende Handler verifiziert die Signatur, durchläuft das Array, überspringt alles, was nicht email.received ist oder bereits verarbeitet wurde, und ruft jede Nachricht ab.

server.js
import crypto from 'node:crypto';
import express from 'express';

const app = express();
const WEBHOOK_SECRET = process.env.EMAILIT_WEBHOOK_SECRET; // whsec_...
const API_KEY = process.env.EMAILIT_API_KEY; // secret_..., Full Access
const processed = new Set(); // use a database table with a unique key in production

function verify(rawBody, signature, timestamp) {
  if (!signature || !timestamp) return false;
  const age = Math.abs(Math.floor(Date.now() / 1000) - Number(timestamp));
  if (!(age <= 300)) return false; // 5-minute tolerance
  const expected = crypto
    .createHmac('sha256', WEBHOOK_SECRET)
    .update(`${timestamp}.`)
    .update(rawBody)
    .digest('hex');
  const a = Buffer.from(expected);
  const b = Buffer.from(signature);
  return a.length === b.length && crypto.timingSafeEqual(a, b);
}

async function fetchEmail(id) {
  const res = await fetch(`https://api.emailit.com/v2/emails/${id}`, {
    headers: { Authorization: `Bearer ${API_KEY}` },
  });
  if (!res.ok) throw new Error(`Emailit API returned ${res.status}`);
  return res.json();
}

async function handleReceived(event) {
  const email = await fetchEmail(event.data.object.id);
  console.log(`From ${email.from} to ${email.to}: ${email.subject}`);
  console.log(email.body.text ?? email.body.html);

  for (const file of email.attachments ?? []) {
    const bytes = Buffer.from(file.content, 'base64');
    console.log(`Attachment ${file.filename} (${file.content_type}, ${bytes.length} bytes)`);
  }
}

// Keep the raw body: the signature is computed over the exact bytes.
app.post('/webhooks/emailit', express.raw({ type: 'application/json' }), async (req, res) => {
  if (!verify(req.body, req.get('X-Emailit-Signature'), req.get('X-Emailit-Timestamp'))) {
    return res.status(401).send('Invalid signature');
  }

  const events = JSON.parse(req.body.toString('utf8'));
  try {
    for (const event of events) {
      if (event.type !== 'email.received' || processed.has(event.event_id)) continue;
      await handleReceived(event);
      processed.add(event.event_id);
    }
    res.sendStatus(200);
  } catch (err) {
    console.error(err);
    res.sendStatus(500); // Emailit retries the whole batch later
  }
});

app.listen(3000);

Wiederholungen und Duplikate behandeln

  • Antworten Sie innerhalb von 30 Sekunden. Emailit wartet bis zu 30 Sekunden auf eine 2xx-Antwort. Ein Timeout, ein anderer Status als 2xx oder eine Weiterleitung gilt als Fehlschlag, und der gesamte Batch wird nach dem Zeitplan für Wiederholungen erneut gesendet. Wenn Abruf und Verarbeitung länger dauern können, legen Sie die Events in einer Warteschlange ab, geben Sie 200 zurück und verarbeiten Sie sie in einem Hintergrundjob.
  • Entfernen Sie Duplikate anhand von event_id. Ein wiederholter Batch enthält erneut alle seine Events, auch solche, die Sie vor dem Fehlschlag bereits verarbeitet haben. Speichern Sie jede event_id nach der Verarbeitung und überspringen Sie bereits gesehene IDs. Jede empfangene Nachricht hat außerdem eine eigene E-Mail-ID, die Sie als zweiten Schlüssel verwenden können.
  • Bestätigen Sie auch Events, die Sie nicht verarbeiten. Geben Sie 2xx zurück, auch wenn ein Batch nur Event-Typen enthält, die Sie ignorieren. Sonst wiederholt Emailit sie immer weiter.
  • Rufen Sie Inhalte zügig ab. Nachrichteninhalte werden nur begrenzte Zeit aufbewahrt, abhängig von Ihrem Tarif (7 Tage bei Pay as you go). Danach liefert die API die E-Mail ohne Body und Anhänge. Siehe Datenaufbewahrung.

Nachrichten nach Adresse verteilen

Da jeder lokale Teil angenommen wird, können Sie Informationen in der Adresse kodieren und aus to wieder auslesen. Senden Sie zum Beispiel Benachrichtigungen mit reply_to auf reply+4821@inbound.acme.com und ordnen Sie Antworten dann Ticket 4821 zu:

JavaScript
const match = email.to.match(/^reply\+(\d+)@inbound\.acme\.com$/i);
if (match) {
  await addReplyToTicket(match[1], email.body.text);
}

Ergebnis prüfen

  1. Senden Sie eine Nachricht an eine Adresse auf Ihrer Inbound-Subdomain.
  2. Im Tab Requests des Webhooks zeigt die Anfrage email.received den Status Delivered.
  3. Ihre Anwendung protokolliert Absender, Betreff und etwaige Anhänge.

Zeigt die Anfrage Attempting oder Failed, wählen Sie in einer fehlgeschlagenen Zeile View, um den Statuscode und den Antwort-Body zu sehen, die Ihr Endpunkt zurückgegeben hat. Siehe Wiederholungen und Fehlschläge.

War diese Seite hilfreich?

Danke für Ihr Feedback.

Danke, wir lesen jede Nachricht.