0
# Connection Management
1
2
Transport connection lifecycle management including verification, pooling, cleanup, and monitoring for reliable email delivery.
3
4
## Capabilities
5
6
### Connection Verification
7
8
Test and verify transport configuration before sending emails to ensure proper setup and connectivity.
9
10
```javascript { .api }
11
/**
12
* Verifies transport configuration by testing connection and authentication
13
* @param {Function} [callback] - Optional callback function (error, success) => void
14
* @returns {Promise<boolean>} Promise resolving to true if connection successful
15
*/
16
verify(callback);
17
```
18
19
**Usage Examples:**
20
21
Callback style verification:
22
```javascript
23
const transporter = nodemailer.createTransport({
24
host: 'smtp.example.com',
25
port: 587,
26
secure: false,
27
auth: {
28
user: 'user@example.com',
29
pass: 'password'
30
}
31
});
32
33
transporter.verify((error, success) => {
34
if (error) {
35
console.error('Transport verification failed:', error);
36
37
// Handle specific error types
38
switch (error.code) {
39
case 'ECONNREFUSED':
40
console.error('Connection refused - check host and port');
41
break;
42
case 'EAUTH':
43
console.error('Authentication failed - check credentials');
44
break;
45
case 'ETLS':
46
console.error('TLS error - check secure settings');
47
break;
48
default:
49
console.error('Unknown error:', error.message);
50
}
51
} else {
52
console.log('Transport is ready to send emails');
53
}
54
});
55
```
56
57
Promise style verification:
58
```javascript
59
async function verifyTransport() {
60
try {
61
const isReady = await transporter.verify();
62
console.log('Transport verified successfully:', isReady);
63
return true;
64
} catch (error) {
65
console.error('Transport verification failed:', error.message);
66
67
// Retry logic
68
if (error.code === 'ECONNREFUSED') {
69
console.log('Retrying in 5 seconds...');
70
await new Promise(resolve => setTimeout(resolve, 5000));
71
return verifyTransport(); // Retry
72
}
73
74
throw error;
75
}
76
}
77
```
78
79
Verification with timeout:
80
```javascript
81
async function verifyWithTimeout(timeoutMs = 10000) {
82
return Promise.race([
83
transporter.verify(),
84
new Promise((_, reject) => {
85
setTimeout(() => {
86
reject(new Error('Verification timeout'));
87
}, timeoutMs);
88
})
89
]);
90
}
91
92
// Usage
93
try {
94
await verifyWithTimeout(5000);
95
console.log('Transport verified within 5 seconds');
96
} catch (error) {
97
console.error('Verification failed or timed out:', error.message);
98
}
99
```
100
101
### Connection Status Monitoring
102
103
Monitor connection status and availability, particularly useful for pooled connections.
104
105
```javascript { .api }
106
/**
107
* Checks if transport is idle and ready to send emails
108
* @returns {boolean} True if transport is idle and available
109
*/
110
isIdle();
111
```
112
113
**Usage Examples:**
114
115
Basic idle checking:
116
```javascript
117
const poolTransporter = nodemailer.createTransport({
118
pool: true,
119
host: 'smtp.example.com',
120
port: 587,
121
secure: false,
122
auth: {
123
user: 'user@example.com',
124
pass: 'password'
125
},
126
maxConnections: 5,
127
maxMessages: 100
128
});
129
130
// Check if pool is idle
131
if (poolTransporter.isIdle()) {
132
console.log('Transport pool is idle - ready to send emails');
133
} else {
134
console.log('Transport pool is busy');
135
}
136
```
137
138
Monitoring pool status:
139
```javascript
140
function monitorPoolStatus() {
141
setInterval(() => {
142
const isIdle = poolTransporter.isIdle();
143
console.log(`Pool status: ${isIdle ? 'idle' : 'busy'} at ${new Date().toISOString()}`);
144
}, 5000);
145
}
146
147
// Start monitoring
148
monitorPoolStatus();
149
```
150
151
Wait for idle state:
152
```javascript
153
async function waitForIdle(maxWaitMs = 30000) {
154
const startTime = Date.now();
155
156
return new Promise((resolve, reject) => {
157
const checkIdle = () => {
158
if (poolTransporter.isIdle()) {
159
resolve(true);
160
} else if (Date.now() - startTime > maxWaitMs) {
161
reject(new Error('Timeout waiting for idle state'));
162
} else {
163
setTimeout(checkIdle, 100);
164
}
165
};
166
167
checkIdle();
168
});
169
}
170
171
// Usage
172
try {
173
await waitForIdle();
174
console.log('Pool is now idle');
175
} catch (error) {
176
console.error('Pool did not become idle:', error.message);
177
}
178
```
179
180
### Connection Events
181
182
Monitor connection events for debugging and operational awareness.
183
184
```javascript { .api }
185
/**
186
* Connection events emitted by transporter
187
* @event idle - Emitted when transport becomes idle
188
* @event error - Emitted on transport errors
189
* @event clear - Emitted when all connections are cleared
190
*/
191
192
// Event listener methods
193
transporter.on('idle', callback);
194
transporter.on('error', callback);
195
transporter.on('clear', callback);
196
```
197
198
**Usage Examples:**
199
200
Basic event handling:
201
```javascript
202
const transporter = nodemailer.createTransport({
203
pool: true,
204
// ... transport config
205
});
206
207
// Handle idle state
208
transporter.on('idle', () => {
209
console.log('Transporter is idle - all connections available');
210
});
211
212
// Handle errors
213
transporter.on('error', (error) => {
214
console.error('Transport error:', error);
215
216
// Implement error recovery logic
217
if (error.code === 'ECONNRESET') {
218
console.log('Connection reset - will retry automatically');
219
}
220
});
221
222
// Handle connection clearing
223
transporter.on('clear', () => {
224
console.log('All connections have been cleared');
225
});
226
```
227
228
Advanced event monitoring:
229
```javascript
230
class TransportMonitor {
231
constructor(transporter) {
232
this.transporter = transporter;
233
this.stats = {
234
idleEvents: 0,
235
errorEvents: 0,
236
clearEvents: 0,
237
lastError: null,
238
lastIdle: null
239
};
240
241
this.setupEventListeners();
242
}
243
244
setupEventListeners() {
245
this.transporter.on('idle', () => {
246
this.stats.idleEvents++;
247
this.stats.lastIdle = new Date();
248
console.log('Transport idle event #' + this.stats.idleEvents);
249
});
250
251
this.transporter.on('error', (error) => {
252
this.stats.errorEvents++;
253
this.stats.lastError = {
254
error: error,
255
timestamp: new Date()
256
};
257
console.error('Transport error event #' + this.stats.errorEvents + ':', error.message);
258
});
259
260
this.transporter.on('clear', () => {
261
this.stats.clearEvents++;
262
console.log('Transport clear event #' + this.stats.clearEvents);
263
});
264
}
265
266
getStats() {
267
return { ...this.stats };
268
}
269
}
270
271
// Usage
272
const monitor = new TransportMonitor(transporter);
273
274
// Check stats later
275
setTimeout(() => {
276
console.log('Transport statistics:', monitor.getStats());
277
}, 60000);
278
```
279
280
### Connection Cleanup
281
282
Properly close connections and cleanup resources to prevent memory leaks and connection exhaustion.
283
284
```javascript { .api }
285
/**
286
* Closes transport connections and cleans up resources
287
* @returns {void}
288
*/
289
close();
290
```
291
292
**Usage Examples:**
293
294
Basic cleanup:
295
```javascript
296
const transporter = nodemailer.createTransport({
297
pool: true,
298
// ... config
299
});
300
301
// Send some emails...
302
// ...
303
304
// Clean up when done
305
transporter.close();
306
console.log('Transport connections closed');
307
```
308
309
Graceful application shutdown:
310
```javascript
311
const transporter = nodemailer.createTransport({
312
pool: true,
313
// ... config
314
});
315
316
// Graceful shutdown handler
317
process.on('SIGTERM', () => {
318
console.log('Received SIGTERM, shutting down gracefully');
319
320
// Close transport connections
321
transporter.close();
322
323
// Wait briefly for cleanup
324
setTimeout(() => {
325
process.exit(0);
326
}, 1000);
327
});
328
329
process.on('SIGINT', () => {
330
console.log('Received SIGINT, shutting down gracefully');
331
transporter.close();
332
process.exit(0);
333
});
334
```
335
336
Multiple transporters cleanup:
337
```javascript
338
class MailerService {
339
constructor() {
340
this.transporters = new Map();
341
}
342
343
createTransporter(name, config) {
344
const transporter = nodemailer.createTransport(config);
345
this.transporters.set(name, transporter);
346
return transporter;
347
}
348
349
closeAll() {
350
console.log(`Closing ${this.transporters.size} transporters...`);
351
352
for (const [name, transporter] of this.transporters) {
353
console.log(`Closing transporter: ${name}`);
354
transporter.close();
355
}
356
357
this.transporters.clear();
358
console.log('All transporters closed');
359
}
360
}
361
362
// Usage
363
const mailerService = new MailerService();
364
mailerService.createTransporter('primary', primaryConfig);
365
mailerService.createTransporter('backup', backupConfig);
366
367
// Cleanup all at once
368
process.on('exit', () => {
369
mailerService.closeAll();
370
});
371
```
372
373
### Connection Pooling Management
374
375
Advanced pooling configuration and management for high-volume email sending.
376
377
```javascript { .api }
378
/**
379
* Pool configuration options
380
*/
381
interface PoolOptions {
382
pool: true; // Enable pooling
383
maxConnections?: number; // Max concurrent connections (default: 5)
384
maxMessages?: number; // Max messages per connection (default: 100)
385
rateDelta?: number; // Rate limiting window in ms (default: 1000)
386
rateLimit?: number; // Max messages per rate window (default: 0)
387
maxRequeues?: number; // Max requeue attempts on connection failure
388
}
389
```
390
391
**Usage Examples:**
392
393
High-volume pool configuration:
394
```javascript
395
const bulkTransporter = nodemailer.createTransport({
396
pool: true,
397
host: 'bulk-smtp.example.com',
398
port: 587,
399
secure: false,
400
auth: {
401
user: 'bulk@example.com',
402
pass: 'password'
403
},
404
// Pool settings for high volume
405
maxConnections: 20, // 20 concurrent connections
406
maxMessages: 50, // 50 messages per connection
407
rateLimit: 100, // 100 messages per second
408
rateDelta: 1000, // 1 second rate window
409
maxRequeues: 3 // Retry failed messages 3 times
410
});
411
412
// Monitor pool performance
413
bulkTransporter.on('idle', () => {
414
console.log('Bulk pool is idle and ready');
415
});
416
417
// Send bulk emails
418
async function sendBulkEmails(recipients) {
419
const promises = recipients.map(recipient => {
420
return bulkTransporter.sendMail({
421
from: 'bulk@example.com',
422
to: recipient.email,
423
subject: recipient.subject,
424
html: recipient.content
425
});
426
});
427
428
try {
429
const results = await Promise.allSettled(promises);
430
const successful = results.filter(r => r.status === 'fulfilled').length;
431
const failed = results.filter(r => r.status === 'rejected').length;
432
433
console.log(`Bulk send completed: ${successful} successful, ${failed} failed`);
434
return results;
435
} catch (error) {
436
console.error('Bulk send error:', error);
437
throw error;
438
}
439
}
440
```
441
442
Pool health monitoring:
443
```javascript
444
class PoolHealthMonitor {
445
constructor(transporter, checkInterval = 30000) {
446
this.transporter = transporter;
447
this.checkInterval = checkInterval;
448
this.isMonitoring = false;
449
this.healthStats = {
450
checksPerformed: 0,
451
lastCheck: null,
452
consecutiveFailures: 0,
453
isHealthy: true
454
};
455
}
456
457
start() {
458
if (this.isMonitoring) return;
459
460
this.isMonitoring = true;
461
this.monitorInterval = setInterval(() => {
462
this.performHealthCheck();
463
}, this.checkInterval);
464
465
console.log('Pool health monitoring started');
466
}
467
468
stop() {
469
if (this.monitorInterval) {
470
clearInterval(this.monitorInterval);
471
this.isMonitoring = false;
472
console.log('Pool health monitoring stopped');
473
}
474
}
475
476
async performHealthCheck() {
477
this.healthStats.checksPerformed++;
478
this.healthStats.lastCheck = new Date();
479
480
try {
481
const isVerified = await this.transporter.verify();
482
483
if (isVerified) {
484
this.healthStats.consecutiveFailures = 0;
485
this.healthStats.isHealthy = true;
486
console.log('Pool health check: HEALTHY');
487
} else {
488
this.handleHealthCheckFailure(new Error('Verification failed'));
489
}
490
} catch (error) {
491
this.handleHealthCheckFailure(error);
492
}
493
}
494
495
handleHealthCheckFailure(error) {
496
this.healthStats.consecutiveFailures++;
497
498
if (this.healthStats.consecutiveFailures >= 3) {
499
this.healthStats.isHealthy = false;
500
console.error('Pool health check: UNHEALTHY - ' + error.message);
501
502
// Implement recovery actions
503
this.attemptRecovery();
504
} else {
505
console.warn(`Pool health check failed (${this.healthStats.consecutiveFailures}/3): ${error.message}`);
506
}
507
}
508
509
attemptRecovery() {
510
console.log('Attempting pool recovery...');
511
512
// Close and recreate connections
513
this.transporter.close();
514
515
// Wait and retry
516
setTimeout(() => {
517
console.log('Pool recovery attempt completed');
518
}, 5000);
519
}
520
521
getHealthStats() {
522
return { ...this.healthStats };
523
}
524
}
525
526
// Usage
527
const healthMonitor = new PoolHealthMonitor(bulkTransporter);
528
healthMonitor.start();
529
530
// Check health stats periodically
531
setInterval(() => {
532
const stats = healthMonitor.getHealthStats();
533
console.log('Pool health stats:', stats);
534
}, 60000);
535
```