The Problem: SES Setup is a Nightmare
Developer forums are filled with horror stories about AWS SES setup. The process involves navigating the AWS console, writing IAM policies by hand, configuring DKIM records, setting up event tracking pipelines, and managing credentials—all before you can send a single email.
I have been denied production access about 3 times now... It's frustrating as the responses we get from the AWS Trust & Safety Team are very point blank and appear to be canned messages for rejecting.— AWS re:Post
After a whole day of configurations in the AWS console I still couldn't send one single email. When going back to Resend, I managed to send my first email in literally 1 minute.SES: 15 hours = $1500; Resend: 15mn = $25— Nino Filiu, Dev.to
The time investment is brutal. When you factor in engineer time, the cost of manual SES setup can dwarf the savings you get from AWS's low per-email pricing. Developers routinely spend full days just getting to the point where they can send a single test email.
But here's the thing—once SES is set up, it's incredibly cheap ($0.10 per 1,000 emails) and you own the infrastructure. The problem isn't SES itself. It's the setup.
The Solution: Infrastructure as Code, Zero Console
Wraps deploys production-ready email infrastructure to your AWS account using Pulumi under the hood. One command. No AWS console spelunking. No sandbox approval essays.
▋That's it. In about 2 minutes, you have:
- SES configured with your domain
- DKIM, SPF, and DMARC ready for DNS
- Event tracking via EventBridge
- Email history in DynamoDB
- Lambda functions processing delivery events
- Proper IAM roles with least-privilege access
- OIDC authentication (no stored credentials)
See It In Action
Option 1: The CLI Path (Fastest)
Installation
Install the CLI globally or run it directly with npx:
npm install -g @wraps.dev/cli
# or just use npx
npx @wraps.dev/cli email initRequirements
- Node.js 20+
- AWS CLI configured with valid credentials
- An AWS account with appropriate permissions
Deploying Infrastructure
Run the init command and the CLI walks you through the entire process:
wraps email initThe CLI handles five steps automatically:
- Credential validation – Confirms your AWS access
- Preset selection – Choose Starter, Production, or Enterprise
- Cost estimation – Shows estimated monthly AWS costs
- Deployment – Pulumi provisions everything
- OIDC setup – Configures credential-free access for Vercel
Command Options
wraps email init -p vercel -r us-east-1 -y| Flag | Description |
|---|---|
| -p, --provider | Hosting provider (vercel, aws, railway, other) |
| -r, --region | AWS region |
| -y, --yes | Skip confirmation prompts |
Adding Your Domain
Once infrastructure is deployed, add your sending domain. This creates the SES identity and returns DKIM tokens for DNS configuration.
wraps email domains add -d yourdomain.comVerifying DNS Configuration
After adding DNS records, verify that everything is configured correctly. The CLI checks DKIM CNAME records, SPF TXT record, DMARC TXT record, and MAIL FROM MX records (if configured).
wraps email domains verify -d yourdomain.comManaging Your Deployment
The CLI provides commands for every lifecycle stage of your email infrastructure:
# Check status of your infrastructure
wraps email status
# List all domains
wraps email domains list
# Upgrade to a higher tier
wraps email upgrade
# Remove everything (careful!)
wraps email destroyManual vs Wraps
| Task | Manual SES | With Wraps |
|---|---|---|
| Time to first email | 4-8 hours | ~2 minutes |
| DNS configuration | Manual lookup | Auto-generated |
| IAM policies | Write from scratch | Least-privilege included |
| Event tracking | Build pipeline | One command |
| Credential management | Store secrets | OIDC (zero secrets) |
Option 2: Understanding the IaC (What Gets Deployed)
Under the hood, Wraps uses Pulumi with @pulumi/aws to provision infrastructure. All resources are namespaced with wraps-email-* for easy identification. Here's the complete picture.
IAM Resources
| Resource | Purpose |
|---|---|
| wraps-email-role | Main IAM role for SDK access |
| wraps-email-policy | Least-privilege policy for email operations |
| OIDC Provider | Enables Vercel to assume the role without stored credentials |
SES Resources
| Resource | Purpose |
|---|---|
| wraps-email-config-set | Configuration set for event tracking |
| Email Identities | Your verified domains |
Event Tracking Architecture
Every email event flows through a reliable, serverless pipeline. SES emits events to EventBridge, which routes them to SQS for buffered processing. A Lambda function reads from the queue and writes structured records to DynamoDB. Failed events land in a Dead Letter Queue for debugging.
Event Processing Architecture
Email sent through SES triggers delivery events
| Resource | Purpose |
|---|---|
| EventBridge Rule | Captures SES events (send, delivery, open, click, bounce, complaint) |
| SQS Queue | Buffers events for reliable processing |
| SQS Dead Letter Queue | Stores failed events for debugging |
| Lambda Function | Processes events and writes to DynamoDB |
Storage
| Resource | Purpose |
|---|---|
| wraps-email-history | DynamoDB table for email history |
| wraps-email-events | DynamoDB table for delivery events |
Event Types Tracked
Resource Naming Convention
All Wraps resources follow the pattern wraps-email-{resource-type}. Every resource is tagged with ManagedBy: 'wraps-cli' so you can easily identify and audit Wraps-managed infrastructure in your AWS account.
Configuration Presets
Choose your deployment complexity based on your needs. Upgrade anytime with wraps email upgrade.
Sending Emails with the SDK
Once infrastructure is deployed, install the TypeScript SDK and start sending. The SDK is fully typed and handles credential resolution automatically.
npm install @wraps.dev/emailOn Vercel, credentials are automatic via OIDC—no environment variables, no stored secrets. The SDK detects the runtime environment and acquires temporary AWS credentials transparently.
import { Wraps } from '@wraps.dev/email';
const wraps = new Wraps();
await wraps.emails.send({
from: 'hello@yourdomain.com',
to: 'user@example.com',
subject: 'Welcome!',
html: '<h1>Hello from Wraps!</h1>',
});Vercel OIDC Integration
One of the nastier parts of AWS integrations is credential management. Wraps eliminates this entirely using OIDC federation.
How It Works
Vercel → OIDC Token → AWS STS → Temporary Credentials → SES- Your Vercel deployment requests an OIDC token
- AWS STS validates the token and issues temporary credentials
- The SDK uses those credentials to call SES
- Credentials rotate automatically—nothing stored
Setup
During wraps email init, you'll be asked for your Vercel team slug and project name. These configure the OIDC trust relationship so your deployments can assume the IAM role without any stored secrets. See our Next.js + Vercel + SES guide for a complete walkthrough.
Connecting Existing SES
Already have SES configured? Wraps can layer on top without touching your existing setup:
wraps email connectThis command scans your existing AWS resources (SES domains, config sets), prompts for which features you want to add, and deploys Wraps resources non-destructively. It never modifies your existing configuration—all new resources are created with the wraps-email- prefix.
Troubleshooting
“AWS credentials not found”
Ensure the AWS CLI is configured by running aws configure. Verify your identity with aws sts get-caller-identity.
“Insufficient permissions”
Your AWS user needs permissions to create IAM roles, SES identities, DynamoDB tables, Lambda functions, SQS queues, and EventBridge rules. Use an admin user for initial setup.
“Domain verification pending”
Add the DKIM CNAME records to your DNS provider. Run wraps email domains verify -d yourdomain.com to check progress. DNS propagation can take up to 72 hours, though it usually completes in minutes. Need help with sandbox approval? See our SES sandbox escape guide.
“OIDC provider already exists”
The Vercel OIDC provider may exist from another project. The CLI handles this gracefully and reuses existing providers—no action needed on your part.
What You're Not Paying For
Traditional email APIs charge you per email sent, plus platform fees, plus storage fees. With Wraps, the model is different:
- You pay AWS directly for sending ($0.10 per 1,000 emails)
- Your data stays in your AWS account
- No vendor lock-in—your infrastructure keeps working even if you stop using Wraps
If you're sending 100,000 emails per month: Resend ~$90/month vs Wraps ~$12 to AWS.
Design Principles
Every CLI decision follows these principles:
Non-Destructive
We never modify your existing AWS resources
Namespaced
All resources prefixed with wraps-email- for easy identification
Fail Fast
Validate early, so you know immediately if something’s wrong
Great UX
Clear output, helpful error messages, suggestions for next steps
Zero Credentials Stored
OIDC authentication only
Continue Learning
Next.js + Vercel + AWS SES Guide
Complete tutorial for Next.js apps with OIDC authentication
Escape AWS SES Sandbox
Get production access on your first try
SES Production Architecture
Dedicated IPs, bounce handling, and scaling patterns
Your DMARC Policy Is Useless
Interactive deep-dive into email authentication
The SPF 10-Lookup Limit
Why your SPF record might be failing silently
Email Tools
Check your domain's email authentication setup
Ready to escape the AWS console?
You'll have production email infrastructure in your AWS account in minutes.

