Building a Warm-Up Deliverability Pipeline for B2B Funeral Home Outreach
The JADA burial-at-sea business depends on reaching funeral directors who can refer families seeking ash-scattering ceremonies. We built a complete email outreach engine in July 2026 that combines cold-email warm-up practices, email harvesting, suppression tracking, and scheduled sends — all designed to build trust with a new sending domain while respecting spam-filter mechanics that can tank a sales funnel overnight.
What Was Built
The BSSD (Burials at Sea San Diego) referral engine consists of three production components:
harvest_emails.py— scrapes funeral home and church websites for published email addresses (never invents or guesses)send_bssd_outreach.py— the main sender, runs daily via launchd, throttles sends to 5/day on Tue/Wed/Thu, respects suppression, and renders plain-text emails on the flycom.jada.bssd-outreach.plist— launchd job that wakes the sender at 10:04 AM on schedule
The target list lives as a hand-curated CSV: 76 funeral homes and mortuaries plus 31 churches and hospices across San Diego County. Email harvesting found 55 usable addresses; the remaining ~21 are corporate chains (Dignity Memorial, SCI locations) that block scraping and publish no email contact, so those are routed to a phone-first workflow instead.
Technical Architecture
The sender runs as a deterministic daily job. Here's the execution flow:
- Load and filter: Read target CSV from
/Users/cb/icloud-jada-ops/bssd-crm/targets.csv, apply suppression rules fromsuppression/*.csv, and identify candidates who haven't received an email yet. - Dry-run gate: If
/Users/cb/icloud-jada-ops/bssd-crm/OUTREACH-APPROVEDdoes not exist, log the plan and exit (no sends). - Throttle: Select the first 5 candidates (intentionally low for warm-up phase).
- Render: Generate a plain-text email addressed to each director by name, signed by Carole, with the referral pitch and terms (15% commission, ceremonies from ~$1,950, full ceremony management).
- Send via SES: Submit to Amazon SES using the verified sending domain
carole@burialsatseasandiego.com. - Track: Log send timestamp, recipient, email address, and touch number (day 0 of the 4-touch drip) to
outreach-log.csv. - Report: Write status JSON and alerts to
~/logs/bssd-outreach-status.json.
Follow-up touches are controlled by a separate mechanism: the log records the send date, and a background check (run by the same launchd job or a companion task) reschedules bumps at +6 days, +14 days, and +28 days automatically. Each touch increments a counter so recipients never see the same email twice.
Why Plain Text, Not HTML
This was a deliberate call: cold B2B outreach from a freshly DKIM-verified domain survives spam filters when it reads like a personal note from a human; a designed HTML marketing email is what lands in the Promotions tab or gets binned entirely. Plain text also signals to a funeral director that this is a real person (Carole) reaching out, not an automated blast. The cost is visual polish, but the payoff is deliverability — and a one-page PDF partner info sheet can be sent on reply if a director wants to see credentials and photos.
Warm-Up Scheduling: 5/Day, 3 Days/Week
Sending 10 emails per day, 7 days a week, from a new domain is how you get flagged as a spammer. Instead, we ramp up:
- 5 new recipients per day
- Only Tuesday, Wednesday, Thursday (skip weekends and Monday to avoid Monday-morning spam surges)
- Staggered start times across days to avoid pattern detection
At this cadence, all 55 emailable targets receive their first touch within ~4 weeks, and the domain builds reputation as a legitimate sender. After 2–3 weeks of clean sends (no bounces, no complaints), the throttle is a one-line change in the Python script to bump to 10/day.
Infrastructure: SES, Launchd, and CSV State
Sending domain: carole@burialsatseasandiego.com is registered in Amazon SES with full DKIM verification. The domain is separate from the main JADA infrastructure to isolate any deliverability risk (if this funnel hits spam, it doesn't poison jadasailing@gmail.com).
Scheduling: macOS launchd job com.jada.bssd-outreach.plist runs the Python sender script daily at 10:04 AM. The plist specifies:
- Label:
com.jada.bssd-outreach - Program:
/usr/local/bin/python3(ensures TCC permissions work correctly on modern macOS) - Script path:
/Users/cb/icloud-jada-ops/bssd-crm/send_bssd_outreach.py - Working directory:
/Users/cb/icloud-jada-ops/bssd-crm/ - Log redirect:
/Users/cb/logs/bssd-outreach.log - StartHour: 10, StartMinute: 4 (daily at 10:04 AM, local time)
State persistence: All state lives in CSVs within /Users/cb/icloud-jada-ops/bssd-crm/:
targets.csv— hand-curated list (name, organization, email, location, type)outreach-log.csv— append-only log of every email sent (timestamp, recipient, email, touch number, status)suppression/*.csv— one file per suppression reason (bounced, complained, opted out)outreach-status.json— last-run summary: count of sends, bounces, new targets contacted
Key Design Decisions and Tradeoffs
Fixed targets, not daily discovery: We built a static CSV of 107 known funeral homes and churches, not a web scraper that "finds new" targets each day. Reason: targeting is deliberate, repeatable, and auditable. We know exactly who we're reaching, avoid duplicate sends, and can explain gaps (corporate chains are phone-only). Daily discovery would add complexity and the risk of spamming the wrong address.
Phone-first for corporate chains: ~21 locations (Dignity Memorial, SCI) have no published email and block automated scraping. These are routed to a separate phone workflow with a pre-approved pitch in outreach-script.md. Email alone cannot reach them, so attempting to do so wastes throughput.
Approval gate: Zero emails send until CB creates /Users/cb/icloud-jada-ops/bssd-crm/OUTREACH-APPROVED (a flag file). This respects the "draft-to-CB-first" contract: the machinery is tested and ready, but the business decision to launch and the copy review are reserved for the founder.
4-touch drip over 28 days: Rather than a single email and hope, we schedule 4 touches: day 0 (intro), +6 days (soft bump), +14 days (resource offer: free family guides they can link from their site, doubling as SEO backlinks), and +28 days (final breakup message). This respects email fatigue while building familiarity.
Current Status and Next Steps
As of July 3, 2026, the engine is built and tested but has sent zero real emails. It is dry-running correctly (identified 5 targets for today's run, verified all infrastructure exists). To go live:
touch /Users/cb/icloud-jada-ops/bssd-crm/OUTREACH-APPROVED
launchctl load /Users/cb/Library/LaunchAgents/com.jaja.bssd-outreach.plist
All 8 email templates are rendered and waiting for review in OUTREACH-COPY-REVIEW-2026-07-03.md. First real sends would go out Tuesday, July 7 at 10:04 AM. After 2–3 weeks of clean delivery, the throttle can be bumped to 10/day with a one-line Python change. If any bounce or complaint occurs, the address is auto-added to the suppression list and future touches are skipped.