Node mailer error : Username and Password cannot be accepted - node.js

I am using Mailtrap.io as smpt server for sending mail using node mailer. I have two files email.js for email setup and authController containing forgotPassword as handler function.
Whenever I hit
http://localhost:8000/api/v1/users/forgotPassword
I get this error as response .
Error: Invalid login: 535-5.7.8 Username and Password not accepted. Learn more at
535 5.7.8 https://support.google.com/mail/?p=BadCredentials g16-20020a05600c4ed000b003974860e15esm21842702wmq.40 - gsmtp
at SMTPConnection._formatError (E:\starter\node_modules\nodemailer\lib\smtp-connection\index.js:784:19)
at SMTPConnection._actionAUTHComplete (E:\starter\node_modules\nodemailer\lib\smtp-connection\index.js:1536:34)
at SMTPConnection.<anonymous> (E:\starter\node_modules\nodemailer\lib\smtp-connection\index.js:540:26)
at SMTPConnection._processResponse (E:\starter\node_modules\nodemailer\lib\smtp-connection\index.js:947:20)
at SMTPConnection._onData (E:\starter\node_modules\nodemailer\lib\smtp-connection\index.js:749:14)
at TLSSocket.SMTPConnection._onSocketData (E:\starter\node_modules\nodemailer\lib\smtp-connection\index.js:189:44)
at TLSSocket.emit (node:events:527:28)
at addChunk (node:internal/streams/readable:315:12)
at readableAddChunk (node:internal/streams/readable:289:9)
at TLSSocket.Readable.push (node:internal/streams/readable:228:10)
at TLSWrap.onStreamRead (node:internal/stream_base_commons:190:23) {
code: 'EAUTH',
response: '535-5.7.8 Username and Password not accepted. Learn more at\n' +
'535 5.7.8 https://support.google.com/mail/?p=BadCredentials g16-20020a05600c4ed000b003974860e15esm21842702wmq.40 - gsmtp',
responseCode: 535,
command: 'AUTH PLAIN'
}
Here is my code.
email.js
const nodemailer = require('nodemailer');
const sendEmail = async (options) => {
//1 Create a transporter
const transporter = nodemailer.createTransport({
service: 'Gmail',
host: process.env.EMAIL_HOST,
port: process.env.EMAIL_PORT,
auth: {
user: process.env.EMAIL_USERNAME,
pass: process.env.EMAIL_PASSWORD,
},
});
//2 Define Email Options
const mailOptions = {
from: 'Farhan Ajmal <18251598-146#uog.edu.pk>',
to: options.email,
subject: options.subject,
text: options.message,
};
//3 Send email
await transporter.sendMail(mailOptions);
};
module.exports = sendEmail;
authController.js
const jwt = require('jsonwebtoken');
const { promisify } = require('util');
const User = require('../models/userModel');
const catchAsync = require('../utils/catchAsync');
const AppError = require('../utils/appError');
const sendEmail = require('../utils/email');
exports.forgotPassword = catchAsync(async (req, res, next) => {
//Get user based on posted email
const user = await User.findOne({ email: req.body.email });
if (!user) {
next(new AppError('There is no user with that email address ', 404));
}
//Send email
try {
await sendEmail({
email: user.email,
subject: 'Your password is only valid for 10 min',
message,
});
res.sendStatus(200);
} catch (err) {
console.log(err);
return next(
new AppError('There was an error sending the email. Try again later'),
500
);
}
});

Gmail/Google has recently removed Less Secure app access. This is what they says:
To help keep your account secure, from May 30, 2022, ​​Google no longer supports the use of third-party apps or devices which ask you to sign in to your Google Account using only your username and password.
So now any emailer having direct SMTP email sending will throw error "535-5.7.8 Username and Password not accepted". This is because now Google is asking for app specific password and the email account password isn't app password so they show username/password not accepted.
You need to create and use App specific password. An app password works like an alternate password for your account. It can only be used by the applications you share it with, so it’s more secure than sharing your primary password.
To create app specific password:
Enable 2 Factor Authentication.
Go to Account settings of Gmail and select App Passwords.
Name it whatever you want and create the password.
Use this new 16 digit password along with gmail email for SMTP (At the place of password use this 16 digit password)
Enjoy sending emails..!!

Related

Using Nodemailer with Hotmail/Node.js

