← 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 →