Skip to content

Instantly share code, notes, and snippets.

@maatthc
Last active July 19, 2021 08:46
Show Gist options
  • Star 1 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save maatthc/82ee4bcf7fefce723c8c31a76a428652 to your computer and use it in GitHub Desktop.
Save maatthc/82ee4bcf7fefce723c8c31a76a428652 to your computer and use it in GitHub Desktop.
How to use the Gmail API - Firstly enable the Gmail API on your account: https://developers.google.com/gmail/api/quickstart/nodejs
/* eslint-disable camelcase */
import { Gmail, gmail_v1, GaxiosResponse } from './gmail-client'
const SEARCH_PATTERN = 'My subject is ..'
const init = async () => {
const client = new Gmail()
console.log('Authenticating...')
await client.authorize()
console.log(`Searching for emails that contains ${SEARCH_PATTERN}..`)
const messagesId = await client.searchMessagesId(SEARCH_PATTERN)
console.log(messagesId)
const fullMessagesPromises = messagesId!.map(m => client.getMessageContent(m.id))
const fullMessages = await Promise.all<GaxiosResponse<gmail_v1.Schema$Message>>(
fullMessagesPromises,
)
const message = client.findLatestMessage(fullMessages)
if (message?.data.id) {
console.log(message)
const body = client.getMessageDecodedBody(message)
console.log(body)
console.log('\n=================================\n')
console.log('Deleting the latest message..')
await client.deleteMessage(message.data.id)
} else {
console.log('No messages found.')
}
}
init()
/* eslint-disable camelcase */
export interface AppCredentials {
installed: {
client_secret: string
client_id: string
redirect_uris: string[]
}
}
/* eslint-disable camelcase */
import * as fs from 'fs'
import * as path from 'path'
import { google, GoogleApis } from 'googleapis'
import * as inquirer from 'inquirer'
import { AppCredentials } from './app-credentials'
const GMAIL_ACCOUNT = 'my-email@gmail.com'
const SCOPES = ['https://www.googleapis.com/auth/gmail.modify']
const TOKEN_FILE = 'token.json'
const APP_CREDENTIALS_FILE = 'credentials.json'
type OAuth2Client = typeof GoogleApis.prototype.auth.OAuth2.prototype
const getAuthUrl = async (oauth2Client: OAuth2Client) => {
return oauth2Client.generateAuthUrl({
access_type: 'offline',
scope: SCOPES,
})
}
const getAuthCode = async () => {
return inquirer.prompt({
type: 'input',
name: 'code',
message: `Please enter the code provided by the Google Page above (click in 'Advanced'):`,
})
}
const generateNewUserAuthToken = async (credentials: AppCredentials) => {
const { client_secret, client_id, redirect_uris } = credentials.installed
const oAuth2Client = new google.auth.OAuth2(client_id, client_secret, redirect_uris[0])
const authUrl = await getAuthUrl(oAuth2Client)
console.log(`Authorize this app by visiting this url (logged as ${GMAIL_ACCOUNT}): \n`, authUrl)
const code = await getAuthCode()
const newAuthToken = await oAuth2Client.getToken(code)
console.log('Update Token file with new content: ', JSON.stringify(newAuthToken.tokens))
return newAuthToken.tokens
}
const init = async () => {
const appCredentials = fs.readFileSync(path.resolve(__dirname, APP_CREDENTIALS_FILE))
console.log('Authenticating...')
const token = await generateNewUserAuthToken(JSON.parse(appCredentials.toString()))
console.log(`Saving new token to file ${TOKEN_FILE}`)
fs.writeFileSync(path.resolve(__dirname, TOKEN_FILE), JSON.stringify(token))
}
init()
/* eslint-disable camelcase */
import * as fs from 'fs'
import * as path from 'path'
import { google, gmail_v1 } from 'googleapis'
import { GaxiosResponse } from 'gaxios'
import { Credentials } from 'google-auth-library'
import { AppCredentials } from './app-credentials'
const TOKEN_FILE = 'token.json' // Must be generated by : generate-gmail-auth-token.ts
const APP_CREDENTIALS_FILE = 'credentials.json' // OAuth 2.0 Client ID credential of your App
class Gmail {
gmail: gmail_v1.Gmail
appCredentials: AppCredentials
token: Credentials
constructor() {
this.gmail = google.gmail({ version: 'v1' })
this.appCredentials = JSON.parse(
fs.readFileSync(path.resolve(__dirname, APP_CREDENTIALS_FILE)).toString(),
)
this.token = JSON.parse(fs.readFileSync(path.resolve(__dirname, TOKEN_FILE)).toString())
}
authorize = async (): Promise<void> => {
const { client_secret, client_id, redirect_uris } = this.appCredentials.installed
const oAuth2Client = new google.auth.OAuth2(client_id, client_secret, redirect_uris[0])
try {
oAuth2Client.setCredentials(this.token)
await oAuth2Client.getAccessToken() // Intended to validate authentication
} catch (e) {
throw new Error(`Auth Token might be expired: ${e}`)
} finally {
google.options({
auth: oAuth2Client,
})
}
}
searchMessagesId = async (
query: string,
userId = 'me',
): Promise<gmail_v1.Schema$Message[] | undefined> => {
const messages = await this.gmail.users.messages.list({
userId,
includeSpamTrash: false,
q: query,
})
return messages.data.messages
}
getMessageContent = async (
messageId: string | null | undefined,
userId = 'me',
): Promise<GaxiosResponse<gmail_v1.Schema$Message>> =>
this.gmail.users.messages.get({
userId,
id: messageId,
})
findLatestMessage = (
messages: GaxiosResponse<gmail_v1.Schema$Message>[],
): GaxiosResponse<gmail_v1.Schema$Message> | null => {
if (messages) {
messages.sort(
(a, b) =>
parseInt((b?.data).internalDate || '', 10) - parseInt((a?.data).internalDate || '', 10),
)
return messages[0]
}
return null
}
getMessageDecodedBody = (message: GaxiosResponse): any => {
const body = message.data.payload.parts[0].body.data
const codedBody = Buffer.alloc(body.length, body, 'base64')
const decodedBody = codedBody.toString('ascii')
return decodedBody
}
deleteMessage = async (messageId: string, userId = 'me'): Promise<any> => {
const result = await this.gmail.users.messages.trash({
userId,
id: messageId,
})
return result
}
}
export { Gmail, GaxiosResponse, gmail_v1 }
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment