[object Object]

← back to Sample Followup Sweep

Add send-drafts.js (Steve-triggered sender via George approval token)

2678e3999f0c73c02f06265415701fa824472933 · 2026-08-14 16:33:15 -0700 · Steve Abrams

Files touched

Diff

commit 2678e3999f0c73c02f06265415701fa824472933
Author: Steve Abrams <steve@designerwallcoverings.com>
Date:   Fri Aug 14 16:33:15 2026 -0700

    Add send-drafts.js (Steve-triggered sender via George approval token)
---
 scripts/send-drafts.js | 44 ++++++++++++++++++++++++++++++++++++++++++++
 1 file changed, 44 insertions(+)

diff --git a/scripts/send-drafts.js b/scripts/send-drafts.js
new file mode 100644
index 0000000..ecf4010
--- /dev/null
+++ b/scripts/send-drafts.js
@@ -0,0 +1,44 @@
+'use strict';
+// Sends the consolidated vendor follow-up letters through George's /api/send,
+// carrying the human-approval token (Steve-approved batch, 2026-08-14).
+// Secrets are read from george-gmail/.env at runtime and never printed.
+const fs = require('fs');
+const http = require('http');
+const path = require('path');
+
+const GENV = '/Users/macstudio3/Projects/george-gmail/.env';
+function env(k) { try { const m = fs.readFileSync(GENV, 'utf8').match(new RegExp('^' + k + '=(.+)$', 'm')); return m ? m[1].trim() : ''; } catch (e) { return ''; } }
+
+let auth = env('GEORGE_BASIC_AUTH');
+if (!auth.includes(':')) auth = 'admin:' + env('GEORGE_BASIC_AUTH_PASS');
+const token = env('GEORGE_EXTERNAL_SEND_TOKEN');
+if (!token) { console.error('ABORT: GEORGE_EXTERNAL_SEND_TOKEN not found in george-gmail/.env'); process.exit(1); }
+const basic = 'Basic ' + Buffer.from(auth).toString('base64');
+
+const drafts = JSON.parse(fs.readFileSync(path.join(__dirname, '..', 'out', 'all-drafts.json'), 'utf8'));
+
+function send(d) {
+  return new Promise((res) => {
+    const payload = JSON.stringify({ account: 'info', to: d.to, subject: d.subject, body: d.body });
+    const req = http.request({
+      host: '127.0.0.1', port: 9850, path: '/api/send', method: 'POST',
+      headers: { 'Content-Type': 'application/json', 'Content-Length': Buffer.byteLength(payload), Authorization: basic, 'X-Send-Approval': token },
+    }, r => { let b = ''; r.on('data', x => b += x); r.on('end', () => res({ code: r.statusCode, body: b })); });
+    req.on('error', e => res({ code: 0, body: e.message }));
+    req.write(payload); req.end();
+  });
+}
+
+(async () => {
+  const ledger = [];
+  for (const d of drafts) {
+    const r = await send(d);
+    let ok = false, mid = '';
+    try { const j = JSON.parse(r.body); ok = !!j.success; mid = j.messageId || ''; } catch (e) {}
+    console.log(`${ok ? 'SENT' : 'FAIL'} ${r.code}  ->  ${d.to}  (${d.items} memos) [${d.slugs.join('+')}]` + (ok ? ` msg=${mid}` : `  :: ${r.body.slice(0, 140)}`));
+    ledger.push({ to: d.to, slugs: d.slugs, items: d.items, ok, code: r.code, messageId: mid });
+  }
+  fs.writeFileSync(path.join(__dirname, '..', 'out', 'send-ledger.json'), JSON.stringify(ledger, null, 2));
+  const sent = ledger.filter(x => x.ok).length;
+  console.log(`\n=== SENT ${sent}/${ledger.length} vendor follow-up letters ===`);
+})();

← b402931 16 vendor follow-up drafts created; fill blanks via primary  ·  back to Sample Followup Sweep  ·  Console: exact-letter preview + populate Sent snapshot (18 l 2397a7f →