feat: implement comprehensive route-based email routing system

Replace legacy domain-rule based routing with flexible route-based system that supports:
- Multi-criteria matching (recipients, senders, IPs, authentication)
- Four action types (forward, process, deliver, reject)
- Moved DKIM signing to delivery phase for signature validity
- Connection pooling for efficient email forwarding
- Pattern caching for improved performance

This provides more granular control over email routing with priority-based matching and comprehensive test coverage.
This commit is contained in:
2025-05-28 13:23:45 +00:00
parent 88099e120a
commit 2e75961d1c
11 changed files with 717 additions and 168 deletions

View File

@ -6,6 +6,7 @@ import * as paths from './paths.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 type { IEmailRoute } from './mail/routing/interfaces.js';
import { logger } from './logger.js';
// Import the email configuration helpers directly from mail/delivery
import { configureEmailStorage, configureEmailServer } from './mail/delivery/index.js';
@ -326,31 +327,26 @@ export class DcRouter {
emailRoutes.push(routeConfig);
}
// Add domain-specific email routes if configured
if (emailConfig.domainRules) {
for (const rule of emailConfig.domainRules) {
// Extract domain from pattern (e.g., "*@example.com" -> "example.com")
const domain = rule.pattern.split('@')[1];
if (domain && rule.mode === 'forward' && rule.target) {
emailRoutes.push({
name: `email-forward-${domain}`,
match: {
ports: emailConfig.ports,
domains: [domain]
},
action: {
type: 'forward',
target: {
host: rule.target.server,
port: rule.target.port || 25
},
tls: {
mode: rule.target.useTls ? 'terminate-and-reencrypt' : 'passthrough'
}
// Add email routes if configured
if (emailConfig.routes) {
for (const route of emailConfig.routes) {
emailRoutes.push({
name: route.name,
match: {
ports: emailConfig.ports,
domains: route.match.recipients ? [route.match.recipients.toString().split('@')[1]] : []
},
action: {
type: 'forward',
target: route.action.type === 'forward' && route.action.forward ? {
host: route.action.forward.host,
port: route.action.forward.port || 25
} : undefined,
tls: {
mode: 'passthrough'
}
});
}
}
});
}
}
@ -509,21 +505,21 @@ export class DcRouter {
* Update domain rules for email routing
* @param rules New domain rules to apply
*/
public async updateDomainRules(rules: IDomainRule[]): Promise<void> {
public async updateEmailRoutes(routes: IEmailRoute[]): Promise<void> {
// Validate that email config exists
if (!this.options.emailConfig) {
throw new Error('Email configuration is required before updating domain rules');
throw new Error('Email configuration is required before updating routes');
}
// Update the configuration
this.options.emailConfig.domainRules = rules;
this.options.emailConfig.routes = routes;
// Update the unified email server if it exists
if (this.emailServer) {
this.emailServer.updateDomainRules(rules);
this.emailServer.updateRoutes(routes);
}
console.log(`Domain rules updated with ${rules.length} rules`);
console.log(`Email routes updated with ${routes.length} routes`);
}
/**