import * as plugins from '../plugins.js'; import { EmailService } from './classes.emailservice.js'; import { logger } from '../logger.js'; // Import MTA classes import { MtaService, Email as MtaEmail, type IEmailOptions, DeliveryStatus, type IAttachment } from '../mta/index.js'; export class MtaConnector { public emailRef: EmailService; private mtaService: MtaService; constructor(emailRefArg: EmailService, mtaService?: MtaService) { this.emailRef = emailRefArg; this.mtaService = mtaService || this.emailRef.mtaService; } /** * Send an email using the MTA service * @param smartmail The email to send * @param toAddresses Recipients (comma-separated or array) * @param options Additional options */ public async sendEmail( smartmail: plugins.smartmail.Smartmail<>, toAddresses: string | string[], options: any = {} ): Promise { try { // Process recipients const toArray = Array.isArray(toAddresses) ? toAddresses : toAddresses.split(',').map(addr => addr.trim()); // Map SmartMail attachments to MTA attachments const attachments: IAttachment[] = smartmail.attachments.map(attachment => { return { filename: attachment.parsedPath.base, content: Buffer.from(attachment.contentBuffer), contentType: (attachment as any)?.getContentType?.() || 'application/octet-stream' // TODO: revisit after smartfile has been updated }; }); // Create MTA Email const mtaEmail = new MtaEmail({ from: smartmail.options.from, to: toArray, subject: smartmail.getSubject(), text: smartmail.getBody(false), // Plain text version html: smartmail.getBody(true), // HTML version attachments }); // Send using MTA const emailId = await this.mtaService.send(mtaEmail); logger.log('info', `Email sent via MTA to ${toAddresses}`, { eventType: 'sentEmail', provider: 'mta', emailId, to: toAddresses }); return emailId; } catch (error) { logger.log('error', `Failed to send email via MTA: ${error.message}`, { eventType: 'emailError', provider: 'mta', error: error.message }); throw error; } } /** * Retrieve and process an incoming email * For MTA, this would handle an email already received by the SMTP server * @param emailData The raw email data or identifier */ public async receiveEmail(emailData: string): Promise> { try { // In a real implementation, this would retrieve an email from the MTA storage // For now, we can use a simplified approach: // Parse the email (assuming emailData is a raw email or a file path) const parsedEmail = await plugins.mailparser.simpleParser(emailData); // Create a Smartmail from the parsed email const smartmail = new plugins.smartmail.Smartmail({ from: parsedEmail.from?.text || '', subject: parsedEmail.subject || '', body: parsedEmail.html || parsedEmail.text || '', creationObjectRef: { From: parsedEmail.from?.text || '', To: parsedEmail.to?.text || '', Subject: parsedEmail.subject || '' } }); // Add attachments if present if (parsedEmail.attachments && parsedEmail.attachments.length > 0) { for (const attachment of parsedEmail.attachments) { smartmail.addAttachment( await plugins.smartfile.SmartFile.fromBuffer( attachment.filename || 'attachment', attachment.content ) ); } } return smartmail; } catch (error) { logger.log('error', `Failed to receive email via MTA: ${error.message}`, { eventType: 'emailError', provider: 'mta', error: error.message }); throw error; } } /** * Check the status of a sent email * @param emailId The email ID to check */ public async checkEmailStatus(emailId: string): Promise<{ status: string; details?: any; }> { try { const status = this.mtaService.getEmailStatus(emailId); if (!status) { return { status: 'unknown', details: { message: 'Email not found' } }; } return { status: status.status, details: { attempts: status.attempts, lastAttempt: status.lastAttempt, nextAttempt: status.nextAttempt, error: status.error?.message } }; } catch (error) { logger.log('error', `Failed to check email status: ${error.message}`, { eventType: 'emailError', provider: 'mta', emailId, error: error.message }); return { status: 'error', details: { message: error.message } }; } } }