Sending email to multiple recipients via nodemailer

后端 未结 8 1769
青春惊慌失措
青春惊慌失措 2020-12-25 11:19

I am trying to send email to multiple recipients. For this I have created an array of recipients, but with my code I am only able to send mail to last email ID of the array

相关标签:
8条回答
  • 2020-12-25 11:31
    maillist.forEach(function (to, i , array) {
      (function(i,to){
         msg.to = to;
      smtpTransport.sendMail(msg, function (err) {
        if (err) { 
          console.log('Sending to ' + to + ' failed: ' + err);
          return;
        } else { 
          console.log('Sent to ' + to);
        }
    
        if (i === maillist.length - 1) { msg.transport.close(); }
      });
    })(i,to)
    });
    
    0 讨论(0)
  • 2020-12-25 11:34

    nodemailer (v2.4.2) docs say:

    to - Comma separated list or an array of recipients e-mail addresses that will appear on the To: field

    so you can just do:

    var maillist = [
      '****.sharma3@****.com',
      '****.bussa@****.com',
      '****.gawri@****.com',
    ];
    
    var msg = {
        from: "******", // sender address
        subject: "Hello ✔", // Subject line
        text: "Hello This is an auto generated Email for testing  from node please ignore it  ✔", // plaintext body
        cc: "*******",
        to: maillist
    }
    
    0 讨论(0)
  • 2020-12-25 11:35

    You are sending the emails asynchronously so you need a waiting function that waits for all the mails till they have been sent because if not, you program exits and some of the requests are not fulfilled. So you have to do sort of a timeout function that checks if the emails have been sent.

    0 讨论(0)
  • 2020-12-25 11:36

    The sendMail method is actually gets resolved after the forEach loop finishes, but the issue is the sendMail method does not return a type of promise, so if you try awaiting this, it still wont work.

    so what you need to do is to create a separate function for sendmail therefore making it a promise like this

        const send = (transporter: any, mailOptions: any) => {
        return new Promise((resolve, reject) => {
            transporter.sendMail(mailOptions, (error: any, info: any) => {
              if (error) {
                return reject(error);
              } else {
                return resolve();
              }
            });
        });
        };
    

    so this enables to await this and therefore the iterator will wait for the process to finish before going to the next loop.

    The full code should look like this

        let transporter = nodemailer.createTransport({
          host: "mail.smtp.com", // your server host address
          port: 587, // port
          secure: false, // use TLS // true for 465, false for other ports
          auth: {
            user: EMAIL_USER, // your email address
            pass: EMAIL_PSW, // your password
          },
          tls: {
            rejectUnauthorized: false
          }
        });
    
        // store an array of errors if any
        let successful: any[] = [];
        let failed: any[] = [];
        await recipients.forEach(async (to, i) => {
          let mailOptions = {
            from, // sender address
            to, // list of receivers
            subject, // Subject line
            text // plain text body
          };
    
          if (html) {
            (mailOptions as any).html = html;
          }
    
          // send mail with defined transport object
          // here we use the fuction we created which is now a promise
          await send(transporter, mailOptions)
            .then(() => {
              successful.push({ success: true, to });
            })
            .catch(reason => {
              failed.push({ success: false, to, message: reason });
            });
          if (i === recipients.length - 1) {
            if (failed.length === recipients.length) {
              return reject({ failed });
            } else {
              return resolve({ successful, failed });
            }
          }
        });
      });
    
    
    const send = (transporter: any, mailOptions: any) => {
    return new Promise((resolve, reject) => {
        transporter.sendMail(mailOptions, (error: any, info: any) => {
          if (error) {
            return reject(error);
          } else {
            return resolve();
          }
        });
    });
    };
    
    0 讨论(0)
  • 2020-12-25 11:38

    A good way to do it asynchronously would be to use the each function in the async module: https://caolan.github.io/async/docs.html#each

    var async = require("async");
    
    async.each(maillist, function(to, callback){
    
        msg.to = to;
    
        smtpTransport.sendMail(msg, function (err) {
            if (err) { 
                console.log('Sending to ' + to + ' failed: ' + err);
                callback(err);
            } else { 
                console.log('Sent to ' + to);
                callback();
            }
        });
    }, function(err){
        if(err){
            console.log("Sending to all emails failed:" + err);
        }
    
        //Do other stuff or return appropriate value here
    });
    
    0 讨论(0)
  • 2020-12-25 11:43

    Your problem is referencing the same msg object from async code. The foreach completes before the sendMail would send out the emails.

    So msg.to wil be the last item from the maiilist object.

    Try to clone/copy msg inside maillist foreach, or just move msg definition to there :

    maillist.forEach(function (to, i , array) {
    
    
      var msg = {
            from: "******", // sender address
            subject: "Hello ✔", // Subject line
            text: "Hello This is an auto generated Email for testing  from node please ignore it  ✔", // plaintext body
            cc: "*******"    
            //  html: "<b>Hello world ✔</b>" // html body
        }
      msg.to = to;
    
      smtpTransport.sendMail(msg, function (err) {
    
    0 讨论(0)
提交回复
热议问题