Personalised emails are powerful when they work correctly — and embarrassing when they do not. A recipient receiving "Hi {{first_name}}," or seeing their colleague's order details is a direct trust failure. This article covers a systematic testing approach for every type of personalisation, including the edge cases most teams miss.
The Personalisation Testing Framework
Test personalisation across four dimensions before any send:
- Happy path — all variables provided correctly
- Missing variables — one or more variables absent; fallback values activate
- Edge case values — unusual but valid values (very long names, special characters, zero amounts)
- Conditional logic — test both true and false paths for every conditional block
Method 1 — Dashboard Preview with Sample Data
- Open your template in the MigoSMTP editor.
- Click Preview.
- In the preview panel, enter sample variable values that represent each scenario you want to test.
- Switch between scenarios using the preview variable inputs to verify each renders correctly.
This is the fastest first pass — catch literal {{variable}} rendering issues immediately before spending time on real test sends.
Method 2 — Test Email Send
Send test emails that represent each test scenario to a real inbox:
// Test Scenario 1 — All variables provided (happy path)
POST /v1/email/send
{
"from": "test@yourcompany.com",
"to": "yourtestemail@yourcompany.com",
"template_id": "order-confirmation-v2",
"variables": {
"first_name": "Rahul",
"order_id": "ORD-TEST-001",
"order_total": "2,499.00",
"currency": "₹",
"delivery_date": "15 June 2026",
"is_premium": "true",
"tracking_url": "https://yourcompany.com/track/test"
}
}
// Test Scenario 2 — Missing first_name (fallback test)
POST /v1/email/send
{
"from": "test@yourcompany.com",
"to": "yourtestemail@yourcompany.com",
"template_id": "order-confirmation-v2",
"variables": {
"order_id": "ORD-TEST-002",
"order_total": "3,199.00",
"currency": "₹",
"delivery_date": "16 June 2026",
"is_premium": "false"
}
// first_name omitted — should show fallback "there"
}
// Test Scenario 3 — Edge case values
POST /v1/email/send
{
"from": "test@yourcompany.com",
"to": "yourtestemail@yourcompany.com",
"template_id": "order-confirmation-v2",
"variables": {
"first_name": "Konstantinos-Alexandros", // Very long name
"order_id": "ORD-TEST-003",
"order_total": "0.00", // Zero amount
"currency": "$", // International currency
"delivery_date": "3 July 2026",
"is_premium": "true"
}
}
Edge Cases to Always Test
| Edge Case | Variable / Value | What to Check |
|---|---|---|
| Very long name | first_name = "Venkatanarasimharajuvaripeta" | Subject line not truncated awkwardly; greeting line does not overflow layout |
| Special characters in name | first_name = "José" / "Müller" / "O'Brien" | UTF-8 characters render correctly; apostrophes do not break HTML |
| Zero or very small amount | order_total = "0.00" | Renders as "₹0.00" not blank; discount block shows/hides correctly |
| Very large amount | order_total = "1,00,00,000.00" | Long number does not break table layout; currency symbol positioned correctly |
| Missing critical URL | tracking_url omitted | Fallback URL renders (not a broken link); conditional hides CTA if no URL |
| HTML in variable value | first_name = "<script>alert(1)</script>" | Script tag is escaped and rendered as text, not executed — critical security check |
| All variables missing | No variables object provided | All fallbacks activate; email is still readable and coherent without any personalisation |
| Boolean conditionals | is_premium = "true" and is_premium = "false" | Both conditional branches render the correct content; neither branch renders for the other |
Automated Pre-Send Personalisation Check
For production systems sending personalised transactional emails at high volume, automate the variable validation as part of your send pipeline:
// Node.js — Personalisation validation middleware
const TEMPLATE_REQUIRED_VARS = {
'order-confirmation-v2': [
'first_name', 'order_id', 'order_total', 'currency', 'tracking_url'
],
'password-reset': ['first_name', 'reset_url', 'expiry_minutes'],
'trial-expiry': ['first_name', 'plan_name', 'days_remaining', 'upgrade_url'],
};
function validatePersonalisation(templateId, variables) {
const required = TEMPLATE_REQUIRED_VARS[templateId] || [];
const warnings = [];
const errors = [];
for (const varName of required) {
if (!variables[varName]) {
if (['tracking_url', 'first_name'].includes(varName)) {
// Non-critical — warn but do not block
warnings.push(`Missing variable: ${varName} (fallback will be used)`);
} else {
// Critical — block the send
errors.push(`Missing required variable: ${varName}`);
}
}
}
// Check for excessively long values
for (const [key, value] of Object.entries(variables)) {
if (typeof value === 'string' && value.length > 500) {
warnings.push(`Variable ${key} is very long (${value.length} chars) — may affect layout`);
}
}
return { valid: errors.length === 0, errors, warnings };
}
Personalisation Testing Checklist
| ✓ | Test |
|---|---|
| □ | Happy path — all variables provided and rendered correctly |
| □ | Missing first_name shows fallback (not literal tag) |
| □ | No variables at all — email still readable with fallbacks |
| □ | Conditional block shows when condition is true |
| □ | Conditional block hides when condition is false |
| □ | Long name does not break subject line or email layout |
| □ | Special characters in name render correctly (José, O'Brien) |
| □ | HTML in variable value is escaped (not rendered as HTML) |
| □ | Subject line personalisation renders correctly in inbox |
| □ | All CTA links personalised correctly and point to correct URLs |