AWS SES Setup Guide: When "Simple" Turns Into Hours of DNS Hell
I set out to build a newsletter feature. Simple, right? Just send some emails. Wrong. What followed was hours of AWS SES configuration, DNS record juggling in Cloudflare, domain verification, SMTP credential generation, and the eternal wait for AWS to approve my Production Access request. My blood pressure spiked every time I saw "Verification Pending." This AWS SES setup guide is the survival manual I wish I had - all five phases from domain verification to production access, with the Cloudflare gotchas and SMTP credential traps that cost me an afternoon.
>
The Reality: Setting up AWS SES is not "click and ship." It's a multi-phase operation involving
domain verification, DNS configuration, SMTP setup, and production access approval. But once it's
done, it's bulletproof.
This is the complete guide I wish I had when I started.
This ensures AWS knows this address is authorized to send
Then came the waiting game. "Verification Pending." I hate waiting.
After about 20 minutes: Verified. Green checkmark. Phase 1 complete.
AWS SES domain verification process: Adding DKIM CNAME records to Cloudflare DNS with proxy
status set to DNS Only for AWS SES email delivery setup.
Phase 2: Deliverability (The Professional Polish)
Getting verified is one thing. Getting emails to actually land in inboxes (not spam) is another.
This is where Custom MAIL FROM comes in.
>
Without Custom MAIL FROM, your emails show up as "via amazonses.com" in Gmail. That's amateur
hour. Custom MAIL FROM makes your emails look professional and improves deliverability.
What I Did:
Set Up Custom MAIL FROM Domain
In the SES Identity settings, I configured mail.bernhardrieder.com
This subdomain becomes the technical sender
Added MX Record to Cloudflare
AWS provided an MX record
Priority: 10
Target: feedback-smtp.us-east-2.amazonses.com
Added to Cloudflare for mail.bernhardrieder.com
Added SPF Record (TXT)
AWS provided a TXT record for SPF
This tells email servers that AWS is authorized to send on my behalf
Added to Cloudflare for mail.bernhardrieder.com
Proxy Check
Ensured both records were set to "DNS Only"
AWS needs direct access to verify these
Result: My emails now show as coming from [email protected] with no "via" disclaimer. Professional.
AWS SES custom MAIL FROM configuration: Setting up MX and SPF records in Cloudflare DNS for
professional email deliverability and AWS SES setup.
Phase 3: Sending Access (The Plumbing)
Now I needed SMTP credentials to actually send emails from my application.
What I Did:
Created SMTP Credentials
Went to SES → SMTP Settings
Clicked "Create SMTP credentials"
AWS automatically created an IAM user
Named the IAM User
Used a clear name: bernhardrieder.com-smtp-user
This makes it easy to identify in the IAM console
Downloaded the Credentials
CRITICAL: The password is only shown once
Downloaded the .csv file immediately
Stored it securely in my project's .agent/ folder (gitignored)
Noted the SMTP Endpoint
My region: us-east-2 (Ohio)
Endpoint: email-smtp.us-east-2.amazonaws.com
Port: 587 (STARTTLS)
Security Note: These credentials are sensitive. Never commit them to Git. I stored mine in .env.local and added it to .gitignore.
AWS SES SMTP credentials configuration: Generating IAM user credentials and noting SMTP endpoint
details for AWS SES email delivery setup.
Phase 4: Production Access (The Final Boss)
Here's the catch: AWS SES starts in Sandbox Mode.
Sandbox Limitations //
In Sandbox Mode, you can only send emails TO verified addresses. You cannot send to random
subscribers. You must request Production Access to send to anyone.
What I Did:
Submitted Production Access Request
Navigated to SES → Account dashboard
Clicked "Request production access"
Filled out the form explaining my use case
Explained My Use Case
Newsletter for my personal website
Expected volume: ~1,000 emails/month initially
Opt-in subscribers only
Clear unsubscribe mechanism
Waited for Approval
AWS reviews these requests manually
Can take 24-48 hours
Current Status: Still waiting
Tested in Sandbox Mode
While waiting, I tested by sending to my own verified Gmail
Clicked "Send test email" in the SES console
Worked perfectly
The Wait: This is where I am now. Waiting for AWS to approve production access. Once approved, I can send to any email address.
Phase 5: Implementation (The Big Rig Integration)
While waiting for production access, I wired everything up in my Next.js app.
Environment Variables (.env.local):
bash
1# AWS SES Configuration2AWS_REGION="us-east-1"3AWS_ACCESS_KEY_ID="[YOUR_ACCESS_KEY]"4AWS_SECRET_ACCESS_KEY="[YOUR_SECRET_KEY]"56# Newsletter Configuration7NEWSLETTER_FROM_EMAIL="[email protected]"89# AWS SES SMTP Credentials10SMTP_HOST="email-smtp.us-east-2.amazonaws.com"11SMTP_PORT="587"12SMTP_USERNAME="[YOUR_SMTP_USERNAME]"13SMTP_PASSWORD="[YOUR_SMTP_PASSWORD]"
API Route (/api/newsletter/send-verification):
I created a Next.js API route that uses the AWS SDK to send verification emails when users subscribe.
The Flow:
User enters email on newsletter page
API generates Firebase Email Link via generateSignInWithEmailLink()
API calls AWS SES to send verification email with that link
User clicks link in email → Firebase Auth completes sign-in
Subscription confirmed and subscriber record created
Current Status: The code is ready. The infrastructure is configured. I'm just waiting for AWS to flip the switch.
AWS SES Setup Takeaway //
Five phases: Verification, Deliverability, SMTP, Production Access, Integration. The grey cloud in
Cloudflare is critical - AWS cannot verify proxied records. Save SMTP credentials immediately.
The Minimalist Cheat Sheet
For anyone setting up AWS SES in the future, here's the condensed version:
Quick Setup Guide
Phase 1: Verification
Create Domain Identity in AWS SES
Generate DKIM records (3 CNAMEs)
Add to Cloudflare DNS (Grey Cloud = DNS Only)
Verify sender email address
Phase 2: Deliverability
Set up Custom MAIL FROM (e.g., mail.yourdomain.com)
Add MX record to DNS (Priority 10)
Add SPF record (TXT) to DNS
Ensure DNS Only (not proxied)
Phase 3: SMTP Access
Create SMTP credentials in SES
Name IAM user clearly
Download .csv file (password shown once!)
Note SMTP endpoint for your region
Phase 4: Production
Request Production Access via SES dashboard
Explain use case clearly
Test with verified emails while waiting
Wait 24-48 hours for approval
Phase 5: Integration
Store credentials in .env.local
Add to .gitignore
Build API routes for sending
Test thoroughly
Pro Tips for Future Setup
The "Grey Cloud" Rule
In Cloudflare, always set DKIM and MAIL FROM records to "DNS Only". AWS cannot verify
proxied records.
Region Consistency
Keep your SES Identity, SMTP Endpoint, and S3 buckets in the same region to avoid latency
issues.
Sandbox Testing
In Sandbox Mode, both sender AND recipient must be verified. Test with your own email first.
Save Credentials Immediately
SMTP password is shown ONCE. Download the CSV immediately and store it securely.
The Current Status
What's Done:
✅ Domain verified in AWS SES
✅ DKIM records configured
✅ Custom MAIL FROM set up
✅ SMTP credentials generated
✅ DNS records added to Cloudflare
✅ Handshake successful
✅ Test email sent and received
✅ API routes built and tested
✅ Environment variables configured
What's Pending:
⏳ AWS Production Access approval (24-48 hours)
What's Next:
Once approved, the newsletter goes live
Subscribers can join via email or Google sign-in
Verification emails will be sent automatically
Archive of past issues will be public
Almost There //
The infrastructure is ready. The code is tested. I'm just waiting for AWS to approve production
access. Once that happens, the newsletter engine is live.
The Aftermath
This was not a quick afternoon project. This was hours of:
Reading AWS documentation
Configuring DNS records
Waiting for verification
Testing SMTP connections
Debugging region mismatches
Filling out production access forms
But it's done. The infrastructure is professional. The emails will be reliable. The cost is minimal.
>
There is a specific satisfaction in building infrastructure that just works. No third-party
service. No monthly fees per subscriber. Just clean, professional email delivery that I control
completely.
Now I wait for AWS to approve production access. Then the newsletter goes live.
If you're setting up AWS SES, use this guide. Save yourself the hours I spent figuring it out.
The Builder Dispatches are coming.
Latest Blog Posts
Manifesto2026-05-02
The Rise of the Agentic Internet
The era of building website content is dead. The digital world just hasn't seen the body yet. I am moving to Full Agentic AI — and the implications will dismantle the current server-based software industry.
2026-02-12
LM Studio vs. Ollama
LM Studio runs Llama 4 Scout on local GPUs - but even 96GB VRAM has limits. Context length matters. Kilo Code bridges your IDE to local models. Here is what I learned.
Best Practices2026-02-08
Why You Must Run ESLint Before You Touch the "Cloud"
Running ESLint locally isn't optional - it's your first defense against broken Vercel deployments. I learned this the hard way when my code pushed to Git, triggered Vercel, and failed after 5 minutes of waiting. The fix? A 0.5-second local ESLint check that catches errors before they reach production. Here's why ESLint prevents deployment failures, code rot, and invisible performance bugs.
Achievement2026-02-08
Building a Neural Link Architecture: Zero Link Rot with AI-Powered Semantic Linking
I got absolutely fed up with broken internal links and manual link maintenance. The problem? Hardcoded links rot when slugs change. The solution? A neural link architecture that uses vector embeddings, hybrid ranking algorithms, and AI to automatically inject semantically relevant links at render-time. This system eliminates link rot, scales to thousands of articles, and ensures every link is contextually relevant. Here's how I built a semantic linker that treats websites as living knowledge graphs for AI citation systems.
A
B
C
This article is part of a Semantic Cluster. All links are managed by the Digital Architect AI.