SendOps connects to your AWS account through **cross-account IAM role assumption** using AWS Security Token Service (STS). Instead of handing over long-lived access keys, you create a role in your account that trusts the SendOps AWS account. SendOps then calls `sts:AssumeRole` to obtain short-lived, scoped credentials every time it needs to interact with your SES resources.

This approach follows AWS best practices — credentials rotate automatically, you control exactly which permissions are granted, and you can revoke access instantly by deleting the role.


  SendOps will **never** ask you for an AWS Access Key ID or Secret Access Key. If you are prompted for static credentials, stop and contact [support@sendops.dev](mailto:support@sendops.dev). Cross-account role assumption is the only supported authentication method.


## Before you begin

Connecting your AWS account is **Phase 1** of the SendOps [Setup Guide](/getting-started/creating-your-account#the-setup-guide). Before selecting a method:

- **Review the permission breakdown** — the Setup Guide displays expandable permission categories (Account & Identities, Sending, Configuration Sets, Email Templates, Suppression List, Contact Lists, Resource Tagging, EventBridge, Stack discovery) showing exactly which IAM permissions are requested.
- **Understand the security scope** — SendOps requests SES and EventBridge permissions only. It never accesses EC2, S3, RDS, Lambda, Billing, IAM (write), or CloudWatch Logs.


  <Badge>Recommended</Badge>

Method 1: Automated (CloudFormation)

One click deploys a CloudFormation stack that creates everything SendOps needs — the IAM role, SES configuration set with event destination, EventBridge rule, webhook connection, and API destination — in a single stack.

### Deploying the stack


  <Step title="Choose your integration method and region">
    In the Setup Guide's AWS Integration phase, select **Automated Setup**. Then use the **AWS Region** dropdown to pick the region where your SES sending is configured. EventBridge rules are regional, so the integration must be deployed in the same region as your SES. See [Supported AWS Regions](/aws-setup/supported-regions) for the full list.
  </Step>

  <Step title="Launch the CloudFormation stack">
    Click **Launch CloudFormation Stack**. This opens the AWS CloudFormation console with the template URL and all parameters pre-filled for your account.

    Confirm the parameters are correct and that the region in the top-right corner of the AWS console matches your SES region. The **stack name** defaults to `sendops` — you can change it, but keeping the default makes support easier.

    Check the IAM capabilities acknowledgment box, then click **Create stack**. Deployment typically completes in one to two minutes.
  </Step>

  <Step title="Copy the Role ARN">
    Once the stack reaches **CREATE_COMPLETE**, the Setup Guide shows a link to the **IAM Role** in the AWS console where you can copy the ARN. You can also check the stack status directly from the link in the Setup Guide.
  </Step>

  <Step title="Validate in SendOps">
    Back in the Setup Guide, paste the Role ARN and click **Validate**. SendOps will perform an `AssumeRole` call to verify the connection. If the connection is already established, the button reads **Re-validate**.
  </Step>



  Click **"Don't have AWS access? Delegate this step"** to open a dialog with two options: **Email a colleague** (a pre-written message with the deploy link and instructions) or **Use an AI assistant** (a ready-to-copy CLI prompt with the full `aws cloudformation create-stack` command). Both include all parameters specific to your workspace.


### What the stack creates

The CloudFormation template provisions seven resources:

| Resource | Type | Purpose |
|---|---|---|
| **IAM Role** (`SendOpsRole`) | `AWS::IAM::Role` | Cross-account role that SendOps assumes. Includes an inline policy (`SendOpsSESAccess`) granting least-privilege SES and EventBridge read permissions. |
| **SES Configuration Set** (`sendops-events`) | `AWS::SES::ConfigurationSet` | SES publishes events from identities associated with this configuration set. |
| **SES Event Destination** (`sendops-eventbridge`) | `AWS::SES::ConfigurationSetEventDestination` | Routes all SES event types (send, reject, bounce, complaint, delivery, open, click, renderingFailure, deliveryDelay, subscription) to the default EventBridge event bus. |
| **EventBridge Connection** (`sendops-webhook`) | `AWS::Events::Connection` | Stores the API key (`x-api-key` header) used to authenticate requests to the SendOps webhook. |
| **EventBridge API Destination** (`sendops-ingest`) | `AWS::Events::ApiDestination` | Defines the SendOps webhook endpoint as an HTTP POST target with a rate limit of 300 invocations per second. |
| **EventBridge IAM Role** (`SendOpsEventBridgeRole`) | `AWS::IAM::Role` | Allows the EventBridge service to invoke the API destination. Has an inline policy granting `events:InvokeApiDestination`. |
| **EventBridge Rule** (`sendops-ses-events`) | `AWS::Events::Rule` | Matches all events from the `aws.ses` source on the default event bus and routes them to the API destination via the EventBridge IAM role. |

### Stack parameters

When you deploy the stack you will provide four parameters. The Setup Guide pre-fills these values in the launch URL.

| Parameter | Description |
|---|---|
| `SendOpsAccountId` | The SendOps AWS account ID. Used in the IAM trust policy so SendOps can assume the cross-account role. |
| `ExternalId` | A unique identifier for your SendOps organization. Prevents [confused deputy](https://docs.aws.amazon.com/IAM/latest/UserGuide/confused-deputy.html) scenarios. |
| `WebhookUrl` | The SendOps event ingestion endpoint URL (HTTPS). |
| `WebhookApiKey` | An API key that authenticates webhook requests. Generated per-organization in SendOps. |

### Stack outputs

Once the stack is created, the **Outputs** tab shows:

| Output | Value |
|---|---|
| `RoleARN` | The ARN of the cross-account IAM role. Paste this into the Setup Guide to validate the connection. |
| `ConfigurationSetName` | The name of the SES configuration set (`sendops-events`). |
| `EventRuleName` | The name of the EventBridge rule (`sendops-ses-events`). |

### Updating the stack

If SendOps releases a new version of the template (e.g., to add permissions for new features), you can update the stack in place. During Connection Validation, SendOps will show an update banner if the deployed template version is behind and any permission probes fail.


<TabPanel>

In the [CloudFormation console](https://console.aws.amazon.com/cloudformation/), select your `sendops` stack and click **Update**. Choose **Replace current template**, enter the new template URL, and click through to **Update stack**.

</TabPanel>
<TabPanel>



</TabPanel>


### Deleting the stack

Deleting the stack removes all resources it created — the IAM roles, configuration set, event destination, EventBridge rule, API destination, and connection. SendOps will stop receiving events from this region.


<TabPanel>

In the [CloudFormation console](https://console.aws.amazon.com/cloudformation/), select your `sendops` stack and click **Delete**. Confirm the deletion when prompted. The stack and all its resources will be removed.

</TabPanel>
<TabPanel>



</TabPanel>



  Deleting the stack does not affect your SES sending capability or any other AWS resources outside the stack. It only removes the event pipeline to SendOps.


## Method 2: Manual

If your organization requires manual resource provisioning, you can create the IAM role step by step. The Setup Guide provides the full IAM policy in both **CloudFormation** and **Terraform** formats with a copy button.


  The manual method creates the cross-account IAM role with SES and EventBridge permissions. It does **not** set up the SES configuration set, event destination, EventBridge rule, or webhook pipeline. Those resources are only provisioned by the automated CloudFormation method.


### How STS AssumeRole works

When SendOps needs to interact with your SES resources, it makes an `sts:AssumeRole` API call to AWS. AWS verifies:

1. **Trust policy** — the role in your account explicitly trusts the SendOps AWS account as a principal.
2. **External ID** — the request includes a unique External ID that matches the condition on your role's trust policy, preventing [confused deputy attacks](https://docs.aws.amazon.com/IAM/latest/UserGuide/confused-deputy.html).
3. **Permissions policy** — the attached policy defines exactly what actions SendOps can perform.

If all checks pass, AWS returns temporary credentials (valid for one hour) that are scoped to the permissions you granted.

### Creating the IAM role manually


  <Step title="Select Manual Setup and choose your region">
    In the Setup Guide's AWS Integration phase, select **Manual Setup**, then pick your **AWS Region** from the dropdown. You will see the IAM policy displayed below in CloudFormation and Terraform tabs.
  </Step>

  <Step title="Copy the policy and create the role in IAM">
    Copy the CloudFormation or Terraform snippet from the Setup Guide. The snippet includes placeholders for `<SendOpsAccountId>` and `<ExternalId>` — replace them with the values shown in the Setup Guide (or use the CloudFormation template directly, which fills them automatically).

    The role should be named `SendOpsRole` with a trust policy that allows `sts:AssumeRole` from the SendOps AWS account, conditioned on the External ID. The inline permissions policy (`SendOpsSESAccess`) grants nine groups of permissions:

    - **Account & Identities** — `ses:GetAccount`, `ses:PutAccountDetails`, `ses:GetSendQuota`, `ses:GetSendStatistics`, `ses:ListEmailIdentities`, `ses:GetEmailIdentity`, `ses:CreateEmailIdentity`, `ses:DeleteEmailIdentity`
    - **Sending** — `ses:SendEmail`, `ses:SendBulkEmail`, `ses:SendBulkTemplatedEmail`
    - **Configuration Sets** — `ses:ListConfigurationSets`, `ses:GetConfigurationSet`, `ses:CreateConfigurationSet`, `ses:DeleteConfigurationSet`, `ses:PutConfigurationSetTrackingOptions`, `ses:PutConfigurationSetReputationOptions`, `ses:PutConfigurationSetSendingOptions`, `ses:PutConfigurationSetDeliveryOptions`, `ses:PutConfigurationSetSuppressionOptions`, `ses:PutEmailIdentityConfigurationSetAttributes`, `ses:CreateConfigurationSetEventDestination`, `ses:GetConfigurationSetEventDestinations`, `ses:UpdateConfigurationSetEventDestination`, `ses:DeleteConfigurationSetEventDestination`
    - **Email Templates** — `ses:CreateEmailTemplate`, `ses:UpdateEmailTemplate`, `ses:DeleteEmailTemplate`, `ses:GetEmailTemplate`, `ses:ListEmailTemplates`
    - **Suppression List** — `ses:ListSuppressedDestinations`, `ses:DeleteSuppressedDestination`
    - **Contact Lists** — `ses:ListContactLists`, `ses:GetContactList`, `ses:CreateContactList`, `ses:UpdateContactList`, `ses:ListContacts`, `ses:GetContact`, `ses:CreateContact`, `ses:UpdateContact`, `ses:DeleteContact`
    - **Resource Tagging** — `ses:TagResource`, `ses:UntagResource`
    - **EventBridge** — `events:DescribeRule`, `events:ListTargetsByRule`
    - **Stack discovery** — `cloudformation:ListStacks`, `cloudformation:DescribeStacks`

    See [IAM Permissions Explained](/aws-setup/iam-permissions) for a full breakdown of every permission and why it is required.
  </Step>

  <Step title="Paste the Role ARN in SendOps">
    After the role is created, open it in the IAM console and copy its **ARN** (e.g., `arn:aws:iam::123456789012:role/SendOpsRole`).

    Back in the Setup Guide, paste the Role ARN and click **Validate**. SendOps will perform an `AssumeRole` call to verify the connection.
  </Step>


## Verifying the connection

Once the AWS Integration is complete (via either method), SendOps attempts to assume the role. If the connection succeeds you will see a green **"AWS account connected"** confirmation showing the Role ARN and region. If it fails, double-check:

- The **SendOps Account ID** in the trust policy matches exactly.
- The **External ID** in the trust policy condition matches the value shown in SendOps.
- The role's permissions policy is attached (not just the trust policy).
- The selected **AWS Region** matches the region where the role and SES are configured.

## What's next?

After completing the AWS Integration phase, click **Continue** to proceed to **Connection Validation**. In this phase, you click **Run Validation** to trigger an asynchronous check that verifies your CloudFormation stack resources (SES configuration set, EventBridge rule, webhook target) and probes your SES account status (sending enabled, sandbox mode, sending limits, verified identities). For a detailed breakdown of every IAM permission SendOps requests, see [IAM Permissions Explained](/aws-setup/iam-permissions).