Send multipe emails using nodemailer and gmail - javascript

I am trying to send an email to multiple recipients ( about 3.000 ). All emails are stored in my DB ( Mongo ). So I make a query that return all the email addresses, and I use async to send all the emails, like:
function _sendEmail(params, callback) {
async.each(params.email, function(user, cb) {
const mailOptions = {
from: sender
to: user,
subject: Subject,
text: 'Hello Word',
};
app.transporter.sendMail(mailOptions, function(err, response) {
if(err) console.log(err);
else console.log(response);
cb();
});
}, callback);
}
I am creating my nodemailer transporte in my app.js, ,like so:
const transporter = nodemailer.createTransport(smtpTransport({
host: 'smtp.gmail.com',
port: 465,
secure: true,
auth: {
user: senderMail,
pass: senderMailPassword
}
}));
When I try to send this to only 10 mails, it works just fine, but when I try to send to all the emails in my DB, I am getting this error a bunch of times:
{ [Error: Data command failed: 421 4.7.0 Temporary System Problem. Try again later (WS). g32sm7412411qtd.28 - gsmtp]
code: 'EENVELOPE',
response: '421 4.7.0 Temporary System Problem. Try again later (WS). g32sm7412411qtd.28 - gsmtp',
responseCode: 421,
command: 'DATA' }
Am I missing something? Do I need to set something to be able to send lots os emails in a small period of time? I am using a gmail account to do that!
Thanks in advance!

It is because you are attempting to create a new smtp connection for each email.
You need to use SMTP pool.
Pooled smtp is mostly useful when you have a large number of messages that you want to send in batches or your provider allows you to only use a small amount of parallel connections.
const transporter = nodemailer.createTransport(smtpTransport({
host: 'smtp.gmail.com',
port: 465,
pool: true, // This is the field you need to add
secure: true,
auth: {
user: senderMail,
pass: senderMailPassword
}
}));
You can close the pool as
transporter.close();

From Gmail :
421 SMTP Server error: too many concurrent sessions
You may handle your send differently :
wait to close the session between each sending
send by bunch of mail
The best way is to manage to not exceed the limit of 10 session in the same time :)

Related

Nodemailer not sending email

I just set up my glitch project with a contact form and im trying to get it to send an email to me when someone fills out the form. The issue that I am having is that the server logs in console that the message has been sent with no errors but I never receive the email. You can find the code at https://glitch.com/edit/#!/gamesalt-dev?path=packages%2FPOSTroutes.js%3A2%3A39 and the contact form can be found at https://gamesalt-dev.glitch.me/.
let account = {
user: "some.name#ethereal.email",
pass: "************"
}
let transporter = nodemailer.createTransport({
host: "smtp.ethereal.email",
port: 587,
secure: false,
auth: {
user: account.user,
pass: account.pass,
},
});
let mailOptions = {
from: `"Contact" <${account.user}>`,
to: "some.name#example.com",
subject: "New Contact!",
text: "Hello world",
html: "<b>Hello world</b>",
}
let info = await transporter.sendMail(mailOptions, (error, info) => {
if(error) return console.log(error);
console.log("Message sent: %s", info.messageId);
console.log("Preview URL: %s", nodemailer.getTestMessageUrl(info));
});
http://ethereal.email/
Ethereal is a fake SMTP service, mostly aimed at Nodemailer users (but not limited to). It's a completely free anti-transactional email service where messages never get delivered.
Instead, you can generate a vanity email account right from Nodemailer, send an email using that account just as you would with any other SMTP provider and finally preview the sent message here as no emails are actually delivered.
Even if not, the server logs in console that the message has been sent with no errors the message you get is that the SMTP server successfully accepted your mail and added it to the send queue, but that will not guarantee that it will be delivered. The receiving SMTP server could still reject it and send a bounce message back.

Send E-Mails using javascript within a domain

