how to send gmail using nodemailer (solution of less secure app deprecated) - node.js

I am trying to send mail using nodemailer node module and configured like this.
... config.js ...
smtp: {
host: "smtp.gmail.com",
port: 465,
secure: true,
auth: {
user: "***#gmail.com",
pass: "****"
}
}
... mail.js ...
const config = require("../config");
const nodemailer = require('nodemailer');
const transporter = nodemailer.createTransport(config.smtp);
const sendEmail = async (data, res) => {
// if(!data.to || !data.subject)
// return false;
data = { ...data, from: config.smtp.auth.user };
console.log(data)
transporter.sendMail(data, (error, info) => {
console.log(error);
res.send(error);
});
res.send(true)
}
module.exports = sendEmail;
... controller ...
router.get('/testEmail', async (req, res) => {
let emailData = {
to: "***#gmail.com",
subject: "Welcome to Musical World",
text: "test test"
};
let result = sendEmail(emailData, res);
console.log(result)
// res.send(result);
})
When I try to send email, it returns
{"code":"EAUTH","response":"535-5.7.8 Username and Password not accepted. Learn more at\n535 5.7.8 https://support.google.com/mail/?p=BadCredentials p25-20020a056638217900b0033c14d2386bsm898629jak.75 - gsmtp","responseCode":535,"command":"AUTH PLAIN"}
So I did googling and found that's why I didn't turn on less secure app in my google account.
But when I went there, google said
I tried to turn on less secure apps , but Gless secure apps feature isn't available.
What do I have to do , then?

I finally resolved by myself!.
Google no longer supports less secure app feature from 05/20/2022.
It will help other developers who get stuck with this issue.
So we can't access to gmail using only emal and password.
Instead we have to use OAuth2 to get access to gmail.
... config.js ...
smtp: {
service: "gmail",
auth: {
type: "OAuth2",
user: "*****#gmail.com",
pass: "******",
clientId: "********",
clientSecret: "***********",
refreshToken: "************"
}
}
You have to have OAuth2 client in your google cloud console for this.
Here's full details you can refer to.
https://www.freecodecamp.org/news/use-nodemailer-to-send-emails-from-your-node-js-server/

Related

Node.js Nodemailer working locally but not when hosted A2hosting

When sending emails through my form in my React frontend it works as it should locally in development, but when I host the webapp on A2hosting in production no emails are being sent or received and I am not getting any errors, on the contrary I am getting an ok status request. Anyone know what the issue and solution might be?
Server.js:
const transport = nodemailer.createTransport({
host: "nl1-ss102.a2hosting.com",
port: 465,
secure: true,
auth: {
user: process.env.USER_SENDER,
pass: process.env.PASS
},
tls: {
rejectUnauthorized: true
}
});
app.post("/send", cors(), async (req, res) => {
let {
name,
//etc...
} = req.body;
await transport.sendMail({
from: `${name}`,
to: process.env.USER_RECEIVER,
subject: "Subject",
html: `
<ul>
<li></li>
</ul>
`
}, (err) => {
if (err) {
console.log(err);
res.status(400).send('Error');
} else {
res.status(200).send('Success');
}
})
});
I had a similar problem when I setup #sendGrid/mail. I would recieve the emails, but the values in the email would all be undefined. Then I saw [that] ("https://www.a2hosting.com/kb/getting-started-guide/setting-up-e-mail/using-external-smtp-servers-to-send-e-mail") a2hosting blocks external SMTP servers for clients who aren't paying for managed account's

How to Resolve Error Sending Email Using nodemailer googleapi?

