Obsługa błędów
5 min czytania
Ten przewodnik wyjaśnia odpowiedzi błędów z MailingAPI i jak je prawidłowo obsługiwać.
Format odpowiedzi błędu
Każdy błąd ma ten sam format JSON:
{
"error": {
"code": "validation_failed",
"message": "Błąd walidacji",
"details": {
"subject": ["can't be blank"]
}
}
}
Pola:
-
code— Stabilny, maszynowo czytelny kod błędu. W swojej integracji rozgałęziaj logikę pocode. -
message— Opis czytelny dla człowieka. Służy do logów i do ludzi, dla niektórych błędów może być po polsku i może się zmieniać — nigdy nie rozgałęziaj logiki pomessage. -
details— Tylko dlavalidation_failed. Mapa: nazwa pola → lista komunikatów. -
retry_after— Tylko przy429. Liczba całkowita, w sekundach.
Kody statusu HTTP
| Kod | Znaczenie | Kiedy występuje |
|---|---|---|
200 |
OK | Żądanie zakończone sukcesem |
201 |
Created | Zasób utworzony |
202 |
Accepted | Operacja asynchroniczna w kolejce |
400 |
Bad Request | Nieprawidłowo sformułowane żądanie |
401 |
Unauthorized | Brak lub nieprawidłowy klucz API |
403 |
Forbidden | Prawidłowy klucz, ale akcja niedozwolona |
404 |
Not Found | Zasób nie istnieje |
409 |
Conflict | Zasób już istnieje lub żądanie idempotentne wciąż się przetwarza |
413 |
Payload Too Large | Body żądania przekracza 25 MB |
422 |
Unprocessable | Walidacja pól nie przeszła lub ponownie użyty klucz idempotencji |
429 |
Too Many Requests | Przekroczony limit żądań lub wysyłki |
500 |
Server Error | Coś poszło nie tak po naszej stronie |
Kody błędów
| HTTP |
code |
Znaczenie | Ponawiać? |
|---|---|---|---|
400 |
bad_request |
Nieprawidłowe żądanie, np. niepoprawny adres nadawcy, batch powyżej 1000, brak messages / recipient_variables |
Nie |
400 |
invalid_idempotency_key |
Idempotency-Key jest pusty lub dłuższy niż 255 znaków |
Nie |
401 |
missing_auth, invalid_auth, invalid_key, insufficient_permissions, ip_not_allowed |
Problem z uwierzytelnieniem lub uprawnieniami | Nie |
403 |
forbidden |
Np. nadawca nie jest z domeny klucza API | Nie |
403 |
organization_not_active, domain_not_verified, api_key_without_domain, daily_limit_reached, monthly_limit_reached, ip_blocked |
Stan konta lub planu | Nie — najpierw napraw stan konta |
404 |
not_found |
Zasób nie istnieje | Nie |
409 |
idempotency_request_in_progress |
Pierwsze żądanie z tym samym Idempotency-Key wciąż się przetwarza |
Tak, po Retry-After sekundach |
409 |
conflict |
Zasób już istnieje (np. rejestracja konta z istniejącym emailem) | Nie |
422 |
validation_failed |
Walidacja pól nie przeszła, patrz details |
Nie |
422 |
idempotency_key_reused |
Ten sam klucz z innym body | Nie |
429 |
rate_limit_exceeded |
Limit żądań API na sekundę / minutę |
Tak, po Retry-After sekundach |
429 |
daily_limit_exceeded |
Dzienny limit wysyłki domeny; retry_after = sekundy do północy UTC |
Tak, po Retry-After sekundach |
429 |
recipient_rate_limited |
Maks. 10 emaili na godzinę i 50 na dobę do tego samego odbiorcy w organizacji; retry_after = sekundy do najbliższej pełnej godziny (limit godzinowy) lub do północy UTC (limit dobowy) |
Tak, po Retry-After sekundach |
500 |
internal_error |
Coś poszło nie tak po naszej stronie |
Tak, z exponential backoff; użyj tego samego Idempotency-Key |
Błędy autentykacji i uprawnień (401, 403)
{"error": {"code": "invalid_key", "message": "Invalid API key"}}
Rozwiązanie: Sprawdź, czy klucz API jest poprawny i aktywny, ma wymagane uprawnienia, a adres from należy do domeny klucza.
Błędy walidacji (422)
{
"error": {
"code": "validation_failed",
"message": "Błąd walidacji",
"details": {
"to": ["can't be blank"],
"subject": ["should be at most 998 character(s)"]
}
}
}
Rozwiązanie: Sprawdź obiekt details i popraw każde pole.
Błędy rate limit (429)
{
"error": {
"code": "rate_limit_exceeded",
"message": "Rate limit exceeded",
"retry_after": 5
}
}
Każda odpowiedź 429 zawiera standardowy nagłówek Retry-After (liczba całkowita sekund) oraz retry_after w body, z tą samą wartością. Zalecamy czytanie nagłówka Retry-After. Odpowiedzi 429 dla limitu na sekundę i na minutę zawierają też nagłówki X-RateLimit-*; odpowiedzi 429 dla limitu dziennego zawierają X-Daily-Limit i X-Daily-Remaining: 0. Zobacz Przegląd API → Rate limiting.
Rozwiązanie: Poczekaj Retry-After sekund, potem ponów żądanie.
Błędy zasobów (404, 409)
{"error": {"code": "not_found", "message": "Message not found"}}
Rozwiązanie: Zweryfikuj ID zasobu lub sprawdź duplikaty.
Obsługa błędów w kodzie
Python
import requests
from requests.exceptions import HTTPError
try:
response = requests.post(
"https://api.mailingapi.com/v1/messages/send",
headers={"Authorization": f"Bearer {api_key}"},
json=payload
)
response.raise_for_status()
result = response.json()
except HTTPError as e:
error = e.response.json().get("error", {})
if e.response.status_code == 401:
# Ponowna autentykacja lub sprawdzenie klucza
handle_auth_error()
elif e.response.status_code == 429:
# Respektuj rate limit: nagłówek Retry-After, w sekundach
retry_after = int(e.response.headers.get("Retry-After", 60))
time.sleep(retry_after)
# Ponów żądanie
elif e.response.status_code == 422:
# Zaloguj błędy walidacji (rozgałęziaj po error["code"], nie po message)
logger.error(f"Validation failed: {error}")
else:
# Nieoczekiwany błąd
logger.error(f"API error: {error}")
raise
JavaScript
async function sendEmail(payload) {
try {
const response = await fetch('https://api.mailingapi.com/v1/messages/send', {
method: 'POST',
headers: {
'Authorization': `Bearer ${apiKey}`,
'Content-Type': 'application/json'
},
body: JSON.stringify(payload)
});
if (!response.ok) {
const { error } = await response.json();
switch (response.status) {
case 401:
throw new AuthenticationError(error.message);
case 429:
// Nagłówek Retry-After jest w sekundach
const retryAfter = Number(response.headers.get('Retry-After')) || 60;
await sleep(retryAfter * 1000);
return sendEmail(payload); // Ponów
case 422:
throw new ValidationError(error.code, error.details);
default:
throw new APIError(error.message, error.code);
}
}
return response.json();
} catch (error) {
console.error('Failed to send email:', error);
throw error;
}
}
Strategia ponawiania
Dla błędów przejściowych (500, 502, 503, 504) implementuj exponential backoff. Dla 429 oraz 409 idempotency_request_in_progress czekaj tyle sekund, ile podaje nagłówek Retry-After:
import time
import random
def send_with_retry(payload, max_retries=3):
for attempt in range(max_retries):
try:
response = send_email(payload)
return response
except TransientError as e:
if attempt == max_retries - 1:
raise
# Exponential backoff z jitter
delay = (2 ** attempt) + random.uniform(0, 1)
time.sleep(delay)
Rób:
-
Ponawiaj przy 429 i 409
idempotency_request_in_progresspoRetry-Aftersekundach -
Ponawiaj przy 500, 502, 503, 504 z exponential backoff, używając tego samego
Idempotency-Key - Używaj exponential backoff
- Dodaj losowy jitter by uniknąć thundering herd
- Ustaw maksymalną liczbę ponowień
Nie rób:
-
Nie ponawiaj przy 400, 401, 403, 404, 409
conflict, 422 — nie zmienią się, dopóki nie zmienisz żądania lub stanu konta - Nie ponawiaj natychmiast bez opóźnienia
- Nie ponawiaj w nieskończoność
Idempotencja
Dla bezpiecznego ponawiania używaj kluczy idempotencji:
curl -X POST https://api.mailingapi.com/v1/messages/send \
-H "Authorization: Bearer $API_KEY" \
-H "Idempotency-Key: unique-request-id-123" \
-H "Content-Type: application/json" \
-d '{...}'
Jeśli ponowisz żądanie z tym samym Idempotency-Key, otrzymasz oryginalną odpowiedź (z nagłówkiem Idempotent-Replayed: true) zamiast tworzyć duplikat. Generuj klucz raz na logiczne żądanie i używaj go przy każdym jego ponowieniu.
Błędy idempotencji:
| Status |
error.code |
Znaczenie | Ponawiać? |
|---|---|---|---|
409 |
idempotency_request_in_progress |
Pierwsze żądanie z tym kluczem jest wciąż przetwarzane |
Tak, po Retry-After sekundach |
422 |
idempotency_key_reused |
Klucz został już użyty z innym body żądania | Nie — użyj nowego klucza |
400 |
invalid_idempotency_key |
Klucz jest pusty lub dłuższy niż 255 znaków | Nie |
Pełne zasady: Przegląd API → Idempotencja.
Wskazówki do debugowania
-
Przeczytaj
codeidetailsbłędu — Kod jest stabilny i maszynowo czytelny;messageto wyjaśnienie dla człowieka - Sprawdź logi żądań — W dashboardzie pod Logi → Żądania API
-
Waliduj lokalnie — Użyj
/v1/messages/analyzeby sprawdzić treść przed wysyłką
Uzyskanie pomocy
Jeśli utkniesz:
- Przeszukaj API Reference (interaktywne, wymaga JavaScript) lub użyj specyfikacji OpenAPI 3 pod /api/openapi po szczegóły endpointów
-
Skontaktuj się support@mailingapi.com z:
- Request ID (z nagłówków odpowiedzi)
- Kodem błędu i wiadomością
- Minimalnym przykładem reprodukcji
Następne kroki
Teraz rozumiesz jak obsługiwać błędy. Naucz się wysyłać emaile w szczegółach.