简体   繁体   English

解码使用 imap nodejs 检索到的 base64 图像 email 附件

[英]Decoding base64 image email attachment retrieved using imap nodejs

I'm attempting to retrieve an e-mail attachment image using Node.js imap that can be found here: https://github.com/mscdex/node-imap我正在尝试使用 Node.js imap 检索电子邮件附件图像,可以在此处找到: https://github.com/mscdex/node-imap

After retrieving the image I want to save it to file and then save the name in the MySQL database so I can retrieve it in the front end using EJS.检索图像后,我想将其保存到文件中,然后将名称保存在 MySQL 数据库中,以便我可以使用 EJS 在前端检索它。

I've gotten as far as retrieving the e-mail attachment image and attempting to decode it and then save it.我已经检索到电子邮件附件图像并尝试对其进行解码然后保存。 Unfortunately when opened from the folder it says: "It appears that we don't support this file format".不幸的是,当从文件夹中打开时,它显示:“我们似乎不支持这种文件格式”。

Upon further investigation, if I convert it to a base64 string using this online tool: https://www.motobit.com/util/base64-decoder-encoder.asp and then go to a base64 to image converter ( https://codebeautify.org/base64-to-image-converter ), it shows the image just fine. Upon further investigation, if I convert it to a base64 string using this online tool: https://www.motobit.com/util/base64-decoder-encoder.asp and then go to a base64 to image converter ( https:// codebeautify.org/base64-to-image-converter ),它可以很好地显示图像。

I'm skeptical that my code is actually converting the image to base64 as the file size goes up from 250kb to 332kb.我怀疑我的代码实际上是将图像转换为 base64,因为文件大小从 250kb 增加到 332kb。

I am unsure of how to proceed to allow the photo to be properly decoded for viewing as the original.jpeg image.我不确定如何继续允许正确解码照片以查看 original.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();

The expected output is a.jpeg image saved to the file directory that is able to be viewed.预期的output是一个.jpeg图像,保存到可以查看的文件目录中。 The actual output I am getting is an image file that when double clicked to view says: "It appears that we don't support this file format."我得到的实际 output 是一个图像文件,双击查看时显示:“看来我们不支持这种文件格式。”

Unfortunately, I couldn't find a way to use node-imap to properly decode and retrieve email attachments.不幸的是,我找不到使用 node-imap 正确解码和检索 email 附件的方法。 I ended up using imap-simple instead and was able to achieve the desired result.我最终改用imap-simple并能够达到预期的结果。

I used imap-simple's example code block to retrieve attachments.我使用 imap-simple 的示例代码块来检索附件。

var imaps = require('imap-simple');

var config = {
    imap: {
        user: 'your@email.address',
        password: 'yourpassword',
        host: 'imap.gmail.com',
        port: 993,
        tls: true,
        authTimeout: 3000
    }
};

imaps.connect(config).then(function (connection) {

connection.openBox('INBOX').then(function () {

    // Fetch emails from the last 24h
    var delay = 24 * 3600 * 1000;
    var yesterday = new Date();
    yesterday.setTime(Date.now() - delay);
    yesterday = yesterday.toISOString();
    var searchCriteria = ['UNSEEN', ['SINCE', yesterday]];
    var fetchOptions = { bodies: ['HEADER.FIELDS (FROM TO SUBJECT DATE)'], struct: true };

    // retrieve only the headers of the messages
    return connection.search(searchCriteria, fetchOptions);
    }).then(function (messages) {

    var attachments = [];

    messages.forEach(function (message) {
        var parts = imaps.getParts(message.attributes.struct);
        attachments = attachments.concat(parts.filter(function (part) {
            return part.disposition && part.disposition.type.toUpperCase() === 'ATTACHMENT';
        }).map(function (part) {
            // retrieve the attachments only of the messages with attachments
            return connection.getPartData(message, part)
                .then(function (partData) {
                    return {
                        filename: part.disposition.params.filename,
                        data: partData
                    };
                });
        }));
    });

    return Promise.all(attachments);
    }).then(function (attachments) {
    console.log(attachments);
    // =>
    //    [ { filename: 'cats.jpg', data: Buffer() },
    //      { filename: 'pay-stub.pdf', data: Buffer() } ]
    });
});

On both instances of Base64Encode rename it to Base64Decode .Base64Encode的两个实例上将其重命名为Base64Decode

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM