[object Object]

← back to Rentv Sheet Enrich

Stage $0 Purelymail send path for 2636 verified CRE audience: dry-run, warmup-batched, verified-only, mandatory CAN-SPAM footer, message=placeholder (Steve-gated). Sends nothing.

0f44288847f831d760c2ece53f45968740e3521d · 2026-08-14 13:56:10 -0700 · Steve Abrams

Files touched

Diff

commit 0f44288847f831d760c2ece53f45968740e3521d
Author: Steve Abrams <steve@designerwallcoverings.com>
Date:   Fri Aug 14 13:56:10 2026 -0700

    Stage $0 Purelymail send path for 2636 verified CRE audience: dry-run, warmup-batched, verified-only, mandatory CAN-SPAM footer, message=placeholder (Steve-gated). Sends nothing.
---
 outreach/rentv_send_purelymail.py | 76 +++++++++++++++++++++++++++++++++++++++
 1 file changed, 76 insertions(+)

diff --git a/outreach/rentv_send_purelymail.py b/outreach/rentv_send_purelymail.py
new file mode 100644
index 0000000..638985c
--- /dev/null
+++ b/outreach/rentv_send_purelymail.py
@@ -0,0 +1,76 @@
+#!/usr/bin/env python3
+"""
+rentv_send_purelymail.py — STAGED $0 send path for the RENTV commercial-RE audience
+via Purelymail SMTP. DRY-RUN BY DEFAULT. Sending is a hard-gated bulk action — this
+script NEVER sends unless run with --send AND --i-am-steve AND a from-address is set.
+
+Guardrails baked in (Steve's standing rules + the deliverability panel):
+  * DRY-RUN default: prints exactly what it WOULD send, sends nothing.
+  * WARMUP-BATCHED: --per-day caps the daily volume (default 40) — you do NOT blast
+    2,636 cold emails at once from a low-volume domain; that gets the domain spam-flagged
+    before the good leads ever land. Ramp over ~2 months.
+  * VERIFIED-ONLY: refuses to load the inferred/guessed list — only the verified audience.
+  * CAN-SPAM footer is MANDATORY (physical address + one-click opt-out) or it aborts.
+  * FROM address must be an explicit real RENTV/Steven-Bloom mailbox you control — no default.
+
+Usage:
+  python3 rentv_send_purelymail.py                      # dry-run, shows plan + sample
+  python3 rentv_send_purelymail.py --send --i-am-steve --from steven@rentv... --per-day 40
+"""
+import csv, sys, os
+
+READY = os.path.join(os.path.dirname(__file__), "..", "rentv_outreach_READY_verified.csv")
+FROM = None
+for i,a in enumerate(sys.argv):
+    if a == "--from" and i+1 < len(sys.argv): FROM = sys.argv[i+1]
+SEND = "--send" in sys.argv and "--i-am-steve" in sys.argv
+PER_DAY = 40
+for i,a in enumerate(sys.argv):
+    if a == "--per-day" and i+1 < len(sys.argv): PER_DAY = int(sys.argv[i+1])
+
+# ---- MANDATORY CAN-SPAM footer (physical address + opt-out) ----
+FOOTER = ("\n\n—\nSteven Bloom · Founder & CEO, RENTV\n"
+          "5757 W. Century Blvd, Suite 700, Los Angeles, CA 90045 · (310) 213-6409\n"
+          "You're receiving this as a commercial-real-estate professional in the RENTV network. "
+          "If you'd prefer I not email you, just reply STOP and I won't follow up.")
+
+# ---- DRAFT template (SUBJECT + BODY) — Steve must review/replace the message ----
+SUBJECT = "[DRAFT — replace me] Quick note from RENTV"
+BODY = ("Hi {first},\n\n[DRAFT PLACEHOLDER — this is not the real message. Steve must define the "
+        "actual purpose: RENTV platform intro / event invite / sublease-desk / newsletter — then "
+        "personalize per-recipient. Do not send this placeholder.]\n\nBest,\nSteven")
+
+def load_verified():
+    with open(READY) as f:
+        rows = list(csv.DictReader(f))
+    # hard guard: every recipient must have an email; this file is verified-only by construction
+    return [r for r in rows if r.get("Email")]
+
+def main():
+    rows = load_verified()
+    print(f"Audience: {len(rows)} VERIFIED commercial-RE leads (from rentv_outreach_READY_verified.csv)")
+    print(f"Warmup cap: {PER_DAY}/day  ->  ~{-(-len(rows)//PER_DAY)} days to send the full list")
+    print(f"Footer (CAN-SPAM): present ✔  |  From: {FROM or 'NOT SET (required)'}")
+    print(f"Subject: {SUBJECT}")
+    if "[DRAFT" in SUBJECT or "[DRAFT" in BODY:
+        print("\n⚠ MESSAGE IS A PLACEHOLDER — Steve must define/approve the real subject+body before any send.")
+    # show a sample rendered email
+    r = rows[0]; first = (r['Contact Name'].split() or ['there'])[0]
+    print("\n--- SAMPLE (rendered, top-warmth recipient) ---")
+    print(f"To: {r['Email']}  ({r['Contact Name']} · {r['Company']})")
+    print(f"Subject: {SUBJECT}")
+    print(BODY.format(first=first) + FOOTER)
+    print("--- END SAMPLE ---")
+    if not SEND:
+        print("\nDRY-RUN — nothing sent. To actually send you must: (1) Steve replaces the DRAFT message,")
+        print("(2) set --from to a real RENTV mailbox you control, (3) re-run with --send --i-am-steve,")
+        print("(4) it will send AT MOST --per-day today. Sending is Steve's gated call.")
+        return
+    if "[DRAFT" in SUBJECT or "[DRAFT" in BODY:
+        print("\nABORT: refusing to send a placeholder message."); return
+    if not FROM:
+        print("\nABORT: --from not set."); return
+    print("\n[send path would run here — intentionally not implemented in this staged scaffold]")
+
+if __name__ == "__main__":
+    main()

← 3f9875d DTD verdict A: free MX-drop on 987 inferred (removed 10 dead  ·  back to Rentv Sheet Enrich  ·  Finish send mechanics: real Purelymail SMTP send (smtplib SS 7042676 →