UNPKG

@hyperbytes/wappler-imap-manager

Version:

IMAP eMail Management for Wappler

202 lines (178 loc) 7.83 kB
const Imap = require('imap-simple'); const nodemailer = require('nodemailer'); const mailcomposer = require('mailcomposer'); const { simpleParser } = require('mailparser'); // Used for debugging email content const { toSystemPath } = require("../../../lib/core/path"); const path = require("path"); exports.imapsaveasdraft = async function (options) { console.log('Starting IMAP draft save process...'); // Parse IMAP configuration const IMAP_HOST = this.parseOptional(options.imap_host, '*', process.env.IMAP_HOST); const IMAP_PASSWORD = this.parseOptional(options.imap_password, '*', process.env.IMAP_PASSWORD); const IMAP_USER = this.parseOptional(options.imap_user, '*', process.env.IMAP_USER); const IMAP_PORT = this.parseOptional(options.imap_port, '*', process.env.IMAP_PORT); const imap_tlsstring = this.parseOptional(options.imap_tls, '*', process.env.IMAP_TLS).toLowerCase(); const IMAP_TLS = (imap_tlsstring === 'true'); // Validate essential IMAP configuration if (!IMAP_HOST || !IMAP_USER || !IMAP_PASSWORD) { console.error('IMAP host, user, or password not configured.'); return { status: 401, message: 'IMAP configuration incomplete.', error: 'IMAP host, user, or password not configured.', uid: '', folder: this.parseOptional(options.mailbox, '*', 'Drafts') }; } // Parse email details const to = this.parseOptional(options.to, "*", ""); console.log('To: ' + to); const mailfrom = this.parseOptional(options.from, "*", ""); console.log('From: ' + mailfrom); const cc = this.parseOptional(options.cc, "*", ""); console.log('CC: ' + cc); const bcc = this.parseOptional(options.bcc, "*", ""); console.log('BCC: ' + bcc); const subject = this.parseOptional(options.mailsubject, "*", "default subject"); console.log('Subject: ' + subject); const body = this.parseOptional(options.body, "*", ""); // Assuming this is HTML body console.log('Body: ' + body); const upload = this.parseOptional(options.attachments, '*', []); console.log('Attachments: ' + upload); let folder = this.parseOptional(options.mailbox, '*', 'Drafts'); // Default to 'Drafts' console.log('Folder: ' + folder); // Check if a UID is provided – meaning the draft is to be updated const providedUid = this.parseOptional(options.uid, "*", ""); console.log('UID: ' + providedUid); console.log(`Attempting to save draft to folder: ${folder}`); // Ensure attachments are properly formatted and converted to system paths const attachmentList = Array.isArray(upload) ? upload.map(file => ({ ...file, // Keep existing properties systemPath: toSystemPath(file.path) // Convert relative path to system path })) : []; // Prepare attachments for Nodemailer const formattedAttachments = attachmentList.map(file => ({ filename: path.basename(file.systemPath), path: file.systemPath // Use transformed system path })); const imapConfig = { imap: { user: IMAP_USER, password: IMAP_PASSWORD, host: IMAP_HOST, port: IMAP_PORT, tls: IMAP_TLS, tlsOptions: { rejectUnauthorized: process.env.IMAP_CERTIFICATE_OVERRIDE === '1' ? false : true }, authTimeout: 5000 } }; let connection; try { // 1. Construct the email message using mailcomposer const mailOptions = { from: mailfrom, to: to, cc: cc, bcc: bcc, subject: subject, html: body, // Use 'text' if it's plain text attachments: formattedAttachments }; const mail = mailcomposer(mailOptions); const rawEmail = await new Promise((resolve, reject) => { mail.build((err, message) => { if (err) { console.error('Error building email:', err); return { status: 400, message: 'Error building email.', uid: '', folder: folder }; } resolve(message); }); }); console.log('Raw email constructed.'); // Debug: Parse the raw email to verify its content const parsedEmail = await simpleParser(rawEmail); console.log('Parsed Email Content:', { subject: parsedEmail.subject, text: parsedEmail.text, html: parsedEmail.html, headers: parsedEmail.headers }); // 2. Connect to IMAP server console.log(`Connecting to IMAP server ${IMAP_HOST}:${IMAP_PORT}...`); connection = await Imap.connect(imapConfig); console.log('Successfully connected to IMAP server.'); // 3. Open the target mailbox await connection.openBox(folder); console.log(`Mailbox "${folder}" opened.`); // Retrieve UID validity of the destination mailbox (if available) // 4. If a UID is provided, update the existing draft; otherwise, append a new one. if (providedUid) { console.log(`UID provided (${providedUid}). Updating existing draft...`); // Attempt to delete the existing draft for that UID try { await connection.deleteMessage(providedUid); console.log(`Existing draft with UID ${providedUid} deleted.`); } catch (delErr) { console.warn(`Could not delete existing draft with UID ${providedUid}: ${delErr}`); // You might decide to abort here if deletion is mandatory } // Append the new draft (note: the server will normally assign a new UID, // but we are returning the provided UID per the requirement). console.log(`Appending updated draft to folder: ${folder}...`); const updateAppendResult = await connection.append(rawEmail, { mailbox: folder, flags: ['\\Draft'] }); console.log('Updated draft appended.', updateAppendResult); return { status: 200, message: 'Draft updated successfully.', uid: providedUid, folder: folder }; } else { console.log(`Appending email as a draft to folder: ${folder}...`); const appendResult = await connection.append(rawEmail, { mailbox: folder, flags: ['\\Draft'] }); console.log('Email appended to drafts folder.', appendResult); // Retrieve UID of the saved message const searchResult = await connection.search(['ALL'], { bodies: ['HEADER.FIELDS (MESSAGE-ID)'] }); const uid = searchResult.length > 0 ? searchResult[searchResult.length - 1].attributes.uid : ''; return { status: 200, message: 'Draft saved successfully.', uid: uid, folder: folder }; } } catch (err) { console.error('IMAP draft save failed:', err); return { status: 400, message: 'Failed to save draft.', error: err.toString(), uid: '', folder: folder }; } finally { if (connection) { try { await connection.end(); console.log('IMAP connection closed.'); } catch (endErr) { console.error('Error ending IMAP connection:', endErr); } } } };