Template Markdown
Scrivi i template email in markdown e lascia che Tratto generi HTML responsive ed email-safe per te.
I template Tratto esistono in due formati: HTML (format: "html", l'HTML
lo fornisci tu) e Markdown (format: "emailmd", scrivi markdown e Tratto
lo renderizza in HTML responsive ed email-safe — dark mode, fix per Outlook e
parte testuale inclusi).
Con un template Markdown:
- Il markdown è la fonte di verità — vive nel campo
sourcedel template. Il campohtmlè derivato dal server al salvataggio e non può essere impostato direttamente. - Il rendering avviene al salvataggio, non all'invio. L'HTML renderizzato viene fissato sul template (e su ogni versione), quindi la consegna è byte-stabile.
- Le
{{variabili}}attraversano il render intatte e vengono sostituite all'invio, esattamente come nei template HTML — anche dentro gli URL dei link.
Preferisci cliccare che leggere? La dashboard ha un editor markdown completo con preview live — vedi Template markdown nella dashboard.
Sintassi
Tutto quello che segue è markdown standard più poche aggiunte specifiche per le email. Il markdown normale funziona come ti aspetti:
## Un titolo
Testo in **grassetto**, un [link](https://example.com), e una lista:
- Primo elemento
- Secondo elementoFrontmatter
Un blocco YAML opzionale in testa al documento imposta i metadati dell'email e poche opzioni di documento:
---
preheader: "Il tuo ordine è partito. Traccialo ora"
lang: it
dir: ltr
breaks: false
theme: auto
---Queste cinque chiavi sono l'elenco completo: Tratto passa al renderer solo queste.
| Chiave | Cosa fa |
|---|---|
preheader | Il testo di anteprima che i client email mostrano accanto all'oggetto nella lista della inbox. È incorporato in modo invisibile nel corpo dell'email. |
lang | La lingua del documento, scritta nell'attributo lang dell'HTML renderizzato. Un tag di lingua: it, en, pt-BR. |
dir | La direzione del testo — ltr (default), rtl o auto. rtl ribalta a destra l'allineamento predefinito. |
breaks | true trasforma un a-capo singolo in un'interruzione di riga; false (default) mantiene il markdown standard, dove i paragrafi si separano con una riga vuota. |
theme | light, dark oppure auto (renderizza chiaro ma si adatta ai lettori con il client email in dark mode). Solo questi tre valori: qualsiasi altro viene ignorato, con un warning. Se manca, il documento usa il tema del workspace, e light se il workspace non ne ha uno. |
Qualsiasi altra chiave viene rimossa prima del render e segnalata come warning di render. In particolare:
- I colori (
brand_color,button_color,divider_color,background_color,content_color, …) si impostano nelle impostazioni di marchio del workspace, non nel template — vedi Dare un aspetto diverso a una campagna. Il render applica il marchio del workspace come garanzia, non come impostazione predefinita che un documento può sovrascrivere. font_familyefontsnon sono supportate.fontscaricherebbe un foglio di stile remoto dentro la casella del destinatario.dark:(palette scura personalizzata) non è supportata. Per una resa scura usatheme: darkotheme: auto, che usano la palette scura coerente del renderer.
Il markdown che salvi non viene modificato: la riga rimossa resta nel
source del template esattamente come l'hai scritta, semplicemente non ha
effetto sull'HTML renderizzato. Vedere ancora brand_color: nell'editor non
significa quindi che sia stato applicato — te lo dicono i warning.
Direttive
Le direttive sono blocchi delimitati che controllano il layout dell'email:
::: header
# Acme Monthly
:::
## Novità di prodotto
Questo mese abbiamo rilasciato **tre** miglioramenti.
::: callout
Il prezzo early-bird finisce **venerdì**.
:::
::: footer
Acme Inc — Milano
[Disiscriviti]({{unsubscribe_url}})
:::::: header— una banda sopra l'area del contenuto, tipicamente un logo o il nome del brand. Centrata di default; accettaleft/right.::: callout— un riquadro evidenziato per la parte che non deve sfuggire. Parametri separati da spazio lo regolano:center/left/rightper l'allineamento,compact/spaciousper il padding — es.::: callout center compact.::: footer— testo più piccolo e attenuato in fondo, per note legali, link di disiscrizione e informazioni aziendali.::: include brand-header: il logo del workspace, in una banda di intestazione. Una riga sola, senza:::di chiusura.
Il logo del workspace
Caricare un logo non lo fa comparire in tutte le email. Un documento lo mostra solo se lo chiede, con questa riga nel punto in cui deve stare il logo (di solito la prima riga dopo il frontmatter):
::: include brand-header
# Il tuo ordine è partitoAl render la riga diventa una banda ::: header con il logo, e il nome del
workspace come testo alternativo. È una scelta voluta: un logo sta bene in una
newsletter, non per forza nel reset di una password, e per toglierlo da un
template basta cancellare la riga.
Il logo viene disegnato dentro un riquadro di 160 × 64 px: rimpicciolito per entrarci, mantenendo le proporzioni, e mai ingrandito. Un logo più piccolo del riquadro resta alla sua dimensione. Le regole di caricamento e gli avvisi sui file piccoli o pesanti sono in Branding.
Se il workspace non ha un logo, la riga non produce niente e il render
segnala il warning Unknown partial "brand-header". Il resto dell'email non
cambia.
Bottoni
Trasforma qualsiasi link in un bottone call-to-action con l'attributo
{button}:
[Conferma email](https://app.example.com/confirm?token={{token}}){button}
[Scopri di più](https://example.com){button.secondary}Variabili
Usa i placeholder {{nomeVariabile}} ovunque — titoli, prosa, URL dei link.
Sopravvivono intatti al render markdown e vengono sostituiti quando l'email
viene inviata, con le variables che passi a POST /v1/emails o a un
invio di test. Per questo l'HTML del template salvato contiene ancora i
placeholder letterali: è voluto.
Dare un aspetto diverso a una campagna
Tema, colori e logo sono un'impostazione di workspace, condivisa da
tutti i template. Un documento può solo scegliere il proprio theme e
decidere se mostrare il logo.
-
Marchio del workspace: un tema predefinito, i tre colori di marchio e il logo si impostano in Settings → Workspace nella dashboard, oppure via
PATCH /v1/workspace(l'oggettobrand) ePUT /v1/workspace/brand/logo(dettagli API in Branding). I colori finiscono qui:Campo del marchio Dove si vede nell'email primaryColorLink, e sfondo dei bottoni primari ( {button})secondaryColorBordo ed etichetta dei bottoni secondari ( {button.secondary})accentColorDivisori e linee orizzontali themeLa palette ( light,dark,auto) dei documenti che non impostano un propriotheme -
Per singolo documento:
theme: light,theme: darkotheme: autonel frontmatter prevale sul tema del workspace, e::: include brand-headermostra il logo. Non c'è altro.
Il marchio si applica quando il markdown viene renderizzato, non quando
l'email parte. Una modifica al marchio raggiunge ogni render successivo, ma
non l'HTML già fissato su template e campagne salvati prima. Un template viene
renderizzato di nuovo solo se il suo markdown cambia: salvare lo stesso
markdown non applica un logo o dei colori nuovi. Modifica il markdown (anche un
solo carattere) e salva, oppure controlla prima il risultato con
render-preview, che usa sempre il marchio attuale.
Non esiste un override di colori, font o palette per singolo template, ed è voluto: quello che il workspace ha configurato è quello che ricevono i destinatari.
Sicurezza: l'HTML raw viene escapato
I template markdown vengono renderizzati con l'input HTML disabilitato.
Qualsiasi cosa somigli a HTML raw nel markdown (<script>,
<img onerror=…>, qualunque tag) viene escapata e mostrata come testo
letterale, e i link javascript: / data: non diventano mai link. Se ti
serve HTML scritto a mano, crea un template con format: "html" — i due
formati non si possono mescolare in un unico template.
End-to-end: markdown → template → test → campagna
1. Crea il template
Invia format: "emailmd" e un campo markdown. Non inviare html — per
questo formato è derivato, e fornirlo fa fallire la validazione (422).
curl -X POST https://api.tratto.email/v1/templates \
-H "Authorization: Bearer tratto_live_..." \
-H "Content-Type: application/json" \
-d '{
"name": "Email di Benvenuto",
"format": "emailmd",
"markdown": "---\npreheader: Il tuo account è pronto\n---\n\n# Benvenuto, {{firstName}}!\n\nGrazie per esserti registrato.\n\n[Conferma email](https://app.example.com/confirm?token={{token}}){button}"
}'Risposta (201):
{
"data": {
"id": "tmpl_abc123",
"name": "Email di Benvenuto",
"status": "draft",
"format": "emailmd",
"source": "---\npreheader: Il tuo account è pronto\n---\n\n# Benvenuto, {{firstName}}!...",
"html": "<!doctype html><html>...</html>",
"renderWarnings": [],
"version": 1,
"createdAt": "2026-08-17T12:00:00Z",
"updatedAt": "2026-08-17T12:00:00Z"
}
}html è il documento renderizzato completo, pronto per l'invio. Il render
produce anche una parte in testo semplice, consegnata come alternativa
text/plain dell'email. Il sorgente markdown ha un limite di 100.000
caratteri.
2. Preview senza salvare
POST /v1/templates/render-preview renderizza il markdown in modo stateless —
è ciò che alimenta la preview live della dashboard:
curl -X POST https://api.tratto.email/v1/templates/render-preview \
-H "Authorization: Bearer tratto_live_..." \
-H "Content-Type: application/json" \
-d '{"markdown": "# Ciao {{firstName}}"}'Risposta (200): { "data": { "html": "...", "text": "...", "warnings": [] } }
Richiede lo stesso permesso templates:write del salvataggio, e ha un rate
limit più stretto di 60 richieste al minuto (il render è CPU-bound), che si
somma al limite globale di 500/minuto per IP invece di sostituirlo — vedi
Rate Limit.
3. Itera: l'aggiornamento ri-renderizza
PATCH con un nuovo markdown ri-renderizza e crea una nuova versione.
Inviare html a un template Markdown — o markdown a un template html —
fallisce con 422. Il formato è fissato alla creazione e non può mai essere
cambiato.
curl -X PATCH https://api.tratto.email/v1/templates/tmpl_abc123 \
-H "Authorization: Bearer tratto_live_..." \
-H "Content-Type: application/json" \
-d '{"markdown": "# Bentornato, {{firstName}}!"}'4. Test, pubblica, invia
Da qui in poi un template Markdown si comporta esattamente come uno HTML.
L'ordine conta: l'invio di test funziona su una bozza, ma l'invio
transazionale finale funziona solo quando il template è published
(vedi Template).
# Invio di test alla tua inbox, con valori di esempio per le variabili
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": "tu@example.com", "variables": {"firstName": "Alice", "token": "TEST"}}'
# Pubblica
curl -X PATCH https://api.tratto.email/v1/templates/tmpl_abc123 \
-H "Authorization: Bearer tratto_live_..." \
-H "Content-Type: application/json" \
-d '{"status": "published"}'
# Invia un'email transazionale con il template
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": "Benvenuto!",
"templateId": "tmpl_abc123",
"variables": {"firstName": "Alice", "token": "abc123"}
}'Anche le campagne partono da un template pubblicato: vedi la sezione seguente.
Modificare il markdown dentro una campagna
Una campagna creata da un template Markdown possiede la propria copia del markdown. Da quel momento il template è il punto di partenza della campagna, non un legame vivo:
- Alla creazione il contenuto viene copiato, non renderizzato di nuovo. La
campagna riceve il
sourcedel template e l'HTML fissato su di esso, esattamente come li hai visti nell'editor del template. - Modificare il template dopo non cambia la campagna, e modificare la campagna non tocca mai il template.
- Per cambiare il testo, modifica la campagna.
PATCH /v1/campaigns/:idcon un campomarkdown(oppure l'editor markdown nella pagina della campagna in dashboard) renderizza di nuovo l'HTML della campagna con il marchio attuale del workspace.
curl -X PATCH https://api.tratto.email/v1/campaigns/camp_xyz789 \
-H "Authorization: Bearer tratto_live_..." \
-H "Content-Type: application/json" \
-d '{"markdown": "::: include brand-header\n\n# Novità di ottobre\n\nTre cose che abbiamo rilasciato."}'Valgono le stesse regole dei template:
| Richiesta | Risultato |
|---|---|
markdown su una campagna Markdown in draft | Renderizzata di nuovo e salvata; i warning in renderWarnings della campagna |
html su una campagna Markdown, o markdown su una HTML | 422 VALIDATION_ERROR |
html e markdown insieme | 422 VALIDATION_ERROR |
Qualsiasi modifica a una campagna non più in draft | 409 CONFLICT |
templateId | Sostituisce il contenuto con una copia nuova di quel template (che deve essere pubblicato). È l'unico modo per cambiare il formato di una campagna |
Alla consegna, click tracking, pixel di apertura e footer di disiscrizione vengono applicati esattamente come per le campagne HTML.
Inviare markdown senza template
POST /v1/emails accetta anche un corpo markdown una tantum — nessun
template coinvolto. Vedi Invia Email.
Warning di render
Il render non fallisce mai su input imperfetto — i problemi degradano in modo
controllato e vengono riportati come warning. Su un template salvato finiscono
in renderWarnings; su render-preview tornano in warnings. Trattali come
una checklist, non come errori: il template è stato salvato e si invia
comunque.
Quelli che incontrerai più spesso:
- Una chiave frontmatter che non è una delle cinque sopra — è stata rimossa prima del render; il warning nomina la chiave. Le chiavi di colore e di font finiscono sempre qui.
- Un valore non valido su una chiave supportata — un
themesconosciuto, undirdiverso daltr/rtl/auto, unlangmalformato, unbreaksche non è un booleano. Il renderer ricade sul default e lo dice. - Un parametro di direttiva sconosciuto — per esempio una parola su una
riga
::: calloutche non è fra quelle documentate. Unknown partial "brand-header": il documento include il logo ma il workspace non ne ha caricato uno. Al suo posto non compare niente.
Solo due situazioni rifiutano la richiesta, entrambe con VALIDATION_ERROR
(422):
- Markdown vuoto —
"markdown must not be empty." - Campi in conflitto —
markdowninsieme ahtml, sui template o suPOST /v1/emails.
Vedi Codici di Errore per i payload.
Con gli SDK
Il supporto markdown richiede la 1.1.0 o successiva degli SDK, su npm come su PyPI, quindi un'installazione nuova ce l'ha; con un pin più vecchio usa direttamente la REST API come mostrato sopra.
Node.js (@tratto/email, 1.1.0+)
// Email markdown una tantum — senza template
const email = await client.emails.send({
from: 'hello@tuodominio.it',
to: 'user@example.com',
subject: 'Benvenuto!',
markdown: '# Benvenuto, {{firstName}}!',
variables: { firstName: 'Alice' },
});
// Crea un template Markdown
const template = await client.templates.create({
name: 'Email di Benvenuto',
markdown: '# Benvenuto, {{firstName}}!',
});
console.log(template.format); // 'emailmd'
console.log(template.renderWarnings); // []Python (tratto-email, 1.1.0+)
from tratto import SendEmailOptions, CreateTemplateOptions
# Email markdown una tantum — senza template
client.emails.send(SendEmailOptions(
from_='hello@tuodominio.it',
to='user@example.com',
subject='Benvenuto!',
markdown='# Benvenuto, {{firstName}}!',
variables={'firstName': 'Alice'},
))
# Crea un template Markdown
template = client.templates.create(CreateTemplateOptions(
name='Email di Benvenuto',
markdown='# Benvenuto, {{firstName}}!',
))PHP (tratto/email, 1.0.0+)
// Email markdown una tantum, senza template
$tratto->emails->send([
'from' => 'hello@tuodominio.it',
'to' => 'user@example.com',
'subject' => 'Benvenuto!',
'markdown' => '# Benvenuto, {{firstName}}!',
'variables' => ['firstName' => 'Alice'],
]);
// Crea un template Markdown
$template = $tratto->templates->create([
'name' => 'Email di Benvenuto',
'markdown' => '# Benvenuto, {{firstName}}!',
]);Prossimi Passi
- Preferisci la dashboard? Vedi Template markdown nella dashboard
- Basi dei template (pubblicazione, versioni, test): Template
- Invia markdown una tantum: Invia Email
- Usa il template in una campagna: Campagne
Modifica questa pagina su GitHub
Ultimo aggiornamento