134 lines
3.2 KiB
JavaScript
134 lines
3.2 KiB
JavaScript
|
'use strict';
|
||
|
|
||
|
const MailParser = require('./mail-parser.js');
|
||
|
|
||
|
module.exports = (input, options, callback) => {
|
||
|
if (!callback && typeof options === 'function') {
|
||
|
callback = options;
|
||
|
options = false;
|
||
|
}
|
||
|
|
||
|
let promise;
|
||
|
if (!callback) {
|
||
|
promise = new Promise((resolve, reject) => {
|
||
|
callback = callbackPromise(resolve, reject);
|
||
|
});
|
||
|
}
|
||
|
|
||
|
options = options || {};
|
||
|
let keepCidLinks = !!options.keepCidLinks;
|
||
|
|
||
|
let mail = {
|
||
|
attachments: []
|
||
|
};
|
||
|
|
||
|
let parser = new MailParser(options);
|
||
|
|
||
|
parser.on('error', err => {
|
||
|
callback(err);
|
||
|
});
|
||
|
|
||
|
parser.on('headers', headers => {
|
||
|
mail.headers = headers;
|
||
|
mail.headerLines = parser.headerLines;
|
||
|
});
|
||
|
|
||
|
let reading = false;
|
||
|
let reader = () => {
|
||
|
reading = true;
|
||
|
|
||
|
let data = parser.read();
|
||
|
|
||
|
if (data === null) {
|
||
|
reading = false;
|
||
|
return;
|
||
|
}
|
||
|
|
||
|
if (data.type === 'text') {
|
||
|
Object.keys(data).forEach(key => {
|
||
|
if (['text', 'html', 'textAsHtml'].includes(key)) {
|
||
|
mail[key] = data[key];
|
||
|
}
|
||
|
});
|
||
|
}
|
||
|
|
||
|
if (data.type === 'attachment') {
|
||
|
mail.attachments.push(data);
|
||
|
|
||
|
let chunks = [];
|
||
|
let chunklen = 0;
|
||
|
data.content.on('readable', () => {
|
||
|
let chunk;
|
||
|
while ((chunk = data.content.read()) !== null) {
|
||
|
chunks.push(chunk);
|
||
|
chunklen += chunk.length;
|
||
|
}
|
||
|
});
|
||
|
|
||
|
data.content.on('end', () => {
|
||
|
data.content = Buffer.concat(chunks, chunklen);
|
||
|
data.release();
|
||
|
reader();
|
||
|
});
|
||
|
} else {
|
||
|
reader();
|
||
|
}
|
||
|
};
|
||
|
|
||
|
parser.on('readable', () => {
|
||
|
if (!reading) {
|
||
|
reader();
|
||
|
}
|
||
|
});
|
||
|
|
||
|
parser.on('end', () => {
|
||
|
['subject', 'references', 'date', 'to', 'from', 'to', 'cc', 'bcc', 'message-id', 'in-reply-to', 'reply-to'].forEach(key => {
|
||
|
if (mail.headers.has(key)) {
|
||
|
mail[key.replace(/-([a-z])/g, (m, c) => c.toUpperCase())] = mail.headers.get(key);
|
||
|
}
|
||
|
});
|
||
|
|
||
|
if (keepCidLinks) {
|
||
|
return callback(null, mail);
|
||
|
}
|
||
|
parser.updateImageLinks(
|
||
|
(attachment, done) => done(false, 'data:' + attachment.contentType + ';base64,' + attachment.content.toString('base64')),
|
||
|
(err, html) => {
|
||
|
if (err) {
|
||
|
return callback(err);
|
||
|
}
|
||
|
mail.html = html;
|
||
|
|
||
|
callback(null, mail);
|
||
|
}
|
||
|
);
|
||
|
});
|
||
|
|
||
|
if (typeof input === 'string') {
|
||
|
parser.end(Buffer.from(input));
|
||
|
} else if (Buffer.isBuffer(input)) {
|
||
|
parser.end(input);
|
||
|
} else {
|
||
|
input
|
||
|
.once('error', err => {
|
||
|
input.destroy();
|
||
|
parser.destroy();
|
||
|
callback(err);
|
||
|
})
|
||
|
.pipe(parser);
|
||
|
}
|
||
|
|
||
|
return promise;
|
||
|
};
|
||
|
|
||
|
function callbackPromise(resolve, reject) {
|
||
|
return function(...args) {
|
||
|
let err = args.shift();
|
||
|
if (err) {
|
||
|
reject(err);
|
||
|
} else {
|
||
|
resolve(...args);
|
||
|
}
|
||
|
};
|
||
|
}
|