Using Email Templates

Learn how to create and use email templates for consistent, dynamic emails.

Using Email Templates

Email templates allow you to create reusable email designs with dynamic content. This guide covers creating, managing, and sending templated emails.

Why Use Templates?

  • Consistency: Maintain brand consistency across all emails
  • Separation of concerns: Designers work on templates, developers trigger sends
  • Dynamic content: Personalize emails with variables
  • Version control: Track changes and roll back if needed
  • A/B testing: Test different templates for better engagement

Creating Templates

Via Dashboard

  1. Navigate to Email > Templates
  2. Click Create Template
  3. Choose a starting point (blank, import, or clone)
  4. Use the visual editor or code editor
  5. Add variables using {{variableName}} syntax
  6. Save and optionally publish

Via API

import { Transactional } from 'transactional-sdk';
 
const client = new Transactional({
  apiKey: process.env.TRANSACTIONAL_API_KEY,
});
 
const template = await client.templates.create({
  name: 'Welcome Email',
  alias: 'welcome-email',
  subject: 'Welcome to {{companyName}}, {{firstName}}!',
  htmlBody: `
    <html>
      <body>
        <h1>Welcome, {{firstName}}!</h1>
        <p>Thanks for joining {{companyName}}. We're excited to have you.</p>
        <a href="{{loginUrl}}">Get Started</a>
      </body>
    </html>
  `,
  textBody: `
    Welcome, {{firstName}}!
 
    Thanks for joining {{companyName}}. We're excited to have you.
 
    Get started: {{loginUrl}}
  `,
});
 
console.log('Template ID:', template.id);
console.log('Template Alias:', template.alias);

Template Variables

Basic Variables

Use double curly braces for variable substitution:

<p>Hello, {{firstName}} {{lastName}}!</p>
<p>Your order #{{orderId}} has shipped.</p>

Conditional Content

Show content based on conditions:

