Templates live inside the campaign that uses them, not as a separate top-level catalogue. Editing a campaign’s templates requires the project
editor role or higher. Fields that support variables can use contact attributes and supplied event data.The template model
Two attributes shape every template: its channel type and its locale.- Channel type decides which fields the template carries. An email template has
from,subject, andhtml. A push template hastitle,body, andurl. The two types share no fields. - Locale lets you author variants of the same template for different audiences. A campaign sending in English and German would carry one email template per locale.
Channel field reference
- Email
- SMS
- Push
- Webhook
- In-app
Compose email templates with the visual builder, WYSIWYG editor, HTML code or plain text.
The
subject, preheader, from, from.name, from.address, reply_to, cc, bcc, text, html and custom-header values support variables before sending.Template variables
Use double braces to insert a value, such as{{user.email}}. The available variable families are:
Use helpers and blocks for formatting and conditional content:
firstName set to Sam, signup_at set to 2026-09-15T00:00:00Z and lifetime_value set to the number 1250, these examples produce Sam, Sep 15, 2026, Hello Sam and $1,250.00.
Double braces escape HTML-sensitive characters. For example, A&B becomes A&B. Use triple braces, such as {{{user.sender_group}}}, only when you intend unescaped output. Missing properties normally produce an empty string; use an if block to supply a fallback.
The same expression syntax works in subject lines, preheaders, plain-text and HTML email bodies, custom email-header values, SMS bodies, push titles, push bodies, push URLs, push custom maps, webhook endpoints, webhook headers and webhook bodies.
Locale variants
Multi-locale projects rely on per-template locales. The pattern is straightforward:- Set a project default locale in Settings → General → Regional defaults.
- Create the default-locale template inside your campaign.
- Add per-locale variants for each additional audience (
en-US,de-DE,es-MX, and so on).
Email editor modes
Email templates carry aneditor field that decides which authoring surface you see:
codedrops you into raw HTML. You write or paste HTML directly. Good for templates moved over from another platform or built externally.visualuses the Visual builder with drag-and-drop blocks. It generates the HTML that Spotzee sends when you save.wysiwyguses the WYSIWYG editor for rich content. It preserves your editable design and generates the HTML that Spotzee sends when you save.plainis plain-text only. Thetextfield is required and thehtmlfield is ignored. Use this for transactional notifications, agent-style communications, or audiences where HTML is unwelcome.
Custom email headers
Use template headers for metadata that varies by contact or campaign. They apply to campaign emails, journey emails and proofs. Configure any routing rules at your provider separately.1
Open the template's header settings
In the campaign wizard, open the email template’s advanced settings. You can also edit headers in the template details form.
2
Add a header row
Select Add header. Enter a literal name in Header name and an expression or fixed value in Header value. For example, use
X-Delivery-Group with {{user.sender_group}} if your provider uses that header for routing.3
Save and verify
Correct any inline validation error, then save. Reopen the template to confirm the rows, send a proof to a controlled contact and inspect the outgoing message headers.
Provider precedence
Template names override matching provider headers without regard to case. Unrelated provider headers remain present. Each message renders its values from that contact’s context, including company references used only in a header. An empty or whitespace-only rendered value suppresses the matching provider header and adds nothing in its place. Previews omit that empty header. Removing the template row restores the provider’s default on later sends.Save and send errors
Invalid names, reserved names, duplicate names and malformed rows prevent saving and identify the affected row or name. Correct or remove the row and save again. The wizard keeps the form open after a failed save. If you edit while navigation is waiting for a save, check the latest edit and select the destination again. If WYSIWYG content fails validation, the previously saved content and header rows remain unchanged. Correct the content and save again. An invalid header expression follows the same error-reporting path as an invalid subject expression. Unsafe rendered control characters also stop the send before provider submission. Check the failed send, journey error or proof error, correct the expression or source data, then test again.Routing from a journey
For a provider that routes onX-Delivery-Group, set its template value to {{user.sender_group}}. In a journey, configure User Update with {"sender_group":"grp_b"}, followed by Delay and the email send. Confirm the property is saved during the delay, then inspect the outgoing message after the journey resumes for X-Delivery-Group: grp_b.
A proof checks the supplied rendering context. A resumed journey checks that the send uses the saved contact update.
Tracking and link wrapping
Two project-level switches change what Spotzee does to template content at send time:- Track opens (email). When on, Spotzee injects a 1×1 tracking pixel into HTML emails so you can report opens. Plain-text emails (
editor: plain) never get a tracking pixel. - Wrap links (email and push). When on, Spotzee rewrites every link through your tracking domain so you can report click-throughs. The link wrapping respects your custom domain configuration if one is set.
Reference
Template header data
The optionaldata.customHeaders field contains an array of objects with string name and value fields. An empty array clears every template header. Existing templates need no migration. Duplication and WYSIWYG saves preserve header rows, including literal empty values.
For example, this value defines one dynamic header and suppresses a provider’s X-Optional default:
Header names
A name must contain one or more printable ASCII characters, excluding whitespace and:. Names are literal and do not support expressions. Duplicate names are rejected without regard to case.
These exact names are reserved, without regard to case:
From,Sender,Reply-To,To,Cc,Bcc,Subject,Date,Message-ID.In-Reply-To,References,Return-Path,Received,Delivered-To,Errors-To.MIME-Version,DKIM-Signature,Authentication-Results,Received-SPF,SPF,DMARC.List-Unsubscribe,List-Unsubscribe-Post,X-Campaign-Id,X-Subscription-Id,X-Test-Email.
Content-, Resent- or ARC- are also reserved, without regard to case. These restrictions protect addressing, message structure, authentication, tracking, unsubscribe and proof headers.
Header values
Spotzee stores values unchanged, including expressions and empty strings. Template headers do not inherit provider header-count or value-length limits; provider configuration keeps its existing validation rules. After rendering, a value containing a carriage return, line feed or another ASCII control character fails compilation. Horizontal tab is allowed; DEL is rejected. The error identifies the header without including its rendered value. Non-empty values are not silently trimmed or sanitised.Next steps
Concepts
Brush up on Users, Journeys, Segments, Channels, and Providers.
Trigger a campaign
Send a one-shot campaign through the API.
Set up a project
Configure your default locale and tracking switches.
Provider catalogue
See which providers handle each channel type.