Nodemailer email confirmation using Async/Await

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;

This is the route where I call it:

//imports including the mail_file.js

//somepath.js
router.post('/somepath',(req,res,next)=>{
      sendresetmail=async()=>
            {
                parameters={
                         //some email parameters
                }
                return await sendmail(params);

            }   
       sendmail()
       .then(response=>{
            //response is always false even when the mail is sent
             })
        .catch(err=>{
           //error
             })
  })

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


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;
} 
     

Maybe, nodemailer now supports async await but 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


As per the Nodemailer documentation:

All public Nodemailer methods support both callbacks and Promises (if callback is omitted). You need to have at least Node v8.0.0 if you want to use async..await with Nodemailer

An example can be found here: https://nodemailer.com/about/#example