Setting up authentication with Gmail in node via Nodemailer causes issues when simply using your plain password. If you Google this issue many people will point you to use something called "Less Secure App Access, however, can't use Less Secure Apps (shown below) anymore, and this change is fairly recent.
To circumvent this issue one must use an "App Password" generated from their Gmail account. Now although this may appear to be Two Factor Authentication, it is not the case and it is misleading. An App Password is used for devices that are not set up for two-factor authentication. However, to get an app password from your account, you need to enable two-factor authentication, which seems counterintuitive.
Step 1-) Enable Two Factor Authentication In Your Gmail Account
To do this go into the settings for the corresponding Gmail account you will be using with Nodemailer at:
https://myaccount.google.com/security
Find the steps for two-factor authentication and set it up accordingly. Once it is done it should look like the image below.
2-) Generate An App Password
Simply click the App Passwords link in the Security section of your profile settings:
https://myaccount.google.com/security
Eventually, this will lead you to a screen to generate an app password as shown below. I was using a Mac so I just selected Mac, but it does not necessarily matter.
3-) Setup your transporter in Node with the corresponding credentials
Create a javascript file with the following content
var dotenv = require("dotenv")
dotenv.config()
const nodemailer = require("nodemailer");
let transporter = nodemailer.createTransport({
service: 'Gmail',
host: 'smtp.gmail.com',
secure: false,
auth: {
user: process.env.EMAIL_TEST,
pass: process.env.EMAIL_TEST_APP_PSWD
},
})
I set up this file as a service in my services directory, but you can place it as you like. I also used a .env file to save my variables in, however, if you like you can just hardcode the values for your email account into the file.
4-) Utilize your transporter object to send an email (optional)
At this point, if you followed the steps correctly you should no longer have any authentication issues regarding your Gmail account. So you are good to go, now you can use the transporter as you like.
In my use case, I used the transporter object to send an email when users sign up for my application to verify their email exists.
module.exports = {
verifyUserEmail: async function verifyUserEmail(name, userEmail, username, token) {
try {
let info = await transporter.sendMail({
from: process.env.EMAIL_TEST,
to: userEmail,
subject: "Hello " + name + " please verify your email by clicking the link",
html: process.env.homepageDev + "/verifyUserEmail/" + username + "/" + token,
})
} catch (err) {
console.log(err)
}
}
}
In the exported function (verifyUserEmail) it takes in:
name: Name of the user
userEmail: The email we are sending to
username: The username of the user in my application
token: A JWT token that is linked to the user
I import this function to my routes handler as follows:
const emails = require('../services/Email');
I then utilize the imported function as follows:
router.post('/signup', async (req, res) => {
const signedUpUser = new Schemas.SignUp({
fullName: req.body.fullName,
username: req.body.username,
email: req.body.email,
password: req.body.password,
role: req.body.role
})
const emailToken = jwt.sign({
username: req.body.username
}, 'secret1234', { expiresIn: '1h' })
emails.verifyUserEmail(req.body.fullName, req.body.email, req.body.username, emailToken)
signedUpUser.save()
.then(data => {
res.json(data)
})
.catch(error => {
res.json(error)
})
})
Conclusion
We are done, this is a good example of how to use the transporter you created from end to end. I hope this tutorial was clear regarding how to get your Gmail configured properly with Nodemailer. The main takeaway is that one-factor authentication with just a password is no longer useable, nor can we use the previously popular "Less Secure Apps" method as detailed across the internet. Thankfully we have App Passwords, and this is a nice and simple way to get your transporter object setup easily. Thanks for reading everyone, now get out of here and spam some emails to your users!