Amazon SES Bridge

Keep your Amazon SES code. Point the SES SDK (or your SMTP settings) at wemail, swap in wemail-issued access keys, and send with the same API v2 and v1 calls — events come back in the SES event format.

The Amazon SES bridge accepts Amazon SES API traffic at https://api.wemail.io/bridge/ses. Your AWS SDK keeps signing requests the way it always does (AWS Signature Version 4) — only the endpoint and the access key pair change. Sends, bulk sends, raw messages, templates and the suppression list keep the same request and response shapes, and delivery events are published in the SES event format.

Authentication

Create an access key pair in the console (API Bridge → Amazon SES). The Access key ID starts with AKWM; the secret access key is shown once. Live keys send email; test keys accept and simulate without delivery. Requests must be signed with AWS Signature Version 4 for the ses service — every AWS SDK does this for you. Revoking a key stops it within a minute.

Supported operations

POST /bridge/ses/v2/email/outbound-emails

API v2 SendEmail — Simple (subject, HTML, text, headers, attachments), Raw (MIME) or Template content.

POST /bridge/ses/v2/email/outbound-bulk-emails

API v2 SendBulkEmail — up to 50 entries with per-entry template data and tags; per-entry results like SES.

GET /bridge/ses/v2/email/account

API v2 GetAccount — sending enabled, send quota and last-24-hours count.

PUT /bridge/ses/v2/email/suppression/addresses

API v2 PutSuppressedDestination (Reason BOUNCE or COMPLAINT).

GET /bridge/ses/v2/email/suppression/addresses

API v2 ListSuppressedDestinations (Reasons, StartDate, EndDate, PageSize, NextToken).

GET /bridge/ses/v2/email/suppression/addresses/{EmailAddress}

API v2 GetSuppressedDestination.

DELETE /bridge/ses/v2/email/suppression/addresses/{EmailAddress}

API v2 DeleteSuppressedDestination.

POST /bridge/ses/

API v1 (Query protocol) — Action=SendEmail, SendRawEmail, SendTemplatedEmail and GetSendQuota, with XML responses.

Templates, tags and configuration sets

TemplateName (or TemplateArn) is matched by name to a template in your wemail workspace, and TemplateData fills its {{variables}}; inline TemplateContent works without a stored template. EmailTags and ConfigurationSetName are kept with every message and returned on its events. Over SMTP, the X-SES-CONFIGURATION-SET and X-SES-MESSAGE-TAGS headers work the same way.

Events

Events use the SES event-publishing JSON — Send, Delivery, Bounce, Complaint, Reject, DeliveryDelay, Open, Click and Rendering Failure — with the full mail object (messageId equals the MessageId returned at send, plus commonHeaders and tags). The legacy notification format (notificationType: Bounce, Complaint, Delivery) is available as a setting. Two ways to receive them:

Event destinations
ParameterTypeRequiredDescription
Your own SNS topicoptionalOptionalCreate an IAM role that trusts wemail (with the External ID shown in the console) and allows only sns:Publish on your topic. Events are published to your topic like SES publishes them, so existing SQS queues, Lambdas and subscribers keep working. Rolling out — the console shows the setup once it is enabled for your workspace.
HTTPS endpoint (SNS-compatible)recommendedOptionalwemail takes the place of Amazon SNS in front of the endpoint your SNS subscription calls today. Add that URL on the Webhooks page: it first receives a SubscriptionConfirmation (confirm it by calling SubscribeURL, as with SNS), then every event as an SNS Notification with the SES event JSON in Message. Messages are signed like SNS SignatureVersion 2 with the wemail certificate at SigningCertURL; allow its host in your SNS validator (PHP: new MessageValidator(null, '/^api\.wemail\.io$/'), Node sns-validator: new MessageValidator(/^api\.wemail\.io$/)). UnsubscribeURL stops delivery. The X-Wemail-Signature header (hex HMAC-SHA256 of the body with the endpoint secret) is sent too.

Known differences from Amazon SES

Differences
ParameterTypeRequiredDescription
Template managementunsupportedOptionalCreateEmailTemplate and related calls are not bridged — manage templates in wemail (same names).
Identities & configuration setsbehaviorOptionalDomains are verified in wemail (DKIM records from the Domains page). Configuration-set names are accepted and echoed on events; their SES-side settings do not apply.
SMTP credentialsbehaviorOptionalSES SMTP passwords do not carry over: use smtp.wemail.io:587 with your wemail SMTP credentials.
ListManagementOptions / feedback forwardingbehaviorOptionalAccepted and ignored.
Inbound emailunsupportedOptionalSES receipt rules are not part of the bridge.

Code examples

