Javascript 通过 nodemailer 向多个收件人发送电子邮件

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/28527561/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-08-23 01:56:40  来源:igfitidea点击:

Sending email to multiple recipients via nodemailer

javascriptnode.jsnodemailer

提问by Atul Sharma

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 three times. What's wrong with my code?

我正在尝试向多个收件人发送电子邮件。为此,我创建了一个收件人数组,但使用我的代码,我只能将邮件发送到该数组的最后一个电子邮件 ID 三次。我的代码有什么问题?

var nodemailer = require("nodemailer");

var smtpTransport = nodemailer.createTransport(
"SMTP",{
  host: '',
  //  secureConnection: true,         // use SSL
  port: 25
});

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: "*******"    
    //  html: "<b>Hello world ?</b>" // html body
}


maillist.forEach(function (to, i , array) {
  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(); }
  });
});

采纳答案by eenagy

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

您的问题是从异步代码中引用相同的 msg 对象。foreach 在 sendMail 发送电子邮件之前完成。

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

所以 msg.to 将是邮件列表对象的最后一项。

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

尝试在邮件列表 foreach 中克隆/复制 msg,或者只是将 msg 定义移动到那里:

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) {

回答by pkyeck

nodemailer (v2.4.2) docssay:

nodemailer (v2.4.2)文档说:

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

to- 逗号分隔的列表或收件人电子邮件地址数组将出现在收件人:字段中

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
}

回答by ackuser

As far as I know you will be able to get multiple recipients like this

据我所知,您将能够获得多个这样的收件人

"[email protected],[email protected],[email protected],[email protected]"

So why you don't do something like

那么为什么你不做类似的事情

var maillist = '****.sharma3@****.com, ****.bussa@****.com, ****.gawri@****.com';

var msg = {
    from: "******", // sender address
    to: maillist,
    subject: "Hello ?", // Subject line
    text: "Hello This is an auto generated Email for ...  ?", // plaintext body
    cc: "*******"    
    //  html: "<b>Hello world ?</b>" // html body
}

I have already tried and it is working. Furthermore, from my point of view, why you have to worry about "asynchronously" or sending emails 1K times if you have the capability of sending all of them only in once without any complication?

我已经尝试过了,它正在工作。此外,在我看来,如果您能够一次发送所有电子邮件而没有任何复杂性,为什么还要担心“异步”或发送 1000 次电子邮件?

Anyway hope this help, answer your question or it may help somebody else

无论如何,希望这会有所帮助,回答您的问题,否则可能对其他人有所帮助

Surely, my answer can be improved..

当然,我的答案可以改进..

回答by Nitin Kumar

var maillist = [
  '****.sharma3@****.com',
  '****.bussa@****.com',
  '****.gawri@****.com',
];

maillist.toString();

var msg = {
    from: "******", // sender address
    to: maillist,
    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
}

回答by bmpickford

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

异步执行的一个好方法是使用 async 模块中的 each 函数: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
});

回答by Klexzi

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.

sendMail 方法实际上在 forEach 循环完成后得到解决,但问题是 sendMail 方法不返回承诺类型,因此如果您尝试等待它,它仍然无法正常工作。

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

所以你需要做的是为 sendmail 创建一个单独的函数,因此使它成为这样的承诺

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

回答by sword fish

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

回答by satchcoder

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.

您正在异步发送电子邮件,因此您需要一个等待功能,等待所有邮件发送完毕,因为如果没有,您的程序将退出并且某些请求未得到满足。因此,您必须执行某种超时功能来检查电子邮件是否已发送。