QMailing
ProduktPreiseAPI & MCP
Anmelden

Dokumentation

Öffentliche API & MCP-Server

Bauen Sie Agenten, CLIs und Backoffice-Integrationen auf QMailing auf. PLUS und höher schaltet Bearer-Token-Authentifizierung an jedem öffentlichen Endpunkt frei – plus einen fertigen MCP-Server, den Sie in Claude Desktop, Cursor oder einen beliebigen anderen kompatiblen Client einbinden können.

Loslegen Token verwalten

Auf dieser Seite

  • 1. Erste Schritte
  • 2. Authentifizierung
  • 3. Scopes
  • 4. Postfächer
  • 5. Domains & DNS
  • 6. E-Mail
  • 7. Webhooks
  • 8. Fehler
  • 9. Rate Limits
  • 10. MCP-Server

Erste Schritte

  1. 1. Auf PLUS upgraden — die öffentliche API ist auf PLUS, PRO, PRO_PLUS oder PRO_MAX verfügbar. FREE-Aufrufer erhalten unabhängig vom Token 402 Payment Required.
  2. 2. Token erstellen — gehen Sie zu Einstellungen → Entwickler, klicken Sie auf Neues Token, wählen Sie die benötigten Scopes und kopieren Sie den qm_live_…-Wert, sobald er angezeigt wird. Token erscheinen nur einmal.
  3. 3. Führen Sie Ihren ersten Aufruf aus:
    curl https://qmailing.com/api/v1/pub/mailboxes \
      -H "Authorization: Bearer qm_live_your_token_here"

Authentifizierung

Jeder Aufruf der öffentlichen API trägt einen Authorization: Bearer qm_live_<…>-Header. Das Token-Format ist mit Namespace versehen (qm_live_ gefolgt von 32 zufälligen Zeichen), sodass Lecks in Logs und Repositories sofort auffallen.

Token werden gehasht (SHA-256) gespeichert. Der Klartext wird zum Erstellungszeitpunkt genau einmal angezeigt und nie wieder — wenn Sie ihn verlieren, erstellen Sie ein neues. Jede Anfrage löst einen Hash-Vergleich in konstanter Zeit aus; last_used_at wird bei Erfolg aktualisiert, damit die Entwickler-UI veraltete Anmeldedaten anzeigen kann.

Plan-Downgrades deaktivieren bestehende Token sofort. Die API prüft apiAccess bei jeder signierten Anfrage erneut — Sie müssen Token bei einem Planwechsel nicht einzeln widerrufen.

Scopes

Jedes Token trägt eine oder mehrere Scope-Strings. Endpunkte deklarieren, welche Scopes sie benötigen; fehlende Scopes liefern 403 InsufficientScope. Der Wildcard (*) gewährt alles — aktivieren Sie ihn nur, wenn Sie ihn wirklich brauchen.

ScopeErlaubt
mailboxes:readPostfächer auflisten und einsehen
mailboxes:writePostfächer erstellen, ändern, löschen
domains:readDomains und DNS-Einträge auflisten
domains:writeEigene Domains hinzufügen, verifizieren, löschen (in v1 nur per FE)
email:readPostfachnachrichten auflisten und einsehen
email:sendAusgehende E-Mails über die API senden
webhooks:readWebhook-Endpunkte auflisten
webhooks:writeWebhook-Endpunkte registrieren, auflisten und widerrufen
*Wildcard — gewährt alles. Sparsam einsetzen.

Postfächer

Auflisten

GET /api/v1/pub/mailboxes
# scope: mailboxes:read

Einzelnes abrufen

GET /api/v1/pub/mailboxes/{id}
# scope: mailboxes:read

Erstellen

POST /api/v1/pub/mailboxes
Content-Type: application/json
# scope: mailboxes:write

{
  "localPart": "support",
  "domain": "yourbrand.com",
  "displayName": "Support team",
  "forwardTo": "ops@yourbrand.com"
}

Das Feld domain ist optional — lassen Sie es weg, und das Postfach wird auf qmailing.com angelegt. Bei einer eigenen Domain muss diese sowohl claimed ALS AUCH fullyVerified sein; eine noch nicht bereite Domain liefert 400 zurück, statt stillschweigend ein nicht zustellbares Postfach zu erstellen.

