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:
parent
bb1cba5e20
commit
cc694ed5bb
2 changed files with 215 additions and 90 deletions
127
docs/AWS_SES_BROWSER_AGENT.md
Normal file
127
docs/AWS_SES_BROWSER_AGENT.md
Normal 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
|
||||
|
|
@ -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 |
|
||||
|
|
|
|||
Loading…
Add table
Reference in a new issue