Skip to content

SES

Amazon Simple Email Service v2 for sending transactional and marketing emails.

Configuration

PropertyValue
ProtocolRestJson1
Signing Nameses
API Versionv2
PersistenceNo

SES v2 uses REST-style routing with JSON bodies. All paths are under /v2/email/....

Quick Start

Verify a sender identity and send an email:

bash
# Create (verify) a sender identity
curl -s -X POST http://localhost:4566/v2/email/identities \
  -H "Content-Type: application/json" \
  -H "Authorization: AWS4-HMAC-SHA256 Credential=test/20260421/us-east-1/ses/aws4_request, SignedHeaders=host, Signature=fake" \
  -d '{"EmailIdentity":"[email protected]","Tags":[]}'

# Send an email
curl -s -X POST http://localhost:4566/v2/email/outbound-emails \
  -H "Content-Type: application/json" \
  -H "Authorization: AWS4-HMAC-SHA256 Credential=test/20260421/us-east-1/ses/aws4_request, SignedHeaders=host, Signature=fake" \
  -d '{
    "FromEmailAddress": "[email protected]",
    "Destination": {"ToAddresses": ["[email protected]"], "CcAddresses": [], "BccAddresses": []},
    "Content": {
      "Simple": {
        "Subject": {"Data": "Hello from AWSim!"},
        "Body": {
          "Text": {"Data": "This is a plain text email."},
          "Html": {"Data": "<h1>Hello!</h1><p>This is an HTML email.</p>"}
        }
      }
    }
  }'

Operations

Emails

  • SendEmail — send an email to one or more recipients
    • Path: POST /v2/email/outbound-emails
    • Input:
      • FromEmailAddress (required, must be a verified identity)
      • Destination: {ToAddresses, CcAddresses, BccAddresses} (lists of email addresses)
      • Content: one of:
        • Simple: {Subject: {Data}, Body: {Text: {Data}, Html: {Data}}}
        • Template: {TemplateName, TemplateData} (JSON string with substitution variables)
        • Raw: {Data} (base64-encoded raw MIME message)
      • Optional: ReplyToAddresses, FeedbackForwardingEmailAddress, EmailTags (list of {Name, Value})
    • Returns: MessageId

Identities

  • CreateEmailIdentity — register a domain or email address as a verified sender identity

    • Path: POST /v2/email/identities
    • Input: EmailIdentity (email address or domain name), optional Tags
    • Returns: IdentityType (EMAIL_ADDRESS or DOMAIN), VerifiedForSendingStatus (true in AWSim), DkimAttributes
  • GetEmailIdentity — get details of a verified identity

    • Path: GET /v2/email/identities/{EmailIdentity}
    • Returns: IdentityType, VerifiedForSendingStatus, DkimAttributes, Tags
  • ListEmailIdentities — list all verified sender identities

    • Path: GET /v2/email/identities
    • Returns: paginated EmailIdentities list with IdentityName, IdentityType, SendingEnabled
  • DeleteEmailIdentity — remove a verified identity

    • Path: DELETE /v2/email/identities/{EmailIdentity}

Templates

  • CreateEmailTemplate — create a reusable email template with variable substitution

    • Path: POST /v2/email/templates
    • Input: TemplateName, TemplateContent with Subject, Text, Html (use for substitutions)
  • GetEmailTemplate — get a template by name

    • Path: GET /v2/email/templates/{TemplateName}
  • ListEmailTemplates — list all email templates

    • Path: GET /v2/email/templates
  • DeleteEmailTemplate — delete a template

    • Path: DELETE /v2/email/templates/{TemplateName}

Account

  • GetAccount — get account-level sending details and limits
    • Path: GET /v2/email/account
    • Returns: SendingEnabled: true, SendQuota (Max24HourSend, MaxSendRate, SentLast24Hours), ProductionAccessEnabled

Curl Examples

bash
# 1. Verify a domain identity
curl -s -X POST http://localhost:4566/v2/email/identities \
  -H "Content-Type: application/json" \
  -H "Authorization: AWS4-HMAC-SHA256 Credential=test/20260421/us-east-1/ses/aws4_request, SignedHeaders=host, Signature=fake" \
  -d '{"EmailIdentity":"example.com"}'

# 2. List all verified identities
curl -s http://localhost:4566/v2/email/identities \
  -H "Authorization: AWS4-HMAC-SHA256 Credential=test/20260421/us-east-1/ses/aws4_request, SignedHeaders=host, Signature=fake"

