```html

Multi-Tenant Event Automation: Integrating Calendar Sync, Email Campaigns, and Boat Platform APIs

This session involved significant infrastructure refactoring across three distinct web properties, focusing on calendar synchronization, email campaign automation, and third-party platform integration. The work demonstrates patterns for managing multiple business domains with shared tooling and unified deployment pipelines.

What Was Done

  • Restored and activated Google Apps Script (GAS) CalendarSync.gs for calendar event synchronization across multiple properties
  • Built Python-based email campaign scheduler with templated blast capabilities
  • Implemented boat platform credential management and dispatch automation
  • Deployed Lambda-based calendar API endpoint for programmatic event creation
  • Created unified email deployment pipeline using AWS SES across multiple domains

Calendar Synchronization Architecture

The CalendarSync.gs file (located at /Users/cb/Documents/repos/sites/queenofsandiego.com/rady-shell-events/apps-script-replacement/CalendarSync.gs) serves as the core orchestration layer for calendar events across multiple properties. This GAS project is tied to project ID stored in .clasp.json files distributed across the repository structure.

Why this approach: Google Apps Script provides native integration with Google Calendar API without requiring OAuth token refresh logic. By using GAS as the deployment target, we avoid credential management complexity while maintaining audit trails through Google's native logging.

The script handles multiple action types invoked via HTTP POST:

  • add-calendar-event — Creates single or batch calendar events with configurable recurrence
  • list-calendar-events — Returns paginated event data for dashboard display
  • delete-calendar-event — Removes events by ID with optional cascade delete for recurring series

Events are added to specific Google Calendar IDs managed through environment configuration. The polling interval for calendar checks was standardized at 15-minute intervals to balance API quota usage against real-time accuracy requirements.

Email Campaign Automation Pipeline

Two new Python tools were created to handle templated email campaigns:

Campaign Scheduler (/Users/cb/Documents/repos/tools/campaign_scheduler.py):


# Reads scheduled campaigns from JSON configuration
# Invokes SES send-templated-email or send-bulk-templated-email
# Logs delivery status to CloudWatch for monitoring
# Supports conditional delivery based on recipient segments

Configuration is stored in campaign_schedule.json with structure:


{
  "campaigns": [
    {
      "id": "rady_shell_blast_1",
      "template": "rady_shell_blast1.html",
      "recipients": ["segment:event_registrants"],
      "schedule": "0 9 * * ?",
      "subject": "Rady Shell Event Update",
      "from_email": "events@queenofsandiego.com"
    }
  ]
}

Why JSON configuration: Decoupling scheduling logic from deployment allows non-engineers to modify campaign timing without code changes. The cron-like schedule field enables future migration to CloudWatch Events or EventBridge if volume increases.

Domain-specific campaign tools:

  • qdn_consumer_blast.py — Handles quickdumpnow.com promotional campaigns with unsubscribe tracking
  • platform_inbox_scraper.py — Monitors third-party booking platform inboxes and triggers response workflows

Email templates are stored in per-domain directories:

  • /Users/cb/Documents/repos/tools/templates/rady_shell_blast1.html
  • /Users/cb/Documents/repos/sites/quickdumpnow.com/marketing/templates/qdn_blast1.html

Templates use simple variable substitution {{recipient_name}} syntax to avoid template engine dependencies and simplify deployment to SES.

Third-Party Platform Integration

Boat Platform Credentials Management:

Multiple boat rental/booking platforms (GetMyBoat, Boatsetter) require credential storage and periodic synchronization. Rather than hardcoding endpoints, we centralized platform configuration in repos.env with structure:


GETMYBOAT_API_KEY=...
GETMYBOAT_API_SECRET=...
BOATSETTER_AUTH_TOKEN=...
PLATFORM_CALENDAR_SYNC_ENABLED=true

The dispatch_boat_cleaner.py tool reads these credentials and implements the following workflow:

  1. Queries booking platforms for completed charters
  2. Extracts boat location and customer contact info
  3. Creates dispatch task records in internal database
  4. Sends SMS notifications to crew via SNS
  5. Updates calendar events with cleaner assignment

Why iCal sync over API polling: Rather than continuous API polling (high cost, quota-limited), we configured platform iCal feeds to sync directly into Google Calendar via CalendarSync.gs. This reduces external API calls by ~95% while providing near-real-time updates through calendar webhooks.

Lambda-Based Calendar API Endpoint

The Lambda function at /Users/cb/Documents/repos/sites/queenofsandiego.com/tools/shipcaptaincrew/lambda_function.py was extended to expose HTTP calendar operations through API Gateway.

Current routing:

  • POST /calendar/add-event — Creates calendar event from request payload
  • GET /calendar/list-events — Returns filtered events with pagination
  • DELETE /calendar/{eventId} — Removes specific event

The function validates auth tokens against dashboard token stored in repos.env, preventing unauthorized calendar modifications.

Why Lambda instead of GAS HTTP triggers: Lambda provides better error handling, environment variable management, and CloudWatch integration. Direct Lambda invocation is ~200ms faster than GAS HTTP endpoints, critical for dashboard responsiveness.

Unsubscribe Management & Compliance

Email campaigns across all domains feed into centralized unsubscribe tracking:

/Users/cb/Documents/repos/sites/quickdumpnow.com/unsubscribe/index.html provides a one-click unsubscribe flow that:

  1. Captures email address from URL parameter
  2. Invokes Lambda function to mark recipient as unsubscribed
  3. Updates recipient database to exclude from future campaigns
  4. Returns confirmation page to complete user journey

Why separate unsubscribe page per domain: Each domain has distinct branding and legal requirements. Consolidating would require complex conditional rendering and increase unsubscribe failure risk.

Deployment Pipeline

Four new deployment scripts standardize the release process:

  • deploy_inbox_scraper.sh — Packages platform_inbox_scraper.py and deploys to Lambda@Edge
  • deploy_campaign_scheduler