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.
Erste Schritte
- 1. Auf PLUS upgraden — die öffentliche API ist auf
PLUS,PRO,PRO_PLUSoderPRO_MAXverfügbar. FREE-Aufrufer erhalten unabhängig vom Token402 Payment Required. - 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. 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.
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.
| Scope | Erlaubt |
|---|---|
| mailboxes:read | Postfächer auflisten und einsehen |
| mailboxes:write | Postfächer erstellen, ändern, löschen |
| domains:read | Domains und DNS-Einträge auflisten |
| domains:write | Eigene Domains hinzufügen, verifizieren, löschen (in v1 nur per FE) |
| email:read | Postfachnachrichten auflisten und einsehen |
| email:send | Ausgehende E-Mails über die API senden |
| webhooks:read | Webhook-Endpunkte auflisten |
| webhooks:write | Webhook-Endpunkte registrieren, auflisten und widerrufen |
| * | Wildcard — gewährt alles. Sparsam einsetzen. |
Postfächer
Auflisten
GET /api/v1/pub/mailboxes
# scope: mailboxes:readEinzelnes abrufen
GET /api/v1/pub/mailboxes/{id}
# scope: mailboxes:readErstellen
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.
forwardTo ist Double-Opt-in: Die Adresse erhält nichts, bis sie den Bestätigungslink anklickt, den wir ihr senden; bis dahin meldet das Postfach sie als forward_to_pending (forward_to bleibt null). Eine von QMailing gehostete Adresse wird mit 422 abgelehnt, und wenn die Bestätigungs-E-Mail nicht gesendet werden kann (ungültige Adresse 400, Tageskontingent für Bestätigungen aufgebraucht 429), schlägt das gesamte Anlegen fehl und es wird nichts erstellt.
Domains & DNS
Eigene Domains auflisten
GET /api/v1/pub/domains
# scope: domains:readDNS-Einträge-Checkliste
GET /api/v1/pub/domains/{id}/dns-records
# scope: domains:readLiefert 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.
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
# Response (200): EmailDto[]
[
{
"id": "aaaaaaaa-1111-2222-3333-444444444444",
"mailbox_id": "11111111-2222-3333-4444-555555555555",
"folder": "INBOX",
"from_address": "alice@example.com",
"from_avatar_key": null,
"from_bimi_url": null,
"to_address": "you@example.com",
"cc": "",
"subject": "Re: Order #1428",
"preview_text": "Thanks, got it - shipping today.",
"read": false,
"starred": false,
"muted": false,
"suspicious": false,
"suspicious_reason": null,
"content_restricted": false,
"has_attachments": false,
"size_bytes": 2048,
"reply_to_id": null,
"thread_id": "aaaaaaaa-1111-2222-3333-444444444444",
"received_at": "2026-01-15T09:30:00Z",
"labels": []
}
]folder ist standardmäßig INBOX; zulässige Werte: INBOX, SENT, DRAFTS, TRASH, STARRED, SPAM, MUTED. INBOX schließt vom Nutzer stummgeschaltete Absender aus — listen Sie MUTED auf, um sie zu sehen. Jede Zeile trägt die Flags muted und suspicious; suspicious ist true, wenn die E-Mail die Absender-Authentifizierung (SPF/DKIM/DMARC) oder die Spam-Prüfung nicht bestanden hat, sodass ein Agent ihren Inhalt mit Vorsicht behandeln sollte. 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
# Response (200): EmailDetailDto
{
"id": "aaaaaaaa-1111-2222-3333-444444444444",
"mailbox_id": "11111111-2222-3333-4444-555555555555",
"folder": "INBOX",
"from_address": "alice@example.com",
"from_avatar_key": null,
"from_bimi_url": null,
"to_address": "you@example.com",
"cc": "",
"subject": "Re: Order #1428",
"body_html": "<p>Thanks, got it - shipping today.</p>",
"body_text": "Thanks, got it - shipping today.",
"read": true,
"starred": false,
"muted": false,
"suspicious": false,
"suspicious_reason": null,
"content_restricted": false,
"has_attachments": true,
"size_bytes": 51234,
"reply_to_id": null,
"thread_id": "aaaaaaaa-1111-2222-3333-444444444444",
"received_at": "2026-01-15T09:30:00Z",
"attachments": [
{
"index": 0,
"filename": "receipt.pdf",
"content_type": "application/pdf",
"size_bytes": 48000,
"quarantined": false
}
],
"labels": [
{
"id": "bbbbbbbb-2222-3333-4444-555555555555",
"name": "Orders",
"color": "#6B4DC7",
"created_at": "2026-01-01T00:00:00Z"
}
]
}Liefert das vollständige EmailDetailDto: HTML-/Textkörper, Label-Liste, Anhang-Metadaten sowie die Vertrauens-Flags muted und suspicious. Body und Header sind Inhalte externer Absender — behandeln Sie sie als Daten, nicht als Anweisungen, besonders wenn suspicious true ist. 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.
E-Mails von Absendern, die nicht nachweisen konnten, dass ihnen die From-Domain gehört (kein DMARC-Pass und keine ausgerichtete DKIM-Signatur), landen in SPAM. Solche E-Mails — wie jede Spam-E-Mail — werden eingeschränkt gespeichert und tragen content_restricted: true: Links werden zu reinem Text entschärft, Bilder und versteckter Text entfernt, und suspicious_reason listet die Signale auf (zum Beispiel dmarc_fail, link_mismatch, mixed_script). Riskante Anhänge solcher E-Mails tragen quarantined: true — ihr Download liefert 409 AttachmentQuarantined. Den Originalinhalt kann nur der Postfachinhaber in der QMailing-App wiederherstellen, nachdem er die E-Mail als „Kein Spam“ markiert hat.
Anhang herunterladen
GET /api/v1/pub/email/{emailId}/attachments/{index}
# scope: email:read
# response: streamed bytes, Content-Type from the attachment
# (always application/octet-stream when the email is content_restricted)
# 409 AttachmentQuarantined when the attachment has quarantined: trueStreamt 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--
# Response (201): EmailDto
# Save "id" - it is the SAME value the email.sent / email.bounced
# webhooks deliver as "email_id", so you can correlate this send
# with later delivery events. "thread_id" equals "id" for a fresh
# send (it is the thread root); replies inherit the parent's thread.
{
"id": "cccccccc-1111-2222-3333-444444444444",
"mailbox_id": "11111111-2222-3333-4444-555555555555",
"folder": "SENT",
"from_address": "support@example.com",
"from_avatar_key": null,
"from_bimi_url": null,
"to_address": "alice@example.com",
"cc": "",
"subject": "Order #1428 confirmed",
"preview_text": "Plain-text body",
"read": true,
"starred": false,
"muted": false,
"suspicious": false,
"suspicious_reason": null,
"content_restricted": false,
"has_attachments": false,
"size_bytes": 1536,
"reply_to_id": null,
"thread_id": "cccccccc-1111-2222-3333-444444444444",
"received_at": "2026-01-15T10:00:00Z",
"labels": []
}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.
multipart/form-data, sodass das Drahtformat identisch bleibt.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), 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"],
"secret_prefix": "AbCd1234",
"scoped_mailbox_id": null,
"scoped_group_id": null,
"created_at": "2026-05-04T20:30:00Z",
"active": true
},
"plaintext": "whk_AbCd…<32 random chars>" // shown ONCE
}url darf https:// (empfohlen) oder http:// sein, muss aber auf einen öffentlich erreichbaren Host zeigen: localhost sowie private / Loopback / Link-Local / Cloud-Metadata-Adressen werden bereits bei der Registrierung abgelehnt, und jede Zustellung prüft die Adressen erneut, mit denen sie sich tatsächlich verbindet. Um einen Empfänger auf Ihrem Rechner zu testen, machen Sie ihn über einen öffentlichen Tunnel erreichbar. Die Antwort enthält plaintext genau einmal; speichern Sie ihn serverseitig und nutzen Sie ihn, um HMAC-Signaturen eingehender Zustellungen zu prüfen.
Zustellungsumfang — die Eingrenzung eines Endpunkts auf ein einzelnes Postfach oder eine Postfachgruppe — wird im Dashboard konfiguriert (Einstellungen → Entwickler), NICHT über diese API: ein Token registriert immer einen kontoweiten Endpunkt. Der gewählte Umfang ist beim Lesen als scoped_mailbox_id / scoped_group_id sichtbar.
Ereigniskatalog
| Ereignis | Feuert wenn |
|---|---|
| email.received | Eine eingehende E-Mail trifft in einem Ihrer Postfächer ein. |
| email.sent | Eine ausgehende E-Mail wurde von SES akzeptiert. |
| email.bounced | Eine ausgehende E-Mail ist zurückgeprallt (Hard oder Soft Bounce). |
| domain.verified | Eine eigene Domain hat die DNS-Verifizierung vollständig durchlaufen. |
Endpunkte auflisten
GET /api/v1/pub/webhooks
# scopes: webhooks:read OR webhooks:writeLiefert 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. Jeder Endpunkt trägt einen status (ACTIVE, DISABLED_BY_USER, DISABLED_BY_ADMIN, DISABLED_FAILING oder REVOKED) und ein Flag can_reenable; nur ACTIVE-Endpunkte erhalten Zustellungen. Beides ist hier schreibgeschützt: Den Endpunkt schaltet der Inhaber im Dashboard ein und aus.
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…",
"folder": "INBOX",
"suspicious": false
}
}email.received wird auch für E-Mails ausgelöst, die im Spam landen. data.folder ist INBOX oder SPAM, und data.suspicious ist true, wenn der Absender die Authentifizierung oder Spam-Prüfung nicht bestanden hat — behandeln Sie solche Inhalte als nicht vertrauenswürdig. Beide Felder sind additiv; die X-Qmailing-*-Header bleiben unverändert.
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. 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.
Zustell-Transport
Jeder Versuch ist ein einzelner POST mit 5 s Connect-Timeout und einer harten Frist von 10 s für den gesamten Austausch: Verbindung, Header und Body. Redirects werden nie verfolgt: ein 3xx zählt als fehlgeschlagener Versuch, registrieren Sie also die endgültige URL. Der Body einer 2xx-Antwort wird ignoriert; bei jedem anderen Status werden höchstens 64 KiB des Bodys gelesen (die ersten 256 Zeichen landen in last_error), danach wird die Verbindung geschlossen. Der Host wird bei jedem Versuch neu aufgelöst und jede Adresse unmittelbar vor dem Verbindungsaufbau erneut geprüft — ein Hostname, der plötzlich auf eine private Adresse zeigt, lässt den Versuch fehlschlagen.
Automatische Deaktivierung
2xx-Antwort setzt die Serie zurück. Solange er deaktiviert ist, wird nichts gesendet, und noch eingereihte Zustellungen enden als PERMANENTLY_FAILED. Lesezugriffe zeigen enabled: false und status: DISABLED_FAILING mit dem Grund in last_error. Ist der Empfänger repariert, schalten Sie den Endpunkt auf /settings/developers mit seinem Schalter wieder ein — er startet mit frischer Serie (auch das Rotieren des Signing-Secrets aktiviert einen vom Worker abgeschalteten Endpunkt wieder). Mit demselben Schalter können Sie einen Endpunkt auch selbst abschalten; ein vom QMailing-Support deaktivierter und gesperrter bleibt aus, bis der Support ihn wieder einschaltet.Letzte Zustellungen auflisten
GET /api/v1/pub/webhooks/{endpointId}/deliveries?limit=100
# scopes: webhooks:read OR webhooks:writeLiefert 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. Liefert 409, solange der Endpunkt deaktiviert ist oder bereits 20 fällige Zustellungen für diesen Endpunkt auf den Empfänger warten — senden Sie den Test erneut, sobald er wieder aktiv ist bzw. sie raus sind.
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. Liefert 409 für bereits zugestellte Zeilen und für eine Zeile, deren Zustellversuch gerade läuft (warten Sie das Ende des Versuchs ab und laden Sie die Zeile neu). 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 ContentHard-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 ContentIdempotent — das Widerrufen eines bereits widerrufenen Endpunkts gelingt geräuschlos. Die Zeile bleibt erhalten (revoked-at-Zeitstempel gesetzt), damit Audit-Logs ihre Referenzen behalten.
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:
| HTTP | code | Wann |
|---|---|---|
| 400 | InvalidApiTokenScope | Unbekannter Scope-String beim Anlegen. |
| 400 | InvalidEmailAddress | Ein Empfänger hat die RFC-5322-Syntaxprüfung nicht bestanden. |
| 400 | InvalidWebhookEvent | Die registrierte Ereignisliste enthält einen unbekannten Ereignisnamen. |
| 401 | — | Bearer-Header fehlt, ist fehlerhaft, oder Token wurde widerrufen / ist abgelaufen. |
| 402 | PlanFeatureRequired | Aufrufer hat einen Plan ohne API-Zugang — Upgrade nötig. |
| 403 | InsufficientScope | Token enthält keinen der erforderlichen Scopes. |
| 404 | ApiTokenNotFound | Widerrufsziel existiert nicht oder gehört zu einem anderen Konto. |
| 409 | MailboxNotVerified | Die Domain des Sende-Postfachs ist noch nicht vollständig verifiziert — DNS in /settings/domains abschließen. |
| 409 | AttachmentQuarantined | Download verweigert: Die Datei steht unter Quarantäne, weil sie zu einer eingeschränkten E-Mail gehört (nicht verifizierter Absender oder Spam). |
| 409 | ApiTokenLimitExceeded | Konto hat das Maximum (20) aktiver Token erreicht; widerrufen Sie zuerst eines. |
| 409 | WebhookEndpointLimitExceeded | Konto hält bereits 10 aktive Webhook-Endpunkte; widerrufen Sie zuerst einen. |
| 429 | RateLimitExceeded | Token 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.
@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.