Skip to main content

Documentation Index

Fetch the complete documentation index at: https://docs.paubox.com/llms.txt

Use this file to discover all available pages before exploring further.

Why migrate

AWS will sign a Business Associate Agreement (BAA) that covers SES as a service, but the BAA does not protect Protected Health Information (PHI) in the body of the mail once it leaves AWS. SES TLS enforcement defaults to opportunistic (TlsPolicy: OPTIONAL), so messages silently fall back to plaintext when the recipient server doesn’t advertise STARTTLS — the customer carries the encryption-in-transit obligation. Paubox closes that gap with always-on TLS, an automatic Secure Portal fallback when the recipient cannot accept encrypted mail, and a BAA signed with every customer. The send-side API is REST/JSON and the migration is straightforward as most patterns map one-to-one.

What stays the same

  • REST API over HTTPS with JSON request bodies (when using SESv2; SES v1 form-encoded callers will move to JSON)
  • Domain authentication: SPF and DKIM records required
  • SMTP as an alternative to the HTTP API
  • Webhook-based event notifications for delivery status
  • Per-domain sending configuration

Key differences

DimensionAmazon SES (SESv2)Paubox Email API
Base URLhttps://email.{region}.amazonaws.com/v2/email/outbound-emailshttps://api.paubox.net/v1/$PAUBOX_ENDPOINT/messages
Region selectionRequired (us-east-1, eu-west-1, …)Single global endpoint, no region
Auth methodAWS SigV4 (access key + secret + region, or IAM role)Bearer token — Authorization: Bearer $PAUBOX_API_KEY
SDK@aws-sdk/client-sesv2, boto3 sesv2, Aws::SESV2, etc.paubox-node, paubox-python3, paubox_ruby, paubox-php, paubox-java, paubox-csharp — or plain fetch / requests
Request body shapeContent.Simple.Subject.Data / Body.Html.Data / Destination.ToAddresses[]data.message.headers.subject / content["text/html"] / recipients[]
AttachmentsRaw MIME via SendRawEmail onlyFirst-class data.message.attachments[] with base64 content
Bulk sendSendBulkEmail (templated only, up to 50 destinations)/bulk_messages endpoint, recommended max 50 per request
TemplatesSES templates (CreateTemplate API, Handlebars-style syntax)Paubox Dynamic Templates (/dynamic_templates CRUD, Handlebars)
SMTP hostemail-smtp.{region}.amazonaws.comsmtp.paubox.com
SMTP credentialsIAM-user-derived SMTP username + password (separate from the AWS API key)Literal string apikey as username, Paubox API key as password
SMTP port25, 465, 587, or 2587587 (also supports 465, 25)
TLS enforcementTlsPolicy: OPTIONAL | REQUIRE (per configuration set)Always-on, cannot be disabled
Delivery feedbackSNS topic subscription → HTTPS endpointPaubox webhooks (HTTPS POST directly to your endpoint)
Message ID returnedMessageIdsourceTrackingId

Send a single email

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

const ses = new SESv2Client({ region: process.env.AWS_REGION });

await ses.send(
  new SendEmailCommand({
    FromEmailAddress: "provider@yourclinic.com",
    Destination: { ToAddresses: ["patient@example.com"] },
    Content: {
      Simple: {
        Subject: { Data: "Your appointment summary" },
        Body: { Html: { Data: "<p>See attached.</p>" } },
      },
    },
  }),
);
Note:$PAUBOX_ENDPOINT is the username shown on your Paubox Email API > Settings page — not your email address.
Note:SES uses AWS SigV4 over the AWS credential chain (AWS_ACCESS_KEY_ID, AWS_SECRET_ACCESS_KEY, AWS_REGION, or an IAM role). Paubox uses a single Bearer token. After cutover, remove the AWS SDK dependency and any AWS credentials scoped to ses:SendEmail from your runtime environment.

SMTP configuration

const transporter = nodemailer.createTransport({
  host: "email-smtp.us-east-1.amazonaws.com",
  port: 587,
  auth: {
    user: process.env.SES_SMTP_USERNAME, // IAM-derived SMTP username
    pass: process.env.SES_SMTP_PASSWORD, // IAM-derived SMTP password
  },
});
Tip:SES SMTP credentials are not the same as your AWS API key — they are derived from a dedicated IAM user via the SES console. After traffic has moved to Paubox, delete that IAM user so the SMTP credential is fully revoked.

