Nodemailer email confirmation using Async/Await

Viewed 26029

I am sending mails using nodemailer. I need to know if the mail is sent or not and then update my database but the mail is sent in the transporter(which I do not think returns promises) which takes time and hence the return is always false, even if the mail is sent.

This is my mail sending file which I call from other routes

// mail_file.js
// imports

sendmail = async (req) => {
  let transporter = nodemailer.createTransport({
    // settings
  });
  var mailOptions = {
    // mailoptions
  };
  let resp = false;
  await transporter.sendMail(mailOptions, function (error, info) {
    if (error) {
      console.log('error is ' + error);
      resp = false;
    } else {
      console.log('Email sent: ' + info.response);
      resp = true;
    }
  });
  return resp;
};

module.exports = sendmail;

When I log the info of the mail, it is after the logging of the response of the sendmail function in the somepath.js

2 Answers

Nodemailer v6.4.8 supports both synchronous version and asynchronous version of sendMail.sendMail(mailOptions: Mail.Options, callback: (err: Error | null, info: SentMessageInfo) => void): void; sendMail(mailOptions: Mail.Options): Promise;

This answer still helps someone who needs to understand how to promisify a function that uses callbacks. Linking an article that explains the same thing https://letsdqode.blogspot.com/2022/01/using-callbacks-with-async-await-or.html

Original Answer: transporter.sendMail does not return a promise, it uses a callback function. change your code

  return new Promise((resolve,reject)=>{
 let transporter = nodemailer.createTransport({
    //settings
 });
var mailOptions = {
   //mailoptions
};
let resp=false;

transporter.sendMail(mailOptions, function(error, info){
    if (error) {
        console.log("error is "+error);
       resolve(false); // or use rejcet(false) but then you will have to handle errors
    } 
   else {
       console.log('Email sent: ' + info.response);
       resolve(true);
    }
   });
 })  

}

as I said earlier, transport.sendMail() function uses call back that's why you can not use await there.But you can write a wrapper function around it so that you can use await in your functions where you need more readble and clean code. just consider the following example

async function wrapedSendMail(mailOptions){
    return new Promise((resolve,reject)=>{
    let transporter = nodemailer.createTransport({//settings});

 transporter.sendMail(mailOptions, function(error, info){
    if (error) {
        console.log("error is "+error);
       resolve(false); // or use rejcet(false) but then you will have to handle errors
    } 
   else {
       console.log('Email sent: ' + info.response);
       resolve(true);
    }
   });
   }
   })

Now you can use this wrappedSendMail function in your other functions like below,

 sendmail= async(req)=>{      
  var mailOptions = {
      //mailoptions
  };
  let resp= await wrapedSendMail(mailOptions);
  // log or process resp;
   return resp;
} 
     
Related