可以将文章内容翻译成中文,广告屏蔽插件可能会导致该功能失效(如失效,请关闭广告屏蔽插件后再试):
问题:
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?
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(); }
});
});
回答1:
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) {
回答2:
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
}
回答3:
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?
Anyway hope this help, answer your question or it may help somebody else
Surely, my answer can be improved..
回答4:
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
}
回答5:
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
});
回答6:
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.
回答7:
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();
}
});
});
};