#!/usr/bin/env python3 # MIT licence. Copyright (c) 2026 Tuper. Written by an AI agent (Claude); use at your own risk. # Permission is hereby granted, free of charge, to any person obtaining a copy of this software, to deal in it without restriction, subject to the usual MIT conditions: https://opensource.org/license/mit """Open-company newsletter, double opt-in (stdlib). Mail goes through tools/send-reply (SMTP2GO, support@example.com). newsletter.py status counts newsletter.py --send-confirmations [--only EMAIL] [--dry-run] ONE confirmation mail per signup (tag open-company, spam=0) newsletter.py --send-issue YYYY-MM-DD [--only EMAIL] [--dry-run] text from bets/open-company/weekly/.md, CONFIRMED and not suppressed only newsletter.py --suppress EMAIL unsubscribe ('reply stop') Tables in the waitlist DB: newsletter_confirmed (written by GET waitlist.tuper.app/confirm/), newsletter_confirm_sent, newsletter_suppressed, newsletter_issues_sent. Test domains (example.*, .test ...) are skipped. """ import argparse, base64, hashlib, hmac, os, re, sqlite3, subprocess HERE = os.path.dirname(os.path.abspath(__file__)) DB = os.path.expanduser("~/path/to/waitlist.db") KEY = os.path.expanduser("~/.config//accounts/newsletter-hmac") TAG = "open-company" RESERVED = re.compile(r"@([a-z0-9-]+\.)*(example\.(com|org|net)|test|invalid|example|localhost)$") NOW = "strftime('%Y-%m-%dT%H:%M:%SZ','now')" def token(email): e = base64.urlsafe_b64encode(email.encode()).decode().rstrip("=") return e + "." + hmac.new(open(KEY, "rb").read().strip(), e.encode(), hashlib.sha256).hexdigest()[:32] def db(): con = sqlite3.connect(DB, timeout=10) for t, c in (("newsletter_confirmed", "email TEXT PRIMARY KEY, ts TEXT"), ("newsletter_suppressed", "email TEXT PRIMARY KEY, ts TEXT"), ("newsletter_confirm_sent", "email TEXT PRIMARY KEY, ts TEXT"), ("newsletter_issues_sent", "issue TEXT, email TEXT, ts TEXT, PRIMARY KEY(issue,email)")): con.execute("CREATE TABLE IF NOT EXISTS %s(%s)" % (t, c)) return con def send(to, subject, text, dry): if dry: print("DRY", to, "|", subject); return True r = subprocess.run([os.path.join(HERE, "send-reply"), "--to", to, "--subject", subject, "--text", text, "--from-name", "Tuper weekly"], capture_output=True, text=True) print(to, "->", (r.stdout.strip() or r.stderr.strip())) return r.returncode == 0 def signups(con, only): rows = [r[0] for r in con.execute("SELECT DISTINCT email FROM signups WHERE tag=? AND spam=0 ORDER BY id", (TAG,))] return [e for e in rows if not RESERVED.search(e) and (not only or e == only)] def main(): p = argparse.ArgumentParser() p.add_argument("--send-confirmations", action="store_true") p.add_argument("--send-issue"); p.add_argument("--suppress"); p.add_argument("--only"); p.add_argument("--dry-run", action="store_true") a = p.parse_args(); con = db() if a.suppress: con.execute("INSERT OR REPLACE INTO newsletter_suppressed VALUES(?,%s)" % NOW, (a.suppress.lower(),)) con.execute("DELETE FROM newsletter_confirmed WHERE email=?", (a.suppress.lower(),)); con.commit(); print("suppressed", a.suppress); return sup = {x for (x,) in con.execute("SELECT email FROM newsletter_suppressed")} if a.send_confirmations: for e in signups(con, a.only): if e in sup or con.execute("SELECT 1 FROM newsletter_confirm_sent WHERE email=?", (e,)).fetchone(): continue txt = ("You asked for the Tuper weekly issue on tuper.app/open (an AI-run company with every number public).\n\n" "Confirm your subscription with one click:\nhttps://waitlist.tuper.app/confirm/%s\n\n" "This is the only mail we send unless you confirm. If it was not you, ignore this mail and nothing more is sent.\n\n" "Tuper is a business run by an AI agent (Claude); this mail was sent by that operation.\n" "Unsubscribe: reply stop to this mail and you get nothing more.\n" % token(e)) if send(e, "Confirm your Tuper weekly subscription", txt, a.dry_run) and not a.dry_run: con.execute("INSERT OR IGNORE INTO newsletter_confirm_sent VALUES(?,%s)" % NOW, (e,)); con.commit() return if a.send_issue: body = open(os.path.join(HERE, "..", "bets", "open-company", "weekly", a.send_issue + ".md")).read().strip() subj = body.splitlines()[0].lstrip("# ").strip() for (e,) in con.execute("SELECT email FROM newsletter_confirmed ORDER BY ts").fetchall(): if e in sup or RESERVED.search(e) or (a.only and e != a.only): continue if con.execute("SELECT 1 FROM newsletter_issues_sent WHERE issue=? AND email=?", (a.send_issue, e)).fetchone(): continue txt = body + "\n\nOnline: https://tuper.app/open/weekly/%s/\nYou confirmed this subscription. Reply stop to unsubscribe.\n" % a.send_issue if send(e, subj, txt, a.dry_run) and not a.dry_run: con.execute("INSERT OR IGNORE INTO newsletter_issues_sent VALUES(?,?,%s)" % NOW, (a.send_issue, e)); con.commit() return q = lambda t: con.execute("select count(*) from " + t).fetchone()[0] print("signups(open-company, real):", len(signups(con, None)), "| confirm mails sent:", q("newsletter_confirm_sent"), "| confirmed:", q("newsletter_confirmed"), "| suppressed:", q("newsletter_suppressed")) main()