# @siwats/mxrelay-consumer [![TypeScript](https://img.shields.io/badge/%3C%2F%3E-TypeScript-%230074c1.svg)](http://www.typescriptlang.org/) [![License: MIT](https://img.shields.io/badge/License-MIT-yellow.svg)](https://opensource.org/licenses/MIT) A production-ready TypeScript client library for SMTP over WebSocket protocol with **dedicated SMTP sessions**, automatic reconnection, and comprehensive error handling. Each email gets its own complete SMTP session for maximum protocol compliance and isolation. ## ๐Ÿš€ Key Features ### **Dedicated SMTP Sessions** - **Isolated SMTP Sessions**: One email = One complete SMTP session (EHLO โ†’ AUTH โ†’ Email โ†’ QUIT) - **Session Mutex**: Only one SMTP session active at a time (protocol compliant) - **Maximum Isolation**: Each email in its own session for better error handling - **Resource Optimization**: Connect only when needed, disconnect when idle ### **Intelligent Queue Management** - **Session Queuing**: Each email queued as its own dedicated session - **Priority-Based Processing**: CRITICAL > HIGH > NORMAL > LOW priority levels - **One-to-One Mapping**: One email per SMTP session for maximum isolation - **Smart Resource Usage**: Auto-connect/disconnect based on queue state ### **Production-Ready Reliability** - **Comprehensive Error Handling**: Structured error classification and meaningful messages - **Automatic Reconnection**: Exponential backoff with configurable retry limits - **Timeout Management**: Session, email, and connection-level timeouts - **Connection State Management**: Full lifecycle state tracking ### **Nodemailer Integration** - **Full Nodemailer Compatibility**: Drop-in replacement for existing transports - **Standard API**: Use familiar Nodemailer methods and options - **Advanced Features**: Attachments, HTML, multipart messages, custom headers ## ๐Ÿ“Š Architecture Overview ```mermaid graph TB subgraph "Client Application" App[Your Application] NM[Nodemailer] Transport[SMTPWSTransport] end subgraph "Session Management" Client[SMTPOverWSClient] Queue[Session Queue] SM[Session Manager] end subgraph "Protocol Layer" WS[WebSocket Connection] Auth[Authentication] Channel[SMTP Channel] end subgraph "Remote Server" Relay[SMTP WebSocket Relay] SMTP[SMTP Server] end App --> NM NM --> Transport Transport --> Client Client --> Queue Queue --> SM SM --> WS WS --> Auth Auth --> Channel Channel --> Relay Relay --> SMTP style Client fill:#e1f5fe style Queue fill:#f3e5f5 style SM fill:#fff3e0 style Channel fill:#e8f5e8 ``` ## ๐Ÿ”„ Session Processing Flow ```mermaid sequenceDiagram participant App as Application participant Client as SMTPOverWSClient participant Queue as Session Queue participant WS as WebSocket participant Server as SMTP Server Note over App,Server: Email Submission App->>Client: queueEmail(from, to[], data) Client->>Queue: Add to session or create new Note over App,Server: Session Processing (Mutex) Queue->>Client: Process next session Client->>WS: Connect (if needed) WS->>Server: WebSocket connection Server-->>WS: Connection established Client->>Server: AUTHENTICATE Server-->>Client: AUTH_SUCCESS Client->>Server: SMTP_CHANNEL_OPEN Server-->>Client: SMTP_CHANNEL_READY Server-->>Client: 220 SMTP ready Client->>Server: EHLO client Server-->>Client: 250 EHLO OK Client->>Server: AUTH PLAIN Server-->>Client: 235 AUTH OK Client->>Server: MAIL FROM: Server-->>Client: 250 Sender OK Client->>Server: RCPT TO: Server-->>Client: 250 Recipient OK Client->>Server: DATA Server-->>Client: 354 Start data Client->>Server: \r\n. Server-->>Client: 250 Message accepted Client->>App: Email resolved Client->>Server: QUIT Server-->>Client: 221 Goodbye Client->>Server: SMTP_CHANNEL_CLOSE WS->>WS: Disconnect (if queue empty) Client->>App: Session completed ``` ## ๐Ÿ“ฆ Installation ```bash npm install @siwats/mxrelay-consumer # or bun add @siwats/mxrelay-consumer ``` ## ๐Ÿš€ Quick Start ### Direct Client Usage (New Session-Based API) ```typescript import { SMTPOverWSClient } from '@siwats/mxrelay-consumer'; const client = new SMTPOverWSClient({ url: 'wss://api.siwatsystem.com/smtp', apiKey: 'your-api-key', debug: true, sessionTimeout: 300000 // 5 minute session timeout }); // Queue individual emails - each gets its own dedicated SMTP session try { // Each email will be sent in its own complete SMTP session const emailId1 = await client.queueEmail( 'sender@example.com', ['recipient1@example.com'], 'Subject: Email 1\r\n\r\nFirst email content' ); const emailId2 = await client.queueEmail( 'sender@example.com', ['recipient2@example.com'], 'Subject: Email 2\r\n\r\nSecond email content' ); console.log('Emails queued:', emailId1, emailId2); } catch (error) { console.error('Email error:', error.message); } finally { await client.shutdown(); } ``` ### Nodemailer Transport (Recommended) ```typescript import nodemailer from 'nodemailer'; import { createTransport } from '@siwats/mxrelay-consumer'; // Create transport with dedicated sessions const transport = createTransport('your-api-key', { host: 'api.siwatsystem.com', port: 443, secure: true, debug: true, sessionBatchTimeout: 2000 // Processing delay between sessions }); const transporter = nodemailer.createTransporter(transport); // Send multiple emails - automatically batched into sessions const emails = [ { from: 'sender@example.com', to: 'user1@example.com', subject: 'Welcome Email', html: '

