Official guide to sending email via Amazon SES including sandbox mode and production access. Read →
# DNS TXT record for yourapp.com:
"v=spf1 include:amazonses.com ~all"
# Says: only Amazon SES may send from @yourapp.com
Signs every email. Receiving servers verify with your public key in DNS. Proves email wasn't tampered with in transit. AWS SES generates keys and provides CNAME records to add to DNS.
# DNS TXT record for _dmarc.yourapp.com:
"v=DMARC1; p=quarantine; rua=mailto:dmarc@yourapp.com"
# p=none → monitor only (start here)
# p=quarantine → failed emails go to spam
# p=reject → failed emails are rejected (goal)
npm install @aws-sdk/client-ses
import { SESClient, SendEmailCommand } from "@aws-sdk/client-ses";
const ses = new SESClient({ region: "us-east-1" });
async function sendWelcomeEmail(to, name) {
await ses.send(new SendEmailCommand({
Source: "hello@yourapp.com", // Must be verified in SES
Destination: { ToAddresses: [to] },
Message: {
Subject: { Data: "Welcome to YourApp!" },
Body: {
Html: { Data: "<h1>Welcome!</h1>" },
Text: { Data: "Welcome!" }
}
}
}));
}
New SES accounts can only send to verified email addresses. Request production access in the SES console before launch (approval takes 1-2 business days).
| Service | Cost | Best for |
|---|---|---|
| AWS SES | $0.10/1,000 emails | High volume, already on AWS, cost-sensitive |
| Resend | Free 3k/month, then $20/mo | Developer-friendly, React Email templates |
| SendGrid | Free 100/day, then $19.95/mo | Marketing + transactional combo |
| Postmark | $15/mo for 10k | Best deliverability for transactional |
Use separate sending domains for transactional and marketing emails. A spam complaint on your newsletter shouldn't tank the deliverability of password resets.