【发布时间】:2020-02-06 03:39:56
【问题描述】:
我正在尝试使用可以在此处找到的 Node.js imap 检索电子邮件附件图像:https://github.com/mscdex/node-imap
检索图像后,我想将其保存到文件中,然后将名称保存在 MySQL 数据库中,以便我可以在前端使用 EJS 检索它。
我已经检索到电子邮件附件图像并尝试对其进行解码然后保存。不幸的是,当从文件夹中打开时,它显示:“我们似乎不支持这种文件格式”。
经过进一步调查,如果我使用此在线工具将其转换为 base64 字符串:https://www.motobit.com/util/base64-decoder-encoder.asp,然后转到 base64 到图像转换器 (https://codebeautify.org/base64-to-image-converter),它可以很好地显示图像。
我怀疑我的代码实际上是将图像转换为 base64,因为文件大小从 250kb 增加到 332kb。
我不确定如何继续允许正确解码照片以作为原始 .jpeg 图像查看。
var fs = require('fs'), fileStream;
var {Base64Encode} = require('base64-stream');
const Imap = require('imap'),
inspect = require('util').inspect;
var imap = new Imap({
user: 'gmailaccount@gmail.com',
password: 'gmailaccount',
host: 'imap.gmail.com',
port: 993,
tls: true
});
/* To Uppercase function */
function toUpper(thing) { return thing && thing.toUpperCase ? thing.toUpperCase() : thing;}
/* function to find attachments in imap email */
function findAttachmentParts(struct, attachments) {
attachments = attachments || [];
for (var i = 0, len = struct.length, r; i < len; ++i) {
if (Array.isArray(struct[i])) {
findAttachmentParts(struct[i], attachments);
}
else {
if (struct[i].disposition && ['INLINE', 'ATTACHMENT'].indexOf(struct[i].disposition.type) > -1) {
attachments.push(struct[i]);
}
}
}
return attachments;
}
function buildAttMessageFunction(attachment) {
var filename = attachment.params.name;
var encoding = attachment.encoding;
return function (msg, seqno) {
var prefix = '(#' + seqno + ') ';
msg.on('body', function(stream, info) {
//Create a write stream so that we can stream the attachment to file;
console.log(prefix + 'Streaming this attachment to file', filename, info);
var writeStream = fs.createWriteStream(filename);
writeStream.on('finish', function() {
console.log(prefix + 'Done writing to file %s', filename);
});
//stream.pipe(writeStream); this would write base64 data to the file.
//so we decode during streaming using
if (toUpper(encoding) === 'BASE64') {
//the stream is base64 encoded, so here the stream is decode on the fly and piped to the write stream (file)
stream.pipe(new Base64Encode()).pipe(writeStream);
} else {
//here we have none or some other decoding streamed directly to the file which renders it useless probably
stream.pipe(writeStream);
}
});
msg.once('end', function() {
console.log(prefix + 'Finished attachment %s', filename);
});
};
}
function openInbox(cb){
imap.openBox('INBOX', true, cb);
}
/* Take all unseen emails, output to console and save them to a text file */
imap.once('ready', function(){
openInbox(function(err, box){
if (err) throw err;
imap.search([ 'UNSEEN' ], function(err, results) {
var messages = [];
if (err) throw err;
var f = imap.fetch(results, { id: 1, bodies: ['HEADER.FIELDS (FROM TO SUBJECT DATE)', '1.1'], struct: true });
f.on('message', function(msg, seqno) {
var body = ''
, header = ''
, parsedMsg = {}
var prefix = '(#' + seqno + ') ';
msg.on('body', function(stream, info) {
var buffer = '', count = 0;
if(info.which === 'TEXT' || info.which === '1.1'){
stream.on('data', function(chunk) { body += chunk.toString('utf8') })
stream.once('end', function() { parsedMsg.body = body })
}
else{
stream.on('data', function(chunk) { header += chunk.toString('utf-8') })
stream.once('end', function() { parsedMsg.header = Imap.parseHeader(header) })
}
stream.pipe(fs.createWriteStream('msg-' + seqno + '-body.txt'));
});
msg.once('attributes', function(attrs) {
var attachments = findAttachmentParts(attrs.struct);
console.log(prefix + 'Has attachments: %d', attachments.length);
for(var i = 0, len = attachments.length; i < len; ++i){
var attachment = attachments[i];
/*This is how each attachment looks like {
partID: '2',
type: 'application',
subtype: 'octet-stream',
params: { name: 'file-name.ext' },
id: null,
description: null,
encoding: 'BASE64',
size: 44952,
md5: null,
disposition: { type: 'ATTACHMENT', params: { filename: 'file-name.ext' } },
language: null
}
*/
console.log(prefix + 'Fetching attachment %s', attachment.params.name);
var f = imap.fetch(attrs.uid , {
bodies: [attachment.partID],
struct: true
});
//build function to process attachment message
f.on('message', buildAttMessageFunction(attachment));
}
parsedMsg.attrs = attrs;
console.log(prefix + 'Attributes: %s', inspect(attrs, false, 8));
});
msg.once('end', function() {
console.log(prefix + 'Finished email');
messages.push( parsedMsg );
});
});
f.once('error', function(err) {
console.log('Fetch error: ' + err);
});
f.once('end', function() {
console.log('Done fetching all messages!');
for( i in messages ) {
console.log( i + ': ' + inspect( messages[i], false, 4 ) );
}
imap.end();
});
});
});
});
imap.once('error', function(err){
console.log(err);
});
imap.once('end', function(){
console.log('Connection ended');
});
imap.connect();
预期的输出是一个 .jpeg 图像,保存在可以查看的文件目录中。我得到的实际输出是一个图像文件,双击查看时显示:“看来我们不支持这种文件格式。”
【问题讨论】:
-
看起来您将其编码为 base64,而不是将其解码为 Base64,从而导致图像被双重编码。
-
@Max 我明白了,我也想多了。我正在关注这个线程(stackoverflow.com/questions/25247207/…),但该解决方案使用 base64.decode() 这不是一个函数。根据 base64-stream 文档,它“应该”是我编写它的方式,但看起来它是对它进行双重编码。因此,鉴于这些信息,我发现我必须找到一种正确的方法来从 base64 解码它并保存它。
-
看看 JS 函数 btoa 和 atob 。 Base64 编码解码已经内置在浏览器中。并且 node.js 在引擎盖下没有别的东西,因为 V8 是谷歌 chrome JS 引擎。
-
@ThomasLudewig 我会看看那些功能,谢谢。
-
@JMP 抱歉回复晚了,我最终使用 imap-simple 来检索附件,它似乎工作得很好 (npmjs.com/package/imap-simple) - 谢谢
标签: javascript node.js base64 imap