Cloud Schedule + Cloud Functions -> Gmail API watch() - WORKING NOW

611 views Asked by At

This is my first post here. I am sorry if it's a repost, but I've been searching for more than one month for the answer to solve my problem in all websites and forums and until now... no answers!

My goal is to make a Gmail pub/sub watch() to make an action whenever I receive a new email.

To do so, according to the developer's website, I need to subscribe to Gmail watch() on a daily basis with the code:

request = {
  'labelIds': ['INBOX'],
  'topicName': 'projects/myproject/topics/mytopic'
}
gmail.users().watch(userId='me', body=request).execute()

Until now i have this a working scheduled task with a service account, with INVOKER Permissions. This part just works fine.

In my "initial autorization function" i have:

const {google} = require('googleapis');

// Retrieve OAuth2 config
const oauth2Client = new google.auth.OAuth2(
  process.env.CLIENT_ID,
  process.env.CLIENT_SECRET,
  process.env.CALLBACK_URL
);

exports.oauth2init = (req, res) => {
  // Define OAuth2 scopes
  const scopes = [
    'https://www.googleapis.com/auth/gmail.modify'
  ];

  // Generate + redirect to OAuth2 consent form URL
  const authUrl = oauth2Client.generateAuthUrl({
    access_type: 'offline',
    scope: scopes,
    //prompt: 'none'// Required in order to receive a refresh token every time
  });
  return res.redirect(authUrl);

};

My issue now is that the access token is generated via (prompt) the first time and never updates to a new one ( the token expires after 1hour...) it means this code stops working after that period and a "manual" intervention is required. According with the documentation, i need to use "offline" method and on "prompt" i can omit (only requests permissions on the 1st time) or none (never asks), like is said here.

I managed how to make it work! tomorow i will continue with the process. Should i post here my working code for reference?

Thanks!

2

There are 2 answers

1
Ralemos On

The documentation you shared in the comments does not say that you can remove the token from the headers of the service account, also the gmail API documentation you also shared says that you only:

need to grant publish privileges to [email protected]. You can do this using the Cloud Pub/Sub Developer Console permissions interface following the resource-level access control instructions.

In order to achieve this basically what you will need is a setup of two cloud functions, the first scheduled function is responsible for setting up the watch(), and you can check this documentation for how to deploy a scheduled function, and the second function being triggered by the pubsub of gmail notifications, you can check this documentation for how to build an event triggered function. Both processes are similar.

NOTE: I have never user the Gmail API, so I am not sure if any extra steps are necessary but then again, the documentation implies that setting up the permissions of that service account is enough to make it work.


EDIT:

As per the information you have shared. The issue is likely that you are not properly setting the Service Account to authenticate with the Cloud Function. As per described in the documentation, you have to grant to the Service Account the role Cloud Functions Invoker in IAM.

Let me know if this fixed the issue.

0
chaiyachaiya On

I will rephrase the process you illustrated so that there is no ambiguity.

According the documentation you pushed:

  1. You do not suscribed to watch(), you call watch()
    watch() is an API call to the Gmail API that will enable automatic events publication on a pub/sub topic you define given conditions you specified. Who are you watching? On what events?
  2. You suscribe to a Pub/Sub topic that is targeted by your previous watch() call
    A process (e.g: Google cloud function) suscribes to the topic and will consume messages sent by the Gmail API
  3. The call is to be renewed at least every seven days
    Because Google needs to be sure you still need to monitor the targeted inbox, it needs a renewal from you. Another watch() call will act so.
  4. Cloud scheduler will enable this periodic renewal
    this service will trigger your renewal script you put in your question. To do so it needs to be authenticated to the platform that host the script. It is easier if your script is hosted in a google service (cloud function, cloud run,...) and the authent type depends on the target URL form. In all cases YOU DO NEED an authent token in your request header. The token is generated from a service account you created with the right permission to call your script (e.g: cloud run invoker). By default the scheduler has the right to generate a token from it

So far so good. Now comes the tricky part and you don't mention it in your question. How is authenticated your gmail api client? You cannot monitor someone inbox, unless this person gave you the permission to i.e you call the API with the right Oauth2 token. Indeed in the video you point they authenticat the user using this principe which is implemented in their code with Express-oauth2-handler. So you will have a cloud function to init end user authent and watch to his/her inbox. The renewal should do so but problem is user will not be there for accepting the end user consent. Here comes the offline access but it is beyond the scope of your question. Finally a second functions will suscribe to the pubsub topic and consume the message as you need. See their implementation code which populate a spreadsheet.