Implementing Autonomous Email Campaign Management with Suppression Lists and Multi-Platform Task Orchestration
This session focused on hardening our email marketing infrastructure by implementing SES suppression list management, creating a multi-platform task orchestration system, and refactoring the jada_blast.py tool to support cadence-based campaigns. The work involved coordinate updates across infrastructure, automation scripts, and dashboard systems to handle bounce management and prevent repeated outreach to unresponsive contacts.
Challenge: Managing Email Suppression at Scale
Our previous email campaigns were generating bounces that weren't being actively managed. Without suppression list enforcement, we risked:
- Damaging sender reputation with repeated sends to invalid addresses
- Wasting campaign budget on undeliverable contacts
- Violating SES compliance thresholds for bounce rates
The solution required three layers: export and clean suppression data, update the blast tool to respect it, and create visibility into which platforms needed outreach.
Technical Implementation: Suppression List Export and Cleaning
We exported the AWS SES suppression list using the suppression list query commands. The export revealed bounced addresses that needed to be excluded from all future campaigns. The workflow was:
- Query SES suppression list via AWS CLI
- Cross-reference against contact files in
/Users/cb/Documents/repos/tools/ - Generate cleaned contact lists excluding bounced addresses
- Update
jada_blast.pyto pre-filter against suppression data
The cleaned contact data was stored back to the tools directory with naming conventions that identify source (e.g., platform names) and processing state.
Refactoring jada_blast.py for Cadence-Based Campaigns
The blast tool needed enhancement to support multi-touch campaign sequences. The original implementation was single-pass; we needed it to handle:
- Initial outreach: First contact to prospects
- Follow-up sequences: Timed follow-ups (Follow-up 1, Follow-up 2)
- Re-engagement: Final "breakup" message before de-prioritizing contact
We implemented cadence logic by adding template matching to jada_blast.py that identifies campaign type from template filenames and applies appropriate filters and SES configuration parameters.
LaunchAgent Scheduling for Automated Cadence
To automate the cadence workflow, we created four macOS LaunchAgent plist files in ~/Library/LaunchAgents/:
com.jada.hotel-outreach-initial.plist— Triggers initial campaigncom.jada.hotel-outreach-followup1.plist— Triggers first follow-up at +7 dayscom.jada.hotel-outreach-followup2.plist— Triggers second follow-up at +14 dayscom.jada.hotel-outreach-breakup.plist— Triggers final re-engagement at +30 days
Each LaunchAgent references the blast tool and passes the appropriate template type, allowing the system to automatically progress contacts through the campaign lifecycle without manual intervention.
Multi-Platform Task Orchestration
To track and manage outreach across heterogeneous platforms (GetMyBoat, WeddingWire, Yelp, etc.), we created a dashboard-backed task system. Each platform requiring outreach received a dedicated task card with:
- Platform name and current integration status
- Credential location notes (without exposing actual credentials)
- Required outreach type (cold outreach, follow-up, partnership inquiry)
- Assigned engineer notes and blockers
The task system uses the update_dashboard.py utility with the add-note command to update card state and track progress. Task creation and updates are logged to the dashboard state file for audit trails.
S3 and CloudFront Integration for Email Assets
Email campaign templates with embedded imagery are stored in S3 buckets with CloudFront distribution in front. When the SDCC hotel outreach HTML template was updated, we:
- Uploaded the cleaned template HTML to the appropriate S3 bucket
- Verified image URLs within the template (boat photos from JADA inventory)
- Invalidated the CloudFront distribution cache (distribution ID tracked in deployment config)
- Confirmed image accessibility before campaign send (HTTP 200 response verification)
This approach allows HTML email templates to be versioned in S3 while CloudFront provides geographic distribution and caching for image assets.
Critical Decision: Brand Voice and Anonymization
During email template review, a prime directive was established: never use personal names in outward-facing marketing materials. This required a systematic search and cleanup across all deployed assets:
- Search all HTML templates in
/Users/cb/Documents/repos/sites/for personal name references - Update demo site files:
dangerouscentaur/demos/HTML files - Update progress dashboard:
progress.queenofsandiego.com/index.html - Redeploy updated files to S3 and invalidate CloudFront caches
The replacement strategy uses brand identity language ("The JADA Team," "Queen of San Diego") instead of individual identities, improving professionalism and reducing personal liability exposure.
Google Apps Script Deployment Challenges
Several systems use Google Apps Script (GAS) for Gmail integration and scheduling:
FuneralOutreach.gs— Handles outreach for funeral/memorial servicesCrewDispatch.gs— Manages crew scheduling and assignmentWorshipRsvp.gs— Tracks event RSVPsCrewScheduler.gs— Calendar-based scheduling automation
These scripts were audited for personal name references and updated accordingly. Deployment uses clasp (Google Apps Script CLI) with project configs stored in .clasp.json files. The challenge was locating and updating all project references without exposing credentials in the configuration.
Key Architecture Patterns
- Suppression List Pattern: Centralized SES suppression data queried pre-send to prevent bounce loops
- Cadence Orchestration: LaunchAgent-driven scheduled sends with progressive contact lifecycle
- Task-Driven Workflow: Dashboard-backed task system for distributed team coordination
- Static Asset Distribution: S3 + CloudFront for email template and image delivery
- Infrastructure as Configuration: LaunchAgent plists and deployment configs version-controlled in repos
What's Next
The multi-platform outreach system is now orchestrated, but requires completion of individual platform integrations. Each task card for GetMyBoat, WeddingWire, and other platforms needs specific credential setup and API testing. The cadence system is ready for the next hotel outreach campaign, with suppression list filtering active and automated