Last week I initially posted this asking for help using nodemailer and googleapi. I'm trying to use nodemailer and googleapis to send an email. I have set up my project in https://console.cloud.google.com/ and have set my CLIENT_ID, CLIENT_SECRET, CLIENT_REDIRECT_URI and REFRESH_TOKEN in a .env and have confirmed that the values are being populated. In debug mode I have noticed the following error stack when I send the error:
'Error: invalid_grant\n at Gaxios._request (/Users/ENV/Tutoring-Invoice-Management-System/node_modules/gaxios/build/src/gaxios.js:130:23)\n at processTicksAndRejections
(node:internal/process/task_queues:96:5)\n
at async OAuth2Client.refreshTokenNoCache (/Users/ENV/Tutoring-Invoice-Management-System/node_modules/google-auth-library/build/src/auth/oauth2client.js:174:21)\n
at async OAuth2Client.refreshAccessTokenAsync (/Users/ENV/Tutoring-Invoice-Management-System/node_modules/google-auth-library/build/src/auth/oauth2client.js:198:19)\n
at async OAuth2Client.getAccessTokenAsync (/Users/ENV/Tutoring-Invoice-Management-System/node_modules/google-auth-library/build/src/auth/oauth2client.js:227:23)\n
at async sendMail (/Users/ENV/Tutoring-Invoice-Management-System/service/send-email.js:17:29)'
The code is below. I have edited it based on an answer to the question already. My question now is, why am I getting the invalid_grant error? Based on the formal documentation I have set everything up correctly in https://console.cloud.google.com/apis/credentials/oauthclient. But perhaps there is an issue there?
const nodemailer = require('nodemailer');
const { google } = require('googleapis');
require('dotenv').config();
console.log("CLIENT_ID: " + process.env.CLIENT_ID);
console.log("CLIENT_SECRET: " + process.env.CLIENT_SECRET);
console.log("CLIENT_REDIRECT_URI: " + process.env.REDIRECT_URI);
console.log("REFRESH_TOKEN: " + process.env.REFRESH_TOKEN);
const oAuth2Client = new google.auth.OAuth2(process.env.CLIENT_ID, process.env.CLIENT_SECRET, process.env.REDIRECT_URI);
console.log("oAuth2Client: " + oAuth2Client);
oAuth2Client.setCredentials({refresh_token: process.env.REFRESH_TOKEN})
async function sendMail() {
try {
const accessToken = await oAuth2Client.getAccessToken()
const transport = nodemailer.createTransport({
host: "smtp.gmail.com",
port: 465,
secure: true,
auth: {
type: 'OAuth2'
}
});
const mailOptions = {
from: 'envolonakis#gmail.com',
to: 'envolonakis#gmail.com',
subject: "Test Email API Subject",
text: "Test Email API Text",
html: "<h1> Test Email API HTML </h1>",
auth: {
user: process.env.OWNER_EMAIL,
accessToken: accessToken.token
}
}
const result = await transport.sendMail(mailOptions);
return result;
} catch (error) {
console.log(error.stack);
return error;
}
}
sendMail()
From the official documentation, this is what you need to use:
try {
const accessToken = await oAuth2Client.getAccessToken()
const transport = nodemailer.createTransport({
host: "smtp.gmail.com",
port: 465,
secure: true,
auth: {
type: 'OAuth2'
}
});
const mailOptions = {
from: process.env.OWNER_EMAIL,
to: process.env.RECIPIENT,
subject: "Test Email API Subject",
text: "Test Email API Text",
html: "<h1> Test Email API HTML </h1>",
auth: {
user: process.env.OWNER_EMAIL,
accessToken: accessToken.token
}
}
const result = await transport.sendMail(mailOptions);
return result;
} catch (error) {
return error;
}
One error that you have whilst using the google api authentication library is with the token. You were passing the complete token object to the auth configuration of nodemailer instead of just the access token string. Another thing to keep in mind, adding or removing parameters to the auth configuration of nodemailer will lead to different errors.
Using #Morfinismo 's solution in addition to creating a new oAuth on https://developers.google.com/oauthplayground resolved my issue.

Cloud Functions using Nodemailer, Email sent but never arrives

