Sending an Gmail by OAuth 2.0 Playground - node.js

I have written code for sending mail from my gmail account to another account by OAuth2. In OAuth2, we need a refreshToken and accessToken generated on https://developers.google.com/oauthplayground/ The accessToken generated by this will expires in 3600 seconds. I want some code that will generate accessToken.
I have written code where i direct put refreshToken and acessToken from this site https://developers.google.com/oauthplayground/ .
//javascript code main file app.js
async function sendEmail() {
const nodemailer = require("nodemailer");
const { google } = require("googleapis");
const OAuth2 = google.auth.OAuth2;
const smtpTransport = nodemailer.createTransport({
service: "gmail",
auth: {
type: "OAuth2",
user: "***************#gmail.com",
clientId: "***********.apps.googleusercontent.com",
clientSecret: "*************",
refreshToken: "**************",
accessToken: "********************************"
}
});
const mailOptions = {
from: "**************#gmail.com",
to: "**************#gmail.com",
subject: "Hello",
generateTextFromHTML: true,
html: "<h1>TEST MAIL SAYS HELLO</h1>"
};
smtpTransport.sendMail(mailOptions, (error, response) => {
error ? console.log(error) : console.log(response);
smtpTransport.close();
});
}
sendEmail();
This is working fine but i want that accessToken generated by using some code.

In order to get the access token and refresh token you will need to enter your credentials at some point in your app. This will require some sort of front end portion. On the back end you will use the auth package in the googleapis node library to take those credentials and generate the tokens you need.
Another way is to make a service account that will send emails on behalf of your account. What is the flow you want, anyone to send an email using Gmail or just yourself?

Related

Google OAuth2.0 - Gaxios invalid_grant error

The below is my mailer.js code
const nodemailer = require("nodemailer");
const { google } = require("googleapis");
const { OAuth2 } = google.auth;
const oauth_link = "https://developers.google.com/oauthplayground";
const { EMAIL, MAILING_ID, MAILING_REFRESH, MAILING_SECRET } = process.env;
const auth = new OAuth2(
MAILING_ID,
MAILING_SECRET,
MAILING_REFRESH,
oauth_link
);
exports.sendVerificationEmail = (email, name, url) => {
console.log("inside send verification email");
auth.setCredentials({
refresh_token: MAILING_REFRESH,
});
const accessToken = auth.getAccessToken();
console.log("accessToken-" + accessToken);
const smtp = nodemailer.createTransport({
service: "gmail",
auth: {
type: "OAuth2",
user: EMAIL,
clientId: MAILING_ID,
clientSecret: MAILING_SECRET,
refreshToken: MAILING_REFRESH,
accessToken,
},
});
console.log("smtp " + smtp);
const mailOptions = {
from: EMAIL,
to: email,
subject: "Facebook email verification",
html: '<div><div style="max-width:500px;margin-bottom:1rem;align-items:center;display:flex"><img style="width:40px" src="https://seeklogo.com/images/F/facebook-icon-circle-logo-09F32F61FF-seeklogo.com.png" alt=""><span style="font-family:sans-serif;color:#3266a8;font-weight:700;padding-left:10px">Action Required : Activate your facebook account</span></div><div style="border-top:1px solid;border-bottom:1px solid;border-color:#deb887;padding:10px;padding-bottom:20px"><div style="height:35px"><span style="font-weight:700;font-family:sans-serif">Hello ${name}</span></div><div style="height:28px;font-family:sans-serif;padding-bottom:20px"><span>You recently created a profile on facebook. Please confirm your account</span></div><div style="">Confirm Your Account</div></div></div>',
};
console.log("mailOptions" + mailOptions);
smtp.sendMail(mailOptions, (err, res) => {
if (err) return err;
return res;
});
};
I have properly generated the Oauth playground configurations and have the below in my process.env
EMAIL=***
MAILING_ID=***
MAILING_SECRET=***
MAILING_REFRESH=***
MAILING_ACCESS=***
I am getting the below error.
GaxiosError: invalid_grant
***
***
data: {
error: 'invalid_grant',
error_description: 'Token has been expired or revoked.'
},
I am totally beginner with the Google OAuth procedure. Which token has expired? Is it Access token or Refresh Token.
Thanks in advance, Dear Developers community..
The refresh token you are using has expired. You need to request a new one. If your project is still in testing refresh tokens only last for seven days.
You need to set it to production in Google cloud console under the OAuth screen and your refresh tokens will no longer expire
I applaud your use of xOAuth2 with the smtp server 👏

