diff --git a/dev/Mime/Parser.js b/dev/Mime/Parser.js index eb13c199b..7d037b054 100644 --- a/dev/Mime/Parser.js +++ b/dev/Mime/Parser.js @@ -76,6 +76,10 @@ export function ParseMime(text) return text.slice(this.start, this.end); } + get headRaw() { + return Object.keys(this.headers || {}).length ? text.slice(this.start, this.bodyStart) : ''; + } + get bodyRaw() { return text.slice(this.bodyStart, this.bodyEnd); } @@ -127,6 +131,16 @@ export function ParseMime(text) // mailbox-list or address-list const lists = ['from','reply-to','to','cc','bcc']; + const isHead = (candidate) => + { + // Unfold potential header lines: join lines that start with whitespace with previous line + let lines = candidate.replace(/\r?\n([ \t])/g, '$1'); + lines = lines.split(/\r?\n/).filter(line => line.trim() !== ''); + const headerLines = lines.filter(line => /^[\w-]+:\s*.+/.test(line)); + // Heuristic: if more than 50% of lines look like headers, we consider it a header section + return (headerLines.length > 0 && headerLines.length / lines.length > 0.5); + } + const ParsePart = (mimePart, start_pos = 0, id = '') => { let part = new MimePart, @@ -140,7 +154,7 @@ export function ParseMime(text) part.parts = []; // get headers - if (head) { + if (isHead(head)) { head.replace(/\r?\n\s+/g, ' ').split(/\r?\n/).forEach(header => { let match = header.match(/^([^:]+):\s*([^;]+)/), params = {}; @@ -191,9 +205,8 @@ export function ParseMime(text) } }); } - - part.headers = headers; } + part.headers = headers; return part; }; diff --git a/dev/Mime/Utils.js b/dev/Mime/Utils.js index 4927898f3..6770589f2 100644 --- a/dev/Mime/Utils.js +++ b/dev/Mime/Utils.js @@ -13,7 +13,7 @@ import { EmailModel } from 'Model/Email'; export function MimeToMessage(data, message) { const struct = ParseMime(data); - if (struct.headers) { + if (struct.headRaw) { let html = struct.getByContentType('text/html'), subject = struct.headerValue('subject'); html = html ? html.body : '';