Nodemailer with Gmail service not working on heroku - node.js

I've got a basic email setup done for sending an email using Nodemailer with AngularJS and NodeJS and I've got the project deployed on heroku.
The emailing seems to be working just fine when I am running the app on heroku, but when I get it deployed to Heroku no emails are sent.
For authentication, I am using a Gmail address and I also have a bcc to another Gmail address. So from and bcc addresses are two different Gmail addresses. The from address is the same as the address used for authentication.
Could somebody help me with resolving this issue?
Edit: Adding code
var nodemailer = require('nodemailer');
var transporter = nodemailer.createTransport({
service: 'Gmail',
auth: {
user: 'foobar#gmail.com',
pass: 'foobar'
}
});
router.post('/send',function(req,res){
var mailOptions = {
from: 'Foo Bar ✔ <foobar#gmail.com>',
to: req.body.email,
subject: "Hello " + req.body.email,
text: 'Hello ' + req.body.email + '✔',
html: "<p>Hello " + req.body.email + " </p>",
bcc: "fred#gmail.com"
};
transporter.sendMail(mailOptions, function(error, info){
if(error){
console.log(error);
}else{
console.log('Message sent: ' + info.response);
res.send(200);
}
});
});

I believe this is an issue with google account security.
Google blocked your sign-in to use the mailing features due to an unknown device (location).
A few step to verify this:
Start your server locally and sends the email.
Check your account alerts for unknown sign-in.
This can be temporally resolved by:
https://accounts.google.com/DisplayUnlockCaptcha
A more permanent resolution would be to change your password to a stronger level:
upper case letter + lower case letter + special symbols + numbers

Instead of using direct gmail credentials like this
auth: {
user: 'foobar#gmail.com',
pass: 'foobar'
}
Use OAuth2
auth: {
type: 'OAuth2',
user: 'user#example.com',
accessToken: 'ya29.Xx_XX0xxxxx-xX0X0XxXXxXxXXXxX0x'
}
Google blocks the heroku IPs (unsafe), if we are using direct credentials like you mentioned above. You can refer this Medium article here

5 years later, I still struggled this problem (all answers found on SO failed in my case). Here is what I did, for now everything works smoothly:
Install SendGrid addon to your Heroku app (Free plan gives you 12k messages a month)
Go to SendGrid panel
Go to Marketing -> Senders to add your sender bot, configure it like this:
From = any_address#heroku.com
Reply = your_gmail#gmail.com
Generate API KEY here
Configure NodeMailer like so:
const nodemailer = require('nodemailer'),
sgTransport = require('nodemailer-sendgrid-transport');
const mailTransporter = nodemailer.createTransport(sgTransport({
auth: {
api_key: process.env.ADMIN_EMAIL_API_KEY // your api key here, better hide it in env vars
}
}))
To send an email now, you have to add your gmail in 'Reply To' field, like so:
mailTransporter.sendMail({
from: `"Admin" <any_address#heroku.com>`,
to: 'receiver#hotmail.com',
replyTo: 'your_gmail#gmail.com',
subject: 'Something',
html: `Boom !`
});
I think that's all, in case I forgot something, please add a comment below

Try updating nodemailer package (using "npm update nodemailer" command)
var transporter = nodemailer.createTransport({
host: 'smtp.gmail.com',
port: 465,
secure: true,
auth: {
user: 'youremai#gmail.com', // Your email id
pass: 'pwd123' // Your password
},
tls: {
// do not fail on invalid certs
rejectUnauthorized: false
}
});
router.post('/send',function(req,res){
var mailOptions = {
from: 'Foo Bar ✔ <foobar#gmail.com>',
to: req.body.email,
subject: "Hello " + req.body.email,
text: 'Hello ' + req.body.email + '✔',
html: "<p>Hello " + req.body.email + " </p>",
bcc: "fred#gmail.com"
};
transporter.sendMail(mailOptions, function(error, info){
if(error){
console.log(error);
}else{
console.log('Message sent: ' + info.response);
res.send(200);
}
});
});

I know I'm too late but hopefully someone will find it helpful.
At the time of writing, Less Secure Apps is no longer supported by google.
And you can't use your google account password.
You're gonna have to generate a new app password.
Follow this link
In the "Select App" dropdown, select Other and give the app a name (could be anything)
Copy the password and replace it with your original password
It works on Local machine and Heroku.
const client = nodemailer.createTransport({
service: "Gmail",
auth: {
user: "username#gmail.com",
pass: "Google-App-Password-Without-Spaces"
}
});
client.sendMail(
{
from: "sender",
to: "recipient",
subject: "Sending it from Heroku",
text: "Hey, I'm being sent from the cloud"
}
)
App passwords only work if 2-step verification is turned on. You can do so here

