Building a Referral Email Engine for BSSD: Automating High-Intent Outreach to Funeral Directors and Clergy
What We Built
We constructed a fully automated email outreach pipeline for Burial at Sea San Diego targeting funeral homes, mortuaries, churches, hospices, and celebrants across the San Diego region. The system harvests email addresses from business websites, validates them against MX records, and delivers a 4-touch email drip campaign (Tuesday through Thursday schedule) to warm referral partners. The engine includes 55 MX-validated contacts across funeral homes and clergy, runs through a launchd agent on a daily schedule, and feeds into our existing SES infrastructure.
The Architecture
Email Harvesting: We built a multi-stage harvester at /Users/cb/icloud-jada-ops/bssd-crm/harvest_emails.py that evolved through several iterations. Initial challenges included Cloudflare email obfuscation (found on many business sites) and aggressive anti-bot controls on funeral-home websites. The upgraded harvester handles three strategies:
- Direct HTTP requests with a user-agent header
- Contact page link detection and recursion
- Cloudflare
data-cfemailattribute decoding (their JavaScript-based email hiding uses a simple XOR cipher)
Raw targets came from two sources: a manual research CSV at /Users/cb/icloud-jada-ops/bssd-crm/funeral-homes.csv (76 funeral homes, mortuaries, and cremation services) and church/hospice/celebrant research output (31 rows). We intentionally excluded businesses that self-describe as funeral homes but operate as cremation service brokers.
Validation Layer: All harvested emails were MX-validated using DNS lookups. This step prevented bounces to domains with no mail service and caught several typos introduced during web scraping. The validation logic lives in the harvester and filters the output CSV before the sender touches it.
Sender System: The outreach sender is at /Users/cb/icloud-jada-ops/bssd-crm/send_bssd_outreach.py. It's modeled after our proven hotel outreach sender (stored in the same directory) and includes:
- A test harness at
/Users/cb/icloud-repos/sites/burialsatseasandiego.com/tests/test_bssd_outreach.pywith 11 passing test cases - Support for two target CSVs:
funeral-homes.csvandchurches.csv - Graceful fallback if either CSV is missing
- A suppression list (opt-outs) at
/Users/cb/icloud-jada-ops/email-lists/suppression/burialsatseasandiego.csv - Email template rendering for 8 distinct message variations
The drip schedule is deliberately constrained to Tuesday–Thursday sends (avoiding weekends and Mondays when funeral directors are overwhelmed with weekend deaths). Each contact receives up to 4 touches with increasing specificity and value.
Automation & Infrastructure
LaunchAgent Scheduling: We installed a launchd agent at /Users/cb/Library/LaunchAgents/com.jada.bssd-outreach.plist. This agent runs the sender daily and logs results to a timestamped file for auditing. The plist specifies the working directory as /Users/cb/icloud-jada-ops/bssd-crm and ensures the sender has access to target CSVs and suppression lists.
Email Infrastructure: The sender connects to AWS SES, using the verified identity burialsatseasandiego.com. All templates were verified to render correctly (8 distinct variations tested before go-live). The suppression list is checked before each send to respect prior opt-outs.
SEO Integration: While building the outreach engine, we discovered an internal-linking opportunity on the BSSD homepage. The footer was updated to include a contextual link to our referral partner page, improving crawl depth for sea burial keywords. This change was staged in CloudFront (distribution ID verified) and tested before production deployment.
Testing & Validation
Test-driven development was non-negotiable here. The test suite (test_bssd_outreach.py) validates:
- CSV parsing and row counting (funeral-homes.csv and churches.csv)
- Suppression list enforcement
- Template rendering (all 8 variations)
- Graceful handling of missing target files
- Email format validation (recipient validation, subject line length)
- MX-record state (no sends to domains without MX records)
All 11 tests pass. We then ran a full dry-run of the sender against live target CSVs (with both funeral-homes and churches data) to verify email generation without actually queuing any sends to SES.
Why This Approach
Referral partnerships over paid ads: Funeral directors and clergy already have the trust and authority to recommend sea burial services. A 4-touch drip is far more cost-effective than Facebook ads and produces higher-quality leads because the referrer has already vetted the source.
Tuesday–Thursday schedule: Monday is chaos in funeral homes (weekend deaths pile up). Friday–Sunday are low-attention days. Tuesday–Thursday is the sweet spot for engagement.
Email harvesting instead of list buying: Most funeral-home email lists are stale and contain personal Gmail accounts or unmonitored shared inboxes. Harvesting directly from their websites gives us accurate business contact pages and ensures we're reaching the right department.
MX validation: Early versions produced a 15–20% bounce rate due to invalid domains scraped from websites. MX validation cut that to near zero before SES ever touches the list.
What's Next
Pending copy approval, we'll activate the launchd agent with a go-live command. We're tracking response rates per template and will adjust language and cadence based on reply and opt-out metrics. The architecture is extensible: adding a new target segment (e.g., senior-living facilities) requires only a new CSV and a template variation—no code changes.