or run

npx @tessl/cli init
Log in

Version

Tile

Overview

Evals

Files

Files

docs

authentication.mdconnection.mdindex.mdplugins.mdsending.mdtesting.mdtransports.md

connection.mddocs/

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

```