Also if your app password is in your .env file you have to add it to the config vars in the settings tab of your app at heroku.

Related

Trouble sending emails using Nodemailer with a Google App Password

I am creating a route on an API which features sending an email when a user signs up. I am using nodemailer and google app password to achieve this. It was working perfectly until February 3rd 2023 that was the last use of the password. However, I did not change any code the connection simply just stopped working.
This is how my code is formatted:
const transporter = nodemailer.createTransport({
service: 'gmail',
auth: {
user: process.env.GOOGLE_EMAIL,
pass: process.env.GOOGLE_APP_PASSWORD
},
});
const mailOptions = {
from: process.env.GOOGLE_EMAIL,
to: "user#gmail.com",
subject: 'Test Email',
html: "<h1>Email is sent<h1>"
};
transporter.sendMail(mailOptions, function (error, info) {
if (error) {
console.log(error);
} else {
console.log('Email sent: ' + info.response);
}
});
I have also tried this format but it doesn't work either:
const transporter = nodemailer.createTransport({
host: "smtp.gmail.com",
port: 587, // or 465
secure: true,
auth: {
user: process.env.GOOGLE_EMAIL,
pass: process.env.GOOGLE_APP_PASSWORD
}
});
const mailOptions = {
from: process.env.GOOGLE_EMAIL,
to: "user#gmail.com",
subject: 'Test Email',
html: "<h1>Email is sent<h1>"
};
transporter.sendMail(mailOptions, function (error, info) {
if (error) {
console.log(error);
} else {
console.log('Email sent: ' + info.response);
}
});
In either case the error I receive after trying to send an email with either format is the following:
Error: Connection timeout
at SMTPConnection._formatError (/workspace/elana-backend/node_modules/nodemailer/lib/smtp-connection/index.js:787:19)
at SMTPConnection._onError (/workspace/elana-backend/node_modules/nodemailer/lib/smtp-connection/index.js:773:20)
at Timeout.<anonymous> (/workspace/elana-backend/node_modules/nodemailer/lib/smtp-connection/index.js:232:22)
at listOnTimeout (node:internal/timers:559:17)
at processTimers (node:internal/timers:502:7) {
code: 'ETIMEDOUT',
command: 'CONN'
}
The first block of code was working perfectly fine up until recently. I thought a possible password change may have revoked the app password because I noticed that in google app password documentation. Therefore, I also created a new app password but it still appeared with the same issue.
Edit -
Are you using an App Password to make these requests? This password is used to connect applications to your Google account and WILL NOT allow you to login/authenticate with your Google account
Have you tried using a service account with domain-wide delegation to send the email?
I use a similar piece of code to send emails (as users in our Google Workspace) when a Slack message is posted in a channel, however I struggled to have success authenticating using basic authentication like you are above. Instead I took a suggestion from #Linda Lawton - DalmTo in this question. Below I am using OAuth2.0 to impersonate a service account that is authorized through domain-wide delegation to send emails as users in the workspace. Sample code:
const transport = nodemailer.createTransport({
service: 'Gmail',
auth: {
type: 'OAuth2',
user: process.env.GOOGLE_EMAIL,
//Derived from Service Account
serviceClient: privatekey.client_id,
privateKey: privatekey.private_key
}
})
const mail_options = {
from: process.env.GOOGLE_EMAIL,
to: 'test#gmail.com',
subject: 'Test Mail',
html: '<h1> Test Email </h1>',
}
transport.sendMail(mail_options, function(error, result){
if(error){
console.log('Error: ' + error);
}else{
console.log('Result: ' + result);
}
transport.close();
})
Google has some confusing, but well written documentation on using domain-wide delegation in your workspace here. If you are not familiar with Google Cloud services there might be some other resources to catch up on with as well
You might also need to add the transport.close() method in the body of the callback in your .sendMail() method
References
OAuth2.0 with Service Accounts
Domain-Wide Delegation with Service Account
Domain-Wide Delegation
Service Accounts

How to send email using angular 9

The following code send email from server side. How to I use that code in Angular 9 application.
Could you please help some one for this.
var nodemailer = require('nodemailer');
var transporter = nodemailer.createTransport({
service: 'gmail',
auth: {
user: 'test#test.com',
pass: 'xxxx'
}
});
var mailOptions = {
from: 'test#test.com',
to: 'test#test.com',
subject: 'Sending Email using Node.js',
text: `Hi, thank you for your nice Node.js Email.`
};
transporter.sendMail(mailOptions, function(error, info){
if (error) {
console.log(error);
} else {
console.log('Email sent: ' + info.response);
}
});
Probably, the above code will works i the Angular application, but the big problem doing that, is you will have exposed mail transport credentials in your front app. As mentioned before, best solution is create a simple API that send the email on server side.

