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