Skip to main content

Email Template Extensions

Email template extensions let your app ship branded HTML for the transactional emails LaunchMyStore sends on the merchant’s behalf — order confirmations, shipment notifications, password resets, and more. The template is stored as part of the merchant’s store and is selected at send time by event name. This replaces the platform’s built-in default HTML for any event the app overrides. Merchants can also save their own templates through the admin UI, with app-provided templates winning on conflict.
Status. Six events check the DB for a template override at send time: order_confirmation, shipment_notification, order_cancellation, newsletter_welcome, abandoned_cart, and digital_delivery. The remaining events (password_reset, account_invitation) are not yet wired — your registered template is stored, but the send path still uses the built-in default HTML. See Supported events for the per-event status.

How Email Templates Work

  1. Your app sends a template manifest at install time (or any time after, via the app-scoped REST API).
  2. LaunchMyStore upserts a template record, keyed by (store, event, app).
  3. When the merchant’s store fires the corresponding event (e.g. an order is placed), the send pipeline selects the active template for that store and event using the resolution rules.
  4. The chosen htmlBody is rendered with the full Aqua (Liquid) engine (interpolation, loops, conditionals, filters) and sent through the merchant’s configured email provider — the platform’s shared sender by default, or the merchant’s own SMTP if one is set. Custom templates only apply when the merchant has configured their own SMTP, to protect the platform’s shared sender reputation.

Architecture

Two separate channels connect your app to LaunchMyStore — only one of them carries email templates.
The merchant never types HTML into a browser. Your server POSTs the template directly. The iframe is optional UI for triggering that POST (e.g. a “Re-sync templates” button).

Two ways the POST happens

At install — LaunchMyStore reads the emailTemplates array from your install manifest and upserts each entry. No separate auth needed because the merchant just authorized the install.
Anytime after install — Your server uses the OAuth access token it received during install to POST a new template:
The appId is read from the bearer token — apps can never write rows under another app’s appId.

Storage

Each template is stored as one record, uniquely keyed by (store, event, app). That key is what makes one merchant + N apps + N events safely concurrent:
Each record is independent; the resolution rules below pick one at send time. A read-only copy of each registered template is also kept in your app’s deployed extension bundle under email-templates/{event}.json, so you can inspect exactly what was deployed:
The bundle copy is never read at send time — it exists for developer inspection (“what did I actually deploy?”) and tooling (CLI pull/sync). To change a template, re-POST through the API; editing the deployed file has no effect.

End-to-end read path (at send time)

SMTP Reputation Gate

Even when a template override exists, it only fires if the merchant has configured their own SMTP. On the platform’s shared sender, the send falls back to the built-in default template. Why this gate exists. Imagine 1,000 stores install the same buggy app. Without the gate, every order email from those stores would go through the platform’s shared sender with malformed/spammy HTML — and spam filters would start marking the platform’s sender address as untrustworthy. Every store on the platform would lose deliverability. With the gate, a bad template only fires on stores that configured their own SMTP. Damage is scoped to that one merchant’s mail.yourstore.com reputation — not the platform’s. If an override exists but the gate blocks it, the send falls back to the default template — the most common reason a registered template “isn’t working” is that the merchant hasn’t configured their own SMTP yet.

Supported Events

Until an event is “wired,” registering a template for it is a no-op at send time — the template is stored, but the send pipeline continues to use the built-in default HTML. Track the changelog for events moving to Wired status.

Template Variables

Templates are rendered with the full Liquid engine — {{ var.path }} interpolation, {% for %} loops, {% if %} conditionals, {% assign %}, and built-in filters (upcase, date, truncate, plus, times, money_without_currency, etc.) all work. Missing values render as empty strings. Both the subject and htmlBody fields are rendered with the same engine and context.

Variables available for digital_delivery

Sent once per digital product on the order, so a customer who buys three digital items receives three emails — each naming its own product.
Use {{ delivery_html }} rather than building the delivery yourself. It renders the correct component for the product type — download buttons with filenames, a monospace licence-code box, a copyable access link, or service notes — already styled to survive Outlook, which ignores CSS gradients and flexbox. Style everything around it however you like; drop this in where the delivery should appear.
The four delivery types render as:

Variables available for order_confirmation

Order — top-level fields about the order: Line items — each item in order.line_items exposes: Customer: Shop: Helpers:

Iterating line items

When a customer orders multiple products, loop over order.line_items to render one row each:
Given a 2-item order, this renders two <tr> rows. Inside the loop you also have access to the standard Liquid forloop object:

Useful built-in filters

Template Manifest

Each entry under extensions.emailTemplates is one event override.

Fields

Entries that don’t match this shape are dropped silently at install.The installer keeps only entries that carry BOTH an event and an htmlBody. There is no error, no warning, and the install still reports success — the override simply never registers and the default email keeps going out.Two mistakes cause this:
  • Using templatePath. A path or URL to a template file is not supported. Inline the HTML into htmlBody, or POST it later through the REST API.
  • Inventing an event name. Only the names in Supported events exist. shipment_created, for example, is not one — the shipping event is shipment_notification.
After installing, confirm the row landed with GET /api/v1/email-templates.json.

Resolution Rules

For each (storeId, event), the active template is selected as follows:
  1. enabled = false rows are skipped entirely.
  2. App-provided rows win over merchant-set rows. Rationale: the merchant explicitly installed the app that ships the template, so the override is opt-in.
  3. Within the same app bucket, newest createdAt wins. Developers can iterate on their template without manual deletion.
If no row matches, LaunchMyStore falls back to the legacy hardcoded HTML for that event.

REST API

Two parallel controllers — pick the one that matches your auth context.

Merchant-scoped (Bearer JWT)

Used by the admin UI when a merchant edits a template directly. storeId is resolved from the JWT.

App-scoped (OAuth Bearer)

Used by your app after install. The appId field is forced to the authenticated app’s id — apps cannot impersonate each other. Required scopes: read_email_templates, write_email_templates.

Upsert example

Response:

Installing at App Install

The recommended flow is to ship your templates inline with the rest of your extension files during install. Add an emailTemplates array to the extensions payload of POST /api/apps/install-extensions:
This single call stores the canonical template record and deploys the read-only bundle copy — see Storage for the full layout.

Complete Example: Order Confirmation Template

A branded order confirmation that uses all of the MVP-supported variables.

See Also

  • App Listing — declaring scopes for email-template access.
  • Aqua Filters — full reference of the Liquid filters available in both theme rendering and email templates.
  • App Bridge Overview — the iframe channel for merchant-facing admin UI, separate from this REST-based template flow.
  • Webhooks — programmatic alternative if you want to send email yourself instead of overriding the built-in template.