AWS SES (Email)
SES v2 used for outbound email and domain identity management. Event notifications arrive via SNS.
Client
src/lib/providers/email.ts:
import { SESv2Client, SendEmailCommand } from "@aws-sdk/client-sesv2";
const ses = new SESv2Client({
region: process.env.AWS_REGION || "us-east-1",
credentials: { accessKeyId: ..., secretAccessKey: ... },
});
Same client singleton reused in src/lib/providers/domain.ts for identity management.
Sending
sendEmail() issues SendEmailCommand with:
FromEmailAddress: params.from,
Destination: { ToAddresses: params.to },
Content: { Simple: { Subject, Body: { Html?, Text? } } }
Returns { providerMessageId, providerResponse } with MessageId and SDK requestId.
Domain identity
src/lib/providers/domain.ts:
| Function | SES command | Purpose |
|---|---|---|
createDomainIdentity(domain) |
CreateEmailIdentityCommand |
Returns DKIM tokens |
checkDomainStatus(domain) |
GetEmailIdentityCommand |
Reads VerifiedForSendingStatus + DKIM status |
deleteDomainIdentity(domain) |
DeleteEmailIdentityCommand |
Removes identity |
Inbound event notifications
SES publishes events (Delivery, Bounce, Complaint, Reject) to a configured SNS topic. Configure that SNS topic to HTTP-subscribe to https://<host>/api/webhooks/ses.
Handler: src/app/api/webhooks/ses/route.ts.
Flow:
- SNS sends
SubscriptionConfirmation— handler fetchesSubscribeURLto confirm. - SNS sends
NotificationwithMessage= JSON-stringified SES event. - Extract
mail.messageId— match tomessages.provider_message_id. - Update status accordingly, fan out to customer webhooks.
Setup (AWS side)
Outside this repo:
- Create SES configuration set with event destination → SNS.
- Configure SNS topic with HTTPS subscription to
/api/webhooks/ses. - Move SES account out of sandbox for production (AWS request).
Security gap
The SES webhook route does not verify SNS signatures — an attacker posting crafted JSON could mutate message statuses. Before production, implement SNSMessageValidator (see AWS docs).