Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

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;

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

like image 214
Abdul Ahad Avatar asked Jun 08 '19 16:06

Abdul Ahad


2 Answers

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

like image 166
Andrew Avatar answered Oct 21 '22 17:10

Andrew


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;
} 
     
like image 38
Ganesh Karewad Avatar answered Oct 21 '22 17:10

Ganesh Karewad