Webhook event mapping

SES does not push HTTP webhooks directly — bounces, complaints, and deliveries are published to an SNS topic that fans out to an HTTPS subscription. Paubox replaces both layers with a direct HTTPS POST to your endpoint.
SES SNS eventPaubox event keyNotes
Deliveryapi_mail_log_delivered
Openapi_mail_log_opened
Bounce (bounceType: Permanent)api_mail_log_permanent_failure
Bounce (bounceType: Transient)api_mail_log_temporary_failure
Click— no equivalentPoll click data via Get message receipt
Complaint— no equivalentManage unsubscribes in the Paubox dashboard
Reject— no equivalentPaubox returns rejections synchronously in the POST response, not as a webhook
Send— no equivalentdelivered confirms acceptance; remove handler
Note:Click tracking is available by polling GET /message_receipt?sourceTrackingId=... — it is not delivered as a push webhook event.
Note:Paubox webhooks POST directly to your HTTPS endpoint. There is no intermediary SNS topic, so the JSON envelope is flatter than the SES → SNS → subscription payload. Configure endpoints in the Paubox dashboard under Email API → Webhooks. See the Webhooks reference for the payload shape.

Template migration

If you use SES templates (CreateTemplate / SendTemplatedEmail / SendBulkTemplatedEmail), recreate each one as a Paubox Dynamic Template. Both systems use Handlebars-style {{variable}} syntax, so most template bodies port verbatim.
1

Export each SES template

Run aws ses get-template --template-name <name> (or aws sesv2 get-email-template) and capture the Subject, HtmlPart, and TextPart fields.
2

Create the Paubox Dynamic Template

POST each template to /dynamic_templates with the body remapped to Paubox’s shape. See the Dynamic templates reference for the request format.
3

Switch from `SendTemplatedEmail` to templated messages

Replace SendTemplatedEmail / SendBulkTemplatedEmail calls with POST /messages (or /bulk_messages) using the template_id and template_variables fields.

Migration checklist

1

Sign a BAA with Paubox

Required before go-live. Contact Paubox to initiate the Business Associate Agreement.
2

Create an account and verify your sending domain

Add your domain on the Paubox Email API > Settings page and complete the TXT record verification. See the Quickstart guide for step-by-step instructions.
3

Generate a Paubox API key

From the Settings page, generate an API key and note your customer endpoint (https://api.paubox.net/v1/YOUR_USERNAME).
4

Replace the AWS SDK call with a Paubox request

Remove @aws-sdk/client-ses / @aws-sdk/client-sesv2 (or the boto3 / Aws::SESV2 equivalent) and call Paubox via fetch / one of the Paubox SDKs. Restructure the request body to use the data.message shape shown above.
5

Remove AWS credentials from runtime config

Drop AWS_ACCESS_KEY_ID, AWS_SECRET_ACCESS_KEY, AWS_REGION, and any IAM role permissions scoped to ses:SendEmail / ses:SendRawEmail / ses:SendBulkEmail.
6

Update SMTP credentials

If you use the SMTP path, update host to smtp.paubox.com, set username to the literal string apikey, and password to your Paubox API key. Delete the IAM user that was created for SES SMTP credentials.
7

Recreate SES templates as Paubox Dynamic Templates

8

Tear down the SNS topic and HTTPS subscription

Remap your bounce / complaint / delivery handler to the Paubox webhook payload using the event mapping table above, then delete the SNS topic and configuration-set event destination used for SES feedback.
9

Remove any TLS policy overrides

Paubox enforces TLS unconditionally — remove TlsPolicy: OPTIONAL or TlsPolicy: REQUIRE from any SES configuration set you were referencing.
10

Send a test message

Confirm delivery using the Get message receipt endpoint with the sourceTrackingId returned from your test send.
11

Swap DNS records

Replace SES SPF and DKIM records with the Paubox records shown in your Settings page.
12

Revoke AWS credentials

Once traffic has fully moved to Paubox, delete the IAM user and access keys used by the SES integration.

Next steps

Quickstart guide

Full setup walkthrough from account creation to first send

Webhooks reference

Configure delivery event notifications

Batch send

Send up to 50 messages in a single request

SMTP API

Connect via SMTP instead of REST