We're building the messaging feature — appointment reminders, billing notices, wellness check notifications, and patient onboarding emails. We need AWS SES configured before the dev team can wire it into the backend.
- Environments: Staging + Production
- AWS Region: us-east-2 (same as existing infra)
- IaC Tool: OpenTofu (
b4m-infrarepo)
| Check | Finding |
|---|---|
| Route53 zones | Already in OpenTofu state in b4m-infra |
| prod zone | starlightpractice.com → ID: Z03036173FL99T10J98KK |
| staging zone | dev.starlightpractice.com → ID: Z028466637NTWD1K6UX8Z |
| IaC tool | OpenTofu (not Pulumi/SST — starlight is separate from lumina5) |
| SES status — prod | SendingEnabled ✅, ProductionAccess ❌ (sandbox) |
| SES status — staging | SendingEnabled ✅, ProductionAccess ❌ (sandbox) |
| Existing SES identities | None on either account |
prod us_east_1 provider |
Already exists in main.tf ✅ |
staging us_east_1 provider |
Missing — must be added to main.tf |
What: Verify starlightpractice.com in SES (us-east-2), add the 3 DKIM CNAME
records to DNS, enable MAIL FROM domain, and confirm both staging and production
accounts have access.
How: OpenTofu — ses.tf in each account directory.
Files:
accounts/starlightpractice-prod/ses.tf(seestarlightpractice-prod-ses.tf)accounts/starlightpractice-dev/ses.tf(seestarlightpractice-dev-ses.tf)
What OpenTofu does for this task:
- Creates the SES domain identity (
aws_sesv2_email_identity) - Generates 3 DKIM tokens and publishes CNAME records into the existing Route53 zone
- Configures MAIL FROM subdomain (
mail.starlightpractice.com) for DMARC alignment - Adds MX + SPF TXT records for the MAIL FROM subdomain
Sending domains per environment:
| Environment | Domain | Sends from |
|---|---|---|
| Production | starlightpractice.com | notifications@starlightpractice.com |
| Staging | dev.starlightpractice.com | notifications@dev.starlightpractice.com |
Each AWS account verifies its own SES identity independently — prod cannot share its verification with staging.
Verify DKIM status (poll after apply, wait 5–30 min):
# Production
aws sesv2 get-email-identity \
--email-identity starlightpractice.com \
--region us-east-2 \
--profile starlightpractice-prod \
--query 'DkimAttributes.Status'
# Staging
aws sesv2 get-email-identity \
--email-identity dev.starlightpractice.com \
--region us-east-2 \
--profile starlightpractice-dev \
--query 'DkimAttributes.Status'What: SES starts in sandbox mode (can only send to verified emails). We need production access for both staging and production accounts.
How: Manual — AWS Console only. No API, OpenTofu resource, or CLI command exists for this.
Timing: Do this AFTER
tofu applycompletes. AWS reviewers check that your domain is already verified before approving. A verified domain improves both approval speed and chances.
Steps (repeat for BOTH accounts):
-
Sign in to AWS Console for the account → region us-east-2
-
Navigate to SES → Account dashboard
-
Click "Request production access"
-
Fill in:
Field Value Mail type TRANSACTIONAL Website https://starlightpractice.comUse case See below Use case description:
"HIPAA-compliant pediatric medical practice sending transactional emails — appointment reminders, billing notices, wellness check notifications, and patient onboarding to families. All recipients have explicitly opted in through the patient portal registration flow. We maintain unsubscribe mechanisms and honor all opt-outs within 10 business days."
-
Submit — AWS typically responds within 24 hours
-
Repeat for the second account
Accounts:
| Account | Account ID | Current Status |
|---|---|---|
| starlightpractice-prod | 524471258033 | ❌ Sandbox |
| starlightpractice-dev | 421807902331 | ❌ Sandbox |
HIPAA Note: Before sending any PHI through SES, ensure a signed AWS Business Associate Agreement (BAA) is activated on both accounts: AWS Console → Account Settings → HIPAA eligibility
What: Configure the from address (notifications@starlightpractice.com or noreply@).
Reply-to is practice-specific (configurable per tenant, stored in practice_settings).
How: OpenTofu — included in ses.tf for each account.
What OpenTofu does for this task:
- Creates an explicit email identity for the from address (
aws_sesv2_email_identity) - Attaches it to the configuration set so sends are tracked
- The domain identity from Task 1 covers all addresses at that domain, but an explicit identity allows per-address configuration set enforcement
What: Lambda execution role needs ses:SendEmail and ses:SendRawEmail permissions,
scoped to the verified identity ARN: arn:aws:ses:us-east-2:*:identity/starlightpractice.com
How: OpenTofu — included in ses.tf. Gated by a variable so it can be skipped on
first apply (Lambda role doesn't exist yet — no SST app deployed for starlight).
Usage:
# Once the SST Lambda role name is known, re-apply with:
tofu apply -var='lambda_role_name=<role-name-from-sst>'The resource uses count = var.lambda_role_name != "" ? 1 : 0 — it safely skips
on first apply when the variable is left blank.
What:
- SNS topic for bounce/complaint notifications
- SES configuration set for tracking sends/bounces/complaints
- CloudWatch alarm if bounce rate exceeds 5%
How: OpenTofu — included in ses.tf for each account.
What OpenTofu does for this task:
- Creates a SES configuration set (
starlight-prod/starlight-dev) with suppression enabled for bounces and complaints - Creates an SNS topic (
ses-events-prod/ses-events-dev) and email subscription - Wires the configuration set to publish BOUNCE, COMPLAINT, DELIVERY_DELAY events to SNS
- Creates two CloudWatch alarms:
- Bounce rate > 5% (AWS auto-suspends at 10%)
- Complaint rate > 0.1% (AWS auto-suspends at 0.5%)
Note on CloudWatch provider: AWS publishes SES reputation metrics to
us-east-1only, regardless of sending region. The alarms useprovider = aws.us_east_1. Prod already has this alias. Staging needs it added — seestarlightpractice-dev-main-addition.tf.
Step 1 → tofu apply (starlightpractice-prod)
Step 2 → tofu apply (starlightpractice-dev)
Step 3 → Poll DKIM status until "SUCCESS" (5–30 min)
Step 4 → Submit sandbox removal via AWS Console (both accounts)
Step 5 → Once SST Lambda roles exist: tofu apply -var='lambda_role_name=...'
Step 6 → Dev team passes ConfigurationSetName in every SendEmail call
prod: "starlight-prod" | staging: "starlight-dev"
# Step 1 — Production (apply first: root domain lives here)
cd accounts/starlightpractice-prod
tofu init && tofu plan && tofu apply
# Step 2 — Staging
cd accounts/starlightpractice-dev
tofu init && tofu plan && tofu apply