How to trigger sending an email from my website via my own Gmail account to my own Gmail account in NodeJS, using Nodemailer?

My situation is this:
I have an ExpressJS app running a very simple website with a form to send an email request to the site administrators
I want to use Nodemailer to connect to my Gmail account and send the email from my own account
I don't have GSuite and I don't want to pay for it, which apparently means I can't use a service account
I have already successfully been able to send myself an email using the following code:
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

How to get email and profile information from OAuth2 Google API?

I'm trying to retrieve the name of a logged in user using Google API Node.js Client, using OAuth2 API.
Following the usage example, I managed to do the login, but I can't find a way to get the profile information.
I'm not using People API nor Plus API, cause as far as i know, OAuth2 includes https://www.googleapis.com/auth/userinfo.profile, which should be enough for the task.
I have seen some similar questions and tried the solutions of this one but it didn't work, maybe it's too old (?)
With the npm package googleapis how do I get the user's email address after authenticating them?
Looking at other API's like Google Sheets, it's possible to call their functions like this:
var google = require('googleapis');
var sheets = google.sheets('v4');
...
sheets.spreadsheets.values.get({
auth: auth,
spreadsheetId: file_id,
range: my_ranges,
}, function(err, response){
...
}
);
But it seems that OAuth2 doesn't work like that...
You can use Quickstart for node.js. The detail information is https://developers.google.com/gmail/api/quickstart/nodejs. Using a sample script from Quickstart, you can retrieve access token by OAuth2, and retrieve email and user profile.
Before it runs a sample of Quickstart, please confirm Prerequisites, Step 1 and Step 2.
You can use by changing listLabels(auth) as follows. The scope is https://www.googleapis.com/auth/gmail.readonly.
Script :
var gmail = google.gmail({
auth: auth,
version: 'v1'
});
gmail.users.getProfile({
auth: auth,
userId: 'me'
}, function(err, res) {
if (err) {
console.log(err);
} else {
console.log(res);
}
});
gmail.users.messages.get({
'userId': 'me',
'id': 'mail ID',
'format': 'raw'
}, function (err, res) {
console.log(new Buffer(res.raw, 'base64').toString())
});
gmail.users.getProfile retrieves user profile.
gmail.users.messages.get retrieves email.
If I misunderstand your question, I'm sorry.
Added :
Please change above to following script. Scope is https://www.googleapis.com/auth/userinfo.profile.
Script :
var oauth2 = google.oauth2({
auth: auth,
version: 'v2'
});
oauth2.userinfo.v2.me.get(
function(err, res) {
if (err) {
console.log(err);
} else {
console.log(res);
}
});
Result :
{
id: '#####',
name: '#####',
given_name: '#####',
family_name: '#####',
link: '#####',
picture: '#####',
gender: '#####',
locale: '#####'
}
2021 Solution
This answer may divert from the originally asked question but I think it will be useful for some people who are getting google user information in the backend by generating AuthUrl and sending it to the client side and then receiving the data response in the call back URL after the user gives permission from the client side.
Some global declarations
import { google } from "googleapis";
const Oauth2Client = new google.auth.OAuth2(
googleCredentials.CLIENT_ID,
googleCredentials.CLIENT_SECRET,
googleCredentials.REDIRECT_URI
);
Generate the Auth URL with the scopes
const SCOPE = [
'https://www.googleapis.com/auth/userinfo.profile', // get user info
'https://www.googleapis.com/auth/userinfo.email', // get user email ID and if its verified or not
];
const auth_url = Oauth2Client.generateAuthUrl({
access_type: "offline",
scope: SCOPE,
prompt: "consent",
state: "GOOGLE_LOGIN",
});
return res.json({ url: auth_url }); // send the Auth URL to the front end
Get the user data in the callback
let code = req.query.code; // get the code from req, need to get access_token for the user
let { tokens } = await Oauth2Client.getToken(code); // get tokens
let oauth2Client = new google.auth.OAuth2(); // create new auth client
oauth2Client.setCredentials({access_token: tokens.access_token}); // use the new auth client with the access_token
let oauth2 = google.oauth2({
auth: oauth2Client,
version: 'v2'
});
let { data } = await oauth2.userinfo.get(); // get user info
console.log(data); // you will find name, email, picture etc. here
Feel free to discuss in the comments if there's any confusion or error
You can also look into PassportJS. They have multiple strategies, including OAuth2 and 3 different Google Auth strategies. My answer doesn't really answer your question but maybe even taking a peek at Passport's code, you may get your answer.
http://passportjs.org/

