Skip to content
Docs

Guide

Move from Amazon SES to Emailit. Map identities, sandbox and quotas, replace SDK calls and SMTP credentials, and turn SNS events into signed webhooks.

Updated Oct 1, 2026

This guide maps Amazon SES concepts, API calls, event notifications, suppressions and templates to their Emailit equivalents. Read Migrate to Emailit first for the overall order and how to run both providers in parallel.

Concepts

Amazon SES Emailit
AWS account in a region Workspace
Verified identities: domains and email addresses Sending domains. Single email address identities aren’t available.
Easy DKIM CNAME records One DKIM TXT record, emailit._domainkey
Custom MAIL FROM domain The return path emailit.<your domain>, which every domain has
Sandbox and production access request Sandbox mode and production access. In sandbox mode you can send to workspace members’ account emails.
Sending quota and maximum send rate Sending limits: emails per second and per day, reset at midnight UTC
IAM credentials and SigV4 signing API keys in an Authorization: Bearer header
SMTP credentials Your API key, used as the SMTP password
Configuration sets and event destinations (SNS, EventBridge, Firehose) Webhooks that post signed JSON to your HTTPS endpoint
Account-level suppression list Workspace suppression list
Email templates Templates with an alias and versions
Receipt rules Inbound email with the email.received webhook
Email tags meta
Dedicated IPs Dedicated IPs on request
Contact lists Contacts, audiences and campaigns

Update your API calls

SES calls are signed with your AWS credentials, so you usually make them through an AWS SDK. With Emailit, you send a JSON request with an API key, or use the Emailit SDK for your language. In Node.js:

Before: Amazon SES (AWS SDK v3)
import { SESv2Client, SendEmailCommand } from '@aws-sdk/client-sesv2';

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

await ses.send(new SendEmailCommand({
  FromEmailAddress: 'Acme <hello@acme.com>',
  Destination: { ToAddresses: ['ada@example.com'] },
  Content: {
    Simple: {
      Subject: { Data: 'Your receipt' },
      Body: {
        Text: { Data: 'Thanks for your order.' },
        Html: { Data: '<p>Thanks for your order.</p>' },
      },
    },
  },
}));
After: Emailit
import { Emailit } from '@emailit/node';

const emailit = new Emailit(process.env.EMAILIT_API_KEY);

await emailit.emails.send({
  from: 'Acme <hello@acme.com>',
  to: 'ada@example.com',
  subject: 'Your receipt',
  text: 'Thanks for your order.',
  html: '<p>Thanks for your order.</p>',
});
Amazon SES (API v2 SendEmail) Emailit (POST /v2/emails)
AWS credentials and SigV4 signature Authorization: Bearer secret_…
FromEmailAddress from
Destination.ToAddresses, CcAddresses, BccAddresses to, cc, bcc, up to 50 each
ReplyToAddresses reply_to
Content.Simple.Subject.Data subject
Content.Simple.Body.Html.Data, Text.Data html, text
Content.Template.TemplateName template, an alias or ID
Content.Template.TemplateData (a JSON string) variables (a JSON object)
Content.Raw (a complete MIME message) Send the MIME message through the SMTP relay, or rebuild it with html, text and attachments
EmailTags meta, returned in webhook events
ConfigurationSetName Not needed. Events go to your webhooks, and tracking is set per domain or per email with tracking.
Response MessageId 200 with id (em_…), message_id, status: "accepted" and ids per recipient

Emailit also supports scheduling with scheduled_at and safe retries with an Idempotency-Key header, which SES doesn’t offer on send. See Send an email.

Switch SMTP settings

Setting Amazon SES Emailit
Host email-smtp.<region>.amazonaws.com smtp.emailit.com
Port 587, 2587 or 25 (STARTTLS), 465 or 2465 (TLS) 587, 2587, 2525 or 25 (STARTTLS), 465 (TLS)
Username Your SES SMTP user name emailit
Password Your SES SMTP password Your Emailit API key

Emailit doesn’t read SES headers such as X-SES-CONFIGURATION-SET. Remove them. See SMTP settings.

Map event notifications

SES publishes events through configuration sets to SNS, EventBridge or Firehose. Emailit sends them directly to your HTTPS endpoint as webhooks, so there’s no topic to subscribe to or confirm.

SES event type Emailit event
Send email.accepted (API only)
Delivery email.delivered
DeliveryDelay email.attempted
Bounce with bounceType Permanent email.bounced
Bounce with bounceType Transient email.attempted while Emailit retries, then email.bounced if every retry fails
Complaint email.complained
Open email.loaded
Click email.clicked
Subscription email.unsubscribed, for campaign email only
Reject, Rendering Failure No direct equivalent. Errors in the request, such as a missing template, are returned by the API right away, and messages Emailit won’t deliver get the status held.
Receipt rule with an SNS or Lambda action email.received, then fetch the content with GET /emails/{id}

The payload changes too:

  • Each Emailit request is a JSON array of up to 100 events, with the name in type and the email in data.object.
  • Use data.object.id, the em_ ID from the send response, instead of the SES messageId. Your meta values are in data.object.meta.
  • Instead of checking SNS message signatures, verify X-Emailit-Signature against X-Emailit-Timestamp and your whsec_ secret. See Request signature.
JavaScript
for (const event of req.body) {
  const email = event.data.object;
  if (event.type === 'email.bounced') markBounced(email.to, email.id);
  if (event.type === 'email.complained') unsubscribe(email.to);
}

Move suppressions

  1. Export the SES account-level suppression list with the AWS CLI. If the output includes a NextToken, repeat the command with --next-token until you have every page.

    Terminal
    aws sesv2 list-suppressed-destinations --output json \
      | jq -r '(["email","type","reason"] | @csv),
               (.SuppressedDestinationSummaries[] | [.EmailAddress, "recipient", ("ses " + .Reason)] | @csv)' \
      > suppressions.csv

    This writes a CSV with the columns email,type,reason. Every row uses the type recipient, which blocks API, SMTP and campaign sends to the address.

  2. If you keep your own list of bounces and complaints from SNS notifications, add those addresses too.

  3. In Email APISuppressions, select Import and upload the file. Each file can have up to 10,000 rows and can be at most 8 MB. Duplicates are skipped.

See Manage suppressions.

Move templates

Get each template with aws sesv2 get-email-template --template-name <name>, then import its HTML in Email MarketingTemplates or create it with the Templates API. Use the SES template name as the Emailit alias, if it fits the alias format of lowercase letters, numbers, - and _.

SES templates use Handlebars-style tags. Temple covers the common parts:

Amazon SES Emailit (Temple)
{{name}}, {{user.name}} The same
{{#if plan}}…{{else}}…{{/if}} The same
{{#each items}}…{{/each}} Not supported. Render the list in your code and pass it as one variable.
TemplateData as a JSON string variables as a JSON object
No built-in default {{name|"there"}} adds a fallback

Temple never escapes HTML, so escape user input before you pass it. See Temple.

Change DNS

Add your domain in Email APIDomains and publish the Emailit records. They use their own names (emailit._domainkey, emailit.<domain>, and optionally go and inbound), so they don’t conflict with the SES Easy DKIM CNAMEs or a custom MAIL FROM subdomain. Keep your DMARC record. See DNS records.

After the cutover, remove the SES DKIM CNAMEs and the custom MAIL FROM records, and delete the identities in SES. If you receive mail with SES receipt rules, move it to an Emailit inbound subdomain first.

Next steps

Was this page helpful?

Thanks for the feedback.

Thanks, we read every message.