简体   繁体   English

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

[英]Sending email to multiple recipients via nodemailer

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.为此,我创建了一个收件人数组,但使用我的代码,我只能将邮件发送到该数组的最后一个电子邮件 ID 三次。 What's wrong with my code?我的代码有什么问题?

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

nodemailer (v2.4.2) docs say: 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
}

As far as I know you will be able to get multiple recipients like this据我所知,您将能够获得多个这样的收件人

"mail1@mail.com,mail2@mail.com,mail3@mail.com,mail4@mail.com"

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..当然,我的答案可以改进..

Your problem is referencing the same msg object from async code.您的问题是从异步代码中引用相同的 msg 对象。 The foreach completes before the sendMail would send out the emails. 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) {
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
}

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
});
let info = await transporter.sendMail({
  from: [{ name: "sender Name", address: "sender@example.com" }], // sender address
  to: [
    { name: "Receiver Name 1", address: "receiver1@example.com" },
    { name: "Receiver Name 2", address: "receiver2@example.com" },
  ],
  subject: "Hey you, awesome!",
  html: "<b>This is bold text</b>",
  text: "This is text version!",
});
  • You can send email to multiple recipient by keeping inside the array of objects where name is Receiver name and address is the receiver email address.您可以通过保留在名称是收件人姓名和地址是收件人电子邮件地址的对象数组中来向多个收件人发送电子邮件。
  • In Above way I am able to send email to multiple recipient.通过上述方式,我可以向多个收件人发送电子邮件。

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

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.因此,您必须执行某种超时功能来检查电子邮件是否已发送。

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

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM