From bc5f368d2a94a2b198421054ad7f8dd3897c6c8a Mon Sep 17 00:00:00 2001 From: radhakrishnan Date: Thu, 24 Jul 2025 20:58:53 +0530 Subject: [PATCH 1/2] Add MSG to EML email conversion support (#367) - Add new msgconvert converter using libemail-outlook-message-perl - Support conversion from Outlook MSG files to standard EML format - Add msgconvert to Docker dependencies and version checking - Register msgconvert converter in main converter registry Implements feature request #367 for email format conversion --- Dockerfile | 1 + src/converters/main.ts | 5 ++++ src/converters/msgconvert.ts | 47 ++++++++++++++++++++++++++++++++++++ src/helpers/printVersions.ts | 10 ++++++++ 4 files changed, 63 insertions(+) create mode 100644 src/converters/msgconvert.ts diff --git a/Dockerfile b/Dockerfile index 16b4740..0711ef9 100644 --- a/Dockerfile +++ b/Dockerfile @@ -59,6 +59,7 @@ RUN apt-get update && apt-get install -y \ libreoffice \ libva2 \ libvips-tools \ + libemail-outlook-message-perl \ lmodern \ mupdf-tools \ pandoc \ diff --git a/src/converters/main.ts b/src/converters/main.ts index bc0c27f..63106ff 100644 --- a/src/converters/main.ts +++ b/src/converters/main.ts @@ -14,6 +14,7 @@ import { convert as convertInkscape, properties as propertiesInkscape } from "./ import { convert as convertLibheif, properties as propertiesLibheif } from "./libheif"; import { convert as convertLibjxl, properties as propertiesLibjxl } from "./libjxl"; import { convert as convertLibreOffice, properties as propertiesLibreOffice } from "./libreoffice"; +import { convert as convertMsgconvert, properties as propertiesMsgconvert } from "./msgconvert"; import { convert as convertPandoc, properties as propertiesPandoc } from "./pandoc"; import { convert as convertPotrace, properties as propertiesPotrace } from "./potrace"; import { convert as convertresvg, properties as propertiesresvg } from "./resvg"; @@ -87,6 +88,10 @@ const properties: Record< properties: propertiesPandoc, converter: convertPandoc, }, + msgconvert: { + properties: propertiesMsgconvert, + converter: convertMsgconvert, + }, dvisvgm: { properties: propertiesDvisvgm, converter: convertDvisvgm, diff --git a/src/converters/msgconvert.ts b/src/converters/msgconvert.ts new file mode 100644 index 0000000..9d13a8f --- /dev/null +++ b/src/converters/msgconvert.ts @@ -0,0 +1,47 @@ +import { execFile } from "node:child_process"; + +export const properties = { + from: { + email: ["msg"], + }, + to: { + email: ["eml"], + }, +}; + +export function convert( + filePath: string, + fileType: string, + convertTo: string, + targetPath: string, + // eslint-disable-next-line @typescript-eslint/no-unused-vars + options?: unknown, +): Promise { + return new Promise((resolve, reject) => { + if (fileType === "msg" && convertTo === "eml") { + // Convert MSG to EML using msgconvert + // msgconvert will output to the same directory as the input file with .eml extension + // We need to use --outfile to specify the target path + const args = ["--outfile", targetPath, filePath]; + + execFile("msgconvert", args, (error, stdout, stderr) => { + if (error) { + reject(`error: ${error}`); + return; + } + + if (stdout) { + console.log(`stdout: ${stdout}`); + } + + if (stderr) { + console.error(`stderr: ${stderr}`); + } + + resolve("Done"); + }); + } else { + reject(`Unsupported conversion from ${fileType} to ${convertTo}. Only MSG to EML conversion is currently supported.`); + } + }); +} diff --git a/src/helpers/printVersions.ts b/src/helpers/printVersions.ts index 68af2e0..eb1a591 100644 --- a/src/helpers/printVersions.ts +++ b/src/helpers/printVersions.ts @@ -154,6 +154,16 @@ if (process.env.NODE_ENV === "production") { } }); + exec("msgconvert --version", (error, stdout) => { + if (error) { + console.error("msgconvert (libemail-outlook-message-perl) is not installed"); + } + + if (stdout) { + console.log(stdout.split("\n")[0]); + } + }); + exec("bun -v", (error, stdout) => { if (error) { console.error("Bun is not installed. wait what"); From 7d0474874e069a3e155d81167a5ea7a6d7a89aad Mon Sep 17 00:00:00 2001 From: radhakrishnan Date: Thu, 24 Jul 2025 21:13:20 +0530 Subject: [PATCH 2/2] Improve msgconvert error handling and security - Remove unnecessary stdout logging to reduce output clutter - Sanitize stderr logging to protect sensitive path information - Return targetPath instead of generic 'Done' message for better caller context - Use proper Error objects instead of string rejections - Address Sourcery AI feedback from PR #370 --- src/converters/msgconvert.ts | 14 ++++++-------- 1 file changed, 6 insertions(+), 8 deletions(-) diff --git a/src/converters/msgconvert.ts b/src/converters/msgconvert.ts index 9d13a8f..b6bf826 100644 --- a/src/converters/msgconvert.ts +++ b/src/converters/msgconvert.ts @@ -26,22 +26,20 @@ export function convert( execFile("msgconvert", args, (error, stdout, stderr) => { if (error) { - reject(`error: ${error}`); + reject(new Error(`msgconvert failed: ${error.message}`)); return; } - if (stdout) { - console.log(`stdout: ${stdout}`); - } - if (stderr) { - console.error(`stderr: ${stderr}`); + // Log sanitized stderr to avoid exposing sensitive paths + const sanitizedStderr = stderr.replace(/(\/[^\s]+)/g, "[REDACTED_PATH]"); + console.warn(`msgconvert stderr: ${sanitizedStderr.length > 200 ? sanitizedStderr.slice(0, 200) + '...' : sanitizedStderr}`); } - resolve("Done"); + resolve(targetPath); }); } else { - reject(`Unsupported conversion from ${fileType} to ${convertTo}. Only MSG to EML conversion is currently supported.`); + reject(new Error(`Unsupported conversion from ${fileType} to ${convertTo}. Only MSG to EML conversion is currently supported.`)); } }); }