2

When I try to retrieve emails through imap with the code below(using an async function), I get the following console output/error:

Inbox: undefined

/Users/mainuser/node_modules/imap/lib/Connection.js:432 cb(err, self._box); ^ TypeError: cb is not a function

var Imap = require('imap');
var inspect = require('util').inspect;

var imap = new Imap({
  user: 'mymailname@mail.com',
  password: 'mymailpassword',
  host: 'imap.mail.com',
  port: 993,
  tls: true
});

const openInbox = async () => {
  try {
    const inbox = await imap.openBox('INBOX', true)
    return inbox
  }catch(error){
    console.log("Error: "+ error)
  }
}

imap.once('ready', () => {
  console.log('ready')
  openInbox()
   .then(inbox => console.log('Inbox: ' + inbox))
});

imap.connect()

However, I can open the inbox and output the inbox Object using nested callbacks as shown below:

imap.once('ready', () => {
  imap.openBox('INBOX', true, (err, inbox) => {
    console.log('Inbox: ' + inbox)
  });
});

imap.connect()
Loup G
  • 169
  • 1
  • 11
  • Apparently the `imap` library does not support promises – Bergi Nov 09 '19 at 11:04
  • You’re right, it doesn’t. Just looking for a way to promising the library now, any ideas? I’ve tried using bluebird promisifyall, no dice. You can see the comments under the answer below. Thanks – Loup G Nov 09 '19 at 13:39
  • Update: The imap-simple library was published in Apr 2020. It has promises built in, and IMO makes async functions much simpler. https://www.npmjs.com/package/imap-simple – Shaun Jul 19 '20 at 18:16

1 Answers1

5

If you prefer to work with promises you should either write a custom wrapper around imap.openBox or wrap it with Node.js built-in util.promisify function:

const Imap = require('imap');
const promisify = require('util').promisify;

const imap = new Imap({
  user: 'mymailname@mail.com',
  password: 'mymailpassword',
  host: 'imap.mail.com',
  port: 993,
  tls: true
});

const openBox = promisify(imap.openBox.bind(imap));

imap.once('ready', () => {
  console.log('ready')
  openBox('INBOX', true)
    .then(inbox => console.log(inbox))
    .catch(err => {
      console.log(err)
    })
});

imap.connect()

In order to promisify the entire API, try to wrap the imap instance in Bluebird.promisifyAll. Note the promisified methods are available with Async prefix:

const bluebird = require('bluebird');
const Imap = require('imap');

const imap = bluebird.promisifyAll(new Imap({
    user: 'mymailname@mail.com',
    password: 'mymailpassword',
    host: 'imap.mail.com',
    port: 993,
    tls: true
}));

imap.once('ready', () => {
  console.log('ready')
  imap.openBoxAsync('INBOX', true)
    .then(inbox => console.log(inbox))
    .catch(err => {
      console.log(err)
    })
});

imap.connect()
antonku
  • 7,377
  • 2
  • 15
  • 21
  • Thanks. I was hoping that I could work with Asyn / Await functions. Never the less, this brings me closer to the solution. After I promisified imap.openbox by doing this:const openBox = promisify(imap.openBox.bind(imap)); I'm able to now successfully log the inbox object. The only question now is: how can I Promisify the ENTIRE imap API? – Loup G Nov 09 '19 at 10:12
  • Hi @LoupG, you can try to use Bluebird.promisifyAll to promisify the entire API. I have updated the answer – antonku Nov 09 '19 at 11:32
  • Hi, I had tried that before put up my comment response to your answer, I guess I should have said so. Have you tried it? If it worked for you, can you put the code up as part of the answer. Thanks in advance – Loup G Nov 09 '19 at 13:42
  • Yes, it worked for me. I have added the code that leverages `bluebird.promisifyAll` to the answer – antonku Nov 09 '19 at 13:48
  • Thanks a lot, I had not realized that the promisify library renames the methods my appending promisify to the method name! – Loup G Nov 09 '19 at 14:05