I know there are a lot of posts about this and i've cycled through a good amount of them, none of them panning out. So here we go:
Trying to send an email via Nodemailer in NestJS application. Tested with the documentations's pre done eretheral test email and it worked fine. Now i'm trying to connect it to the hotmail account (which I have attained an app password) and no luck so far. Here's the function:
export async function sendEmail(createTicketDto: CreateTicketDto) {
const { username, email, ticket_body, issue_type } = createTicketDto;
const emailBody = `
User ${email} reporting issue regarding ${issue_type}:\n
\t${ticket_body}\n
\t\tActive username is: ${username}`;
const transporter = nodemailer.createTransport({
service: 'hotmail',
host: 'smtp-mail.outlook.com',
secure: false,
port: 587,
auth: {
user: 'xxx#hotmail.com',
pass: 'PASSWORD',
},
tls: {
ciphers: 'SSLv3',
},
});
console.log(emailBody);
const mailData = await transporter.sendMail({
from: '"XXXSUPPORT"<XXX#hotmail.com>',
to: 'YYY#gmail.com',
subject: issue_type,
text: emailBody,
});
Logger.log(`Email sent with ID: ${mailData.messageId}`);
return mailData;
}
The error being returned resembles:
[Nest] 22727 - 02/10/2023, 1:32:32 PM ERROR [ExceptionsHandler] Invalid login: 535 5.7.3 Authentication unsuccessful [MN2PR17CA0007.namprd17.prod.outlook.com 2023-02-10T18:32:32.130Z 08DB0B4DDC8F1521]
Feedback is appreciated, thank you!!
So problem has been resolved, however a few notes for myself (and anyone who stumbles across this):
const transporter = nodemailer.createTransport({
service: 'hotmail',
auth: {
user: process.env.EMAIL_USER,
pass: process.env.EMAIL_PASS,
},
});
After that it was still failing, so based on a throwaway line in another forum post, I sent a test email to and from the hotmail account, and... it worked! So apparently, if you haven't sent any emails from the target send account, at least in the case of hotmail, it will not work.

SMTP ERROR using Nodemailer to send email

