Test Emails
Plan Feature
This feature is only available on Launch, Growth, and Scale plans.
Test emails let your users send a preview of their template to a real inbox before going live. When enabled, the editor toolbar shows a Send Test Email button.
How It Works
- Your token endpoint returns a list of allowed recipient addresses and a cryptographic signature (see Setup)
- The SDK shows a Send Test Email button in the editor toolbar
- The user picks a recipient from the allowed list and clicks send
- The SDK saves the template, exports the HTML, runs the
onBeforeTestEmailcallback (if configured), and sends the email
The allowed recipients list is signed with HMAC-SHA256 so it cannot be tampered with on the client side.
Setup
1. Get Your Signing Key
Find the Signing Key in your project settings on the Templatical dashboard. This key is used to sign the allowed recipients list. Store it securely on your backend alongside your Client ID and Client Secret.
2. Update Your Token Endpoint
Your token endpoint already returns a token response (see Authentication). To enable test emails, add two extra fields to the response:
{
"token": "eyJhbGciOiJIUzI1NiIs...",
"expires_at": 1709251200,
"project_id": "proj_abc123",
"tenant": "acme-corp",
"test_email": {
"allowed_emails": ["[email protected]", "[email protected]"],
"signature": "a1b2c3d4..."
}
}| Field | Type | Description |
|---|---|---|
test_email | object | Test email configuration (omit to hide the button) |
test_email.allowed_emails | string[] | Email addresses allowed to receive test emails |
test_email.signature | string | HMAC-SHA256 signature of the allowed emails list |
If the test_email field is omitted, the Send Test Email button will not appear in the toolbar.
Computing the Signature
The signature algorithm is:
- Sort the email addresses alphabetically
- JSON-encode the sorted array
- HMAC-SHA256 the JSON string with your signing key
Backend Examples
import crypto from 'crypto';
app.post('/api/token', async (req, res) => {
// 1. Get the token from Templatical
const response = await fetch('https://templatical.com/api/v1/auth/token', {
method: 'POST',
headers: { 'Content-Type': 'application/json' },
body: JSON.stringify({
client_id: process.env.TEMPLATICAL_CLIENT_ID,
client_secret: process.env.TEMPLATICAL_CLIENT_SECRET,
tenant: req.user.organizationId,
}),
});
const tokenData = await response.json();
// 2. Define allowed test email recipients
const allowedEmails = ['[email protected]', '[email protected]'];
// 3. Compute the HMAC signature
const sorted = [...allowedEmails].sort();
const signature = crypto
.createHmac('sha256', process.env.TEMPLATICAL_SIGNING_KEY)
.update(JSON.stringify(sorted))
.digest('hex');
// 4. Return token + test email config
res.json({
...tokenData,
test_email: {
allowed_emails: allowedEmails,
signature,
},
});
});TIP
You can dynamically determine the allowed recipients based on the authenticated user — for example, only the current user's own email, or a shared team test inbox.
onBeforeTestEmail
Called before a test email is sent. Use this callback to transform the HTML before it reaches the recipient — for example, to replace merge tags with real test data so the email looks realistic.
The callback receives the raw HTML string and must return the transformed HTML (or a Promise that resolves to it). If no callback is provided, the HTML is sent as-is.
const editor = await init({
container: '#email-editor',
auth: { url: 'https://your-app.com/api/token' },
onBeforeTestEmail: async (html) => {
// Fetch test data from your API
const testData = await fetch('/api/test-data').then(r => r.json());
// Use a global regex to replace all occurrences
return html
.replace(/\{\{first_name\}\}/g, testData.firstName)
.replace(/\{\{last_name\}\}/g, testData.lastName)
.replace(/\{\{email\}\}/g, testData.email)
.replace(/\{\{unsubscribe_url\}\}/g, 'https://example.com/unsubscribe');
},
});Rate Limiting
Test email sending is rate-limited on the server side to prevent abuse. If the limit is exceeded, the SDK will surface an error through the onError callback.