This commit is contained in:
2025-05-20 19:46:59 +00:00
parent f3f06ed06d
commit f37cddf26d
18 changed files with 338 additions and 553 deletions

View File

@ -0,0 +1,71 @@
import * as plugins from '../../plugins.js';
import * as paths from '../../paths.js';
import type { SzPlatformService } from '../../classes.platformservice.js';
/**
* Configures MTA storage settings for the platform service
* @param platformService Reference to the platform service
* @param options Configuration options containing storage paths
*/
export function configureMtaStorage(platformService: SzPlatformService, options: any): void {
// Extract the receivedEmailsPath if available
if (options?.emailPortConfig?.receivedEmailsPath) {
const receivedEmailsPath = options.emailPortConfig.receivedEmailsPath;
// Ensure the directory exists
plugins.smartfile.fs.ensureDirSync(receivedEmailsPath);
// Apply configuration to MTA service if available
if (platformService.mtaService) {
platformService.mtaService.configure({
storagePath: receivedEmailsPath
});
console.log(`Configured MTA to store received emails to: ${receivedEmailsPath}`);
}
}
}
/**
* Configure MTA service with port and storage settings
* @param platformService Reference to the platform service
* @param config Configuration settings for MTA
*/
export function configureMtaService(
platformService: SzPlatformService,
config: {
port?: number;
host?: string;
secure?: boolean;
storagePath?: string;
}
): boolean {
if (!platformService?.mtaService) {
console.error('MTA service not available in platform service');
return false;
}
// Configure MTA with the provided port
const mtaConfig = {
port: config.port, // Use the port provided by the config
host: config.host || 'localhost',
secure: config.secure || false,
storagePath: config.storagePath
};
// Configure the MTA service
platformService.mtaService.configure(mtaConfig);
console.log(`Configured MTA service on port ${mtaConfig.port}`);
// Set up storage path if provided
if (config.storagePath) {
configureMtaStorage(platformService, {
emailPortConfig: {
receivedEmailsPath: config.storagePath
}
});
}
return true;
}

View File

@ -1,72 +0,0 @@
import * as plugins from '../../plugins.js';
import * as paths from '../../paths.js';
import type { SzPlatformService } from '../../platformservice.js';
/**
* Extension to the MTA service to handle custom email storage
*/
export function configureEmailStorage(mtaService: any, options: any = {}) {
const originalSaveToLocalMailbox = mtaService.saveToLocalMailbox;
// Override the saveToLocalMailbox method to use custom path
mtaService.saveToLocalMailbox = async function(email: any): Promise<void> {
try {
// Use the custom received emails path if configured
const customPath = options?.receivedEmailsPath;
if (customPath) {
// Ensure the directory exists
plugins.smartfile.fs.ensureDirSync(customPath);
// Check if this is a bounce notification
const isBounceNotification = this.isBounceNotification(email);
if (isBounceNotification) {
await this.processBounceNotification(email);
return;
}
// Store the email in the custom path
const emailContent = email.toRFC822String();
const filename = `${Date.now()}_${email.to[0].replace(/[^a-zA-Z0-9]/g, '_')}.eml`;
plugins.smartfile.memory.toFsSync(
emailContent,
plugins.path.join(customPath, filename)
);
console.log(`Email saved to custom mailbox location: ${customPath}/${filename}`);
} else {
// Use the original implementation
await originalSaveToLocalMailbox.call(this, email);
}
} catch (error) {
console.error('Error saving email to local mailbox:', error);
throw error;
}
};
return mtaService;
}
/**
* Apply the email storage configuration to the platform service
*/
export function applyCustomEmailStorage(platformService: SzPlatformService, options: any): void {
// Extract the receivedEmailsPath if available
if (options?.emailPortConfig?.receivedEmailsPath) {
const receivedEmailsPath = options.emailPortConfig.receivedEmailsPath;
// Ensure the directory exists
plugins.smartfile.fs.ensureDirSync(receivedEmailsPath);
// Apply configuration to MTA service if available
if (platformService.mtaService) {
configureEmailStorage(platformService.mtaService, {
receivedEmailsPath
});
console.log(`Configured MTA to store received emails to: ${receivedEmailsPath}`);
}
}
}

View File

