Email Templates

Create reusable email templates with dynamic content and consistent styling.

Overview

Email templates let you create reusable layouts with dynamic content. Instead of building HTML for every email, define templates once and inject variables at send time.

Template Basics

Creating a Template

const template = await client.templates.create({
  name: 'Welcome Email',
  subject: 'Welcome to {{company_name}}!',
  html: `
    <h1>Welcome, {{user_name}}!</h1>
    <p>Thanks for joining {{company_name}}.</p>
    <a href="{{action_url}}">Get Started</a>
  `,
});

Sending with a Template

await client.emails.send({
  from: 'hello@yourapp.com',
  to: 'user@example.com',
  templateId: template.id,
  variables: {
    company_name: 'Acme Inc',
    user_name: 'John',
    action_url: 'https://app.acme.com/onboarding',
  },
});

Variable Syntax

Basic Variables

Use double curly braces for variable substitution:

<p>Hello, {{first_name}}!</p>

Nested Variables

Access nested object properties with dot notation:

<p>Order #{{order.id}} for {{order.customer.name}}</p>

Variables:

{
  "order": {
    "id": "12345",
    "customer": {
      "name": "John Doe"
    }
  }
}

Default Values

Provide fallback values for missing variables:

<p>Hello, {{first_name|default:"there"}}!</p>

Conditional Content

If Statements

Show content conditionally:

{{#if has_subscription}}
  <p>Thanks for being a subscriber!</p>
{{else}}
  <p>Consider upgrading to our premium plan.</p>
{{/if}}

Unless Statements

Show content when condition is false:

{{#unless is_verified}}
  <p>Please verify your email address.</p>
{{/unless}}

Loops

Each Loops

Iterate over arrays:

<h2>Your Order</h2>
<ul>
{{#each items}}
  <li>{{this.name}} - ${{this.price}}</li>
{{/each}}
</ul>

Variables:

{
  "items": [
    { "name": "Widget", "price": "9.99" },
    { "name": "Gadget", "price": "19.99" }
  ]
}

Template Best Practices

Keep Templates Simple

  • Avoid complex logic in templates
  • Calculate values in your application code
  • Pass pre-formatted data to templates

Use Meaningful Variable Names

<!-- Good -->
<p>Your order {{order_number}} has shipped.</p>
 
<!-- Bad -->
<p>Your order {{x}} has shipped.</p>

Test with Sample Data

Always test templates with realistic data before production use.

Handle Missing Variables

Use default values to prevent blank content:

<p>Hello, {{first_name|default:"Valued Customer"}}!</p>

Template Layouts

Base Layout

Create a base layout for consistent styling:

<!-- layouts/base.html -->
<!DOCTYPE html>
<html>
<head>
  <style>
    body { font-family: Arial, sans-serif; }
    .container { max-width: 600px; margin: 0 auto; }
    .button { background: #007bff; color: white; padding: 12px 24px; }
  </style>
</head>
<body>
  <div class="container">
    {{content}}
    <footer>
      <p>© {{year}} {{company_name}}</p>
    </footer>
  </div>
</body>
</html>

Content Templates

Create content that extends the base:

<h1>Order Confirmation</h1>
<p>Thanks for your order, {{customer_name}}!</p>
<table>
  {{#each items}}
  <tr>
    <td>{{this.name}}</td>
    <td>${{this.price}}</td>
  </tr>
  {{/each}}
</table>
<p>Total: ${{total}}</p>

Managing Templates

Versioning

Templates maintain version history:

// Get template versions
const versions = await client.templates.listVersions(templateId);
 
// Revert to previous version
await client.templates.revertToVersion(templateId, versionId);

Testing Templates

Preview templates with test data:

const preview = await client.templates.preview(templateId, {
  variables: {
    first_name: 'Test User',
    order_number: '12345',
  },
});
 
console.log(preview.html);

Next Steps