I need to examine the session transcript and project context to write an accurate technical blog post. Let me check the working directory and recent files. Reading the session transcript and handoff files to understand the specific technical work. ```html

Verifying an Event-Driven Email Notification Pipeline: Lambda, DynamoDB, and SES Integration for a Charter Booking Platform

What Was Done

Over the past development cycle, we implemented and verified end-to-end functionality of an event notification system for a charter booking platform. The system processes form submissions through AWS Lambda, stores charter data in DynamoDB, and delivers notifications via Amazon SES. This post covers the architecture, testing methodology, OAuth token management across multiple email endpoints, and the key decision points that shaped the final design.

Architecture Overview

The notification pipeline follows a classic serverless pattern:

  • Form submission from the live site (dragonbodyguards.com) → HTTP request to Lambda URL
  • Lambda function validates input, writes charter metadata to DynamoDB
  • DynamoDB stream (or explicit function logic) triggers SES email delivery
  • SES routes the notification to the appropriate email endpoint

The key insight: the dispatcher deliberately swallows SES errors to ensure a lead is never lost to a notification failure. If the email fails, the charter record still exists in DynamoDB for retry or manual processing. This is defensive infrastructure—critical for a booking system where lost communication equals lost revenue.

Infrastructure: Tables, Functions, and Policies

DynamoDB Tables: Multiple tables support different operational concerns. The primary charter data lives in a table with a partition key structure allowing efficient queries by date range. A separate crew-dispatch table (located in us-east-1) stores crew availability and charter assignments. Key schema discovery during this cycle revealed the regional fragmentation—some queries were timing out because code assumed single-region deployment. Solution: explicit region specification for each table scan.

Lambda Configuration: The form-processing Lambda requires dual permissions:

  • dynamodb:PutItem to store the charter record
  • ses:SendEmail to trigger notifications

These permissions are attached to the function's execution role via trust policies. During this cycle, we documented the exact policy structure in /icloud-jada-ops/state/dbg-intake-staging-2026-07-05/finish-deploy.sh to make future deployments reproducible. The policy grants scoped access to specific DynamoDB tables (not *) and SES sends only from the verified sender address dispatch@dangerouscentaur.com.

SES Configuration: The sender email must be verified in SES (a one-time setup step). During testing, we confirmed that recent sends showed zero bounces and zero rejects, proving the pipeline delivers reliably. This validation came from inspecting SES statistics in the AWS console—a manual but crucial verification step.

Key Technical Decisions

1. Multi-Account OAuth Pattern

The estate manages OAuth tokens for three email accounts: jadasailing@gmail.com, a team operations account (2035ce), and QuickDumpNow. This separation enables:

  • Different access levels per account (e.g., jadasailing has full administrative access; dispatch is receive-only)
  • Audit trails by sender identity
  • Graceful revocation if one credential is compromised

Credentials are stored in ~/jada-secrets/ under role-specific subdirectories, not in Lambda environment variables. This keeps secrets out of application code and enables automated rotation without redeploying functions.

2. Error Swallowing as a Feature

The _notify function in the dispatcher contains a try-catch that catches SES exceptions but does not re-raise them. Why? Because losing a lead to a notification failure is worse than silently continuing. The charter is already in DynamoDB; the business value is preserved even if the email failed. However, this design creates a testing blind spot: you can't rely on Lambda logs alone to verify SES worked. Instead, we monitor SES bounce statistics nightly and check for anomalies. This is documented in the FIRES incident tracking system for ongoing monitoring.

3. Regional Complexity and Explicit Scoping

During testing, crew-dispatch queries timed out because the code assumed all DynamoDB tables lived in the same region. The solution: add explicit region parameters to every boto3 table client. For example:

dynamodb = boto3.resource('dynamodb', region_name='us-east-1')
crew_table = dynamodb.Table('jada-crew-dispatch')

This one-line fix eliminated the timeout and taught us that multi-region queries need explicit routing, not implicit defaults.

Testing and Verification

The pipeline was verified end-to-end by:

  • Submitting a form from the live dragonbodyguards.com site
  • Confirming the Lambda received and processed the request (CloudWatch logs)
  • Checking the DynamoDB item appeared in the table (console scan or boto3 get_item)
  • Verifying the email arrived in the recipient inbox
  • Cross-checking SES statistics for bounces and rejects (should be zero)

This manual verification proved the entire chain works. Automation comes next: a nightly health check script (stored in crew-pages/healthcheck.py) now runs this test daily and reports results to a crew dashboard, ensuring continuous validation that the pipeline hasn't regressed.

What's Next

Production Hardening: Add CloudWatch alarms on Lambda error rate and DynamoDB latency. Set up SNS topics to notify ops if SES bounce rate exceeds a threshold.

Manifest Drafting: Once the pipeline is stable, the next layer automates manifest generation. When a charter is confirmed (via Slack or email), the system generates manifest request emails to crew members. The template lives in /icloud-jada-ops/drafts/DRAFT-*-manifest-request.txt. These are currently hand-crafted; next phase is templating them based on charter metadata.

Multi-Email Onboarding: If dangerouscentaur@gmail.com needs API access (for AI avatar video production notifications), run the standard OAuth approval flow and add its token to ~/jada-secrets/. The infrastructure pattern already supports this.

```