Gmail refresh tokens, xoauth2 and general informations

I started using nodejs and nodemailer a week ago and I've got some questions about Gmail oauth.
I've set my client ID my secret ID pretty easily but now I'm stuck on a "problem", I'm using gmail refresh tokens for authorizing my botmailer to send newsletter emails, being said it seems that when the token expires my bot is no more authorized and I cannot send emails anymore.
Is there a way I can automatically update the refresh token in my code ?
This is what I got so far, thanks in advance!
var transporter = nodemailer.createTransport({
service: 'gmail',
auth: {
xoauth2: xoauth2.createXOAuth2Generator({
user: 'mybotemail',
clientId: 'myclientid',
clientSecret: 'mysecretid',
refreshToken: 'myrefreshtoken',
accessToken: 'myaccesstoken'
})
}
});
var mailOptions = {
from: "myemailverifiedabove",
to: user,
subject: "Hello world",
generateTextFromHTML: true,
html: "<b>Hello world</b>"
};
transporter.sendMail(mailOptions, function(error, response) {
if (error) {
console.log(error);
} else {
console.log(response);
}
transporter.close();
});
EDIT: Gmail also suspended my account once without even saying why, if some of you does know why, I would appreciate it.

Nodemailer XOauth2 [Error: unauthorized_client] when trying to get new access token

I am sending emails through Gmail succefully using nodemailer with xoauth2, but when the time comes to get new access token i receive [Error: unauthorized_client].
My code:
var express = require('express');
var nodemailer = require("nodemailer");
var xoauth2 = require('xoauth2');
app = express();
var generator = xoauth2.createXOAuth2Generator({
user: {userEmail},
clientId: {clientId},
clientSecret: {clientSecret}
refreshToken: {refreshToken},
accessToken: {accessToken}
});
var smtpTransport = nodemailer.createTransport({
service: "gmail",
auth: {
xoauth2: generator
}
});
var mailOptions = {mailOptions}
app.get('/send',
function (req, res) {
generator.generateToken(function (err, token, access) {
console.log(err, token, access);
smtpTransport.sendMail(mailOptions, function (error, response) {
if (error) {
console.log(error);
res.sendStatus(404);
} else {
console.log(response);
res.sendStatus(200);
}
smtpTransport.close();
});
});
});
app.listen(5000);
I am invoking generateToken just for testing purposes. But in normal use is not responding also.
I obtained here Google Developers clientId and clientSecret, where i also added https://developers.google.com/oauthplayground/ to Authorized redirect URIs. After that I went developers playground (the same as the redirect uri), I selected Gmail API with scope mail.google.com, then I exchanged the "Authorization code" for refresh and access tokens and I checked "Auto-refresh the token before it expires". After the timeout has finished (the 3600 seconds) I am not able to obtain new accessToken using xoauth2.
Can be marked as closed. I have not found the reason for that problem. I just deleted the project in Google Developers Console and create new one. In new project i followed the same steps desribed above I and succesfully obtained an access token.
Perhaps you were using
https://developers.google.com/oauthplayground/
instead of
https://developers.google.com/oauthplayground

Resources