#!/usr/bin/env node import { google } from 'googleapis'; import minimist from 'minimist'; import { getAuthClient, parseAccountArg } from './auth/auth-utils.js'; import { logAction } from './action-logger.js'; function createEmailMessage(to, subject, body, options = {}) { const { cc, bcc, html, replyTo } = options; const headers = [ `To: ${to}`, `Subject: ${subject}`, ]; if (cc) headers.push(`Cc: ${cc}`); if (bcc) headers.push(`Bcc: ${bcc}`); if (replyTo) headers.push(`Reply-To: ${replyTo}`); headers.push('Content-Type: text/html; charset=utf-8'); headers.push(''); const message = headers.join('\r\n') + (html || body); return Buffer.from(message) .toString('base64') .replace(/\+/g, '-') .replace(/\//g, '_') .replace(/=+$/, ''); } async function manageDrafts(args) { const action = args.action || args.a; if (!action) { throw new Error('Missing required argument: --action (list|create|update|send|delete)'); } // Get authenticated client for specified account (or default) const accountId = parseAccountArg(args); const oauth2Client = await getAuthClient(accountId); const gmail = google.gmail({ version: 'v1', auth: oauth2Client }); switch (action) { case 'list': { const response = await gmail.users.drafts.list({ userId: 'me', maxResults: args.limit || 10 }); if (!response.data.drafts) { return { success: true, action: 'list', count: 0, drafts: [] }; } // Get details for each draft const drafts = await Promise.all( response.data.drafts.map(async (draft) => { const details = await gmail.users.drafts.get({ userId: 'me', id: draft.id }); const headers = details.data.message.payload.headers; const getHeader = (name) => headers.find(h => h.name === name)?.value || ''; return { id: draft.id, messageId: details.data.message.id, to: getHeader('To'), subject: getHeader('Subject'), snippet: details.data.message.snippet }; }) ); return { success: true, action: 'list', count: drafts.length, drafts: drafts }; } case 'create': { if (!args.to || !args.subject) { throw new Error('--to and --subject are required for create action'); } const encodedMessage = createEmailMessage( args.to, args.subject, args.body || '', { cc: args.cc, bcc: args.bcc, html: args.html, replyTo: args['reply-to'] } ); const response = await gmail.users.drafts.create({ userId: 'me', requestBody: { message: { raw: encodedMessage } } }); return { success: true, action: 'create', draftId: response.data.id, to: args.to, subject: args.subject }; } case 'update': { if (!args.id) { throw new Error('--id (draft ID) is required for update action'); } if (!args.to || !args.subject) { throw new Error('--to and --subject are required for update action'); } const encodedMessage = createEmailMessage( args.to, args.subject, args.body || '', { cc: args.cc, bcc: args.bcc, html: args.html, replyTo: args['reply-to'] } ); const response = await gmail.users.drafts.update({ userId: 'me', id: args.id, requestBody: { message: { raw: encodedMessage } } }); return { success: true, action: 'update', draftId: response.data.id, to: args.to, subject: args.subject }; } case 'send': { if (!args.id) { throw new Error('--id (draft ID) is required for send action'); } const response = await gmail.users.drafts.send({ userId: 'me', requestBody: { id: args.id } }); return { success: true, action: 'send', draftId: args.id, messageId: response.data.id, threadId: response.data.threadId }; } case 'delete': { if (!args.id) { throw new Error('--id (draft ID) is required for delete action'); } await gmail.users.drafts.delete({ userId: 'me', id: args.id }); return { success: true, action: 'delete', draftId: args.id }; } default: throw new Error(`Unknown action: ${action}. Use: list, create, update, send, or delete`); } } // Main execution const args = minimist(process.argv.slice(2)); const startTime = Date.now(); manageDrafts(args) .then(result => { // Log the action logAction('drafts', args, result, { account: args.account || 'default', duration: Date.now() - startTime, draftAction: result.action }); console.log(JSON.stringify(result, null, 2)); }) .catch(error => { const errorResult = { success: false, error: error.message }; // Log the failed action logAction('drafts', args, errorResult, { account: args.account || 'default', duration: Date.now() - startTime, failed: true }); console.error(JSON.stringify(errorResult, null, 2)); process.exit(1); });