import * as plugins from '../../plugins.js'; import { EmailService } from '../services/classes.emailservice.js'; import { logger } from '../../logger.js'; import { Email, type IEmailOptions } from './classes.email.js'; export class RuleManager { public emailRef: EmailService; public smartruleInstance = new plugins.smartrule.SmartRule(); constructor(emailRefArg: EmailService) { this.emailRef = emailRefArg; // Register handler for incoming emails if email server is enabled if (this.emailRef.unifiedEmailServer) { this.setupIncomingHandler(); } } /** * Set up handler for incoming emails via the UnifiedEmailServer */ private setupIncomingHandler() { // Use UnifiedEmailServer events for incoming emails const incomingDir = './received'; // The UnifiedEmailServer raises events for incoming emails // For backward compatibility, also watch the directory this.watchIncomingEmails(incomingDir); } /** * Watch directory for incoming emails (conceptual implementation) */ private watchIncomingEmails(directory: string) { console.log(`Watching for incoming emails in: ${directory}`); // Conceptual - in a real implementation, set up proper file watching // or use UnifiedEmailServer events for incoming emails /* // Example using a file watcher: const watcher = plugins.fs.watch(directory, async (eventType, filename) => { if (eventType === 'rename' && filename.endsWith('.eml')) { const filePath = plugins.path.join(directory, filename); await this.handleIncomingEmail(filePath); } }); */ // Set up event listener on UnifiedEmailServer if available if (this.emailRef.unifiedEmailServer) { this.emailRef.unifiedEmailServer.on('emailProcessed', (email: Email, mode, rule) => { // Process email through rule system this.smartruleInstance.makeDecision(email); }); } } /** * Handle incoming email received via email server */ public async handleIncomingEmail(emailPath: string) { try { // Process the email file using direct file access or access through UnifiedEmailServer // For compatibility with existing code, we'll make a basic assumption about structure const emailContent = await plugins.fs.promises.readFile(emailPath, 'utf8'); // Parse the email content into proper format const parsedContent = await plugins.mailparser.simpleParser(emailContent); // Create an Email object with the parsed content const fromAddress = Array.isArray(parsedContent.from) ? parsedContent.from[0]?.text || 'unknown@example.com' : parsedContent.from?.text || 'unknown@example.com'; const toAddress = Array.isArray(parsedContent.to) ? parsedContent.to[0]?.text || 'unknown@example.com' : parsedContent.to?.text || 'unknown@example.com'; const fetchedEmail = new Email({ from: fromAddress, to: toAddress, subject: parsedContent.subject || '', text: parsedContent.text || '', html: parsedContent.html || undefined }); console.log('======================='); console.log('Received a mail:'); console.log(`From: ${fetchedEmail.from}`); console.log(`Subject: ${fetchedEmail.subject}`); console.log('^^^^^^^^^^^^^^^^^^^^^^^'); logger.log( 'info', `email from ${fetchedEmail.from} with subject '${fetchedEmail.subject}'`, { eventType: 'receivedEmail', provider: 'unified', email: { from: fetchedEmail.from, subject: fetchedEmail.subject, }, } ); // Process with rules this.smartruleInstance.makeDecision(fetchedEmail); } catch (error) { logger.log('error', `Failed to process incoming email: ${error.message}`, { eventType: 'emailError', provider: 'unified', error: error.message }); } } public async init() { // Setup email rules await this.createForwards(); } /** * creates the default forwards */ public async createForwards() { const forwards: { originalToAddress: string[]; forwardedToAddress: string[] }[] = []; console.log(`${forwards.length} forward rules configured:`); for (const forward of forwards) { console.log(forward); } for (const forward of forwards) { this.smartruleInstance.createRule( 10, async (emailArg: Email) => { const matched = forward.originalToAddress.reduce((prevValue, currentValue) => { return emailArg.to.some(to => to.includes(currentValue)) || prevValue; }, false); if (matched) { console.log('Forward rule matched'); console.log(forward); return 'apply-continue'; } else { return 'continue'; } }, async (emailArg: Email) => { forward.forwardedToAddress.map(async (toArg) => { const forwardedEmail = new Email({ from: 'forwarder@mail.lossless.one', to: toArg, subject: `Forwarded mail for '${emailArg.to.join(', ')}'`, html: `
Original Sender:
${emailArg.from}
Original Recipient:
${emailArg.to.join(', ')}
Forwarded to:
${forward.forwardedToAddress.reduce((pVal, cVal) => { return `${pVal ? pVal + ', ' : ''}${cVal}`; }, null)}
Subject:
${emailArg.getSubject()}
The original body can be found below.
` + emailArg.getBody(true), text: `Forwarded mail from ${emailArg.from} to ${emailArg.to.join(', ')}\n\n${emailArg.getBody()}`, attachments: emailArg.attachments }); // Use the EmailService's sendEmail method to send with the appropriate provider await this.emailRef.sendEmail(forwardedEmail); console.log(`forwarded mail to ${toArg}`); logger.log( 'info', `email from ${emailArg.from} to ${toArg} with subject '${emailArg.getSubject()}'`, { eventType: 'forwardedEmail', email: { from: emailArg.from, to: emailArg.to.join(', '), forwardedTo: toArg, subject: emailArg.subject, }, } ); }); } ); } } }