11 KiB
11 KiB
@siwatsystem/mxrelay-consumer
A production-ready TypeScript client library for SMTP over WebSocket protocol with intelligent queue management, automatic reconnection, and comprehensive error handling. Includes full Nodemailer transport compatibility.
Features
Intelligent Queue Management
- Automatic WebSocket connection when messages are queued
- Priority-based message processing (CRITICAL > HIGH > NORMAL > LOW)
- Configurable queue limits and overflow protection
- Auto-disconnect when queue is empty
Robust Connection Handling
- Automatic reconnection with exponential backoff
- Connection state management and lifecycle
- Heartbeat monitoring and timeout handling
- Graceful connection recovery
High Performance
- Efficient SMTP channel cycling per message
- Minimal resource usage with smart connection management
- Concurrent message processing support
- Optimized WebSocket communication
Enterprise-Grade Reliability
- Comprehensive SMTP error handling with meaningful messages
- Timeout management for all operations
- Retry logic with configurable attempts
- Structured error classification
Nodemailer Integration
- Full Nodemailer transport compatibility
- Transparent bridge for all email features
- Support for attachments, HTML, multipart messages
- Standard Nodemailer API compatibility
Installation
npm install @siwatsystem/mxrelay-consumer
# or
bun add @siwatsystem/mxrelay-consumer
Quick Start
Direct Client Usage
import { SMTPOverWSClient } from '@siwatsystem/mxrelay-consumer';
const client = new SMTPOverWSClient({
url: 'wss://api.siwatsystem.com/smtp',
apiKey: 'your-api-key',
debug: true
});
// Send SMTP commands directly
try {
const response = await client.sendSMTPCommand(`
MAIL FROM: <sender@example.com>
RCPT TO: <recipient@example.com>
DATA
Subject: Test Email
Hello from SMTP over WebSocket!
.
QUIT
`);
console.log('Email sent:', response);
} catch (error) {
console.error('SMTP error:', error.message);
} finally {
await client.shutdown();
}
Nodemailer Transport
import nodemailer from 'nodemailer';
import { createTransport } from '@siwatsystem/mxrelay-consumer';
// Create transport (uses defaults: api.siwatsystem.com:443 secure)
const transport = createTransport('your-api-key');
// Or with custom options
const transport = createTransport('your-api-key', {
host: 'custom.server.com',
port: 80,
secure: false,
debug: true
});
const transporter = nodemailer.createTransporter(transport);
// Send email using standard Nodemailer API
const info = await transporter.sendMail({
from: 'sender@example.com',
to: 'recipient@example.com',
subject: 'Test Email via SMTP WebSocket',
text: 'Plain text version',
html: '<h1>HTML version</h1>',
attachments: [
{
filename: 'document.pdf',
path: './document.pdf'
}
]
});
console.log('Message sent:', info.messageId);
await transport.close();
Configuration
Client Configuration
interface SMTPClientConfig {
url: string; // WebSocket server URL
apiKey: string; // Authentication API key
debug?: boolean; // Enable debug logging (default: false)
maxQueueSize?: number; // Queue capacity limit (default: 1000)
reconnectInterval?: number; // Reconnect delay (default: 5000ms)
maxReconnectAttempts?: number; // Max retry attempts (default: 10)
authTimeout?: number; // Auth timeout (default: 30000ms)
channelTimeout?: number; // Channel timeout (default: 10000ms)
messageTimeout?: number; // Message timeout (default: 60000ms)
heartbeatInterval?: number; // Heartbeat interval (default: 30000ms)
maxConcurrentMessages?: number; // Concurrent limit (default: 1)
}
Transport Configuration
interface TransportOptions {
host?: string; // Server host (default: 'api.siwatsystem.com')
port?: number; // Server port (default: 443)
secure?: boolean; // Use wss:// (default: true)
debug?: boolean; // Enable debug mode (default: false)
// ... other SMTPClientConfig options
}
Advanced Usage
Priority-Based Messaging
import { MessagePriority } from '@siwatsystem/mxrelay-consumer';
// High priority (processed first)
await client.sendSMTPCommand('URGENT EMAIL DATA', {
priority: MessagePriority.HIGH,
timeout: 30000
});
// Critical priority (highest)
await client.sendSMTPCommand('CRITICAL ALERT EMAIL', {
priority: MessagePriority.CRITICAL
});
Event Monitoring
// Connection events
client.on('connected', () => console.log('WebSocket connected'));
client.on('authenticated', () => console.log('Authentication successful'));
client.on('disconnected', () => console.log('Connection lost'));
// Queue events
client.on('messageQueued', (messageId, queueSize) => {
console.log(`Message ${messageId} queued. Queue size: ${queueSize}`);
});
client.on('messageProcessed', (messageId, responseTime) => {
console.log(`Message ${messageId} processed in ${responseTime}ms`);
});
// Error events
client.on('error', (error) => console.error('Client error:', error));
Statistics and Monitoring
const stats = client.getStats();
console.log('Client Statistics:', {
messagesQueued: stats.messagesQueued,
messagesProcessed: stats.messagesProcessed,
messagesFailed: stats.messagesFailed,
averageResponseTime: stats.averageResponseTime,
queueSize: stats.queueSize
});
Error Handling
SMTP Error Detection
The transport properly detects and categorizes SMTP errors:
try {
await transporter.sendMail({
from: 'unauthorized@domain.com', // Invalid sender
to: 'recipient@example.com',
subject: 'Test'
});
} catch (error) {
console.error('SMTP Error:', error.message);
// Output: "Sender not authorized: Sender domain not authorized for your IP or subnet"
console.log('Error details:', {
smtpCode: error.context.smtpCode, // "550"
rejectedRecipients: error.context.rejectedRecipients
});
}
Error Classification
import {
ConnectionError,
AuthenticationError,
MessageError,
TimeoutError
} from '@siwatsystem/mxrelay-consumer';
try {
await client.sendSMTPCommand('MAIL FROM: <test@example.com>');
} catch (error) {
if (error instanceof ConnectionError) {
console.error('Connection failed:', error.message);
} else if (error instanceof AuthenticationError) {
console.error('Authentication failed:', error.message);
} else if (error instanceof MessageError) {
console.error('SMTP error:', error.message, 'Code:', error.context.smtpCode);
} else if (error instanceof TimeoutError) {
console.error('Operation timed out:', error.message);
}
}
Connection States
The client manages connection states automatically:
DISCONNECTED
- No connectionCONNECTING
- Establishing WebSocket connectionCONNECTED
- WebSocket connected, authentication pendingAUTHENTICATING
- Sending credentialsAUTHENTICATED
- Ready for SMTP operationsCHANNEL_OPENING
- Opening SMTP channelCHANNEL_READY
- SMTP channel activeCHANNEL_CLOSED
- SMTP channel closedRECONNECTING
- Attempting reconnectionFAILED
- Connection failed, max retries reached
Development
This project uses Bun as the primary runtime. TypeScript files can be run directly without building.
Setup
# Clone repository
git clone https://git.siwatsystem.com/siwat/mxrelay-consumer.git
cd mxrelay-consumer
# Install dependencies
bun install
# Run examples directly
bun run examples/nodemailer-transport.ts
# Run with environment variable
MXRELAY_API_KEY=your-key bun run examples/nodemailer-transport.ts
Build & Test
# Build (optional - bun runs TypeScript directly)
bun run build
# Run tests
bun test
# Run linting
bun run lint
# Format code
bun run format
Protocol Implementation
WebSocket Message Types
AUTHENTICATE
/AUTHENTICATE_RESPONSE
- Authentication flowSMTP_CHANNEL_OPEN
/SMTP_CHANNEL_READY
- Channel managementSMTP_CHANNEL_CLOSED
/SMTP_CHANNEL_ERROR
- Channel lifecycleSMTP_TO_SERVER
/SMTP_FROM_SERVER
- SMTP data exchange
Connection Flow
- WebSocket Connection - Connect to relay server
- Authentication - Authenticate using API key
- Channel Management - Open SMTP channel per message
- Data Transfer - Exchange SMTP commands and responses
- Cleanup - Close channel and disconnect when queue empty
Best Practices
Production Configuration
const client = new SMTPOverWSClient({
url: 'wss://api.siwatsystem.com/smtp',
apiKey: process.env.MXRELAY_API_KEY,
// Production settings
debug: false,
maxQueueSize: 5000,
reconnectInterval: 10000,
maxReconnectAttempts: 5,
messageTimeout: 120000
});
Graceful Shutdown
process.on('SIGTERM', async () => {
console.log('Shutting down...');
try {
await client.shutdown(30000); // 30 second timeout
console.log('Shutdown complete');
} catch (error) {
console.error('Forced shutdown');
}
process.exit(0);
});
API Reference
createTransport(apiKey, options?)
Creates a Nodemailer-compatible transport.
apiKey
- Your API key for authenticationoptions
- Optional transport configuration
SMTPOverWSClient
Main client class for direct SMTP operations.
Methods
sendSMTPCommand(data, options?)
- Send SMTP commandgetStats()
- Get client statisticsgetConnectionState()
- Get current stategetQueueSize()
- Get queue sizeshutdown(timeout?)
- Graceful shutdown
Events
- Connection:
connecting
,connected
,authenticated
,disconnected
- Queue:
messageQueued
,messageProcessed
,messageFailed
- State:
stateChanged
,error
License
MIT License - see LICENSE file for details.
Support
- Issues: Git Repository Issues
- Documentation: Project Repository
Built by SiwatSystem