Mail to PDF - initial commit
commit
1b44541a1e
@ -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`
|
@ -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\>.*\<\/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(/</g, "<");
|
||||
}
|
||||
|
||||
const to_download = attachments
|
||||
.split("\n")
|
||||
.slice(1)
|
||||
.filter((line) => 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 */ `<li>
|
||||
${filename}<img style="width: 100%" src="data:${mime};base64,${base64}" />
|
||||
</li>`
|
||||
)
|
||||
.join("\n");
|
||||
|
||||
html = html.replace(
|
||||
/<\/body>/i,
|
||||
/* HTML */ `<hr/><h3>Załączniki:</h3>
|
||||
<ul>
|
||||
${attachments_items}
|
||||
</ul></body>`
|
||||
);
|
||||
|
||||
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(
|
||||
/<body>/i,
|
||||
`<body>` +
|
||||
/* HTML */ `<h1>${subject}</h1>
|
||||
<table>
|
||||
<tr>
|
||||
<th>Temat wiadomości:</th>
|
||||
<td>${subject}</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<th>Wysłano:</th>
|
||||
<td>${escape(date)}</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<th>Od:</th>
|
||||
<td>${escape(from)}</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<th>Do:</th>
|
||||
<td>${escape(to)}</td>
|
||||
</tr>
|
||||
</table>`
|
||||
);
|
||||
|
||||
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"
|
||||
)}`;
|
||||
}
|
Loading…
Reference in New Issue