fix(mail options): simplify mail options
This commit is contained in:
parent
2aeb52bf13
commit
6aa54d974e
BIN
readme.plan.md
BIN
readme.plan.md
Binary file not shown.
@ -3,10 +3,9 @@ import * as paths from './paths.js';
|
||||
|
||||
// Certificate types are available via plugins.tsclass
|
||||
|
||||
// Import the consolidated email config
|
||||
import type { IEmailConfig, IDomainRule } from './mail/routing/classes.email.config.js';
|
||||
import type { EmailProcessingMode } from './mail/delivery/interfaces.js';
|
||||
import { UnifiedEmailServer } from './mail/routing/classes.unified.email.server.js';
|
||||
// Import the email server and its configuration
|
||||
import { UnifiedEmailServer, type IUnifiedEmailServerOptions } from './mail/routing/classes.unified.email.server.js';
|
||||
import type { IDomainRule, EmailProcessingMode } from './mail/routing/classes.email.config.js';
|
||||
import { logger } from './logger.js';
|
||||
// Import the email configuration helpers directly from mail/delivery
|
||||
import { configureEmailStorage, configureEmailServer } from './mail/delivery/index.js';
|
||||
@ -19,10 +18,10 @@ export interface IDcRouterOptions {
|
||||
smartProxyConfig?: plugins.smartproxy.ISmartProxyOptions;
|
||||
|
||||
/**
|
||||
* Consolidated email configuration
|
||||
* Email server configuration
|
||||
* This enables all email handling with pattern-based routing
|
||||
*/
|
||||
emailConfig?: IEmailConfig;
|
||||
emailConfig?: IUnifiedEmailServerOptions;
|
||||
|
||||
/**
|
||||
* Custom email port configuration
|
||||
@ -238,7 +237,7 @@ export class DcRouter {
|
||||
/**
|
||||
* Generate SmartProxy routes for email configuration
|
||||
*/
|
||||
private generateEmailRoutes(emailConfig: IEmailConfig): plugins.smartproxy.IRouteConfig[] {
|
||||
private generateEmailRoutes(emailConfig: IUnifiedEmailServerOptions): plugins.smartproxy.IRouteConfig[] {
|
||||
const emailRoutes: plugins.smartproxy.IRouteConfig[] = [];
|
||||
|
||||
// Get the custom port mapping if available, otherwise use defaults
|
||||
@ -442,20 +441,22 @@ export class DcRouter {
|
||||
throw new Error('Email configuration is required for unified email handling');
|
||||
}
|
||||
|
||||
const emailConfig = this.options.emailConfig;
|
||||
// Apply port mapping if behind SmartProxy
|
||||
const portMapping = this.options.emailPortConfig?.portMapping || {
|
||||
25: 10025, // SMTP
|
||||
587: 10587, // Submission
|
||||
465: 10465 // SMTPS
|
||||
};
|
||||
|
||||
// Create unified email server with mapped internal ports
|
||||
this.emailServer = new UnifiedEmailServer(this, {
|
||||
...emailConfig,
|
||||
domains: emailConfig.domains || [], // Provide default empty array
|
||||
ports: emailConfig.ports.map(port => portMapping[port] || port + 10000),
|
||||
// Create config with mapped ports
|
||||
const emailConfig: IUnifiedEmailServerOptions = {
|
||||
...this.options.emailConfig,
|
||||
ports: this.options.emailConfig.ports.map(port => portMapping[port] || port + 10000),
|
||||
hostname: 'localhost' // Listen on localhost for SmartProxy forwarding
|
||||
});
|
||||
};
|
||||
|
||||
// Create unified email server
|
||||
this.emailServer = new UnifiedEmailServer(this, emailConfig);
|
||||
|
||||
// Set up error handling
|
||||
this.emailServer.on('error', (err: Error) => {
|
||||
@ -465,14 +466,14 @@ export class DcRouter {
|
||||
// Start the server
|
||||
await this.emailServer.start();
|
||||
|
||||
logger.log('info', `Email server started on ports: ${this.emailServer['options'].ports.join(', ')}`);
|
||||
logger.log('info', `Email server started on ports: ${emailConfig.ports.join(', ')}`);
|
||||
}
|
||||
|
||||
/**
|
||||
* Update the unified email configuration
|
||||
* @param config New email configuration
|
||||
*/
|
||||
public async updateEmailConfig(config: IEmailConfig): Promise<void> {
|
||||
public async updateEmailConfig(config: IUnifiedEmailServerOptions): Promise<void> {
|
||||
// Stop existing email components
|
||||
await this.stopUnifiedEmailComponents();
|
||||
|
||||
@ -598,7 +599,7 @@ export class DcRouter {
|
||||
}
|
||||
}
|
||||
|
||||
// Re-export types for convenience
|
||||
export type { IEmailConfig, IDomainRule, EmailProcessingMode };
|
||||
// Re-export email server types for convenience
|
||||
export type { IUnifiedEmailServerOptions, IDomainRule, EmailProcessingMode };
|
||||
|
||||
export default DcRouter;
|
||||
|
@ -1,5 +1,37 @@
|
||||
import type { IBaseConfig, ITlsConfig, IQueueConfig, IRateLimitConfig, IMonitoringConfig } from './base.config.js';
|
||||
|
||||
/**
|
||||
* MIGRATION GUIDE:
|
||||
* ================
|
||||
* The IEmailConfig and IMtaConfig interfaces are deprecated.
|
||||
* Please use IUnifiedEmailServerOptions from '../mail/routing/classes.unified.email.server.js' instead.
|
||||
*
|
||||
* Example migration:
|
||||
*
|
||||
* OLD:
|
||||
* ```typescript
|
||||
* const config: IEmailConfig = {
|
||||
* ports: [25, 587],
|
||||
* hostname: 'mail.example.com',
|
||||
* domainRules: [...],
|
||||
* defaultMode: 'forward'
|
||||
* };
|
||||
* ```
|
||||
*
|
||||
* NEW:
|
||||
* ```typescript
|
||||
* const config: IUnifiedEmailServerOptions = {
|
||||
* ports: [25, 587],
|
||||
* hostname: 'mail.example.com',
|
||||
* domains: ['example.com'],
|
||||
* domainRules: [...],
|
||||
* defaultMode: 'forward'
|
||||
* };
|
||||
* ```
|
||||
*
|
||||
* The new interface consolidates all email configuration into a single, cleaner structure.
|
||||
*/
|
||||
|
||||
/**
|
||||
* Email processing modes
|
||||
*/
|
||||
@ -127,6 +159,8 @@ export interface IDomainRule {
|
||||
|
||||
/**
|
||||
* Email service configuration
|
||||
* @deprecated Use IUnifiedEmailServerOptions from mail/routing/classes.unified.email.server.ts instead
|
||||
* This interface is kept for backward compatibility only
|
||||
*/
|
||||
export interface IEmailConfig extends IBaseConfig {
|
||||
/**
|
||||
@ -262,6 +296,8 @@ export interface IEmailConfig extends IBaseConfig {
|
||||
|
||||
/**
|
||||
* MTA configuration
|
||||
* @deprecated Use IUnifiedEmailServerOptions from mail/routing/classes.unified.email.server.ts instead
|
||||
* This interface is kept for backward compatibility only
|
||||
*/
|
||||
export interface IMtaConfig {
|
||||
/**
|
||||
|
194
ts/config/email.port.mapping.ts
Normal file
194
ts/config/email.port.mapping.ts
Normal file
@ -0,0 +1,194 @@
|
||||
/**
|
||||
* Email Port Mapping Configuration
|
||||
*
|
||||
* Centralizes the logic for mapping external email ports to internal ports
|
||||
* when running behind SmartProxy
|
||||
*/
|
||||
|
||||
/**
|
||||
* Default email port mapping
|
||||
* Maps external ports to internal ports for SmartProxy forwarding
|
||||
*/
|
||||
export const DEFAULT_EMAIL_PORT_MAPPING: Record<number, number> = {
|
||||
25: 10025, // SMTP - Standard email delivery port
|
||||
587: 10587, // Submission - Authenticated submission port
|
||||
465: 10465, // SMTPS - Implicit TLS submission port
|
||||
2525: 12525 // Alternative SMTP port (often used for testing)
|
||||
};
|
||||
|
||||
/**
|
||||
* Email port configuration
|
||||
*/
|
||||
export interface IEmailPortConfig {
|
||||
/**
|
||||
* External port number
|
||||
*/
|
||||
external: number;
|
||||
|
||||
/**
|
||||
* Internal port number (where the email server actually listens)
|
||||
*/
|
||||
internal: number;
|
||||
|
||||
/**
|
||||
* Port description
|
||||
*/
|
||||
description: string;
|
||||
|
||||
/**
|
||||
* TLS mode for this port
|
||||
*/
|
||||
tlsMode: 'none' | 'starttls' | 'implicit';
|
||||
|
||||
/**
|
||||
* Whether authentication is required on this port
|
||||
*/
|
||||
requireAuth?: boolean;
|
||||
}
|
||||
|
||||
/**
|
||||
* Standard email port configurations
|
||||
*/
|
||||
export const EMAIL_PORT_CONFIGS: Record<number, Omit<IEmailPortConfig, 'internal'>> = {
|
||||
25: {
|
||||
external: 25,
|
||||
description: 'SMTP - Standard email delivery',
|
||||
tlsMode: 'starttls',
|
||||
requireAuth: false
|
||||
},
|
||||
587: {
|
||||
external: 587,
|
||||
description: 'Submission - Authenticated email submission',
|
||||
tlsMode: 'starttls',
|
||||
requireAuth: true
|
||||
},
|
||||
465: {
|
||||
external: 465,
|
||||
description: 'SMTPS - Implicit TLS submission',
|
||||
tlsMode: 'implicit',
|
||||
requireAuth: true
|
||||
},
|
||||
2525: {
|
||||
external: 2525,
|
||||
description: 'Alternative SMTP - Often used for testing',
|
||||
tlsMode: 'starttls',
|
||||
requireAuth: false
|
||||
}
|
||||
};
|
||||
|
||||
/**
|
||||
* Map external ports to internal ports
|
||||
* @param externalPorts Array of external ports
|
||||
* @param customMapping Optional custom port mapping
|
||||
* @returns Array of internal ports
|
||||
*/
|
||||
export function mapEmailPorts(
|
||||
externalPorts: number[],
|
||||
customMapping?: Record<number, number>
|
||||
): number[] {
|
||||
const mapping = { ...DEFAULT_EMAIL_PORT_MAPPING, ...customMapping };
|
||||
|
||||
return externalPorts.map(port => {
|
||||
// Use custom mapping if available, otherwise add 10000 to the port
|
||||
return mapping[port] || port + 10000;
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* Get full port configuration including internal port mapping
|
||||
* @param externalPort External port number
|
||||
* @param customMapping Optional custom port mapping
|
||||
* @returns Full port configuration
|
||||
*/
|
||||
export function getEmailPortConfig(
|
||||
externalPort: number,
|
||||
customMapping?: Record<number, number>
|
||||
): IEmailPortConfig | undefined {
|
||||
const config = EMAIL_PORT_CONFIGS[externalPort];
|
||||
if (!config) {
|
||||
return undefined;
|
||||
}
|
||||
|
||||
const mapping = { ...DEFAULT_EMAIL_PORT_MAPPING, ...customMapping };
|
||||
const internalPort = mapping[externalPort] || externalPort + 10000;
|
||||
|
||||
return {
|
||||
...config,
|
||||
internal: internalPort
|
||||
};
|
||||
}
|
||||
|
||||
/**
|
||||
* Generate SmartProxy routes for email ports
|
||||
* @param externalPorts Array of external ports to handle
|
||||
* @param hostname Hostname for the email server
|
||||
* @param customMapping Optional custom port mapping
|
||||
* @returns Array of SmartProxy route configurations
|
||||
*/
|
||||
export function generateEmailProxyRoutes(
|
||||
externalPorts: number[],
|
||||
_hostname: string,
|
||||
customMapping?: Record<number, number>
|
||||
): plugins.smartproxy.IRouteConfig[] {
|
||||
const routes: plugins.smartproxy.IRouteConfig[] = [];
|
||||
|
||||
for (const externalPort of externalPorts) {
|
||||
const config = getEmailPortConfig(externalPort, customMapping);
|
||||
if (!config) {
|
||||
continue;
|
||||
}
|
||||
|
||||
// Create route for this email port
|
||||
const route: plugins.smartproxy.IRouteConfig = {
|
||||
name: `email-${config.description.toLowerCase().replace(/\s+/g, '-')}`,
|
||||
match: {
|
||||
ports: [externalPort]
|
||||
},
|
||||
action: {
|
||||
type: 'forward',
|
||||
target: {
|
||||
host: 'localhost',
|
||||
port: config.internal
|
||||
},
|
||||
tls: {
|
||||
// For SMTP/Submission ports, use passthrough to let email server handle STARTTLS
|
||||
// For SMTPS (465), SmartProxy handles TLS termination
|
||||
mode: config.tlsMode === 'implicit' ? 'terminate' : 'passthrough',
|
||||
certificate: config.tlsMode === 'implicit' ? 'auto' : undefined
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
routes.push(route);
|
||||
}
|
||||
|
||||
return routes;
|
||||
}
|
||||
|
||||
/**
|
||||
* Validate email port configuration
|
||||
* @param ports Array of ports to validate
|
||||
* @throws Error if invalid ports are specified
|
||||
*/
|
||||
export function validateEmailPorts(ports: number[]): void {
|
||||
const invalidPorts = ports.filter(port => {
|
||||
// Check if port is a valid number
|
||||
if (!Number.isInteger(port) || port < 1 || port > 65535) {
|
||||
return true;
|
||||
}
|
||||
|
||||
// Warn about non-standard ports
|
||||
if (!EMAIL_PORT_CONFIGS[port]) {
|
||||
console.warn(`Port ${port} is not a standard email port. Supported standard ports are: ${Object.keys(EMAIL_PORT_CONFIGS).join(', ')}`);
|
||||
}
|
||||
|
||||
return false;
|
||||
});
|
||||
|
||||
if (invalidPorts.length > 0) {
|
||||
throw new Error(`Invalid email ports specified: ${invalidPorts.join(', ')}`);
|
||||
}
|
||||
}
|
||||
|
||||
// Type imports to avoid circular dependencies
|
||||
import type * as plugins from '../plugins.js';
|
@ -91,7 +91,7 @@ export type {
|
||||
IPlatformConfig,
|
||||
IEmailConfig,
|
||||
IMtaConfig,
|
||||
ISmsConfig,
|
||||
ISmsConfig,
|
||||
IBaseConfig,
|
||||
ITlsConfig,
|
||||
IHttpServerConfig,
|
||||
|
Loading…
x
Reference in New Issue
Block a user