Skip to main content
The SMTPServer class extends EventEmitter and emits events for connection lifecycle and errors. You can listen to these events to monitor server activity, implement logging, or integrate with external systems.

Listening to Events

const { SMTPServer } = require('smtp-server');

const server = new SMTPServer({ /* options */ });

server.on('connect', data => {
  console.log('New connection:', data);
});

server.on('error', err => {
  console.error('Server error:', err);
});

server.on('close', () => {
  console.log('Server closed');
});

Events

connect

Emitted when a new client connection is established and ready to proceed (after HELO/EHLO or XCLIENT/XFORWARD).
This event is emitted after the connection is validated, not immediately when the socket connects. Use the onConnect handler for early connection control.

Event Data

id
String
required
Unique connection identifier
localAddress
String
Server IP address
localPort
Number
Server port number
remoteAddress
String
Client IP address
remotePort
Number
Client port number
hostNameAppearsAs
String
Hostname provided by client in HELO/EHLO
clientHostname
String
Client hostname from reverse DNS or [IP]

Example

server.on('connect', data => {
  console.log(`[${data.id}] Connection from ${data.remoteAddress}:${data.remotePort}`);
  console.log(`[${data.id}] Client hostname: ${data.clientHostname}`);
  console.log(`[${data.id}] Identified as: ${data.hostNameAppearsAs}`);
});

error

Emitted when an error occurs with the server or a connection.
You should always listen to the error event. Unhandled error events can crash your application.

Event Data

error
Error
required
Error object with the following properties:

Example

server.on('error', err => {
  console.error('SMTP Server Error:', err.message);
  
  if (err.code === 'EADDRINUSE') {
    console.error('Port already in use!');
    process.exit(1);
  }
});

close

Emitted when the server is closed and no longer accepting connections.
This event is emitted after all connections have been closed and the server has fully shut down.

Event Data

This event has no data payload.

Example

server.on('close', () => {
  console.log('SMTP server has been shut down');
  
  // Clean up resources
  database.disconnect();
  cache.close();
  
  console.log('All resources cleaned up');
});

// Initiate shutdown
process.on('SIGTERM', () => {
  console.log('Received SIGTERM, closing server...');
  server.close();
});

Complete Example

Here’s a comprehensive example using all events:
const { SMTPServer } = require('smtp-server');

// Connection tracking
const connections = new Map();
let totalConnections = 0;
let totalErrors = 0;

const server = new SMTPServer({
  logger: true,
  
  onAuth(auth, session, callback) {
    // Implement authentication
    callback(null, { user: auth.username });
  },
  
  onData(stream, session, callback) {
    stream.on('end', () => {
      callback(null, 'Message queued');
    });
  }
});

// Track new connections
server.on('connect', data => {
  totalConnections++;
  connections.set(data.id, {
    remoteAddress: data.remoteAddress,
    hostname: data.clientHostname,
    connectedAt: new Date(),
    authenticated: false
  });
  
  console.log(`[CONNECT] ${data.id} from ${data.remoteAddress}`);
  console.log(`Active: ${connections.size}, Total: ${totalConnections}`);
});

// Handle errors
server.on('error', err => {
  totalErrors++;
  
  if (err.remoteAddress) {
    console.error(`[ERROR] ${err.remoteAddress}: ${err.message}`);
  } else {
    console.error(`[ERROR] Server: ${err.message}`);
  }
  
  // Alert on high error rate
  if (totalErrors > 100) {
    console.error('[ALERT] High error rate detected!');
  }
});

// Handle server close
server.on('close', () => {
  console.log('[CLOSE] Server shut down');
  console.log(`Final stats - Total connections: ${totalConnections}, Errors: ${totalErrors}`);
  connections.clear();
});

// Start server
server.listen(2525, () => {
  console.log('SMTP server listening on port 2525');
});

// Graceful shutdown
process.on('SIGTERM', () => {
  console.log('Shutting down gracefully...');
  server.close(() => {
    process.exit(0);
  });
});

Event Timing

Events are emitted in this typical order:
  1. connect - After client completes HELO/EHLO (or XCLIENT/XFORWARD if enabled)
  2. error - Whenever an error occurs (can happen at any time)
  3. close - When server.close() completes
The connect event may be delayed if useXClient or useXForward options are enabled, as the server waits for these commands before emitting the event.

See Also

Build docs developers (and LLMs) love