Dokumentacja / API Reference

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-Unsubscribe nie 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.code to jedno z: validation_failed, forbidden (domena nadawcy), bad_request lub send_failed; error.details występuje tylko dla validation_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 z 400 bad_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-Key dotyczy 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