thunderbird2docuware/lib/mail.js

105 lines
3.5 KiB
JavaScript
Raw Normal View History

// Extraktion von Mail-Inhalten über die Thunderbird messages.* API.
const Mail = {
/** Rohe RFC822-Nachricht als .eml-File. */
async getEmlFile(messageId, subject) {
const raw = await browser.messages.getRaw(messageId); // String (RFC822)
const blob = new Blob([raw], { type: "message/rfc822" });
const name = `${this._safeName(subject) || "email"}.eml`;
return new File([blob], name, { type: "message/rfc822" });
},
/** Kopf + Body als strukturierte Metadaten zum Vorbefüllen. */
async getMeta(messageId) {
const header = await browser.messages.get(messageId);
const full = await browser.messages.getFull(messageId);
const bodyText = this._extractText(full);
const sender = this._parseAddress(header.author);
const account = await this._accountForMessage(messageId);
return {
subject: header.subject || "",
senderEmail: sender.email,
senderName: sender.name,
to: (header.recipients || []).join(", "),
cc: (header.ccList || []).join(", "),
bcc: (header.bccList || []).join(", "),
date: header.date instanceof Date ? header.date : new Date(header.date),
bodyText,
account,
direction: this._direction(header, account),
sizeBytes: header.size || 0,
};
},
/** Liste der Anhänge: [{partName, name, contentType, size}]. */
async listAttachments(messageId) {
const atts = await browser.messages.listAttachments(messageId);
return (atts || [])
.filter((a) => a.partName && a.name) // echte Datei-Anhänge
.map((a) => ({
partName: a.partName,
name: a.name,
contentType: a.contentType,
size: a.size || 0,
}));
},
/** Anhang als File holen. */
async getAttachmentFile(messageId, partName) {
return browser.messages.getAttachmentFile(messageId, partName); // File
},
// --- Helfer ---------------------------------------------------------------
_extractText(fullPart) {
// Rekursiv den ersten text/plain-Teil suchen, sonst text/html entkernen.
let plain = "";
let html = "";
const walk = (part) => {
if (!part) return;
if (part.contentType === "text/plain" && part.body) plain += part.body;
else if (part.contentType === "text/html" && part.body) html += part.body;
(part.parts || []).forEach(walk);
};
walk(fullPart);
if (plain.trim()) return plain;
if (html.trim()) return html.replace(/<[^>]+>/g, " ").replace(/\s+/g, " ").trim();
return "";
},
_parseAddress(str) {
if (!str) return { name: "", email: "" };
const m = str.match(/^\s*"?([^"<]*)"?\s*<([^>]+)>\s*$/);
if (m) return { name: m[1].trim(), email: m[2].trim() };
return { name: "", email: str.trim() };
},
async _accountForMessage(messageId) {
try {
const msg = await browser.messages.get(messageId);
const folder = msg.folder;
if (folder && folder.accountId) {
const acc = await browser.accounts.get(folder.accountId);
return acc ? acc.name : "";
}
} catch (_) {}
return "";
},
_direction(header, accountName) {
// Heuristik: ist der Account-Name/eine Identität Absender -> Ausgang.
// Robustere Erkennung erfolgt später über Identitäten; v1 simpel:
const folderType = header.folder && header.folder.type;
if (folderType === "sent" || folderType === "outbox") return "Ausgang";
return "Eingang";
},
_safeName(s) {
return (s || "").replace(/[\\/:*?"<>|]+/g, "_").slice(0, 80).trim();
},
};
if (typeof module !== "undefined") module.exports = { Mail };