import * as plugins from '../../plugins.js'; import * as paths from '../../paths.js'; import { MtaConnector } from '../delivery/classes.connector.mta.js'; import { RuleManager } from '../core/classes.rulemanager.js'; import { ApiManager } from './classes.apimanager.js'; 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 MTA service import { MtaService, type IMtaConfig } from '../delivery/classes.mta.js'; export interface IEmailConstructorOptions { useMta?: boolean; mtaConfig?: IMtaConfig; templateConfig?: { from?: string; replyTo?: string; footerHtml?: string; footerText?: string; }; loadTemplatesFromDir?: boolean; } /** * Email service with MTA support */ export class EmailService { public platformServiceRef: SzPlatformService; // typedrouter public typedrouter = new plugins.typedrequest.TypedRouter(); // connectors public mtaConnector: MtaConnector; public qenv = new plugins.qenv.Qenv('./', '.nogit/'); // MTA service public mtaService: MtaService; // services public apiManager: ApiManager; public ruleManager: RuleManager; public templateManager: TemplateManager; public emailValidator: EmailValidator; public bounceManager: BounceManager; // configuration private config: IEmailConstructorOptions; constructor(platformServiceRefArg: SzPlatformService, options: IEmailConstructorOptions = {}) { this.platformServiceRef = platformServiceRefArg; this.platformServiceRef.typedrouter.addTypedRouter(this.typedrouter); // Set default options this.config = { useMta: options.useMta ?? true, mtaConfig: options.mtaConfig || {}, templateConfig: options.templateConfig || {}, loadTemplatesFromDir: options.loadTemplatesFromDir ?? true }; // Initialize validator this.emailValidator = new EmailValidator(); // Initialize bounce manager this.bounceManager = new BounceManager(); // Initialize template manager this.templateManager = new TemplateManager(this.config.templateConfig); if (this.config.useMta) { // Initialize MTA service this.mtaService = new MtaService(platformServiceRefArg, this.config.mtaConfig); // Initialize MTA connector this.mtaConnector = new MtaConnector(this); } // Initialize API manager and rule manager this.apiManager = new ApiManager(this); this.ruleManager = new RuleManager(this); // Set up MTA SMTP server webhook if using MTA if (this.config.useMta) { // The MTA SMTP server will handle incoming emails directly // through its SMTP protocol. No additional webhook needed. } } /** * Start the email service */ public async start() { // Initialize rule manager await this.ruleManager.init(); // Load email templates if configured if (this.config.loadTemplatesFromDir) { try { await this.templateManager.loadTemplatesFromDirectory(paths.emailTemplatesDir); } catch (error) { logger.log('error', `Failed to load email templates: ${error.message}`); } } // Start MTA service if enabled if (this.config.useMta && this.mtaService) { await this.mtaService.start(); logger.log('success', 'Started MTA service'); } logger.log('success', `Started email service`); } /** * Stop the email service */ public async stop() { // Stop MTA service if it's running if (this.config.useMta && this.mtaService) { await this.mtaService.stop(); logger.log('info', 'Stopped MTA service'); } logger.log('info', 'Stopped email service'); } /** * Send an email using the MTA * @param email The email to send * @param to Recipient(s) * @param options Additional options */ public async sendEmail( email: plugins.smartmail.Smartmail, to: string | string[], options: any = {} ): Promise { // Determine which connector to use if (this.config.useMta && this.mtaConnector) { return this.mtaConnector.sendEmail(email, to, options); } else { throw new Error('MTA not configured'); } } /** * Send an email using a template * @param templateId The template ID * @param to Recipient email(s) * @param context The template context data * @param options Additional options */ public async sendTemplateEmail( templateId: string, to: string | string[], context: any = {}, options: any = {} ): Promise { try { // Get email from template const smartmail = await this.templateManager.prepareEmail(templateId, context); // Send the email return this.sendEmail(smartmail, to, options); } catch (error) { logger.log('error', `Failed to send template email: ${error.message}`, { templateId, to, error: error.message }); throw error; } } /** * Validate an email address * @param email The email address to validate * @param options Validation options * @returns Validation result */ public async validateEmail( email: string, options: { checkMx?: boolean; checkDisposable?: boolean; checkRole?: boolean; } = {} ): Promise { return this.emailValidator.validate(email, options); } /** * Get email service statistics */ public getStats() { const stats: any = { activeProviders: [] }; if (this.config.useMta) { stats.activeProviders.push('mta'); stats.mta = this.mtaService.getStats(); } return stats; } }