169 lines
4.9 KiB
TypeScript
169 lines
4.9 KiB
TypeScript
|
import * as plugins from '../plugins.js';
|
||
|
import { EmailService } from './email.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 }
|
||
|
};
|
||
|
}
|
||
|
}
|
||
|
}
|