Documentation Index Fetch the complete documentation index at: https://mintlify.com/puiusabin/bun-smtp/llms.txt
Use this file to discover all available pages before exploring further.
Quickstart
Get your first SMTP server running with bun-smtp in just a few steps.
Installation
Install bun-smtp
Add bun-smtp to your project: Make sure you have Bun 1.2.0 or higher installed. Check your version with bun --version.
Create your server file
Create a new file called server.ts: import { SMTPServer } from "bun-smtp" ;
const server = new SMTPServer ({
authOptional: true ,
onData ( stream , session , callback ) {
async function drain () {
const chunks : Uint8Array [] = [];
for await ( const chunk of stream ) {
chunks . push ( chunk );
}
console . log ( `Received ${ chunks . length } chunks from ${ session . envelope . mailFrom ?. address } ` );
callback ( null );
}
drain (). catch ( callback );
},
});
await server . listen ( 2525 );
console . log ( "SMTP server listening on port 2525" );
This example sets authOptional: true to accept unauthenticated connections. In production, you should implement proper authentication.
Run your server
Start the server with Bun: You should see: SMTP server listening on port 2525
Test your server
Test your server using curl or telnet. Here’s an example using curl: curl --url 'smtp://localhost:2525' \
--mail-from 'sender@example.com' \
--mail-rcpt 'recipient@example.com' \
--upload-file - << EOF
From: sender@example.com
To: recipient@example.com
Subject: Test Email
This is a test message.
EOF
Your server should log the received chunks.
Understanding the Code
Let’s break down what’s happening in the example:
SMTPServer Options
const server = new SMTPServer ({
authOptional: true , // Allow connections without authentication
onData ( stream , session , callback ) {
// Handle incoming email data
},
});
The SMTPServer constructor accepts various options. The most important ones for getting started are:
authOptional : Set to true to allow unauthenticated connections
onData : Callback invoked when email data is ready to be processed
The onData Callback
onData ( stream , session , callback ) {
async function drain () {
const chunks : Uint8Array [] = [];
for await ( const chunk of stream ) {
chunks . push ( chunk );
}
callback ( null ); // Signal success
}
drain (). catch ( callback ); // Handle errors
}
The onData callback receives:
stream : A ReadableStream<Uint8Array> containing the email data
session : An SMTPSession object with connection and envelope information
callback : Call this with null on success, or an error object on failure
The stream must be consumed before calling the callback. Use a for await loop to read all chunks.
Starting the Server
await server . listen ( 2525 );
The listen() method starts the server on the specified port. It returns a Promise that resolves when the server is ready.
Next Steps
Now that you have a basic server running, you can:
Add Authentication Secure your server with SASL authentication
Enable TLS Encrypt connections with STARTTLS or implicit TLS
Handle Messages Save emails to a database or forward them
Configure Options Explore all available server options
Common Patterns
Save Email to File
import { SMTPServer } from "bun-smtp" ;
import { join } from "path" ;
const server = new SMTPServer ({
authOptional: true ,
onData ( stream , session , callback ) {
async function saveEmail () {
const chunks : Uint8Array [] = [];
for await ( const chunk of stream ) {
chunks . push ( chunk );
}
const buffer = Buffer . concat ( chunks );
const filename = ` ${ session . id } - ${ Date . now () } .eml` ;
await Bun . write ( join ( "./emails" , filename ), buffer );
callback ( null );
}
saveEmail (). catch ( callback );
},
});
await server . listen ( 2525 );
import { SMTPServer } from "bun-smtp" ;
const server = new SMTPServer ({
authOptional: true ,
onMailFrom ( address , session , callback ) {
console . log ( `Mail from: ${ address . address } ` );
callback (); // Accept the sender
},
onRcptTo ( address , session , callback ) {
console . log ( `Recipient: ${ address . address } ` );
callback (); // Accept the recipient
},
onData ( stream , session , callback ) {
async function drain () {
const chunks : Uint8Array [] = [];
for await ( const chunk of stream ) {
chunks . push ( chunk );
}
console . log ( `Envelope:` , {
from: session . envelope . mailFrom ?. address ,
to: session . envelope . rcptTo . map ( r => r . address ),
});
callback ( null );
}
drain (). catch ( callback );
},
});
await server . listen ( 2525 );
Reject Invalid Senders
import { SMTPServer } from "bun-smtp" ;
import type { SMTPError } from "bun-smtp" ;
const server = new SMTPServer ({
authOptional: true ,
onMailFrom ( address , session , callback ) {
const allowedDomain = "example.com" ;
if ( ! address . address . endsWith ( `@ ${ allowedDomain } ` )) {
const error = new Error ( "Invalid sender domain" ) as SMTPError ;
error . responseCode = 550 ;
return callback ( error );
}
callback (); // Accept the sender
},
onData ( stream , session , callback ) {
async function drain () {
const chunks : Uint8Array [] = [];
for await ( const chunk of stream ) {
chunks . push ( chunk );
}
callback ( null );
}
drain (). catch ( callback );
},
});
await server . listen ( 2525 );
Always validate and sanitize email addresses and data before processing them to prevent security vulnerabilities.