Template: Crea, Versiona e Test
Gestisci template email versionati con sostituzione di variabili
I template sono template email riutilizzabili con variabili placeholder. Invece di comporre HTML nel codice ogni volta, definisci un template una volta e invialo centinaia di volte con variabili diverse.
Due Formati: HTML e Markdown
Ogni template ha un format, scelto alla creazione e immutabile dopo:
html(default) — l'HTML dell'email lo fornisci tu. Tutto in questa pagina usa questo formato.emailmd— fornisci markdown nel campomarkdown; il server lo renderizza in HTML responsive ed email-safe al salvataggio e memorizza il markdown comesource. Il campohtmldella risposta è l'output renderizzato e non può essere impostato direttamente (inviarehtmlper questo formato fallisce con 422). Un endpoint statelessPOST /v1/templates/render-previewrenderizza il markdown senza salvare.
I template markdown hanno una guida dedicata — sintassi, modello di sicurezza,
flusso end-to-end: Template Markdown.
Le risposte in questa pagina omettono il campo format per brevità; i
template creati prima dell'esistenza dei formati sono html.
Crea un Template
Un template è un nome più un corpo. La richiesta accetta name, format e
uno fra html e markdown — nient'altro.
Un template non ha un oggetto. Non esiste un campo subject sul template,
né un campo text che tu possa impostare: l'oggetto appartiene al singolo
invio. Passarlo in questa richiesta non ha alcun effetto — viene scartato in
silenzio, non memorizzato.
cURL
curl -X POST https://api.tratto.email/v1/templates \
-H "Authorization: Bearer tratto_live_..." \
-H "Content-Type: application/json" \
-d '{
"name":"Email di Benvenuto",
"html":"<h1>Benvenuto, {{firstName}}!</h1><p>Il tuo codice: {{code}}</p>"
}'Risposta:
{
"data": {
"id": "tmpl_abc123",
"name": "Email di Benvenuto",
"html": "<h1>Benvenuto, {{firstName}}!</h1><p>Il tuo codice: {{code}}</p>",
"status": "draft",
"version": 1,
"createdAt": "2025-06-30T12:00:00Z",
"updatedAt": "2025-06-30T12:00:00Z"
}
}Pubblica prima di inviare
Un template nasce con status: "draft", e status accetta draft o
published. Solo un template published può essere usato per inviare.
Pubblicare è un passaggio, non un'etichetta: il template deve essere
published, e qualsiasi altro stato viene rifiutato.
Pubblicalo come qualsiasi altro aggiornamento di campo:
cURL
curl -X PATCH https://api.tratto.email/v1/templates/tmpl_abc123 \
-H "Authorization: Bearer tratto_live_..." \
-H "Content-Type: application/json" \
-d '{"status":"published"}'status è anche un filtro sull'endpoint di elenco:
GET /v1/templates?status=published.
Dove si applica il gate
| Cosa fai con un template in bozza | Cosa succede |
|---|---|
POST /v1/campaigns con templateId | 422 TEMPLATE_NOT_PUBLISHED |
PATCH /v1/campaigns/:id che sostituisce templateId | 422 TEMPLATE_NOT_PUBLISHED |
POST /v1/flows/:id/activate con uno step send_email che lo usa | 422 TEMPLATE_NOT_PUBLISHED (404 se il template non esiste) |
POST /v1/emails con templateId | accettata, poi l'email viene marcata failed e non parte |
POST /v1/templates/:id/test-send | permesso, vedi sotto |
Gli errori di campagne e flussi hanno questa forma:
{
"error": {
"code": "TEMPLATE_NOT_PUBLISHED",
"message": "Template 'tmpl_abc123' is not published and cannot be used to send.",
"docs": "https://docs.tratto.email/en/docs/error-codes",
"suggestion": "Publish the template first: PATCH /v1/templates/:id with { \"status\": \"published\" }, or use the Publish button in the template editor."
}
}All'attivazione di un flusso il messaggio nomina anche lo step:
Template 'tmpl_abc123' on step 's0' is not published and cannot be used to send.
POST /v1/emails non legge il template quando accetta la richiesta, quindi
risponde comunque 202. Il gate viene applicato dal worker di consegna:
l'email finisce con status: "failed" e non parte nulla. Con l'API 0.29.0 o
successiva GET /v1/emails/{id} restituisce
failureReason: "template_not_published", e i webhook iscritti a failed
ricevono un evento failed il cui
data.error è
Template 'tmpl_abc123' is not published and cannot be used to send.
L'email resta comunque persa, quindi non inviare con una bozza. Lo stesso vale
se un template viene de-pubblicato dopo che un'email è già stata messa in coda
con quel template.
I test-send sono esenti. POST /v1/templates/:id/test-send funziona anche
su un template draft: controllare una bozza in una casella vera è esattamente
il punto, ed è l'unico modo di rivederla prima di pubblicarla. Il test di una
campagna non è toccato in nessun caso: invia la copia dell'HTML che la campagna
possiede e non risolve mai un template.
Il gate non è retroattivo. Una campagna copia dentro di sé l'HTML del template al momento della creazione, quindi le campagne create prima che questo esistesse mantengono il loro contenuto e continuano a partire. Il gate si applica quando una campagna viene creata o le viene sostituito il template, quando un flusso viene attivato, e in consegna per le email che risolvono un template.
Invia Usando un Template
Il template fornisce il corpo e deve essere published (vedi
Pubblica prima di inviare). subject è
obbligatorio sull'invio e va passato ogni volta: se lo ometti la richiesta
fallisce con 422.
cURL
curl -X POST https://api.tratto.email/v1/emails \
-H "Authorization: Bearer tratto_live_..." \
-H "Content-Type: application/json" \
-d '{
"from":"hello@tuodominio.it",
"to":"user@example.com",
"subject":"Benvenuta, {{firstName}}!",
"templateId":"tmpl_abc123",
"variables":{
"firstName":"Alice",
"code":"SECRET123"
}
}'Risultato:
Subject: Benvenuta, Alice!
HTML: <h1>Benvenuto, Alice!</h1><p>Il tuo codice: SECRET123</p>L'oggetto viene renderizzato con le stesse variables del corpo, quindi
{{firstName}} funziona in entrambi. Una variabile che non passi diventa una
stringa vuota anche nell'oggetto — vedi Passa Sempre Tutte le Variabili più
sotto.
Un template html non ha una parte testuale. Un template Markdown fissa al
salvataggio una parte testuale renderizzata, e quella viene inviata come
text/plain accanto all'HTML.
Aggiorna un Template
Aggiorna un template. Questo crea una nuova versione, lasciando intatte le versioni precedenti.
cURL
curl -X PATCH https://api.tratto.email/v1/templates/tmpl_abc123 \
-H "Authorization: Bearer tratto_live_..." \
-H "Content-Type: application/json" \
-d '{
"html":"<h1>Benvenuto di nuovo, {{firstName}}!</h1><p>Codice: {{code}}</p>"
}'Risposta: il template completo, con version incrementata.
{
"data": {
"id": "tmpl_abc123",
"name": "Email di Benvenuto",
"html": "<h1>Benvenuto di nuovo, {{firstName}}!</h1><p>Codice: {{code}}</p>",
"status": "draft",
"version": 2,
"createdAt": "2025-06-30T12:00:00Z",
"updatedAt": "2025-06-30T12:05:00Z"
}
}La versione si incrementa solo se il contenuto cambia davvero: una PATCH che
reimposta lo stesso HTML la lascia com'è. Le versioni non hanno uno status
proprio, e il bump di versione non tocca lo status del template.
Per i template Markdown, aggiorna invece il campo markdown — ogni modifica
ri-renderizza l'HTML e incrementa la versione allo stesso modo. html e
markdown sono mutuamente esclusivi in una PATCH, e ciascuno è accettato solo
da un template del formato corrispondente (422 altrimenti).
De-pubblicare un template usato da un flusso attivo
Riportare status a draft risponde 409 se un flusso attivo sta usando
quel template:
{
"error": {
"code": "CONFLICT",
"message": "This template is used by flow 'Benvenuto' (active). Unpublishing it would break the next send.",
"suggestion": "Pause the flow, or point that step at another template first."
}
}Il motivo è il gate descritto sopra: un template non pubblicato viene rifiutato in consegna, quindi de-pubblicarlo mentre un flusso lo usa lo romperebbe al prossimo step. Un flusso in bozza non blocca nulla, perché non spedisce.
Cronologia delle Versioni
Elenca le versioni di un template, dalla più recente (fino a 20). Ogni voce contiene solo il numero di versione e il momento del salvataggio:
cURL
curl https://api.tratto.email/v1/templates/tmpl_abc123/versions \
-H "Authorization: Bearer tratto_live_..."Risposta:
{
"data": [
{ "version": 2, "savedAt": "2025-06-30T12:05:00Z" },
{ "version": 1, "savedAt": "2025-06-30T12:00:00Z" }
]
}Ottieni una Versione
Per leggere il contenuto di una versione passata — l'unico modo di recuperarlo — richiedila per numero:
cURL
curl https://api.tratto.email/v1/templates/tmpl_abc123/versions/1 \
-H "Authorization: Bearer tratto_live_..."Risposta:
{
"data": {
"version": 1,
"html": "<h1>Benvenuto, {{firstName}}!</h1><p>Il tuo codice: {{code}}</p>",
"savedAt": "2025-06-30T12:00:00Z"
}
}Su un template Markdown la risposta porta anche source: il markdown che ha
prodotto l'HTML di quella versione.
Invio di Test
Invia un'email di test usando il template per verificare che appaia corretta.
cURL
curl -X POST https://api.tratto.email/v1/templates/tmpl_abc123/test-send \
-H "Authorization: Bearer tratto_live_..." \
-H "Content-Type: application/json" \
-d '{
"to":"your-email@example.com",
"variables":{
"firstName":"Alice",
"code":"TEST123"
}
}'Un'email di test viene inviata immediatamente al tuo indirizzo in modo che tu possa esaminarla nella tua inbox.
Se Tratto non riesce a mettere in coda l'email di test, l'API restituisce
503 SERVICE_UNAVAILABLE con l'header Retry-After: non è partito niente e non
è stata creata alcuna email, quindi puoi riprovare. Vedi
Codici di Errore.
Il suo oggetto è [Test] seguito dal nome del template. Un invio di test non
ha un contatto, quindi le variabili del destinatario che non passi prendono
valori di anteprima: email è l'indirizzo di test, firstName è Preview,
lastName è Recipient e unsubscribe_url è un link di anteprima che non
disiscrive nessuno. Ogni altra variabile che ometti diventa vuota, come in un
invio reale.
Gratis, con un tetto giornaliero
I test-send sono gratuiti: non contano sulla
quota mensile. Ogni chiamata invia a un solo
destinatario. Con l'API 0.24.0 o successiva, un workspace può fare 20
test-send al giorno su Free, 100 su Starter e Growth e 200 su Scale, fra template e campagne insieme, e il conteggio si azzera
a mezzanotte UTC. Oltre il tetto l'API risponde 429 QUOTA_EXCEEDED e non
parte niente: non riprovare prima dell'azzeramento. Una chiamata rifiutata con
404 o 422 non consuma il tetto; una chiamata accettata sì, anche se poi
risponde 503, perché il tetto si conta prima della consegna alla coda.
{
"error": {
"code": "QUOTA_EXCEEDED",
"message": "Test send daily limit of 20 per workspace reached.",
"suggestion": "The limit resets at midnight UTC. Test sends are free and do not count against your monthly quota. Starter raises the test-send limit to 100 a day. The account owner can upgrade at https://app.tratto.email/settings/billing.",
"docs": "https://docs.tratto.email/en/docs/error-codes"
}
}Elenca i Template
Elenca i template del workspace, dal più recente, una pagina alla volta.
Richiede templates:read.
cURL
curl "https://api.tratto.email/v1/templates?status=published&limit=50" \
-H "Authorization: Bearer tratto_live_..."Parametri di query:
| Parametro | Default | A cosa serve |
|---|---|---|
limit | 50 | Risultati per pagina, da 1 a 100 |
after | nessuno | Il nextCursor della pagina precedente |
status | nessuno | draft o published. Qualsiasi altro valore risponde 422 |
include | nessuno | html aggiunge a ogni riga l'html del template. È l'unico valore accettato |
Risposta:
{
"data": [
{
"id": "tmpl_abc123",
"name": "Benvenuto",
"status": "published",
"format": "html",
"version": 2,
"createdAt": "2025-06-30T12:00:00Z",
"updatedAt": "2025-07-02T09:30:00Z"
}
],
"pagination": {
"hasMore": true,
"nextCursor": "tmpl_abc123"
}
}Le righe non contengono html se non lo chiedi con include=html: è il campo
più pesante di un template e a quasi tutti gli elenchi non serve. Per tutto il
resto di un singolo template usa Ottieni un Template.
L'elenco si ferma a una pagina. Senza after ricevi i 50 template più
recenti, e l'unico segnale che ce ne sono altri è pagination.hasMore. Per
leggerli tutti passa nextCursor come after finché hasMore è false:
# Prima pagina
curl "https://api.tratto.email/v1/templates?limit=100" \
-H "Authorization: Bearer tratto_live_..."
# Pagina successiva: after = il nextCursor appena ricevuto
curl "https://api.tratto.email/v1/templates?limit=100&after=tmpl_abc123" \
-H "Authorization: Bearer tratto_live_..."Sull'ultima pagina hasMore è false e nextCursor è null. Un cursore che
non corrisponde a un template esistente viene ignorato e l'elenco riparte dalla
prima pagina. Tieni lo stesso status su tutte le pagine di una stessa lettura.
Ottieni un Template
Recupera un template specifico.
cURL
curl https://api.tratto.email/v1/templates/tmpl_abc123 \
-H "Authorization: Bearer tratto_live_..."Elimina un Template
Elimina permanentemente un template (non può essere annullato).
cURL
curl -X DELETE https://api.tratto.email/v1/templates/tmpl_abc123 \
-H "Authorization: Bearer tratto_live_..."L'eliminazione di un template non può essere annullata: se ne va anche tutta la cronologia delle versioni, con l'HTML e il markdown di ogni revisione passata.
Un template in uso non si elimina. Se un flusso lo referenzia, o se una
campagna non ancora conclusa (scheduled, sending, paused) lo usa, la
richiesta risponde 409 e dice chi lo sta usando:
{
"error": {
"code": "CONFLICT",
"message": "This template is used by flow 'Benvenuto' (active).",
"suggestion": "Remove it from those first, or leave the template in place."
}
}Una campagna già completed non blocca l'eliminazione: non spedirà più.
Prima del 29 settembre 2026 l'eliminazione passava comunque, e il flusso falliva
al primo invio successivo: l'email veniva segnata failed e l'iscrizione
avanzava lo stesso, quindi il destinatario non riceveva nulla e in dashboard non
compariva alcun errore.
Sintassi Variabile del Template
Usa le doppie graffe {{variableName}} per i placeholder — gli spazi attorno
sono ammessi, quindi funziona anche {{ firstName }}. Le variabili fanno
distinzione tra maiuscole e minuscole. Non ci sono condizioni né cicli: è
sostituzione, non un linguaggio di template.
Template:
HTML: <p>Ciao {{firstName}}, la tua email è {{email}}</p>Invio:
{
"variables": {
"firstName": "Alice",
"email": "alice@example.com"
}
}Renderizzato:
HTML: <p>Ciao Alice, la tua email è alice@example.com</p>La sostituzione si applica all'oggetto e ai corpi HTML e testo.
Best Practice
1. Usa Nomi Variabili Semantici
✅ {{firstName}}, {{orderID}}, {{confirmationCode}}
❌ {{x}}, {{var1}}, {{v}}
2. Passa Sempre Tutte le Variabili
Una variabile mancante non fa fallire l'invio: il placeholder viene sostituito con una stringa vuota. Questo template
<p>Ciao {{firstName}}, benvenuto a {{companyName}}!</p>inviato senza firstName né companyName arriva come Ciao , benvenuto a !
— la punteggiatura resta orfana, ma il destinatario non vede mai il nome della
tua variabile.
Vale per l'oggetto e per il corpo, in HTML e in Markdown, sia sugli invii
transazionali che sulle campagne. Anche null sostituisce vuoto: non
comparirà mai la stringa null o undefined in un'email.
Non è un invito a passare meno variabili — al contrario. Una frase con un
buco resta una frase sbagliata, e ora niente te lo segnala: né all'invio,
né prima. Con il placeholder visibile un refuso come {{firstname}} al posto
di {{firstName}} almeno si notava nell'anteprima; con la sostituzione vuota
sparisce senza lasciare traccia.
Il controllo automatico esiste solo per le campagne, dove Tratto conosce
l'insieme delle variabili disponibili e può quindi segnalare in bozza quelle
che non ne fanno parte. L'insieme è elencato in
Variabili di una Campagna. Per un
template non è possibile: le variabili arrivano da chi chiama
POST /v1/emails, quindi non esiste un insieme contro cui verificarle e ogni
controllo sarebbe un'ipotesi.
Su un template, quindi, l'unica difesa è passare a ogni invio tutti i placeholder che il template usa.
3. Usa Template per Invii Bulk
Non comporre HTML per ogni email. Usa template e variabili per consistenza e riutilizzabilità.
4. Fai un Test Prima di Usarlo
Fai sempre un test-send del template prima di inviarlo a qualcuno, per
intercettare problemi di rendering. Il test-send è l'unico invio che un
template draft può fare, quindi è anche l'unica revisione possibile prima di
pubblicarlo.
Prossimi Passi
- Inviare con un template? Vedi Invia Email
- Scrivere template in markdown? Vedi Template Markdown
- Usare i template nelle campagne? Vai a Campagne
- Usare i template nei flussi? Vedi Flussi
Modifica questa pagina su GitHub
Ultimo aggiornamento