gmail-tester-extended
Version:
A simple NodeJS gmail client which checks the inbox for specific message existance
356 lines (335 loc) • 11.6 kB
JavaScript
const fs = require("fs");
const path = require("path");
const readline = require("readline");
const {google} = require("googleapis");
const Base64 = require('js-base64').Base64;
const MailComposer = require('nodemailer/lib/mail-composer');
// If modifying these scopes, delete token.json.
const SCOPES = ["https://www.googleapis.com/auth/gmail.readonly",
"https://www.googleapis.com/auth/gmail.send"];
// 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";
/**
* Create an OAuth2 client with the given credentials, and then execute the
* given callback function.
* @param {Object} credentials The authorization client credentials.
*/
async function authorize(credentials, token_path) {
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.
try {
const token = fs.readFileSync(
token_path || path.resolve(__dirname, TOKEN_PATH)
);
oAuth2Client.setCredentials(JSON.parse(token));
return oAuth2Client;
} catch (error) {
return await get_new_token(oAuth2Client, token_path);
}
}
/**
* 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.
*/
async function get_new_token(oAuth2Client, token_path) {
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
});
return new Promise((resolve, reject) => {
rl.question("Enter the code from that page here: ", async code => {
rl.close();
oAuth2Client.getToken(code, function (err, token) {
if (err) {
reject(err);
} else {
oAuth2Client.setCredentials(token);
fs.writeFileSync(
token_path || path.resolve(__dirname, TOKEN_PATH),
JSON.stringify(token)
);
resolve(oAuth2Client);
}
});
});
});
}
/**
* Lists the labels in the user's account.
*
* @param {google.auth.OAuth2} auth An authorized OAuth2 client.
*/
async function list_labels(gmail, oauth2Client) {
try {
const labels = await new Promise((resolve, reject) => {
gmail.users.labels.list(
{
userId: "me",
auth: oauth2Client
},
function (err, res) {
if (err) {
reject(err);
} else {
const labels = res.data.labels;
resolve(labels);
}
}
);
});
return labels;
} catch (err) {
console.log("The API returned an error: " + err);
throw err;
}
}
/**
* Retrieve Messages in user's mailbox matching query.
*
* @param {String} userId User's email address. The special value 'me'
* can be used to indicate the authenticated user.
* @param {String} query String used to filter the Messages listed.
*/
async function list_messages(gmail, oauth2Client, query, labelIds) {
const messages = await new Promise((resolve, reject) => {
gmail.users.messages.list(
{
userId: "me",
q: query,
auth: oauth2Client,
labelIds: labelIds
},
async function (err, res) {
if (err) {
reject(err);
} else {
let result = res.data.messages || [];
let {nextPageToken} = res.data;
while (nextPageToken) {
const resp = await new Promise((resolve, reject) => {
gmail.users.messages.list(
{
userId: "me",
q: query,
auth: oauth2Client,
labelIds: labelIds,
pageToken: nextPageToken
},
function (err, res) {
if (err) {
reject(err);
} else {
resolve(res);
}
}
);
});
result = result.concat(resp.data.messages);
nextPageToken = resp.data.nextPageToken;
}
resolve(result);
}
}
);
});
let result = messages || [];
return result;
}
/**
* Get the recent email from your Gmail account
*
* @param {google.auth.OAuth2} oauth2Client An authorized OAuth2 client.
* @param {String} query String used to filter the Messages listed.
*/
async function get_recent_email(gmail, oauth2Client, query = "") {
try {
const labels = await list_labels(gmail, oauth2Client);
const inbox_label_id = [labels.find(l => l.name === "INBOX").id];
const messages = await list_messages(
gmail,
oauth2Client,
query,
inbox_label_id
);
let promises = [];
for (let message of messages) {
promises.push(
new Promise((resolve, reject) => {
gmail.users.messages.get(
{
auth: oauth2Client,
userId: "me",
id: message.id,
format: "full"
},
function (err, res) {
if (err) {
reject(err);
} else {
resolve(res);
}
}
);
})
);
}
const results = await Promise.all(promises);
return results.map(r => r.data);
} catch (error) {
}
}
async function createEmail(to, from, subject, message) {
let email = ["Content-Type: text/plain; charset=\"UTF-8\"\n",
"MIME-Version: 1.0\n",
"Content-Transfer-Encoding: 7bit\n",
"to: ", to, "\n",
"from: ", from, "\n",
"subject: ", subject, "\n\n",
message
].join('');
return Base64.encodeURI(email);
}
async function reply(gmail, oauth2Client, threadId, subject, from, to, message) {
try {
let promises = [];
var email = ["Content-Type: text/plain; charset=\"UTF-8\"\n",
"MIME-Version: 1.0\n",
"Content-Transfer-Encoding: 7bit\n",
"to: ", to, "\n",
"from: ", from, "\n",
"subject: ", subject, "\n\n",
message
].join('');
var base64EncodedEmail = Base64.encodeURI(email);
promises.push(
new Promise((resolve, reject) => {
gmail.users.messages.send(
{
auth: oauth2Client,
userId: "me",
resource: {
raw: base64EncodedEmail,
threadId: threadId
}
},
function (err, res) {
if (err) {
reject(err);
} else {
resolve(res);
}
}
);
})
);
const result = await Promise.all(promises);
return result;
} catch (error) {
return 'Error ' + error
}
}
async function send(gmail, oauth2Client, subject, from, to, message) {
try {
let promises = [];
var email = ["Content-Type: text/plain; charset=\"UTF-8\"\n",
"MIME-Version: 1.0\n",
"Content-Transfer-Encoding: 7bit\n",
"to: ", to, "\n",
"from: ", from, "\n",
"subject: ", subject, "\n\n",
message
].join('');
var base64EncodedEmail = Base64.encodeURI(email);
promises.push(
new Promise((resolve, reject) => {
gmail.users.messages.send(
{
auth: oauth2Client,
userId: "me",
resource: {
raw: base64EncodedEmail,
}
},
function (err, res) {
if (err) {
reject(err);
} else {
resolve(res);
}
}
);
})
);
const result = await Promise.all(promises);
return result;
} catch (error) {
return 'Error ' + error
}
}
async function sendEmailWithAttachments(gmail, oauth2Client, subject, from, to, message, attachments) {
try {
let promises = [];
let mail = new MailComposer(
{
to: to,
html: " <html> " + message + " </html>",
subject: subject,
textEncoding: "base64",
attachments: attachments
});
mail.compile().build((error, msg) => {
if (error) return console.log('Error compiling email ' + error);
const encodedMessage = Buffer.from(msg)
.toString('base64')
.replace(/\+/g, '-')
.replace(/\//g, '_')
.replace(/=+$/, '');
const gmail = google.gmail({version: 'v1', oauth2Client});
promises.push(
new Promise((resolve, reject) => {
gmail.users.messages.send(
{
auth: oauth2Client,
userId: "me",
resource: {
raw: encodedMessage,
}
},
function (err, res) {
if (err) {
reject(err);
} else {
resolve(res);
}
}
);
})
);
});
const result = await Promise.all(promises);
return result;
} catch (error) {
return 'Error ' + error
}
}
module.exports = {
authorize,
get_recent_email,
reply,
send,
sendEmailWithAttachments
};