Templates
Create reusable email templates with variable substitution. Templates support HTML content with {{variable}} placeholders that are replaced at send time.
/templatesCreate a new email template. Templates start in draft status.
{
"name": "Welcome Email",
"subject": "Welcome to {{company_name}}, {{first_name}}!",
"html": "<h1>Hello {{first_name}},</h1><p>Welcome to {{company_name}}.</p>",
"text": "Hello {{first_name}}, Welcome to {{company_name}}.",
"variables": ["first_name", "company_name"]
}/templatesList all templates with pagination.
{
"templates": [
{
"id": "tpl_abc123def456ghi789",
"name": "Welcome Email",
"status": "published",
"created_at": "2026-03-23T10:00:00.000Z",
"updated_at": "2026-03-23T12:00:00.000Z"
}
],
"pagination": {
"total": 12,
"page": 1,
"per_page": 20,
"total_pages": 1
}
}/templates/:idRetrieve a single template including its full HTML content and variable list.
{
"id": "tpl_abc123def456ghi789",
"name": "Welcome Email",
"subject": "Welcome to {{company_name}}, {{first_name}}!",
"html": "<h1>Hello {{first_name}},</h1><p>Welcome to {{company_name}}.</p>",
"text": "Hello {{first_name}}, Welcome to {{company_name}}.",
"status": "published",
"variables": ["first_name", "company_name"],
"created_at": "2026-03-23T10:00:00.000Z",
"updated_at": "2026-03-23T12:00:00.000Z"
}/templates/:idUpdate a template. Published templates create a new version.
{
"name": "Welcome Email v2",
"html": "<h1>Hi {{first_name}}!</h1><p>Thanks for joining {{company_name}}.</p>"
}/templates/:idDelete a template. This does not affect emails already sent using this template.
{
"deleted": true
}/templates/:id/publishPublish a draft template, making it available for sending.
{
"id": "tpl_abc123def456ghi789",
"status": "published",
"published_at": "2026-03-23T15:00:00.000Z"
}/templates/:id/unpublishRevert a published template back to draft status.
{
"id": "tpl_abc123def456ghi789",
"status": "draft"
}/templates/:id/duplicateCreate a copy of an existing template. The duplicate starts in draft status with '(Copy)' appended to the name.
{
"id": "tpl_new_copy_456ghi789",
"name": "Welcome Email (Copy)",
"status": "draft",
"created_at": "2026-03-23T16:00:00.000Z"
}/templates/presetsList available template presets from the gallery. Presets are pre-built templates you can use as a starting point.
{
"presets": [
{
"id": 1,
"name": "Welcome Email",
"description": "A clean welcome email with logo and CTA",
"subject": "Welcome!",
"html": "<h1>Welcome</h1>...",
"text": "Welcome..."
},
{
"id": 2,
"name": "Newsletter",
"description": "Multi-section newsletter layout",
"subject": "Your Weekly Update",
"html": "<h1>Newsletter</h1>...",
"text": "Newsletter..."
}
]
}/templates/presets/:presetId/useCreate a new template from a preset. The template starts in draft status with the preset's content.
{
"id": "tpl_new_from_preset",
"name": "Welcome Email",
"subject": "Welcome!",
"status": "draft",
"created_at": "2026-03-23T16:00:00.000Z"
}Using Templates with Emails
Reference a published template by ID when sending an email. Provide the variable values to populate the placeholders:
await poststack.emails.send({
from: 'you@yourdomain.com',
to: ['alice@example.com'],
template_id: 'tpl_abc123def456ghi789',
variables: {
first_name: 'Alice',
company_name: 'Acme Inc',
},
});{
"from": "you@yourdomain.com",
"to": ["alice@example.com"],
"template_id": "tpl_abc123def456ghi789",
"variables": {
"first_name": "Alice",
"company_name": "Acme Inc"
}
}Conditional Blocks
Templates support flat conditional blocks for inclusion or exclusion of content based on whether a variable is truthy. Useful for optional greetings, footer lines that only appear for certain audiences, or fallback copy when a value is missing:
{{#if first_name}}Hi {{first_name}},{{/if}}
{{#unless first_name}}Hi there,{{/unless}}
Welcome to {{company_name}}.
{{#if support_url}}Need help? Visit {{support_url}}.{{/if}}A variable counts as truthy when present and not the empty string, "0", or "false". Conditionals do not nest in this pass — flat use covers the common cases (greet when known, fall back when unknown, hide CTAs that lack a URL). Conditionals are evaluated before variable substitution, so the inner content can reference the same variables.
Visual Template Builder
The dashboard includes a block-based visual editor as an alternative to hand-written HTML. When you choose Visual Builder at create time, you compose the email from typed blocks — heading, paragraph, button, image, divider — and PostStack renders them to the final HTML on save. The underlying builder_blocks JSON is stored alongside the compiled HTML so the editor can round-trip without lossy re-parsing. Variable placeholders ({{first_name}}) pass through any block's text content untouched and are substituted at send time.
You can switch a template between builder_type "html" and "visual", but going visual → html is one-way: editing the HTML directly discards the block tree. Publish bumps the version; renaming does not.
React Email Components
PostStack does not run a React renderer server-side. If you author your emails as React components (for example via react-email), render to HTML at build time or in your application before sending. The TS SDK accepts plain HTML on the html field — bring your own renderer:
import { render } from '@react-email/render';
import { WelcomeEmail } from './emails/welcome';
const html = render(<WelcomeEmail name="Alice" />);
await poststack.emails.send({
from: 'you@yourdomain.com',
to: ['alice@example.com'],
subject: 'Welcome',
html,
});This pattern keeps PostStack's surface small and the SDK runtime fast — the React renderer stays in your application's deployment, not in the email pipeline.