Welcome to our service!

' }, { from: 'sender@example.com', to: 'user2@example.com', subject: 'Newsletter', html: '

Monthly Newsletter

', attachments: [{ filename: 'report.pdf', path: './report.pdf' }] } ]; // Send all emails - each gets its own dedicated SMTP session for (const email of emails) { try { const info = await transporter.sendMail(email); console.log('Email sent:', info.messageId); } catch (error) { console.error('Failed to send email:', error.message); } } await transport.close(); ``` ## โš™๏ธ Configuration ### Client Configuration ```typescript interface SMTPClientConfig { url: string; // WebSocket server URL apiKey: string; // Authentication API key // Session Management sessionTimeout?: number; // Session timeout (default: 300000ms) sessionBatchTimeout?: number; // Processing delay between sessions (default: 1000ms) // Connection Management debug?: boolean; // Enable debug logging (default: false) maxQueueSize?: number; // Session queue limit (default: 100) 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; // SMTP command timeout (default: 60000ms) heartbeatInterval?: number; // Heartbeat interval (default: 30000ms) } ``` ### Transport Configuration ```typescript interface TransportOptions extends Omit { host?: string; // Server host (default: 'api.siwatsystem.com') port?: number; // Server port (default: 443) secure?: boolean; // Use wss:// (default: true) apiKey?: string; // API key for authentication } ``` ## ๐ŸŽฏ Advanced Usage ### Session Priority and Options ```typescript import { MessagePriority, SessionSendOptions } from '@siwats/mxrelay-consumer'; // High priority email (processed first) await client.queueEmail( 'urgent@company.com', ['admin@company.com'], 'Subject: URGENT ALERT\r\n\r\nSystem down!', { priority: MessagePriority.HIGH, timeout: 30000, retries: 5 } ); // Critical priority email (highest priority) await client.queueEmail( 'security@company.com', ['security-team@company.com'], 'Subject: SECURITY BREACH\r\n\r\nImmediate action required!', { priority: MessagePriority.CRITICAL, immediate: true // Send with highest priority } ); ``` ### Session Event Monitoring ```typescript // Session-level events client.on('sessionQueued', (sessionId, queueSize) => { console.log(`Session ${sessionId} queued. Queue size: ${queueSize}`); }); client.on('sessionStarted', (sessionId, emailCount) => { console.log(`Processing session ${sessionId} with ${emailCount} emails`); }); client.on('sessionCompleted', (sessionId, results) => { console.log(`Session ${sessionId} completed with ${results.length} emails`); }); // Email-level events within sessions client.on('emailProcessed', (sessionId, emailId, responseTime) => { console.log(`Email ${emailId} in session ${sessionId} processed in ${responseTime}ms`); }); client.on('emailFailed', (sessionId, emailId, error) => { console.error(`Email ${emailId} in session ${sessionId} failed:`, error.message); }); // Connection events client.on('connected', () => console.log('WebSocket connected')); client.on('authenticated', () => console.log('Authentication successful')); client.on('disconnected', () => console.log('Connection lost')); ``` ### Session Statistics ```typescript const stats = client.getStats(); console.log('Session Statistics:', { sessionsQueued: stats.sessionsQueued, sessionsProcessed: stats.sessionsProcessed, sessionsFailed: stats.sessionsFailed, emailsProcessed: stats.emailsProcessed, emailsFailed: stats.emailsFailed, averageSessionTime: stats.averageSessionTime, averageEmailTime: stats.averageEmailTime, queueSize: stats.queueSize }); console.log('Session State:', client.getSessionState()); // IDLE, PROCESSING, FAILED console.log('Connection State:', client.getConnectionState()); // DISCONNECTED, CONNECTED, etc. ``` ## ๐Ÿ›ก๏ธ Error Handling ### SMTP Session Errors ```typescript try { await client.queueEmail( 'invalid-sender@domain.com', ['recipient@example.com'], 'Subject: Test\r\n\r\nTest message' ); } catch (error) { if (error instanceof MessageError) { console.error('SMTP Error:', error.message); console.log('Email ID:', error.messageId); console.log('Retry Count:', error.retryCount); } } ``` ### Session State Management The client manages session states automatically: ```mermaid stateDiagram-v2 [*] --> IDLE IDLE --> PROCESSING: Session queued PROCESSING --> IDLE: Session completed PROCESSING --> FAILED: Session error FAILED --> PROCESSING: Retry session FAILED --> IDLE: Max retries reached IDLE --> [*]: Client shutdown ``` - `IDLE` - No active session, ready to process - `PROCESSING` - Session currently being processed (mutex locked) - `FAILED` - Session failed, will retry or reject - `COMPLETED` - Session successfully completed ### Connection States ```mermaid stateDiagram-v2 [*] --> DISCONNECTED DISCONNECTED --> CONNECTING: Connect requested CONNECTING --> CONNECTED: WebSocket established CONNECTED --> AUTHENTICATING: Send credentials AUTHENTICATING --> AUTHENTICATED: Auth successful AUTHENTICATED --> CHANNEL_OPENING: Open SMTP channel CHANNEL_OPENING --> CHANNEL_READY: Channel established CHANNEL_READY --> CHANNEL_CLOSED: Session complete CHANNEL_CLOSED --> AUTHENTICATED: Ready for next session AUTHENTICATED --> DISCONNECTED: Queue empty CONNECTING --> RECONNECTING: Connection failed AUTHENTICATING --> RECONNECTING: Auth failed CHANNEL_OPENING --> RECONNECTING: Channel failed RECONNECTING --> CONNECTING: Retry attempt RECONNECTING --> FAILED: Max retries reached FAILED --> [*]: Shutdown DISCONNECTED --> [*]: Shutdown ``` ## ๐Ÿ”ง Session Queue Architecture ```mermaid flowchart TD subgraph Emails ["๐Ÿ“ง Email Submission"] E1[Email 1 - HIGH] E2[Email 2 - NORMAL] E3[Email 3 - HIGH] E4[Email 4 - CRITICAL] end subgraph Queue ["๐Ÿ“‹ Session Creation"] SQ[Session Queue] S1[Session 1 - CRITICAL - Email 4] S2[Session 2 - HIGH - Email 1] S3[Session 3 - HIGH - Email 3] S4[Session 4 - NORMAL - Email 2] end subgraph Processing ["โšก Session Processing"] SP[Session Processor] SC[SMTP Connection] SM[Session Manager] end E1 --> SQ E2 --> SQ E3 --> SQ E4 --> SQ SQ --> S1 SQ --> S2 SQ --> S3 SQ --> S4 S1 --> SP S2 --> SP S3 --> SP S4 --> SP SP --> SC SC --> SM style S1 fill:#ffcdd2 style S2 fill:#fff3e0 style S3 fill:#e8f5e8 style SP fill:#e1f5fe style SC fill:#f3e5f5 ``` ## ๐Ÿญ Production Configuration ### Optimal Settings ```typescript const client = new SMTPOverWSClient({ url: 'wss://api.siwatsystem.com/smtp', apiKey: process.env.MXRELAY_API_KEY, // Production optimizations debug: false, sessionBatchTimeout: 5000, // Longer delay between sessions sessionTimeout: 600000, // 10 minute session timeout maxQueueSize: 1000, // Higher queue capacity reconnectInterval: 15000, // Longer reconnect delay maxReconnectAttempts: 3, // Fewer retries in production messageTimeout: 120000 // 2 minute SMTP timeout }); ``` ### Graceful Shutdown ```typescript process.on('SIGTERM', async () => { console.log('Shutting down SMTP client...'); try { // Wait for current sessions to complete await client.shutdown(60000); // 60 second timeout console.log('SMTP client shutdown complete'); } catch (error) { console.error('Forced SMTP client shutdown'); } process.exit(0); }); ``` ## ๐Ÿ“š API Reference ### SMTPOverWSClient #### Methods - `queueEmail(from, to[], data, options?)` - Queue email for session processing - `getStats()` - Get session and email statistics - `getConnectionState()` - Get current connection state - `getSessionState()` - Get current session processing state - `getQueueSize()` - Get session queue size - `shutdown(timeout?)` - Graceful shutdown with session completion #### Events - **Session Events**: `sessionQueued`, `sessionStarted`, `sessionCompleted`, `sessionFailed` - **Email Events**: `emailProcessed`, `emailFailed` - **Connection Events**: `connecting`, `connected`, `authenticated`, `disconnected`, `reconnecting` - **Queue Events**: `queueProcessingStarted`, `queueProcessingCompleted` - **State Events**: `stateChanged`, `error` ### createTransport(apiKey, options?) Creates a Nodemailer-compatible transport with dedicated SMTP sessions. - `apiKey` - Your API key for authentication - `options` - Optional transport and session configuration ## ๐Ÿ” Debugging ### Enable Debug Logging ```typescript const client = new SMTPOverWSClient({ url: 'wss://api.siwatsystem.com/smtp', apiKey: 'your-api-key', debug: true // Enable comprehensive logging }); // Debug output includes: // - Session creation (one per email) // - SMTP protocol commands and responses // - Connection state transitions // - Queue processing details // - Error stack traces ``` ### Monitor Session Processing ```typescript client.on('sessionStarted', (sessionId, emailCount) => { console.log(`๐Ÿš€ Starting session ${sessionId} with ${emailCount} emails`); }); client.on('emailProcessed', (sessionId, emailId, responseTime) => { console.log(`โœ… Email ${emailId} processed in ${responseTime}ms`); }); client.on('sessionCompleted', (sessionId, results) => { const successful = results.filter(r => r.success).length; const failed = results.filter(r => !r.success).length; console.log(`๐ŸŽ‰ Session ${sessionId} complete: ${successful} sent, ${failed} failed`); }); ``` ## ๐Ÿงช Development ### Setup ```bash # Clone repository git clone https://git.siwatsystem.com/siwatsystem-public/mxrelay-consumer.git cd mxrelay-consumer # Install dependencies bun install # Run examples directly (TypeScript) bun run examples/nodemailer-transport.ts ``` ### Build & Test ```bash # Build all formats bun run build # Run tests bun test # Run linting bun run lint # Format code bun run format ``` ## ๐Ÿ“„ License MIT License - see [LICENSE](LICENSE) file for details. ## ๐Ÿ†˜ Support - **Issues**: [Git Repository Issues](https://git.siwatsystem.com/siwatsystem-public/mxrelay-consumer/issues) - **Documentation**: [Project Repository](https://git.siwatsystem.com/siwatsystem-public/mxrelay-consumer) --- **Built by SiwatSystem** | *Session-based SMTP over WebSocket*