I am trying to implement a method to send emails to multiple recipients but also I want to pass to the html template the user attribute which will have the name of the recipient.
My code in this stage is like this:
SellerMatched: function (fromUser, offer, cb) {
var maillist = [];
var users = [];
for (var i=0; i<fromUser.length; i++)
{
maillist[i]=fromUser[i].email;
users[i] = fromUser[i].Name;
}
maillist.toString();
users.toString();
mail.sendMail({
from: 'Website Support <help@domain.com>',
to: maillist,
subject: 'Seller Matched',
template: 'SellerMatch',
context: {
user: users,
username: offer.owner.username,
OfferName: offer.name,
category: offer.category
}
}, cb);
}
and the html have those attributes: It's something like this:
...
Hi {{user}},
A offer is uploaded that matched your preference.
Offer detail:
Name : {{OfferName}}
By: {{username}}
Category: {{category}}
....
This is working properly, emails are sent to the recipients but in the attribute Hi {{user}}, I want to show only the name of recipient because now it shows the array of all recipients.
Thanks
This is working properly, emails are sent to the recipients but in the attribute Hi {{user}}, I want to show only the name of recipient because now it shows the array of all recipients.
The reason is, in your context object, you assign the users array to the user variable, and the template has no logic to call itself for a number of users found in the user variable.
The docs say about templating that you deal with 'object' - singular. In contrast, the docs explain under Common fields that to can take a comma separated list of recipients - plural. Very incomplete and I guess a bit confusing.
As @lichtjaeger and @mgiambanco stated, you need to handle the sending differently than you do right now. The EmailTemplate extension shows how to do it too.
You sending a single mail to multiple recipients. The render function is only called once.
You have two possibilities:
var promises = [];
for (var i = 0; i < fromUser.length; i++) {
promises.push(new Promise(function(resolve, reject) {
mail.sendMail({
from: 'Website Support <help@domain.com>',
to: fromUser[i].email,
subject: 'Seller Matched',
template: 'SellerMatch',
context: {
user: fromUser[i].Name,
username: offer.owner.username,
OfferName: offer.name,
category: offer.category
}
}, function(err, info) {
if (err) {
reject(err)
} else {
resolve(info)
}
});
}));
}
Promise.all(promises).then(function(infos) { cb(null, infos) }, function(err) { cb(err) });
I use Promises to collect all callbacks. If you can't use ES2015 you need to polyfill them or try an other solution.
Disadvantages: "To" contains only a single recipient. In error case you only get the first error and don't know which mails are sended and which not (and why).
I never tried this because it doesn't work on every client.
You should use push to add the users to the list
(all code untested - have never used nodemailer but this looks pretty basic)
for (var i=0; i<fromUser.length; i++)
{
maillist.push({email: fromUser[i].email, user_name: fromUser[i].Name });
}
Drop these lines
maillist.toString();
users.toString();
Then put your mail.sendMail into a for loop
for(var m = 0; m < maillist.length; m++) {
mail.sendMail({
from: 'Website Support <help@domain.com>',
to: maillist[m].email,
subject: 'Seller Matched',
template: 'SellerMatch',
context: maillist[m]
}, cb);
}
And change the handlebars in the template to reflect the new object from maillist
Dong Nguyen
Web Developer
Last year I had faced another issue related to multi recipients : github.com/nodemailer/nodemailer/issues/385
It looks like you need to send to each one people in the mailing list a separate email.