391 lines
No EOL
11 KiB
Markdown
391 lines
No EOL
11 KiB
Markdown
# @siwatsystem/mxrelay-consumer
|
|
|
|
[](http://www.typescriptlang.org/)
|
|
[](https://opensource.org/licenses/MIT)
|
|
|
|
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
|
|
|
|
```bash
|
|
npm install @siwatsystem/mxrelay-consumer
|
|
# or
|
|
bun add @siwatsystem/mxrelay-consumer
|
|
```
|
|
|
|
## Quick Start
|
|
|
|
### Direct Client Usage
|
|
|
|
```typescript
|
|
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
|
|
|
|
```typescript
|
|
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
|
|
|
|
```typescript
|
|
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
|
|
|
|
```typescript
|
|
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
|
|
|
|
```typescript
|
|
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
|
|
|
|
```typescript
|
|
// 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
|
|
|
|
```typescript
|
|
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:
|
|
|
|
```typescript
|
|
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
|
|
|
|
```typescript
|
|
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 connection
|
|
- `CONNECTING` - Establishing WebSocket connection
|
|
- `CONNECTED` - WebSocket connected, authentication pending
|
|
- `AUTHENTICATING` - Sending credentials
|
|
- `AUTHENTICATED` - Ready for SMTP operations
|
|
- `CHANNEL_OPENING` - Opening SMTP channel
|
|
- `CHANNEL_READY` - SMTP channel active
|
|
- `CHANNEL_CLOSED` - SMTP channel closed
|
|
- `RECONNECTING` - Attempting reconnection
|
|
- `FAILED` - Connection failed, max retries reached
|
|
|
|
## Development
|
|
|
|
This project uses Bun as the primary runtime. TypeScript files can be run directly without building.
|
|
|
|
### Setup
|
|
|
|
```bash
|
|
# 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
|
|
|
|
```bash
|
|
# 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 flow
|
|
- `SMTP_CHANNEL_OPEN` / `SMTP_CHANNEL_READY` - Channel management
|
|
- `SMTP_CHANNEL_CLOSED` / `SMTP_CHANNEL_ERROR` - Channel lifecycle
|
|
- `SMTP_TO_SERVER` / `SMTP_FROM_SERVER` - SMTP data exchange
|
|
|
|
### Connection Flow
|
|
|
|
1. **WebSocket Connection** - Connect to relay server
|
|
2. **Authentication** - Authenticate using API key
|
|
3. **Channel Management** - Open SMTP channel per message
|
|
4. **Data Transfer** - Exchange SMTP commands and responses
|
|
5. **Cleanup** - Close channel and disconnect when queue empty
|
|
|
|
## Best Practices
|
|
|
|
### Production Configuration
|
|
|
|
```typescript
|
|
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
|
|
|
|
```typescript
|
|
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 authentication
|
|
- `options` - Optional transport configuration
|
|
|
|
### SMTPOverWSClient
|
|
|
|
Main client class for direct SMTP operations.
|
|
|
|
#### Methods
|
|
- `sendSMTPCommand(data, options?)` - Send SMTP command
|
|
- `getStats()` - Get client statistics
|
|
- `getConnectionState()` - Get current state
|
|
- `getQueueSize()` - Get queue size
|
|
- `shutdown(timeout?)` - Graceful shutdown
|
|
|
|
#### Events
|
|
- Connection: `connecting`, `connected`, `authenticated`, `disconnected`
|
|
- Queue: `messageQueued`, `messageProcessed`, `messageFailed`
|
|
- State: `stateChanged`, `error`
|
|
|
|
## License
|
|
|
|
MIT License - see [LICENSE](LICENSE) file for details.
|
|
|
|
## Support
|
|
|
|
- Issues: [Git Repository Issues](https://git.siwatsystem.com/siwat/mxrelay-consumer/issues)
|
|
- Documentation: [Project Repository](https://git.siwatsystem.com/siwat/mxrelay-consumer)
|
|
|
|
---
|
|
|
|
Built by SiwatSystem |