Created
February 3, 2023 19:38
-
-
Save hisabimbola/cfc9df00b4d713cc2021c1d18b357764 to your computer and use it in GitHub Desktop.
group emails by sender
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
import { promises as fs } from 'fs'; | |
import * as path from 'path' | |
import { authenticate } from '@google-cloud/local-auth'; | |
import { gmail_v1, google } from 'googleapis' | |
import { JSONClient } from 'google-auth-library/build/src/auth/googleauth'; | |
import { OAuth2Client } from 'google-auth-library'; | |
const SCOPES = ['https://mail.google.com/']; | |
// 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 = path.join(process.cwd(), 'token.json'); | |
const MAIL_LIST_PATH = path.join(process.cwd(), 'mail-list.json') | |
const MAILS_PATH = path.join(process.cwd(), 'mails.json') | |
const CREDENTIALS_PATH = path.join(process.cwd(), 'credentials.json'); | |
function getResultPath(email: string) { | |
return path.join(process.cwd(), `result2-${email}.json`) | |
} | |
async function loadSavedCredentialsIfExist() { | |
try { | |
const content = await fs.readFile(TOKEN_PATH) as unknown as string; | |
const credentials = JSON.parse(content); | |
return google.auth.fromJSON(credentials); | |
} catch (err) { | |
return null; | |
} | |
} | |
async function saveCredentials(client: JSONClient | OAuth2Client) { | |
const content = await fs.readFile(CREDENTIALS_PATH) as unknown as string; | |
const keys = JSON.parse(content); | |
const key = keys.installed || keys.web; | |
const payload = JSON.stringify({ | |
type: 'authorized_user', | |
client_id: key.client_id, | |
client_secret: key.client_secret, | |
refresh_token: client.credentials.refresh_token, | |
}); | |
await fs.writeFile(TOKEN_PATH, payload); | |
} | |
async function authorize() { | |
let client: JSONClient | OAuth2Client | null | |
client = await loadSavedCredentialsIfExist(); | |
if (client) { | |
return client; | |
} | |
client = await authenticate({ | |
scopes: SCOPES, | |
keyfilePath: CREDENTIALS_PATH, | |
}); | |
if (client?.credentials) { | |
await saveCredentials(client); | |
} | |
return client; | |
} | |
const mailList: gmail_v1.Schema$Message[] = [] | |
async function listEmails(auth: JSONClient | OAuth2Client) { | |
const gmail = google.gmail({version: 'v1', auth}) | |
let nextPageToken: string | undefined | |
let count = 0 | |
do { | |
const res = await gmail.users.messages.list({ | |
userId: 'me', | |
maxResults: 500, | |
pageToken: nextPageToken | |
}) | |
mailList.push(...(res.data.messages || [])) | |
count += res.data.messages?.length || 0 | |
nextPageToken = res.data.nextPageToken as string | undefined | |
} while (nextPageToken) | |
console.log('fetched', count, 'messages') | |
console.log(mailList.length, 'count of messages') | |
await fs.writeFile(MAIL_LIST_PATH, JSON.stringify(mailList)); | |
return auth | |
} | |
async function getCurrentUserEmail(auth: JSONClient | OAuth2Client) { | |
const gmail = google.gmail({version: 'v1', auth}) | |
const res = await gmail.users.getProfile({ | |
userId: 'me' | |
}) | |
const email = res.data.emailAddress as string | |
return email.toLowerCase() | |
} | |
const senderMap = new Map() | |
async function getMails(auth: JSONClient | OAuth2Client) { | |
const gmail = google.gmail({version: 'v1', auth}) | |
const rawData = await fs.readFile(MAIL_LIST_PATH) as unknown as string; | |
const mailList = JSON.parse(rawData); | |
let count = 0 | |
const currentUserEmail = await getCurrentUserEmail(auth); | |
if (mailList.length) { | |
while(count < mailList.length) { | |
const res = await gmail.users.messages.get({ | |
userId: 'me', | |
id: mailList[count].id, | |
format: 'metadata' | |
}) | |
const message = res.data | |
const fromHeader = message.payload?.headers?.find((val) => val.name?.toLowerCase() === 'from') | |
let sender = fromHeader?.value?.match(/<(.*)>/)?.[1].toLowerCase() | |
if (!sender) { | |
sender = fromHeader?.value?.toLowerCase() as string | |
} | |
if (sender !== currentUserEmail && sender) { | |
senderMap.set(sender.toLowerCase(), (senderMap.get(sender.toLowerCase()) || 0) + 1) | |
} | |
count++ | |
} | |
} | |
const sortedArray = [...senderMap.entries()].sort((a,b) => b[1] - a[1]) | |
console.log(sortedArray) | |
await fs.writeFile(getResultPath(currentUserEmail), JSON.stringify(sortedArray, null, 2)); | |
return auth | |
} | |
async function cleanUp() { | |
await fs.rm(MAIL_LIST_PATH) | |
} | |
authorize().then(listEmails).then(getMails).then(cleanUp).catch(console.error); |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
{ | |
"dependencies": { | |
"@google-cloud/local-auth": "^2.1.0", | |
"googleapis": "^105.0.0" | |
}, | |
"devDependencies": { | |
"@types/node": "^18.11.18" | |
} | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment