Templates
Créez et gérez des templates d'e-mails réutilisables avec substitution dynamique de variables
Créez des templates d'e-mails réutilisables avec des variables dynamiques. Les templates stockent le sujet, le contenu HTML et le contenu texte de vos e-mails, afin que vous puissiez envoyer des e-mails personnalisés sans reconstruire le contenu à chaque requête.
Créer un template
POST https://api.mail.land/v1/templatescurl -X POST https://api.mail.land/v1/templates \
-H "Authorization: Bearer eyJhbGciOiJIUzI1NiIs..." \
-H "Content-Type: application/json" \
-d '{
"name": "Order Confirmation",
"subject": "Your order #{{orderNumber}} is confirmed",
"htmlContent": "<h1>Thanks, {{firstName}}!</h1><p>Order #{{orderNumber}} has been confirmed. Total: {{total}}</p>",
"textContent": "Thanks, {{firstName}}! Order #{{orderNumber}} has been confirmed. Total: {{total}}",
"categoryId": "k3v9q2m7xw4tpa"
}'{
"id": "t8x2m4q9zk7wpr",
"name": "Order Confirmation",
"subject": "Your order #{{orderNumber}} is confirmed",
"htmlContent": "<h1>Thanks, {{firstName}}!</h1>...",
"textContent": "Thanks, {{firstName}}!...",
"categoryId": "k3v9q2m7xw4tpa",
"categoryName": "Transactional",
"categoryColor": "#3B82F6",
"createdAt": "2026-02-17T10:00:00Z",
"updatedAt": null
}Règles de validation
| Champ | Contrainte |
|---|---|
name | Obligatoire, 200 caractères maximum |
subject | Obligatoire, 500 caractères maximum |
htmlContent | Obligatoire, 1 Mo maximum |
textContent | Optionnel, 1 Mo maximum |
categoryId | Optionnel, doit référencer une catégorie existante |
Syntaxe des variables
Utilisez des doubles accolades pour la substitution de variables :
<h1>Hello {{firstName}},</h1>
<p>Your order #{{orderNumber}} shipped on {{shipDate}}.</p>
<p>Track your package: <a href="{{trackingUrl}}">{{trackingNumber}}</a></p>Les variables sont remplacées au moment de l'envoi. Transmettez les valeurs via le champ variables dans votre requête d'envoi :
{
"from": { "email": "[email protected]" },
"to": [
{
"email": "[email protected]",
"variables": {
"firstName": "Jane",
"orderNumber": "ORD-12345",
"shipDate": "Feb 17, 2026",
"trackingUrl": "https://track.example.com/ABC123",
"trackingNumber": "ABC123"
}
}
],
"templateId": "t8x2m4q9zk7wpr"
}Les variables fonctionnent à la fois dans subject et dans htmlContent/textContent. Chaque {{variable}} qu'un modèle utilise doit avoir une valeur, dans les variables de la requête ou dans les variables propres au destinataire. Si l'une n'a pas de valeur, MailLand n'envoie pas le message avec l'espace réservé : POST /v1/transactional/send répond 422 TEMPLATE_VARIABLE_MISSING en nommant les variables manquantes, et POST /v1/transactional/send-batch ignore ce destinataire et le liste dans rejectedRecipients. Les campagnes et les automatisations ignorent aussi ce destinataire. Un htmlContent en ligne envoyé sans aucune variables part tel qu'il est écrit. Les espaces réservés sont exactement {{name}}, sans filtres, conditions ni boucles. Un modèle indique grammarVersion: "legacy-v1", la seule grammaire aujourd'hui ; vous pouvez omettre ce champ à la création ou à la modification d'un modèle.
Valeurs par défaut
Un modèle peut porter une valeur par défaut pour chaque champ de contact qu'il utilise, afin qu'un abonné sans valeur pour ce champ reçoive quand même l'e-mail. Définissez-les avec variableDefaults, un objet associant nom d'espace réservé et valeur, à la création et à la mise à jour. Elles sont aussi renvoyées quand vous récupérez, listez ou dupliquez un modèle.
{
"name": "Welcome",
"subject": "Hello {{firstName}}",
"htmlContent": "<p>Hi {{firstName}}</p>",
"variableDefaults": { "firstName": "cher client" }
}Règles :
- Les valeurs par défaut s'appliquent uniquement aux envois de campagnes et d'automatisations. La valeur non vide propre au destinataire l'emporte toujours sur la valeur par défaut.
- Un champ sans valeur ni valeur par défaut est toujours refusé : MailLand n'envoie jamais un
{{firstName}}littéral. - Les envois transactionnels par API et SMTP ne sont pas concernés. Les valeurs y viennent de votre requête, et une valeur manquante est refusée comme décrit plus haut.
- À la mise à jour, omettre
variableDefaultsconserve les valeurs enregistrées. Envoyez{}pour les effacer. - Les noms suivent la syntaxe des espaces réservés.
emailetsubscriberIdsont toujours fournis et n'ont pas de valeur par défaut. Une valeur tient sur une ligne, 200 caractères au plus, et un modèle contient au plus 50 valeurs par défaut.
Dans l'éditeur du tableau de bord, chaque espace réservé a un champ de valeur par défaut qui indique combien d'abonnés n'ont pas ce champ, et l'enregistrement vous avertit si un champ manquant chez des abonnés n'a pas de valeur par défaut.
Prévisualiser un template
Prévisualisez un template avec des valeurs d'exemple automatiquement remplies pour les variables détectées :
GET https://api.mail.land/v1/templates/{id}/previewcurl https://api.mail.land/v1/templates/t8x2m4q9zk7wpr/preview \
-H "Authorization: Bearer eyJhbGciOiJIUzI1NiIs..."{
"id": "t8x2m4q9zk7wpr",
"name": "Order Confirmation",
"subject": "Your order #12345 is confirmed",
"renderedHtml": "<h1>Thanks, John!</h1><p>Order #12345 has been confirmed.</p>",
"renderedText": "Thanks, John! Order #12345 has been confirmed."
}Dupliquer un template
Clonez un template existant :
POST https://api.mail.land/v1/templates/{id}/duplicatecurl -X POST https://api.mail.land/v1/templates/t8x2m4q9zk7wpr/duplicate \
-H "Authorization: Bearer eyJhbGciOiJIUzI1NiIs..."Le duplicata reçoit un nom généré automatiquement : "Order Confirmation (Copy)". Si une copie existe déjà, le nom est incrémenté : "Order Confirmation (Copy 2)", etc.
Catégories de templates
Organisez les templates en catégories avec des couleurs optionnelles.
Créer une catégorie
POST https://api.mail.land/v1/templates/categoriescurl -X POST https://api.mail.land/v1/templates/categories \
-H "Authorization: Bearer eyJhbGciOiJIUzI1NiIs..." \
-H "Content-Type: application/json" \
-d '{
"name": "Transactional",
"description": "Order confirmations, receipts, and shipping notifications",
"color": "#3B82F6"
}'| Champ | Contrainte |
|---|---|
name | Obligatoire, 1 à 100 caractères |
description | Optionnel, 500 caractères maximum |
color | Optionnel, format hexadécimal (#3B82F6 ou #38F) |
Lister les catégories
GET https://api.mail.land/v1/templates/categoriescurl https://api.mail.land/v1/templates/categories \
-H "Authorization: Bearer eyJhbGciOiJIUzI1NiIs..."{
"categories": [
{
"id": "k3v9q2m7xw4tpa",
"name": "Transactional",
"description": "Order confirmations, receipts",
"color": "#3B82F6",
"templateCount": 12,
"createdAt": "2026-01-15T10:00:00Z"
}
],
"totalCount": 3
}Lister les templates
GET https://api.mail.land/v1/templates?limit=50curl "https://api.mail.land/v1/templates?limit=50" \
-H "Authorization: Bearer eyJhbGciOiJIUzI1NiIs..."Filtrer par catégorie :
GET https://api.mail.land/v1/templates?categoryId=k3v9q2m7xw4tpacurl "https://api.mail.land/v1/templates?categoryId=k3v9q2m7xw4tpa" \
-H "Authorization: Bearer eyJhbGciOiJIUzI1NiIs..."{
"items": [
{
"id": "t8x2m4q9zk7wpr",
"name": "Order Confirmation",
"subject": "Your order #{{orderNumber}} is confirmed",
"htmlContent": "...",
"categoryName": "Transactional",
"categoryColor": "#3B82F6",
"createdAt": "2026-02-17T10:00:00Z"
}
],
"nextCursor": "eyJ2IjoxLCJzIjoiY3JlYXRlZGF0OmRlc2MiLCJrIjoi...",
"hasMore": true
}Mettre à jour un template
PUT https://api.mail.land/v1/templates/{id}Tous les champs sont obligatoires dans la requête de mise à jour (il s'agit d'un remplacement complet, pas d'une mise à jour partielle) :
curl -X PUT https://api.mail.land/v1/templates/t8x2m4q9zk7wpr \
-H "Authorization: Bearer eyJhbGciOiJIUzI1NiIs..." \
-H "Content-Type: application/json" \
-d '{
"name": "Order Confirmation v2",
"subject": "Order #{{orderNumber}} confirmed - {{companyName}}",
"htmlContent": "<h1>Thanks, {{firstName}}!</h1><p>Updated template content.</p>",
"textContent": "Thanks, {{firstName}}! Updated template content.",
"categoryId": "k3v9q2m7xw4tpa"
}'Supprimer un template
DELETE https://api.mail.land/v1/templates/{id}curl -X DELETE https://api.mail.land/v1/templates/t8x2m4q9zk7wpr \
-H "Authorization: Bearer eyJhbGciOiJIUzI1NiIs..."Renvoie 204 No Content en cas de succès. Un modèle supprimé ne peut plus être récupéré, listé ni utilisé pour l'envoi : une demande d'envoi qui le référence, immédiate ou planifiée, est rejetée avec 400 TEMPLATE_NOT_FOUND, et une planification dont le modèle est supprimé avant son échéance est rejetée de la même façon au moment de l'envoi.
Utiliser les templates lors de l'envoi
Référencez un template par son identifiant dans votre requête d'envoi. Le sujet et le contenu du template sont utilisés, avec les variables substituées :
{
"from": { "email": "[email protected]" },
"to": [
{
"email": "[email protected]",
"variables": {
"firstName": "Jane",
"orderNumber": "ORD-12345"
}
}
],
"templateId": "t8x2m4q9zk7wpr",
"variables": {
"companyName": "Acme Inc"
}
}Lorsque templateId est defini, le sujet rendu du template est toujours utilise ; un subject dans la requete d'envoi est ignore.
Limites du forfait
Le nombre de templates que vous pouvez créer dépend de votre forfait. Si vous atteignez la limite, la création d'un nouveau template renvoie 403 PLAN_LIMIT_REACHED.
Étapes suivantes
- REST API : envoyer des e-mails avec des templates
- Envoi par lots : utiliser des templates avec les envois par lots
- E-mails programmés : utiliser des templates via
/v1/transactional/sendavecscheduledAt(le point de terminaison de planification n'a pas de champtemplateId)