Amazon SES to Volanea migration is not just a credentials swap. Your application code is usually the smallest part of the move; sender authentication, bounce handling, templates, suppression logic, and a controlled cutover determine whether the migration is uneventful.
This guide is for developers moving transactional or campaign email from Amazon SES to Volanea. It focuses on a staged migration that keeps production mail flowing, avoids duplicate sends, and treats deliverability data as operational state rather than something to rebuild later.
Start with an inventory, not a code change
Amazon SES can sit in more places than the obvious SendEmail call. Before creating a Volanea integration, make a concise inventory of every application, worker, cron job, and third-party system that can send from SES.
Look beyond your main product backend. Password resets might use one sender identity, invoices another, and operational alerts may come from a Lambda function, a queue consumer, or an SMTP relay configured in a legacy application. A migration that changes only the primary Node service can leave important messages on SES unintentionally—or, worse, create an inconsistent mix of sender identities and event handling.
Create an inventory with one row per sending workload:
| Workload | Trigger | SES integration | From domain | Volume pattern | Event consumer | Cutover owner |
|---|---|---|---|---|---|---|
| Password reset | User request | AWS SDK | auth.example.com | Spiky, latency-sensitive | Account service | Backend team |
| Receipts | Payment success | Queue worker | mail.example.com | Steady | Billing service | Payments team |
| Product alerts | Scheduled job | SMTP | alerts.example.com | Bursty | Data platform | Platform team |
| Lifecycle campaign | Audience segment | SES v2 API | news.example.com | Large batches | Marketing data pipeline | Lifecycle team |
For each workload, record whether it sends plain HTML, raw MIME, attachments, templated content, bulk mail, or messages with custom headers. Those distinctions tell you where a straightforward send-call replacement is appropriate and where you need a separate workstream.
Also capture the operational contract around each email. A password reset is successful only when the recipient can use it soon enough. A receipt may need a durable audit trail. A campaign can tolerate queued delivery but must honor unsubscribe status. “The API returned a success response” is not a complete definition of success for any of these flows.
Understand what changes—and what does not
A migration changes the provider-facing layer, but it should not casually change your mail policy. Keep the pieces that represent your own business rules independent of Amazon SES and independent of Volanea.
These policies should remain yours:
- Which events cause an email to be sent.
- Who is eligible to receive each message type.
- Which addresses have opted out or must never be contacted.
- How a user’s locale, identity, and authorization affect content.
- How long you keep delivery evidence and message metadata.
- Which failures are retryable, and how retries are deduplicated.
Amazon SES has AWS-specific objects and concepts, including Regions, verified identities, configuration sets, event destinations, IAM permissions, and SES-managed suppression behavior. Volanea has its own sending credentials, domain setup, event delivery configuration, and platform model. Do not assume that an SES object maps one-to-one merely because both platforms can send email.
A configuration set, for example, can carry several concerns in SES: event publishing, tagging, IP-pool selection, dedicated-IP behavior, reputation configuration, and suppression overrides. In a new integration, split those concerns into explicit requirements. Ask: where is the event stream configured, where are tags passed, where do suppressions live, and how is traffic segmented? This produces a migration design you can test rather than a collection of hopeful substitutions.
There are valid reasons to stay on SES for some workloads. SES can be a strong choice for teams deeply integrated with AWS, teams that want direct control over regional architecture, or systems whose IAM, CloudWatch, SNS, EventBridge, and infrastructure-as-code patterns are already mature. Volanea can be a better fit when your team wants one email-focused API and operational workflow for transactional and campaign sending. The right decision is workload-specific, not ideological.
Design the migration as an adapter layer
The safest application change is usually not replacing every SES call with provider-specific code throughout your repository. Instead, introduce a provider-neutral email boundary inside your application.
That boundary should accept concepts your product owns: sender, recipients, subject, HTML, text, reply-to, attachments, tags, a message category, and an idempotency value. Then implement an SES adapter and a Volanea adapter behind it during the migration period.
A minimal internal contract might look like this:
type OutboundEmail = {
from: string;
to: string[];
cc?: string[];
bcc?: string[];
replyTo?: string[];
subject: string;
html?: string;
text?: string;
headers?: Record<string, string>;
tags?: Record<string, string>;
category: "auth" | "billing" | "product" | "marketing";
idempotencyKey: string;
};
type SendResult = {
provider: "ses" | "volanea";
providerMessageId?: string;
accepted: boolean;
};
The point is not abstraction for its own sake. It is to give your product a stable sending contract while provider details change. It also lets you route a small percentage of non-critical traffic to Volanea without editing every call site again when you expand the rollout.
Keep the adapter thin. It should translate input and return a normalized acceptance result, not silently rewrite recipients, remove custom headers, or swallow provider errors. Business rules such as consent checks and internal suppressions belong before the adapter; provider-specific response parsing belongs inside it.
Use the current Volanea API reference and setup guides when implementing the provider adapter. In particular, verify the current send endpoint, authentication scheme, payload field names, attachment format, header support, idempotency mechanism, and response structure rather than inferring them from another email API.
Before and after: Amazon SES SDK call vs a Volanea call
The Amazon SES example below uses the AWS SDK for JavaScript v3 and the classic SES SendEmailCommand. It sends a formatted message from a verified sender or domain. The values are intentionally simple so the difference between the application-level email request and the provider adapter is clear.
Before: direct Amazon SES SDK usage
import { SESClient, SendEmailCommand } from "@aws-sdk/client-ses";
const ses = new SESClient({
region: process.env.AWS_REGION,
});
export async function sendPasswordResetWithSes(input: {
to: string;
resetUrl: string;
}) {
const command = new SendEmailCommand({
Source: "Example App <auth@example.com>",
Destination: {
ToAddresses: [input.to],
},
Message: {
Subject: {
Charset: "UTF-8",
Data: "Reset your password",
},
Body: {
Html: {
Charset: "UTF-8",
Data: `<p>Reset your password: <a href="${input.resetUrl}">Reset password</a></p>`,
},
Text: {
Charset: "UTF-8",
Data: `Reset your password: ${input.resetUrl}`,
},
},
},
ReplyToAddresses: ["support@example.com"],
Tags: [
{ Name: "category", Value: "auth" },
{ Name: "message_type", Value: "password_reset" },
],
});
const result = await ses.send(command);
return {
provider: "ses" as const,
providerMessageId: result.MessageId,
accepted: true,
};
}
After: call your Volanea adapter from the same product contract
import { sendWithVolanea } from "./email/volanea-adapter.js";
export async function sendPasswordResetWithVolanea(input: {
to: string;
resetUrl: string;
passwordResetId: string;
}) {
return sendWithVolanea({
from: "Example App <auth@example.com>",
to: [input.to],
replyTo: ["support@example.com"],
subject: "Reset your password",
html: `<p>Reset your password: <a href="${input.resetUrl}">Reset password</a></p>`,
text: `Reset your password: ${input.resetUrl}`,
tags: {
category: "auth",
message_type: "password_reset",
},
category: "auth",
idempotencyKey: `password-reset:${input.passwordResetId}`,
});
}
The sendWithVolanea function is deliberately your own adapter name, not an assumed Volanea SDK method. Implement its HTTP or SMTP request using the exact current Volanea documentation. This avoids embedding invented endpoint paths, package names, authentication headers, or payload fields into application code.
A practical implementation should do five things:
- Build the Volanea request from
OutboundEmailusing verified field mappings. - Attach the provider’s documented idempotency value or retain your own durable outbox deduplication if the selected send path does not provide one.
- Capture the provider message identifier returned after acceptance.
- Convert provider errors into your application’s retryable versus permanent error types.
- Log a correlation record containing your internal email ID, idempotency key, recipient count, category, and provider message ID—but not secrets or full sensitive content.
This design means the visible change at the call site is small: an AWS SDK command becomes an application-level email request routed to Volanea. The exact Volanea request stays in one tested module, where updates to API versions or optional provider features are contained.
Preserve idempotency during retries
Do not let a provider migration turn transient failures into duplicate password resets, receipts, or notifications. If a worker times out after handing a message to a provider, it may not know whether the provider accepted the request. A blind retry can therefore create a second message.
Use an immutable, business-level key that identifies one intended message. For example, a payment receipt might use receipt:<invoice-id>:<invoice-version>. A password reset might use a server-generated reset-token identifier rather than the recipient address. Store it in your database or outbox before dispatch.
The migration test is straightforward: deliberately interrupt the sender after initiating a request, retry the job, and confirm that the recipient gets no more than one message. Test this behavior for each sending path, not just the most convenient one.
Authenticate domains without breaking existing mail
Domain authentication deserves its own rollout. DNS records are shared infrastructure, and changing them carelessly can affect mail still being sent through Amazon SES, Google Workspace, Microsoft 365, support systems, and other vendors.
In most cases, do not remove SES DNS records immediately. First add and validate the records Volanea requires for the same sending domain or, preferably, for a dedicated sending subdomain. Keep SES authenticated until the Volanea rollout has completed and the retention period for operational rollback has passed.
SPF, DKIM, and DMARC are related but separate
SPF authorizes sending infrastructure through a TXT record on the envelope-sender domain. DKIM adds a cryptographic signature using a selector and public key published in DNS. DMARC tells receiving systems how to evaluate alignment between the visible From domain and SPF and/or DKIM, and how to handle failures.
The migration requirement is not simply “add the new provider’s DNS.” It is to ensure that messages sent through Volanea produce SPF and DKIM results aligned with the domain visible to recipients, consistent with your DMARC policy.
Be especially careful with SPF. A domain has one SPF policy record, and multiple independent SPF TXT records can cause SPF evaluation problems. If both SES and Volanea send using the same envelope-sender domain during the overlap, consolidate the necessary authorized mechanisms into one valid SPF policy according to the providers’ documented instructions. Do not copy an example include mechanism from memory; use the values generated for your domain.
DKIM is usually easier to overlap because selectors distinguish keys. You can have valid DKIM selectors for multiple senders at the same time. That does not mean every selector should live forever: after cutover, document which records still serve active senders and remove only records you have confirmed are no longer needed.
DMARC should not be weakened merely to make a migration look successful. If you already use p=quarantine or p=reject, validate the Volanea sending path with real test messages before routing production traffic. Review authentication results in the received message headers at major inbox providers, including the visible From domain, envelope sender, DKIM d= domain, and DMARC disposition.
DNS and authentication re-verification checklist
- Identify every domain and subdomain used in the visible From address, return path, reply-to address, and tracking links.
- Add Volanea’s required DNS records exactly as provided for each sending domain.
- Preserve SES records until the SES path is no longer required for production or rollback.
- Confirm there is one valid SPF policy per applicable domain and that the transitional policy supports every active sender.
- Confirm DKIM passes for messages sent through Volanea and that its signing domain aligns with your DMARC strategy.
- Send to controlled Gmail, Outlook, Yahoo, and corporate test mailboxes; inspect message headers rather than relying solely on a dashboard status.
- Verify the visible From domain aligns under DMARC for both transactional and campaign messages.
- Review existing DMARC aggregate reports during the overlap for unexpected sources or alignment failures.
- Confirm any custom MAIL FROM domain, bounce domain, or branded tracking domain works as intended under the new setup.
- Record DNS TTLs and the exact change window so responders know whether a result could still be affected by caching.
A dedicated subdomain such as notify.example.com can reduce risk when you have a complicated parent-domain SPF policy. It also creates a clearer boundary for reputation monitoring. But it is still a new sending identity: ramp volume intentionally and make sure user-facing addresses remain recognizable and trustworthy.
Rebuild webhook handling around events, not provider names
SES event pipelines often use configuration sets that publish to Amazon SNS, EventBridge, Kinesis Data Firehose, CloudWatch, or another AWS destination. Your code may receive SES-shaped notification envelopes, not just normalized bounce and complaint facts.
Volanea webhook delivery should be treated as a new event integration. Do not point it at a consumer that only understands SES events and expect it to work. Build or update a provider-specific webhook adapter that verifies the provider’s documented signature and turns validated events into your internal event model.
A useful internal event format might include:
type EmailEvent = {
provider: "ses" | "volanea";
providerMessageId?: string;
internalEmailId?: string;
type: "accepted" | "delivered" | "bounced" | "complained" | "opened" | "clicked" | "unsubscribed";
occurredAt: string;
recipient?: string;
reason?: string;
rawEventId: string;
};
Not every provider exposes every event with the same timing, semantics, identifiers, or retention. “Delivered” generally means the receiving server accepted the message; it does not prove a person saw or read it. Opens and clicks are estimates affected by privacy protections, image blocking, security scanners, link rewriting, and automated prefetching. Preserve those distinctions in your analytics and product logic.
Webhook migration checklist
- List all SES configuration sets and the event destinations attached to each one.
- Identify which applications consume bounces, complaints, deliveries, opens, clicks, rejects, and rendering failures.
- Create a Volanea webhook endpoint or endpoints following the current documented setup and signing process.
- Verify webhook signatures before parsing or acting on event bodies.
- Make the receiver idempotent using the provider event ID or a durable derived key.
- Return success only after durable handling, or use a queue/outbox pattern that prevents event loss.
- Test duplicate delivery, delayed delivery, out-of-order events, malformed payloads, and temporarily unavailable endpoints.
- Map Volanea events into your internal vocabulary without assuming identical names or meanings.
- Keep the SES event pipeline active while SES still sends traffic.
- Update alerting dashboards, dead-letter handling, and on-call runbooks before increasing Volanea traffic.
Avoid making a single webhook event your only source of truth for an important customer workflow. For example, do not mark an invoice as “received” merely because an open pixel fired. Use your own product records, event timestamps, and delivery signals appropriately.
Move suppression data carefully
Suppression is one of the highest-risk parts of an email migration because it protects recipients and sender reputation. Amazon SES has account-level suppression behavior that can be scoped by AWS Region, and it distinguishes reasons such as bounces and complaints. SES also has provider-managed suppression behavior that is not the same thing as a portable list you own.
Export and migrate only the suppression data you are entitled to use and that represents your own sending policy. At a minimum, this normally includes hard bounces, spam complaints, global opt-outs, category-specific unsubscribes, and internal “do not contact” records. Keep original reason, source, timestamp, scope, and any evidence or audit reference where available.
Do not treat all negative events as interchangeable. A marketing unsubscribe should suppress promotional mail but may not suppress a legally required receipt. A hard bounce is a strong reason to stop sending until the address is corrected or revalidated. A complaint deserves a conservative policy. Your internal model should represent the difference.
A portable suppression record
type SuppressionRecord = {
email: string;
normalizedEmail: string;
reason: "hard_bounce" | "complaint" | "unsubscribe" | "manual" | "invalid";
scope: "all" | "marketing" | "transactional" | "category";
category?: string;
source: "ses" | "application" | "support" | "import";
suppressedAt: string;
evidence?: string;
};
Normalize for your own lookup logic, but preserve the original address form for audit purposes. Be aware that Amazon SES suppression-list management is case-sensitive for API operations even though email delivery itself generally treats address case as equivalent. During export and import, avoid accidental duplicates caused by inconsistent casing.
What is harder to migrate
Large historical suppression lists are rarely a clean one-click import. You may have millions of records, inconsistent reason codes, partial timestamps, addresses suppressed in several AWS Regions, or data that comes from a mixture of SES, CRM, support, and custom tables. Rate limits, batch sizes, import validation, and provider-specific list semantics may require chunked jobs with checkpoints.
There is also a fundamental portability limit: Amazon SES’s provider-managed global suppression behavior is not your private exportable customer list. Your own account-level suppressions and application-level consent records can inform the new platform’s suppression policy, but you should not assume that a destination provider will make the same independent decisions as SES for every recipient.
Run the import as an auditable data migration. Calculate source count, accepted count, rejected count, duplicate count, and reason breakdown. Sample records from each category. Then run a dry test: attempt to send only to controlled addresses that represent suppressed and non-suppressed states, and verify your application blocks or routes each one correctly before the messages reach the provider.
Audit templates, raw MIME, and SES-specific features
Amazon SES supports stored templates and inline templated sending in its v2 API. Those templates can contain subject, HTML, text, and replacement variables. If your system depends on them, template migration is its own project—not a minor detail of the send-call replacement.
Template syntax differences are an honest source of migration work. Variable delimiters, escaping rules, conditionals, loops, default values, helper functions, supported content fields, preview behavior, and rendering-failure handling can differ across systems. A template that looks correct in an editor can still render broken URLs, unescaped user data, missing text content, or invalid HTML under production data.
Export every template plus representative rendering data. For each template, build a fixture set that includes long names, apostrophes, non-Latin characters, missing optional fields, large totals, empty lists, multiple locales, and malicious-looking values such as angle brackets. Compare rendered HTML, rendered text, subject lines, links, headers, and visual output in target inboxes.
Raw MIME is another deliberate decision point. If you use SES SendRawEmail for complex attachments, inline images, S/MIME, custom headers, calendar invitations, or carefully constructed multipart messages, confirm the supported Volanea path before scheduling the cutover. A JSON email API can be easier for routine transactional messages, but raw-message control may require a different implementation or an SMTP path.
SES capabilities to explicitly assess for mapping
- Stored SES templates and inline templates.
- Bulk or personalized bulk sending workflows.
SendRawEmailand custom MIME construction.- Configuration sets and their event destinations.
- SES message tags and downstream cost, analytics, or tenant attribution.
- Dedicated IP pools, shared IP usage, or any custom routing choices.
- Custom MAIL FROM domains and bounce processing.
- Email receiving rules, receipt rules, inbound actions, and Lambda processing.
- AWS IAM roles, access keys, Secrets Manager rotation, and organization policies.
- Regional sending quotas, sandbox status, and multi-Region failover or global endpoint architecture.
Some features will map directly; some will map differently; some may belong in your application or another AWS service after the migration. Write down a decision for every item. “Not used” is a good decision when verified. “Probably handled by the new provider” is not.
Use a staged cutover with a real rollback path
Do not switch all production email at once because a test message looked good. Begin with low-risk, observable mail, then expand by category and percentage while checking actual outcomes.
A typical rollout sequence is:
- Create and validate Volanea credentials, domains, DNS, and webhook processing in a non-production environment where possible.
- Add the Volanea adapter behind a feature flag or routing rule without changing default production delivery.
- Send internal test traffic through Volanea and inspect received headers, content rendering, and events.
- Route a small, low-risk production category—such as non-urgent internal notifications or a small percentage of one transactional flow—to Volanea.
- Compare acceptance, bounce, complaint, delivery, latency, webhook lag, suppression decisions, and support tickets against the SES baseline.
- Increase traffic gradually only when the metrics and operational team support the change.
- Keep SES credentials and event processing available for the defined rollback window.
- Decommission SES paths only after all workloads, scheduled jobs, templates, suppressions, and monitoring have been verified.
Your rollback mechanism should be a routing decision, not a redeploy under pressure. For example, a configuration flag can choose ses or volanea per category or per percentage bucket. Keep the message contract and idempotency behavior consistent across both adapters so rollback does not create duplicates.
Avoid shadow sending real customer messages to both providers. Sending two password resets or receipts is harmful, and comparing delivery by delivering the same content twice can distort reputation and analytics. Instead, use controlled seed addresses, internal routing, provider test modes if available and documented, or carefully selected non-customer test traffic.
Define abort thresholds in advance. Examples include authentication failures, a spike in hard bounces relative to your baseline, missing webhook events, unacceptable latency for password resets, unexplained duplicate sends, or malformed rendering on a priority template. A rollback decision is much easier when it is based on a pre-agreed threshold rather than a vague sense that something feels wrong.
Monitor deliverability and operations after the switch
A successful API response means the provider accepted your request. It does not mean the message reached an inbox, passed authentication, avoided spam filtering, or was acted on by a recipient. Monitor the whole path after the cutover.
At minimum, track:
- Send attempts, accepted sends, and API failures by message category.
- Queue age and end-to-end time from product event to provider acceptance.
- Delivery, bounce, and complaint rates by sender domain and category.
- Suppression blocks by reason and source.
- Authentication results from seed-message header checks.
- Webhook arrival lag, parse failures, signature failures, and dead-letter volume.
- Duplicate-send detections using your idempotency keys.
- Template rendering failures, link failures, and attachment errors.
Segment metrics. A healthy overall bounce rate can conceal a broken sender domain, an imported list issue, or a single product flow with invalid recipient data. Separate transactional from campaign mail, and separate high-risk recipient acquisition sources from established customers.
If you are comparing costs, compare the entire operating model: email volume, overages, attachment usage, event retention, dedicated infrastructure, support requirements, engineering time, and the cost of maintaining AWS-specific glue code. Review sending plans and actual message costs alongside technical requirements, not as a substitute for them.
A final pre-cutover checklist
Use this checklist before moving a major production workload from SES to Volanea:
- Every SES sender has an identified Volanea destination configuration.
- Volanea domain authentication is complete and tested with real inbox headers.
- Existing SES DNS records remain in place for every sender still using SES.
- SPF, DKIM, and DMARC alignment have been reviewed for each From domain.
- Your Volanea adapter uses current documented authentication and payload syntax.
- The adapter records provider message IDs and durable internal correlation IDs.
- Retry behavior cannot create duplicate customer messages.
- Webhook signatures are verified and events are processed idempotently.
- Event mappings have been tested for delivery, bounce, complaint, and unsubscribe handling where applicable.
- Your own suppression, opt-out, and do-not-contact data has been imported or remains enforced before send.
- Historical suppression migration has reconciliation counts and an exception report.
- Every priority template has fixture-based rendering tests and inbox visual checks.
- Raw MIME, attachments, bulk sending, inbound email, and SES configuration-set dependencies have explicit migration decisions.
- Dashboards, alerts, support procedures, and rollback flags are ready.
- A staged rollout schedule, owner, and abort criteria are documented.
Conclusion
An Amazon SES to Volanea migration succeeds when it preserves the reliability work already present in your email system: authenticated domains, conservative suppression policy, durable event processing, correct templates, and idempotent sending. The send API is important, but it is only one layer of the system.
Keep SES and Volanea behind a small application-owned adapter, validate DNS without disrupting active senders, treat webhook payloads as a new integration, and move traffic gradually. That approach gives you a credible rollback path and lets your team evaluate the new platform on real operational results rather than a single successful test send.
FAQ
Can I keep Amazon SES running while I migrate to Volanea?
Yes. Keeping SES active during a staged rollout is usually safer than a hard cutover. Retain SES authentication records, credentials, and event processing for workloads that still send through SES and for the planned rollback window.
Do I need to change my SPF, DKIM, and DMARC records?
You will need to add and verify the DNS records Volanea requires. Do not remove SES records until SES is fully retired. Review SPF carefully because one domain should publish one valid SPF policy, while DKIM can typically support multiple active selectors during an overlap.
Can I import my Amazon SES suppression list?
You can migrate suppression data that you own and are authorized to use, such as account-level suppression records and your application’s unsubscribe or do-not-contact data. Large lists may require batch import, normalization, reconciliation, and careful reason-code mapping. SES provider-managed suppression behavior does not necessarily map as a portable list.
Are Amazon SES templates compatible with Volanea templates?
Do not assume direct compatibility. Template variables, escaping, helpers, conditional logic, and rendering behavior can differ. Export source templates, build representative data fixtures, and compare rendered subject, HTML, text, and links before routing production traffic.
What is the hardest part of an Amazon SES to Volanea migration?
For simple transactional messages, the send-call change is usually straightforward. The harder work is preserving suppression policy, remapping event pipelines, validating authentication alignment, migrating complex templates or raw MIME, and building a cutover process that prevents duplicate messages and supports quick rollback.