opengraph stuff
This commit is contained in:
@@ -0,0 +1,407 @@
|
||||
/**
|
||||
* Gmail API - Node.js/TypeScript Example
|
||||
*
|
||||
* Complete working example showing all major operations.
|
||||
* Save this file and run: npx ts-node example-nodejs.ts
|
||||
*/
|
||||
|
||||
import fs from "fs/promises";
|
||||
import readline from "readline";
|
||||
import { google, gmail_v1 } from "googleapis";
|
||||
import { OAuth2Client } from "google-auth-library";
|
||||
|
||||
// Configuration
|
||||
const SCOPES = ["https://www.googleapis.com/auth/gmail.modify"];
|
||||
const CREDENTIALS_PATH = "credentials.json";
|
||||
const TOKEN_PATH = "token.json";
|
||||
|
||||
/**
|
||||
* Authenticate user and return Gmail service
|
||||
*/
|
||||
async function authenticate(): Promise<gmail_v1.Gmail> {
|
||||
try {
|
||||
const credentialsContent = await fs.readFile(CREDENTIALS_PATH, "utf-8");
|
||||
const credentials = JSON.parse(credentialsContent);
|
||||
const { client_id, client_secret, redirect_uris } = credentials.installed;
|
||||
|
||||
const oauth2Client = new google.auth.OAuth2(
|
||||
client_id,
|
||||
client_secret,
|
||||
redirect_uris[0]
|
||||
);
|
||||
|
||||
// Check for cached token
|
||||
try {
|
||||
const tokenContent = await fs.readFile(TOKEN_PATH, "utf-8");
|
||||
const token = JSON.parse(tokenContent);
|
||||
oauth2Client.setCredentials(token);
|
||||
|
||||
// Refresh if expired
|
||||
if (token.expiry_date && token.expiry_date < Date.now()) {
|
||||
const newToken = await oauth2Client.refreshAccessToken();
|
||||
oauth2Client.setCredentials(newToken.credentials);
|
||||
await fs.writeFile(TOKEN_PATH, JSON.stringify(newToken.credentials));
|
||||
}
|
||||
|
||||
console.log("✅ Using cached credentials");
|
||||
return google.gmail({ version: "v1", auth: oauth2Client });
|
||||
} catch {
|
||||
// No token, need to authenticate
|
||||
console.log("⚠️ No cached token, initiating authentication...");
|
||||
return authenticateUser(oauth2Client);
|
||||
}
|
||||
} catch (error) {
|
||||
console.error("❌ Authentication failed:", error);
|
||||
throw error;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Get user authorization via browser
|
||||
*/
|
||||
async function authenticateUser(
|
||||
oauth2Client: OAuth2Client
|
||||
): Promise<gmail_v1.Gmail> {
|
||||
const authUrl = oauth2Client.generateAuthUrl({
|
||||
access_type: "offline",
|
||||
scope: SCOPES,
|
||||
});
|
||||
|
||||
console.log(`\n🔗 Please visit this URL to authorize:\n${authUrl}\n`);
|
||||
|
||||
const rl = readline.createInterface({
|
||||
input: process.stdin,
|
||||
output: process.stdout,
|
||||
});
|
||||
|
||||
return new Promise((resolve, reject) => {
|
||||
rl.question("Enter the authorization code: ", async (code) => {
|
||||
rl.close();
|
||||
try {
|
||||
const { tokens } = await oauth2Client.getToken(code);
|
||||
oauth2Client.setCredentials(tokens);
|
||||
await fs.writeFile(TOKEN_PATH, JSON.stringify(tokens));
|
||||
console.log("✅ Token saved");
|
||||
resolve(google.gmail({ version: "v1", auth: oauth2Client }));
|
||||
} catch (error) {
|
||||
reject(error);
|
||||
}
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* Get user profile
|
||||
*/
|
||||
async function getProfile(gmail: gmail_v1.Gmail) {
|
||||
console.log("\n📋 Getting user profile...");
|
||||
const response = await gmail.users.getProfile({ userId: "me" });
|
||||
const data = response.data;
|
||||
|
||||
console.log(` Email: ${data.emailAddress}`);
|
||||
console.log(` Total Messages: ${data.messagesTotal}`);
|
||||
console.log(` Total Threads: ${data.threadsTotal}`);
|
||||
|
||||
return data;
|
||||
}
|
||||
|
||||
/**
|
||||
* List all labels
|
||||
*/
|
||||
async function listLabels(gmail: gmail_v1.Gmail) {
|
||||
console.log("\n🏷️ Listing labels...");
|
||||
const response = await gmail.users.labels.list({ userId: "me" });
|
||||
const labels = response.data.labels || [];
|
||||
|
||||
labels.slice(0, 10).forEach((label) => {
|
||||
console.log(` - ${label.name} (ID: ${label.id})`);
|
||||
});
|
||||
|
||||
console.log(` ... and ${Math.max(0, labels.length - 10)} more`);
|
||||
return labels;
|
||||
}
|
||||
|
||||
/**
|
||||
* List inbox messages
|
||||
*/
|
||||
async function listInboxMessages(gmail: gmail_v1.Gmail) {
|
||||
console.log("\n📧 Listing inbox messages (last 5)...");
|
||||
const response = await gmail.users.messages.list({
|
||||
userId: "me",
|
||||
q: "in:inbox",
|
||||
maxResults: 5,
|
||||
});
|
||||
|
||||
const messages = response.data.messages || [];
|
||||
|
||||
for (const message of messages) {
|
||||
const msgDetails = await gmail.users.messages.get({
|
||||
userId: "me",
|
||||
id: message.id!,
|
||||
format: "metadata",
|
||||
metadataHeaders: ["Subject", "From", "Date"],
|
||||
});
|
||||
|
||||
const headers = msgDetails.data.payload?.headers || [];
|
||||
const subject =
|
||||
headers.find((h) => h.name === "Subject")?.value || "No Subject";
|
||||
const from = headers.find((h) => h.name === "From")?.value || "Unknown";
|
||||
const date = headers.find((h) => h.name === "Date")?.value || "Unknown";
|
||||
|
||||
console.log(`\n From: ${from}`);
|
||||
console.log(` Subject: ${subject}`);
|
||||
console.log(` Date: ${date}`);
|
||||
}
|
||||
|
||||
return messages;
|
||||
}
|
||||
|
||||
/**
|
||||
* Search messages
|
||||
*/
|
||||
async function searchMessages(gmail: gmail_v1.Gmail, query: string) {
|
||||
console.log(`\n🔍 Searching for: ${query}`);
|
||||
const response = await gmail.users.messages.list({
|
||||
userId: "me",
|
||||
q: query,
|
||||
maxResults: 5,
|
||||
});
|
||||
|
||||
const messages = response.data.messages || [];
|
||||
console.log(` Found ${messages.length} messages`);
|
||||
|
||||
return messages;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get full message details
|
||||
*/
|
||||
async function getFullMessage(gmail: gmail_v1.Gmail, messageId: string) {
|
||||
console.log(`\n📄 Getting full message: ${messageId}`);
|
||||
const response = await gmail.users.messages.get({
|
||||
userId: "me",
|
||||
id: messageId,
|
||||
format: "full",
|
||||
});
|
||||
|
||||
const message = response.data;
|
||||
const headers = message.payload?.headers || [];
|
||||
const bodyData = message.payload?.body?.data || "";
|
||||
|
||||
const subject =
|
||||
headers.find((h) => h.name === "Subject")?.value || "No Subject";
|
||||
const from = headers.find((h) => h.name === "From")?.value || "Unknown";
|
||||
const to = headers.find((h) => h.name === "To")?.value || "Unknown";
|
||||
|
||||
let body = "";
|
||||
if (bodyData) {
|
||||
body = Buffer.from(bodyData, "base64").toString();
|
||||
}
|
||||
|
||||
console.log(` Subject: ${subject}`);
|
||||
console.log(` From: ${from}`);
|
||||
console.log(` To: ${to}`);
|
||||
console.log(` Body length: ${body.length} chars`);
|
||||
|
||||
return {
|
||||
subject,
|
||||
from,
|
||||
to,
|
||||
body: body.substring(0, 500), // First 500 chars
|
||||
};
|
||||
}
|
||||
|
||||
/**
|
||||
* Send a message
|
||||
*/
|
||||
async function sendMessage(
|
||||
gmail: gmail_v1.Gmail,
|
||||
to: string,
|
||||
subject: string,
|
||||
body: string
|
||||
) {
|
||||
console.log(`\n✉️ Sending message to ${to}...`);
|
||||
|
||||
const message =
|
||||
`From: me\r\n` +
|
||||
`To: ${to}\r\n` +
|
||||
`Subject: ${subject}\r\n` +
|
||||
`\r\n` +
|
||||
`${body}`;
|
||||
|
||||
const encodedMessage = Buffer.from(message)
|
||||
.toString("base64")
|
||||
.replace(/\+/g, "-")
|
||||
.replace(/\//g, "_")
|
||||
.replace(/=+$/, "");
|
||||
|
||||
const response = await gmail.users.messages.send({
|
||||
userId: "me",
|
||||
requestBody: {
|
||||
raw: encodedMessage,
|
||||
},
|
||||
});
|
||||
|
||||
console.log(` ✅ Message sent with ID: ${response.data.id}`);
|
||||
return response.data;
|
||||
}
|
||||
|
||||
/**
|
||||
* Create a draft
|
||||
*/
|
||||
async function createDraft(
|
||||
gmail: gmail_v1.Gmail,
|
||||
to: string,
|
||||
subject: string,
|
||||
body: string
|
||||
) {
|
||||
console.log(`\n📝 Creating draft for ${to}...`);
|
||||
|
||||
const message =
|
||||
`From: me\r\n` +
|
||||
`To: ${to}\r\n` +
|
||||
`Subject: ${subject}\r\n` +
|
||||
`\r\n` +
|
||||
`${body}`;
|
||||
|
||||
const encodedMessage = Buffer.from(message)
|
||||
.toString("base64")
|
||||
.replace(/\+/g, "-")
|
||||
.replace(/\//g, "_")
|
||||
.replace(/=+$/, "");
|
||||
|
||||
const response = await gmail.users.drafts.create({
|
||||
userId: "me",
|
||||
requestBody: {
|
||||
message: {
|
||||
raw: encodedMessage,
|
||||
},
|
||||
},
|
||||
});
|
||||
|
||||
console.log(` ✅ Draft created with ID: ${response.data.id}`);
|
||||
return response.data;
|
||||
}
|
||||
|
||||
/**
|
||||
* Apply label to message
|
||||
*/
|
||||
async function applyLabelToMessage(
|
||||
gmail: gmail_v1.Gmail,
|
||||
messageId: string,
|
||||
labelName: string
|
||||
) {
|
||||
console.log(`\n🏷️ Applying label "${labelName}" to message...`);
|
||||
|
||||
const labelsResponse = await gmail.users.labels.list({ userId: "me" });
|
||||
const label = labelsResponse.data.labels?.find((l) => l.name === labelName);
|
||||
|
||||
if (!label) {
|
||||
console.log(` ❌ Label "${labelName}" not found`);
|
||||
return null;
|
||||
}
|
||||
|
||||
const response = await gmail.users.messages.modify({
|
||||
userId: "me",
|
||||
id: messageId,
|
||||
requestBody: {
|
||||
addLabelIds: [label.id!],
|
||||
},
|
||||
});
|
||||
|
||||
console.log(` ✅ Label applied`);
|
||||
return response.data;
|
||||
}
|
||||
|
||||
/**
|
||||
* List threads
|
||||
*/
|
||||
async function listThreads(gmail: gmail_v1.Gmail) {
|
||||
console.log("\n💬 Listing threads (last 3)...");
|
||||
const response = await gmail.users.threads.list({
|
||||
userId: "me",
|
||||
q: "in:inbox",
|
||||
maxResults: 3,
|
||||
});
|
||||
|
||||
const threads = response.data.threads || [];
|
||||
|
||||
for (const thread of threads) {
|
||||
const threadData = await gmail.users.threads.get({
|
||||
userId: "me",
|
||||
id: thread.id!,
|
||||
format: "metadata",
|
||||
});
|
||||
|
||||
const numMessages = threadData.data.messages?.length || 0;
|
||||
const firstMsg = threadData.data.messages?.[0];
|
||||
const headers = firstMsg?.payload?.headers || [];
|
||||
const subject =
|
||||
headers.find((h) => h.name === "Subject")?.value || "No Subject";
|
||||
|
||||
console.log(
|
||||
`\n Thread ${thread.id}: ${numMessages} messages - "${subject}"`
|
||||
);
|
||||
}
|
||||
|
||||
return threads;
|
||||
}
|
||||
|
||||
/**
|
||||
* Move message to trash
|
||||
*/
|
||||
async function moveToTrash(gmail: gmail_v1.Gmail, messageId: string) {
|
||||
console.log(`\n🗑️ Moving message to trash...`);
|
||||
const response = await gmail.users.messages.trash({
|
||||
userId: "me",
|
||||
id: messageId,
|
||||
});
|
||||
|
||||
console.log(` ✅ Message moved to trash`);
|
||||
return response.data;
|
||||
}
|
||||
|
||||
/**
|
||||
* Main demo function
|
||||
*/
|
||||
async function main() {
|
||||
console.log("🚀 Gmail API - Node.js/TypeScript Example\n");
|
||||
|
||||
try {
|
||||
// Authenticate
|
||||
const gmail = await authenticate();
|
||||
|
||||
// Run examples
|
||||
await getProfile(gmail);
|
||||
await listLabels(gmail);
|
||||
await listInboxMessages(gmail);
|
||||
|
||||
// Search example
|
||||
await searchMessages(gmail, "is:unread");
|
||||
|
||||
// Get first message details
|
||||
const messages = await listInboxMessages(gmail);
|
||||
if (messages.length > 0) {
|
||||
await getFullMessage(gmail, messages[0].id!);
|
||||
}
|
||||
|
||||
// Draft example (uncomment to use)
|
||||
// await createDraft(
|
||||
// gmail,
|
||||
// "recipient@example.com",
|
||||
// "Test Draft",
|
||||
// "This is a test draft created by the example script."
|
||||
// );
|
||||
|
||||
// List threads
|
||||
await listThreads(gmail);
|
||||
|
||||
console.log("\n✅ All examples completed!");
|
||||
} catch (error) {
|
||||
console.error("\n❌ Error:", error);
|
||||
process.exit(1);
|
||||
}
|
||||
}
|
||||
|
||||
// Run if executed directly
|
||||
main();
|
||||
Reference in New Issue
Block a user