@hyperbytes/wappler-imap-manager
Version:
IMAP eMail Management for Wappler
179 lines (146 loc) • 6.2 kB
JavaScript
const nodemailer = require("nodemailer");
const imap = require("imap");
const fs = require("fs");
const path = require("path");
const { toSystemPath } = require("../../../lib/core/path");
exports.imapsendmail = async function (options) {
const upload = this.parseOptional(options.attachments, '*', []);
console.log("Attachments: " + JSON.stringify(upload))
const upload2 = this.parseOptional(options.server_attachments, '*', []);
console.log("Server_Attachments: " + JSON.stringify(upload2))
const combinedJson = { "attachments": [upload, upload2] };
console.log('CombinedJson: ' + JSON.stringify(combinedJson))
// 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
}))
: [];
console.log("Attachment upload initially:", upload);
console.log("Transformed Attachments List:", attachmentList);
const smtpFile = this.parseOptional(options.smtp_file, '*', 'default');
// const SMTP_SETTINGS_PATH = toSystemPath(`/.wappler/targets/${process.env.NODE_ENV}/app/modules/Mailer/${smtpFile}.json`);
const SMTP_SETTINGS_PATH = toSystemPath(`/app/modules/Mailer/${smtpFile}.json`);
console.log("SMTP Config Path:", SMTP_SETTINGS_PATH);
// Load SMTP settings dynamically
function loadSMTPSettings() {
try {
const settingsData = fs.readFileSync(SMTP_SETTINGS_PATH, "utf8");
const settings = JSON.parse(settingsData);
return settings.options;
} catch (error) {
console.error("Error loading SMTP settings:", error);
return null;
}
}
const smtpConfig = loadSMTPSettings();
if (!smtpConfig) {
return { status: 401, error: "Failed to load SMTP settings." };
}
const to = this.parseRequired(options.to, '*', "No to email address specified");
const cc = this.parseOptional(options.cc, '*', "");
const bcc = this.parseOptional(options.bcc, '*', "");
const from = this.parseRequired(options.from, '*', "No from email address specified");
const subject = this.parseOptional(options.subject, '*', "");
const body = this.parseRequired(options.body, '*', "No email body specified");
const saveToSent = this.parseOptional(options.save_to_send, '*', false);
try {
const transporter = nodemailer.createTransport({
host: smtpConfig.host,
port: smtpConfig.port,
secure: smtpConfig.useSSL,
auth: {
user: smtpConfig.username,
pass: smtpConfig.password,
},
logger: false, // Enable logging
debug: false, // Enable debugging
});
// Prepare attachments for Nodemailer
const formattedAttachments = attachmentList.map(file => ({
filename: path.basename(file.systemPath),
path: file.systemPath // Use transformed system path
}));
const mailOptions = {
from: from,
to: to,
cc: cc,
bcc: bcc,
subject: subject,
text: body,
html: body,
attachments: formattedAttachments
};
console.log("Final Attachments List:", formattedAttachments);
let info = await transporter.sendMail(mailOptions);
console.log("Email sent:", info.messageId);
// Save to Sent Items if requested
if (saveToSent) {
await saveToSentFolder(options, mailOptions);
}
return { status: 200, messageId: info.messageId };
} catch (error) {
console.error("Error sending email:", error);
return { status: 400, error: error.message };
}
};
// Function to **save email & attachments** in Sent Items (Promise-based)
async function saveToSentFolder(options, mailOptions) {
return new Promise((resolve, reject) => {
const imapConfig = {
user: process.env.IMAP_USER,
password: process.env.IMAP_PASSWORD,
host: process.env.IMAP_HOST,
port: process.env.IMAP_PORT,
tls: true,
};
let emailContent = `From: ${mailOptions.from}
To: ${mailOptions.to}
Subject: ${mailOptions.subject}
Content-Type: multipart/mixed; boundary="boundary"
--boundary
Content-Type: text/plain
${mailOptions.text || ""}
`;
// Attach files in MIME format
for (let attachment of mailOptions.attachments) {
try {
const fileData = fs.readFileSync(attachment.path).toString("base64");
emailContent += `--boundary
Content-Type: application/octet-stream; name="${attachment.filename}"
Content-Disposition: attachment; filename="${attachment.filename}"
Content-Transfer-Encoding: base64
${fileData}
`;
} catch (err) {
console.error(`Error reading attachment file: ${attachment.path}`, err);
return reject(err);
}
}
emailContent += "--boundary--"; // Closing MIME boundary
const imapClient = new imap(imapConfig);
imapClient.once("ready", () => {
imapClient.openBox("Sent", true, (err) => {
if (err) {
console.error("Error opening Sent Items folder:", err);
return reject(err);
}
imapClient.append(Buffer.from(emailContent), { mailbox: "Sent" }, (err) => {
if (err) {
console.error("Failed to save email to Sent Items:", err);
return reject(err);
}
console.log("Email successfully saved to Sent Items with attachments.");
imapClient.end();
resolve();
});
});
});
imapClient.once("error", (err) => {
console.error("IMAP connection error:", err);
reject(err);
});
imapClient.connect();
});
}