MailViewr - Free HTML Email Preview Tool

Free Welcome Email Template — New Subscriber Onboarding

New subscribers · onboarding · welcome series

Includes:HTML fileHandlebars variablessample-data.jsonVariables reference600px · Inline CSS · No dependencies

This template is compatible with Mailchimp automations, Klaviyo Flows, SendGrid Dynamic Templates, Brevo transactional emails, HubSpot workflows, Postmark, and any backend using Handlebars.js, Jinja2, or Liquid templating.

Template Preview

Previewed with sample-data.json. Replace {{variables}} with your ESP tags before sending.

How to use it

1

Download or copy the HTML

Self-contained file. No external dependencies.

2

Swap variables for your ESP tags

See the reference table below for Mailchimp, SendGrid, Klaviyo.

3

Or plug into a template engine

Handlebars.js · Jinja2 · Liquid. Use sample-data.json to test.

4

Preview before sending

Paste rendered HTML back into MailViewr to verify.


Compatible with

MailchimpSendGridKlaviyoBrevoHubSpotHandlebars.jsJinja2Liquid

Test with real data⬇ sample-data.json

Variables reference

9 variables · ESP merge tag equivalents · expectations[] loop

{{first_name}} · {{company_name}} · {{blog_url}} · {{resources_url}} · {{contact_url}} · {{cta_url}} · {{preferences_url}} · {{unsubscribe_url}} · {{year}} · expectations[]
VariableDescriptionMailchimpSendGridKlaviyoBrevo
{{first_name}}Subscriber's first name*|FNAME|*{{first_name}}{{ first_name }}{{ contact.FIRSTNAME }}
{{company_name}}Your company / brand name*|LIST:COMPANY|*{{company_name}}{{ company_name }}{{ params.company_name }}
{{blog_url}}Link to your blog*|ARCHIVE|*{{blog_url}}{{ blog_url }}{{ params.blog_url }}
{{resources_url}}Link to your resources page*|LIST:URL|*{{resources_url}}{{ resources_url }}{{ params.resources_url }}
{{contact_url}}Link to your contact / support page*|LIST:URL|*{{contact_url}}{{ contact_url }}{{ params.contact_url }}
{{cta_url}}Get started CTA button link*|LIST:URL|*{{cta_url}}{{ cta_url }}{{ params.cta_url }}
{{preferences_url}}Email preference centre link*|UPDATE_PROFILE|*{{preferences_url}}{{ preferences_url }}{{ params.preferences_url }}
{{unsubscribe_url}}One-click unsubscribe link*|UNSUB|*{{{unsubscribe}}}{{ unsubscribe_url }}{{ unsubscribeUrl }}
{{year}}Current year for copyright*|CURRENT_YEAR|*{{year}}{{ "now" | date: "%Y" }}{{ params.year }}

expectations[] loop — What to Expect list

