gmail-tester-extended
Version:
A simple NodeJS gmail client which checks the inbox for specific message existance
390 lines (370 loc) • 13.4 kB
JavaScript
const gmail = require("./gmail");
const fs = require("fs");
const {google} = require("googleapis");
const util = require("util");
function _get_header(name, headers) {
const found = headers.find(h => h.name === name);
return found && found.value;
}
function _init_query(options) {
const {to, from, subject, before, after} = options;
let query = "";
if (to) {
query += `to:"${to}" `;
}
if (from) {
query += `from:"${from}" `;
}
if (subject) {
query += `subject:(${subject}) `;
}
if (after) {
const after_epoch = Math.round(new Date(after).getTime() / 1000);
query += `after:${after_epoch} `;
}
if (before) {
const before_epoch = Math.round(new Date(before).getTime() / 1000);
query += `before:${before_epoch} `;
}
query = query.trim();
return query;
}
async function _get_recent_email(credentials_json, token_path, options = {}) {
const emails = [];
const query = _init_query(options);
// Load client secrets from a local file.
const content = fs.readFileSync(credentials_json);
const oAuth2Client = await gmail.authorize(JSON.parse(content), token_path);
const gmail_client = google.gmail({version: "v1", oAuth2Client});
const gmail_emails = await gmail.get_recent_email(
gmail_client,
oAuth2Client,
query
);
for (const gmail_email of gmail_emails) {
const email = {
from: _get_header("From", gmail_email.payload.headers),
subject: _get_header("Subject", gmail_email.payload.headers),
receiver: _get_header("Delivered-To", gmail_email.payload.headers),
threadId: gmail_email.threadId,
snippet: gmail_email.snippet,
date: new Date(+gmail_email["internalDate"]),
parts: gmail_email.payload.parts,
};
if (options.include_body) {
let email_body = {
html: "",
text: ""
};
const {body} = gmail_email.payload;
if (body.size) {
switch (gmail_email.payload.mimeType) {
case "text/html":
email_body.html = Buffer.from(body.data, "base64").toString("utf8");
break;
case "text/plain":
default:
email_body.text = Buffer.from(body.data, "base64").toString("utf8");
break;
}
} else {
let body_part = gmail_email.payload.parts.find(
p => p.mimeType === "text/html"
);
if (body_part) {
email_body.html = Buffer.from(body_part.body.data, "base64").toString(
"utf8"
);
}
body_part = gmail_email.payload.parts.find(
p => p.mimeType === "text/plain"
);
if (body_part) {
email_body.text = Buffer.from(body_part.body.data, "base64").toString(
"utf8"
);
}
}
email.body = email_body;
}
emails.push(email);
}
return emails;
}
async function reply_email(credentials_json,
token_path,
subject,
from,
to,
replyMessage,
wait_time_sec = 30,
max_wait_time_sec = 60,
options = {}) {
const content = fs.readFileSync(credentials_json);
const oAuth2Client = await gmail.authorize(JSON.parse(content), token_path);
const gmail_client = google.gmail({version: "v1", oAuth2Client});
var foundEmail = await check_inbox(credentials_json,
token_path,
subject,
from,
to,
wait_time_sec,
max_wait_time_sec,
options)
const response = await gmail.reply(
gmail_client,
oAuth2Client,
foundEmail.threadId,
subject,
to,
from,
replyMessage
);
return response;
}
async function send_email(credentials_json,
token_path,
subject,
from,
to,
emailMessage,
wait_time_sec = 30,
max_wait_time_sec = 60,
options = {}) {
const content = fs.readFileSync(credentials_json);
const oAuth2Client = await gmail.authorize(JSON.parse(content), token_path);
const gmail_client = google.gmail({version: "v1", oAuth2Client});
const response = await gmail.send(
gmail_client,
oAuth2Client,
subject,
from,
to,
emailMessage
);
return response;
}
async function send_email_with_attachments(credentials_json,
token_path,
subject,
from,
to,
emailMessage,
attachments,
wait_time_sec = 30,
max_wait_time_sec = 60,
options = {}) {
const content = fs.readFileSync(credentials_json);
const oAuth2Client = await gmail.authorize(JSON.parse(content), token_path);
const gmail_client = google.gmail({version: "v1", oAuth2Client});
const response = await gmail.sendEmailWithAttachments(
gmail_client,
oAuth2Client,
subject,
from,
to,
emailMessage,
attachments
);
return response;
}
async function get_all_emails(credentials_json, token_path, options = {}) {
const query = _init_query(options);
const content = fs.readFileSync(credentials_json);
const oAuth2Client = await gmail.authorize(JSON.parse(content), token_path);
const gmail_client = google.gmail({version: "v1", oAuth2Client});
const gmail_emails = await gmail.get_recent_email(
gmail_client,
oAuth2Client,
query
);
return gmail_emails;
}
async function login(credentials_json, token_path, options = {}) {
const query = _init_query(options);
const content = fs.readFileSync(credentials_json);
const oAuth2Client = await gmail.authorize(JSON.parse(content), token_path);
const gmail_client = google.gmail({version: "v1", oAuth2Client});
return gmail_client;
}
async function check_inbox(credentials_json,
token_path,
subject,
from,
to,
wait_time_sec = 30,
max_wait_time_sec = 60 * 5,
options = {}) {
try {
console.log(
`[gmail] Checking for message from '${from}', to: ${to}, contains '${subject}' in subject...`
);
// Load client secrets from a local file.
let found_email = null;
let done_waiting_time = 0;
do {
const emails = await _get_recent_email(
credentials_json,
token_path,
options
);
for (let email of emails) {
if (
email.receiver === to &&
email.subject.indexOf(subject) >= 0 &&
email.from.indexOf(from) >= 0
) {
console.log(`[gmail] Found!`);
found_email = email;
break;
}
}
if (!found_email) {
console.log(
`[gmail] Message not found. Waiting ${wait_time_sec} seconds...`
);
done_waiting_time += wait_time_sec;
if (done_waiting_time >= max_wait_time_sec) {
console.log("[gmail] Maximum waiting time exceeded!");
break;
}
await util.promisify(setTimeout)(wait_time_sec * 1000);
}
} while (!found_email);
return found_email;
} catch (err) {
console.log("[gmail] Error:", err);
}
}
async function getMessageWithTextInBody(credentials_json,
token_path,
subject,
from,
to,
bodyText,
wait_time_sec = 30,
max_wait_time_sec = 60 * 5,
options = {}) {
try {
console.log(
`[gmail] Checking for message from '${from}', to: ${to}, contains '${subject}' in subject...`
);
// Load client secrets from a local file.
let found_email = null;
let done_waiting_time = 0;
do {
const emails = await _get_recent_email(
credentials_json,
token_path,
options
);
for (let email of emails) {
if (
email.receiver === to &&
email.subject.indexOf(subject) >= 0 &&
email.from.indexOf(from) >= 0 &&
Buffer.from(email.parts[0].body.data, "base64").toString("utf8").indexOf(bodyText) >= 0
) {
console.log(`[gmail] Found!`);
found_email = email;
break;
}
}
if (!found_email) {
console.log(
`[gmail] Message not found. Waiting ${wait_time_sec} seconds...`
);
done_waiting_time += wait_time_sec;
if (done_waiting_time >= max_wait_time_sec) {
console.log("[gmail] Maximum waiting time exceeded!");
break;
}
await util.promisify(setTimeout)(wait_time_sec * 1000);
}
} while (!found_email);
return found_email;
} catch (err) {
console.log("[gmail] Error:", err);
}
}
async function checkGoogleEmailWithMessage(credentials_json,
token_path,
subject,
message,
from,
to,
wait_time_sec = 30,
max_wait_time_sec = 60,
options = {}) {
try {
console.log(
`[gmail] Checking for message from '${from}', to: ${to}, contains '${subject}' in subject...`
);
let found_email = null;
let done_waiting_time = 0;
do {
const emails = await _get_recent_email(
credentials_json,
token_path,
options
);
for (let email of emails) {
if (
email.receiver === to &&
email.subject.indexOf(subject) >= 0 &&
email.from.indexOf(from) >= 0 &&
email.snippet.indexOf(message) >=0
) {
console.log(`[gmail] Found!`);
found_email = email;
break;
}
}
if (!found_email) {
console.log(
`[gmail] Message not found. Waiting ${wait_time_sec} seconds...`
);
done_waiting_time += wait_time_sec;
if (done_waiting_time >= max_wait_time_sec) {
console.log("[gmail] Maximum waiting time exceeded!");
break;
}
await util.promisify(setTimeout)(wait_time_sec * 1000);
}
} while (!found_email);
return found_email;
} catch (err) {
console.log("[gmail] Error:", err);
}
}
/**
* Get an array of messages
*
* @param {string} credentials_json - Path to credentials json file.
* @param {string} token_path - Path to token json file.
* @param {Object} options
* @param {boolean} options.include_body - Return message body string.
*/
async function get_messages(credentials_json, token_path, options) {
try {
const emails = await _get_recent_email(
credentials_json,
token_path,
options
);
return emails;
} catch (err) {
console.log("[gmail] Error:", err);
}
}
module.exports = {
check_inbox,
get_messages,
get_all_emails,
reply_email,
send_email,
send_email_with_attachments,
getMessageWithTextInBody,
checkGoogleEmailWithMessage,
login
};