← back to George Gmail
Fleet auto-responder: deliveredto query fix + --only-ids scoped-test flag
7d77cad42a25e2787a594ab46e73d5170872c740 · 2026-05-19 10:08:50 -0700 · Steve Abrams
Tested live on barwallpaper.com + grassclothwallcovering.com (2-domain test):
- Gmail does not match plus-tags via to:; switched candidate query to
deliveredto: and rely on Delivered-To header parsing for domain recovery.
- Added --only-ids flag so a scoped test does not touch the inbox backlog
of unrelated probe mail.
- Verified: reply sent from info@designerwallcoverings.com landed in the
recipient INBOX (not Spam), correct per-domain sign-off, no loop, label
+ 7-day ledger dedup both idempotent on re-run.
Ledger (data/fleet-autoresponder-ledger.json) gitignored — runtime state.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Files touched
M .gitignoreM fleet-autoresponder.js
Diff
commit 7d77cad42a25e2787a594ab46e73d5170872c740
Author: Steve Abrams <steve@designerwallcoverings.com>
Date: Tue May 19 10:08:50 2026 -0700
Fleet auto-responder: deliveredto query fix + --only-ids scoped-test flag
Tested live on barwallpaper.com + grassclothwallcovering.com (2-domain test):
- Gmail does not match plus-tags via to:; switched candidate query to
deliveredto: and rely on Delivered-To header parsing for domain recovery.
- Added --only-ids flag so a scoped test does not touch the inbox backlog
of unrelated probe mail.
- Verified: reply sent from info@designerwallcoverings.com landed in the
recipient INBOX (not Spam), correct per-domain sign-off, no loop, label
+ 7-day ledger dedup both idempotent on re-run.
Ledger (data/fleet-autoresponder-ledger.json) gitignored — runtime state.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
---
.gitignore | 2 ++
fleet-autoresponder.js | 34 +++++++++++++++++++++++++++-------
2 files changed, 29 insertions(+), 7 deletions(-)
diff --git a/.gitignore b/.gitignore
index 7e6a9c3..46948d6 100644
--- a/.gitignore
+++ b/.gitignore
@@ -10,3 +10,5 @@ dist/
build/
.next/
*.bak
+# fleet-autoresponder runtime ledger (per-sender reply timestamps — not source)
+data/fleet-autoresponder-ledger.json
diff --git a/fleet-autoresponder.js b/fleet-autoresponder.js
index 2768a05..b060a9a 100644
--- a/fleet-autoresponder.js
+++ b/fleet-autoresponder.js
@@ -20,8 +20,10 @@
* is never double-replied. Idempotent on re-run.
*
* USAGE
- * node fleet-autoresponder.js # process inbox once, send replies
- * node fleet-autoresponder.js --dry-run # detect + log, send nothing
+ * node fleet-autoresponder.js # process inbox once, send replies
+ * node fleet-autoresponder.js --dry-run # detect + log, send nothing
+ * node fleet-autoresponder.js --only-ids a,b # restrict to specific Gmail msg ids
+ * # (used for the scoped 2-domain test)
*
* This script reuses George's OAuth credentials (DW-MCP/.env). It does NOT need
* the George server running and makes no prod deploy.
@@ -36,6 +38,13 @@ const { google } = require('googleapis');
// Config
// ─────────────────────────────────────────────────────────────────────────────
const DRY_RUN = process.argv.includes('--dry-run');
+// --only-ids a,b,c → restrict processing to these exact Gmail message ids.
+// Used for the scoped 2-domain test so a backlog of probe mail is not touched.
+const ONLY_IDS = (() => {
+ const i = process.argv.indexOf('--only-ids');
+ if (i === -1 || !process.argv[i + 1]) return null;
+ return new Set(process.argv[i + 1].split(',').map(s => s.trim()).filter(Boolean));
+})();
const PROCESSED_LABEL = 'fleet-autoreplied';
const LEDGER_PATH = path.join(__dirname, 'data', 'fleet-autoresponder-ledger.json');
const DEDUP_WINDOW_MS = 7 * 24 * 60 * 60 * 1000; // 7 days
@@ -44,6 +53,9 @@ const SIGNATURE_NAME = 'Steve';
const SENDER_FROM = 'Designer Wallcoverings <info@designerwallcoverings.com>';
const SEND_ACCOUNT = 'info'; // George account that physically sends
const READ_ACCOUNT = 'steve-office'; // George account whose inbox receives the forwards
+// How far back to scan for inquiries. Gmail's newer_than granularity is days;
+// override with FLEET_SCAN_WINDOW (e.g. "2h", "1d", "14d") for tighter scoping.
+const SCAN_WINDOW = process.env.FLEET_SCAN_WINDOW || '14d';
// ─────────────────────────────────────────────────────────────────────────────
// Fleet domain list — loaded from dw-domain-fleet/sites/*.json
@@ -301,12 +313,20 @@ async function main() {
const ledger = loadLedger();
- // Candidate inquiries: unprocessed inbox mail addressed to a steve+ plus-tag.
+ // Candidate inquiries: unprocessed inbox mail delivered to a steve+ plus-tag.
+ // Gmail matches the plus-tag against the Delivered-To header via deliveredto:,
+ // NOT the visible To: header (which is the customer-facing info@<domain>).
// We deliberately scope to INBOX (excludes SPAM) and exclude already-labelled mail.
- const q = `in:inbox -label:${PROCESSED_LABEL} to:steve+ newer_than:14d`;
- const list = await officeGmail.users.messages.list({ userId: 'me', q, maxResults: 100 });
- const ids = (list.data.messages || []).map(m => m.id);
- log(`[fleet-autoresponder] ${ids.length} candidate message(s) matched query: ${q}`);
+ const q = `in:inbox -label:${PROCESSED_LABEL} deliveredto:steve+ newer_than:${SCAN_WINDOW}`;
+ let ids;
+ if (ONLY_IDS) {
+ ids = [...ONLY_IDS];
+ log(`[fleet-autoresponder] --only-ids set — processing exactly ${ids.length} message(s): ${ids.join(', ')}`);
+ } else {
+ const list = await officeGmail.users.messages.list({ userId: 'me', q, maxResults: 100 });
+ ids = (list.data.messages || []).map(m => m.id);
+ log(`[fleet-autoresponder] ${ids.length} candidate message(s) matched query: ${q}`);
+ }
const results = { replied: [], skipped: [] };
← d135118 Add fleet auto-responder for the 44 dw-domain-fleet domains
·
back to George Gmail
·
Fleet auto-responder: multipart/alternative HTML+plain reply 13d4e3b →