this is my nodemailer program Even if i give wrong mail in TO addrress also it is showing message sent how to rectifyy that

const nodemailer = require('nodemailer');
let mailTransporter = nodemailer.createTransport({
host: 'smtp.gmail.com',
port: 587,
secure: false,
auth: {
user: '*************',
pass: '*********',
},
});
let mailDetails = {
from: '********',
to: 'uuwdwuvw#', //guguygugiug
subject: 'Test mail',
//text: 'redeem your gift',
html: 'redeem your coupon code ',
};
mailTransporter.sendMail(mailDetails, function (err, data) {
if (err) {
console.log('Error Occurs');
} else {
console.log('Email sent successfully');
}
});
this is my nodemailer program Even if i give wrong mail in TO addrress also it is showing message sent how to rectifyy that
Nodemailer itself can't tell if an email has been delivered or not. It can tell you only if the email has been sent. There's a difference between email being sent and being delivered. Detecting bounced emails is out of scope for the Nodemailer.
In order to do that you need to implement your own bounced email mechanism, probably with your own SMTP server. It's not an easy thing to do, so you should probably use some real email provider that has this functionality instead of Gmail (Google likes to block such applications).
Have a look at the similar question I've found on GitHub and on SO.

Sending emails using Mailgun with NodeMailer package

A couple of days ago I realized that Google has changed the security of gmail accounts, particularly for the possibility of sending emails from applications. After Googling around for a while I couldn't find a fix for it.
So, I resorted to using Mailgun. I created an account and had it enabled with Business verification. However, I still can't send emails. I keep getting an error about the requested URL not being found.
I am suspecting that since I haven't set up a domain yet, it is not picking the mailgun domain it provided by default. Could someone show me how to test sending emails using Mailgun from NodeMailer indicating the sandbox name provided by mailgun.
thanks in advance
José
var nodemailer = require('nodemailer');
// send mail with password confirmation
var transporter = nodemailer.createTransport( {
service: 'Mailgun',
auth: {
user: 'postmaster#sandboxXXXXXXXXXXXXXXXX.mailgun.org',
pass: 'XXXXXXXXXXXXXXXX'
}
});
var mailOpts = {
from: 'office#yourdomain.com',
to: 'user#gmail.com',
subject: 'test subject',
text : 'test message form mailgun',
html : '<b>test message form mailgun</b>'
};
transporter.sendMail(mailOpts, function (err, response) {
if (err) {
//ret.message = "Mail error.";
} else {
//ret.message = "Mail send.";
}
});
I created the Nodemailer transport for mailgun.
Here it how it works.
You install the package with npm install as you would do with any package, then in an empty file:
var nodemailer = require('nodemailer');
var mg = require('nodemailer-mailgun-transport');
// This is your API key that you retrieve from www.mailgun.com/cp (free up to 10K monthly emails)
var auth = {
auth: {
api_key: 'key-1234123412341234',
domain: 'sandbox3249234.mailgun.org'
}
}
var nodemailerMailgun = nodemailer.createTransport(mg(auth));
nodemailerMailgun.sendMail({
from: 'myemail#example.com',
to: 'recipient#domain.com', // An array if you have multiple recipients.
subject: 'Hey you, awesome!',
text: 'Mailgun rocks, pow pow!',
}, function (err, info) {
if (err) {
console.log('Error: ' + err);
}
else {
console.log('Response: ' + info);
}
});
Replace your API key with yours and change the details and you're ready to go!
It worked me, when I added the domain also to the auth object (not only the api_key). Like this:
var auth = {
auth: {
api_key: 'key-12319312391',
domain: 'sandbox3249234.mailgun.org'
}
};

Sending email via Node.js using nodemailer is not working

