# AWS SES Integration

> Complete guide to integrating AWS Simple Email Service (SES) with Broadcast for email sending and tracking.

Source: https://sendbroadcast.net/docs/esp-integrations/aws-ses

Amazon Simple Email Service (SES) is a cloud-based email sending service designed for high-volume email delivery. Broadcast provides deep integration with AWS SES, including automatic resource setup, webhook tracking, and suppression list synchronization.

## Features

| Feature | Supported |
| --- | --- |
| SMTP Delivery |  |
| API Delivery |  |
| Automatic Setup |  |
| Webhook Tracking |  |
| Suppression List Sync |  |
| Open Tracking |  |
| Click Tracking |  |

## Delivery Methods

Broadcast supports two delivery methods for AWS SES:

### API Delivery (Recommended)

API delivery uses the AWS SDK to send emails directly through the SES API. Benefits include:

- **Faster sending**: No SMTP handshake overhead
- **Better error handling**: Detailed error messages from AWS
- **Reduced infrastructure**: No need to open SMTP ports
- **Direct access**: To SES-specific features

### SMTP Delivery

Traditional SMTP delivery works with standard email infrastructure. Use this if:

- You have existing SMTP infrastructure
- Your network restricts API calls
- You need maximum compatibility

Both methods support full webhook integration for tracking email events.

---

## Setting Up AWS SES

### Prerequisites

Before you begin, ensure you have:

1. An AWS account with SES access
2. A verified domain or email address in SES
3. SES out of sandbox mode (for production sending)
4. An IAM user with appropriate permissions

### Creating an IAM User

Create a dedicated IAM user for Broadcast with the following policies:

#### Security Best Practice

Create a dedicated IAM user for Broadcast. Never use your root account or a user with broad access.

**Required IAM Policies:**

| Policy | Purpose |
|--------|---------|
| `AmazonSESFullAccess` | Email sending & suppression list sync |
| `AmazonSNSFullAccess` | Webhook event notifications (automatic setup) |

---

## Guided Setup (Recommended)

The fastest way to connect a new AWS SES server is the **Guided Setup** wizard, which walks through Connect, Verify, and Webhooks in three steps:

1. Navigate to **Settings** → **Email Servers**
2. Click **Add email server** → **Guided Setup**
3. Select **AWS SES**
4. Enter your **Access Key ID**, **Secret Access Key**, and the **Region** your SES account is in
5. Click **Verify & Connect**. Broadcast checks the credentials and auto-discovers the domains and senders already verified in your SES account, then continues to the Verify and Webhooks steps.