@ -14,7 +14,7 @@ import { RateLimiter, type IRateLimitConfig } from './classes.ratelimiter.js';
import { ContentScanner } from '../../security/classes.contentscanner.js';
import { IPWarmupManager } from '../../deliverability/classes.ipwarmupmanager.js';
import { SenderReputationMonitor } from '../../deliverability/classes.senderreputationmonitor.js';
import type { SzPlatformService } from '../../platformservice.js';
import type { SzPlatformService } from '../../classes.platformservice.js';
/**
* Configuration options for the MTA service
@ -41,6 +41,8 @@ export interface IMtaConfig {
keyPath?: string;
certPath?: string;
};
/** Custom path to store received emails */
customStoragePath?: string;
/** Outbound email sending configuration */
outbound?: {
/** Maximum concurrent sending jobs */
@ -694,6 +696,8 @@ export class MtaService {
/**
* Save an email to a local mailbox
*
* This implementation supports custom email storage paths via options.receivedEmailsPath
*/
private async saveToLocalMailbox(email: Email): Promise<void> {
// Check if this is a bounce notification
@ -704,19 +708,43 @@ export class MtaService {
return;
}
// Simplified implementation - in a real system, this would store to a user's mailbox
const mailboxPath = plugins.path.join(paths.receivedEmailsDir, 'local');
plugins.smartfile.fs.ensureDirSync(mailboxPath);
const emailContent = email.toRFC822String();
const filename = `${Date.now()}_${email.to[0].replace('@', '_at_')}.eml`;
plugins.smartfile.memory.toFsSync(
emailContent,
plugins.path.join(mailboxPath, filename)
);
console.log(`Email saved to local mailbox: ${filename}`);
try {
// Check if we have a custom storage path configured
const customPath = this.config?.customStoragePath;
if (customPath) {
// Ensure the directory exists
plugins.smartfile.fs.ensureDirSync(customPath);
// Store the email in the custom path
const emailContent = email.toRFC822String();
const filename = `${Date.now()}_${email.to[0].replace(/[^a-zA-Z0-9]/g, '_')}.eml`;
plugins.smartfile.memory.toFsSync(
emailContent,
plugins.path.join(customPath, filename)
);
console.log(`Email saved to custom mailbox location: ${customPath}/${filename}`);
} else {
// Use the default path
const mailboxPath = plugins.path.join(paths.receivedEmailsDir, 'local');
plugins.smartfile.fs.ensureDirSync(mailboxPath);
const emailContent = email.toRFC822String();
const filename = `${Date.now()}_${email.to[0].replace('@', '_at_')}.eml`;
plugins.smartfile.memory.toFsSync(
emailContent,
plugins.path.join(mailboxPath, filename)
);
console.log(`Email saved to local mailbox: ${filename}`);
}
} catch (error) {
console.error('Error saving email to local mailbox:', error);
throw error;
}
}
/**
@ -1322,6 +1350,81 @@ export class MtaService {
return this.reputationMonitor;
}
/**
* Configure MTA with new settings
*/
public configure(config: {
port?: number;
host?: string;
secure?: boolean;
storagePath?: string;
}): void {
console.log('Configuring MTA service with new settings:', config);
// Update SMTP port if provided
if (config.port !== undefined) {
// Store the original port
const originalPort = this.config.smtp.port;
this.config.smtp.port = config.port;
console.log(`Updated MTA port from ${originalPort} to ${config.port}`);
// If the server is already running, we need to restart it
if (this.server && this.running) {
console.log('Restarting SMTP server with new port');
const restartServer = async () => {
try {
// Stop the current server
await this.server.stop();
// Create and start the new server with updated config
const smtpOptions: ISmtpServerOptions = {
port: this.config.smtp.port,
key: this.certificate.privateKey,
cert: this.certificate.publicKey,
hostname: this.config.smtp.hostname
};
this.server = new SMTPServer(this, smtpOptions);
this.server.start();
console.log(`SMTP server restarted on port ${smtpOptions.port}`);
} catch (error) {
console.error('Error restarting SMTP server:', error);
}
};
// Execute the restart
restartServer().catch(error => {
console.error('Failed to restart SMTP server:', error);
});
}
}
// Update hostname if provided
if (config.host) {
this.config.smtp.hostname = config.host;
console.log(`Updated MTA hostname to ${config.host}`);
}
// Update TLS settings if secure flag is provided
if (config.secure !== undefined) {
// This would update TLS settings as appropriate
console.log(`Updated MTA TLS settings (secure: ${config.secure})`);
}
// Update storage path if provided
if (config.storagePath) {
this.config.customStoragePath = config.storagePath;
// Ensure the directory exists
plugins.smartfile.fs.ensureDirSync(config.storagePath);
console.log(`Updated MTA storage path to ${config.storagePath}`);
}
}
/**
* Get MTA service statistics
*/

View File

@ -15,4 +15,7 @@ export { RateLimiter } from './classes.ratelimiter.js';
export type { IRateLimitConfig } from './classes.ratelimiter.js';
// Unified rate limiter
export * from './classes.unified.rate.limiter.js';
export * from './classes.unified.rate.limiter.js';
// MTA configuration helpers
export * from './classes.mta.config.js';

View File

@ -7,7 +7,7 @@ import { TemplateManager } from '../core/classes.templatemanager.js';
import { EmailValidator } from '../core/classes.emailvalidator.js';
import { BounceManager } from '../core/classes.bouncemanager.js';
import { logger } from '../../logger.js';
import type { SzPlatformService } from '../../platformservice.js';
import type { SzPlatformService } from '../../classes.platformservice.js';
// Import MTA service
import { MtaService } from '../delivery/classes.mta.js';