I am using Google Cloud Functions to send E-Mail via Nodemailer, the mails are authenticated via Oauth2. It seems to work without any problems, the emails get sent and are also shown in the sent e-mails of my gmail account, but they actually never arrive at my other email address... Does someone know why?
This is my Code
const mailTransport = nodemailer.createTransport({
name: "gmail.com",
host: "smtp.gmail.com",
port: 465,
secure: true,
auth: {
type: "OAuth2",
user: gmailEmail,
pass: gmailPassword,
clientId: clientid,
clientSecret: clientsecret,
refreshToken: clientrefreshtoken,
accessToken: clientaccesstoken,
expires: 3599,
},
});
exports.submit = functions.https.onRequest((req, res) => {
const corsMiddleware = cors(corsOptions);
corsMiddleware(req, res, () => {
if (req.method !== "POST") {
return;
}
const mailOptions = {
from: req.body.email,
replyTo: req.body.email,
to: "myemail#gmx.at",
subject: `Absender: ${req.body.email}`,
html: req.body.message,
};
mailTransport.sendMail(mailOptions);
res.status(200).send({isEmailSend: true});
});
});
Thanks in Advance
Update!
Somehow i get some e-mails really late, but not all of them. More like 1 out of 10 and i also got this in my Mail inbox:
The recipient server did not accept our requests to connect.
Learn more at https://support.google.com/mail/answer/7720 [mx00.emig.gmx.net. 212.227.15.9: 421-gmx.net (mxgmx017)
Nemesis ESMTP Service not available 421-Service unavailable 421-Reject due to policy restrictions.
421 For explanation visit https://postmaster.gmx.net/en/error-messages?ip=209.85.222.194&c=sp ] [mx01.emig.gmx.net. 212.227.17.5: 421-gmx.net (mxgmx114)
Nemesis ESMTP Service not available 421-Service unavailable 421-Reject due to policy restrictions.
421 For explanation visit https://postmaster.gmx.net/en/error-messages?ip=209.85.222.196&c=sp ]
So after 2 days of trying i think the problem has nothing to do with my code....
Seems to be a problem with gmx servers, maybe i am on any blacklist? i dont know, account is new actually...
Nevermind sending it to my private email from my domain worked.
It is maybe not the reason of your problem, but you should wait that the asynchronous sendMail() execution is completed before sending back the response. If you don't do that you indicate to the Cloud Function platform that it can clean up the instance running your Cloud Function, without waiting for the asynchronous task to be completed.
exports.submit = functions.https.onRequest((req, res) => {
const corsMiddleware = cors(corsOptions);
corsMiddleware(req, res, () => {
if (req.method !== "POST") {
return;
}
const mailOptions = {
from: req.body.email,
replyTo: req.body.email,
to: "myemail#gmx.at",
subject: `Absender: ${req.body.email}`,
html: req.body.message,
};
mailTransport.sendMail(mailOptions)
.then(() => {
res.status(200).send({isEmailSend: true});
})
});
});

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

Nodemailer and GMail with access tokens

I try to use Nodemailer to send an email with my GMail account but it doesn't work, it works in local but on my remote server I recieve an email from Google "Someone is using your account...."
How can I do ?
exports.contact = function(req, res){
var name = req.body.name;
var from = req.body.from;
var message = req.body.message;
var to = '******#gmail.com';
var transport = nodemailer.createTransport("SMTP", {
service: 'Gmail',
auth: {
XOAuth2: {
user: "******#gmail.com",
clientId: "*****",
clientSecret: "******",
refreshToken: "******",
}
}
});
var options = {
from: from,
to: to,
subject: name,
text: message
}
transport.sendMail(options, function(error, response) {
if (error) {
console.log(error);
} else {
console.log(response);
}
transport.close();
});
}
Check out the solution from Unable to send email via google smtp on centos VPS:
In my case, my script is on a VPS so I don't have a way to load any url with a browser. What I did: Changed my gmail pw. Gmail > Settings > Accounts. Then in Google Accounts they listed suspicious logins that were blocked by google (these were my script's attempted logins). Then I clicked the option "Yes, that was me". After that, my script worked (using the new pw).

Resources