Nodemailer email confirmation using Async/Await

20,858

Solution 1

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

Solution 2

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

Share:
20,858
Abdul Ahad
Author by

Abdul Ahad

Updated on January 12, 2022

Comments

  • Abdul Ahad
    Abdul Ahad over 2 years

    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

  • Abdul Ahad
    Abdul Ahad almost 5 years
    Thanks, it worked but could you tell me what happened here and if there are any other ways to do this, like using async/await or then/catch?
  • newguy
    newguy almost 4 years
    As of May, 2020 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<SentMessageInfo>;
  • Asleepious
    Asleepious over 2 years
    This was and still is a great answer, even though the library now supports async, and "omit the callback" is now the answer to the question. This answer is at least my first result googling "nodemailer sendMail with promises" so I think it would be useful to edit @newguy 's comment at the top of the original answer, for future seekers.