No description
- Added error classes for various SMTP-related issues (ConnectionError, AuthenticationError, etc.) in `errors.ts`. - Created main entry point for the SMTP over WebSocket client library in `index.ts`, exporting client, types, errors, and transport. - Developed Nodemailer transport adapter for SMTP over WebSocket in `transport.ts`, including methods for sending mail and verifying transport configuration. - Defined type definitions for the SMTP over WebSocket protocol in `types.ts`, including message types, connection states, and client configuration options. |
||
---|---|---|
.claude | ||
examples | ||
src | ||
tests | ||
workflows | ||
.eslintrc.js | ||
.gitignore | ||
.prettierrc | ||
CLAUDE.md | ||
jest.config.js | ||
LICENSE | ||
package-lock.json | ||
package.json | ||
README.md | ||
tsconfig.cjs.json | ||
tsconfig.esm.json | ||
tsconfig.json | ||
tsconfig.types.json |
@siwatsystem/smtp-ws-relay-client
A production-ready TypeScript client library for SMTP over WebSocket protocol with intelligent queue management, automatic reconnection, and comprehensive error handling.
Features
🚀 Intelligent Queue Management
- Automatic WebSocket connection when messages are queued
- Priority-based message processing
- Configurable batch processing
- Queue size limits and overflow protection
🔄 Robust Connection Handling
- Automatic reconnection with exponential backoff
- Connection state management
- Heartbeat monitoring
- Graceful connection lifecycle
⚡ High Performance
- Efficient SMTP channel cycling
- Concurrent message processing support
- Optimized resource usage
- Minimal memory footprint
🛡️ Enterprise-Grade Reliability
- Comprehensive error handling and classification
- Timeout management for all operations
- Retry logic with configurable attempts
- Graceful degradation and recovery
📊 Monitoring & Observability
- Real-time statistics and metrics
- Structured logging with configurable levels
- Event-driven architecture for monitoring
- Performance tracking and analytics
Installation
npm install @siwatsystem/smtp-ws-relay-client
Quick Start
import { SMTPOverWSClient, MessagePriority } from '@siwatsystem/smtp-ws-relay-client';
// Create client instance
const client = new SMTPOverWSClient({
url: 'ws://your-smtp-relay-server:3000/smtp',
apiKey: 'your-api-key',
debug: true
});
// Send SMTP commands
try {
const response1 = await client.sendSMTPCommand('EHLO example.com\\r\\n');
const response2 = await client.sendSMTPCommand('MAIL FROM: <test@example.com>\\r\\n');
const response3 = await client.sendSMTPCommand('RCPT TO: <recipient@example.com>\\r\\n');
console.log('SMTP responses:', [response1, response2, response3]);
} catch (error) {
console.error('SMTP error:', error);
}
// Graceful shutdown
await client.shutdown();
Configuration Options
interface SMTPClientConfig {
/** WebSocket server URL */
url: string;
/** API key for authentication */
apiKey: string;
/** Interval between reconnection attempts (default: 5000ms) */
reconnectInterval?: number;
/** Maximum reconnection attempts (default: 10) */
maxReconnectAttempts?: number;
/** Authentication timeout (default: 30000ms) */
authTimeout?: number;
/** Channel operation timeout (default: 10000ms) */
channelTimeout?: number;
/** Message timeout (default: 60000ms) */
messageTimeout?: number;
/** Maximum concurrent messages (default: 1) */
maxConcurrentMessages?: number;
/** Enable debug logging (default: false) */
debug?: boolean;
/** Custom logger implementation */
logger?: Logger;
/** Connection heartbeat interval (default: 30000ms) */
heartbeatInterval?: number;
/** Queue processing batch size (default: 10) */
batchSize?: number;
/** Maximum queue size (default: 1000) */
maxQueueSize?: number;
}
Advanced Usage
Priority-Based Message Queuing
import { MessagePriority } from '@siwatsystem/smtp-ws-relay-client';
// High priority message (processed first)
await client.sendSMTPCommand('URGENT EMAIL DATA\\r\\n', {
priority: MessagePriority.HIGH,
timeout: 30000
});
// Normal priority message
await client.sendSMTPCommand('NORMAL EMAIL DATA\\r\\n', {
priority: MessagePriority.NORMAL
});
// Low priority message (processed last)
await client.sendSMTPCommand('NEWSLETTER DATA\\r\\n', {
priority: MessagePriority.LOW
});
Event Monitoring
// Connection events
client.on('connected', () => {
console.log('WebSocket connected');
});
client.on('authenticated', () => {
console.log('Authentication successful');
});
client.on('disconnected', (reason) => {
console.log('Disconnected:', reason);
});
// 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`);
});
client.on('queueProcessingStarted', (queueSize) => {
console.log(`Processing ${queueSize} queued messages`);
});
// Error events
client.on('error', (error) => {
console.error('Client error:', error);
});
client.on('messageFailed', (messageId, error) => {
console.error(`Message ${messageId} failed:`, error);
});
Statistics and Monitoring
// Get real-time statistics
const stats = client.getStats();
console.log('Client Statistics:', {
messagesQueued: stats.messagesQueued,
messagesProcessed: stats.messagesProcessed,
messagesFailed: stats.messagesFailed,
averageResponseTime: stats.averageResponseTime,
connectionUptime: stats.connectionUptime,
queueSize: stats.queueSize
});
// Monitor connection state
console.log('Current state:', client.getConnectionState());
console.log('Queue size:', client.getQueueSize());
Custom Logger
import { Logger } from '@siwatsystem/smtp-ws-relay-client';
class CustomLogger implements Logger {
debug(message: string, ...args: any[]): void {
// Send to your logging service
console.debug(`[DEBUG] ${message}`, ...args);
}
info(message: string, ...args: any[]): void {
console.info(`[INFO] ${message}`, ...args);
}
warn(message: string, ...args: any[]): void {
console.warn(`[WARN] ${message}`, ...args);
}
error(message: string, ...args: any[]): void {
console.error(`[ERROR] ${message}`, ...args);
}
}
const client = new SMTPOverWSClient({
url: 'ws://localhost:3000/smtp',
apiKey: 'your-api-key',
logger: new CustomLogger()
});
Error Handling
The library provides comprehensive error classification:
import {
ConnectionError,
AuthenticationError,
ChannelError,
TimeoutError,
QueueError,
MessageError
} from '@siwatsystem/smtp-ws-relay-client';
try {
await client.sendSMTPCommand('EHLO example.com\\r\\n');
} 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 TimeoutError) {
console.error('Operation timed out:', error.message);
} else if (error instanceof QueueError) {
console.error('Queue error:', error.message);
} else if (error instanceof MessageError) {
console.error('Message processing failed:', error.message);
}
}
Connection States
The client manages several connection states:
DISCONNECTED
- No connection to serverCONNECTING
- Establishing WebSocket connectionCONNECTED
- WebSocket connected, authentication pendingAUTHENTICATING
- Sending authentication credentialsAUTHENTICATED
- Ready to open SMTP channelsCHANNEL_OPENING
- Opening SMTP channelCHANNEL_READY
- SMTP channel active, ready for dataCHANNEL_CLOSED
- SMTP channel closedCHANNEL_ERROR
- SMTP channel error occurredRECONNECTING
- Attempting to reconnectFAILED
- Connection failed, max retries reached
Protocol Support
This client implements the SMTP over WebSocket protocol specification:
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
- Data transfer
Connection Flow
- WebSocket Connection - Establish WebSocket to relay server
- Authentication - Authenticate using API key
- Channel Management - Open/close SMTP channels per message
- Data Transfer - Exchange SMTP commands and responses
- Cleanup - Close channels and connection when queue empty
Performance Considerations
Queue Management
- Messages are processed in priority order
- Batch processing reduces connection overhead
- Automatic queue size management prevents memory issues
Connection Efficiency
- Single WebSocket connection handles multiple SMTP sessions
- Intelligent connect/disconnect based on queue state
- Connection pooling and reuse optimization
Memory Usage
- Efficient message queuing with cleanup
- Automatic resource management
- Configurable limits and timeouts
Best Practices
Production Configuration
const client = new SMTPOverWSClient({
url: 'ws://your-production-server/smtp',
apiKey: process.env.SMTP_RELAY_API_KEY!,
// Connection settings
reconnectInterval: 10000,
maxReconnectAttempts: 5,
heartbeatInterval: 30000,
// Timeouts
authTimeout: 30000,
channelTimeout: 15000,
messageTimeout: 120000,
// Queue settings
maxQueueSize: 5000,
batchSize: 50,
// Monitoring
debug: false,
logger: new ProductionLogger()
});
Error Recovery
client.on('error', async (error) => {
// Log error to monitoring system
logger.error('SMTP client error', { error: error.toJSON() });
// Implement circuit breaker pattern
if (error instanceof ConnectionError && consecutiveErrors > 10) {
await client.shutdown();
// Implement fallback mechanism
}
});
Graceful Shutdown
process.on('SIGTERM', async () => {
console.log('Shutting down SMTP client...');
try {
await client.shutdown(30000); // 30 second timeout
console.log('SMTP client shutdown complete');
} catch (error) {
console.error('Forced shutdown due to timeout');
}
process.exit(0);
});
Development
Building from Source
# Clone repository
git clone https://github.com/siwatsystem/smtp-ws-relay-client.git
cd smtp-ws-relay-client
# Install dependencies
npm install
# Build library
npm run build
# Run tests
npm test
# Run examples
npm run example:basic
Testing
# Run all tests
npm test
# Run with coverage
npm run test:coverage
# Watch mode
npm run test:watch
API Reference
SMTPOverWSClient
Constructor
new SMTPOverWSClient(config: SMTPClientConfig)
Methods
sendSMTPCommand(data: string, options?: SendOptions): Promise<string>
getStats(): ClientStats
getConnectionState(): ConnectionState
getQueueSize(): number
clearQueue(): void
shutdown(timeout?: number): Promise<void>
Events
connecting
,connected
,authenticated
,disconnected
reconnecting
,reconnected
,error
messageQueued
,messageProcessed
,messageFailed
queueProcessingStarted
,queueProcessingCompleted
channelOpened
,channelClosed
,channelError
stateChanged
Contributing
We welcome contributions! Please see our Contributing Guidelines for details.
- Fork the repository
- Create a feature branch (
git checkout -b feature/amazing-feature
) - Commit your changes (
git commit -m 'Add amazing feature'
) - Push to the branch (
git push origin feature/amazing-feature
) - Open a Pull Request
License
This project is licensed under the MIT License - see the LICENSE file for details.
Support
- 📧 Email: support@siwatsystem.com
- 🐛 Issues: GitHub Issues
- 📖 Documentation: API Docs
Changelog
See CHANGELOG.md for version history and updates.
Built with ❤️ by SiwatSystem