Skip to main content
Handler methods are callbacks that process SMTP commands and connection events. They can be defined either as options in the constructor or as instance methods.

onConnect

Called when a new client connection is established, before the greeting is sent.

Signature

onConnect(session, callback)

Parameters

session
Object
Session object containing connection information
callback
Function
Callback function (err). Call with an Error to reject the connection.

Example

const server = new SMTPServer({
  onConnect(session, callback) {
    // Reject connections from specific IP
    if (session.remoteAddress === '192.0.2.1') {
      const err = new Error('Connection not allowed');
      err.responseCode = 421;
      return callback(err);
    }
    callback();
  }
});
The default implementation calls callback() immediately.

onSecure

Called after a TLS connection is established (either via STARTTLS or direct TLS).

Signature

onSecure(socket, session, callback)

Parameters

socket
tls.TLSSocket
The TLS socket object
session
Object
Session object with TLS information
callback
Function
Callback function (err). Call with an Error to close the connection.

Example

const server = new SMTPServer({
  onSecure(socket, session, callback) {
    // Verify client certificate
    const cert = socket.getPeerCertificate();
    
    if (!cert || !cert.subject) {
      return callback(new Error('Client certificate required'));
    }
    
    console.log('Client cert:', cert.subject.CN);
    callback();
  }
});
The default implementation calls callback() immediately.

onAuth

Called when a client attempts authentication.

Signature

onAuth(auth, session, callback)

Parameters

auth
Object
Authentication object containing:
session
Object
callback
Function
Callback function (err, response).
  • On success: callback(null, { user: userData })
  • On failure: callback(new Error('Authentication failed'))

Response Object

user
Any
User data to store in session.user. Can be username, user ID, or user object.
data
Object
For XOAUTH2: Object with status, schemes, and scope properties for continuation.
message
String
Custom error message to return to client.

Examples

const server = new SMTPServer({
  onAuth(auth, session, callback) {
    const validUser = 'admin';
    const validPass = 'secret';
    
    if (auth.username !== validUser || auth.password !== validPass) {
      return callback(new Error('Invalid credentials'));
    }
    
    callback(null, { user: auth.username });
  }
});
The default implementation rejects all authentication attempts. You must implement this handler to enable authentication.

onMailFrom

Called for the MAIL FROM command to validate the sender address.

Signature

onMailFrom(address, session, callback)

Parameters

address
Object
Address object containing:
session
Object
callback
Function
Callback function (err). Call with an Error to reject the sender.

Error Properties

responseCode
Number
SMTP response code (e.g., 550 for permanent failure, 450 for temporary)

Examples

const server = new SMTPServer({
  onMailFrom(address, session, callback) {
    const blockedDomains = ['spam.com', 'blocked.net'];
    const domain = address.address.split('@')[1];
    
    if (blockedDomains.includes(domain)) {
      const err = new Error('Domain not allowed');
      err.responseCode = 550;
      return callback(err);
    }
    
    callback();
  }
});
The default implementation accepts all sender addresses.

onRcptTo

Called for the RCPT TO command to validate each recipient address.

Signature

onRcptTo(address, session, callback)

Parameters

address
Object
Address object (same structure as onMailFrom)
session
Object
Session object including session.envelope.mailFrom
callback
Function
Callback function (err). Call with an Error to reject the recipient.

Examples

const server = new SMTPServer({
  onRcptTo(address, session, callback) {
    const localDomains = ['example.com', 'example.net'];
    const domain = address.address.split('@')[1];
    
    if (!localDomains.includes(domain)) {
      return callback(new Error('Relay not permitted'));
    }
    
    callback();
  }
});
The default implementation accepts all recipient addresses.

onData

Called for the DATA command to process the message content.

Signature

onData(stream, session, callback)

Parameters

stream
Stream
Readable stream of the message content
session
Object
Session object with complete envelope information
callback
Function
Callback function (err, message). Call when message processing is complete.
  • err: Error object if processing failed
  • message: Success message string (or array for LMTP)

Examples

const fs = require('fs');
const path = require('path');

const server = new SMTPServer({
  onData(stream, session, callback) {
    const fileName = path.join('/tmp', session.id + '.eml');
    const writeStream = fs.createWriteStream(fileName);
    
    stream.pipe(writeStream);
    
    stream.on('end', () => {
      if (stream.sizeExceeded) {
        const err = new Error('Message too large');
        err.responseCode = 552;
        return callback(err);
      }
      
      callback(null, 'Message saved: ' + session.id);
    });
    
    writeStream.on('error', callback);
  }
});
You must consume the stream (by piping or reading) to prevent memory leaks. The default implementation discards the message.

onClose

Called when a connection is closed.

Signature

onClose(session)

Parameters

session
Object
Session object for the closed connection
This method does not take a callback and is called asynchronously.

Example

const server = new SMTPServer({
  onClose(session) {
    console.log('Connection closed:', session.id);
    
    // Clean up session-specific resources
    if (session.user) {
      logUserDisconnect(session.user);
    }
  }
});
The default implementation does nothing.

See Also

Build docs developers (and LLMs) love