move() is only copying message #358

Closed
mikehedman opened this Issue Mar 8, 2014 · 6 comments

Comments

Projects
None yet
3 participants

I am trying to move select messages from the Inbox to a spam folder. The right messages are ending up in the spam folder, but they also stay in the inbox. Is this my bug, a server issue, or an issue with node-imap?

Here's the code:

var Imap = require('imap');

var imap = new Imap({
  user: 'xxxx',
  password: 'yyyy',
  host: 'secure.emailsrvr.com',
  port: 143,
  tlsOptions: {
    rejectUnauthorized:false
  },
  autotls: 'always'
});

function openInbox(cb) {
  imap.openBox('INBOX', false, cb);
}

imap.once('ready', function() {
  openInbox(function(err, box) {
    if (err) throw err;
    var f = imap.seq.fetch((box.messages.total - 10) + ':*', {
      bodies: 'HEADER.FIELDS (FROM TO SUBJECT DATE)',
      struct: true
    });
    f.on('message', function(msg, seqno) {
      msg.on('body', function(stream, info) {
        var buffer = '';
        stream.on('data', function(chunk) {
          buffer += chunk.toString('utf8');
        });
        stream.once('end', function() {
          var header = Imap.parseHeader(buffer);
          var subject = header['subject'][0];
          if (subject.indexOf('Refund failure') == 0 ) {
            imap.seq.move(seqno, 'node', function(err) {
              console.log('Move error: ' + err);
            });
          }
        });
      });
    });
    f.once('error', function(err) {
      console.log('Fetch error: ' + err);
    });
    f.once('end', function() {
      imap.end();
    });
  });
});

imap.connect();

Thanks! Mike

Owner

mscdex commented Mar 8, 2014

Can you set debug: console.log in the constructor object and post the output somewhere?

Here's what I think is the relevant part of the output:
<= '+ idling'
<= 'IDLE OK Idle completed.'
=> 'A8 COPY 838 "node"'
<= 'A8 OK [COPYUID 1345047984 77272 33] Copy completed.'
=> 'A9 COPY 839 "node"'
<= 'A9 OK [COPYUID 1345047984 77273 34] Copy completed.'
=> 'A10 LOGOUT'
<= '* BYE Logging out'
<= 'A10 OK Logout completed.'
[connection] Ended
Connection ended
[connection] Closed

Thanks!

Owner

mscdex commented Mar 8, 2014

I think it may be because you're logging out too early and it hasn't been given the chance to remove the source messages in the current mailbox. This 'copy then delete' process is only used on servers that don't support better moving methods (e.g. the MOVE capability, which does it all in one command).

You might try something like this:

imap.once('ready', function() {
  openInbox(function(err, box) {
    if (err) throw err;
    var f = imap.seq.fetch((box.messages.total - 10) + ':*', {
      bodies: 'HEADER.FIELDS (FROM TO SUBJECT DATE)',
      struct: true
    });
    var moveUIDs = [];
    f.on('message', function(msg, seqno) {
      var shouldMove, uid;
      msg.on('body', function(stream, info) {
        var buffer = '';
        stream.on('data', function(chunk) {
          buffer += chunk.toString('utf8');
        });
        stream.once('end', function() {
          var header = Imap.parseHeader(buffer);
          var subject = header['subject'][0];
          if (subject.indexOf('Refund failure') === 0) {
            shouldMove = true;
            if (uid !== undefined)
              moveUIDs.push(uid);
          }
        });
      });
      msg.once('attributes', function(attrs) {
        uid = attrs.uid;
        if (shouldMove === true)
          moveUIDs.push(uid);
      });
    });
    f.once('error', function(err) {
      console.log('Fetch error: ' + err);
    });
    f.once('end', function() {
      var uidsLeft = moveUIDs.length;
      if (uidsLeft) {
        moveUIDs.forEach(function(uid) {
          imap.move(uid, 'node', function(err) {
            if (err)
              console.log('Move error: ' + err);
            if (--uidsLeft === 0)
              imap.end();
          });
        });
        return;
      }
      imap.end();
    });
  });
});

If I were British, I would say: "that worked a treat". Thanks, it's working great now.
I have hopes to turn this into a full blown mail sorter (work email is on Rackspace mail, and the rules are rather weak). I'll give you a shout if/when I get it done.
Thanks!!

mikehedman closed this Mar 9, 2014

I got my project done, and it's working away on my server. Here it is: https://github.com/mikehedman/imap-mail-rules
Again, thank you for your help. And thanks for the idea of how to do a parameterized unit test with an array of testcases and a foreach...I'm doing that everywhere now 👍

bblack commented Jun 5, 2014

I ran into this issue today. @mscdex how do you feel about a verson of imap#end that waits until all expected responses for pending commands have come back?

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment