Wysyłanie zaplanowane
Ustaw scheduled_at, aby wstrzymać wiadomość do określonego czasu. Gdy ten czas nadejdzie, wiadomość wchodzi w normalny cykl dostarczania i generuje te same zdarzenia co wysyłka natychmiastowa. Twoja aplikacja nie musi uruchamiać własnego harmonogramu.
Planowanie wysyłki
Dodaj znacznik czasu scheduled_at do zwykłej wysyłki POST /v1/email/messages. Nic innego w payloadzie się nie zmienia.
const msg = await bird.email.send({
from: "news@yourdomain.com",
to: ["delivered@messagebird.dev"],
subject: "Your weekly digest",
html: "<p>Here is what happened this week...</p>",
category: "marketing",
scheduled_at: "2027-01-15T09:00:00Z",
});
console.log(msg.id, msg.status); // "em_…", "accepted"msg = client.email.send(
from_="news@yourdomain.com",
to=["delivered@messagebird.dev"],
subject="Your weekly digest",
html="<p>Here is what happened this week...</p>",
category="marketing",
scheduled_at="2027-01-15T09:00:00Z",
)
print(msg.id, msg.status)package main
import (
"context"
"fmt"
"log"
"os"
"time"
bird "github.com/messagebird/bird-sdk-go"
"github.com/messagebird/bird-sdk-go/option"
)
func main() {
client, err := bird.NewClient(option.WithAPIKey(os.Getenv("BIRD_API_KEY")))
if err != nil {
log.Fatal(err)
}
msg, err := client.Email.Send(context.Background(), bird.EmailSendParams{
From: "news@yourdomain.com",
To: []string{"delivered@messagebird.dev"},
Subject: "Your weekly digest",
HTML: "<p>Here is what happened this week...</p>",
Category: bird.CategoryMarketing,
ScheduledAt: time.Date(2026, 7, 30, 9, 0, 0, 0, time.UTC),
})
if err != nil {
log.Fatal(err)
}
fmt.Println(msg.Id, *msg.Status)
}$message = $bird->email->send(
from: 'news@yourdomain.com',
to: ['delivered@messagebird.dev'],
subject: 'Your weekly digest',
html: '<p>Here is what happened this week...</p>',
category: 'marketing',
scheduledAt: new \DateTimeImmutable('2027-01-15T09:00:00Z'),
);
echo $message->getId(), ' ', $message->getStatus();bird email send \
--from news@yourdomain.com \
--to delivered@messagebird.dev \
--subject 'Your weekly digest' \
--html '<p>Here is what happened this week...</p>' \
--category marketing \
--scheduled-at 2027-01-15T09:00:00Zcurl -X POST https://us1.platform.bird.com/v1/email/messages \
-H "Authorization: Bearer bk_us1_..." \
-H "Content-Type: application/json" \
-d '{
"from": "news@yourdomain.com",
"to": ["delivered@messagebird.dev"],
"subject": "Your weekly digest",
"html": "<p>Here is what happened this week...</p>",
"category": "marketing",
"scheduled_at": "2027-01-15T09:00:00Z"
}'Wywołanie natychmiast zwraca 202 Accepted z ID wiadomości z prefiksem em_ oraz status: accepted. Jest to ten sam obiekt wiadomości, który zwraca wysyłka natychmiastowa, plus scheduled_at zwrócony w UTC, dzięki czemu możesz potwierdzić czas wysyłki bez dodatkowego odczytu. Przyjęcie jest synchroniczne, dostarczenie jest odroczone. Pomiń scheduled_at w żądaniu, a wiadomość zostanie wysłana od razu; odpowiedź nie będzie zawierać klucza scheduled_at.
Na endpointach odczytu wiadomość pokazuje status: scheduled ze swoim scheduled_at do momentu nadejścia czasu wysyłki:
Przykład kodu
{
"id": "em_01ky7q24hafjgvzfg02v3m177p",
"status": "scheduled",
"scheduled_at": "2027-01-15T09:00:00Z",
"category": "marketing"
}Gdy czas nadchodzi, wiadomość zostaje zwolniona, a jej status przechodzi przez zwykłe stany (accepted, potem processed, potem delivered itd.). scheduled_at pozostaje ustawiony po wysłaniu, więc zawsze możesz sprawdzić, na kiedy wiadomość była zaplanowana.
Zaplanowanie wysyłki zużywa jedną jednostkę limitu zaplanowanych e-maili Twojej organizacji w danym okresie rozliczeniowym. Przekroczenie tego limitu jest odrzucane z błędem 422 (E10003).
Zaplanowana wysyłka używa treści inline
scheduled_at i template wzajemnie się wykluczają, a wysyłka ustawiająca oba jest odrzucana z błędem 422. Taka jest zasada: zaplanowana wysyłka ma własny subject i treść, a wysyłka z szablonem jest realizowana natychmiast. Aby zaplanować treść szablonu, najpierw wyrenderuj jego temat i treść. Dashboard oraz bird CLI pokazują dokładny temat, HTML i tekst, które wysyłka z szablonem dostarczyłaby. Zaplanuj te wyrenderowane wartości jako treść inline.
Element batch przyjmuje scheduled_at na tych samych zasadach, więc jeden batch może łączyć wiadomości zaplanowane i natychmiastowe. Każdy zaplanowany element zużywa własną jednostkę limitu, a cały batch jest odrzucany, jeśli czas dowolnego elementu jest poza zakresem. Każdy zaplanowany element zwraca własny scheduled_at w odpowiedzi batcha, a element wysyłany natychmiast nie ma klucza scheduled_at; dokumentacja batch pokazuje oba przypadki w jednej odpowiedzi.
Payload wysyłki natychmiastowej może być zbyt duży do zaplanowania. Jeśli jego treść, lista odbiorców lub metadane przekraczają limit planowania, API zwraca 422. Zmniejsz te pola lub wyślij wiadomość natychmiast.
Wybór czasu wysyłki
scheduled_at to absolutny znacznik czasu RFC 3339. Obowiązują dwie reguły:
- Musi przypadać między 30 sekund a 30 dni w przyszłości. Bliżej niż 30 sekund lub dalej niż 30 dni oznacza odrzucenie z błędem 422. Dolna granica zapobiega wyścigowi z wysyłką natychmiastową. Trzydzieści dni to najdalszy horyzont, przez który przechowujemy wiadomość.
- Podaj dokładny moment. Dołącz sufiks UTC Z (2027-01-15T09:00:00Z) lub jawne przesunięcie (2026-07-30T09:00:00-04:00, ten sam moment co 13:00:00Z). Porównujemy podany moment z bieżącym czasem i nigdy nie interpretujemy samego czasu lokalnego ani nie stosujemy strefy czasowej odbiorcy. Aby wysłać o 9:00 w czasie lokalnym każdego odbiorcy, oblicz te momenty samodzielnie i zaplanuj osobną wysyłkę dla każdej strefy.
Wyrażenia względne, takie jak "in 2 hours", nie są akceptowane. Wyślij rozwiązany znacznik czasu.
Wyświetlanie zaplanowanych wiadomości
Przefiltruj listę wiadomości po statusie, aby zobaczyć wiadomości, które jeszcze nie zostały wysłane:
for await (const message of bird.email.list({ status: "scheduled" })) {
console.log(message.id, message.scheduled_at);
}for message in client.email.list(status="scheduled"):
print(message.id, message.scheduled_at)for msg, err := range client.Email.List(context.Background(), bird.EmailListParams{Status: bird.EmailStatusScheduled}) {
if err != nil {
log.Fatal(err)
}
fmt.Println(msg.Id)
}foreach ($bird->email->list(['status' => 'scheduled']) as $message) {
echo $message->getId(), "\n";
}bird email list --status scheduledcurl "https://us1.platform.bird.com/v1/email/messages?status=scheduled" \
-H "Authorization: Bearer bk_us1_..."status=canceled wyświetla te, które anulowałeś przed wysłaniem. Gdy zaplanowana wiadomość zostanie wysłana, przechodzi do pipeline i pojawia się ze statusami dostarczenia, tak samo jak każda inna wysyłka. Log e-maili w dashboardzie oferuje te same filtry Scheduled i Canceled.
Anulowanie zaplanowanej wysyłki
Anuluj wiadomość w dowolnym momencie przed rozpoczęciem wysyłki za pomocą POST /v1/email/messages/{message_id}/cancel:
await bird.email.cancel("em_abc123");client.email.cancel("em_abc123")if err := client.Email.Cancel(context.Background(), "em_abc123"); err != nil {
log.Fatal(err)
}$bird->email->cancel('em_01krdgeqcxet5s7t44vh8rt9mg');bird email cancel <message-id> --yescurl -X POST "https://{region}.platform.bird.com/v1/email/messages/{message_id}/cancel" \
-H "Authorization: Bearer $TOKEN"Pomyślne anulowanie zwraca 204 No Content. Status wiadomości zmienia się na canceled, wiadomość nigdy nie zostaje wysłana i uruchamiany jest webhook email.canceled. Cztery rzeczy, o których warto wiedzieć:
-
Anulować można tylko wiadomość wciąż zaplanowaną. Wiadomość, której wysyłka już się rozpoczęła, która została już wysłana lub już anulowana, zwraca 409:Przykład kodu
{ "error": { "type": "conflict_error", "code": "E10005", "name": "EmailNotCancelable", "message": "This message cannot be canceled.", "remediation": "Only a scheduled message that has not started sending can be canceled. Once sending begins there is no way to pull it back." } }W momencie nadejścia czasu wysyłki anulowanie może też przegrać wyścig z samą wysyłką i zwrócić 409 z tego samego powodu. -
Duża wysyłka może potrzebować kilku sekund, zanim będzie można ją anulować. Zaplanowana wysyłka z załącznikami lub dużą treścią wciąż zapisuje zawartość po 202, więc:
- Anulowanie w tym oknie zwraca 409, a wiadomość pozostaje zaplanowana.
- Odczytaj wiadomość ponownie.
- Jeśli wciąż pokazuje status: scheduled, spróbuj ponownie anulować.
-
Anulowanie nie zwraca jednostki limitu zaplanowanych e-maili. Jednostka zużyta w momencie planowania pozostaje zużyta, co uniemożliwia obchodzenie limitu przez pętlę planuj-anuluj. Twój zwykły limit wysyłek pozostaje nienaruszony, ponieważ jest naliczany dopiero wtedy, gdy wiadomość faktycznie zostaje wysłana.
-
Anulowanie można bezpiecznie ponawiać z użyciem Idempotency-Key, tak jak każdą inną operację zapisu.
Aby przenieść zaplanowaną wysyłkę na inny czas, anuluj ją i wyślij nowe żądanie z nowym scheduled_at. Otrzymasz nowy identyfikator em_.
Co dzieje się w momencie wysyłki
Planowanie zmienia tylko moment zwolnienia wiadomości. Jej budowa i reguły pozostają takie same. Załączniki, kategoria, tagi i metadane działają dokładnie tak samo jak przy wysyłce natychmiastowej i są zwracane w zdarzeniach webhooka w ten sam sposób. Cztery kontrole rozłożone na dwa momenty:
- Walidacja payloadu i domeny odbywa się od razu. Nieprawidłowa zaplanowana wysyłka kończy się błędem na wywołaniu API z odpowiedzią 422, więc dowiadujesz się teraz, a nie o 9:00.
- Domena nadawcy jest ponownie sprawdzana w momencie wysyłki. Jeśli Twoja domena from nie jest już zweryfikowana w zaplanowanym momencie, wiadomość nie zostaje wysłana. Odbiorcy są zwracani jako rejected z podaniem przyczyny, zamiast otrzymać wiadomość z niezweryfikowanej domeny. Utrzymuj domenę zweryfikowaną przez cały okres oczekiwania.
- Twój limit wysyłek jest naliczany w momencie wysyłki. Zwykły limit wysyłek jest zużywany w chwili wysłania wiadomości. Zaplanowanie nie zmienia limitu. Jeśli limit jest wyczerpany w momencie wysyłki, odbiorcy są odrzucani.
- Supresja jest oceniana w momencie wysyłki, względem Twojej listy supresji w jej aktualnym stanie, więc osoba, która wypisze się między zaplanowaniem a wysyłką, jest uwzględniana.
Błędy
| Status | Kod | Kiedy |
|---|---|---|
| 422 | E10003 | Limit zaplanowanych e-maili Twojej organizacji na dany okres rozliczeniowy został wyczerpany |
| 422 | scheduled_at jest bliżej niż 30 sekund lub dalej niż 30 dni | |
| 422 | scheduled_at został połączony z template | |
| 422 | Payload jest zbyt duży do zaplanowania; zmniejsz treść, odbiorców lub metadane albo wyślij teraz | |
| 409 | E10005 | Wiadomości nie można już anulować: wysyłka już się rozpoczęła, została wysłana lub anulowana |
| 404 | Brak wiadomości o tym ID w tym obszarze roboczym |
Webhooki
Dwa zdarzenia są specyficzne dla planowania, oprócz zwykłych zdarzeń dostarczenia:
- email.scheduled jest wysyłany, gdy wiadomość zostaje przyjęta z przyszłym scheduled_at, i raportuje ten czas.
- email.canceled jest wysyłany, gdy zaplanowana wiadomość zostaje anulowana przed wysłaniem.
Gdy wiadomość zostanie wysłana, normalny łańcuch email.accepted następuje bez zmian.
Następne kroki
- Wysyłanie e-maili: pełny payload wysyłki i asynchroniczny model 202
- Supresje: do kogo nie dostarczamy i dlaczego, oceniane w momencie wysyłki
- Zdarzenia i webhooki: zdarzenia generowane przez zaplanowaną wiadomość po jej wysłaniu
- Idempotentność: bezpieczne ponawianie wywołań planowania i anulowania
- Dokumentacja API: pełny kontrakt endpointu anulowania
- Zaplanuj wysyłkę e-maila na później: film pokazujący zaplanowaną wysyłkę i sposób jej anulowania
Powiązane zasoby
Kontynuuj z dokumentacją, przewodnikami i przykładami dotyczącymi tego tematu. Zasoby są w języku angielskim.