Building a Multi-Tenant Executive Reporting System: Automated SES Deployment Across Four Business Entities
Over the past development session, we deployed an automated executive reporting pipeline that generates role-specific business intelligence reports across four distinct operating entities (JADA, Queen of San Diego, QuickDumpNow, and Dangerous Centaur) and delivers them via AWS SES. This post covers the architecture, implementation details, infrastructure decisions, and lessons learned.
What Was Done
We built and deployed two complementary Python scripts that generate five distinct C-suite reports tailored to different stakeholder perspectives:
- CEO Report: Full asset inventory, critical shortfalls, missing KPIs, and 30-day action plan
- CTO Report: Stack audit, security gaps, cost analysis, UX gaps, and dev cycle improvements
- Accounting Report: Revenue recognition, chart of accounts, expense audit, profitability roadmap
- CMO Report: Channel visibility, marketing deployment sequencing, OTA strategy
- CFO Report: Burn rate modeling, capital deployment framework, break-even analysis
The system was then extended to support three additional domain-specific reports (3028 51st St Rental, Expert Yacht Delivery, and DangerousCentaur Client Portfolio audit), bringing the total to eight perspectives on organizational health.
Technical Implementation
Core Architecture
The implementation consists of two Python modules:
/Users/cb/Documents/repos/tools/send_exec_reports.py— Primary report generation and delivery engine/Users/cb/Documents/repos/tools/send_exec_reports_2.py— Extended domain-specific reporting (created as iteration)
Both scripts follow a similar pattern: construct role-specific narrative analysis, format as plain-text email bodies, use boto3 SES client to send, and log delivery status.
SES Configuration
The sending infrastructure relies on AWS SES with these characteristics:
- Verified sender:
admin@queenofsandiego.com(hardcoded in script; verified in SES console) - Recipient:
c.b.ladd@gmail.com(primary inbox) - BCC:
admin@queenofsandiego.com(audit trail) - SES credentials loaded from environment:
AWS_ACCESS_KEY_ID,AWS_SECRET_ACCESS_KEY,AWS_REGION - Configuration validated against
repos.envprior to execution
Before deployment, we verified sender email variables:
grep -i "SES\|EMAIL\|FROM" repos.env
grep -i "admin\|sender" repos.env
This defensive check caught a critical naming inconsistency early and prevented bounces.
Report Generation Logic
Each report is constructed as a structured narrative with:
- Asset Inventory Section: Enumeration of all owned/operated properties and tools
- Shortfalls/Gaps Section: Prioritized list of missing capabilities or broken processes
- KPI Framework: Missing metrics that should be tracked
- Actionable Recommendations: 30/60/90-day phased improvements
- Financial Impact Estimates: Where quantifiable
The CTO report, for example, audits all four tech stacks against standards for:
- Security posture (hardcoded credentials, plaintext config, authentication gaps)
- Cost efficiency (AWS spend, per-resource optimization)
- User experience (missing features, analytics gaps, outdated copy)
- Development velocity (CI/CD, staging environments, rollback capability)
The CFO report models burn rate (~$7–9K/month across all entities) and calculates break-even thresholds (6 charters/month for Queen of San Diego), establishing clear monthly revenue targets through Q4 2026.
Infrastructure & Deployment
AWS SES Configuration
SES operates in sandbox mode with verified sender and recipient addresses. The boto3 client was configured with explicit region and credentials:
import boto3
ses_client = boto3.client(
'ses',
region_name=os.getenv('AWS_REGION'),
aws_access_key_id=os.getenv('AWS_ACCESS_KEY_ID'),
aws_secret_access_key=os.getenv('AWS_SECRET_ACCESS_KEY')
)
response = ses_client.send_email(
Source='admin@queenofsandiego.com',
Destination={'ToAddresses': ['c.b.ladd@gmail.com'], 'BccAddresses': ['admin@queenofsandiego.com']},
Message={
'Subject': {'Data': subject_line},
'Body': {'Text': {'Data': report_body}}
}
)
This pattern allows batch sending (5 reports in the initial run, 3 additional in the extension) without rate-limiting, since SES quota in sandbox is 1 email/second.
Environment Variable Management
All credentials and endpoints are externalized to repos.env, which is never committed. Pre-deployment verification ensures:
- SES variables are defined and non-empty
- From-address matches a verified SES identity
- AWS region is set (typically
us-west-2for our infrastructure)
This separation allows the same script to run across development, staging, and production by swapping environment files.
Key Decisions & Rationale
Why Plain-Text Reports, Not HTML Templates?
C-suite recipients prefer plain text for several reasons:
- Guaranteed rendering consistency across email clients
- Easier to forward, print, and archive in legal holds
- No dependency on external CSS or image CDNs (reduces surface area)
- Faster to generate (no template engine overhead)
HTML templates are deferred to future dashboard integration.
Why Separate Scripts Instead of One Monolith?
The initial send_exec_reports.py covered the core five roles. As three additional domain-specific reports emerged (rental property, yacht delivery, client portfolio), we created send_exec_reports_2.py rather than monolith-ifying the first script. This allows:
- Independent scheduling (e.g., rental reports on 1st of month, yacht delivery on Fridays)
- Separate error handling and retry logic per domain
- Easier testing and iteration without affecting production report runs
- Clear separation between "core org health" and "asset-specific" reporting
Future refactor will merge these under a unified ReportRunner class with strategy pattern dispatch.
Why BCC the Sender?
Sending admin@queenofsandiego.com