i am building a web app and i want to send emails to registered users that forgot their password. But I am having problem with sending the mail through Node mail. I keep getting a 421 response error that the server is busy with too many connections ans i dont understand why.
below is my code and the error i keep getting.
require('dotenv').config()
const nodeMailer = require('nodemailer')
const sendMail = async (email, token) => {
const transporter = nodeMailer.createTransport({
host: process.env.EMAIL_HOST,
port: 587,
auth: {
user: process.env.EMAIL_USER,
pass: process.env.EMAIL_PASSWORD,
},
});
console.log("passed transportrt ");
await transporter.sendMail({
from: process.env.EMAIL_USER,
to: email,
subject: "Password RESET",
text: `Follow this link to reset your password. It expires in 15minutes. \n\n
http://localhost:4000/reset/${token}`,
});
console.log('out')
}
module.exports = sendMail
the other parts and work flow works well till it gets to await transporter.sendMail({...
and this is the error i keep getting below
Error: Invalid greeting. response=421 Service not available: 421 Service not available
at SMTPConnection._actionGreeting (.../node_modules/nodemailer/lib/smtp-connection/index.js:1205:27)
at SMTPConnection._processResponse (.../node_modules/nodemailer/lib/smtp-connection/index.js:947:20)
at SMTPConnection._onData (.../node_modules/nodemailer/lib/smtp-connection/index.js:749:14)
at Socket.SMTPConnection._onSocketData (.../node_modules/nodemailer/lib/smtp-connection/index.js:189:44)
at Socket.emit (node:events:526:28)
at addChunk (node:internal/streams/readable:315:12)
at readableAddChunk (node:internal/streams/readable:289:9)
at Socket.Readable.push (node:internal/streams/readable:228:10)
at TCP.onStreamRead (node:internal/stream_base_commons:190:23) {
code: 'EPROTOCOL',
response: '421 Service not available',
responseCode: 421,
command: 'CONN'
}
Is there something i am possibly doing wrong? Plus i am running this on unbuntu(if it has any connection to the error)
A 421 error with an EPROTOCOL error usually means the mail client could not connect to the mail server. Two easy possibilities to check:
process.env.EMAIL_HOST is not defined (not set in .env file or OS)
Your server cannot connect to the mail host at port 587 (easily checked with telnet).

Nodemailer error ,even if password and emailid is correct

I am developing an automatic email sender using nodeJs and nodemailer but encountered with this error.
Even if email id and password is correct nodemailer throws an error.
I have also enabled third party app access to gmail.
const contactEmail = nodemailer.createTransport({
service:'gmail',
host:"xyx",
port:465,
secure:true,
auth:{
user:"xyz#gmail.com",
pass:"xyz"
}
});
contactEmail.verify((error)=>{
if(!error) console.log("Ready to send");
else console.log(error);
})
this gives me
Error: Invalid login: 535-5.7.8 Username and Password not accepted.
code: 'EAUTH',
response: '535-5.7.8 Username and Password not accepted. Learn more at\n' +
'535 5.7.8 https://support.google.com/mail/?p=BadCredentials gw20sm7224858pjb.3 - gsmtp',
responseCode: 535,
command: 'AUTH PLAIN'

Nodemailer error while using gmail in firebase functions

I am using firebase cloud functions. I have the following setup configured. While that is working completely fine on my local machine, It's giving me an issue when run on the servers. I have tried gazillion work arounds on the internet but no luck. What is wrong with this?
'use strict'
const functions = require('firebase-functions');
var admin = require('firebase-admin');
const express = require('express');
const nodemailer = require('nodemailer');
const app = express()
var emailRecepient;
var userName;
const smtpTransport = nodemailer.createTransport({
service: "gmail",
host: 'smtp.gmail.com',
port: 587, // tried enabling and disabling these, but no luck
secure: false, // similar as above
auth: {
user: '<emailid>',
pass: '<password>'
},
tls: {
rejectUnauthorized: false
}
});
var mailOptions = {
from: 'test <hello#example.com>',
to: emailRecepient,
subject: 'Welcome to test',
text: 'welcome ' + userName + ". did you see the new things?"
};
function sendmail() {
smtpTransport.sendMail(mailOptions, function (error, info) {
if (error) {
console.log(error);
}
else {
console.log('Email sent: ' + info.response);
}
});
};
exports.sendEmails = functions.database.ref('/users/{userID}/credentials').onCreate((snap, context) => {
const userID = context.params.userID;
const vals = snap.val()
userName = vals.name;
emailRecepient = vals.email;
smtpTransport.sendMail(mailOptions, function (error, info) {
if (error) {
console.log("Error sending email ---- ",error);
}
else {
console.log('Email sent: ' + info.response);
}
});
return true;
});
The error I got on all cases is :
Error sending email 2 ---- { Error: Invalid login: 534-5.7.14 <https://accounts.google.com/signin/continue?sarp=1&scc=1&plt=AKgnsbsi
534-5.7.14 qRQLfD9YlFZDsPj7b8QQACro9c41PjhSVo0NZ4i5ZHNlyycFi_FyRp8VdZ_dH5ffWWAABQ
534-5.7.14 8rH2VcXkyZBFu00-YHJUQNOqL-IqxEsZqbFCwCgk4-bo1ZeDaKTdkEPhwMeIM2geChH8av
534-5.7.14 0suN293poXFBAk3TzqKMMI34zCvrZlDio-E6JVmTrxyQ-Vn9Ji26LaojCvdm9Bq_4anc4U
534-5.7.14 SpQrTnR57GNvB0vRX1BihDqKuKiXBJ5bfozV1D1euQq18PZK2m> Please log in via
534-5.7.14 your web browser and then try again.
534-5.7.14 Learn more at
534 5.7.14 https://support.google.com/mail/answer/78754 t2sm3669477iob.7 - gsmtp
at SMTPConnection._formatError (/user_code/node_modules/nodemailer-smtp-transport/node_modules/smtp-connection/lib/smtp-connection.js:528:15)
at SMTPConnection._actionAUTHComplete (/user_code/node_modules/nodemailer-smtp-transport/node_modules/smtp-connection/lib/smtp-connection.js:1231:30)
at SMTPConnection.<anonymous> (/user_code/node_modules/nodemailer-smtp-transport/node_modules/smtp-connection/lib/smtp-connection.js:319:22)
at SMTPConnection._processResponse (/user_code/node_modules/nodemailer-smtp-transport/node_modules/smtp-connection/lib/smtp-connection.js:669:16)
at SMTPConnection._onData (/user_code/node_modules/nodemailer-smtp-transport/node_modules/smtp-connection/lib/smtp-connection.js:493:10)
at emitOne (events.js:96:13)
at TLSSocket.emit (events.js:188:7)
at readableAddChunk (_stream_readable.js:176:18)
at TLSSocket.Readable.push (_stream_readable.js:134:10)
at TLSWrap.onread (net.js:559:20)
code: 'EAUTH',
response: '534-5.7.14 <https://accounts.google.com/signin/continue?sarp=1&scc=1&plt=AKgnsbsi\n534-5.7.14 qRQLfD9YlFZDsPj7b8QQACro9c41PjhSVo0NZ4i5ZHNlyycFi_FyRp8VdZ_dH5ffWWAABQ\n534-5.7.14 8rH2VcXkyZBFu00-YHJUQNOqL-IqxEsZqbFCwCgk4-bo1ZeDaKTdkEPhwMeIM2geChH8av\n534-5.7.14 0suN293poXFBAk3TzqKMMI34zCvrZlDio-E6JVmTrxyQ-Vn9Ji26LaojCvdm9Bq_4anc4U\n534-5.7.14 SpQrTnR57GNvB0vRX1BihDqKuKiXBJ5bfozV1D1euQq18PZK2m> Please log in via\n534-5.7.14 your web browser and then try again.\n534-5.7.14 Learn more at\n534 5.7.14 https://support.google.com/mail/answer/78754 t2sm3669477iob.7 - gsmtp',
responseCode: 534,
command: 'AUTH PLAIN' }
I have even turned of the allow secure apps in the google settings. But for some reason this doesn't seem to work. Any help is extremely appreciated.
As advised by Renaud, I tried firebase-samples/email-confirmation and I am having following error :
TypeError: snapshot.changed is not a function
at exports.sendEmailConfirmation.functions.database.ref.onWrite (/user_code/index.js:38:17)
at Object.<anonymous> (/user_code/node_modules/firebase-functions/lib/cloud-functions.js:112:27)
at next (native)
at /user_code/node_modules/firebase-functions/lib/cloud-functions.js:28:71
at __awaiter (/user_code/node_modules/firebase-functions/lib/cloud-functions.js:24:12)
at cloudFunction (/user_code/node_modules/firebase-functions/lib/cloud-functions.js:82:36)
at /var/tmp/worker/worker.js:758:24
at process._tickDomainCallback (internal/process/next_tick.js:135:7)
Cheers
When you execute an asynchronous operation in a background triggered Cloud Function, you must return a promise, in such a way the Cloud Function waits that this promise resolves in order to terminate.
This is very well explained in the official Firebase video series here: https://firebase.google.com/docs/functions/video-series/. In particular watch the three videos titled "Learn JavaScript Promises" (Parts 2 & 3 especially focus on background triggered Cloud Functions, but it really worth watching Part 1 before).
So you should modify your code as follows:
exports.sendEmails = functions.database.ref('/users/{userID}/credentials').onCreate((snap, context) => {
const userID = context.params.userID;
const vals = snap.val()
userName = vals.name;
emailRecepient = vals.email;
return smtpTransport.sendMail(mailOptions);
});
If you want to print to the console the result of the email sending, you can do as follows:
return smtpTransport.sendMail(mailOptions)
.then((info) => console.log('Email sent: ' + info.response))
.catch((error) => console.log("Error sending email ---- ", error));
});
Actually there is an official Cloud Functions sample that does exactly that, see https://github.com/firebase/functions-samples/blob/master/email-confirmation/functions/index.js
I see it was a long discussion, let me share the code snippets which worked out for me for others with similar issues so it will be easier to figure out.
1) function.ts (it's written in TypeScript)
import * as admin from 'firebase-admin';
import * as functions from 'firebase-functions';
import * as nodemailer from 'nodemailer';
admin.initializeApp();
// I'm taking all these constants as secrets injected dynamically (important when you make `git push`), but you can simply make it as a plaintext.
declare const MAIL_ACCOUNT: string; // Declare mail account secret.
declare const MAIL_HOST: string; // Declare mail account secret.
declare const MAIL_PASSWORD: string; // Declare mail password secret.
declare const MAIL_PORT: number; // Declare mail password secret.
const mailTransport = nodemailer.createTransport({
host: MAIL_HOST,
port: MAIL_PORT, // This must be a number, important! Don't make this as a string!!
auth: {
user: MAIL_ACCOUNT,
pass: MAIL_PASSWORD
}
});
exports.sendMail = functions.https.onRequest(() => {
const mailOptions = {
from: 'ME <SENDER#gmail.com>',
to: 'RECEIVER#gmail.com',
subject: `Information Request from ME`,
html: '<h1>Test</h1>'
};
mailTransport
.sendMail(mailOptions)
.then(() => {
return console.log('Mail sent'); // This log will be shown in Firebase Firebase Cloud Functions logs.
})
.catch(error => {
return console.log('Error: ', error); // This error will be shown in Firebase Cloud Functions logs.
});
});
This said, you should receive an e-mail from SENDER#gmail.com to RECEIVER#gmail.com, of course modify it for your own needs.
Note: I got the same issue with sending mails correctly on localhost, but on deployment it did not. Looks like the problem in my case was that I did not use port and host in createTransport, instead I had:
const mailTransport = nodemailer.createTransport({
service: 'gmail',
auth: {
user: MAIL_ACCOUNT,
pass: MAIL_PASSWORD
}
});
On top of this do not forget about enabling Less secure app access to ON. Also https://accounts.google.com/DisplayUnlockCaptcha might be helpful.
After checking that all the things listed above were done within my code, I solved the problem login in Google´s account (with the account I'm using with my proyect). I had to recognize the activity form another origin (google detected Firebase was trying to access to that account), and that was it.
After that I tryed to send another email from firebase cloud and it was working fine

Nodemailer whit GMail SMTP OAuth2 autentication is getting me 'Invalid status code 401'

I'm trying to make a simple mail sender using Nodemailer 3, the GMail API whit OAuth2 autentication.
Here's my script:
var serverConfig = {
gmail: {
client_user : 'my#email.com',
client_id : '349...myClientId',
secret : 'mysecret..123jd123',
refresh_token : 'x/xxxxxxxxxxxxxx-reZuEMeSuJaSERmCVY',
access_token : 'xxxxxxxxxxxxxxxxx',
expires: '3599'
}
}
// 3LO authentication https://nodemailer.com/smtp/oauth2/#example-3
var transporter = nodemailer.createTransport({
service: 'gmail',
auth: {
type: 'OAuth2',
user: serverConfig.gmail.client_user,
clientId: serverConfig.gmail.client_id,
clientSecret: serverConfig.gmail.secret,
refreshToken: serverConfig.gmail.refresh_token
},
});
module.exports = {
"send": function(_from,_to,_subject,_html,_text){
// setup email data with unicode symbols
var mailOptions = {
from: _from,
to: _to, // list of receivers
subject: _subject, // Subject line
html: _html, // html body
text: _text // plain text body
};
transporter.sendMail(mailOptions, function(error, info){
if (error) {
return console.log(error);
}
console.log('Message ' + info.messageId + ' sent: %s' + info.response);
})
}
}
When I force the access_token in the auth object, the email is sent without any problem. But, when I don't specify the access_token, only de refresh_token, I'm getting this error:
{ Error: Invalid status code 401
at ClientRequest.req.on.res (/myproject/node_modules/nodemailer/lib/fetch/index.js:193:23)
at emitOne (events.js:96:13)
at ClientRequest.emit (events.js:188:7)
at HTTPParser.parserOnIncomingClient [as onIncoming] (_http_client.js:474:21)
at HTTPParser.parserOnHeadersComplete (_http_common.js:99:23)
at TLSSocket.socketOnData (_http_client.js:363:20)
at emitOne (events.js:96:13)
at TLSSocket.emit (events.js:188:7)
at readableAddChunk (_stream_readable.js:176:18)
at TLSSocket.Readable.push (_stream_readable.js:134:10)
type: 'FETCH',
sourceUrl: 'https://accounts.google.com/o/oauth2/token',
code: 'EAUTH',
command: 'AUTH XOAUTH2' }
Maybe it's too late, but just answering here incase someone comes across the same issue. My problem rectified when the refreshToken was reset. This article gives great instructions for the whole process
I was able to fix this by going to https://console.cloud.google.com/apis/credentials, selecting the correct OAuth 2.0 Client ID, and choosing "Reset Secret" at the top. This revoked my old secret and generated a new one, which I then used in the OAuth Playground to exchange for a refresh token. I put the new Client Secret and Refresh Token in the auth object for nodemailer and it started working again.

Resources