Search code examples
node.jsoauth-2.0push-notificationgmailgmail-api

Gmail API Push Notifications with Nodejs


I'm making a web-app with Nodejs and Gmail API that notifies me about E-mails received in a certain label.

After some research, I found this guide: Push Notifications | Gmail API

But I've come to a halt as I cannot understand what to do after this.

The watch() function works fine and gives me the correct response.

Here is my full code (The authorization part is taken from the Gmail API's quickstart guide for Nodejs):

const fs = require('fs');
const http = require('http');
const readline = require('readline');
const {
    google
} = require('googleapis');

// If modifying these scopes, delete token.json.
const SCOPES = ['https://www.googleapis.com/auth/gmail.readonly', "https://www.googleapis.com/auth/pubsub"];
// The file token.json stores the user's access and refresh tokens, and is
// created automatically when the authorization flow completes for the first
// time.
const TOKEN_PATH = 'token.json';

// Load client secrets from a local file.
fs.readFile('credentials.json', (err, content) => {
    if (err) return console.log('Error loading client secret file:', err);
    // Authorize a client with credentials, then call the Gmail API.
    authorize(JSON.parse(content), (auth) => {
        listUnreadMsgs(auth), watchMyLabel(auth)
    });
});

/**
 * Create an OAuth2 client with the given credentials, and then execute the
 * given callback function.
 * @param {Object} credentials The authorization client credentials.
 * @param {function} callback The callback to call with the authorized client.
 */
function authorize(credentials, callback) {
    const {
        client_secret,
        client_id,
        redirect_uris
    } = credentials.installed;
    const oAuth2Client = new google.auth.OAuth2(
        client_id, client_secret, redirect_uris[0]);

    // Check if we have previously stored a token.
    fs.readFile(TOKEN_PATH, (err, token) => {
        if (err) return getNewToken(oAuth2Client, callback);
        oAuth2Client.setCredentials(JSON.parse(token));
        callback(oAuth2Client);
    });
}

/**
 * Get and store new token after prompting for user authorization, and then
 * execute the given callback with the authorized OAuth2 client.
 * @param {google.auth.OAuth2} oAuth2Client The OAuth2 client to get token for.
 * @param {getEventsCallback} callback The callback for the authorized client.
 */
function getNewToken(oAuth2Client, callback) {
    const authUrl = oAuth2Client.generateAuthUrl({
        access_type: 'offline',
        scope: SCOPES,
    });
    console.log('Authorize this app by visiting this url:', authUrl);
    const rl = readline.createInterface({
        input: process.stdin,
        output: process.stdout,
    });
    rl.question('Enter the code from that page here: ', (code) => {
        rl.close();
        oAuth2Client.getToken(code, (err, token) => {
            if (err) return console.error('Error retrieving access token', err);
            oAuth2Client.setCredentials(token);
            // Store the token to disk for later program executions
            fs.writeFile(TOKEN_PATH, JSON.stringify(token), (err) => {
                if (err) return console.error(err);
                console.log('Token stored to', TOKEN_PATH);
            });
            callback(oAuth2Client);
        });
    });
}
/**
 * Lists the labels in the user's account.
 *
 * @param {google.auth.OAuth2} auth An authorized OAuth2 client.
 */
async function listUnreadMsgs(auth) {
    var gmail = google.gmail({
        auth: auth,
        version: 'v1'
    });

    gmail.users.history.list({
        userId: "me",
        startHistoryId: 2982217,
        labelId: 'Label_8061975816208384485'
    }, async function (err, results) {
        // https://developers.google.com/gmail/api/v1/reference/users/history/list#response
        if (err) return console.log(err);
        const latest = await results.data.history[results.data.history.length - 1].messages;
        gmail.users.messages.get({
            userId: 'me',
            id: latest[latest.length - 1].id
        }, (err, res) => {
            if (res.data.labelIds.includes('UNREAD')) {
                console.log(res.data.snippet);
            } else {
                console.log('No unread messages here!');
            }
        });

    });
}

/**
 * Lists the labels in the user's account.
 *
 * @param {google.auth.OAuth2} auth An authorized OAuth2 client.
 */
async function watchMyLabel(auth) {
    const gmail = google.gmail({
        version: 'v1',
        auth
    });
    const res = await gmail.users.watch({
        userId: 'me',
        requestBody: {
            labelIds: ['Label_8061975816208384485', 'UNREAD'],
            labelFilterAction: "include",
            topicName: 'projects/quickstart-1593237046786/topics/notifications'
        }
    });
}

And here is the output:

And here

What to do next?

TL;DR

  • I'm making a push notification system from Gmail API with Nodejs.
  • I don't understand what to do after this
  • I want to console.log the changes in my mailbox in real-time, without restarting the nodejs app.

Thank you. Please help =).

EDIT : I have no prior understanding of webhooks so it would be really good if anyone could explain me exactly what to do next in my case.


Solution

  • Turns out the next step was to use the Google Cloud Pub/Sub API: Receiving messages using Pull.

    Ensure proper authorization and user access.