← back to George Gmail

trash-fleet-mailtests.js

76 lines

/**
 * trash-fleet-mailtests.js — one-off cleanup.
 *
 * Trashes the fleet inbound-mail delivery TEST emails that piled up in the
 * steve-office inbox while verifying the 44-domain dw-domain-fleet catch-all
 * forwarding. Two batches were sent, each tagged with a unique random token:
 *   FLEETMAILTEST-75986316   (first delivery test)
 *   RETEST-a3cdc29a          (re-test from a third-party account)
 * Both tokens are cryptographically unique, so the query has zero
 * false-positive risk against real mail.
 *
 * George's MCP exposes no delete tool, so this uses George's own OAuth creds
 * directly (gmail.modify scope) — same pattern as trash-redfin-zillow.js.
 * Trashing is reversible: messages sit in Trash for 30 days.
 *
 *   node trash-fleet-mailtests.js
 */
const fs = require('fs');
const path = require('path');
const { google } = require('googleapis');

const ENV_PATH = path.join(process.env.HOME || '', 'Projects/Designer-Wallcoverings/DW-MCP/.env');
const env = {};
fs.readFileSync(ENV_PATH, 'utf8').split('\n').forEach(l => {
  const m = l.match(/^([^#=]+)=(.+)/);
  if (m) env[m[1].trim()] = m[2].trim();
});

const QUERY = 'subject:(RETEST-a3cdc29a OR FLEETMAILTEST-75986316)';
// sanity bounds: 44 RETEST + 44 FLEETMAILTEST + 1 bounced "Re:" = ~89.
const MIN_EXPECTED = 60;
const MAX_EXPECTED = 120;

(async () => {
  const oc = new google.auth.OAuth2(
    env.GMAIL_CLIENT_ID, env.GMAIL_CLIENT_SECRET, 'http://localhost:9850/oauth2callback');
  oc.setCredentials({ refresh_token: env.GMAIL_REFRESH_TOKEN });
  const gm = google.gmail({ version: 'v1', auth: oc });

  console.log('=== steve@designerwallcoverings.com ===');
  console.log('query:', QUERY);

  // 1. Collect matching message IDs
  const ids = [];
  let pageToken = null;
  do {
    const r = await gm.users.messages.list({
      userId: 'me', q: QUERY, maxResults: 500, pageToken: pageToken || undefined });
    (r.data.messages || []).forEach(m => ids.push(m.id));
    pageToken = r.data.nextPageToken || null;
  } while (pageToken);
  console.log(`  collected ${ids.length} message IDs`);

  // 2. Safety gate — abort if the count is wildly off what we expect
  if (ids.length === 0) { console.log('  nothing to trash — exiting.'); return; }
  if (ids.length < MIN_EXPECTED || ids.length > MAX_EXPECTED) {
    console.error(`  ABORT: ${ids.length} is outside the expected ${MIN_EXPECTED}-${MAX_EXPECTED} range.`);
    console.error('  Re-check the query before trashing. No messages were modified.');
    process.exit(1);
  }

  // 3. Trash — add TRASH, remove INBOX
  const BATCH = 1000;
  let trashed = 0;
  for (let i = 0; i < ids.length; i += BATCH) {
    const chunk = ids.slice(i, i + BATCH);
    await gm.users.messages.batchModify({
      userId: 'me',
      requestBody: { ids: chunk, addLabelIds: ['TRASH'], removeLabelIds: ['INBOX'] }
    });
    trashed += chunk.length;
    console.log(`  trashed ${trashed}/${ids.length}`);
  }
  console.log(`\n=== DONE: ${trashed} fleet test emails moved to Trash ===`);
})().catch(e => { console.error('FAILED:', e.message); process.exit(1); });