The “What to Expect” bullet list uses a {{#each expectations}} loop. Each item requires one field: this.text (the bullet text). Add, remove, or reword bullets by adjusting the expectations array in your template data.

How to use this template

Step-by-step integration guide for Mailchimp, SendGrid, Klaviyo, Brevo, HubSpot, Handlebars.js, Jinja2, and Liquid.

Variable mapping

Template variableMailchimp tag
{{first_name}}*|FNAME|*
{{unsubscribe_url}}*|UNSUB|*
{{company_name}}*|MC:COMPANY|*
{{year}}Hardcode current year (e.g. 2025)
{{discount_percent}}, {{offer_price}}, {{expiry_hours}}, {{cta_url}}, {{terms_url}}Hardcode per campaign or use Content Blocks
{{#each features}}...{{/each}}Not supported — hardcode items or use Content Blocks

Steps

  1. Download the HTML template.
  2. Replace variables using the mapping table above.
  3. In Mailchimp: Campaigns → Create Email → Code Your Own.
  4. Paste the modified HTML into the code editor.
  5. Click Send Test to verify rendering before launching.

⚠ Gotcha

Mailchimp strips box-shadow and some advanced CSS properties. Always send a test email before launching your campaign.

Preview your Mailchimp template before sending

Variable mapping

Template variableSendGrid tag
{{first_name}}{{first_name}}
{{discount_percent}}{{discount_percent}}
{{offer_price}}{{offer_price}}
{{expiry_hours}}{{expiry_hours}}
{{cta_url}}{{cta_url}}
{{terms_url}}{{terms_url}}
{{unsubscribe_url}}{{unsubscribe_url}}
{{company_name}}{{company_name}}
{{year}}{{year}}
{{#each features}}...{{/each}}{{#each features}}...{{/each}} (native)

Steps

  1. Download the HTML template — variables are already Handlebars syntax, no changes needed.
  2. In SendGrid: Email API → Dynamic Templates → Create a Dynamic Template.
  3. Add a new version and paste the HTML into the code editor.
  4. In the Test Data panel, paste your JSON data object.
  5. Use the template ID in API calls with the dynamic_template_data field.

⚠ Gotcha

Handlebars support is only available in Dynamic Transactional Templates — not Marketing Campaigns. Make sure you're using the correct template type.

Variable mapping

Template variableKlaviyo tag
{{first_name}}{{ first_name }}
{{discount_percent}}{{ discount_percent }}
{{offer_price}}{{ offer_price }}
{{expiry_hours}}{{ expiry_hours }}
{{cta_url}}{{ cta_url }}
{{terms_url}}{{ terms_url }}
{{unsubscribe_url}}{{ unsubscribe_url }}
{{company_name}}{{ company_name }}
{{year}}{{ year }}
{{#each features}}{% for feature in features %}
{{this.name}}, {{this.original_price}}{{ feature.name }}, {{ feature.original_price }}
{{/each}}{% endfor %}

Steps

  1. Download the HTML template.
  2. Replace all variables and loops using the mapping table above.
  3. In Klaviyo: Campaigns → Create Campaign → Email → drag in an HTML block.
  4. Paste the modified HTML.
  5. Use Preview with a profile to verify variable substitution.

⚠ Gotcha

Klaviyo uses Jinja2-style syntax, not Handlebars. The {{#each}} loop must be rewritten as {% for feature in features %} … {% endfor %}.

Variable mapping

Template variableBrevo tag
{{first_name}}{{ contact.FIRSTNAME }}
{{discount_percent}}{{ params.discount_percent }}
{{offer_price}}{{ params.offer_price }}
{{expiry_hours}}{{ params.expiry_hours }}
{{cta_url}}{{ params.cta_url }}
{{terms_url}}{{ params.terms_url }}
{{unsubscribe_url}}{{ params.unsubscribe_url }}
{{company_name}}{{ params.company_name }}
{{year}}{{ params.year }}
{{#each features}}{% for feature in params.features %}
{{this.name}}, {{this.original_price}}{{ feature.name }}, {{ feature.original_price }}
{{/each}}{% endfor %}

Steps

  1. Download the HTML template.
  2. Replace variables using the mapping table above.
  3. In Brevo: Email Campaigns → Template Library → New Template → paste HTML.
  4. Pass transactional params in your API call under the params object.
  5. Preview and test before sending.

⚠ Gotcha

Brevo distinguishes between contact attributes (contact. prefix) and transactional params (params. prefix). Mixing them up is the most common integration error.

Variable mapping

Template variableHubSpot tag
{{first_name}}{{ contact.firstname }}
{{unsubscribe_url}}{{ unsubscribe_link }}
{{company_name}}{{ account.company_name }}
{{discount_percent}}{{ discount_percent }}
{{offer_price}}{{ offer_price }}
{{expiry_hours}}{{ expiry_hours }}
{{cta_url}}{{ cta_url }}
{{terms_url}}{{ terms_url }}
{{year}}{{ year }}
{{#each features}}{% for feature in features %}
{{this.name}}, {{this.original_price}}{{ feature.name }}, {{ feature.original_price }}
{{/each}}{% endfor %}

Steps

  1. Download the HTML template.
  2. Swap variables to HubL syntax using the mapping table above.
  3. In HubSpot: Marketing → Email → Create Email → Custom Code module.
  4. Paste the modified HTML.
  5. Use Preview & Test to verify with a contact record.

⚠ Gotcha

HubSpot uses HubL (a Jinja2 variant). Custom HTML emails require a paid Marketing Hub account.

Variable mapping

Template variableHandlebars.js tag
{{first_name}}{{first_name}} — no change
{{discount_percent}}, {{offer_price}}, etc.All scalar variables — no change
{{#each features}}...{{/each}}{{#each features}}...{{/each}} — no change

Steps

  1. Install: npm install handlebars
  2. Load the template HTML as a string (e.g. via fs.readFileSync).
  3. Compile and render using the snippet below.
  4. Pass your data object to the compiled template function.
const Handlebars = require('handlebars');
const fs = require('fs');

const templateStr = fs.readFileSync('template.html', 'utf-8');
const template = Handlebars.compile(templateStr);

const html = template({
  first_name: 'Alex',
  discount_percent: '20',
  offer_price: '$79',
  expiry_hours: '48',
  cta_url: 'https://example.com/deal',
  terms_url: 'https://example.com/terms',
  unsubscribe_url: 'https://example.com/unsubscribe',
  company_name: 'Acme Inc.',
  year: new Date().getFullYear(),
  features: [
    { name: 'Feature A', original_price: '$99' },
    { name: 'Feature B', original_price: '$49' },
  ],
});

Variable mapping

Template variableJinja2 tag
{{first_name}}{{ first_name }}
{{discount_percent}}{{ discount_percent }}
{{offer_price}}{{ offer_price }}
{{expiry_hours}}{{ expiry_hours }}
{{cta_url}}{{ cta_url }}
{{terms_url}}{{ terms_url }}
{{unsubscribe_url}}{{ unsubscribe_url }}
{{company_name}}{{ company_name }}
{{year}}{{ year }}
{{#each features}}{% for feature in features %}
{{this.name}}, {{this.original_price}}{{ feature.name }}, {{ feature.original_price }}
{{/each}}{% endfor %}

Steps

  1. Install: pip install jinja2
  2. Load and render the template using the snippet below.
from jinja2 import Environment
from datetime import datetime

env = Environment()
with open('template.html') as f:
    template = env.from_string(f.read())

html = template.render(
    first_name='Alex',
    discount_percent='20',
    offer_price='$79',
    expiry_hours='48',
    cta_url='https://example.com/deal',
    terms_url='https://example.com/terms',
    unsubscribe_url='https://example.com/unsubscribe',
    company_name='Acme Inc.',
    year=datetime.now().year,
    features=[
        {'name': 'Feature A', 'original_price': '$99'},
        {'name': 'Feature B', 'original_price': '$49'},
    ],
)

⚠ Gotcha

Jinja2 uses {% %} for logic blocks and {{ }} for variables. The Handlebars {{#each}} loop must be rewritten as {% for feature in features %} … {% endfor %}.

Variable mapping

Template variableLiquid tag
{{first_name}}{{ first_name }}
{{discount_percent}}{{ discount_percent }}
{{offer_price}}{{ offer_price }}
{{expiry_hours}}{{ expiry_hours }}
{{cta_url}}{{ cta_url }}
{{terms_url}}{{ terms_url }}
{{unsubscribe_url}}{{ unsubscribe_url }}
{{company_name}}{{ company_name }}
{{year}}{{ year }}
{{#each features}}{% for feature in features %}
{{this.name}}, {{this.original_price}}{{ feature.name }}, {{ feature.original_price }}
{{/each}}{% endfor %}

Steps

  1. Download the HTML template.
  2. Replace Handlebars syntax with Liquid using the mapping table above.
  3. In Shopify Emails: use {{ customer.first_name }} for customer-scoped data.
  4. In Klaviyo or generic Liquid contexts: use flat {{ first_name }} syntax.
  5. Preview with a test customer or profile to verify rendering.

⚠ Gotcha

Shopify Liquid uses customer-scoped variables ({{ customer.first_name }}), while standard Liquid uses flat variables ({{ first_name }}). Know which context you're targeting.

Frequently asked questions

Yes. This welcome email template is completely free to download and use. No signup required.

Yes. Replace the {{variable}} placeholders with Mailchimp merge tags. For example, replace {{first_name}} with *|FNAME|* and {{unsubscribe_url}} with *|UNSUB|*.

Yes. Klaviyo uses Liquid syntax. Scalar variables use {{ variable }} with spaces. Replace {{unsubscribe_url}} with {{ unsubscribe_url }} and link it appropriately in your flow.

Yes. The template ships with Handlebars syntax natively, including a {{#each expectations}} loop for the onboarding list. For Jinja2 change {{variable}} to {{ variable }} and {{#each expectations}} to {% for item in expectations %}. A sample-data.json is included to test rendering.

Yes. The template is 600px max-width with fully inline CSS. It renders correctly in Gmail, Outlook, Apple Mail, and mobile clients.

Replace {{company_name}} with your brand name, update the gradient header colours in the inline style attributes, and swap the CTA link {{cta_url}} to your onboarding page.