BREAKING CHANGE(mta): migrate internal MTA to @push.rocks/smartmta and remove legacy mail/deliverability implementation

This commit is contained in:
2026-02-11 16:32:49 +00:00
parent 048f038e36
commit 530ebbf3e4
276 changed files with 1661 additions and 91193 deletions

View File

@@ -3,12 +3,14 @@ import * as paths from './paths.js';
// Certificate types are available via plugins.tsclass
// Import the email server and its configuration
import { UnifiedEmailServer, type IUnifiedEmailServerOptions } from './mail/routing/classes.unified.email.server.js';
import type { IEmailRoute, IEmailDomainConfig } from './mail/routing/interfaces.js';
// Import the email server and its configuration from smartmta
import {
UnifiedEmailServer,
type IUnifiedEmailServerOptions,
type IEmailRoute,
type IEmailDomainConfig,
} from '@push.rocks/smartmta';
import { logger } from './logger.js';
// Import the email configuration helpers directly from mail/delivery
import { configureEmailStorage, configureEmailServer } from './mail/delivery/index.js';
// Import storage manager
import { StorageManager, type IStorageConfig } from './storage/index.js';
// Import cache system
@@ -221,12 +223,6 @@ export class DcRouter {
// Set up unified email handling if configured
if (this.options.emailConfig) {
await this.setupUnifiedEmailHandling();
// Apply custom email storage configuration if available
if (this.emailServer && this.options.emailPortConfig?.receivedEmailsPath) {
logger.log('info', 'Applying custom email storage configuration');
configureEmailStorage(this.emailServer, this.options);
}
}
// Set up DNS server if configured with nameservers and scopes
@@ -533,37 +529,26 @@ export class DcRouter {
break;
}
// Create action based on mode
let action: any;
if (emailConfig.useSocketHandler) {
// Socket-handler mode
action = {
type: 'socket-handler' as any,
socketHandler: this.createMailSocketHandler(port)
};
} else {
// Traditional forwarding mode
const defaultPortMapping = {
25: 10025, // SMTP
587: 10587, // Submission
465: 10465 // SMTPS
};
const portMapping = this.options.emailPortConfig?.portMapping || defaultPortMapping;
const internalPort = portMapping[port] || port + 10000;
action = {
type: 'forward',
target: {
host: 'localhost', // Forward to internal email server
port: internalPort
},
tls: {
mode: tlsMode as any
}
};
}
// Create forward action to route to internal email server ports
const defaultPortMapping: Record<number, number> = {
25: 10025, // SMTP
587: 10587, // Submission
465: 10465 // SMTPS
};
const portMapping = this.options.emailPortConfig?.portMapping || defaultPortMapping;
const internalPort = portMapping[port] || port + 10000;
let action: any = {
type: 'forward',
targets: [{
host: 'localhost', // Forward to internal email server
port: internalPort
}],
tls: {
mode: tlsMode as any
}
};
// For TLS terminate mode, add certificate info
if (tlsMode === 'terminate' && action.tls) {
@@ -845,7 +830,7 @@ export class DcRouter {
// Update the unified email server if it exists
if (this.emailServer) {
this.emailServer.updateRoutes(routes);
this.emailServer.updateEmailRoutes(routes);
}
console.log(`Email routes updated with ${routes.length} routes`);
@@ -862,67 +847,6 @@ export class DcRouter {
return stats;
}
/**
* Configure MTA for email handling with custom port and storage settings
* @param config Configuration for the MTA service
*/
public async configureEmailMta(config: {
internalPort: number;
host?: string;
secure?: boolean;
storagePath?: string;
portMapping?: Record<number, number>;
}): Promise<boolean> {
logger.log('info', 'Configuring MTA service with custom settings');
// Update email port configuration
if (!this.options.emailPortConfig) {
this.options.emailPortConfig = {};
}
// Configure storage paths for received emails
if (config.storagePath) {
// Set the storage path for received emails
this.options.emailPortConfig.receivedEmailsPath = config.storagePath;
}
// Apply port mapping if provided
if (config.portMapping) {
this.options.emailPortConfig.portMapping = {
...this.options.emailPortConfig.portMapping,
...config.portMapping
};
logger.log('info', `Updated MTA port mappings: ${JSON.stringify(this.options.emailPortConfig.portMapping)}`);
}
// Use the dedicated helper to configure the email server
// Pass through the options specified by the implementation
if (this.emailServer) {
configureEmailServer(this.emailServer, {
ports: [config.internalPort], // Use whatever port the implementation specifies
hostname: config.host,
tls: config.secure ? {
// Basic TLS settings if secure mode is enabled
certPath: this.options.tls?.certPath,
keyPath: this.options.tls?.keyPath,
caPath: this.options.tls?.caPath
} : undefined,
storagePath: config.storagePath
});
}
// If email handling is already set up, restart it to apply changes
if (this.emailServer) {
logger.log('info', 'Restarting unified email handling to apply MTA configuration changes');
await this.stopUnifiedEmailComponents();
await this.setupUnifiedEmailHandling();
}
return true;
}
/**
* Register DNS records with the DNS server
* @param records Array of DNS records to register
@@ -1245,8 +1169,8 @@ export class DcRouter {
logger.log('info', 'Initializing DKIM keys for email domains...');
// Get DKIMCreator instance from email server
const dkimCreator = (this.emailServer as any).dkimCreator;
// Get DKIMCreator instance from email server (public in smartmta)
const dkimCreator = this.emailServer.dkimCreator;
if (!dkimCreator) {
logger.log('warn', 'DKIMCreator not available, skipping DKIM initialization');
return;
@@ -1408,51 +1332,6 @@ export class DcRouter {
}
}
/**
* Create mail socket handler for email traffic
*/
private createMailSocketHandler(port: number): (socket: plugins.net.Socket) => Promise<void> {
return async (socket: plugins.net.Socket) => {
if (!this.emailServer) {
logger.log('error', 'Mail socket handler called but email server not initialized');
socket.end();
return;
}
logger.log('debug', `Mail socket handler: handling connection for port ${port}`);
try {
// Port 465 requires immediate TLS
if (port === 465) {
// Wrap the socket in TLS
const tlsOptions = {
isServer: true,
key: this.options.tls?.keyPath ? plugins.fs.readFileSync(this.options.tls.keyPath, 'utf8') : undefined,
cert: this.options.tls?.certPath ? plugins.fs.readFileSync(this.options.tls.certPath, 'utf8') : undefined
};
const tlsSocket = new plugins.tls.TLSSocket(socket, tlsOptions);
tlsSocket.on('secure', () => {
// Pass the secure socket to the email server
this.emailServer!.handleSocket(tlsSocket, port);
});
tlsSocket.on('error', (err) => {
logger.log('error', `TLS handshake error on port ${port}: ${err.message}`);
socket.destroy();
});
} else {
// For ports 25 and 587, pass raw socket (STARTTLS handled by email server)
await this.emailServer.handleSocket(socket, port);
}
} catch (error) {
logger.log('error', `Mail socket handler error on port ${port}: ${error.message}`);
socket.destroy();
}
};
}
/**
* Set up RADIUS server for network authentication
*/