platformservice/ts/email/classes.connector.mta.ts

169 lines
4.9 KiB
TypeScript
Raw Normal View History

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<string> {
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<plugins.smartmail.Smartmail<>> {
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 }
};
}
}
}