![Step 1 of the AWS SES guided setup, Connect, with Access Key ID, Secret Access Key and Region fields above a Verify and Connect button](https://sendbroadcast.net/assets/docs/esp-integrations/aws-ses-connect-130c3a95.png)

The **Region** dropdown covers the 18 regions where SES is available, and must match the region your SES identities live in: credentials that work in one region will not see identities in another. The **How to create an IAM user with the right permissions** link on that screen expands the exact policy required.

If you already have an AWS SES email server in Broadcast and only want to add webhook resources to it, use the automatic setup below instead.

## Automatic Setup

Broadcast can automatically create all the necessary AWS resources for webhook integration. This is the easiest way to get started.

### What Broadcast Creates

The automatic setup process creates:

- **SES Configuration Set**: For email tracking and event routing
- **SNS Topic**: For receiving email event notifications
- **SNS Subscription**: Connects the topic to your Broadcast webhook endpoint
- **Event Destinations**: Routes sends, bounces, complaints, deliveries, opens, clicks, and rejects

### Running Automatic Setup

1. Go to **Settings** → **Email Servers**
2. In the **Amazon SES integration** section, select your AWS SES email server
3. Click **Integrate Selected Server**
4. Enter your AWS credentials:
   - **AWS Access Key ID**
   - **AWS Secret Access Key**
   - **AWS Region** (must match your SES region)
5. Click **Setup AWS Integration**

Broadcast will create all resources and configure your email server automatically. Once complete, you'll see an "Integrated" badge next to your server.

### Reconfiguring an Existing Integration

If you set up AWS SES integration before and want to update your AWS resources with new event types, you can reconfigure:

1. Go to **Settings** → **Email Servers**
2. Find your integrated server (shows "Integrated" badge)
3. Click **Reconfigure** next to the badge
4. Confirm your AWS credentials
5. Click **Reconfigure Integration**

The setup service is idempotent: it will reuse existing resources and only create or update what's needed.

---

## Configuring Email Delivery

### API Delivery Setup

To use API delivery instead of SMTP:

1. Go to **Settings** → **Email Servers**
2. Click **New Email Server** or edit an existing AWS SES server
3. Configure:
   - **Vendor**: AWS SES
   - **Delivery Method**: API
   - **AWS Access Key ID**: Your IAM user's access key
   - **AWS Secret Access Key**: Your IAM user's secret key
   - **AWS Region**: Your SES region (e.g., us-east-1)
   - **AWS SES Configuration Set**: (Optional) For webhook tracking
4. Select which email types to send (Broadcasts, Sequences, Transactional)
5. Save your configuration

### SMTP Delivery Setup

For SMTP delivery:

1. In AWS Console, go to **SES** → **SMTP settings**
2. Click **Create SMTP credentials**
3. Note the SMTP endpoint, username, and password
4. In Broadcast, go to **Settings** → **Email Servers**
5. Create or edit an email server:
   - **Vendor**: AWS SES
   - **Delivery Method**: SMTP
   - **SMTP Address**: Your SES SMTP endpoint
   - **SMTP Port**: 587 (recommended) or 465
   - **SMTP Username**: From AWS
   - **SMTP Password**: From AWS
   - **AWS SES Configuration Set**: (Optional) For webhook tracking
6. Click **Test SMTP settings** to verify
7. Save your configuration

---

## Suppression List Sync

AWS SES maintains an account-level suppression list of email addresses that have bounced or complained. Broadcast can sync this list to ensure you don't send to these addresses.

### How It Works

When you trigger a sync, Broadcast:

1. Queries your AWS SES account's suppression list
2. Imports each address (whether AWS suppressed it for a bounce or a complaint) as a **channel suppression** for the channel that owns the email server
3. Records the sync timestamp and any errors

Imported addresses appear under **Settings** → **Global Suppression** on the **Channel** tab, not the **Global** tab. If you want an address blocked across every channel, add it to the Global tab yourself, see [Suppression Lists](https://sendbroadcast.net/docs/suppression-lists).

This ensures that addresses suppressed at the AWS level are also suppressed in Broadcast, preventing wasted sends and protecting your sender reputation.

### Running a Sync

1. Go to **Settings** → **Email Servers**
2. Scroll to **Suppression List Sync** section
3. Find your integrated AWS SES server
4. Click **Sync Suppression List**
5. Confirm the sync

You'll see the results showing how many addresses were added and skipped.

### Sync Information

For each server, Broadcast displays:

- **Last synced**: When the suppression list was last synchronized
- **Sync errors**: Any errors from the most recent sync attempt

#### When to Sync

Run a sync before major campaigns to ensure your suppression list is up to date. This is especially important if you're migrating from another platform or have been sending emails outside of Broadcast.

---

## Auto-Suppression

When Broadcast receives bounce or complaint webhooks from AWS SES, it automatically:

1. **Marks the outbound receipt** as bounced (recording the AWS bounce type and sub-type) or as a complaint
2. **Deactivates the subscriber:** they are set inactive with an unsubscribed timestamp, and a history entry is written reading "Bounced (Unsubscribed) [Webhook]" or "Reported Spam (Unsubscribed) [Webhook]"
3. **Adds the email to the channel suppression list** for the channel that sent the message

This triple protection ensures:

- The specific subscriber won't receive emails
- The email address won't receive emails from that channel even if re-added
- Your sender reputation is protected

### Where to See Suppressed Bounces

Auto-suppression is **channel-scoped**. Bounced and complained addresses appear under **Settings** → **Global Suppression** on the **Channel** tab. The **Global** tab only holds addresses you have blocked across every channel by hand, so a bounce will never show up there: that is the most common reason auto-suppression looks like it isn't working.

The bounce itself is visible in three other places:

- On the broadcast's activity, using the **Bounced** and **Spam** filters
- In the **Bounce** and **Spam** columns on the broadcasts list
- In the subscriber's **Activity** section

Bounces also fire the `subscriber.bounced` and `subscriber.unsubscribed` webhook events, see [Webhooks](https://sendbroadcast.net/docs/webhooks).

---

## Testing the Integration

### Using the AWS SES Simulator

AWS provides simulator addresses for testing without affecting your reputation:

| Address | Purpose |
|---------|---------|
| `success@simulator.amazonses.com` | Successful delivery |
| `bounce@simulator.amazonses.com` | Hard bounce |
| `complaint@simulator.amazonses.com` | Spam complaint |
| `suppressionlist@simulator.amazonses.com` | On suppression list |

### Test Procedure

1. Add a test subscriber with `bounce@simulator.amazonses.com`
2. Create and send a test broadcast
3. Check the subscriber's detail page
4. Verify:
   - Bounce event was received
   - Subscriber was deactivated
   - Email was added to **Settings** → **Global Suppression** → **Channel** tab

---

## Webhook Events

AWS SES sends the following event types through SNS:

| Event Type | Description |
|------------|-------------|
| `Bounce` | Email bounced (hard or soft) |
| `Complaint` | Recipient marked as spam |
| `Delivery` | Email successfully delivered |
| `Send` | Email sent to SES |
| `Reject` | SES rejected the email |
| `Open` | Recipient opened the email |
| `Click` | Recipient clicked a link |
| `Subscription` | Subscription-related event |

Broadcast automatically processes these events and updates:

- Outbound receipt records
- Subscriber status
- The channel suppression list (for bounces/complaints)

### How Events Are Matched to a Send

SNS delivers events to Broadcast at `https://your-broadcast-domain/wh/ses`. Broadcast then has to tie each event back to the message it came from:

- **API delivery**: the send carries a `broadcast_message_id` message tag, which SES returns on the event. (SES overwrites the `Message-ID` header on API sends, which is why the tag is used.)
- **SMTP delivery**: the identifier is read from the `Message-ID` header.

An event that matches no outbound receipt is discarded. That means bounces for mail sent **outside Broadcast**, or sent **before the integration was configured**, will appear in the SES message log but never in Broadcast. Use Suppression List Sync above to bring those addresses across.

---

## Troubleshooting

### Common Issues

**"AWS credentials invalid" error**

- Verify your Access Key ID and Secret Access Key are correct
- Ensure the IAM user has the required permissions
- Check that you're using credentials for the correct AWS region

**Webhooks not being received**

- In the AWS console, open the SNS topic and check the subscription to `https://your-broadcast-domain/wh/ses`. Its status must be **Confirmed**: a subscription left at *PendingConfirmation* silently drops every event, and it is by far the most common cause
- Check that the configuration set is assigned to your email server in Broadcast
- Ensure the event destination includes all event types, in particular **Bounce** and **Complaint**
- Verify your Broadcast instance is accessible from the internet

**Bounces appear in the AWS SES message log but nowhere in Broadcast**

A received bounce always does all three things listed under Auto-Suppression, so if none of them happened the event never reached Broadcast or never matched a send.

- Work through the webhook checks above first
- Confirm you are looking at the **Channel** tab under **Settings** → **Global Suppression**, not the **Global** tab
- Check whether the affected mail was sent through Broadcast at all, and after the integration was set up, see "How Events Are Matched to a Send" above
- To bring across bounces AWS already knows about, run a Suppression List Sync

**Suppression sync failing**

- Ensure your IAM user has `ses:ListSuppressedDestinations` permission
- Check that AWS SES is configured in the correct region
- Verify your credentials haven't expired

**"Configuration set not found" error**

- Verify the configuration set name matches exactly (case-sensitive)
- Ensure the configuration set exists in the same region as your SES account

### Verifying Webhook Delivery

1. Go to your SNS topic in AWS Console
2. Check **Monitoring** for delivery metrics
3. Look for failed deliveries or throttling
4. In Broadcast, check the subscriber or broadcast detail pages for event activity

### Getting Help

If you're experiencing issues:

1. Check AWS CloudWatch logs for SES and SNS errors
2. Review the Broadcast Email Servers page for error messages
3. Verify all configuration steps were completed
4. Contact support at [simon@sendbroadcast.net](mailto:simon@sendbroadcast.net)
