At $0.10 per thousand emails, Amazon SES is half the price of its nearest competitor and a twentieth of the price of Mailchimp. What you give up is the hand-holding. SES assumes you know what a DKIM selector is, that you have a plan for bounces, and that you will monitor your own reputation. When SES works it is untouchable; when it doesn't, the failure modes are subtle.
SES sandbox vs production
Every new SES account starts in sandbox mode: you can only send to verified addresses, at a capped rate. To get out of sandbox you file a support request and AWS reviews your use case. This is a good forcing function: if your content or volume plan is marginal, they will say no.
The common mistake: rushing the production-access request. AWS reviews the sample email you attach. If it contains a broken unsubscribe link, missing List-Unsubscribe headers, or a clearly cold-outreach tone, they reject. Fix the message first, then ask for the limit lift.
If your sandbox test messages are already landing in Spam at Gmail, requesting a limit increase won't help — the underlying problem (auth, content, content) scales with you into production. Run a placement test from sandbox first.
What shared-pool placement looks like on SES
SES uses two categories of infrastructure: shared pools (by default, per region) and dedicated IPs (opt-in, per IP, paid). On the shared pool, your placement is a function of the collective behaviour of every SES sender in that region.
Typical SES shared-pool numbers we see in aggregate:
- Gmail: 72–82% Inbox, 8–15% Promotions, 5–15% Spam
- Outlook.com / Microsoft 365: 58–75% Inbox
- Yahoo: 70–80% Inbox
- Mail.ru / Yandex: 30–50% Inbox (highly variable)
Compared with Postmark's vetted transactional pool (85–90% Gmail Inbox) the spread is meaningful. It is also the price you pay for an order of magnitude cheaper sending.
How to request a dedicated IP and when it is worth it
SES dedicated IPs cost $24.95 per month per IP on top of per-message pricing. They solve the noisy-neighbour problem completely — you build and own the reputation. But they need volume to be healthy: below about 20k emails per month a dedicated IP is actually worse than the shared pool, because Gmail treats low-volume-from-a-dedicated-IP as suspicious.
Rule of thumb: if you send >50k emails / month, get a dedicated IP. Between 20k and 50k, use the SES Dedicated IP Pool feature (multiple sending identities sharing a small dedicated pool). Below 20k, stay on the shared pool and fix placement via domain reputation and content.
SES-specific setup quirks
DKIM: EasyDKIM vs BYOD
SES offers two DKIM modes. EasyDKIM (the default) publishes three CNAME records pointing at SES-managed keys; rotation is automatic. BYOD (bring your own DKIM) lets you use your own private key, which matters if you send through multiple providers that must all sign with the same selector. EasyDKIM is the right default for 95% of accounts.
BIMI and VMC
SES supports BIMI if you have p=quarantine or p=reject DMARC, a VMC (verified mark certificate), and a published BIMI TXT record. Gmail will display your brand logo next to the sender name. For ecommerce and B2C senders this gives a measurable open-rate lift; for B2B outreach it is cosmetic.
Easy-setup traps
The SES console's "easy setup" wizard publishes a Route53 record set that works for sending, but it does not publish DMARC. You have to add DMARC manually. A sender who just finished easy-setup and assumes everything is done will fail Gmail's 2024 bulk-sender requirements.
How the free placement test integrates into an SES workflow
- In sandbox: verify the seedbox address list, send one test message to the list through SES.
- Review per-provider placement. Fix any auth failures, content flags, or tracking-domain issues.
- Request production access with the now-clean test message as the attached sample.
- After production: schedule a placement test on the first 500 messages of every new campaign or drip sequence.
// Node.js: test-before-send pattern with SES
import { SESClient, SendEmailCommand } from "@aws-sdk/client-ses";
const ses = new SESClient({ region: "us-east-1" });
async function testBeforeSend(campaign) {
// 1. Send to seedbox list first
const seedList = await fetchSeedList(); // from placement-test API
await ses.send(new SendEmailCommand({
Source: campaign.from,
Destination: { ToAddresses: seedList },
Message: campaign.message,
}));
// 2. Poll placement API for verdict (30-60s later)
const verdict = await fetchVerdict(campaign.id);
// 3. Abort or proceed
if (verdict.gmailInbox < 0.75 || verdict.outlookInbox < 0.65) {
throw new Error("Placement below threshold, aborting campaign");
}
return sendRealCampaign(campaign);
}SES's attraction is linear cost at high volume. If you enter production with Spam rates above 5%, you don't get cheaper email — you get cheaper Spam at scale. The pre-send placement check is the cheapest insurance against that outcome.
GlockApps / Litmus comparison
GlockApps and Litmus both integrate with SES. GlockApps focuses on placement and blocklist monitoring ($79–$399/month). Litmus focuses on rendering across clients ($99–$199/month). They solve partially overlapping problems. For a pre-send placement check on a tight budget, Inbox Check covers the same 20+ provider seedbox the paid tools use, plus SpamAssassin and Rspamd scoring, for free. It does not cover Litmus-style rendering previews.