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.gsfor 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 recurrencelist-calendar-events— Returns paginated event data for dashboard displaydelete-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 trackingplatform_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:
- Queries booking platforms for completed charters
- Extracts boat location and customer contact info
- Creates dispatch task records in internal database
- Sends SMS notifications to crew via SNS
- 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 payloadGET /calendar/list-events— Returns filtered events with paginationDELETE /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:
- Captures email address from URL parameter
- Invokes Lambda function to mark recipient as unsubscribed
- Updates recipient database to exclude from future campaigns
- 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@Edgedeploy_campaign_scheduler