From cc694ed5bbfd9bb45fbc319c1eb9ffa111e869a9 Mon Sep 17 00:00:00 2001 From: fullsizemalt <106900403+fullsizemalt@users.noreply.github.com> Date: Sun, 21 Dec 2025 14:40:20 -0800 Subject: [PATCH] docs: Add comprehensive AWS SES setup guides - AWS_SES_SETUP.md: Complete setup with prod/dev env separation - AWS_SES_BROWSER_AGENT.md: Step-by-step for browser-based agent - Explicit security notes about IAM scoping and key handling --- docs/AWS_SES_BROWSER_AGENT.md | 127 ++++++++++++++++++++++++ docs/AWS_SES_SETUP.md | 178 +++++++++++++++++----------------- 2 files changed, 215 insertions(+), 90 deletions(-) create mode 100644 docs/AWS_SES_BROWSER_AGENT.md diff --git a/docs/AWS_SES_BROWSER_AGENT.md b/docs/AWS_SES_BROWSER_AGENT.md new file mode 100644 index 0000000..7d82b8c --- /dev/null +++ b/docs/AWS_SES_BROWSER_AGENT.md @@ -0,0 +1,127 @@ +# AWS SES Setup - Browser Agent Handoff + +## Objective + +Configure AWS SES for the Elmeg platform to enable transactional emails (verification, password reset). + +**Domain:** `elmeg.xyz` +**Production URL:** `https://elmeg.xyz` +**Sender Email:** `noreply@elmeg.xyz` + +--- + +## Step 1: Verify Domain in SES + +1. Go to: +2. Select region **US East (N. Virginia) us-east-1** from top-right dropdown +3. Left sidebar → **Verified identities** → Click **Create identity** +4. Select **Domain** +5. Enter: `elmeg.xyz` +6. Keep "Use a custom MAIL FROM domain" unchecked +7. Click **Create identity** +8. Copy the DNS records shown: + - 1 TXT record (for verification) + - 3 CNAME records (for DKIM) +9. **Save these records** - they need to be added to elmeg.xyz DNS + +--- + +## Step 2: Add DNS Records + +Go to the DNS provider for `elmeg.xyz` and add: + +| Type | Name | Value | +|------|------|-------| +| TXT | `_amazonses.elmeg.xyz` | (from SES console) | +| CNAME | `xxxx._domainkey.elmeg.xyz` | (DKIM 1 from SES) | +| CNAME | `xxxx._domainkey.elmeg.xyz` | (DKIM 2 from SES) | +| CNAME | `xxxx._domainkey.elmeg.xyz` | (DKIM 3 from SES) | + +Wait for verification (can take 5-72 hours). + +--- + +## Step 3: Request Production Access + +By default SES is in sandbox mode (can only send to verified emails). + +1. In SES console → **Account dashboard** (left sidebar) +2. Find "Your account is in the Amazon SES sandbox" banner +3. Click **Request production access** +4. Fill form: + - **Mail type:** Transactional + - **Website URL:** + - **Use case description:** + > "Transactional emails for user account lifecycle on a live music rating platform. Emails include: account verification, password reset, and account notifications. Expected volume: under 1000 emails/month initially." +5. Submit and wait for approval (~24 hours) + +--- + +## Step 4: Create IAM User for SES + +1. Go to: +2. Left sidebar → **Users** → **Create user** +3. User name: `elmeg-ses-sender` +4. Click **Next** +5. Select **Attach policies directly** +6. Click **Create policy** (opens new tab): + - Select **JSON** tab + - Paste: + + ```json + { + "Version": "2012-10-17", + "Statement": [ + { + "Effect": "Allow", + "Action": ["ses:SendEmail", "ses:SendRawEmail"], + "Resource": "*" + } + ] + } + ``` + + - Click **Next** + - Policy name: `SES-SendEmail-Only` + - Click **Create policy** +7. Back on user creation, refresh policies, search `SES-SendEmail-Only`, select it +8. Click **Next** → **Create user** + +--- + +## Step 5: Create Access Key + +1. Click on user `elmeg-ses-sender` +2. Tab: **Security credentials** +3. Scroll to **Access keys** → **Create access key** +4. Select: **Application running outside AWS** +5. Click **Next** → **Create access key** +6. **SAVE BOTH VALUES:** + - Access key ID: `AKIA...` + - Secret access key: `...` +7. Click **Done** + +--- + +## Step 6: Return Values + +Return these values to the user: + +``` +AWS_ACCESS_KEY_ID=AKIA... +AWS_SECRET_ACCESS_KEY=... +AWS_SES_REGION=us-east-1 +EMAIL_FROM=noreply@elmeg.xyz +FRONTEND_URL=https://elmeg.xyz +``` + +Also return the DNS records that need to be added for domain verification. + +--- + +## Notes + +- **Never share or commit AWS keys** +- SES sandbox removal takes ~24hrs +- Domain verification DNS propagation can take up to 72hrs +- DKIM is required or emails will be marked as spam diff --git a/docs/AWS_SES_SETUP.md b/docs/AWS_SES_SETUP.md index 143f90b..b1a91f6 100644 --- a/docs/AWS_SES_SETUP.md +++ b/docs/AWS_SES_SETUP.md @@ -1,73 +1,105 @@ # AWS SES Email Setup -## Overview +## Environment Configuration -The Elmeg platform uses AWS SES (Simple Email Service) for sending transactional emails (verification, password reset). Cost: ~$0.10 per 1,000 emails. +### Production (`elmeg.xyz`) + +```bash +AWS_ACCESS_KEY_ID=AKIA... # IAM user with SES send-only perms +AWS_SECRET_ACCESS_KEY=... +AWS_SES_REGION=us-east-1 # Must match region where domain is verified +EMAIL_FROM=noreply@elmeg.xyz # Must be on SES-verified domain +FRONTEND_URL=https://elmeg.xyz +NODE_ENV=production +APP_ENV=production +``` + +### Development (`elmeg.runfoo.run`) + +```bash +FRONTEND_URL=https://elmeg.runfoo.run +APP_ENV=development +# AWS keys optional in dev - emails log to console instead +``` --- -## Prerequisites +## SES Setup Checklist -- AWS Account -- Domain: `elmeg.xyz` (for verified sender) -- Production server: `tangible-aacorn` / `nexus-vector` +### 1. Verify Domain in SES + +1. AWS Console → SES → Verified Identities → Create identity +2. Select "Domain" → enter `elmeg.xyz` +3. Add DNS records AWS provides: + - **TXT record** for domain verification + - **3 CNAME records** for DKIM signing + +> [!IMPORTANT] +> Add DKIM records or mail will get flagged as spam + +### 2. Move Out of Sandbox + +By default SES is sandboxed (can only send to verified emails). + +1. SES → Account dashboard → Request production access +2. Fill out: + - Mail type: **Transactional** + - Website URL: `https://elmeg.xyz` + - Use case: "User registration verification, password reset for live music rating platform" +3. Wait for approval (~24hrs) + +### 3. Create IAM User + +1. IAM → Users → Create user: `elmeg-ses-sender` +2. Attach inline policy (SES send only): + +```json +{ + "Version": "2012-10-17", + "Statement": [ + { + "Effect": "Allow", + "Action": [ + "ses:SendEmail", + "ses:SendRawEmail" + ], + "Resource": "*" + } + ] +} +``` + +3. Security credentials → Create access key +4. Save credentials securely + +> [!CAUTION] +> **Never commit AWS keys.** Use environment variables only. Never use root AWS credentials - always create a scoped IAM user. --- -## Setup Steps +## DNS Records Required -### 1. Verify Email Domain in SES +Add these to `elmeg.xyz` DNS (exact values from SES console): -1. Go to AWS Console → SES → Verified Identities -2. Click "Create identity" → Choose "Domain" -3. Enter: `elmeg.xyz` -4. Enable "Use a custom MAIL FROM domain" (optional) -5. Add the provided DNS records to your domain +| Type | Name | Value | +|------|------|-------| +| TXT | `_amazonses.elmeg.xyz` | (provided by SES) | +| CNAME | `xxxx._domainkey.elmeg.xyz` | (DKIM 1) | +| CNAME | `xxxx._domainkey.elmeg.xyz` | (DKIM 2) | +| CNAME | `xxxx._domainkey.elmeg.xyz` | (DKIM 3) | -**Required DNS Records** (example): +--- -``` -Type: TXT -Name: _amazonses.elmeg.xyz -Value: [provided by AWS] +## Deployment -Type: CNAME -Name: [dkim1]._domainkey.elmeg.xyz -Value: [provided by AWS] -``` - -### 2. Move Out of SES Sandbox - -By default, SES is in sandbox mode (can only send to verified emails). - -1. Go to SES → Account dashboard -2. Click "Request production access" -3. Fill out: - - Mail type: Transactional - - Website URL: - - Use case: User registration verification, password reset -4. Wait for approval (usually 24hrs) - -### 3. Create IAM User for SES - -1. Go to IAM → Users → Create user -2. Name: `elmeg-ses-sender` -3. Attach policy: `AmazonSESFullAccess` (or create custom with `ses:SendEmail` only) -4. Create access key for "Application running outside AWS" -5. Save: - - Access Key ID - - Secret Access Key - -### 4. Configure Production Server - -SSH into server and update environment: +### Add to production server ```bash ssh root@tangible-aacorn cd /srv/containers/elmeg-demo ``` -Edit `docker-compose.yml`, add to `backend` service: +Edit `docker-compose.yml` backend environment: ```yaml backend: @@ -78,56 +110,21 @@ backend: - AWS_SES_REGION=us-east-1 - EMAIL_FROM=noreply@elmeg.xyz - FRONTEND_URL=https://elmeg.xyz + - APP_ENV=production ``` -Or create `.env` file: - -```env -AWS_ACCESS_KEY_ID=AKIA... -AWS_SECRET_ACCESS_KEY=your-secret-key -AWS_SES_REGION=us-east-1 -EMAIL_FROM=noreply@elmeg.xyz -FRONTEND_URL=https://elmeg.xyz -``` - -### 5. Add boto3 to Requirements - -```bash -# Add to backend/requirements.txt -boto3>=1.28.0 -``` - -### 6. Run Migration & Restart +Rebuild and restart: ```bash docker compose build backend -docker compose exec backend python migrations/add_email_verification.py docker compose restart backend ``` -### 7. Test - -1. Register at -2. Check for verification email -3. Test forgot password at - ---- - -## Environment Variables - -| Variable | Description | Example | -|----------|-------------|---------| -| `AWS_ACCESS_KEY_ID` | IAM user access key | `AKIA...` | -| `AWS_SECRET_ACCESS_KEY` | IAM user secret | `wJalr...` | -| `AWS_SES_REGION` | SES region | `us-east-1` | -| `EMAIL_FROM` | Verified sender address | `noreply@elmeg.xyz` | -| `FRONTEND_URL` | Base URL for links | `https://elmeg.runfoo.run` | - --- ## Cost -- $0.10 per 1,000 emails +- **$0.10 per 1,000 emails** - No monthly minimum - First 62,000 emails/month free if sending from EC2 @@ -137,7 +134,8 @@ docker compose restart backend | Issue | Solution | |-------|----------| -| "Email address is not verified" | Domain not verified in SES, or still in sandbox | -| "Access Denied" | Check IAM permissions for ses:SendEmail | +| "Email address is not verified" | Domain not verified, or still in sandbox | +| "Access Denied" | Check IAM policy has `ses:SendEmail` | | Emails not sending | Check `docker compose logs backend` | -| Emails in spam | Complete DKIM setup, verify domain | +| Emails in spam | Verify DKIM records are set correctly | +| Wrong links in emails | Check `FRONTEND_URL` matches prod domain |