My situation is this:
const nm = require('nodemailer');
const {google} = require('googleapis');
const OAuth2 = google.auth.OAuth2;
const api = module.exports = {};
api.createTransporter = async () => {
const client = new OAuth2(
process.env.CLIENT_ID,
process.env.CLIENT_SECRET,
'https://developers.google.com/oauthplayground'
);
client.setCredentials({
refresh_token: process.env.REFRESH_TOKEN
});
console.log(`Refresh token is: ${process.env.REFRESH_TOKEN}`);
const accessToken = await new Promise((resolve, reject) => {
client.getAccessToken((err, token) => {
if (err)
reject(err);
resolve(token);
});
});
console.log('access token:');
console.log(accessToken);
return nm.createTransport({
service: 'Gmail',
auth: {
type: 'OAuth2',
user: process.env.EMAIL,
accessToken,
clientId: process.env.CLIENT_ID,
clientSecret: process.env.CLIENT_SECRET,
refreshToken: process.env.REFRESH_TOKEN
}
});
};
I then used the sendMail function in another module to successfully send an email. However, my refresh token expired after 7 days. According to Google OAuth guide:
A Google Cloud Platform project with an OAuth consent screen configured for an external user type and a publishing status of "Testing" is issued a refresh token expiring in 7 days. There is currently a limit of 50 refresh tokens per Google Account per OAuth 2.0 client ID. If the limit is reached, creating a new refresh token automatically invalidates the oldest refresh token without warning. This limit does not apply to service accounts.
In other words, it would seem that you either need to use a service account (which requires Google workspace/GSuite, which is a paid service) or you need to verify your app. However, I am the ONLY ONE using it. I am not creating an account for users, only to send email from myself to myself. Having to get a new refresh token every 7th day is not a good option for me. And it seems that using an API key is the only other method, and that may be severely limited in what you can do (I'm not sure if you can even send an email using that).
What is the preferred method of sending an email in NodeJS with Nodemailer from a server-based application with no users? Is there a way to do it with Gmail without paying for a GSuite/Google Workspace account? I only wanted to use OAuth for security because I was using my own account, but if there is a simpler method I haven't understood, I'm all ears! Thanks.
I am going to share with you what we do for ALL the web apps we create at the company I work for. (www.piersolutions.ca)
Nodemailer is powerful, but I think you are using it wrong. I develop in NodeJs, same as you.
function xxx() {
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.gmail.com",
port: 587,
secure: false, // true for 465, false for other ports
auth: {
user: "xxx@gmail.com",
pass: "xxx",
//your password needs to be a special password in Gmail.
},
});
// send mail with defined transport object
let clientEmail = await transporter.sendMail({
from: "xxx.com", // sender address
to: username, // list of receivers
subject: "Welcome To PSD", // Subject line
text: "Hey " + firstname + ", \n\nYou have been registered for ..." // plain text body
});
console.log("Message sent: %s", clientEmail.messageId);
// Message sent: <b658f8ca-6296-ccf4-8306-87d57a0b4321@example.com>
// Preview only available when sending through an Ethereal account
// Preview URL: https://ethereal.email/message/WaQKMgKddxQDoou...
}
main().catch(console.error);
}
your password is in gmail, you have to set up 2 factor auth for your gmail account, and then add an app specific password. You can just google how to get smtp password for google. I can send emails to anyone. You can define the users recieving emails in a variable, or hardcore them in there. Since it's only you receiving emails, probably just best to hardcode. Hope this helped