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.
{
"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. Rawhtml 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
variablesobjectOptionalorder_id or a magic link.contact.dataobjectOptionaldata 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.
// 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-timevariables 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:
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.
| Placeholder | Value present | Value missing |
|---|---|---|
{{first_name}} | Jane | (empty) |
{{first_name | "there"}} | Jane | there |
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.
{{#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
Fill in sample data
Preview across inboxes
Preview is not a send
Sample data lives in the editor only. Actual sends resolve placeholders from your send-timevariables and the recipient contact’s stored data — not from the preview panel.