Das Löschen von Postfächern wird in v1 bewusst nicht angeboten. Es protokolliert eine AGB-Zustimmung und verbraucht einen Slot des kontoweiten Lebenszeit-Kontingents — beides gehört zu einem Menschen, der nach dem Lesen des Dialogs einen Knopf drückt, nicht zu einem unbeaufsichtigten Agenten. Verwenden Sie das Frontend.

Domains & DNS

Eigene Domains auflisten

GET /api/v1/pub/domains
# scope: domains:read

DNS-Einträge-Checkliste

GET /api/v1/pub/domains/{id}/dns-records
# scope: domains:read

Liefert die vollständige 8-Eintrag-Checkliste (Challenge-TXT, MX, SPF, drei DKIM-CNAMEs, DMARC, optional _amazonses) mit einem zeilenweisen status aus PENDING / FOUND / MISMATCH / NOT_REQUIRED. Damit kann der Agent dem Nutzer genau sagen, was beim DNS-Anbieter zu veröffentlichen ist.

E-Mail

Postfachinhalte lesen und ausgehende E-Mails versenden. Die Ordner-Pagination entspricht der internen API des Frontends — Agenten, die zwischen Cookie-JWT- und Bearer-Auth wechseln, sehen keine Formänderung.

Nach Ordner auflisten

GET /api/v1/pub/email?folder=INBOX&offset=0&limit=25
# scope: email:read

# Optional query params:
#   mailboxId   filter to one mailbox (omit for all-mailboxes view)
#   folder      INBOX | SENT | DRAFTS | TRASH | STARRED | SPAM
#   offset      0-based index, default 0
#   limit       1..100, default 25

folder ist standardmäßig INBOX; zulässige Werte: INBOX, SENT, DRAFTS, TRASH, STARRED, SPAM. mailboxId ist optional — ohne Angabe werden alle Postfächer des Aufrufers ausgelesen. Pagination via offset + limit; limit wird auf den Bereich 1–100 begrenzt (Standard 25).

Einzelne abrufen

GET /api/v1/pub/email/{id}
# scope: email:read

Liefert das vollständige EmailDetailDto: HTML-/Textkörper, Label-Liste, Anhang-Metadaten. Anhang-Inhalte sind nicht inline enthalten — laden Sie jeden über GET /{emailId}/attachments/{index} unten herunter; dieser Endpunkt streamt die Rohbytes mit dem ursprünglichen Dateinamen und dem Content-Type.

Anhang herunterladen

GET /api/v1/pub/email/{emailId}/attachments/{index}
# scope: email:read
# response: streamed bytes, Content-Type from the attachment

Streamt die Rohbytes des Anhangs (nullbasierter Index in der Anhangsliste der Nachricht). Gleiche Form wie der sitzungsbasierte Download: Content-Type wird durchgereicht, Content-Disposition nach RFC 6266 mit dem ursprünglichen Dateinamen (UTF-8 prozent-codiert für Unicode). MCP-Agenten, die über @qmailing/mcp-server aufrufen, nutzen das Tool qmailing_get_attachment, das die Bytes base64-kodiert inline zurückgibt (Cap: 5 MiB).

Senden

Compose-Endpunkt. multipart/form-data-Body mit einem command-JSON-Part (Empfänger / Betreff / Body) und null oder mehr attachments-Datei-Parts:

POST /api/v1/pub/email/send
Content-Type: multipart/form-data
# scope: email:send

--boundary
Content-Disposition: form-data; name="command"
Content-Type: application/json

{
  "mailboxId": "11111111-2222-3333-4444-555555555555",
  "to":      ["alice@example.com"],
  "cc":      [],
  "bcc":     [],
  "subject": "Order #1428 confirmed",
  "bodyText": "Plain-text body",
  "bodyHtml": "<p>Rich body</p>",
  "replyToId": null
}
--boundary
Content-Disposition: form-data; name="attachments"; filename="receipt.pdf"
Content-Type: application/pdf

<binary bytes>
--boundary--

Form des command-JSON:

{
  "mailboxId":   "uuid (required) — must be SES-verified",
  "to":          "string[] (required, max 50)",
  "cc":          "string[] (optional, max 50)",
  "bcc":         "string[] (optional, max 50)",
  "subject":     "string (max 998 chars)",
  "bodyText":    "string — plain-text body",
  "bodyHtml":    "string — HTML body",
  "replyToId":   "uuid | null — set for in-thread replies"
}