cURL
# curl 7.75+ signs with AWS Signature Version 4 itself
curl https://api.wemail.io/bridge/ses/v2/email/outbound-emails \
  --aws-sigv4 "aws:amz:eu-west-1:ses" \
  --user "AKWMXXXXXXXXXXXXXXXX:YOUR_SECRET" \
  -H "Content-Type: application/json" \
  -d '{
    "FromEmailAddress": "sender@yourdomain.com",
    "Destination": { "ToAddresses": ["user@example.com"] },
    "Content": { "Simple": {
      "Subject": { "Data": "Hello" },
      "Body": { "Html": { "Data": "<p>Hi there</p>" } }
    } }
  }'
Node.js
import { SESv2Client, SendEmailCommand } from '@aws-sdk/client-sesv2';

const ses = new SESv2Client({
  region: 'eu-west-1',
  endpoint: 'https://api.wemail.io/bridge/ses',
  credentials: { accessKeyId: 'AKWMXXXXXXXXXXXXXXXX', secretAccessKey: process.env.WEMAIL_SES_SECRET },
});

const { MessageId } = await ses.send(new SendEmailCommand({
  FromEmailAddress: 'sender@yourdomain.com',
  Destination: { ToAddresses: ['user@example.com'] },
  Content: { Simple: { Subject: { Data: 'Hello' }, Body: { Html: { Data: '<p>Hi there</p>' } } } },
}));
Python
import os, boto3

ses = boto3.client(
    'sesv2', region_name='eu-west-1',
    endpoint_url='https://api.wemail.io/bridge/ses',
    aws_access_key_id='AKWMXXXXXXXXXXXXXXXX',
    aws_secret_access_key=os.environ['WEMAIL_SES_SECRET'],
)

resp = ses.send_email(
    FromEmailAddress='sender@yourdomain.com',
    Destination={'ToAddresses': ['user@example.com']},
    Content={'Simple': {'Subject': {'Data': 'Hello'}, 'Body': {'Html': {'Data': '<p>Hi there</p>'}}}},
)
print(resp['MessageId'])
PHP
$ses = new Aws\SesV2\SesV2Client([
    'region' => 'eu-west-1',
    'version' => 'latest',
    'endpoint' => 'https://api.wemail.io/bridge/ses',
    'credentials' => ['key' => 'AKWMXXXXXXXXXXXXXXXX', 'secret' => getenv('WEMAIL_SES_SECRET')],
]);

$result = $ses->sendEmail([
    'FromEmailAddress' => 'sender@yourdomain.com',
    'Destination' => ['ToAddresses' => ['user@example.com']],
    'Content' => ['Simple' => ['Subject' => ['Data' => 'Hello'], 'Body' => ['Html' => ['Data' => '<p>Hi there</p>']]]],
]);
echo $result['MessageId'];
Go
cfg, _ := config.LoadDefaultConfig(ctx, config.WithRegion("eu-west-1"),
    config.WithCredentialsProvider(credentials.NewStaticCredentialsProvider("AKWMXXXXXXXXXXXXXXXX", secret, "")))

client := sesv2.NewFromConfig(cfg, func(o *sesv2.Options) {
    o.BaseEndpoint = aws.String("https://api.wemail.io/bridge/ses")
})

out, err := client.SendEmail(ctx, &sesv2.SendEmailInput{
    FromEmailAddress: aws.String("sender@yourdomain.com"),
    Destination:      &types.Destination{ToAddresses: []string{"user@example.com"}},
    Content: &types.EmailContent{Simple: &types.Message{
        Subject: &types.Content{Data: aws.String("Hello")},
        Body:    &types.Body{Html: &types.Content{Data: aws.String("<p>Hi there</p>")}},
    }},
})
Java
SesV2Client ses = SesV2Client.builder()
    .region(Region.EU_WEST_1)
    .endpointOverride(URI.create("https://api.wemail.io/bridge/ses"))
    .credentialsProvider(StaticCredentialsProvider.create(
        AwsBasicCredentials.create("AKWMXXXXXXXXXXXXXXXX", System.getenv("WEMAIL_SES_SECRET"))))
    .build();

SendEmailResponse res = ses.sendEmail(r -> r
    .fromEmailAddress("sender@yourdomain.com")
    .destination(d -> d.toAddresses("user@example.com"))
    .content(c -> c.simple(m -> m
        .subject(s -> s.data("Hello"))
        .body(b -> b.html(h -> h.data("<p>Hi there</p>"))))));
C#
var ses = new AmazonSimpleEmailServiceV2Client(
    new BasicAWSCredentials("AKWMXXXXXXXXXXXXXXXX", Environment.GetEnvironmentVariable("WEMAIL_SES_SECRET")),
    new AmazonSimpleEmailServiceV2Config { ServiceURL = "https://api.wemail.io/bridge/ses" });

var res = await ses.SendEmailAsync(new SendEmailRequest {
    FromEmailAddress = "sender@yourdomain.com",
    Destination = new Destination { ToAddresses = { "user@example.com" } },
    Content = new EmailContent { Simple = new Message {
        Subject = new Content { Data = "Hello" },
        Body = new Body { Html = new Content { Data = "<p>Hi there</p>" } } } },
});