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:
| Parameter | Type | Required | Description |
|---|---|---|---|
Your own SNS topic | optional | Optional | Create 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) | recommended | Optional | wemail 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
| Parameter | Type | Required | Description |
|---|---|---|---|
Template management | unsupported | Optional | CreateEmailTemplate and related calls are not bridged — manage templates in wemail (same names). |
Identities & configuration sets | behavior | Optional | Domains 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 credentials | behavior | Optional | SES SMTP passwords do not carry over: use smtp.wemail.io:587 with your wemail SMTP credentials. |
ListManagementOptions / feedback forwarding | behavior | Optional | Accepted and ignored. |
Inbound email | unsupported | Optional | SES receipt rules are not part of the bridge. |
Code examples
# 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>" } }
} }
}'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>' } } } },
}));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'])$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'];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>")}},
}},
})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>"))))));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>" } } } },
});