0
# Templates and Personalization
1
2
Templates and personalization enable dynamic, customized email content for individual recipients. SendGrid supports both modern dynamic templates and legacy templates, with comprehensive personalization capabilities for per-recipient customization.
3
4
## Capabilities
5
6
### Dynamic Templates
7
8
Modern template system with handlebars-style syntax and rich data binding capabilities.
9
10
```javascript { .api }
11
// Dynamic template message structure
12
const msg = {
13
to: recipients,
14
from: 'sender@example.com',
15
templateId: 'd-1234567890abcdef', // Dynamic templates start with 'd-'
16
dynamicTemplateData: templateData // Object with template variables
17
};
18
19
// Template data can include any JSON-serializable data
20
interface DynamicTemplateData {
21
[key: string]: any; // Strings, numbers, objects, arrays, booleans
22
}
23
```
24
25
**Usage Examples:**
26
27
```javascript
28
// Basic dynamic template
29
const msg = {
30
to: 'user@example.com',
31
from: 'noreply@example.com',
32
templateId: 'd-abc123def456',
33
dynamicTemplateData: {
34
firstName: 'John',
35
lastName: 'Doe',
36
accountBalance: 1250.75,
37
isVip: true,
38
orders: [
39
{ id: '12345', total: 99.99, date: '2024-03-15' },
40
{ id: '67890', total: 149.50, date: '2024-03-10' }
41
]
42
}
43
};
44
45
sgMail.send(msg);
46
47
// Complex template data with nested objects
48
const welcomeEmail = {
49
to: 'newuser@example.com',
50
from: 'welcome@example.com',
51
templateId: 'd-welcome-series-1',
52
dynamicTemplateData: {
53
user: {
54
firstName: 'Alice',
55
lastName: 'Johnson',
56
email: 'newuser@example.com',
57
signupDate: '2024-03-15',
58
preferences: {
59
newsletter: true,
60
notifications: false
61
}
62
},
63
company: {
64
name: 'Example Corp',
65
supportUrl: 'https://example.com/support',
66
unsubscribeUrl: 'https://example.com/unsubscribe'
67
},
68
features: [
69
{ name: 'Dashboard', available: true },
70
{ name: 'Analytics', available: false },
71
{ name: 'API Access', available: true }
72
]
73
}
74
};
75
```
76
77
### Legacy Templates
78
79
Traditional template system using substitution tags for simple variable replacement.
80
81
```javascript { .api }
82
// Legacy template message structure
83
const msg = {
84
to: recipients,
85
from: 'sender@example.com',
86
templateId: 'legacy-template-id', // Legacy templates don't start with 'd-'
87
substitutions: substitutionData, // Object mapping tags to values
88
substitutionWrappers: ['::', '::'] // Optional custom wrappers
89
};
90
91
// Substitution format
92
interface Substitutions {
93
[key: string]: string; // All values must be strings
94
}
95
```
96
97
**Usage Examples:**
98
99
```javascript
100
// Basic legacy template
101
const msg = {
102
to: 'user@example.com',
103
from: 'noreply@example.com',
104
templateId: 'password-reset-template',
105
subject: 'Password Reset for ::firstName::',
106
substitutions: {
107
'::firstName::': 'John',
108
'::resetUrl::': 'https://app.example.com/reset?token=abc123',
109
'::expiryTime::': '24 hours'
110
}
111
};
112
113
// Custom substitution wrappers
114
const customMsg = {
115
to: 'user@example.com',
116
from: 'noreply@example.com',
117
templateId: 'custom-template',
118
substitutions: {
119
'[[username]]': 'johndoe',
120
'[[activationCode]]': '123456'
121
},
122
substitutionWrappers: ['[[', ']]']
123
};
124
125
// Template sections for reusable content blocks
126
const sectionMsg = {
127
to: 'user@example.com',
128
from: 'noreply@example.com',
129
templateId: 'newsletter-template',
130
sections: {
131
'::header::': '<h1>Monthly Newsletter</h1>',
132
'::footer::': '<p>© 2024 Example Corp</p>',
133
'::promotions::': '<div>Special offers this month!</div>'
134
},
135
substitutions: {
136
'::firstName::': 'John',
137
'::month::': 'March'
138
}
139
};
140
```
141
142
### Personalization Objects
143
144
Per-recipient customization allowing different template data, subjects, and recipients for each personalization.
145
146
```javascript { .api }
147
// Personalization data structure
148
interface PersonalizationData {
149
to: EmailData | EmailData[]; // Required recipients
150
from?: EmailData; // Override sender
151
cc?: EmailData | EmailData[]; // CC recipients
152
bcc?: EmailData | EmailData[]; // BCC recipients
153
subject?: string; // Override subject
154
headers?: { [key: string]: string }; // Custom headers
155
substitutions?: { [key: string]: string }; // Legacy template data
156
dynamicTemplateData?: { [key: string]: any }; // Dynamic template data
157
customArgs?: { [key: string]: string }; // Custom tracking args
158
sendAt?: number; // Scheduled send time
159
}
160
161
// Use personalizations in mail data
162
const msg = {
163
from: 'sender@example.com',
164
templateId: 'd-personalized-template',
165
personalizations: [personalizationData]
166
};
167
```
168
169
**Usage Examples:**
170
171
```javascript
172
// Multiple personalizations for different recipients
173
const msg = {
174
from: 'newsletter@example.com',
175
templateId: 'd-monthly-newsletter',
176
personalizations: [
177
{
178
to: [{ email: 'premium@example.com', name: 'Premium User' }],
179
subject: 'Premium Newsletter - Exclusive Content',
180
dynamicTemplateData: {
181
firstName: 'John',
182
subscriptionType: 'Premium',
183
exclusiveContent: true,
184
featuredArticles: [
185
{ title: 'Advanced Features Guide', url: 'https://example.com/premium1' },
186
{ title: 'Investment Strategies', url: 'https://example.com/premium2' }
187
]
188
}
189
},
190
{
191
to: [{ email: 'basic@example.com', name: 'Basic User' }],
192
subject: 'Monthly Newsletter - Latest Updates',
193
dynamicTemplateData: {
194
firstName: 'Jane',
195
subscriptionType: 'Basic',
196
exclusiveContent: false,
197
featuredArticles: [
198
{ title: 'Getting Started Guide', url: 'https://example.com/basic1' },
199
{ title: 'Tips and Tricks', url: 'https://example.com/basic2' }
200
]
201
}
202
}
203
]
204
};
205
206
// Personalization with different send times
207
const scheduledMsg = {
208
from: 'reminders@example.com',
209
templateId: 'd-appointment-reminder',
210
personalizations: [
211
{
212
to: ['patient1@example.com'],
213
subject: 'Appointment Reminder - Tomorrow at 10 AM',
214
sendAt: Math.floor(Date.now() / 1000) + 86400, // 24 hours from now
215
dynamicTemplateData: {
216
patientName: 'John Smith',
217
appointmentDate: '2024-03-16',
218
appointmentTime: '10:00 AM',
219
doctorName: 'Dr. Johnson'
220
}
221
},
222
{
223
to: ['patient2@example.com'],
224
subject: 'Appointment Reminder - Tomorrow at 2 PM',
225
sendAt: Math.floor(Date.now() / 1000) + 86400, // 24 hours from now
226
dynamicTemplateData: {
227
patientName: 'Jane Doe',
228
appointmentDate: '2024-03-16',
229
appointmentTime: '2:00 PM',
230
doctorName: 'Dr. Williams'
231
}
232
}
233
]
234
};
235
```
236
237
### Personalization Class
238
239
Use the Personalization class for programmatic construction of personalization objects.
240
241
```javascript { .api }
242
const { Personalization } = require('@sendgrid/helpers').classes;
243
244
/**
245
* Create a new personalization instance
246
* @param data - Optional initial personalization data
247
*/
248
const personalization = new Personalization(data);
249
250
// Recipient management
251
personalization.setTo(to);
252
personalization.addTo(to);
253
personalization.setCc(cc);
254
personalization.addCc(cc);
255
personalization.setBcc(bcc);
256
personalization.addBcc(bcc);
257
258
// Content customization
259
personalization.setSubject(subject);
260
personalization.setSendAt(sendAt);
261
personalization.setDynamicTemplateData(data);
262
personalization.setSubstitutions(substitutions);
263
264
// Headers and tracking
265
personalization.setHeaders(headers);
266
personalization.addHeader(key, value);
267
personalization.setCustomArgs(customArgs);
268
personalization.addCustomArg(key, value);
269
270
// Substitution management
271
personalization.addSubstitution(key, value);
272
personalization.reverseMergeSubstitutions(substitutions);
273
personalization.setSubstitutionWrappers(wrappers);
274
275
// Convert to JSON
276
const jsonData = personalization.toJSON();
277
```
278
279
**Usage Examples:**
280
281
```javascript
282
const { Personalization } = require('@sendgrid/helpers').classes;
283
284
// Build personalization programmatically
285
const personalization = new Personalization();
286
287
// Set recipients
288
personalization.setTo([
289
{ email: 'user1@example.com', name: 'User One' },
290
{ email: 'user2@example.com', name: 'User Two' }
291
]);
292
personalization.addCc('manager@example.com');
293
294
// Set custom subject
295
personalization.setSubject('Personal Message for Your Team');
296
297
// Add dynamic template data
298
personalization.setDynamicTemplateData({
299
teamName: 'Development Team',
300
projectStatus: 'On Track',
301
deadline: '2024-04-01',
302
completionPercentage: 75
303
});
304
305
// Add custom tracking
306
personalization.setCustomArgs({
307
teamId: 'dev-team-1',
308
projectId: 'proj-2024-q1'
309
});
310
311
// Add custom headers
312
personalization.addHeader('X-Team-Priority', 'High');
313
314
// Use in email
315
const msg = {
316
from: 'pm@example.com',
317
templateId: 'd-team-update-template',
318
personalizations: [personalization]
319
};
320
```
321
322
### Template Data Helpers
323
324
Utility functions for working with template data and substitutions.
325
326
```javascript { .api }
327
// Global template data application (Mail class methods)
328
const mail = new Mail();
329
330
/**
331
* Apply global substitutions to a personalization
332
* @param personalization - Personalization instance to modify
333
*/
334
mail.applySubstitutions(personalization);
335
336
/**
337
* Apply global dynamic template data to a personalization
338
* @param personalization - Personalization instance to modify
339
*/
340
mail.applyDynamicTemplateData(personalization);
341
342
// Substitution merging (Personalization class method)
343
/**
344
* Merge substitutions while preserving existing ones
345
* @param substitutions - New substitutions to merge
346
*/
347
personalization.reverseMergeSubstitutions(substitutions);
348
```
349
350
**Usage Examples:**
351
352
```javascript
353
const { Mail, Personalization } = require('@sendgrid/helpers').classes;
354
355
// Global template data
356
const mail = new Mail();
357
mail.setDynamicTemplateData({
358
companyName: 'Example Corp',
359
supportEmail: 'support@example.com',
360
unsubscribeUrl: 'https://example.com/unsubscribe'
361
});
362
363
// Individual personalization
364
const personalization = new Personalization();
365
personalization.setTo('user@example.com');
366
personalization.setDynamicTemplateData({
367
firstName: 'John',
368
accountBalance: 1500.00
369
});
370
371
// Apply global data to personalization
372
mail.applyDynamicTemplateData(personalization);
373
// Now personalization has both global and individual data
374
375
// Merge substitutions safely
376
personalization.setSubstitutions({
377
'::firstName::': 'John',
378
'::accountType::': 'Premium'
379
});
380
381
personalization.reverseMergeSubstitutions({
382
'::firstName::': 'Johnny', // Won't override existing
383
'::lastName::': 'Doe' // Will be added
384
});
385
// Result: firstName stays 'John', lastName becomes 'Doe'
386
```
387
388
## Template Best Practices
389
390
### Dynamic Template Guidelines
391
392
1. **Use descriptive variable names**: `{{user.firstName}}` instead of `{{n}}`
393
2. **Structure data logically**: Group related data in objects
394
3. **Provide fallbacks**: Use handlebars helpers for missing data
395
4. **Validate data types**: Ensure template expects the right data types
396
397
### Legacy Template Guidelines
398
399
1. **Consistent wrapper syntax**: Stick to one wrapper style throughout
400
2. **Escape special characters**: Be careful with HTML in substitutions
401
3. **String values only**: All substitution values must be strings
402
4. **Use sections for reusable content**: Define common blocks in sections
403
404
### Personalization Strategy
405
406
1. **Segment recipients appropriately**: Group similar recipients together
407
2. **Optimize for deliverability**: Don't over-personalize to avoid spam filters
408
3. **Test with real data**: Validate templates with actual production data
409
4. **Monitor performance**: Track open and click rates by personalization type
410
411
## Error Handling
412
413
```javascript
414
// Handle template errors
415
sgMail.send(templateMsg)
416
.catch(error => {
417
if (error.response && error.response.body) {
418
const { errors } = error.response.body;
419
420
errors.forEach(err => {
421
if (err.field === 'template_id') {
422
console.error('Template not found or invalid:', err.message);
423
} else if (err.field === 'personalizations') {
424
console.error('Personalization error:', err.message);
425
}
426
});
427
}
428
});
429
```