Messages API
9 min czytania
API Messages pozwala wysyłać emaile transakcyjne, śledzić status dostarczenia i zarządzać zaplanowanymi wiadomościami.
Wyślij email
Wyślij pojedynczą wiadomość email.
POST /v1/messages/send
Body żądania
| Pole | Typ | Wymagane | Opis |
|---|---|---|---|
from |
string | Tak | Adres nadawcy (musi pasować do zweryfikowanej domeny) |
to |
string/array | Tak | Adres(y) odbiorcy |
subject |
string | Tak | Temat wiadomości |
html |
string | * | Body HTML (* wymagane przynajmniej jedno z html/text) |
text |
string | * | Body tekstowe |
cc |
array | Nie | Odbiorcy CC |
bcc |
array | Nie | Odbiorcy BCC |
headers |
object | Nie | Własne nagłówki email |
| cc, bcc | Tablice adresów e-mail. to, cc i bcc łącznie: max 50 odbiorców. Każdy odbiorca liczy się do limitu dziennego i miesięcznego. |
| attachments | array | Nie | Załączniki |
| template_id | string | Nie | ID szablonu do użycia |
| template_data | object | Nie | Dane szablonu |
| tags | array | Nie | Tagi dla analityki |
| metadata | object | Nie | Własne metadata |
| tracking | object \| boolean | Nie | Ustawienia śledzenia (false wyłącza oba) |
| transactional | boolean | Nie | Deklaruje pocztę transakcyjną — skutek jak wyłączenie obu śledzeń |
| scheduled_at | string | Nie | Data/czas ISO 8601 dla zaplanowanej wysyłki |
| optimize_send_time | boolean | Nie | Optymalizuj czas dostawy |
Przykładowe żądanie
curl -X POST https://api.mailingapi.com/v1/messages/send \
-H "Authorization: Bearer $API_KEY" \
-H "Content-Type: application/json" \
-d '{
"from": "Twoja Firma <hello@twojadomena.pl>",
"to": "Jan Kowalski <jan@example.com>",
"subject": "Twoje zamówienie zostało wysłane",
"html": "<h1>Zamówienie wysłane</h1><p>Cześć {{name}}, Twoje zamówienie #{{order_id}} jest w drodze!</p>",
"text": "Zamówienie wysłane\n\nCześć {{name}}, Twoje zamówienie #{{order_id}} jest w drodze!",
"template_data": {
"name": "Jan",
"order_id": "12345"
},
"tags": ["transactional", "shipping"],
"metadata": {
"user_id": "usr_123",
"order_id": "ord_456"
}
}'
Odpowiedź
{
"data": {
"id": "550e8400-e29b-41d4-a716-446655440000",
"message_id": "<abc123@mailingapi.com>",
"from": "hello@twojadomena.pl",
"to": "jan@example.com",
"subject": "Twoje zamówienie zostało wysłane",
"status": "queued",
"tags": ["transactional", "shipping"],
"metadata": {"user_id": "usr_123", "order_id": "ord_456"},
"created_at": "2024-01-15T10:30:00Z"
}
}
Załączniki
{
"attachments": [
{
"filename": "faktura.pdf",
"content": "base64-encoded-content",
"content_type": "application/pdf"
},
{
"filename": "logo.png",
"content": "base64-encoded-content",
"content_type": "image/png",
"content_id": "logo"
}
]
}
Użyj content_id dla obrazów inline, potem odwołuj się przez <img src="cid:logo">.
Każdy załącznik wymaga filename i content (Base64). Załącznik bez któregoś z tych pól lub przekraczający poniższe limity jest odrzucany z 422 validation_failed — nigdy nie jest po cichu pomijany.
Limity pól
Te limity dotyczą POST /v1/messages/send oraz każdej wiadomości w batchu. Przekroczenie któregokolwiek zwraca 422 validation_failed z details dla danego pola — nic nie jest po cichu pomijane.
| Pole | Limit |
|---|---|
subject |
1–998 znaków |
tags |
Max 10 tagów, każdy 1–64 znaków |
metadata |
Obiekt JSON, max 50 kluczy, max 2 KB po serializacji do JSON |
headers |
Max 20 własnych nagłówków. Nazwa: tylko litery, cyfry i myślniki, max 128 znaków. Wartość: tekst, max 1000 znaków, bez łamań linii (CR/LF) |
attachments |
Max 10 załączników, każdy z filename i content (Base64), max 10 MB na plik po zdekodowaniu |
scheduled_at |
Najwyżej 7 dni w przód |
Zarezerwowane nagłówki są ustawiane automatycznie, a ich przekazanie skutkuje odrzuceniem: From, To, Cc, Bcc, Subject, Date, MIME-Version, DKIM-Signature, Return-Path, Sender, Content-Type, Content-Transfer-Encoding. Reply-To jest dozwolony. Message-ID jest przyjmowany, ale ignorowany: MailingAPI zawsze nadaje własną wartość. Do wątkowania odpowiedzi użyj In-Reply-To i References.
Całe body żądania może mieć maksymalnie 25 MB. Base64 zwiększa pliki o ok. 33%, więc w praktyce w jednym żądaniu mieści się ok. 18 MB załączników (np. jeden plik 10 MB plus kilka małych). Większe body jest odrzucane z HTTP 413.
Przykład przekroczenia limitu:
{
"error": {
"code": "validation_failed",
"message": "Błąd walidacji",
"details": {
"tags": ["should have at most 10 item(s)"]
}
}
}
Opcje śledzenia
Kontroluj śledzenie otwarć i kliknięć per wiadomość:
{
"tracking": {
"opens": true,
"clicks": true
}
}
| Pole | Typ | Domyślnie | Opis |
|---|---|---|---|
opens |
boolean |
true |
Śledź otwarcia emaili (wstawia pixel śledzący) |
clicks |
boolean |
true |
Śledź kliknięcia linków (przepisuje URL-e przez domenę śledzenia) |
Gdy oba opens i clicks są ustawione na false, email jest traktowany jako transakcyjny:
- Pixel śledzący nie jest wstawiany
- Linki nie są przepisywane
-
Nagłówek
List-Unsubscribenie jest dodawany (zapobiega klasyfikacji emaila jako promocyjny/bulk przez Gmail)
Dobra praktyka: Wyłącz śledzenie dla powiadomień transakcyjnych (resety haseł, potwierdzenia zamówień, alerty systemowe) aby poprawić dostarczalność do inbox. Śledzenie pozostaw włączone dla emaili marketingowych i newsletterów.
{
"from": "alerty@twojadomena.pl",
"to": "user@example.com",
"subject": "Wykryto nowe logowanie",
"html": "<p>Wykryto nowe logowanie na Twoim koncie.</p>",
"tracking": {
"opens": false,
"clicks": false
}
}
Skróty
tracking przyjmuje też zwykłą wartość logiczną, a transactional wyraża
intencję wprost. Wszystkie trzy zapisy są równoważne:
{ "tracking": { "opens": false, "clicks": false } }
{ "tracking": false }
{ "transactional": true }
transactional ma pierwszeństwo przed tracking — jest bardziej szczegółową
deklaracją, więc {"transactional": true, "tracking": {"opens": true}} i tak
wyśle z wyłączonym śledzeniem.
Każda inna wartość to błąd.
tracking, które nie jest ani obiektem, ani wartością logiczną (np."tracking": "off"), zwraca 400. Do 2026-07 takie wartości były cicho ignorowane — integrator mógł być przekonany, że wyłączył śledzenie, podczas gdy pixel nadal leciał. Jeśli integrowałeś się wcześniej, sprawdź, czy wysyłasz jeden z trzech powyższych kształtów.
Dlaczego to nie jest wyłącznie kwestia dostarczalności
Śledzenie kliknięć przepisuje każdy href na
https://api.mailingapi.com/c/<id>. Jeśli Twoje linki niosą poświadczenia —
tokeny zaproszeń, magic linki, jednorazowe adresy resetu hasła — te
poświadczenia przechodzą przez ten serwis i są w nim logowane. Awaria redirectu
psuje też linki już dostarczone. Dla tej klasy poczty wyłącz śledzenie, zamiast
traktować je jako pokrętło do strojenia folderu spam.
Wysyłka batch
Wyślij wiele spersonalizowanych emaili w jednym żądaniu.
POST /v1/messages/batch
Używając zmiennych odbiorcy
curl -X POST https://api.mailingapi.com/v1/messages/batch \
-H "Authorization: Bearer $API_KEY" \
-H "Content-Type: application/json" \
-d '{
"from": "hello@twojadomena.pl",
"subject": "Witaj, {{name}}!",
"html": "<p>Cześć {{name}}, Twój kod to {{code}}.</p>",
"recipient_variables": {
"alice@example.com": {"name": "Alicja", "code": "ABC123"},
"bob@example.com": {"name": "Robert", "code": "XYZ789"}
}
}'
Używając tablicy wiadomości
curl -X POST https://api.mailingapi.com/v1/messages/batch \
-H "Authorization: Bearer $API_KEY" \
-H "Content-Type: application/json" \
-d '{
"messages": [
{
"from": "hello@twojadomena.pl",
"to": "alice@example.com",
"subject": "Twoja faktura",
"html": "<p>Faktura #001 w załączniku.</p>"
},
{
"from": "hello@twojadomena.pl",
"to": "bob@example.com",
"subject": "Twój paragon",
"html": "<p>Paragon #002 w załączniku.</p>"
}
]
}'
Odpowiedź
Endpoint batch zwraca HTTP 202, gdy samo żądanie jest poprawne — nawet jeśli część lub wszystkie wiadomości zostały odrzucone. Zawsze sprawdzaj data.errors.
| Pole | Opis |
|---|---|
data.total |
Liczba wiadomości w żądaniu |
data.queued |
Liczba wiadomości przyjętych do kolejki wysyłki |
data.errors |
Liczba (liczba całkowita, nie lista) odrzuconych wiadomości |
data.messages |
Jedna pozycja na wiadomość, w kolejności żądania, każda z index |
Każda pozycja ma status równy "queued" lub "error":
-
Przyjęta:
{"index": 0, "status": "queued", "id": "<uuid>", "to": "a@example.com"} -
Odrzucona:
{"index": 1, "status": "error", "to": "b@example.com", "error": {...}}— odrzucone pozycje nie mająid.error.codeto jedno z:validation_failed,forbidden(domena nadawcy),bad_requestlubsend_failed;error.detailswystępuje tylko dlavalidation_failed.
Przykład z dwiema przyjętymi i jedną odrzuconą wiadomością:
{
"data": {
"total": 3,
"queued": 2,
"errors": 1,
"messages": [
{"index": 0, "status": "queued", "id": "550e8400-e29b-41d4-a716-446655440000", "to": "alice@example.com"},
{
"index": 1,
"status": "error",
"to": "bob@example.com",
"error": {
"code": "validation_failed",
"message": "subject: can't be blank",
"details": {"subject": ["can't be blank"]}
}
},
{"index": 2, "status": "queued", "id": "550e8400-e29b-41d4-a716-446655440002", "to": "carol@example.com"}
]
}
}
Limity batcha
-
Maksymalnie 1000 wiadomości na żądanie (lub 1000 odbiorców w trybie
recipient_variables). Przekroczenie odrzuca całe żądanie z400bad_request. - Każda wiadomość jest walidowana i przetwarzana niezależnie — odrzucona wiadomość nie blokuje pozostałych.
-
Każda wiadomość podlega tym samym limitom pól co
/send. -
Idempotency-Keydotyczy całego batcha jako jednej całości — patrz Idempotencja.
Pobierz wiadomość
Pobierz szczegóły wysłanej wiadomości.
GET /v1/messages/{message_id}
Przykładowe żądanie
curl https://api.mailingapi.com/v1/messages/msg_1a2b3c4d5e6f \
-H "Authorization: Bearer $API_KEY"
Odpowiedź
{
"data": {
"id": "550e8400-e29b-41d4-a716-446655440000",
"message_id": "<abc123@mailingapi.com>",
"from": "hello@twojadomena.pl",
"to": "jan@example.com",
"subject": "Twoje zamówienie zostało wysłane",
"status": "delivered",
"sent_at": "2024-01-15T10:30:02Z",
"delivered_at": "2024-01-15T10:30:05Z",
"opened_at": "2024-01-15T11:45:00Z",
"tags": ["transactional", "shipping"],
"metadata": {"user_id": "usr_123", "order_id": "ord_456"},
"created_at": "2024-01-15T10:30:00Z"
}
}
Statusy wiadomości
| Status | Opis |
|---|---|
pending |
Wiadomość utworzona, jeszcze nie w kolejce |
queued |
Wiadomość zaakceptowana, czeka na wysyłkę |
sent |
Wiadomość wysłana do serwera odbiorcy |
delivered |
Wiadomość zaakceptowana przez serwer odbiorcy |
bounced |
Wiadomość odrzucona przez serwer odbiorcy |
failed |
Permanentny błąd |
Lista wiadomości
Pobierz listę wysłanych wiadomości.
GET /v1/messages
Parametry zapytania
| Parametr | Typ | Opis |
|---|---|---|
limit |
integer | Wyników na stronę (domyślnie: 50, max: 100) |
offset |
integer | Pomiń wyniki (domyślnie: 0) |
status |
string | Filtruj po statusie |
to |
string | Filtruj po emailu odbiorcy |
since |
string | Data początkowa (ISO 8601) |
until |
string | Data końcowa (ISO 8601) |
Przykładowe żądanie
curl "https://api.mailingapi.com/v1/messages?status=delivered&since=2024-01-01T00:00:00Z&limit=50" \
-H "Authorization: Bearer $API_KEY"
Odpowiedź
{
"data": [
{
"id": "550e8400-e29b-41d4-a716-446655440000",
"from": "hello@twojadomena.pl",
"to": "jan@example.com",
"subject": "Twoje zamówienie zostało wysłane",
"status": "delivered",
"created_at": "2024-01-15T10:30:00Z"
}
],
"meta": {
"count": 1,
"total": 1250,
"limit": 50,
"offset": 0,
"has_more": true
}
}
Analizuj wiadomość
Zwaliduj email przed wysłaniem. Zwraca spam score i potencjalne problemy.
POST /v1/messages/analyze
Przykładowe żądanie
curl -X POST https://api.mailingapi.com/v1/messages/analyze \
-H "Authorization: Bearer $API_KEY" \
-H "Content-Type: application/json" \
-d '{
"from": "hello@twojadomena.pl",
"to": "user@example.com",
"subject": "Testowy email",
"html": "<p>Treść tutaj</p>"
}'
Odpowiedź
{
"data": {
"score": 85,
"grade": "good",
"issues_count": 1,
"critical_count": 0,
"high_count": 0,
"medium_count": 1,
"low_count": 0,
"can_send": true,
"recommendations": [
"Rozważ dodanie wersji tekstowej dla lepszej dostarczalności"
],
"issues": [
{
"type": "content",
"subtype": "missing_text",
"severity": "medium",
"detail": "Brak wersji tekstowej",
"penalty": 5
}
]
}
}
Zaplanuj wiadomość
Zaplanuj email na przyszłą dostawę. Użyj scheduled_at w żądaniu wysyłki:
curl -X POST https://api.mailingapi.com/v1/messages/send \
-H "Authorization: Bearer $API_KEY" \
-H "Content-Type: application/json" \
-d '{
"from": "hello@twojadomena.pl",
"to": "user@example.com",
"subject": "Świąteczne życzenia",
"html": "<p>Wesołych Świąt!</p>",
"scheduled_at": "2024-12-25T09:00:00Z"
}'
Lista zaplanowanych wiadomości
GET /v1/messages/scheduled
Odpowiedź
{
"data": [
{
"id": "msg_abc123",
"to": "user@example.com",
"subject": "Świąteczne życzenia",
"scheduled_at": "2024-12-25T09:00:00Z",
"status": "scheduled"
}
]
}
Anuluj zaplanowaną wiadomość
DELETE /v1/messages/{message_id}/schedule
Przykładowe żądanie
curl -X DELETE https://api.mailingapi.com/v1/messages/msg_abc123/schedule \
-H "Authorization: Bearer $API_KEY"
Odpowiedź
{
"data": {
"id": "550e8400-e29b-41d4-a716-446655440000",
"status": "cancelled",
"created_at": "2024-01-15T10:30:00Z"
}
}
Eventy wiadomości
Pobierz historię eventów wiadomości.
GET /v1/messages/{message_id}/events
Przykładowe żądanie
curl https://api.mailingapi.com/v1/messages/550e8400-e29b-41d4-a716-446655440000/events \
-H "Authorization: Bearer $API_KEY"
Odpowiedź
{
"data": [
{"id": "evt_1", "type": "queued", "timestamp": "2024-01-15T10:29:55Z", "metadata": {}},
{"id": "evt_2", "type": "sent", "timestamp": "2024-01-15T10:30:00Z", "metadata": {}},
{"id": "evt_3", "type": "delivered", "timestamp": "2024-01-15T10:30:05Z", "metadata": {}},
{"id": "evt_4", "type": "opened", "timestamp": "2024-01-15T11:00:00Z", "metadata": {"user_agent": "Mozilla/5.0"}}
]
}
Typy eventów
| Typ | Opis |
|---|---|
queued |
Wiadomość weszła do kolejki wysyłki |
sent |
Wiadomość przekazana do serwera odbiorcy |
delivered |
Serwer odbiorcy zaakceptował wiadomość |
opened |
Odbiorca otworzył email |
clicked |
Odbiorca kliknął link |
bounced |
Wiadomość została odrzucona |
complained |
Odbiorca oznaczył jako spam |
unsubscribed |
Odbiorca wypisał się |
Kody błędów
Każdy błąd ma stabilny, maszynowo czytelny error.code. Rozgałęziaj logikę po code, nigdy po message. Format i pełną listę kodów opisuje Obsługa błędów.
Kody, które możesz dostać z Messages API:
| 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 | 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 |
Wiadomość nie istnieje | Nie |
409 |
idempotency_request_in_progress |
Ten sam Idempotency-Key wciąż się przetwarza |
Tak, po Retry-After sekundach |
413 |
— | Body żądania większe niż 25 MB | Nie — wyślij mniej danych |
422 |
validation_failed |
Walidacja pól nie przeszła (także limity pól), patrz details |
Nie |
422 |
idempotency_key_reused |
Ten sam klucz, inne 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 |
Tak, po Retry-After sekundach |
429 |
recipient_rate_limited |
Maks. 10 emaili/godzinę i 50/dobę do tego samego odbiorcy w organizacji |
Tak, po Retry-After sekundach |
500 |
internal_error |
Błąd serwera |
Tak, exponential backoff, ten sam Idempotency-Key |