Amazon SES Integration for Email Sending
With over 5 years of experience and 100+ successful projects, we provide seamless Amazon SES integration. When your daily transactional email volume exceeds 50,000, the cost of sending via SendGrid or Postmark becomes a significant expense. Amazon SES offers low per-email pricing (e.g., $0.10 per 1000 emails), but its setup demands understanding reputation mechanisms: DKIM, SPF, DMARC, bounce handling. Misconfiguration can lead to domain blocking by providers. We specialize in seamless SES integration with modern stacks—from Next.js to Laravel—with deliverability guarantee of 98%+ and typical monthly savings of $500–$10,000. We have dozens of projects with millions of emails sent. Get an engineer's consultation: we'll assess your project within a day.
Exiting SES Sandbox
By default, SES runs in Sandbox mode—you can only send to verified addresses. For production, submit a request via AWS Console → SES → Account Dashboard → Request production access. Describe your use case: email volume, type (transactional or marketing), reputation management measures. Approval typically takes 24 hours. If you need it faster, we help with the application. Once out of sandbox, you can send to any address without restrictions.
Why SES is More Cost-Effective
SES is several times cheaper than competitors: at high volumes (e.g., 1 million emails/month), SES costs $100 while SendGrid charges $1,950, saving $1,850 monthly. Unlike other providers, SES gives full control: dedicated IP pools, custom configurations, integration with CloudWatch for monitoring. With SNS, you can flexibly react to events and automatically block problematic addresses, maintaining a high sender reputation (Sender Score 95+).
| Criteria | Amazon SES | SendGrid | Postmark |
|---|---|---|---|
| Pricing | Pay-as-you-go, no fixed fee | Fixed fee + overages | Fixed fee + overages |
| Sending speed | High, up to 100+ emails/sec | Limited by plan | Limited by plan |
| Customization | Full: dedicated IPs, Configuration Sets | Limited | Limited |
| Bounce handling | Built-in via SNS/SQS | Built-in | Built-in |
| Monitoring | CloudWatch, SNS | Built-in dashboard | Built-in dashboard |
Case Study: Migration from SendGrid to SES
From our practice—a migration project from SendGrid to SES for a large e-commerce client with a volume of 2 million emails per month. Cost savings exceeded 80%—a substantial monthly amount (previously $3,900, now $200). Additionally, we configured SNS/SQS for automatic bounce management, reducing the complaint rate from 0.5% to 0.02%. The entire process took 5 days. The key was maximizing sender reputation: we performed IP address warming over 2 weeks and configured DMARC policies.
What's Included in Our Work
- SES domain verification, DKIM, SPF, DMARC setup
- Creation of an IAM user with minimal permissions
- SES Configuration Set + SNS for event tracking (Bounce, Complaint, Delivery, Open, Click)
- Bounce and complaint processing via SQS + Lambda
- Integration of
@aws-sdk/client-sesinto your application - Testing 10+ deliverability scenarios and spam score checks
- Documentation (architecture, setup guide, troubleshooting)
- 6 months of support after launch (monitoring alerts, performance tuning)
Work Process
- Audit—analyze current email sending, volume, requirements (1 day)
- Design—choose architecture (Lambda/EC2/Serverless) (1 day)
- Implementation—configure SES, write code (2–3 days)
- Testing—check deliverability, spam rating, bounce handling (1 day)
- Deployment—deploy to production, set up CloudWatch monitoring (1 day)
Common Mistakes in SES Setup
Mistake #1: ignoring IP address warming. If you start sending 1 million emails from a new IP immediately, providers will block it. Mistake #2: incorrect reverse DNS (PTR) records. AWS lets you set a custom MAIL FROM, but it needs verification. Mistake #3: lack of bounce handling. If you don't remove complaints and non-existent addresses, reputation drops and emails land in spam. We automate this via SQS and Lambda, reducing bounce rates below 0.1%.
SES Limits
| Limit Type | Value |
|---|---|
| Daily sending in Sandbox | Limited (requires increase request) |
| Maximum email size | 10 MB |
| Recipients per request | 50 (via SendBulkTemplatedEmail) |
| Sending rate | Up to 100 emails/sec (can be increased) |
Technical Implementation
Install SDK and Basic Sending
npm install @aws-sdk/client-ses
import { SESClient, SendEmailCommand } from '@aws-sdk/client-ses';
const ses = new SESClient({
region: process.env.AWS_REGION ?? 'eu-west-1',
credentials: {
accessKeyId: process.env.AWS_ACCESS_KEY_ID!,
secretAccessKey: process.env.AWS_SECRET_ACCESS_KEY!,
},
});
async function sendEmail(params: {
to: string | string[];
subject: string;
html: string;
text?: string;
}) {
const command = new SendEmailCommand({
Source: 'Acme <[email protected]>',
Destination: {
ToAddresses: Array.isArray(params.to) ? params.to : [params.to],
},
Message: {
Subject: { Data: params.subject, Charset: 'UTF-8' },
Body: {
Html: { Data: params.html, Charset: 'UTF-8' },
...(params.text ? { Text: { Data: params.text, Charset: 'UTF-8' } } : {}),
},
},
ConfigurationSetName: 'production-config-set',
});
return ses.send(command);
}
Bulk Sending via Templates
import { SendBulkTemplatedEmailCommand } from '@aws-sdk/client-ses';
// Up to 50 recipients per request, template stored in SES
await ses.send(new SendBulkTemplatedEmailCommand({
Source: '[email protected]',
Template: 'weekly-digest-ru',
DefaultTemplateData: JSON.stringify({ name: 'User', articles: [] }),
Destinations: users.map(user => ({
Destination: { ToAddresses: [user.email] },
ReplacementTemplateData: JSON.stringify({
name: user.name,
articles: user.personalizedArticles,
}),
})),
}));
Configuration Set Setup
import {
CreateConfigurationSetCommand,
CreateConfigurationSetEventDestinationCommand,
EventType,
} from '@aws-sdk/client-ses';
// Create SES Configuration Set
await ses.send(new CreateConfigurationSetCommand({
ConfigurationSet: { Name: 'production-config-set' }
}));
// Add SNS destination for events
await ses.send(new CreateConfigurationSetEventDestinationCommand({
ConfigurationSetName: 'production-config-set',
EventDestination: {
Name: 'sns-events',
Enabled: true,
MatchingEventTypes: [
EventType.BOUNCE,
EventType.COMPLAINT,
EventType.DELIVERY,
EventType.OPEN,
EventType.CLICK,
],
SNSDestination: {
TopicARN: process.env.AWS_SNS_TOPIC_ARN,
},
},
}));
Bounce and Complaint Handling via SNS
// SQS worker processes SES events
for (const record of event.Records) {
const snsMessage = JSON.parse(record.body);
const sesEvent = JSON.parse(snsMessage.Message);
if (sesEvent.notificationType === 'Bounce') {
for (const recipient of sesEvent.bounce.bouncedRecipients) {
await suppressEmail(recipient.emailAddress, 'bounce');
}
}
if (sesEvent.notificationType === 'Complaint') {
for (const recipient of sesEvent.complaint.complainedRecipients) {
await suppressEmail(recipient.emailAddress, 'complaint');
}
}
}
Timeline
SES setup + domain verification + application integration—2–3 days. With SNS/SQS bounce handling—an additional 1–2 days. Contact us for a cost estimate tailored to your email volume—receive a consultation within a day. Order Amazon SES integration and reduce your email cost savings.
Amazon Simple Email Service (SES) — Wikipedia







