```html

Implementing Multi-Platform Email Campaign Architecture with Dynamic Suppression List Management

This session focused on consolidating email marketing infrastructure across multiple platforms while implementing intelligent contact suppression and cadence optimization. The work involved refactoring the jada_blast.py tool, deploying cleaned campaign assets, and establishing a sustainable outreach framework that respects recipient engagement patterns.

What Was Done

The primary objectives were:

  • Clean and redeploy email campaign assets (removing personal identifiers from marketing materials)
  • Implement SES suppression list integration into the blast tool
  • Create platform-specific task tracking for multi-channel outreach
  • Establish cadence optimization logic for widening engagement gaps
  • Verify infrastructure dependencies (image CDN delivery, email templates, contact databases)

Technical Details: Email Infrastructure Refactoring

The SDCC (San Diego Convention Center) email campaign template at /tmp/sdcc-hotel-outreach-2026.html was the primary asset requiring updates. The campaign featured embedded promotional imagery that needed verification before deployment.

Image Delivery Verification: Boat promotional images referenced in the template were hosted on S3 and served through CloudFront distribution. We verified accessibility by performing HTTP HEAD requests against the CDN endpoints, confirming 200 responses from both primary and fallback image URLs. This pre-deployment validation step prevents bounce-backs due to broken asset references—a critical failure mode in email campaigns.

Template Deployment: The cleaned HTML template was uploaded to the S3 bucket designated for SDCC assets and CloudFront cache was invalidated using the distribution ID. Cache invalidation was necessary because previous versions existed in edge locations; without explicit invalidation, some recipients would receive stale template versions.

Platform-Specific Template Management: We identified multiple Google Apps Script files managing outreach across different business domains:

  • FuneralOutreach.gs - Funeral services vertical
  • CrewDispatch.gs - Crew scheduling and dispatch
  • CrewScheduler.gs - Event crew coordination
  • WorshipRsvp.gs and ViatorApiFollowUp.gs - Event-specific automations

Each file manages separate contact lists and cadence logic. Centralizing suppression list checks required identifying common SES integration points across these scripts.

Infrastructure: SES Suppression List Integration

Amazon SES maintains three suppression list types: bounce, complaint, and unsubscribe. The jada_blast.py tool needed integration with the account suppression list to prevent re-contacting recipients who have complained or generated hard bounces.

Suppression List Export Process:


# Query SES suppression list (via AWS CLI or SDK)
# Export includes:
# - EmailAddress: recipient address
# - ListType: BOUNCE | COMPLAINT | UNSUBSCRIBE
# - Timestamp: when suppression was added
# - BounceType: (for BOUNCE list) Permanent | Transient

# De-duplicate across contact sources
# Check master contact CSV against all three suppression lists
# Flag any matches for exclusion before sending

The suppression check happens during the contact filtering phase, before templating and transmission. This prevents SES bounce penalties and maintains account health metrics.

Blast Tool Refactoring: jada_blast.py

The blast script at /Users/cb/Documents/repos/tools/jada_blast.py underwent four iterations during this session to integrate:

1. Suppression List Filtering: Contact records are validated against SES suppression lists using the SDK. Matching records are logged but excluded from transmission.

2. Cadence Optimization (Widening-Gap Pattern): Recipients showing declining engagement (lower open rates over time) are moved to extended cadence intervals. The logic identifies these patterns by querying SES send statistics and CloudWatch logs for delivery/bounce/complaint metrics.

Example cadence adjustment:


# Standard cadence: 7-day intervals
# If open_rate_week_2 < open_rate_week_1 * 0.8:
#   Move to 14-day intervals
# If open_rate_week_4 < open_rate_week_2 * 0.75:
#   Move to 30-day intervals
# If bounce_count > threshold:
#   Add to suppression list

3. Platform Credential Management: The tool references repos.env for SES credentials and region configuration. Platform-specific credentials (GetMyBoat, WeddingWire, Zillow APIs) are stored in the same encrypted environment file.

4. Contact Source Abstraction: Different platforms maintain contacts in different formats (Google Sheets via Apps Script, CSV exports, API queries). The tool abstracts these sources through a contact provider interface, enabling unified filtering and templating regardless of source.

Platform Task Creation and Tracking

A systematic task framework was established for non-live platforms:

  • GetMyBoat - Boat rental and experience listings platform
  • WeddingWire - Wedding services marketplace
  • Additional platforms - Each requiring distinct API authentication, contact schema mapping, and outreach templates

Each platform received a dedicated dashboard task card with:

  • Authentication status and credential location
  • Contact extraction queries or API endpoints
  • Template requirements and personalization fields
  • Cadence recommendations based on platform type

Tasks are tracked in the dashboard at a known URL, with task IDs used as identifiers for status updates and blocking relationships.

Frontend Deployment: Removing Identifiers

Multiple demo and progress sites contained personal identifiers in public-facing HTML:

  • /Users/cb/Documents/repos/sites/dangerouscentaur/demos/3028fiftyfirststreet.92105.dangerouscentaur.com/index.html
  • /Users/cb/Documents/repos/sites/dangerouscentaur/demos/demo.dangerouscentaur.com/index.html
  • /Users/cb/Documents/repos/sites/progress.queenofsandiego.com/index.html

A search-and-replace operation identified all instances of personal identifiers across marketing materials. Updated files were re-deployed to S3 and CloudFront caches were invalidated to ensure recipients receive cleaned versions.

Deployment command pattern:


# Upload cleaned files to S3
aws s3 cp index.html s3://bucket-name/path/ --no-progress

# Invalidate CloudFront distribution
aws cloudfront create-invalidation \
  --distribution-id DISTRIBUTION_ID \
  --paths "/*"

Key Decisions and Rationale

Why SES Suppression Integration: Manually tracking bounces across multiple platforms introduces operational risk and compliance issues. SES maintains authoritative suppression state; integrating it into the blast tool makes suppression checks transactional and auditable.

Why Cadence Optimization: Fixed-interval sends ignore recipient engagement signals. Reducing frequency for declining recipients preserves sending reputation and