Building the messaging feature — appointment reminders, billing notices, wellness check notifications, and patient onboarding emails. AWS SES must be configured before the dev team can wire it into the backend.
- Environments: Staging (dev) + Production
- AWS Region: us-east-2
- IaC Tool: OpenTofu (existing
b4m-infrarepo — NOT Pulumi/SST)
| Account | Domain | Zone ID | File |
|---|---|---|---|
| starlightpractice-prod (524471258033) | starlightpractice.com | Z03036173FL99T10J98KK | accounts/starlightpractice-prod/main.tf |
| starlightpractice-dev (421807902331) | dev.starlightpractice.com | Z028466637NTWD1K6UX8Z | accounts/starlightpractice-dev/main.tf |
Both zones are already managed in OpenTofu state in b4m-infra. SES DKIM CNAMEs
reference them directly — no new zones needed.
The starlight project uses OpenTofu exclusively in b4m-infra. Pulumi is NOT used here.
OpenTofu is the correct tool for all automatable tasks.
| Account | Sending Enabled | Production Access | Existing Identities |
|---|---|---|---|
| starlightpractice-dev | ✅ Yes | ❌ Sandbox only | None |
| starlightpractice-prod | ✅ Yes | ❌ Sandbox only | None |
Both accounts need the manual sandbox removal request (Task 2).
| Task | Method | Notes |
|---|---|---|
| 1. Domain verification + DKIM + MAIL FROM | OpenTofu | ses.tf in each account |
| 2. Sandbox → Production access | AWS Console (manual) | No API exists for this |
| 3. Sending identity (notifications@) | OpenTofu | Included in ses.tf |
| 4. IAM permissions for Lambda | OpenTofu | Included in ses.tf, gated by variable |
| 5. SNS + config set + CloudWatch alarms | OpenTofu | Included in ses.tf |
| File | Action |
|---|---|
accounts/starlightpractice-prod/ses.tf |
Create new — full SES for prod |
accounts/starlightpractice-dev/ses.tf |
Create new — full SES for dev |
accounts/starlightpractice-dev/main.tf |
Edit existing — add us_east_1 provider alias |
AWS publishes SES reputation metrics (Reputation.BounceRate, Reputation.ComplaintRate)
to CloudWatch in us-east-1 only, regardless of which region SES is deployed in.
The CloudWatch alarm resources require a provider pointed at us-east-1.
The prod account already has this alias — dev is missing it and needs it added.
starlightpractice.com(root domain) lives in the prod account's Route53dev.starlightpractice.comis a subdomain delegated from prod (seemodule "dev_delegation"in prod's main.tf)- Each AWS account verifies its own SES identity independently — prod cannot share its verification with dev
- Prod is applied first to confirm the root domain and DNS delegation are healthy before layering dev on top
| Account | Sends from | Verifies in |
|---|---|---|
| starlightpractice-prod | notifications@starlightpractice.com | SES account 524471258033 |
| starlightpractice-dev | notifications@dev.starlightpractice.com | SES account 421807902331 |
cd accounts/starlightpractice-prod
tofu init
tofu plan
tofu applyCreates: SES domain identity, 3 DKIM CNAMEs, MAIL FROM records, sending identity, config set, SNS topic, CloudWatch alarms.
cd accounts/starlightpractice-dev
tofu init
tofu plan
tofu applySame as prod but for dev.starlightpractice.com.
Poll until Status = "SUCCESS":
# Prod
aws sesv2 get-email-identity \
--email-identity starlightpractice.com \
--region us-east-2 \
--profile starlightpractice-prod \
--query 'DkimAttributes.Status'
# Dev
aws sesv2 get-email-identity \
--email-identity dev.starlightpractice.com \
--region us-east-2 \
--profile starlightpractice-dev \
--query 'DkimAttributes.Status'See task-2-sandbox-removal.md. Do this for both accounts once DKIM = "SUCCESS".
AWS typically responds within 24 hours.
Once the Lambda execution role name is known, run:
# Prod
cd accounts/starlightpractice-prod
tofu apply -var='lambda_role_name=<role-name-from-sst>'
# Dev
cd accounts/starlightpractice-dev
tofu apply -var='lambda_role_name=<role-name-from-sst>'Every SendEmail SDK call must include the configuration set:
- Prod:
ConfigurationSetName = "starlight-prod" - Dev:
ConfigurationSetName = "starlight-dev"
-
HIPAA BAA: Ensure a signed AWS Business Associate Agreement is activated on both accounts before sending any PHI through SES. This is a manual checkbox under Account Settings → HIPAA eligibility in the AWS Console.
-
Lambda role: Task 4 (IAM) is gated by the
lambda_role_namevariable. Leave it empty on first apply — the resource usescount = 0when the variable is blank, so it safely skips without error. Fill it in once the SST app is deployed. -
Configuration set is required: SES bounce/complaint suppression and CloudWatch tracking only work if the dev team passes
ConfigurationSetNamein every send call. Without it, sends are untracked and the suppression list is bypassed.