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
This commit is contained in:
fullsizemalt 2025-12-21 14:40:20 -08:00
parent bb1cba5e20
commit cc694ed5bb
2 changed files with 215 additions and 90 deletions

View file

@ -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: <https://console.aws.amazon.com/ses>
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:** <https://elmeg.xyz>
- **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: <https://console.aws.amazon.com/iam>
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

View file

@ -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: <https://elmeg.xyz>
- 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 <https://elmeg.runfoo.run/register>
2. Check for verification email
3. Test forgot password at <https://elmeg.runfoo.run/forgot-password>
---
## 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 |