From 1b44541a1ec4b2896b9749efc8cfe0ec9db5fc35 Mon Sep 17 00:00:00 2001 From: Kuba Orlik Date: Sun, 12 Sep 2021 20:50:16 +0200 Subject: [PATCH] Mail to PDF - initial commit --- README.md | 12 +++++ mail-to-pdf.mjs | 120 ++++++++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 132 insertions(+) create mode 100644 README.md create mode 100755 mail-to-pdf.mjs diff --git a/README.md b/README.md new file mode 100644 index 0000000..18265c9 --- /dev/null +++ b/README.md @@ -0,0 +1,12 @@ +# Mail-to-pdf + +Skrypt konwertujący pliki .eml do plików PDF, razem z załącznikami w postaci zdjęć. + +## Wymagania + +- zx +- wkhtmltopdf + +## Sposób użycia + +`./mail-to-pdf.mjs plik.eml` diff --git a/mail-to-pdf.mjs b/mail-to-pdf.mjs new file mode 100755 index 0000000..b20e21b --- /dev/null +++ b/mail-to-pdf.mjs @@ -0,0 +1,120 @@ +#!/usr/bin/zx --quiet + +import { resolve, basename } from "path"; + +const pwd = (await $`pwd`).stdout.replace("\n", ""); + +$`echo $PWD`; + +const path = resolve(process.env.PWD, process.argv.slice(-1)[0]); + +const mail_body = (await $`mu view ${path} -o sexp`).stdout.replace( + /\\"/g, + '"' +); + +let html = mail_body.match(/\.*\<\/html\>/gis)[0]; + +const attachments = (await $`mu extract ${path}`).stdout; + +function getSimpleHeader(body, header_name) { + const regexp = new RegExp(`:${header_name} (.*)\n`); + return body.match(regexp)[1]; +} + +function formatAddress(sexp) { + sexp = sexp + .replace(/(^\(\(|\)\)$)/g, "") + .replace(/"? \. "/, " <") + .replace(/"$/, ">") + .replace(/^"/, "") + .replace(/^nil <(.*)>$/, "$1"); + return sexp; +} + +function escape(str) { + return str.replace(/ line.includes("image")) + .map((line) => { + return { + filename: line.match(/\d+ (.*) image\//)[1], + mime: line.match(/image\/[^ ]+/)[0], + }; + }); + +const files = await Promise.all( + to_download.map(async ({ filename, mime }) => { + await $`mu extract --overwrite --target-dir=/tmp ${path} ${filename}`; + const base64 = (await $`base64 -w 0 < ${`/tmp/${filename}`}`).stdout; + return { filename, base64, mime }; + }) +); + +const attachments_items = files + .map( + ({ filename, mime, base64 }) => /* HTML */ `
  • + ${filename} +
  • ` + ) + .join("\n"); + +html = html.replace( + /<\/body>/i, + /* HTML */ `

    Załączniki:

    + ` +); + +const subject = getSimpleHeader(mail_body, "subject").slice(1, -1); // slice to remove " +const from = formatAddress(getSimpleHeader(mail_body, "from")); +const to = formatAddress(getSimpleHeader(mail_body, "to")); +const date = await formatDate(getSimpleHeader(mail_body, "date")); + +// console.log({ subject, from, to, date }); + +html = html.replace( + //i, + `` + + /* HTML */ `

    ${subject}

    + + + + + + + + + + + + + + + + + +
    Temat wiadomości:${subject}
    Wysłano:${escape(date)}
    Od:${escape(from)}
    Do:${escape(to)}
    ` +); + +const output = (await $`mktemp --suffix=.html`).stdout.replace("\n", ""); + +await fs.writeFile(output, html); +await $`wkhtmltopdf ${output} ${`${basename(path)}.pdf`}`; +// console.log(pwd + "output.html"); +// console.log(mail_body); + +async function formatDate(sexp) { + const parsed = (await $`emacsclient --eval ${`(decode-time '${sexp})`}`) + .stdout; + const [, minutes, hours, date, month, year] = parsed.split(" "); + return `${year}-${month.padStart(2, "0")}-${date} ${hours}:${minutes.padStart( + 2, + "0" + )}`; +} \ No newline at end of file