Jeder Aufruf zählt gegen das tägliche Sende-Limit des Plans, die SES-Sendekontingente des Postfachs und das Speicherkontingent des Nutzers für die resultierende SENT-Kopie. Empfänger werden als RFC-5322-Adressen validiert; ungültige liefern 400 mit der betreffenden Adresse zurück. Das in mailboxId referenzierte Postfach muss SES-verifiziert sein — sonst 409 MailboxNotVerified mit einem Hinweis auf die Domains-Seite.

Agenten, die JSON gegenüber Multipart bevorzugen, können das mitgelieferte MCP-Tool nutzen — es kodiert Anhänge inline in Base64 und packt sie auf dem Weg nach außen wieder in multipart/form-data, sodass das Drahtformat identisch bleibt.
Der filename am command-Teil ist optional — Node fetch stempelt automatisch filename="blob" auf jeden Blob, Browser- und Node-Clients können command.json übergeben, und konforme curl --form-Clients dürfen ihn ganz weglassen. Alle drei Formen werden gleich geparst; ausschlaggebend ist nur Content-Type: application/json auf den Bytes des Teils.

Scopes: email:read für Liste + Einzelabruf, email:send für Versand.

Webhooks

Registrieren Sie einen HTTPS-Endpunkt, und QMailing POSTet einen signierten JSON-Envelope an diesen, sobald eines der abonnierten Ereignisse eintritt. Die Zustellung ist live — der Worker pollt eine Per-Event-Queue alle 10s, signiert jeden Request mit HMAC-SHA256 und wiederholt Fehler mit exponentiellem Backoff (1m / 5m / 15m / 1h / 6h), bevor die Zeile zur manuellen Prüfung im DLQ landet.

Endpunkt registrieren

POST /api/v1/pub/webhooks
Content-Type: application/json
# scope: webhooks:write

{
  "url":    "https://your-server.example.com/qmailing-events",
  "label":  "Production listener",
  "events": ["email.received", "email.bounced", "domain.verified"]
}

# Response (201):
{
  "endpoint": {
    "id":         "uuid",
    "url":        "https://your-server.example.com/qmailing-events",
    "label":      "Production listener",
    "events":     ["email.received", "email.bounced", "domain.verified"],
    "secretPrefix": "whk_AbCd",
    "createdAt":  "2026-05-04T20:30:00Z",
    "active":     true
  },
  "plaintext":  "whk_AbCd…<32 random chars>"   // shown ONCE
}

url muss ein HTTPS-Endpunkt sein (HTTP nur für localhost im Dev erlaubt). Der Host wird gegen eine Allow-List für SSRF geprüft — private / Loopback / Cloud-Metadata-Adressen werden bereits bei der Registrierung abgelehnt. Die Antwort enthält plaintext genau einmal; speichern Sie ihn serverseitig und nutzen Sie ihn, um HMAC-Signaturen eingehender Zustellungen zu prüfen.

Ereigniskatalog

EreignisFeuert wenn
email.receivedEine eingehende E-Mail trifft in einem Ihrer Postfächer ein.
email.sentEine ausgehende E-Mail wurde von SES akzeptiert.
email.bouncedEine ausgehende E-Mail ist zurückgeprallt (Hard oder Soft Bounce).
domain.verifiedEine eigene Domain hat die DNS-Verifizierung vollständig durchlaufen.

Endpunkte auflisten

GET /api/v1/pub/webhooks
# scopes: webhooks:read OR webhooks:write

Liefert aktive und widerrufene Endpunkte, neueste zuerst. Lesezugriff funktioniert mit webhooks:read oder webhooks:write — ein Inspektor-Token muss damit nicht den breiteren Write-Scope tragen.

Wire-Format der Zustellung

Jede Zustellung ist ein einzelner POST an Ihren Endpunkt mit Content-Type: application/json. Der Body ist der Event-Envelope mit den Feldern event (Ereignisname), occurred_at (ISO-Zeitstempel) und einem data-Block, dessen Form vom Ereignis abhängt (siehe Tabelle oben). Drei Header tragen Routing + Verifikations-Metadaten:

