Sign inGet Started

Invio di email

POST /v1/email/messages invia una singola email. Fornisci un mittente, i destinatari e il contenuto in un payload JSON. L'API restituisce 202 Accepted con un ID messaggio, poi consegna l'email in modo asincrono. Consulta il reference di API per gli schemi completi.

Un invio minimale

Il payload valido più piccolo è un from, almeno un destinatario to, un subject e un corpo (html, text o entrambi). L'indirizzo from deve trovarsi su un dominio che hai verificato in questo spazio di lavoro oppure sul dominio di onboarding.

const msg = await bird.email.send({
  from: { email: "onboarding@messagebird.dev", name: "Bird" },
  to: ["delivered@messagebird.dev"],
  subject: "Hello from Bird",
  html: "<p>My first Bird email.</p>",
});
console.log(msg.id, msg.status); // "em_…", "accepted"

Usa il tuo host regionale (https://us1.platform.bird.com o https://eu1.platform.bird.com) con una chiave bk_{region}_... corrispondente.

L'esempio di invio usa delivered@messagebird.dev, un indirizzo sandbox che accetta sempre la posta. L'API rifiuta i domini segnaposto con un 422: example.com, example.net, example.org, example.edu, test.com e qualsiasi dominio sotto i TLD riservati .test, .example, .invalid o .localhost. Un invio a questi domini può solo rimbalzare, il che danneggia la tua reputazione di mittente.

Invio prima della verifica di un dominio

Durante l'onboarding puoi inviare dal nostro dominio di onboarding condiviso, onboarding@messagebird.dev. Questi invii saltano il controllo del dominio, ma raggiungono solo i membri verificati del tuo spazio di lavoro e gli indirizzi sandbox, con un limite giornaliero di destinatari. Il quickstart contiene le regole e i limiti esatti.

Costruire il payload

Destinatari

to, cc e bcc accettano ciascuno fino a 50 indirizzi, e to ne richiede almeno uno. Ogni voce è una stringa email semplice, una stringa mailbox RFC 5322 (Jane <jane@acme.com>) o un oggetto con un nome visualizzato opzionale.

I destinatari presenti nella lista di soppressione dello spazio di lavoro non fanno fallire la richiesta. Viene comunque restituito un 202, e ogni destinatario soppresso appare sugli endpoint di lettura come status: rejected con la motivazione recipient_suppressed, anche quando si tratta di tutti i destinatari dell'invio.

Contenuto

subject è obbligatorio per gli invii inline, fino a 998 caratteri. Fornisci html, text o entrambi, ciascuno fino a 524.288 caratteri. Invia entrambi quando possibile: un client che non riesce a visualizzare l'HTML ripiega sulla parte di testo.

Per personalizzare il contenuto inline, inserisci token {{ variable }} nell'oggetto o nel corpo e passa i relativi valori in parameters, fino a 16 KB serializzati. Un unico set di valori vale per tutti i destinatari dell'invio, e un token senza chiave corrispondente viene visualizzato vuoto. Per i contenuti che riutilizzi, invia invece un template.

Includi parameters, anche come oggetto vuoto ({}), per elaborare l'oggetto e il corpo come Liquid. Omettilo per inviare token come {{ animal }} esattamente come scritti. Ogni nome di parametro è una singola parola, ad esempio first_name; i nomi con punti e il nome riservato bird vengono rifiutati. Una sintassi Liquid non valida e tag o filtri non supportati restituiscono 422.

I valori inseriti nell'HTML vengono sottoposti a escape, così non possono alterare il markup circostante. Per un link completo o l'URL di un'immagine, usa {{ link }} senza url_encode. Per un valore all'interno della query di un URL, codifica quel valore esplicitamente, ad esempio https://example.com/search?q={{ query | url_encode }}.

Reply-to e header personalizzati

reply_to accetta da 1 a 25 indirizzi, negli stessi formati dei destinatari. Ogni risposta di un destinatario va a tutti questi indirizzi, quindi di solito se ne indicano uno o due.

headers è un oggetto stringa-stringa per i tuoi header, ad esempio {"X-Campaign": "spring-2026"}, con un massimo di 25 header e valori fino a 998 caratteri. Due tipi di header vengono rifiutati con un 422:

  • Header di indirizzamento e di piattaforma. Imposta l'indirizzamento del messaggio tramite i campi dedicati (from, to, cc, bcc, reply_to, subject). Quei nomi, e gli header che generiamo per te (Content-Type, Content-Transfer-Encoding, DKIM-Signature, Received, Return-Path), non possono essere impostati qui.
  • Qualsiasi valore con un ritorno a capo o un avanzamento riga.

Gli invii transazionali accettano List-Unsubscribe e List-Unsubscribe-Post. Gli invii marketing usano per impostazione predefinita la disiscrizione gestita da Bird.

Tracciamento

track_opens e track_clicks hanno entrambi il valore predefinito true. Imposta uno dei due a false per saltare l'iniezione del pixel di apertura o la riscrittura dei link su questo invio. Questi flag lasciano intatti i pixel di tracciamento e i link già presenti nel contenuto che invii. Tracciamento e metriche descrive cosa ciascuno modifica nel messaggio.

Categoria e pool di IP

category classifica il contenuto e imposta la policy di soppressione: marketing blocca la consegna per qualsiasi motivo di soppressione e per qualsiasi opt-out, mentre transactional consegna nonostante una soppressione per reclamo o un opt-out solo marketing (un opt-out registrato per tutti i messaggi lo blocca comunque). Il valore predefinito è la categoria del template su un invio con template e marketing altrimenti, quindi imposta transactional esplicitamente per ricevute, reset di password e altra posta operativa. Categorie tratta la scelta. La posta inviata tramite SMTP prende invece la categoria dalla configurazione SMTP della chiave.

ip_pool_id seleziona il pool di invio: un ID pool (ipp_...), oppure ipp_shared per instradare esplicitamente attraverso il pool condiviso. Omettilo per usare il pool predefinito della tua organizzazione. Un pool sconosciuto, o uno senza IP dedicati disponibili per l'invio, viene rifiutato con un 422.

Riferimento dei campi

CampoTipoObbligatorioLimiti e note
fromaddresssìDeve trovarsi su un dominio verificato o sul dominio di onboarding
toaddress[]sìDa 1 a 50
cc, bccaddress[]noFino a 50 ciascuno
subjectstringinvii inlineFino a 998 caratteri; omettere negli invii con template
html, textstringalmeno unoFino a 524.288 caratteri ciascuno; omettere negli invii con template
reply_toaddress[]noDa 1 a 25; le risposte raggiungono tutti gli indirizzi elencati
headersobject (string → string)noFino a 25; nomi riservati rifiutati (vedi header personalizzati)
parametersobjectnoValori per {{ tokens }} nel contenuto inline; fino a 16 KB serializzati; condivisi tra i destinatari
tags{name, value}[]noFino a 20; nome ≤ 32 caratteri, valore ≤ 64 caratteri; solo [A-Za-z0-9_-]; nomi univoci per invio
metadataobjectnoJSON arbitrari, fino a 2 KB serializzati
referencestringnoDa 1 a 255 caratteri; corrispondenza esatta per ?reference= nell'elenco messaggi
track_opensbooleannoPredefinito true
track_clicksbooleannoPredefinito true
categorystringnomarketing o transactional; predefinito quello del template su un invio con template, altrimenti marketing
ip_pool_idstringnoipp_... o ipp_shared; omettere per il pool predefinito della tua organizzazione
templateobjectnoInvia un template pubblicato per id o slug, con parameters per le sue variabili e un language opzionale
attachmentsobject[]noFino a 20; vedi allegati
scheduled_atRFC 3339 timestampnoProgramma l'invio di contenuto inline o di un template; vedi invio programmato

Invio con un template

I template possono usare i valori bird.contact.* del contatto che corrisponde a ciascun indirizzo To. I destinatari Cc e Bcc ricevono una copia dell'email personalizzata di ciascun destinatario To. Questo funziona anche nel API in batch e per gli invii programmati; consulta Personalizzazione con variabili per un esempio con più destinatari.

Anziché contenuto inline, invia un template pubblicato: imposta template su un oggetto che lo identifica per id (emt_...) o per slug, esattamente uno dei due, con i valori delle variabili in template.parameters. Ometti subject, html e text, perché il template li contiene già.

const msg = await bird.email.send({
  from: { email: "onboarding@messagebird.dev", name: "Bird" },
  to: ["delivered@messagebird.dev"],
  category: "transactional",
  template: {
    slug: "welcome-email",
    parameters: { first_name: "Jane" },
  },
});
console.log(msg.id, msg.status);

Il contenuto di un template è Liquid, quindi oltre alla semplice sostituzione {{ variable }} può usare filtri, condizionali {% if %} e cicli {% for %}. Personalizzazione con variabili elenca i pochi costrutti rifiutati alla pubblicazione. In template.parameters inserisci i valori per i parametri del template, indicizzati per nome. Se ne ometti uno, l'invio viene rifiutato con un 422 che lo indica. L'invio supporta gli stessi tags, metadata, tracciamento e allegati dell'email inline. Cosa è specifico di un invio con template:

  • Inline o con template, mai entrambi. Inviare template insieme a subject, html o text viene rifiutato con un 422. L'API rifiuta anche i valori delle variabili nel campo di primo livello parameters; in un invio con template vanno in template.parameters.
  • bird è l'unico nome riservato. Un percorso placeholder che inizia con bird. identifica dati nostri, come il link di disiscrizione o il record del contatto del destinatario, quindi una chiave template.parameters non può chiamarsi bird. Tutte le altre chiavi sono definibili da te, e ognuna è una singola parola: {"order_number": "A-1043"} riempie {{ order_number }}.
  • Un template può essere inviato subito o in un secondo momento. Aggiungi scheduled_at per programmare l'invio. Al momento dell'accettazione salviamo la versione pubblicata, la lingua selezionata, i parametri del chiamante e i valori dei contatti, quindi le modifiche successive ai contatti o ai fallback non cambiano i messaggi già accettati. Se elimini il template prima dell'orario di invio, il messaggio viene rifiutato con generation_failure.
  • Personalizza con gli attributi del contatto. Consulta requisiti dei contatti e saluti predefiniti.
  • La corrispondenza dei contatti ignora i nomi visualizzati. Gli indirizzi email vengono convertiti in minuscolo, mantenendo punti e tag con il segno più. Se più contatti condividono quell'indirizzo, l'invio restituisce EmailTemplateContactAmbiguous; aggiorna i record duplicati prima di riprovare.
  • L'invio usa i permessi email. Una chiave con emails:write può inviare un template pubblicato senza il permesso di individuazione dei contatti. emails:read concede l'accesso al contenuto non sensibile del messaggio risultante. L'individuazione di contatti e proprietà mantiene i permessi esistenti.
  • Un invio usa la versione pubblicata del template. Le bozze non vengono mai inviate. Un template sconosciuto viene rifiutato con un 404, e un template senza versione pubblicata con un 422.
  • language seleziona una delle lingue del template. Omettilo per inviare la lingua predefinita del template. Chiedi una lingua che il template non ha, e la sua impostazione on_missing_language decide se viene inviata la corrispondenza più vicina o se l'invio viene rifiutato. Un template che imposta language_source_required rifiuta un invio che non specifica alcuna lingua.
  • La categoria del template è un valore predefinito, e la tua lo sovrascrive. Ometti category e l'invio eredita quella del template, quindi un template transazionale non ha bisogno di ripeterla a ogni chiamata.

Template email tratta la creazione, la pubblicazione e i costrutti che un template può contenere.

Leggere il contenuto per un destinatario

La cronologia dei messaggi con template usa i valori dei contatti salvati al momento dell'accettazione dell'invio, anche se in seguito modifichi o elimini il contatto. Ogni consegna in copia ha il proprio ID destinatario.

Elenca i destinatari del messaggio per ottenerne gli ID, poi passa recipient_id a Get stored message content. Un nuovo messaggio con template con più snapshot di destinatari restituisce 422 senza quel selettore. Un singolo destinatario viene selezionato automaticamente; un destinatario che appartiene a un altro messaggio restituisce 404.

Le risposte GET e di elenco dei messaggi usano l'oggetto accettato per il primo destinatario To, identificato da subject_recipient_id. L'elenco dei destinatari fornisce l'oggetto di ciascun destinatario. Questi oggetti restano disponibili anche quando l'archiviazione del corpo è disabilitata. Le letture del contenuto seguono comunque le impostazioni di archiviazione e conservazione del messaggio, inclusi 404 quando il contenuto non è archiviato, 425 mentre è in attesa e 410 dopo la scadenza.

Se uno snapshot di destinatario conservato diventa non disponibile, lo stato del messaggio e l'oggetto rappresentativo restano leggibili, ma gli oggetti per destinatario vengono omessi e il contenuto non è disponibile. Le letture non consultano i valori attuali dei contatti per ricostruire un invio precedente.

Tag e metadati a confronto

Questi campi associano dati tuoi a un invio e differiscono nel modo in cui li interroghi successivamente:

  • I tags sono coppie {name, value} strutturate: fino a 20 per invio, nome fino a 32 caratteri, valore fino a 64, solo lettere ASCII, cifre, underscore e trattino, e nomi univoci all'interno dell'invio. I tag sono dimensioni di filtro, quindi puoi filtrare l'elenco messaggi per tag e segmentare analytics e aggregazioni dashboard per tag. Usali per etichette a bassa cardinalità come campaign, experiment_variant o source.
  • I metadata sono un oggetto JSON arbitrario, fino a 2 KB serializzati. Li conserviamo, li restituiamo nelle letture API e li includiamo in ogni evento webhook, quindi sono adatti a contesti che vuoi ricevere indietro: ID interni, chiavi esterne, payload strutturati.
  • reference è una stringa da 1 a 255 caratteri con cui vuoi ritrovare il messaggio, ad esempio un numero d'ordine o di ticket. GET /v1/email/messages?reference= la confronta in modo esatto, distinguendo maiuscole e minuscole, e più messaggi possono condividere lo stesso valore. Viene restituita nelle letture e inclusa negli eventi webhook del messaggio. Impostala solo se devi cercare in base a essa, e inserisci tutti gli altri dati in metadata.

Ogni evento webhook include i tag e i metadati insieme agli ID di correlazione (email_id, recipient_id), così puoi riconciliare i dati con i tuoi record senza una seconda ricerca. I nomi dei tag e le chiavi di metadati di primo livello che iniziano con __bird vengono rifiutati. Non è necessario codificare dispositivo, area geografica, provider di casella di posta, tipo di bounce o dominio del destinatario in nessuno dei due campi, perché registriamo già ciascuno di questi come dimensione di analytics.

Esempio di codice
{
  "tags": [{ "name": "campaign", "value": "onboarding" }],
  "metadata": { "user_id": "usr_12345", "order_id": "ord_98765" },
  "reference": "ord_98765"
}

Allegati

attachments accetta fino a 20 file per messaggio, come byte codificati in base64 inline. Rifiutiamo un invio la cui dimensione stimata del messaggio generato supera 20 MB, misurata dopo la codifica base64, quindi mantieni il contenuto grezzo degli allegati a 15 MB o meno per avere margine. Allegati contiene il contratto dei campi, le immagini inline, i tipi di file bloccati e come scaricare un allegato.

Cosa significa un 202

Un invio riuscito restituisce 202 Accepted con un ID messaggio prefissato da em_ e status: accepted:

Esempio di codice
{
  "id": "em_01ky7ma8y2es1s2akzk53tmjn0",
  "status": "accepted",
  "category": "marketing",
  "from": { "email": "hello@yourdomain.com" },
  "to": [{ "email": "delivered@messagebird.dev" }],
  "subject": "Hello from Bird",
  "accepted_count": 1,
  "processed_count": 0,
  "delivered_count": 0,
  "deferred_count": 0,
  "bounced_count": 0,
  "complained_count": 0,
  "rejected_count": 0,
  "open_count": 0,
  "click_count": 0,
  "track_opens": true,
  "track_clicks": true,
  "created_at": "2026-07-23T13:58:20.866Z"
}

Il 202 significa che l'invio è stato accettato in modo durevole. Gli errori che puoi correggere tornano sulla richiesta stessa come 422: un dominio mittente non verificato o un campo non valido. Gli esiti per destinatario (consegnato, respinto, differito, segnalato) arrivano successivamente tramite i webhook e gli endpoint di lettura del messaggio.

Da questo derivano due conseguenze:

  • Le letture restituiscono lo stato senza il corpo. GET /v1/email/messages/{message_id} restituisce lo stato del messaggio e dei destinatari, mai il corpo html o text. Quando l'archiviazione dei contenuti è abilitata per lo spazio di lavoro, i corpi archiviati restano disponibili fino a 30 giorni da GET /v1/email/messages/{message_id}/content.
  • Una lettura può seguire brevemente l'invio. Un 404 sugli endpoint di lettura subito dopo un 202 significa che il messaggio non è ancora visibile: riprova dopo un momento.

Riprovare in sicurezza

Invia un header Idempotency-Key con un valore univoco per ogni invio logico. Se una richiesta è riuscita ma non hai mai visto la risposta, ripetila con la stessa chiave. L'API restituisce il risultato originale invece di inviare una seconda email e include un header Idempotency-Replay. Idempotenza contiene il formato della chiave e la durata di conservazione.

Invio in batch

Per ridurre le richieste API, POST /v1/email/batches accetta fino a 100 messaggi indipendenti e li valida come un'unica unità. Anche chiamare l'endpoint di invio singolo in un ciclo è supportato. Ogni elemento del batch usa il payload descritto in questa pagina, scheduled_at incluso, quindi un singolo batch può combinare messaggi immediati e programmati.

Costi e fatturazione

Gli invii email vengono conteggiati per destinatario, quindi un messaggio a tre destinatari conta come tre invii. Con il piano Email Free, gli invii vengono conteggiati nella quota mensile e giornaliera del piano. Con un piano Email a pagamento, ogni invio viene addebitato sul tuo wallet alla tariffa del piano per 1.000 email. Fatturazione e utilizzo descrive il modello di conteggio e la lettura dell'utilizzo in tempo reale, e la pagina dei prezzi email elenca la tariffa di ogni piano.

Prossimi passi

Continua con la documentazione, le guide e gli esempi per questo argomento.