Invio programmato
Imposta scheduled_at per trattenere un messaggio fino a un orario specifico. Quando quell'orario arriva, il messaggio entra nel normale ciclo di vita della consegna e produce gli stessi eventi di un invio immediato. La tua applicazione non ha bisogno di un proprio scheduler.
Programmare un invio
Aggiungi un timestamp scheduled_at a un normale invio POST /v1/email/messages. Il resto del payload non cambia.
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><p><a href="{{ bird.unsubscribe_url }}">Unsubscribe</a></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><p><a href=\"{{ bird.unsubscribe_url }}\">Unsubscribe</a></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><p><a href=\"{{ bird.unsubscribe_url }}\">Unsubscribe</a></p>",
Category: bird.CategoryMarketing,
ScheduledAt: time.Date(2027, 1, 15, 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><p><a href="{{ bird.unsubscribe_url }}">Unsubscribe</a></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><p><a href="{{ bird.unsubscribe_url }}">Unsubscribe</a></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><p><a href=\"{{ bird.unsubscribe_url }}\">Unsubscribe</a></p>",
"category": "marketing",
"scheduled_at": "2027-01-15T09:00:00Z"
}'La chiamata restituisce subito 202 Accepted con l'ID del messaggio prefissato da em_ e status: accepted. È lo stesso oggetto messaggio restituito da un invio immediato, più scheduled_at riportato in UTC, così puoi confermare l'orario di invio senza una lettura successiva. L'accettazione è sincrona; la consegna è differita. Ometti scheduled_at dalla richiesta e il messaggio parte subito, e la risposta non contiene la chiave scheduled_at.
Le letture si aggiornano in modo asincrono. Un messaggio appena programmato può inizialmente restituire 404 tramite Recupera un messaggio e non comparire nell'elenco dei messaggi o nella dashboard. Contenuti di grandi dimensioni o allegati possono prolungare l'attesa mentre li archiviamo. Conserva l'ID e scheduled_at della risposta 202 e riprova le letture con quell'ID, lasciando una pausa tra i tentativi. Puoi anche annullare con questo ID prima che il messaggio compaia.
Quando un messaggio compare mentre è ancora in attesa di invio, le letture mostrano status: scheduled e il suo scheduled_at:
{
"id": "em_01ky7q24hafjgvzfg02v3m177p",
"status": "scheduled",
"scheduled_at": "2027-01-15T09:00:00Z",
"category": "marketing"
}Quando arriva il momento, il messaggio viene rilasciato e il suo stato avanza attraverso gli stati consueti (accepted, poi processed, poi delivered e così via). scheduled_at resta impostato anche dopo, così puoi sempre vedere per quando era programmato un messaggio.
L'invio di un messaggio può iniziare prima che le letture si aggiornino, quindi potresti vedere prima uno stato successivo. Non esiste un intervallo fisso dopo il quale una lettura mostrerà sicuramente il messaggio.
La programmazione consuma un'unità della quota di email programmate della tua organizzazione per il periodo di fatturazione. Il superamento di tale quota viene rifiutato con un 422 (E10003).
Programmare contenuti inline o un modello
Usa scheduled_at con contenuti inline o un modello salvato, costruito come un invio con modello immediato. Fissiamo la versione pubblicata, la lingua selezionata e i valori dei parametri quando accettiamo la richiesta e inviamo quella versione all’ora pianificata. Pubblicare una versione più recente non modifica la selezione. Se il modello viene eliminato prima dell’ora pianificata, il messaggio viene rifiutato senza essere inviato.
Un messaggio della categoria marketing riceve un link di disiscrizione come piccolo piè di pagina alla fine del corpo. Per posizionare il link tu stesso, inserisci {{ bird.unsubscribe_url }} in ogni corpo del messaggio fornito oppure, per un invio con modello, nei corpi del modello.
Un elemento di un batch accetta scheduled_at alle stesse condizioni, quindi un singolo batch può mescolare messaggi programmati e immediati. Ogni elemento programmato consuma la propria unità della quota, e l'intero batch viene rifiutato se l'orario di un qualsiasi elemento è fuori intervallo. Ogni elemento programmato riporta il proprio scheduled_at nella risposta del batch, e un elemento inviato immediatamente non ha la chiave scheduled_at; il riferimento batch mostra entrambi in un'unica risposta.
Un payload di invio immediato può comunque essere troppo grande per la programmazione. Se il body, la lista dei destinatari o i metadati superano il limite di programmazione, API restituisce 422. Riduci quei campi o invia il messaggio immediatamente.
Scegliere l'orario di invio
scheduled_at è un timestamp assoluto RFC 3339. Due regole lo governano:
- Deve essere tra 30 secondi e 30 giorni nel futuro. Meno di 30 secondi o più di 30 giorni viene rifiutato con un
422. Il limite inferiore impedisce a una programmazione di competere con un invio immediato. Trenta giorni è l'orizzonte massimo per cui tratteniamo un messaggio. - Fornisci un istante esatto. Includi un suffisso UTC
Z(2027-01-15T09:00:00Z) o un offset esplicito (2026-07-30T09:00:00-04:00, lo stesso istante di13:00:00Z). Confrontiamo l'istante con l'ora corrente e non interpretiamo mai un'ora locale senza offset né applichiamo il fuso orario del destinatario. Per inviare alle 9:00 nell'ora locale di ciascun destinatario, calcola tu quegli istanti e programma un invio per fuso orario.
Espressioni relative come "in 2 hours" non sono accettate. Invia un timestamp risolto.
Elencare i messaggi programmati
Filtra l'elenco dei messaggi per stato per vedere i messaggi già visibili e ancora in attesa di invio. Un invio programmato appena accettato può non comparire mentre il contenuto viene caricato o le letture si aggiornano:
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 elenca quelli che hai annullato prima dell'invio. Quando un messaggio programmato parte, entra nella pipeline e compare con gli stati di consegna, come qualsiasi altro invio. Il log email della dashboard offre gli stessi filtri Scheduled e Canceled.
Annullare un invio programmato
Annulla un messaggio in qualsiasi momento prima che inizi l'invio con 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"Un annullamento riuscito restituisce 204 No Content. Lo stato del messaggio diventa canceled, il messaggio non viene mai inviato e viene emesso un webhook email.canceled. Quattro cose da sapere:
-
Solo un messaggio ancora programmato può essere annullato. Un messaggio che ha già iniziato l'invio, è già stato inviato o è già stato annullato restituisce
409:Esempio di codice{ "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." } }All'avvicinarsi dell'orario di invio, un annullamento può anche perdere la corsa con l'invio stesso e restituire
409per lo stesso motivo. -
Puoi annullare l’invio mentre il contenuto è ancora in caricamento. Un invio programmato con allegati o un corpo di grandi dimensioni potrebbe ancora memorizzare il contenuto dopo la risposta
202. Un annullamento riuscito resta valido anche se il caricamento termina in seguito. -
L'annullamento non restituisce l'unità della quota di email programmate. L'unità consumata al momento della programmazione resta consumata: è ciò che impedisce a un ciclo programma-e-annulla di aggirare la quota. La tua quota di invio regolare non viene toccata, perché viene addebitata solo quando un messaggio viene effettivamente inviato.
-
L'annullamento è sicuro da riprovare con un
Idempotency-Key, come qualsiasi altra scrittura.
Per spostare un invio programmato a un orario diverso, annullalo e invia un nuovo messaggio con il nuovo scheduled_at. Ottieni un nuovo ID em_.
Cosa succede al momento dell'invio
La programmazione cambia solo quando un messaggio viene rilasciato. La sua costruzione e le sue regole restano le stesse. Allegati, categoria, tag e metadati si comportano esattamente come in un invio immediato e vengono riportati negli eventi webhook allo stesso modo. Cinque controlli si dividono tra i due momenti:
- La validazione del payload e del dominio avviene subito. Un invio programmato malformato fallisce nella chiamata API con un
422, così lo scopri ora e non alle 9 di mattina. - Il dominio del mittente viene ricontrollato al momento dell'invio. Se il tuo dominio
fromnon è più verificato quando arriva l'orario programmato, il messaggio non viene inviato. I suoi destinatari vengono restituiti comerejectedcon un motivo, invece di ricevere email da un dominio non verificato. Mantieni il dominio verificato per tutta la finestra. - La quota di invio viene addebitata al momento dell'invio. La quota di invio regolare viene consumata quando il messaggio parte. La programmazione lascia la quota invariata. Se la quota è esaurita al momento dell'invio, i destinatari vengono rifiutati.
- La soppressione viene valutata al momento dell'invio, in base alla tua lista di soppressione così com'è in quel momento, quindi chi si disiscrive tra la programmazione e l'invio viene comunque rispettato.
- Un modello salvato deve esistere ancora al momento dell'invio. Se elimini il modello dopo la programmazione, il messaggio non viene inviato. I suoi destinatari vengono restituiti come
rejectedcongeneration_failure.
Errori
| Stato | Codice | Quando |
|---|---|---|
422 | E10003 | La quota di email programmate della tua organizzazione per il periodo di fatturazione è esaurita |
422 | scheduled_at è a meno di 30 secondi o a più di 30 giorni di distanza | |
422 | Il payload è troppo grande per essere parcheggiato; riduci body, destinatari o metadati, oppure invia subito | |
409 | E10005 | Il messaggio non può più essere annullato: ha già iniziato l'invio, è stato inviato o è stato annullato |
404 | La lettura del messaggio non ne riflette ancora l'accettazione, oppure non esiste alcun messaggio con quell'ID in questo spazio di lavoro |
Webhook
Due eventi sono specifici della programmazione, oltre ai consueti eventi di consegna:
email.scheduledsegnala un messaggio in attesa dell'orario futuro indicato dascheduled_at. Per gli invii con un modello, la versione selezionata viene caricata di nuovo e il suo contenuto viene preparato al momento dell'invio. Questo evento può arrivare prima che la preparazione sia completata.email.canceledviene emesso quando un messaggio programmato viene annullato prima dell'invio.
Quando il messaggio parte, la normale catena email.accepted prosegue invariata.
Gli eventi di programmazione vengono pubblicati in modo asincrono. Un messaggio può uscire dallo stato programmato prima che venga pubblicato email.scheduled. Ricevere un webhook non significa che gli endpoint di lettura mostrino già quello stato.
Passi successivi
- Invio email: il payload di invio completo e il modello asincrono 202
- Soppressioni: a chi non consegniamo e perché, valutato al momento dell'invio
- Eventi e webhook: gli eventi prodotti da un messaggio programmato dopo la partenza
- Idempotenza: riprovare in sicurezza le chiamate di programmazione e annullamento
- Riferimento API: il contratto completo dell'endpoint di annullamento
- Programmare l'invio di un'email in un secondo momento: un video che mostra un invio programmato e come annullarlo
Risorse correlate
Continua con la documentazione, le guide e gli esempi per questo argomento.