I am using gmail APIs to sync emails with my portal. I have added around 10 gmail accounts and have added watch for all of them which is working via gmail pub-sub. I am getting changes perfectly for around 8 accounts where as for 1 or two accounts, i am not getting changes via pub-sub topic to my web-hook server.
by manual (API)call to fetch changes, i am getting further changes as well But not via pub-sub topic.
The code I am using to create watch is:
let oauth2Client = new auth.OAuth2(clientId, clientSecret);
oauth2Client.credentials = { 'access_token': accessToken, 'refresh_token': refreshToken };
gmail.users.watch({
auth: oauth2Client,
userId: 'me',
resource: { topicName: googleAppsSMTP.topicName }
}, (err, response) => {
console.log(response);
defer.resolve(response);
});
Is there anything I am missing here ?
Thanks in advance.
Related
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
I am implementing authentication with google in my mobile flutter app. I get the access_token in my app, and then I send it to backend which is written with Node.js. And thene I need to fetch user basic info + birthday and gender. In Google Cloud Platform console I did all configs, I added certain scopes,'https://www.googleapis.com/auth/user.birthday.read', 'https://www.googleapis.com/auth/user.gender.read',. I enabled Google People API. But I still can not get birthday and gender. Here is backend part from.
const token =
"HARDCODED_ACCESS_TOKEN";
var google = require("googleapis").google;
var OAuth2 = google.auth.OAuth2;
var oauth2Client = new OAuth2();
oauth2Client.setCredentials({
access_token: token,
scope: "https://www.googleapis.com/auth/user.gender.read",
});
var oauth2 = google.oauth2({
auth: oauth2Client,
version: "v2",
});
oauth2.userinfo.get(function (err, res) {
if (err) {
console.log(err);
} else {
console.log(res.data);
}
});
And here what I got in response.
I tried almost everything, but still couldn't get gender and birthday.
In order to get information about gender and birthdays from the authenticated user, you can call People API's people.get with resourceName=people/me and personFields=genders,birthdays:
oauth2Client.setCredentials({
access_token: token,
});
const service = google.people({version: 'v1', auth: oauth2Client});
service.people.get({
resourceName: 'people/me',
personFields: 'genders,birthdays'
}, (err, res) => {
// Do your thing
});
Notes:
You didn't provide the code for most of the authentication process, but please note that the scopes have to be provided before retrieving the access_token, since the access token depends on those scopes. Also, I'd suggest you to set a refresh_token, since the access_token will expire in an hour. For more information about the OAuth process, please take a look at the Node.js quickstart.
It is assumed that both genders and birthdays are added to the authenticated user's account.
Thank you for reading this question.
we wish to grand our users to fetch data from our servers using batch process.
they are using node.js.
this is what I have tried to do that with no success.
can you help me, please?
var AuthenticationClient = require('auth0').AuthenticationClient;
var auth0 = new AuthenticationClient({
domain: '...',
clientId: '...'
});
var data = {
username: 's#gmail.com ',
password: '*****'
};
console.log(auth0.oauth.oauth.token); //<---- undefined
auth0.oauth.token(data, function (err, userData) {
if (err) { // Handle error. }
console.log(userData);
});
Thank you so much
go it. instead of using email and password.
I had to log in using client_id, client_secrect that was generated specifically for my customer. with specific privileges.
using the manage user interface under the API menu.
thank you all
so i am using this: https://github.com/google/google-api-nodejs-client#using-api-keys
here is the nodejs code:
router.get("/deals", function(req, res, next) {
var key = require('../gmail-a574e06ad196.json');
var jwtClient = new google.auth.JWT(
key.client_email,
null,
key.private_key,
['https://www.googleapis.com/auth/gmail.readonly', 'https://mail.google.com/'], // an array of auth scopes
null
);
jwtClient.authorize(function (err, tokens) {
if (err) {
res.send('123');
return;
}
console.log('token is: ', tokens)
// Make an authorized request to list Drive files.
drive.users.labels.list({
auth: jwtClient,
userId: 'me'
}, function (err, resp) {
console.log(err)
res.send('123')
});
});
});
but once i hit that api, i got the following error:
errors:
[ { domain: 'global',
reason: 'failedPrecondition',
message: 'Bad Request' } ] }
I google around. found on some sites that said, the service account only work if you have G-Suite account, which is a paid account. My gmail account is a normal personal account. so no matter what i do, it just wont work?
Is that true?
What i am trying to do is, so i have a gmail account to collects newsletters, I want to create a nodejs api that returns/lists all emails from that account. I dont want oAuth, because really, no need to manually login. All i want is when page load, login automaically happens and the api returns list of emails, so everyone can see the list. Is there any other appoach of achieving this?
Thanks
you can not use service account with a normal users Gmail account due to the fact that there is no way to delicate access to another user. you can only do it with gsuite.
you could consider going through the SMTP or IMAP server's directly
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/