The Production SES Stack
Amazon SES is deceptively simple to start with—verify a domain, call the API, emails flow. But production deployments need supporting infrastructure: EventBridge routes events, SQS ensures durability, Lambda processes data, and CloudWatch monitors health. Without these, you're flying blind when deliverability drops.
Here's what a production-ready SES architecture looks like—and what Wraps deploys to your AWS account:
Production SES Architecture (What Wraps Deploys)
Your application sends through SES using the @wraps.dev/email SDK, which routes emails through your configured IP pool. All 10 SES event types flow to EventBridge for processing, enabling real-time tracking and reputation monitoring. The configuration set wraps-email-tracking ties it all together.
wraps email init) deploys this entire architecture to your AWS account: IAM roles with OIDC authentication, SES configuration set with all 10 event types, EventBridge rules, SQS queues with DLQ, Lambda processor, and DynamoDB for event history. All tagged with ManagedBy: wraps-cli.Before you start: Make sure your domain has proper email authentication configured. Check your DMARC policy and verify your DNS records are correct before deploying production infrastructure.
Dedicated IPs: When & Why
SES offers three IP strategies with distinct economics. Shared IPs work for most startups, but high-volume senders need dedicated IPs to isolate their reputation. On shared IPs, if another sender gets flagged for spam, your deliverability suffers too—even if you did nothing wrong.
| Strategy | Cost | Best For | Warmup Required |
|---|---|---|---|
| Shared IPs | Free | <100K emails/day, variable volume | None |
| Dedicated Standard | $24.95/IP/month | Consistent high volume | 45 days auto-warmup |
| Dedicated Managed | $15/mo + tiered | Variable volume, multiple ISPs | Automatic per-ISP |
See our pricing page for full cost breakdowns including Wraps platform features.
Warming Schedule
Standard dedicated IPs warm automatically over 45 days. Here's the typical progression:
| Week | Daily Volume per ISP | Total Daily |
|---|---|---|
| Week 1 | 50-200 | ~1,000 |
| Week 2 | 200-1,000 | ~4,000 |
| Week 3 | 1,000-5,000 | ~20,000 |
| Week 4 | 5,000-20,000 | ~80,000 |
| Week 5-6 | 20,000-50,000 | ~200,000 |
Configuration Set Architecture
Configuration sets let you separate email types so they don't affect each other's reputation. A promotional campaign with high unsubscribes won't hurt your password reset deliverability. Each set controls its own event tracking, IP routing, and suppression behavior. Large deployments use 3-6 configuration sets for different email types.
Configuration Set → IP Pool Mapping
wraps-email-tracking that captures all 10 event types. It includes: EventBridge destination for event routing, bounce & complaint suppression at the config set level, optional TLS enforcement, and optional custom tracking domain for branded click/open tracking URLs.├── wraps-email-tracking # Wraps default config set
│ └── Event Destination: EventBridge (all 10 event types)
│ └── Suppression: Bounces + Complaints (config set level)
│ └── TLS: Required (optional)
│ └── Tracking Domain: track.yourdomain.com (optional)
│
# For advanced use cases, you can create additional sets:
├── transactional-critical # Password resets, 2FA codes
│ └── IP Pool: dedicated-transactional
│
└── marketing-campaigns # Newsletters, promotions
└── IP Pool: dedicated-marketingEvent Processing Pipeline
AWS pauses sending at 10% bounce rate or 0.5% complaint rate. Cross these thresholds and your account goes under review—emails stop flowing while you scramble to fix it. A robust event processing pipeline catches problems early through real-time analysis and automatic suppression.
Event Processing Pipeline (Wraps Architecture)
| Metric | Target | Warning Alert | Critical Alert | AWS Review |
|---|---|---|---|---|
| Bounce Rate | <2% | 2% | 4% | 5% |
| Complaint Rate | <0.05% | 0.05% | 0.08% | 0.1% |
How Wraps Processes Events
The Lambda processor receives batches of 10 events from SQS, parses the EventBridge envelope, and stores normalized data in DynamoDB. Here's the key processing logic:
// Wraps Lambda Event Processor (simplified)
export async function handler(event) {
const results = [];
for (const record of event.Records) {
try {
const eventBridgeEvent = JSON.parse(record.body);
const sesEvent = eventBridgeEvent.detail;
// Extract common fields
const messageId = sesEvent.mail.messageId;
const eventType = sesEvent.eventType;
const timestamp = new Date(sesEvent.mail.timestamp).getTime();
// Normalize event data based on type
const eventData = {
messageId,
sentAt: timestamp,
accountId: process.env.AWS_ACCOUNT_ID,
from: sesEvent.mail.source,
to: sesEvent.mail.destination,
subject: sesEvent.mail.commonHeaders?.subject,
eventType: normalizeEventType(sesEvent),
eventData: sesEvent,
expiresAt: computeTTL(timestamp, RETENTION_DAYS),
};
await dynamodb.put({
TableName: 'wraps-email-history',
Item: eventData,
});
results.push({ itemIdentifier: record.messageId });
} catch (error) {
// Failed items go to DLQ after 3 retries
console.error('Failed to process:', error);
}
}
return { batchItemFailures: results };
}Rate Limiting Architecture
SES quotas use rolling 24-hour windows—your limit resets continuously, not at midnight. Default production quotas start around 50,000 emails/day and 14 emails/second. Without a buffer, a sudden spike in signups exhausts your quota and delays critical emails like password resets. Queue-based architectures absorb bursts so SES processes them at a sustainable rate.
Queue-Based Rate Limiting
SQS + Lambda Configuration
functions:
emailSender:
handler: sender.handler
reservedConcurrency: 5 # SES rate / batch size / safety factor
events:
- sqs:
arn: !GetAtt EmailQueue.Arn
batchSize: 10
functionResponseTypes:
- ReportBatchItemFailures
resources:
Resources:
EmailQueue:
Type: AWS::SQS::Queue
Properties:
VisibilityTimeout: 180 # 6x Lambda timeout
MessageRetentionPeriod: 1209600 # 14 days
RedrivePolicy:
deadLetterTargetArn: !GetAtt EmailDLQ.Arn
maxReceiveCount: 5reservedConcurrency to (14 / 10) * 0.8 ≈ 1-2. The 0.8 factor prevents hitting limits during retry bursts.CloudWatch Monitoring
Essential alarms catch reputation problems before AWS intervenes. These Terraform configurations create early-warning alerts:
resource "aws_cloudwatch_metric_alarm" "ses_bounce_rate" {
alarm_name = "ses-bounce-rate-warning"
comparison_operator = "GreaterThanOrEqualToThreshold"
evaluation_periods = 1
metric_name = "Reputation.BounceRate"
namespace = "AWS/SES"
period = 300
statistic = "Maximum"
threshold = 0.02 # 2% - warns before AWS review (5%)
alarm_actions = [aws_sns_topic.alerts.arn]
treat_missing_data = "notBreaching"
}
resource "aws_cloudwatch_metric_alarm" "ses_complaint_rate" {
alarm_name = "ses-complaint-rate-warning"
comparison_operator = "GreaterThanOrEqualToThreshold"
evaluation_periods = 1
metric_name = "Reputation.ComplaintRate"
namespace = "AWS/SES"
period = 300
statistic = "Maximum"
threshold = 0.0005 # 0.05% - warns before AWS (0.1%) and Gmail (0.3%)
alarm_actions = [aws_sns_topic.alerts.arn]
treat_missing_data = "notBreaching"
}wraps email upgrade → "Enable reputation alerts". Wraps deploys 5 CloudWatch alarms with thresholds that warn before AWS takes action: bounce rate at 2%/4% (vs AWS 5%/10%), complaint rate at 0.05%/0.08% (vs AWS 0.1%/0.5%), plus DLQ monitoring. You'll get email notifications when your reputation needs attention.Dashboard Metrics
| Widget | Metrics | Purpose |
|---|---|---|
| Reputation | BounceRate, ComplaintRate | Account health at a glance |
| Delivery Funnel | Send, Delivery, Bounce, Complaint | Conversion through stages |
| Throughput | Send rate over time | Detect throttling patterns |
| ISP Breakdown | VDM metrics by domain | Per-provider performance |
Common Mistakes That Kill Deliverability
These mistakes can wreck months of careful reputation building. We've seen them tank otherwise healthy sender accounts:
Related: Why your DMARC policy is useless covers SPF/DKIM alignment in detail, and our SPF configuration guide explains the include mechanism.
Missing Custom MAIL FROM
SPF alignment fails without it, causing DMARC failures even with valid SPF records. See our DMARC guide for proper alignment.
Testing with real addresses
Use bounce@simulator.amazonses.com for testing—real bounces hurt your reputation. Learn proper testing in our sandbox guide.
Ignoring soft bounces
Repeatedly sending to soft-bouncing addresses signals poor list hygiene to ISPs.
Sudden volume spikes
ISPs interpret sudden increases as spam behavior. Scale gradually—doubling overnight is a red flag.
Region confusion
SES credentials, quotas, and domains are region-specific. Verified in us-east-1 ≠ verified in eu-west-1.
Continue Learning
AWS SES Sandbox Exit Guide
Step-by-step guide to getting production access with proper DNS configuration.
Fix Your DMARC Policy
Most DMARC policies don't protect you. Learn what actually works.
Wraps Platform Dashboard
Monitor deliverability, track events, and manage your email infrastructure.
Domain Verification Guide
Configure DKIM, SPF, and DMARC records for your sending domain.
Skip the infrastructure headaches
wraps email init deploys 7 AWS resources to your account: IAM roles, SES configuration, EventBridge rules, SQS queues, Lambda processor, and DynamoDB storage. All wired together and ready to send.
You own everything—no vendor lock-in. Pay only AWS pricing (~$0.10 per 1,000 emails). Don't like it? wraps email destroy removes everything cleanly.
You'll need: AWS credentials and a verified domain. That's it.

