DeckleDocs
Dashboard

Sending

Variables & personalization

Insert per-recipient values into subjects and templates with {{variable}} placeholders, with fallbacks and conditional blocks for the tricky cases.

Personalization in Deckle is a single primitive: {{variable}} placeholders. Drop them into a subject line or a template, provide values on send or from the contact, and Deckle fills them in as it renders each email.

Placeholders#

A placeholder is a name wrapped in double curly braces, like {{first_name}}. You can use placeholders in the subject and anywhere in a template body. When Deckle renders the email, each placeholder is replaced with the matching value for that recipient.

template.json
{
  "subject": "{{first_name}}, your order is on its way",
  "body": "Hi {{first_name}}, order #{{order_id}} shipped to {{city}} today."
}

Placeholder names are case-sensitive and should be lowercase with underscores (first_name, order_id). A placeholder with no matching value renders as empty unless you give it a fallback.

Where variables are applied

Placeholders are resolved for template sends and for the subject line. Raw html sends are delivered as-is and are not instrumented or interpolated — pass a template when you want personalization.

Providing values#

Values come from two places, merged together for each recipient:

Value sources

variablesobjectOptional
A key/value map you pass on the send call. Great for one-off values that only exist at send time, like order_id or a magic link.
contact.dataobjectOptional
The custom data stored on a contact (keyed by email). Anything you saved on the contact is available as a placeholder without repeating it on every send.

Pass a variables map alongside the template when you send. Keys match placeholder names; values are strings (or numbers that render as text).

import { Deckle } from "@deckle/sdk";

const deckle = new Deckle(process.env.DECKLE_API_KEY!);

await deckle.emails.send({
  from: "Acme <hello@acme.com>",
  to: "jane@example.com",
  template: "tmpl_shipping_update",
  variables: {
    first_name: "Jane",
    order_id: "1234",
    city: "Portland",
  },
});

When you send to a known contact, Deckle also pulls from that contact's stored data. If a placeholder appears in both places, the variables you pass on the send win — so you can store defaults on the contact and override them per send.

contact.ts
// Store data on the contact once...
await deckle.contacts.create({
  email: "jane@example.com",
  name: "Jane Doe",
  data: { first_name: "Jane", plan: "Pro" },
});

// ...then {{first_name}} and {{plan}} resolve automatically,
// even when you don't pass them in variables.
await deckle.emails.send({
  from: "Acme <hello@acme.com>",
  to: "jane@example.com",
  template: "tmpl_welcome",
});

Precedence at a glance

Send-time variables override contact.data, which overrides the placeholder’s fallback, which falls back to empty. Most specific wins.

Fallback values#

Real data is never complete. Give any placeholder a fallback with the pipe syntax so a missing value degrades gracefully instead of leaving a hole:

text
Hi {{first_name | "there"}}, welcome aboard.

If first_name resolves to a value, that value is used; otherwise the quoted fallback is rendered. Fallbacks work everywhere placeholders do — subject and body alike.

PlaceholderValue presentValue missing
{{first_name}}Jane(empty)
{{first_name | "there"}}Janethere

Default your greetings

A fallback on the first placeholder in a greeting is the single highest-leverage habit for personalization — Hi {{first_name | "there"}} never renders an awkward “Hi ,”.

Conditional blocks#

For advanced templates you can render a chunk of content only when a value is present. This is useful when a section only makes sense for some recipients — a plan name, a referral code, a shipping note.

text
{{#if plan}}
  You're on the {{plan}} plan — thanks for being a customer.
{{else}}
  Upgrade any time to unlock more sends.
{{/if}}

Conditional blocks are an advanced feature; for most emails, placeholders with fallbacks cover what you need. Build and preview conditionals in the template editor before you rely on them in a send.

Previewing#

The template editor renders your placeholders against sample data so you can see exactly how a personalized email will look before it goes out.

Open the template

In the dashboard, go to Templates and open the template you're editing.

Fill in sample data

Set sample values for each placeholder in the editor's variable panel. Try both a filled value and an empty one to confirm your fallbacks behave.

Preview across inboxes

Toggle desktop/mobile and light/dark inbox preview. The editor also flags missing variables and broken links so nothing ships half-personalized.

Preview is not a send

Sample data lives in the editor only. Actual sends resolve placeholders from your send-time variables and the recipient contact’s stored data — not from the preview panel.

Next steps#