Anleitung
Idempotente Anfragen
Wiederholen Sie Sende- und Weiterleitungsanfragen sicher mit dem Header Idempotency-Key. Schlüsselformat, das 24-Stunden-Fenster, Wiederholungen, die Antworten 409 und 503 sowie Strategien für Schlüssel.
Netzwerke fallen aus. Wenn eine Sendeanfrage in ein Timeout läuft, wissen Sie nicht, ob Emailit sie erhalten hat, und ein erneutes Senden könnte Ihrem Kunden die E-Mail zweimal zustellen. Ein Header Idempotency-Key macht die Wiederholung sicher: Emailit verarbeitet die erste Anfrage und gibt für jede Wiederholung mit demselben Schlüssel dieselbe Antwort zurück.
So funktioniert es
Fügen Sie POST /emails oder POST /emails/{id}/forward einen Header Idempotency-Key hinzu.
- Erste Anfrage. Emailit reserviert den Schlüssel für Ihren Workspace und verarbeitet die Anfrage.
- Erfolg. Emailit speichert die Antwort 24 Stunden lang. Jede Anfrage mit demselben Schlüssel in diesem Zeitfenster erhält die gespeicherte Antwort mit
200zurück, und es wird keine neue E-Mail erstellt. - Fehlschlag. Schlägt die Anfrage fehl, zum Beispiel mit
400oder402, gibt Emailit den Schlüssel wieder frei. Beheben Sie das Problem und wiederholen Sie die Anfrage mit demselben Schlüssel. - Überschneidung. Trifft eine zweite Anfrage ein, während die erste noch läuft, erhält sie
409, und nichts wird gesendet. Wiederholen Sie die Anfrage kurz darauf mit demselben Schlüssel.
Schlüssel gelten pro Workspace, sodass zwei Workspaces denselben Schlüssel ohne Konflikt verwenden können.
Schlüsselformat
| Regel | Wert |
|---|---|
| Länge | 1 bis 256 Zeichen |
| Zeichen | Buchstaben A–Z und a–z, Ziffern 0–9, Bindestrich - und Unterstrich _ |
| Gültigkeitsbereich | Pro Workspace |
| Zeitfenster | 24 Stunden nach der ersten erfolgreichen Antwort |
Ein Schlüssel mit anderen Zeichen, etwa : oder /, wird mit 400 Invalid Idempotency-Key abgelehnt.
Schlüssel wählen
Leiten Sie den Schlüssel aus dem Ereignis ab, das die E-Mail auslöst, damit jeder Wiederholungspfad denselben Schlüssel erzeugt:
| Beispielschlüssel | |
|---|---|
| Bestellbeleg | order-1042-receipt |
| Passwort-Reset | password-reset-7f3c9a1e (die ID des Reset-Tokens) |
| Wöchentlicher Digest | digest-user-881-2026-w40 |
| Hintergrundjob | Die ID des Jobs oder eine UUID, die Sie beim Einreihen des Jobs erzeugen und mit ihm speichern |
Vermeiden Sie Schlüssel, die sich zwischen Versuchen ändern, etwa Zeitstempel oder eine UUID, die in der Wiederholungsschleife erzeugt wird. Sie lassen jede Wiederholung wie eine neue Anfrage aussehen.
Mit Idempotenzschlüssel senden
Die Beispiele für Node.js, Python und PHP wiederholen die Anfrage bei Netzwerkfehlern und bei den Antworten 409, 429 und 5xx und verwenden dabei jedes Mal denselben Schlüssel. Das cURL-Beispiel nutzt die eingebaute Wiederholung von curl, die Timeouts, 429 und die meisten 5xx-Antworten abdeckt.
curl https://api.emailit.com/v2/emails \
-H "Authorization: Bearer $EMAILIT_API_KEY" \
-H "Content-Type: application/json" \
-H "Idempotency-Key: order-1042-receipt" \
--retry 3 \
-d '{
"from": "Acme <orders@acme.com>",
"to": "ada@example.com",
"subject": "Receipt for order 1042",
"text": "Thanks for your order."
}'async function sendOnce(payload, key, attempts = 4) {
for (let attempt = 1; attempt <= attempts; attempt++) {
try {
const res = await fetch('https://api.emailit.com/v2/emails', {
method: 'POST',
headers: {
Authorization: `Bearer ${process.env.EMAILIT_API_KEY}`,
'Content-Type': 'application/json',
'Idempotency-Key': key,
},
body: JSON.stringify(payload),
});
if (res.ok) return res.json();
if (![409, 429].includes(res.status) && res.status < 500) {
throw new Error(`Send failed: ${res.status} ${await res.text()}`);
}
const wait = Number(res.headers.get('retry-after')) || attempt * 2;
await new Promise((r) => setTimeout(r, wait * 1000));
} catch (err) {
if (err.message.startsWith('Send failed') || attempt === attempts) throw err;
await new Promise((r) => setTimeout(r, attempt * 2000));
}
}
throw new Error('Send failed after retries');
}
const email = await sendOnce(
{
from: 'Acme <orders@acme.com>',
to: 'ada@example.com',
subject: 'Receipt for order 1042',
text: 'Thanks for your order.',
},
'order-1042-receipt',
);import os
import time
import requests
def send_once(payload, key, attempts=4):
for attempt in range(1, attempts + 1):
try:
res = requests.post(
"https://api.emailit.com/v2/emails",
headers={
"Authorization": f"Bearer {os.environ['EMAILIT_API_KEY']}",
"Idempotency-Key": key,
},
json=payload,
timeout=30,
)
except requests.RequestException:
if attempt == attempts:
raise
time.sleep(attempt * 2)
continue
if res.ok:
return res.json()
if res.status_code not in (409, 429) and res.status_code < 500:
res.raise_for_status()
time.sleep(int(res.headers.get("retry-after", attempt * 2)))
raise RuntimeError("Send failed after retries")
email = send_once(
{
"from": "Acme <orders@acme.com>",
"to": "ada@example.com",
"subject": "Receipt for order 1042",
"text": "Thanks for your order.",
},
"order-1042-receipt",
)function sendOnce(array $payload, string $key, int $attempts = 4): array
{
for ($attempt = 1; $attempt <= $attempts; $attempt++) {
$ch = curl_init('https://api.emailit.com/v2/emails');
curl_setopt_array($ch, [
CURLOPT_POST => true,
CURLOPT_RETURNTRANSFER => true,
CURLOPT_TIMEOUT => 30,
CURLOPT_HTTPHEADER => [
'Authorization: Bearer ' . getenv('EMAILIT_API_KEY'),
'Content-Type: application/json',
'Idempotency-Key: ' . $key,
],
CURLOPT_POSTFIELDS => json_encode($payload),
]);
$body = curl_exec($ch);
$status = curl_getinfo($ch, CURLINFO_RESPONSE_CODE);
curl_close($ch);
if ($body !== false && $status >= 200 && $status < 300) {
return json_decode($body, true);
}
if ($body !== false && !in_array($status, [409, 429]) && $status < 500) {
throw new RuntimeException("Send failed: $status $body");
}
sleep($attempt * 2);
}
throw new RuntimeException('Send failed after retries');
}
$email = sendOnce([
'from' => 'Acme <orders@acme.com>',
'to' => 'ada@example.com',
'subject' => 'Receipt for order 1042',
'text' => 'Thanks for your order.',
], 'order-1042-receipt');Antworten
| Status | Wann | Was Sie tun |
|---|---|---|
200 |
Erste erfolgreiche Anfrage oder ihre Wiederholung innerhalb von 24 Stunden | Verwenden Sie die Antwort. Eine Wiederholung hat denselben Body, einschließlich derselben id. |
400 Invalid Idempotency-Key |
Der Schlüssel ist leer, zu lang oder enthält ungültige Zeichen | Korrigieren Sie den Schlüssel. |
409 Idempotency key in progress |
Eine Anfrage mit demselben Schlüssel wird noch verarbeitet | Warten Sie einen Moment und wiederholen Sie die Anfrage dann mit demselben Schlüssel. |
503 Idempotency unavailable |
Emailit konnte seinen Idempotenzspeicher nicht erreichen und hat die Anfrage abgelehnt, statt ein Duplikat zu riskieren | Wiederholen Sie die Anfrage mit demselben Schlüssel. |
| Jeder andere Fehler | Die Anfrage ist fehlgeschlagen, und der Schlüssel wurde freigegeben | Beheben Sie die Ursache und wiederholen Sie die Anfrage mit demselben Schlüssel. |
Rate Limits werden vor dem Schlüssel geprüft, daher kann eine Wiederholung trotzdem 429 erhalten. Warten Sie die im Header retry-after angegebene Zeit ab und senden Sie denselben Schlüssel erneut.