Working with Templates
Learn how to use templates when sending emails via the FormaMail API.
Overview
Templates in FormaMail are pre-designed email and attachment formats created in the dashboard. When sending emails via API, you reference these templates by their ID and provide variables for personalization.
Template Management: Templates can be created, updated, and deleted via both the Dashboard UI and JWT-authenticated API endpoints. The Dashboard provides a visual designer for easier template creation, while the API allows programmatic management for automation and integration purposes.
How Templates Work
1. Create Templates
Templates can be created in two ways:
Option A: Dashboard (Recommended for Design)
- Navigate to Templates in the dashboard
- Click Create Template
- Use the visual drag-and-drop designer
- Define variables for dynamic content
- Save and publish your template
See the Templates User Guide for detailed instructions.
Option B: API (For Automation)
- Use JWT-authenticated API endpoints
- Programmatically create and manage templates
- Ideal for CI/CD pipelines and automated workflows
- Requires template schema knowledge
See the API Reference - Templates for API documentation.
2. Use Templates for Sending Emails
Once templates are created, reference them in API calls:
{
templateId: 'tmpl_welcome', // Required - references dashboard template
to: [
{ email: 'user@example.com', name: 'John Doe' }
],
variables: { // Fills in template placeholders
firstName: 'John',
companyName: 'Acme Corp'
}
}Template Types
FormaMail supports two types of templates:
Email Templates
Used for sending HTML emails with personalized content:
- Text, headings, paragraphs
- Buttons and links
- Images and logos
- Tables for data display
- Conditional blocks
- Loops for repeating content
Usage:
curl https://api.formamail.com/api/emails/send \
-H "Authorization: Bearer fm_sk_abc123..." \
-H "Content-Type: application/json" \
-X POST \
-d '{
"templateId": "tmpl_welcome",
"to": [{ "email": "user@example.com", "name": "John Doe" }],
"variables": { "firstName": "John" }
}'Attachment Templates
Used for generating PDF and Excel files:
- All email components plus:
- Native charts (bar, line, pie, area, scatter) with Excel interactivity
- Advanced table formatting with calculated columns
- Page breaks and headers/footers
Charts in Email Templates: Charts are also available in email templates! In emails, charts are rendered as high-resolution static images via QuickCharts API. In PDF/Excel attachments, charts are rendered natively with full interactivity in Excel.
Usage:
Attachment templates are generated automatically when sending emails if the email template includes attachment references:
{
templateId: 'tmpl_invoice_email', // Email template
to: [{ email: 'customer@example.com' }],
variables: {
invoiceNumber: '12345',
amount: 99.99
},
// Attachments are auto-generated from template configuration
}Or generate attachments directly (if template is configured for it):
{
templateId: 'tmpl_invoice_pdf', // Attachment template
to: [{ email: 'customer@example.com' }],
variables: {
invoiceNumber: '12345',
items: [
{ name: 'Product A', price: 49.99 },
{ name: 'Product B', price: 49.99 }
]
}
}Using Template Variables
Variable Syntax
Templates use Handlebars syntax for variables:
Hello {{firstName}}!
Your order #{{orderNumber}} has been confirmed.
Total: ${{orderTotal}}Providing Variable Values
Pass variable values in the variables object:
const response = await fetch('https://api.formamail.com/api/emails/send', {
method: 'POST',
headers: {
'Authorization': `Bearer ${apiKey}`,
'Content-Type': 'application/json'
},
body: JSON.stringify({
templateId: 'tmpl_order_confirmation',
to: [{ email: 'customer@example.com' }],
variables: {
firstName: 'John',
orderNumber: '12345',
orderTotal: 99.99
}
})
});Variable Types
Templates can use different variable types:
| Type | Example | Description |
|---|---|---|
| String | {{firstName}} | Text values |
| Number | {{orderTotal}} | Numeric values |
| Boolean | {{isPremium}} | True/false values |
| Array | {{#each items}}...{{/each}} | Lists of items |
| Object | {{user.name}} | Nested data |
Complex Variables Example
{
templateId: 'tmpl_invoice',
to: [{ email: 'customer@example.com' }],
variables: {
// Simple values
invoiceNumber: 'INV-12345',
issueDate: '2025-11-07',
// Object values
customer: {
name: 'John Doe',
company: 'Acme Corp',
email: 'john@acme.com'
},
// Array values
items: [
{ name: 'Product A', quantity: 2, price: 49.99 },
{ name: 'Product B', quantity: 1, price: 29.99 }
],
// Calculated values
subtotal: 129.97,
tax: 13.00,
total: 142.97
}
}Required vs Optional Variables
Required Variables
Templates can define required variables. If you don’t provide them, the API will return an error:
{
"statusCode": 400,
"code": "ERR_TMPL_004",
"message": "Missing required template variable",
"relatedInfo": {
"variable": "firstName",
"templateId": "tmpl_welcome"
}
}Solution: Provide all required variables:
{
templateId: 'tmpl_welcome',
to: [{ email: 'user@example.com' }],
variables: {
firstName: 'John', // Required
lastName: 'Doe', // Required
companyName: 'Acme' // Required
}
}Optional Variables
Optional variables can be omitted. The template handles missing values gracefully:
Hello {{firstName}}{{#if lastName}} {{lastName}}{{/if}}!Conditional Content
Templates support conditional blocks using Handlebars helpers:
Template Design (Dashboard)
{{#if isPremium}}
<p>Thanks for being a premium member! You get free shipping.</p>
{{else}}
<p>Upgrade to premium for free shipping.</p>
{{/if}}API Usage
{
templateId: 'tmpl_order_confirmation',
to: [{ email: 'user@example.com' }],
variables: {
isPremium: true // Controls conditional block
}
}Loops and Repeating Content
Templates can loop through arrays of data:
Template Design (Dashboard)
<h2>Order Items</h2>
<table>
{{#each items}}
<tr>
<td>{{this.name}}</td>
<td>{{this.quantity}}</td>
<td>${{this.price}}</td>
</tr>
{{/each}}
</table>API Usage
{
templateId: 'tmpl_invoice',
to: [{ email: 'customer@example.com' }],
variables: {
items: [
{ name: 'Product A', quantity: 2, price: 49.99 },
{ name: 'Product B', quantity: 1, price: 29.99 },
{ name: 'Product C', quantity: 3, price: 19.99 }
]
}
}Finding Template IDs
Via Dashboard
- Navigate to Templates in the dashboard
- Click on a template to view details
- Copy the Template ID from the details page
Template IDs follow the format: tmpl_xxxxxxxxxx
Naming Convention
Use descriptive template IDs for clarity:
tmpl_welcome- Welcome email for new userstmpl_invoice- Invoice generationtmpl_password_reset- Password reset emailtmpl_order_confirmation- Order confirmation
Template Errors
Template Not Found
{
"statusCode": 404,
"code": "ERR_TMPL_002",
"message": "Email template not found",
"relatedInfo": {
"templateId": "tmpl_invalid"
}
}Solution: Verify the template ID exists in your dashboard.
Template Not Published
{
"statusCode": 400,
"code": "ERR_TMPL_003",
"message": "Template is not published",
"relatedInfo": {
"templateId": "tmpl_welcome",
"status": "draft"
}
}Solution: Publish the template in the dashboard before using it via API.
Missing Required Variable
{
"statusCode": 400,
"code": "ERR_TMPL_004",
"message": "Missing required template variable",
"relatedInfo": {
"variable": "firstName",
"templateId": "tmpl_welcome"
}
}Solution: Provide all required variables in the variables object.
Best Practices
1. Use Descriptive Template Names
✅ Good:
tmpl_welcome_new_usertmpl_invoice_monthlytmpl_password_reset
❌ Bad:
tmpl_001tmpl_testtmpl_email
2. Define Clear Variable Names
✅ Good:
{
variables: {
customerFirstName: 'John',
orderNumber: '12345',
orderTotal: 99.99
}
}❌ Bad:
{
variables: {
fn: 'John',
on: '12345',
t: 99.99
}
}3. Validate Variable Data
Always validate data before sending:
function validateOrderData(order) {
if (!order.number) throw new Error('Order number required');
if (!order.customer.email) throw new Error('Customer email required');
if (order.items.length === 0) throw new Error('Order must have items');
return true;
}
// Use it
validateOrderData(orderData);
await sendEmail({
templateId: 'tmpl_order_confirmation',
to: [{ email: orderData.customer.email }],
variables: orderData
});4. Use Template Versioning
When templates are updated in the dashboard, the API automatically uses the latest published version. To ensure consistency:
- Test template changes in a non-production environment first
- Use separate templates for different environments (e.g.,
tmpl_welcome_dev,tmpl_welcome_prod) - Document template changes in your version control system
5. Handle Missing Optional Variables
Design templates to handle missing optional variables gracefully:
{{#if companyName}}
<p>From: {{companyName}}</p>
{{/if}}6. Keep Templates Simple
- Break complex emails into smaller, reusable templates
- Use consistent naming conventions
- Document required and optional variables
- Test templates with various data combinations
Testing Templates
Test with Real Data
Always test templates with realistic data:
// Production-like test data
const testVariables = {
firstName: 'John',
lastName: 'Doe',
orderNumber: '12345',
items: [
{ name: 'Product A', quantity: 2, price: 49.99 },
{ name: 'Product B', quantity: 1, price: 29.99 }
],
total: 129.97
};
// Send to test email
await sendEmail({
templateId: 'tmpl_invoice',
to: [{ email: 'test@yourdomain.com' }],
variables: testVariables
});Testing Tips
When testing templates:
- Send to email addresses you control
- Use the template preview in the dashboard
- Verify all variable substitutions work correctly
See Authentication for API key details.
Common Use Cases
Welcome Email
{
templateId: 'tmpl_welcome',
to: [{ email: user.email, name: user.name }],
variables: {
firstName: user.firstName,
dashboardUrl: 'https://app.yourdomain.com/dashboard',
supportEmail: 'support@yourdomain.com'
}
}Order Confirmation
{
templateId: 'tmpl_order_confirmation',
to: [{ email: customer.email, name: customer.name }],
variables: {
orderNumber: order.number,
orderDate: order.date,
items: order.items,
subtotal: order.subtotal,
tax: order.tax,
shipping: order.shipping,
total: order.total,
trackingUrl: order.trackingUrl
}
}Password Reset
{
templateId: 'tmpl_password_reset',
to: [{ email: user.email }],
variables: {
resetLink: `https://app.yourdomain.com/reset-password?token=${resetToken}`,
expiresIn: '1 hour'
}
}Invoice with PDF Attachment
{
templateId: 'tmpl_invoice_email',
to: [{ email: customer.email }],
variables: {
invoiceNumber: invoice.number,
customer: {
name: customer.name,
company: customer.company,
email: customer.email
},
items: invoice.items,
total: invoice.total
}
// PDF attachment is auto-generated from template configuration
}Next Steps
- Create Templates: Learn how to design templates in the Templates User Guide
- Send Emails: See complete API documentation in Sending Emails
- Handle Errors: Learn about error handling in Error Handling
- Bulk Personalization: Send personalized emails at scale with Bulk Emails
Related: Sending Emails | Authentication | Templates User Guide