What is the safest and most elegant way to send a E-Mail from javascript within a domain?
We have our own mail server and I'm trying to avoid 3rd party API's as smtpjs or emailjs.
Is this possible?
You can't send email via JavaScript alone. You can either open the mail client on the users device via window.open('mailto:{{to_address}}'), or by calling an API that's hosted on a server (Using nodejs with mandrill would work for this). For an example on how to do that, there's a pretty exhaustive code sample here.
In nodejs you can use nodemailer to connect your email server and send emails.
Here is a sample code to do that (from Nodemailer's Docs):
const nodemailer = require("nodemailer");
// async..await is not allowed in global scope, must use a wrapper
async function main() {
// Generate test SMTP service account from ethereal.email
// Only needed if you don't have a real mail account for testing
let testAccount = await nodemailer.createTestAccount();
// create reusable transporter object using the default SMTP transport
let transporter = nodemailer.createTransport({
host: "smtp.ethereal.email",
port: 587,
secure: false, // true for 465, false for other ports
auth: {
user: testAccount.user, // generated ethereal user
pass: testAccount.pass, // generated ethereal password
},
});
// send mail with defined transport object
let info = await transporter.sendMail({
from: '"Fred Foo đź‘»" <foo#example.com>', // sender address
to: "bar#example.com, baz#example.com", // list of receivers
subject: "Hello âś”", // Subject line
text: "Hello world?", // plain text body
html: "<b>Hello world?</b>", // html body
});
console.log("Message sent: %s", info.messageId);
// Message sent: <b658f8ca-6296-ccf4-8306-87d57a0b4321#example.com>
// Preview only available when sending through an Ethereal account
console.log("Preview URL: %s", nodemailer.getTestMessageUrl(info));
// Preview URL: https://ethereal.email/message/WaQKMgKddxQDoou...
}
main().catch(console.error);

Error: Connection timeout at SMTPConnection._formatError

Error: Connection timeout at SMTPConnection._formatError, don't know what is wrong, can't send mails,please help me.
am trying to send a mail using nodemailer, but i keep getting this error in my console
Error: Connection timeout
at SMTPConnection._formatError (/home/codabae/Desktop/mailmonster/Backend/v1/node_modules/nodemailer/lib/smtp-connection/index.js:784:19)
at listOnTimeout (internal/timers.js:531:17)
at processTimers (internal/timers.js:475:7) {
code: 'ETIMEDOUT',
command: 'CONN'
}
this is my api
here i don't know what am doing wrong, i getting the details from the mongodb and am filling it in the nodmailer fields, i really don't know what am doing wrong.
router.post('/', auth, (req, res) => {
const { to, cc, bcc, subject, message, attachment, smtpDetails } = req.body;
if (!to || !subject || !message || !smtpDetails) return res.status(400).send('input cannot be empty')
let transporter = nodemailer.createTransport({
service: 'gmail',
auth: {
user: '...#gmail.com',
pass: '...'
}
});
let mailOptions = {
from: '...#gmail.com',
to: to,
cc: cc,
bcc: bcc,
subject: subject,
text: `${message}`
};
transporter.sendMail(mailOptions, function (error, info) {
if (error) {
console.log(error);
res.send('mail not sent')
} else {
console.log('Email sent: ' + info.response);
res.send('mail sent')
}
});
module.exports = router;
The part of the error message to focus on here is SMTPConnection._formatError. You are receiving this error because the transport configuration variables are not correct. You need the following variables, with correct values for each.
There are additional variables that can be used, but based on the fields in your code, the following configuration should work fine. If you need additional info, you can always reference the Nodemailer documentation.
//transport configuration for user a site server to send an email.
let transporter = nodemailer.createTransport({
// This is the SMTP mail server to use for notifications.
// GCDS uses this mail server as a relay host.
host: "smtp.gmail.com",
// SMTP is unlike most network protocols, which only have a single port number.
// SMTP has at least 3. They are port numbers 25, 587, and 465.
// Port 25 is still widely used as a **relay** port from one server to another.
// Port for SSL: 465
// Port for TLS/STARTTLS: 587
port: 465,
// if true the connection will use TLS when connecting to server. If false (the
// default) then TLS is used if server supports the STARTTLS extension. In most
// cases set this value to true if you are connecting to port 465. For port 587 or
// 25 keep it false
secure: true, // use TLS
auth: {
// Your full email address
user: process.env.SMTP_TO_EMAIL,
// Your Gmail password or App Password
pass: process.env.SMTP_TO_PASSWORD
}
});
You mentioned filling these in using some sort of information from MongoDB. I cannot see from where you are getting the variables and values in your configuration, but you may need to use a different source or update your query if you are pulling the values from a database.
NOTE:
Another common issue to be aware of involves using the Gmail password, which cannot be used if your account has 2FA enabled. In this case you must generate a unique App Password by following these guidelines from Google.

Nodemailer fails only in production

When I try to send an e-mail using nodemailer I got an connection timeout error with code 'ETIMEDOUT', but when I try on my notebook there's no error, both using the same e-mail account and password.
This is the file 'mail.js':
const nodemailer = require('nodemailer');
const user = process.env.EMAIL;
const pass = process.env.EMAIL_PASS;
const transporter = nodemailer.createTransport({
service: 'kinghost',
host: 'smtp.kinghost.net',
port: 587,
secure: false,
pool: true,
auth: { user, pass }
});
module.exports = {
sendMail(to, subject, html) {
const mailOptions = {
from: user,
to,
subject,
html
};
console.log(user)
transporter.sendMail(mailOptions, (err, info) => {
if (err) {
console.log(err)
};
console.log(`Mail to ${mail} has been sended`);
});
}
};
It might be because on a production website, you are on a server that has a different IP to your own, and perhaps your email service is running some filtering because it thinks it might be unintended behaviour.
You should maybe look into other secure ways of authenticating your email client, or perhaps see if you can register the IP of your production server (less effective).
Hey programmer friend.
I went through the same situation using kinghost. Make sure you check your email provider's dashboard for an option called "SMTP INTERNATIONAL".
Quick fix:
change your config
nodemailer.createTransport({
host: **"smtpi.kinghost.net"**, // smtp international
secure: true, // force port 465
port: 465, // default port
auth: {
user: process.env.EMAIL, //email
pass: process.env.EMAIL_PASS, //pass
}
});
Your ECS or EC2 container must run on a different source, for this reason, activate the international email in your provider and use the same to solve this problem.
Your ECS or EC2 container must run on a different source, for this reason, activate the international email in your provider and use the same to solve this problem.
For my application this worked.

How to get nodemailer to work with 2LO for service accounts?

I have followed the instructions on the nodemailer site to the letter, but OAuth2 for google service accounts simply does not work for me.
Either I get ECONN timeouts when setting "host" to mail.google.com or some combination of "401, user/pwd not accepted, can not create access token" errors when using smtp.gmail.com as the host.
I've used this as my template:
http://nodemailer.com/smtp/oauth2/#example-4
I've set up a service account: https://developers.google.com/identity/protocols/OAuth2ServiceAccount
I've enabled the gmail api.
I've created tokens that validate:
https://www.googleapis.com/oauth2/v1/tokeninfo
I have also tried the xoauth2 npm package to generate tokens and failed...
I also tried the answer in this question, but still no luck...
There seems to be an endless supply of answers for 3LO, but none that I've tried for 2LO that work. Now, having said all that.
var nodemailer = require("nodemailer");
var { google } = require("googleapis");
var accessToken;
var expires;
var key = require(“path/to/secrets.json");
var privateKey = key.private_key;
var jwtClient = new google.auth.JWT(key.client_email, null, key.private_key, ["https://mail.google.com/"], null);
jwtClient.authorize(function(err, tokens) {
if (err) {
return;
} else {
token = tokens
accessToken = tokens.access_token //this **IS** a valid token
expires = tokens.expiry_date
}
var transporter = nodemailer.createTransport({
host: "smtp.gmail.com",
port: 465,
secure: true,
auth: {
type: "OAuth2",
user: key.client_email, //I've also used my email here
serviceClient: key.client_id,
privateKey: privateKey,
accessToken: accessToken,
expires: expires,
},
});
var mailOptions = {
from: “me#here.com”
to: “me#there.com",
subject: "Ready",
text: “Really Ready"
}
transporter.sendMail(mailOptions, function(error, info) {
if (error) {
return;
}
console.log("Message %s sent: %s", info.messageId, info.response);
});
});
which generated the error:
535-5.7.8 Username and Password not accepted.
But as I mentioned, I've tried differing configurations and settings and gotten just as many different errors...
SO... Has anyone had success in using service accounts for 2LO using nodemailer?
I'm using node 9.5.0 and nodemailer ^4.6.0
I got it working (2021!), these were the steps:
Log in to console.- https://console.cloud.google.com/
Create a service account under the project.
Click on the new service account, go to permissions and add a member. You will use this member's email address when sending the request.
Create keys for the service account. - keys -> add key. https://console.cloud.google.com/iam-admin/serviceaccounts
Download your key file. You will get something like service-account-name-accountid.json. It will have all the information you need to get the code below running.
Delegate authority to your service account https://developers.google.com/identity/protocols/oauth2/service-account#delegatingauthority. Addhttps://mail.google.com/ as the scope.
Write some code like below:
const nodemailer = require('nodemailer');
const json = require('./service-account-name-accountid.json');
const sendEmail = async (email, subject, text) => {
try {
const transporter = nodemailer.createTransport({
host: 'smtp.gmail.com',
port: 465,
secure: true,
auth: {
type: 'OAuth2',
user: email, //your permissioned service account member e-mail address
serviceClient: json.client_id,
privateKey: json.private_key
}
});
await transporter.verify();
await transporter.sendMail({
from: json.service_email,
to: email, //you can change this to any other e-mail address and it should work!
subject,
text
});
console.log('success!');
return {
status : 200
}
} catch (error) {
console.log(error);
return {
status : 500,
error
}
}
}
sendEmail('your_permissioned_service_account_email_address#some_place.com, 'testing 123', 'woohoo!');
Why? Because one the default scopes on your credentials for OAuth 2.0 client IDs are these:
email <- Can only view email address
profile
openid
If you want to send email using node mailer it should include this scope:
https://mail.google.com/
and which is a sensitive scope, so google needs to verify it first else you will receive some delegation error messages.
Follow this verification process.
And add scope in the consent page
Or
Make sure you're an admin of the gsuite then give your service account access to sending email or an admin can give your service account access to sending email.
This guide will help. It's in Japanese just translate it to english.
Old thread, but I've got this working just now (after a lot of trying) so a few suggestions for anyone interested:
Enable the Gmail API in the Cloud Console
Use your 'normal' email address as the user (not the Service Account email)
Go here https://admin.google.com/ac/owl/domainwidedelegation and add your service client to the list. Here you will have to type in your client_id for the Client Name part and https://mail.google.com/ as the API scope. This last part was hard to find, but made it work for me in the end.
Also, I found this guide very helpful: Here you will have to type in your client_id for the Client Name part and https://mail.google.com/ as the API scope before pressing the Authorise.

Categories

Resources