Migration

Migrate from AWS SES

SES gives you a raw sending primitive and leaves the rest — bounce handling via SNS, suppression lists, open and click tracking, configuration sets — for you to assemble and operate. Migrating to eusend mostly means deleting that assembly: the platform does those jobs out of the box. And where SES in eu-west-1 keeps your mail in an EU region of a US cloud, eusend is EU end-to-end — EU infrastructure, EU company.

The code change

Install the SDK with npm install @eusend_dev/sdk. The nested Destination/Content structure flattens into plain fields, and auth is an API key instead of IAM credentials. Calls return { data, error } instead of throwing.

Before · SES (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: ['user@example.com'] },
  Content: {
    Simple: {
      Subject: { Data: 'Welcome' },
      Body: {
        Html: { Data: '<p>Thanks for signing up.</p>' },
      },
    },
  },
}))
After · eusend
import { Eusend } from '@eusend_dev/sdk'

const eusend = new Eusend(
  process.env.EUSEND_API_KEY
)

await eusend.emails.send({
  from: 'Acme <hello@acme.com>',
  to: 'user@example.com',
  subject: 'Welcome',
  html: '<p>Thanks for signing up.</p>',
})

Field mapping

SES (SESv2)eusendNotes
FromEmailAddressfromMust use a domain you verified in eusend
Destination.ToAddresses / CcAddresses / BccAddressesto / cc / bccString or array
ReplyToAddressesreplyTo
Content.Simple.Subject.Datasubject
Content.Simple.Body.Html / Texthtml / text
Content.Raw (SendRawEmailCommand)headersIf you built raw MIME just to set custom headers, a plain headers object replaces it. For attachments, pass an attachments array (base64 content) instead of hand-building MIME — see below.
ConfigurationSetNameNot needed. Tracking and event delivery are per-send flags and webhooks.
Templates (SendTemplatedEmailCommand)templateIdeusend has server-side templates; see the docs for the variable syntax

If you send over SMTP (or nodemailer)

Many SES setups actually send through nodemailer pointed at the SES SMTP endpoint. That path migrates without touching application code — swap the transport and delete the IAM SMTP credential dance:

nodemailer
// Before: email-smtp.eu-west-1.amazonaws.com:587, IAM-derived SMTP credentials
// After — fixed username, API key as password, implicit TLS on 465 (not STARTTLS)
const transport = nodemailer.createTransport({
  host: 'smtp.eusend.dev',
  port: 465,
  secure: true,
  auth: { user: 'eusend', pass: process.env.EUSEND_API_KEY },
})

The plumbing you get to delete

This is usually the real win. A production SES setup carries a stack of supporting pieces that eusend replaces with built-ins:

On SES you runOn eusend
SNS topics + subscriptions for bounces and complaintsSigned webhooks: email.bounced, email.complained, email.delivered, plus opens and clicks — HMAC-SHA256 signed, no SNS confirmation handshake
Your own suppression handlingHard bounces and complaints are suppressed automatically
Configuration sets + event destinations for open/click trackingtrackOpens / trackClicks flags, on by default, with a built-in analytics dashboard
CloudWatch alarms on bounce rate to protect your accountPlatform-level monitoring — you see your rates in the dashboard and we flag problems before they hurt you

What's honestly different

Before you flip production

Want it done for you?
The migration page has a copy-paste prompt that lets an AI coding agent do the whole swap against our live API reference. Or email support@eusend.dev — we're happy to help you move over.