Referenz
Rate Limits
Wie Emailit den Versand pro Workspace begrenzt, die Rate-Limit-Header bei jeder Sendung, wie eine 429-Antwort aussieht, weitere Limits einzelner Endpunkte und wie Sie mit Backoff wiederholen.
Emailit begrenzt, wie schnell und wie viel ein Workspace senden kann, nicht wie viele API-Aufrufe Sie machen. Diese Seite erklärt die Versandlimits, die Header, die sie melden, die wenigen Endpunkte mit eigenen Limits und wie Sie mit Backoff reagieren, wenn Sie 429 erhalten.
Versandlimits
Jeder Workspace hat zwei Versandlimits. Neue Workspaces starten in jedem Tarif mit diesen Standardwerten:
| Limit | Standardwert | Zeitfenster |
|---|---|---|
| Pro Sekunde | 2 E-Mails | Gleitendes Fenster von einer Sekunde |
| Pro Tag | 5.000 E-Mails | Kalendertag in UTC, wird um 00:00 UTC zurückgesetzt |
So gelten die Limits:
- Pro Workspace. Alle API-Schlüssel und das SMTP-Relay teilen sich dieselben Zähler. Der Versand per SMTP verbraucht dasselbe Kontingent wie die API.
- Nach Empfängern gezählt. Jede eindeutige Adresse in
to,ccundbcczählt als eine E-Mail. Eine Anfrage mit drei Empfängern zählt als drei. - Nur Sendungen zählen. Die Limits gelten für E-Mail senden und E-Mail weiterleiten. Das Lesen von Daten und das Verwalten von Ressourcen zählen nicht dazu.
- Vorher geprüft, danach gezählt. Eine Sendung wird angenommen, solange der Workspace das Limit noch nicht erreicht hat, und ihre Empfänger werden anschließend zu den Zählern addiert. Eine Anfrage mit vielen Empfängern kann Sie über das Limit bringen. Die nächsten Anfragen erhalten dann
429, bis das Zeitfenster abgelaufen ist.
Die aktuellen Limits und die heutige Nutzung sehen Sie auf der Startseite Dashboard in der Karte Sending Limits.
Rate-Limit-Header
Antworten der Endpunkte zum Senden und Weiterleiten enthalten diese Header:
| Header | Beschreibung |
|---|---|
ratelimit-limit |
E-Mails, die der Workspace pro Sekunde senden kann. |
ratelimit-remaining |
Verbleibende E-Mails im aktuellen Fenster von einer Sekunde. |
ratelimit-reset |
Sekunden, bis das Sekundenfenster zurückgesetzt wird. |
ratelimit-daily-limit |
E-Mails, die der Workspace pro Tag senden kann. |
ratelimit-daily-remaining |
Heute noch verbleibende E-Mails. |
ratelimit-daily-reset |
Sekunden, bis das Tageslimit um 00:00 UTC zurückgesetzt wird. |
retry-after |
Sekunden, die Sie vor einer Wiederholung warten sollten. Nur bei 429-Antworten. |
HTTP/1.1 200 OK
content-type: application/json; charset=utf-8
ratelimit-limit: 2
ratelimit-remaining: 1
ratelimit-reset: 1
ratelimit-daily-limit: 5000
ratelimit-daily-remaining: 4812
ratelimit-daily-reset: 52113Wenn Sie ein Limit erreichen
Eine Sendung über dem Limit gibt 429 Too Many Requests mit dem Header retry-after zurück. Der Body nennt das erreichte Limit:
{
"error": "Rate limit exceeded",
"message": "Too many requests. Maximum 2 messages per second allowed.",
"limit": 2,
"current": 2,
"retry_after": 1
}{
"error": "Daily limit exceeded",
"message": "Daily sending limit of 5000 messages has been reached.",
"limit": 5000,
"current": 5000,
"retry_after": 41760
}| Feld | Beschreibung |
|---|---|
error |
Rate limit exceeded für das Limit pro Sekunde, Daily limit exceeded für das Tageslimit. |
limit |
Das erreichte Limit. |
current |
Wie viele E-Mails im Zeitfenster bereits gezählt wurden. |
retry_after |
Wartezeit in Sekunden. 1 beim Limit pro Sekunde, beim Tageslimit die Sekunden bis 00:00 UTC. |
Wird eine Anfrage abgelehnt, wird nichts gesendet und es werden keine Credits verbraucht. Wiederholen Sie Anfragen, die wegen des Limits pro Sekunde abgelehnt wurden, nach kurzer Wartezeit. Bei Ablehnungen wegen des Tageslimits stellen Sie die E-Mail in eine Warteschlange und senden sie nach dem Zurücksetzen, oder Sie beantragen ein höheres Limit.
Weitere Limits
Einige Endpunkte haben eigene Limits:
| Endpunkt | Limit | Gezählt pro |
|---|---|---|
POST /emails/{id}/forward |
3 pro Stunde | Workspace |
POST /webhooks/{id}/test |
5 pro Minute | IP-Adresse |
Gehostete An- und Abmeldelinks (/subscribe/{token}, /unsubscribe/{token}) |
30 pro Minute | IP-Adresse |
Öffentliche Formular-Endpunkte: Formular laden (GET /forms/{token}) |
60 pro Minute | IP-Adresse |
Öffentliche Formular-Endpunkte: Formular absenden (POST /forms/{token}/submit) |
30 pro Minute | IP-Adresse |
Weiterleitungen zählen außerdem zu den oben genannten Versandlimits. Über dem Limit für Weiterleitungen gibt die API 429 mit dem Header retry-after zurück:
{
"error": "too_many_requests",
"message": "Forwarding is limited to 3 emails per hour for this workspace. Try again later."
}Diese Limits sind fest und ändern sich nicht mit Ihrem Tarif oder Ihren Versandlimits.
Alle anderen Endpunkte
Endpunkte, die Daten lesen oder Ressourcen verwalten, haben kein festes Limit pro Endpunkt. Halten Sie Ihre Nutzung in einem vernünftigen Rahmen: Verwenden Sie einen kleinen Pool gleichzeitiger Anfragen statt Tausender paralleler Anfragen, cachen Sie Daten, die sich selten ändern, und verwenden Sie Webhooks, statt den E-Mail-Status regelmäßig abzufragen.
Limits erhöhen
- Pro und Business. Die Limits steigen beim Senden automatisch, abhängig von Ihrer Versandgesundheit. Emailit erhöht sie höchstens einmal alle sieben Tage und nur, solange Ihre Versandgesundheit gut ist und keine Ihrer Domains pausiert ist.
- Jeder Tarif. Beantragen Sie eine Erhöhung auf der Startseite Dashboard: Wählen Sie in der Karte Sending Limits die Schaltfläche Request Increase, geben Sie die benötigten Limits pro Sekunde und pro Tag ein und beschreiben Sie, woher Ihre Liste stammt und warum Sie die Erhöhung brauchen. Das Support-Team prüft Anfragen in der Regel innerhalb von 24 Stunden.
Alle Tariflimits finden Sie unter Limits.
Mit Backoff wiederholen
Wiederholen Sie Anfragen mit den Antworten 429, 409 (Idempotenzschlüssel in Bearbeitung), 500 und 503. Warten Sie retry-after Sekunden, wenn der Header vorhanden ist, und verwenden Sie andernfalls exponentielles Backoff mit Jitter. Senden Sie einen Idempotency-Key, damit eine wiederholte Sendung nie doppelt zugestellt wird, und warten Sie ein Tageslimit nicht in einer Anfrageschleife ab.
# curl retries 429 and 5xx responses and honors retry-after.
curl https://api.emailit.com/v2/emails \
--retry 5 --retry-max-time 60 \
-H "Authorization: Bearer $EMAILIT_API_KEY" \
-H "Content-Type: application/json" \
-H "Idempotency-Key: order-1042-confirmation" \
-d '{
"from": "Acme <orders@acme.com>",
"to": "ada@example.com",
"subject": "Your order #1042",
"text": "Thanks for your order."
}'import { randomUUID } from 'node:crypto';
const RETRYABLE = new Set([409, 429, 500, 503]);
const sleep = (ms) => new Promise((resolve) => setTimeout(resolve, ms));
export async function sendEmail(payload, maxAttempts = 5) {
const idempotencyKey = randomUUID();
for (let attempt = 1; attempt <= maxAttempts; attempt++) {
const response = await fetch('https://api.emailit.com/v2/emails', {
method: 'POST',
headers: {
Authorization: `Bearer ${process.env.EMAILIT_API_KEY}`,
'Content-Type': 'application/json',
'Idempotency-Key': idempotencyKey,
},
body: JSON.stringify(payload),
});
const body = await response.json();
if (response.ok) return body;
const retryAfter = Number(response.headers.get('retry-after')) || 0;
// Daily limit: retry_after is hours away, so give up and queue it.
if (!RETRYABLE.has(response.status) || retryAfter > 60 || attempt === maxAttempts) {
throw new Error(`Emailit ${response.status}: ${body.message ?? body.error}`);
}
const backoff = Math.min(1000 * 2 ** (attempt - 1), 30_000);
await sleep(retryAfter ? retryAfter * 1000 : backoff + Math.random() * 250);
}
}import os
import random
import time
import uuid
import requests
RETRYABLE = {409, 429, 500, 503}
def send_email(payload, max_attempts=5):
idempotency_key = str(uuid.uuid4())
for attempt in range(1, max_attempts + 1):
response = requests.post(
"https://api.emailit.com/v2/emails",
headers={
"Authorization": f"Bearer {os.environ['EMAILIT_API_KEY']}",
"Idempotency-Key": idempotency_key,
},
json=payload,
timeout=30,
)
if response.ok:
return response.json()
retry_after = int(response.headers.get("retry-after", 0))
# Daily limit: retry_after is hours away, so give up and queue it.
if response.status_code not in RETRYABLE or retry_after > 60 or attempt == max_attempts:
response.raise_for_status()
backoff = min(2 ** (attempt - 1), 30) + random.random() / 4
time.sleep(retry_after or backoff)Tipps für hohe Volumen
- Senden Sie aus einer Warteschlange mit einer festen Anzahl von Workern, und bemessen Sie den Pool nach Ihrem Limit pro Sekunde.
- Verteilen Sie große Batch-Jobs über den Tag, statt sie alle auf einmal zu starten, damit ein einzelner Job nicht das gesamte Tageskontingent verbraucht.
- Beobachten Sie
ratelimit-daily-remainingund verlangsamen Sie, bevor der Wert null erreicht. - Verwenden Sie für Newsletter an Ihre Kontaktlisten Kampagnen, statt den Sende-Endpunkt in einer Schleife aufzurufen.