I've set up a basic NodeJS server (using the nodemailer module) locally (http://localhost:8080) just so that I can test whether the server can actually send out emails.
If I understand the SMTP option correctly (please correct me if I'm wrong), I can either try to send out an email from my server to someone's email account directly, or I can send the email, still using Node.js, but via an actual email account (in this case my personal Gmail account), i.e using SMTP. This option requires me to login into that acount remotely via NodeJS.
So in the server below I'm actually trying to use NodeJs to send an email from my personal email account to my personal email account.
Here's my simple server :
var nodemailer = require('nodemailer');
var transporter = nodemailer.createTransport("SMTP", {
service: 'Gmail',
auth: {
user: '*my personal Gmail address*',
pass: '*my personal Gmail password*'
}
});
var http = require('http');
var httpServer = http.createServer(function (request, response)
{
transporter.sendMail({
from: '*my personal Gmail address*',
to: '*my personal Gmail address*',
subject: 'hello world!',
text: 'hello world!'
});
}).listen(8080);
However, it's not working. I got an email by Google saying :
Google Account: sign-in attempt blocked
If this was you
You can switch to an app made by Google such as Gmail to access your account (recommended) or change
your settings at https://www.google.com/settings/security/lesssecureapps so that your account is no
longer protected by modern security standards.
I couldn't find a solution for the above problem on the nodemailer GitHub page. Does anyone have a solution/suggestion ?
Thanks! :-)
The answer is in the message from google.
Go to : https://www.google.com/settings/security/lesssecureapps
set the Access for less secure apps setting to Enable
For the second part of the problem, and in response to
I'm actually simply following the steps from the nodemailer github page so there are no errors in my code
I will refer you to the nodemailer github page, and this piece of code :
var transporter = nodemailer.createTransport({
service: 'Gmail',
auth: {
user: 'gmail.user#gmail.com',
pass: 'userpass'
}
});
It differs slightly from your code, in the fact that you have : nodemailer.createTransport("SMTP".
Remove the SMTP parameter and it works (just tested). Also, why encapsulating it in a http server? the following works :
var nodemailer = require('nodemailer');
var transporter = nodemailer.createTransport({
service: 'Gmail',
auth: {
user: 'xxx',
pass: 'xxx'
}
});
console.log('created');
transporter.sendMail({
from: 'xxx#gmail.com',
to: 'xxx#gmail.com',
subject: 'hello world!',
text: 'hello world!'
});
Outdated: refreshToken and accessToken no longer exist in JSON file output
For those who actually want to use OAuth2 / don't want to make the app "less secure", you can achieve this by
Search "Gmail API" from the google API console and click "Enable"
Follow the steps at https://developers.google.com/gmail/api/quickstart/nodejs. In the quickstart.js file, changing the SCOPES var from ['https://www.googleapis.com/auth/gmail.readonly'] to ['https://mail.google.com/'] in the quickstart js file provided as suggested in troubleshooting at https://nodemailer.com/smtp/oauth2/
After following the steps in (2), the generated JSON file will contain the acessToken, refreshToken, and expires attributes needed in the OAuth2 Examples for Nodemailer
This way you can use OAuth2 authentication like the following
let transporter = nodemailer.createTransport({
service: 'Gmail',
auth: {
type: 'OAuth2',
user: 'user#example.com',
clientId: '000000000000-xxx0.apps.googleusercontent.com',
clientSecret: 'XxxxxXXxX0xxxxxxxx0XXxX0',
refreshToken: '1/XXxXxsss-xxxXXXXXxXxx0XXXxxXXx0x00xxx',
accessToken: 'ya29.Xx_XX0xxxxx-xX0X0XxXXxXxXXXxX0x',
expires: 1484314697598
}
});
instead of storing your gmail password in plaintext and downgrading the security on your account.
i just set my domain to: smtp.gmail.com and it works. I am using a VPS Vultr.
the code:
const nodemailer = require('nodemailer');
const ejs = require('ejs');
const fs = require('fs');
let transporter = nodemailer.createTransport({
host: 'smtp.gmail.com',
port: 465,
secure: true,
auth: {
user: 'xxx#gmail.com',
pass: 'xxx'
}
});
let mailOptions = {
from: '"xxx" <xxx#gmail.com>',
to: 'yyy#gmail.com',
subject: 'Teste Templete ✔',
html: ejs.render( fs.readFileSync('e-mail.ejs', 'utf-8') , {mensagem: 'olá, funciona'})
};
transporter.sendMail(mailOptions, (error, info) => {
if (error) {
return console.log(error);
}
console.log('Message %s sent: %s', info.messageId, info.response);
});
my ejs template (e-mail.ejs):
<html>
<body>
<span>Esse é um templete teste</span>
<p> gerando com o EJS - <%=mensagem%> </p>
</body>
</html>
Make sure:
install ejs: npm install ejs --save
install nodemailer: npm install nodemailer --save
ping to smtp.gmail.com works: ping smtp.gmail.com
change xxx#gmail.com to your gmail email
change yyy#gmail.com to the email that you want to send a email
Enable less secure apps
Disable Captcha temporarily
have a nice day ;)
While the above answers do work, I'd like to point out that you can decrease security from Gmail by the following TWO steps.
STEP #1
Google Account: sign-in attempt blocked If this was you You can switch to an app made by Google such as Gmail to access your account (recommended) or change your settings at https://www.google.com/settings/security/lesssecureapps so that your account is no longer protected by modern security standards.
STEP #2
In addition to enabling Allow less secure apps, you might also need to navigate to https://accounts.google.com/DisplayUnlockCaptcha and click continue.
You only need App password for google auth, then replace your google password in your code.
go here https://myaccount.google.com/apppasswords
sample code:
const nodemailer = require('nodemailer');
var transporter = nodemailer.createTransport({
service: "Gmail",
auth: {
user: 'example#gmail.com',
pass: 'app password here'
}
});
transporter.sendMail(option, function(error, info){
if (error) {
console.log(error);
} else {
console.log('Email sent: ' + info.response);
}
});
For debugging purpose it is handy to implement a callback function (they never do on the nodemailer github page) which shows the error message (if there is one).
transporter.sendMail({
from: from,
to: to,
subject: subject,
html: text
}, function(err){
if(err)
console.log(err);
})
It helped me solve my problem... Turns out newer versions are not working properly:
"Looks like nodemailer 1.0 has breaking changes so 0.7 must be used instead: http://www.nodemailer.com/
Message posted on nodemailer as of 12/17/15:
Do not upgrade Nodemailer from 0.7 or lower to 1.0 as there are breaking changes. You can continue to use the 0.7 branch as long as you like. See the documentation for 0.7 here."
I found this answer here
And install smtp module as dependency:
npm install smtp
var nodemailer = require('nodemailer');
var transporter = nodemailer.createTransport({
service: 'gmail',
type: "SMTP",
host: "smtp.gmail.com",
secure: true,
auth: {
user: 'writeYourGmailId#gmail.com',
pass: 'YourGmailPassword'
}
});
var mailOptions = {
from: 'xyz.khan704#gmail.com',
to: 'azran.khan704#gmail.com',
subject: 'Sending Email to test Node.js nodemailer',
text: 'That was easy to test!'
};
transporter.sendMail(mailOptions, function(error, info){
if (error) {
console.log(error);
} else {
console.log('Email sent');
}
});
Go to https://myaccount.google.com/lesssecureapps
and change it ON because
Some apps and devices use less secure sign-in technology, which makes your account more vulnerable. You can turn off access for these apps, which we recommend, or turn on access if you want to use them despite the risks.
You should not use gmail password for it anymore!
Recently google has provided a new method to use in 3rd party apps or APIs. You need to use App Password instead of the gmail password. But for creating it, you need to enable 2-step Authentication mode in your google account:
You can find steps here: https://support.google.com/mail/answer/185833?hl=en
try this code its work for me.
var http = require('http');
var nodemailer = require('nodemailer');
http.createServer(function (req, res) {
res.writeHead(200, {'Content-Type': 'text/plain'});
var fromEmail = 'akarthi#xyz.com';
var toEmail = 'akarthi#xyz.com';
var transporter = nodemailer.createTransport({
host: 'domain',
port: 587,
secure: false, // use SSL
debug: true,
auth: {
user: 'fromEmail#xyz.com',
pass: 'userpassword'
}
});
transporter.sendMail({
from: fromEmail,
to: toEmail,
subject: 'Regarding forget password request',
text: 'This is forget password response from your app',
html: '<p>Your password is <b>sample</b></p>'
}, function(error, response){
if(error){
console.log('Failed in sending mail');
console.dir({success: false, existing: false, sendError: true});
console.dir(error);
res.end('Failed in sending mail');
}else{
console.log('Successful in sending email');
console.dir({success: true, existing: false, sendError: false});
console.dir(response);
res.end('Successful in sending email');
}
});
}).listen(8000);
console.log('Server listening on port 8000');
response:
Successful in sending email
{ success: true, existing: false, sendError: false }
{ accepted: [ 'akarthi#xyz.com' ],
rejected: [],
response: '250 2.0.0 uAMACW39058154 Message accepted for delivery',
envelope:
{ from: 'akarthi#xyz.com',
to: [ 'akarthi#xyz.com' ] },
messageId: '1479809555147-33de4987-29d605fa-6ee150f1#xyz.com' }
Adding to xShirase answer just providing screenshots where to enable. Also confirm in security that previous attempt was from you.
Xshirase deserves all upvotes.Iam just showing screenshot.
Here is best way send email using gmail
const transporter = nodemailer.createTransport({
service: 'gmail',
auth: {
user: '******#gmail.com',
pass: '**********',
},
});
use two authentication from google => security => app password and do fill some stuff get app password

Resources