Appearance
Email Templates
Channel: email. For SMS, see SMS Templates.
A template holds the email body written in RCML. Templates are independent objects — they are not linked to a message at creation time. The link is made later, via a dynamic set. This means the same template can be reused across multiple messages.
Creating a template
Use createEmailTemplate() to create a new email template. The template's RCML document defines the visual structure and content of the email.
typescript
import { buildRcmlDocument } from '@rule/rcml';
const rcml = buildRcmlDocument({ /* ... your template ... */ });
const template = await client.templates.createEmailTemplate({
name: 'Order shipped — v1',
content: rcml,
});
const templateId = template.id;Template names must be unique within the account. When creating templates programmatically, append a timestamp to avoid conflicts: name: \${baseName} - ${Date.now()}``.
See the @rule/rcml documentation for how to build the RCML document.
Fetching a template
Use get() to retrieve a single template by its ID. It returns null if the template does not exist, rather than throwing an error.
typescript
const template = await client.templates.get(templateId);
if (!template) {
console.log('Template not found');
} else {
console.log(template.name); // 'Order shipped — v1'
console.log(template.messageType); // 'email'
console.log(template.createdAt);
}Updating a template
Use updateEmailTemplate() to change a template's name or RCML content. Pass only the fields you want to change — omitted fields are left as-is.
typescript
// Rename without changing content
await client.templates.updateEmailTemplate(templateId, {
name: 'Order shipped — v2',
});
// Replace content without renaming
await client.templates.updateEmailTemplate(templateId, {
content: updatedRcml,
});
// Change both at once
await client.templates.updateEmailTemplate(templateId, {
name: 'Order shipped — v3',
content: updatedRcml,
});Previewing output
Use render() to get the fully rendered HTML output of a template before attaching it to a campaign or automation. This is useful to confirm the visual result and catch any rendering issues early.
If your template uses smart fields, pass a subscriberId to get a personalized preview with the subscriber's actual data substituted in.
typescript
// Render the template as-is
const html = await client.templates.render(templateId);
// Render with a specific subscriber's data substituted into smart fields
const personalized = await client.templates.render(templateId, { subscriberId: 42 });
// render() returns null when the template doesn't exist
if (!html) {
console.log('Template not found');
}Deleting a template
Use delete() to permanently remove a template. Before deleting, remove any dynamic sets that reference the template first — otherwise those dynamic sets will point to a non-existent template and the message they belong to cannot be sent. See Dynamic Sets for how to manage them.
typescript
await client.templates.delete(templateId);Listing templates
The API returns templates of all types (email and SMS) and does not support server-side filtering by message type. Use the method that fits your use case:
typescript
// One page — for UI tables, manual pagination, or retrying a specific page
const page = await client.templates.listTemplates({ pagination: { page: 1, pageSize: 50 } });
// All templates as a single array — convenient for scripts and small libraries
const all = await client.templates.listAllTemplates();
// Stream individual templates — memory-efficient for large libraries
for await (const template of client.templates.iterateTemplates()) {
console.log(template.name);
}
// Stream page by page — useful for batched processing
for await (const page of client.templates.iterateTemplatesPages({ pagination: { pageSize: 50 } })) {
console.log(`Batch of ${page.length} templates`);
}listTemplates() fetches exactly one page. The iterators auto-paginate until all templates have been yielded.
Next steps
- Link the template to a message: Dynamic Sets
- Build RCML templates: @rule/rcml documentation