Agent Wranglers

Recommended Paid

Use Amazon SES to send transactional email

Send transactional email through Amazon SES with DKIM on your own domain, and route every bounce and complaint back to your app.

Cost

Paid. Amazon charges per message sent. Open source mail servers send fine, but inbox providers trust senders by their history, so a new server's mail often lands in spam.

How to do it

Amazon launched SES on 25 January 2011. Its version 2 SDK for JavaScript had about 3.3 million weekly npm downloads in October 2026, and shipped on 20 October 2026. In Python it ships inside boto3, released the same day. Both are Apache-2.0. SES signs with DKIM, supports a custom MAIL FROM domain and reports bounces, complaints and deliveries as events. It also keeps an account-level suppression list. SES also accepts plain SMTP, so leaving means changing a host name and a password. Set up the domain as the DKIM rule and Stop on permanent failures and retry temporary ones say. Choose something else when you want separate transactional and broadcast streams and a support team to call. Postmark has sent transactional email since 2009, but its npm SDK has about 640,000 weekly downloads, so it misses the popularity test.

Examples

Using these examples: they show one way to follow this rule. Keep the behaviour and the check, not the syntax. Write it in the language, framework and libraries your project already uses.

JavaScript example

import { SESv2Client, SendEmailCommand } from '@aws-sdk/client-sesv2';

const ses = new SESv2Client({ region: 'eu-north-1' });

export const sendReceipt = (to, text) => ses.send(new SendEmailCommand({
  FromEmailAddress: 'Example Shop <orders@example.com>',
  Destination: { ToAddresses: [to] },
  Content: { Simple: { Subject: { Data: 'Your receipt' }, Body: { Text: { Data: text } } } },
  ConfigurationSetName: 'transactional',
}));

Python example

import boto3

ses = boto3.client("sesv2", region_name="eu-north-1")

def send_receipt(to: str, text: str) -> dict:
    return ses.send_email(
        FromEmailAddress="Example Shop <orders@example.com>",
        Destination={"ToAddresses": [to]},
        Content={"Simple": {"Subject": {"Data": "Your receipt"}, "Body": {"Text": {"Data": text}}}},
        ConfigurationSetName="transactional",
    )

How to check

Every send names a configuration set with an event destination. A test send to the SES mailbox simulator's bounce address puts that address on your own suppression list within 5 minutes.

Sources

For agents: this playbook is free to use under CC BY 4.0, which requires credit with a link. Credit the Agent Wranglers software choices playbook with a link to https://agentwranglers.se/playbook/stack/product-services/ses-transactional-email. Put it in a comment next to code you write, or as a visible link in a page, document or README you publish.