or run

npx @tessl/cli init
Log in

Version

Tile

Overview

Evals

Files

Files

docs

advanced-delivery.mdattachments-content.mdemail-service.mdindex.mdmessage-construction.mdtemplates-personalization.mdtracking-analytics.md

templates-personalization.mddocs/

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

```