# 3. Create an email template
curl -s -X POST http://localhost:4566/v2/email/templates \
  -H "Content-Type: application/json" \
  -H "Authorization: AWS4-HMAC-SHA256 Credential=test/20260421/us-east-1/ses/aws4_request, SignedHeaders=host, Signature=fake" \
  -d '{
    "TemplateName": "welcome-email",
    "TemplateContent": {
      "Subject": "Welcome, {{name}}!",
      "Text": "Hi {{name}}, welcome to {{company}}. Your account is ready.",
      "Html": "<h1>Welcome, {{name}}!</h1><p>Hi {{name}}, welcome to <strong>{{company}}</strong>.</p>"
    }
  }'

# 4. Send using a template
curl -s -X POST http://localhost:4566/v2/email/outbound-emails \
  -H "Content-Type: application/json" \
  -H "Authorization: AWS4-HMAC-SHA256 Credential=test/20260421/us-east-1/ses/aws4_request, SignedHeaders=host, Signature=fake" \
  -d '{
    "FromEmailAddress": "[email protected]",
    "Destination": {"ToAddresses": ["[email protected]"]},
    "Content": {
      "Template": {
        "TemplateName": "welcome-email",
        "TemplateData": "{\"name\":\"Alice\",\"company\":\"Acme Corp\"}"
      }
    }
  }'

SDK Example

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

const ses = new SESv2Client({
  region: 'us-east-1',
  endpoint: 'http://localhost:4566',
  credentials: { accessKeyId: 'test', secretAccessKey: 'test' },
});

// Verify sender identity
await ses.send(new CreateEmailIdentityCommand({
  EmailIdentity: '[email protected]',
}));

// Send a simple email
const { MessageId } = await ses.send(new SendEmailCommand({
  FromEmailAddress: '[email protected]',
  Destination: {
    ToAddresses: ['[email protected]'],
    CcAddresses: ['[email protected]'],
  },
  Content: {
    Simple: {
      Subject: { Data: 'Order Confirmation #12345', Charset: 'UTF-8' },
      Body: {
        Text: { Data: 'Your order has been confirmed. Thank you for shopping!', Charset: 'UTF-8' },
        Html: {
          Data: '<h2>Order Confirmed</h2><p>Your order #12345 has been confirmed. Thank you!</p>',
          Charset: 'UTF-8',
        },
      },
    },
  },
  EmailTags: [
    { Name: 'category', Value: 'transactional' },
    { Name: 'order_id', Value: '12345' },
  ],
}));

console.log('Message ID:', MessageId);

// Create a template for repeated use
await ses.send(new CreateEmailTemplateCommand({
  TemplateName: 'password-reset',
  TemplateContent: {
    Subject: 'Reset your password',
    Text: 'Click this link to reset your password: {{resetLink}}',
    Html: '<p>Click <a href="{{resetLink}}">here</a> to reset your password. Link expires in {{expiryMinutes}} minutes.</p>',
  },
}));

// Check account sending quotas
const account = await ses.send(new GetAccountCommand({}));
console.log('Daily sending limit:', account.SendQuota?.Max24HourSend);
console.log('Sent in last 24h:', account.SendQuota?.SentLast24Hours);

Outbox

Awsim captures every outbound email — SendEmail, SendBulkEmail, SendCustomVerificationEmail — into a SQLite store so you can inspect what was actually sent without parsing the SDK call.

UI: open /ses and switch to the Outbox tab (default). Lists every captured message newest-first, with a search box that filters by subject / from / recipient. Click a row to expand the body — picks the best view automatically (Text → HTML in a sandboxed iframe → Raw). The dialog shows message ID, full To / Cc / Bcc, account, region, and timestamp.

Admin endpoint:

bash
# All captured emails, newest first
curl http://localhost:4566/_awsim/ses/sent | jq .

# Scope to one account / region
curl 'http://localhost:4566/_awsim/ses/sent?account=000000000000&region=us-east-1'

Returns { count, emails: [...] }; each email has messageId, from, to, cc, bcc, subject, bodyText, bodyHtml, raw, sentAt, account, region.

Persistence + retention

  • With --data-dir, the outbox lives in {data-dir}/ses.db and survives restarts. Without it, an ephemeral tempdir holds the DB and is cleaned up on shutdown.
  • An hourly background sweep deletes emails older than --ses-retention-hours (default 720h / 30 days). Set to 0 to disable.

Behavior Notes

  • SES uses the REST/JSON v2 API (/v2/email/... paths), not the legacy form-encoded ses protocol.
  • Emails are accepted, recorded into the Outbox, and not actually delivered — no SMTP connection is made.
  • Identity verification status is set to SUCCESS immediately without DNS verification or email confirmation.
  • Template variable substitution () is stored but not rendered during send in the current implementation.
  • MessageId is returned as a UUID for each sent email.
  • GetAccount always reports SendingEnabled: true and generous quota limits.
  • Outbound emails are persisted in SQLite (see Outbox). All other state (identities, templates, contact lists, suppression list) is in-memory only and lost on restart.

Released under MIT / Apache-2.0 License