{{#if isPremium}}
  <p>Thanks for being a Premium member!</p>
{{else}}
  <p>Upgrade to Premium for exclusive benefits.</p>
{{/if}}

Loops

Iterate over arrays:

<h2>Your Order Items</h2>
<ul>
{{#each items}}
  <li>{{this.name}} - ${{this.price}}</li>
{{/each}}
</ul>
<p>Total: ${{total}}</p>

Built-in Variables

These are automatically available:

VariableDescription
{{unsubscribeUrl}}One-click unsubscribe link
{{preferencesUrl}}Email preferences link
{{viewInBrowserUrl}}View email in browser
{{currentYear}}Current year (e.g., 2024)

Sending Templated Emails

Using Template Alias

await client.emails.send({
  from: 'hello@yourapp.com',
  to: 'user@example.com',
  templateAlias: 'welcome-email',
  templateModel: {
    firstName: 'John',
    companyName: 'Acme Inc',
    loginUrl: 'https://app.acme.com/login',
  },
});

Using Template ID

await client.emails.send({
  from: 'hello@yourapp.com',
  to: 'user@example.com',
  templateId: 12345,
  templateModel: {
    firstName: 'John',
    companyName: 'Acme Inc',
    loginUrl: 'https://app.acme.com/login',
  },
});

Batch Sending with Templates

const users = [
  { email: 'john@example.com', name: 'John', plan: 'Pro' },
  { email: 'jane@example.com', name: 'Jane', plan: 'Basic' },
  { email: 'bob@example.com', name: 'Bob', plan: 'Enterprise' },
];
 
const messages = users.map((user) => ({
  from: 'hello@yourapp.com',
  to: user.email,
  templateAlias: 'monthly-newsletter',
  templateModel: {
    name: user.name,
    plan: user.plan,
    upgradeUrl: `https://app.yourapp.com/upgrade?user=${user.email}`,
  },
}));
 
const results = await client.emails.sendBatch(messages);

Template Layouts

Use layouts for consistent headers and footers across templates:

Create a Layout

const layout = await client.layouts.create({
  name: 'Main Layout',
  alias: 'main-layout',
  htmlBody: `
    <!DOCTYPE html>
    <html>
    <head>
      <style>
        body { font-family: sans-serif; }
        .header { background: #3B82F6; color: white; padding: 20px; }
        .footer { background: #F3F4F6; padding: 20px; font-size: 12px; }
      </style>
    </head>
    <body>
      <div class="header">
        <img src="{{logoUrl}}" alt="Logo" />
      </div>
 
      <div class="content">
        {{{body}}}
      </div>
 
      <div class="footer">
        <p>&copy; {{currentYear}} Your Company. All rights reserved.</p>
        <a href="{{unsubscribeUrl}}">Unsubscribe</a>
      </div>
    </body>
    </html>
  `,
});

Use Layout in Template

const template = await client.templates.create({
  name: 'Order Confirmation',
  alias: 'order-confirmation',
  layoutAlias: 'main-layout',
  subject: 'Order #{{orderId}} Confirmed',
  htmlBody: `
    <h1>Thanks for your order!</h1>
    <p>Hi {{name}},</p>
    <p>Your order #{{orderId}} has been confirmed.</p>
 
    <h2>Order Details</h2>
    <table>
      {{#each items}}
        <tr>
          <td>{{this.name}}</td>
          <td>${{this.price}}</td>
        </tr>
      {{/each}}
    </table>
    <p><strong>Total: ${{total}}</strong></p>
  `,
});

Common Template Examples

Welcome Email

<h1>Welcome to {{companyName}}!</h1>
 
<p>Hi {{firstName}},</p>
 
<p>Thanks for signing up. Here's what you can do next:</p>
 
<ul>
  <li><a href="{{setupUrl}}">Complete your profile</a></li>
  <li><a href="{{docsUrl}}">Read the documentation</a></li>
  <li><a href="{{supportUrl}}">Get help from support</a></li>
</ul>
 
{{#if referralCode}}
<p>Your referral code is: <strong>{{referralCode}}</strong></p>
{{/if}}
 
<a href="{{loginUrl}}" style="background: #3B82F6; color: white; padding: 12px 24px; text-decoration: none; border-radius: 6px;">
  Get Started
</a>

Password Reset

<h1>Reset Your Password</h1>
 
<p>Hi {{firstName}},</p>
 
<p>We received a request to reset your password. Click the button below to create a new password:</p>
 
<a href="{{resetUrl}}" style="background: #3B82F6; color: white; padding: 12px 24px; text-decoration: none; border-radius: 6px;">
  Reset Password
</a>
 
<p style="color: #666; font-size: 14px; margin-top: 20px;">
  This link will expire in {{expiryHours}} hours. If you didn't request this, you can safely ignore this email.
</p>
 
<p style="color: #666; font-size: 12px;">
  For security, this request was received from {{ipAddress}} using {{browser}} on {{operatingSystem}}.
</p>

Order Confirmation

<h1>Order Confirmed! 🎉</h1>
 
<p>Hi {{customerName}},</p>
 
<p>Thank you for your order! Here's a summary:</p>
 
<table style="width: 100%; border-collapse: collapse;">
  <tr style="background: #F3F4F6;">
    <th style="padding: 12px; text-align: left;">Item</th>
    <th style="padding: 12px; text-align: right;">Price</th>
  </tr>
  {{#each items}}
  <tr style="border-bottom: 1px solid #E5E7EB;">
    <td style="padding: 12px;">
      {{this.name}}
      {{#if this.quantity}}
        <span style="color: #666;"> × {{this.quantity}}</span>
      {{/if}}
    </td>
    <td style="padding: 12px; text-align: right;">${{this.price}}</td>
  </tr>
  {{/each}}
  <tr>
    <td style="padding: 12px;"><strong>Total</strong></td>
    <td style="padding: 12px; text-align: right;"><strong>${{total}}</strong></td>
  </tr>
</table>
 
<h2>Shipping Address</h2>
<p>
  {{shippingAddress.street}}<br/>
  {{shippingAddress.city}}, {{shippingAddress.state}} {{shippingAddress.zip}}<br/>
  {{shippingAddress.country}}
</p>
 
<a href="{{trackingUrl}}" style="background: #3B82F6; color: white; padding: 12px 24px; text-decoration: none; border-radius: 6px;">
  Track Order
</a>

Testing Templates

Preview with Sample Data

const preview = await client.templates.preview('welcome-email', {
  firstName: 'John',
  companyName: 'Acme Inc',
  loginUrl: 'https://app.acme.com/login',
});
 
console.log('Subject:', preview.subject);
console.log('HTML:', preview.htmlBody);
console.log('Text:', preview.textBody);

Send Test Email

await client.templates.sendTest('welcome-email', {
  to: 'test@yourdomain.com',
  templateModel: {
    firstName: 'Test',
    companyName: 'Acme Inc',
    loginUrl: 'https://app.acme.com/login',
  },
});

Template Versioning

Track changes and roll back if needed:

// List versions
const versions = await client.templates.listVersions('welcome-email');
 
// Restore a previous version
await client.templates.restoreVersion('welcome-email', versionId);

Next Steps