```html

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.env prior 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-2 for 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