POST https://your-server.example.com/qmailing-events
Content-Type: application/json
User-Agent: qmailing-webhook/1 (+https://qmailing.com)
X-Qmailing-Event: email.received
X-Qmailing-Delivery: 5f3b2a91-7c4d-4d52-9c3e-aa1bcd8a4f12
X-Qmailing-Signature: t=1685120800,v1=abc123def…

{
  "event": "email.received",
  "occurred_at": "2026-05-23T19:46:40Z",
  "data": {
    "email_id":   "uuid",
    "mailbox_id": "uuid",
    "from":       "alice@example.com",
    "subject":    "Hello",
    "preview_text": "Just checking in…"
  }
}

Signatur-Schema

# Receiver side (Node example)
const crypto = require("node:crypto");

function verify(headers, body, secret) {
  const sig = headers["x-qmailing-signature"];           // "t=1685120800,v1=abc123…"
  const m = /t=(\d+),v1=([0-9a-f]+)/.exec(sig);
  if (!m) return false;
  const ts = Number(m[1]);
  if (Math.abs(Date.now() / 1000 - ts) > 300) return false;  // 5-min replay window
  const expected = crypto
    .createHmac("sha256", secret)
    .update(`${ts}.${body}`)
    .digest("hex");
  return crypto.timingSafeEqual(Buffer.from(expected), Buffer.from(m[2]));
}

Lehnen Sie den Request ab, wenn der Timestamp älter als 5 Minuten ist (Replay-Fenster) oder wenn der neu berechnete HMAC nicht mit dem v1-Hex übereinstimmt — unser BE-Signer folgt den Stripe / GitHub-Konventionen exakt, sodass jede der Standard-Verifier-Bibliotheken sofort funktioniert.

Retry-Policy

Nicht-2xx-Antworten (oder Transportfehler — DNS, TLS, Connection Refused, 10s Timeout) erhöhen attempt_count und schieben next_attempt_at auf den nächsten Slot in 1m / 5m / 15m / 1h / 6h. Nach dem fünften Fehlversuch geht die Zustellung in FAILED (DLQ) — sichtbar auf /settings/developers, wo Sie manuell wiederholen können. Idempotenz: jeder Retry trägt dieselbe X-Qmailing-Delivery-UUID — Empfänger deduplizieren über diesen Header.

Letzte Zustellungen auflisten

GET /api/v1/pub/webhooks/{endpointId}/deliveries?limit=100
# scopes: webhooks:read OR webhooks:write

Liefert die letzten limit Zustellungen eines einzelnen Endpunkts (Default 100, max 100), neueste zuerst. Jede Zeile enthält Status, Versuchszähler, letzten HTTP-Code, letzte Fehlermeldung und das Original-Payload-JSON — versorgt die History-Ansicht im Developer-Dashboard.

Testzustellung senden

POST /api/v1/pub/webhooks/{endpointId}/test
# scope: webhooks:write
# Response 202: WebhookDeliveryDto (enqueued, picked up next worker tick)

Feuert ein synthetisches webhook.test-Ereignis am Endpunkt ab — derselbe Dispatch-Pfad wie echte Ereignisse, nützlich zur Verifikation von Signatur + TLS vor dem Abonnieren von Live-Traffic.

Zustellung wiederholen

POST /api/v1/pub/webhooks/deliveries/{deliveryId}/retry
# scope: webhooks:write
# Response 200: WebhookDeliveryDto (status=PENDING, attempt=MAX-1)

Stellt eine Zustellungszeile manuell wieder in die Queue. Bereits zugestellte Zeilen können nicht wiederholt werden (409). Der Retry gibt genau einen weiteren Versuch (Zähler auf MAX-1), sodass ein dauerhaft kaputter Endpunkt nicht durch wiederholte Klicks endlos geloopt wird.

Zustellung aus History löschen

DELETE /api/v1/pub/webhooks/deliveries/{deliveryId}
# scope: webhooks:write
# Response: 204 No Content

Hard-Delete einer Zustellungszeile aus der History-Tabelle. Das Compliance-Audit-Log erfasst das Löschen selbst, sodass Traceability auch ohne die Zeile erhalten bleibt.

Endpunkt widerrufen

DELETE /api/v1/pub/webhooks/{id}
# scope: webhooks:write
# Response: 204 No Content

Idempotent — das Widerrufen eines bereits widerrufenen Endpunkts gelingt geräuschlos. Die Zeile bleibt erhalten (revoked-at-Zeitstempel gesetzt), damit Audit-Logs ihre Referenzen behalten.

Limit: 10 aktive Endpunkte pro Konto, 32 Ereignisse pro Endpunkt. Beides wird bei der Registrierung erzwungen — 409 WebhookEndpointLimitExceeded / 400 InvalidWebhookEvent.

Fehler

Jede Antwort, die nicht 2xx ist, ist ein RFC-7807-ProblemDetail mit einem stabilen code-Feld, auf das Ihr Agent verzweigen kann:

HTTPcodeWann
400InvalidApiTokenScopeUnbekannter Scope-String beim Anlegen.
400InvalidEmailAddressEin Empfänger hat die RFC-5322-Syntaxprüfung nicht bestanden.
400InvalidWebhookEventDie registrierte Ereignisliste enthält einen unbekannten Ereignisnamen.
401—Bearer-Header fehlt, ist fehlerhaft, oder Token wurde widerrufen / ist abgelaufen.
402PlanFeatureRequiredAufrufer hat einen Plan ohne API-Zugang — Upgrade nötig.
403InsufficientScopeToken enthält keinen der erforderlichen Scopes.
404ApiTokenNotFoundWiderrufsziel existiert nicht oder gehört zu einem anderen Konto.
409MailboxNotVerifiedDie Domain des Sende-Postfachs ist noch nicht vollständig verifiziert — DNS in /settings/domains abschließen.
409ApiTokenLimitExceededKonto hat das Maximum (20) aktiver Token erreicht; widerrufen Sie zuerst eines.
409WebhookEndpointLimitExceededKonto hält bereits 10 aktive Webhook-Endpunkte; widerrufen Sie zuerst einen.
429RateLimitExceededToken hat 300 Anfragen pro Minute überschritten. Retry-After in Sekunden.

Rate Limits

Jedes Token erhält einen eigenen Bucket von 300 Anfragen pro Minute. Multi-Agent-Setups (CLI + Cron + IDE-Plugin) mit unterschiedlichen Token für dasselbe Konto laufen unabhängig — sie kämpfen nie um einen gemeinsamen Bucket. 429 RateLimitExceeded enthält einen Retry-After-Header in Sekunden.

MCP-Server

Das Paket @qmailing/mcp-server läuft lokal und stellt die öffentliche API als Werkzeuge des Model Context Protocol bereit. Binden Sie es in Claude Desktop, Cursor, Continue oder einen beliebigen MCP-kompatiblen Client ein.

Das Wire-Format ist stabil — aber in jedem 0.x-Release können neue Werkzeuge hinzukommen. Pinnen Sie eine bestimmte Version (@qmailing/mcp-server@0.2.0), wenn Sie keine automatischen Upgrades wünschen.
{
  "mcpServers": {
    "qmailing": {
      "command": "npx",
      "args": ["-y", "@qmailing/mcp-server"],
      "env": {
        "QMAILING_API_TOKEN": "qm_live_your_token_here"
      }
    }
  }
}

Mitgelieferte Werkzeuge: qmailing_list_mailboxes, qmailing_get_mailbox, qmailing_create_mailbox, qmailing_list_domains, qmailing_get_dns_records, qmailing_list_emails, qmailing_get_email, qmailing_get_attachment, qmailing_send_email, qmailing_register_webhook, qmailing_list_webhooks, qmailing_delete_webhook. Der Katalog wächst, sobald neue Endpunkte hinzukommen.

Einen Bug gefunden oder eine Frage? Token, Scopes, Plan-Limits und Rate-Limit-Zähler sind alle auf Ihrer Entwicklerseite einsehbar.

QMailing

Erstelle Postfächer, keine Konten.

Produkt

  • Alles, was Sie brauchen
  • Preise
  • Vergleich
  • Anwendungsfälle
  • API & MCP

Rechtliches

  • Datenschutzrichtlinie
  • Nutzungsbedingungen
  • Rückerstattung
  • Datenlöschung

Support

  • Support kontaktieren
© 2026 QMailing. Alle Rechte vorbehalten.