update
This commit is contained in:
124
readme.hints.md
124
readme.hints.md
@@ -452,4 +452,126 @@ External Port → SmartProxy → Internal Port → UnifiedEmailServer → Proces
|
||||
- Use single SmtpClient instance for all outbound mail
|
||||
- Simplify DcRouter to just manage high-level services
|
||||
- Add connection pooling for better performance
|
||||
- See readme.plan.md for detailed implementation plan
|
||||
- See readme.plan.md for detailed implementation plan
|
||||
|
||||
## SMTP Client Management (2025-05-27)
|
||||
|
||||
### Centralized SMTP Client in UnifiedEmailServer
|
||||
- SMTP clients are now managed centrally in UnifiedEmailServer
|
||||
- Uses connection pooling for efficiency (one pool per destination host:port)
|
||||
- Classes using UnifiedEmailServer get SMTP clients via `getSmtpClient(host, port)`
|
||||
|
||||
### Implementation Details
|
||||
```typescript
|
||||
// In UnifiedEmailServer
|
||||
private smtpClients: Map<string, SmtpClient> = new Map(); // host:port -> client
|
||||
|
||||
public getSmtpClient(host: string, port: number = 25): SmtpClient {
|
||||
const clientKey = `${host}:${port}`;
|
||||
let client = this.smtpClients.get(clientKey);
|
||||
|
||||
if (!client) {
|
||||
client = createPooledSmtpClient({
|
||||
host,
|
||||
port,
|
||||
secure: port === 465,
|
||||
connectionTimeout: 30000,
|
||||
socketTimeout: 120000,
|
||||
maxConnections: 10,
|
||||
maxMessages: 1000,
|
||||
pool: true
|
||||
});
|
||||
this.smtpClients.set(clientKey, client);
|
||||
}
|
||||
|
||||
return client;
|
||||
}
|
||||
```
|
||||
|
||||
### Usage Pattern
|
||||
- EmailSendJob and DeliverySystem now use `this.emailServerRef.getSmtpClient(host, port)`
|
||||
- Connection pooling happens automatically
|
||||
- Connections are reused across multiple send jobs
|
||||
- All SMTP clients are closed when UnifiedEmailServer stops
|
||||
|
||||
### Dependency Injection Pattern
|
||||
- Classes that need UnifiedEmailServer functionality receive it as constructor argument
|
||||
- This provides access to SMTP clients, DKIM signing, and other shared functionality
|
||||
- Example: `new EmailSendJob(emailServerRef, email, options)`
|
||||
|
||||
## Email Class Design Pattern (2025-05-27)
|
||||
|
||||
### Three-Interface Pattern for Email
|
||||
The Email system uses three distinct interfaces for clarity and type safety:
|
||||
|
||||
1. **IEmailOptions** - The flexible input interface:
|
||||
```typescript
|
||||
interface IEmailOptions {
|
||||
to: string | string[]; // Flexible: single or array
|
||||
cc?: string | string[]; // Optional
|
||||
attachments?: IAttachment[]; // Optional
|
||||
skipAdvancedValidation?: boolean; // Constructor-only option
|
||||
}
|
||||
```
|
||||
- Used as constructor parameter
|
||||
- Allows flexible input formats
|
||||
- Has constructor-only options (like skipAdvancedValidation)
|
||||
|
||||
2. **INormalizedEmail** - The normalized runtime interface:
|
||||
```typescript
|
||||
interface INormalizedEmail {
|
||||
to: string[]; // Always an array
|
||||
cc: string[]; // Always an array (empty if not provided)
|
||||
attachments: IAttachment[]; // Always an array (empty if not provided)
|
||||
mightBeSpam: boolean; // Always has a value (defaults to false)
|
||||
}
|
||||
```
|
||||
- Represents the guaranteed internal structure
|
||||
- No optional arrays - everything has a default
|
||||
- Email class implements this interface
|
||||
|
||||
3. **Email class** - The implementation:
|
||||
```typescript
|
||||
export class Email implements INormalizedEmail {
|
||||
// All INormalizedEmail properties
|
||||
to: string[];
|
||||
cc: string[];
|
||||
// ... etc
|
||||
|
||||
// Additional runtime properties
|
||||
private messageId: string;
|
||||
private envelopeFrom: string;
|
||||
}
|
||||
```
|
||||
- Implements INormalizedEmail
|
||||
- Adds behavior methods and computed properties
|
||||
- Handles validation and normalization
|
||||
|
||||
### Benefits of This Pattern:
|
||||
- **Type Safety**: Email class explicitly implements INormalizedEmail
|
||||
- **Clear Contracts**: Input vs. runtime structure is explicit
|
||||
- **Flexibility**: IEmailOptions allows various input formats
|
||||
- **Consistency**: INormalizedEmail guarantees structure
|
||||
- **Validation**: Constructor validates and normalizes
|
||||
|
||||
### Usage:
|
||||
```typescript
|
||||
// Input with flexible options
|
||||
const options: IEmailOptions = {
|
||||
from: 'sender@example.com',
|
||||
to: 'recipient@example.com', // Single string
|
||||
subject: 'Hello',
|
||||
text: 'World'
|
||||
};
|
||||
|
||||
// Creates normalized Email instance
|
||||
const email = new Email(options);
|
||||
|
||||
// email.to is guaranteed to be string[]
|
||||
email.to.forEach(recipient => {
|
||||
// No need to check if it's an array
|
||||
});
|
||||
|
||||
// Convert back to options format
|
||||
const optionsAgain = email.toEmailOptions();
|
||||
```
|
Reference in New Issue
Block a user