Amazon SES IAM Permissions Explained: Least-Privilege Policies for Sending Email

Isometric illustration of a teal vault with a shield lock, a faded stack of IAM policy documents, and a single purple key floating beside it.

The IAM action that lets your code call SendEmail is the same one that lets it delete every verified domain in your account. AWS ships a managed policy called AmazonSESFullAccess that grants both, and most teams attach it because it is the path of least resistance. According to the AWS Service Authorization Reference, Amazon SES has more than 80 distinct IAM actions, and the average sending integration uses two of them.

This post shows the real least-privilege policies for the four most common Amazon SES integration patterns: send-only, send plus identity management, send plus suppression list, and full BYO-SES management layer. Every policy is copy-paste ready, and every action name comes from the AWS docs - no guessing.

How SES permissions work (actions, resources, conditions)

Every Amazon SES API call is gated by three things: an IAM action (what verb you can call), a resource ARN (which identity it applies to), and optional condition keys (when and how it applies). For email-sending APIs, the resource is the verified identity ARN, formatted as arn:aws:ses:<region>:<account-id>:identity/<domain-or-email>. For account-level actions like reading sending statistics, the resource is usually * because the action is not scoped to a single identity.

Two API versions matter, but both share the same ses: IAM service prefix. The original v1 actions are ses:SendEmail, ses:SendRawEmail, and ses:SendBulkTemplatedEmail. The v2 API adds new action names like ses:SendBulkEmail, ses:CreateEmailIdentity, and the v2-only suppression list and configuration set APIs. The SMTP interface is gated by ses:SendRawEmail, so any SMTP-based integration needs that action at a minimum.

Condition keys give you finer control. The five most useful ones are ses:FromAddress, ses:FromDisplayName, ses:Recipients, ses:FeedbackAddress, and ses:ApiVersion. These let you write policies like "this key can only send from marketing@example.com" without changing the application code that uses the key.

Send-only IAM policy (the most common case)

For a server, Lambda function, or SaaS tool that only sends transactional email and never manages domains or lists, the policy is two actions on a wildcard resource. This is the policy the AWS docs themselves recommend for "Allowing Access to Email-Sending Actions Only" and it is the right starting point for any send-only integration.

{
  "Version": "2012-10-17",
  "Statement": [
    {
      "Sid": "SendOnly",
      "Effect": "Allow",
      "Action": [
        "ses:SendEmail",
        "ses:SendRawEmail"
      ],
      "Resource": "*"
    }
  ]
}

If you know exactly which domain or mailbox the integration sends from, scope the resource to that identity instead of *. The example below limits the user to sending from example.com and any of its sub-identities (a verified mailbox at noreply@example.com is a sub-identity of the domain identity).

{
  "Version": "2012-10-17",
  "Statement": [
    {
      "Sid": "SendFromExampleDotCom",
      "Effect": "Allow",
      "Action": [
        "ses:SendEmail",
        "ses:SendRawEmail"
      ],
      "Resource": [
        "arn:aws:ses:us-east-1:123456789012:identity/example.com"
      ]
    }
  ]
}

For full BYO-SES setup walkthroughs that show where this key gets used, see our amazon ses setup guide.

Send + identity management (for tools that verify domains)

If the integration verifies new domains on the customer's behalf (for example, a marketing tool that adds a "Connect your domain" flow), it needs identity creation and verification status reads on top of the send actions. The minimum extra actions are ses:CreateEmailIdentity (v2), ses:GetEmailIdentity (v2), and ses:VerifyDomainIdentity (v1, still used by older SDKs). For DKIM verification status, add ses:GetIdentityDkimAttributes.

{
  "Version": "2012-10-17",
  "Statement": [
    {
      "Sid": "Send",
      "Effect": "Allow",
      "Action": [
        "ses:SendEmail",
        "ses:SendRawEmail"
      ],
      "Resource": "*"
    },
    {
      "Sid": "ManageIdentities",
      "Effect": "Allow",
      "Action": [
        "ses:CreateEmailIdentity",
        "ses:GetEmailIdentity",
        "ses:ListEmailIdentities",
        "ses:VerifyDomainIdentity",
        "ses:VerifyDomainDkim",
        "ses:GetIdentityVerificationAttributes",
        "ses:GetIdentityDkimAttributes",
        "ses:PutEmailIdentityMailFromAttributes"
      ],
      "Resource": "*"
    }
  ]
}

Notice we did not include ses:DeleteEmailIdentity or ses:DeleteIdentity. That action is destructive and a leaked key with delete rights can wipe verified domains and force a re-verification cycle that takes 24-72 hours. Only grant deletion permissions to a separate admin role that humans assume, not to the application's IAM user.

Send + suppression list (for tools that manage bounces)

The Amazon SES account-level suppression list automatically captures bounces and complaints and prevents future sends to those addresses. Tools that want to display the suppression list, add addresses, or remove false positives need the v2 suppression APIs. According to AWS documentation, the relevant actions are ses:PutSuppressedDestination, ses:DeleteSuppressedDestination, ses:GetSuppressedDestination, and ses:ListSuppressedDestinations.

{
  "Version": "2012-10-17",
  "Statement": [
    {
      "Sid": "Send",
      "Effect": "Allow",
      "Action": [
        "ses:SendEmail",
        "ses:SendRawEmail"
      ],
      "Resource": "*"
    },
    {
      "Sid": "SuppressionList",
      "Effect": "Allow",
      "Action": [
        "ses:GetSuppressedDestination",
        "ses:ListSuppressedDestinations",
        "ses:PutSuppressedDestination",
        "ses:DeleteSuppressedDestination",
        "ses:PutAccountSuppressionAttributes",
        "ses:GetAccountSendingEnabled",
        "ses:GetAccount"
      ],
      "Resource": "*"
    }
  ]
}

The ses:GetAccount action is what surfaces the sandbox status and the daily sending quota - any tool that displays "you can send X more emails today" needs it. If your bounce rate gets you into trouble, our SES account suspended fix guide walks through the remediation path and which of these APIs you need to call to investigate.

Send + configuration sets + event destinations (full integration)

The most permissive policy a legitimate sending integration should ever need is the one for a full BYO-SES management layer: send, manage identities, manage the suppression list, plus create configuration sets and event destinations so per-campaign analytics (opens, clicks, bounces, complaints) flow back to the tool. Mailblast uses a policy similar to the one below when connecting a customer's SES account.

{
  "Version": "2012-10-17",
  "Statement": [
    {
      "Sid": "Send",
      "Effect": "Allow",
      "Action": [
        "ses:SendEmail",
        "ses:SendRawEmail",
        "ses:SendBulkEmail"
      ],
      "Resource": "*"
    },
    {
      "Sid": "Identities",
      "Effect": "Allow",
      "Action": [
        "ses:CreateEmailIdentity",
        "ses:GetEmailIdentity",
        "ses:ListEmailIdentities",
        "ses:VerifyDomainDkim",
        "ses:GetIdentityVerificationAttributes",
        "ses:GetIdentityDkimAttributes",
        "ses:PutEmailIdentityMailFromAttributes"
      ],
      "Resource": "*"
    },
    {
      "Sid": "ConfigSets",
      "Effect": "Allow",
      "Action": [
        "ses:CreateConfigurationSet",
        "ses:DescribeConfigurationSet",
        "ses:GetConfigurationSet",
        "ses:ListConfigurationSets",
        "ses:CreateConfigurationSetEventDestination",
        "ses:UpdateConfigurationSetEventDestination",
        "ses:DescribeConfigurationSetEventDestinations",
        "ses:DeleteConfigurationSetEventDestination"
      ],
      "Resource": "*"
    },
    {
      "Sid": "Suppression",
      "Effect": "Allow",
      "Action": [
        "ses:GetSuppressedDestination",
        "ses:ListSuppressedDestinations",
        "ses:PutSuppressedDestination",
        "ses:DeleteSuppressedDestination"
      ],
      "Resource": "*"
    },
    {
      "Sid": "AccountInfo",
      "Effect": "Allow",
      "Action": [
        "ses:GetAccount",
        "ses:GetSendQuota",
        "ses:GetSendStatistics"
      ],
      "Resource": "*"
    }
  ]
}

That is 26 specific actions instead of the 80+ that AmazonSESFullAccess grants. The table below shows how each integration pattern stacks up.

Pattern Actions granted Identity mgmt Suppression list Config sets Destructive APIs
Send-only 2 No No No None
Send + identities 10 Read + create No No None
Send + suppression 9 No Full No Delete suppression entries
Full BYO-SES (recommended) 26 Read + create Full Full Config set + suppression deletes
AmazonSESFullAccess (managed) 80+ Full incl. delete Full Full All including delete identity
Source: AWS Service Authorization Reference for Amazon SES.

Restricting by resource (from-address scoping, identity ARNs)

For send actions, the Resource element accepts identity ARNs. Set it to a list of the specific domains the integration is allowed to send from, and SES will reject any SendEmail call whose From address resolves to a different identity. The ARN format is arn:aws:ses:<region>:<account-id>:identity/<domain> for domain identities and arn:aws:ses:<region>:<account-id>:identity/<email> for verified mailboxes.

{
  "Version": "2012-10-17",
  "Statement": [
    {
      "Sid": "SendFromMarketingAndTransactional",
      "Effect": "Allow",
      "Action": [
        "ses:SendEmail",
        "ses:SendRawEmail"
      ],
      "Resource": [
        "arn:aws:ses:us-east-1:123456789012:identity/marketing.example.com",
        "arn:aws:ses:us-east-1:123456789012:identity/tx.example.com"
      ]
    }
  ]
}

For even tighter control, layer a condition key onto a resource-scoped statement. The policy below restricts a key to sending only as marketing@example.com, only to recipients at @example.com, only over TLS:

{
  "Version": "2012-10-17",
  "Statement": [
    {
      "Sid": "LockedDownMarketingKey",
      "Effect": "Allow",
      "Action": [
        "ses:SendEmail",
        "ses:SendRawEmail"
      ],
      "Resource": "arn:aws:ses:us-east-1:123456789012:identity/example.com",
      "Condition": {
        "StringEquals": {
          "ses:FromAddress": "marketing@example.com",
          "aws:SecureTransport": "true"
        },
        "ForAllValues:StringLike": {
          "ses:Recipients": ["*@example.com"]
        }
      }
    }
  ]
}

aws:SecureTransport blocks any request that arrives over plain HTTP. There is no legitimate reason to call the SES API without TLS, and adding this condition is free defence against misconfigured clients.

Common IAM mistakes

Most BYO-SES security incidents come from the same handful of patterns. Here are the ones we see most often when reviewing customer setups.

Attaching AmazonSESFullAccess to the application user. This is the single most common mistake. The managed policy grants every SES action including ses:DeleteIdentity, ses:DeleteConfigurationSet, and ses:PutAccountSendingAttributes (which can disable sending account-wide). A leaked key with this policy can destroy a SES tenancy in seconds. Replace it with one of the scoped policies above.

Using the AWS account root user for SES API calls. Root credentials cannot be scoped and cannot have MFA enforced on programmatic access. AWS documentation explicitly recommends never using root for daily operations. Create an IAM user (or better, an IAM role) for every integration.

Wildcard resources on actions that support scoping. Setting Resource: "*" on ses:SendEmail means the key can send from any verified identity in the account. If you only ship from one or two domains, list those identity ARNs explicitly. The policy gets a few lines longer and the blast radius of a leak gets a lot smaller.

Storing access keys in environment files committed to git. Even private repositories leak. Use AWS Secrets Manager, your platform's secret store (Vercel, Fly.io, Render all have one), or instance profile credentials via IAM roles. Mailblast stores customer SES credentials encrypted at rest with per-tenant keys for exactly this reason.

Granting send permissions to every developer in the org. Send credentials in dev hands means production sending from laptops, debugging campaigns leaking to real customer addresses, and audit trails that point to "the team" instead of one identifiable principal. Use a sandbox SES account for dev, and gate production access through assume-role with logging.

Credential rotation and security best practices

Rotate access keys every 90 days at minimum. AWS Access Analyzer surfaces unused keys older than 90 days for free, and you can automate rotation with AWS Secrets Manager rotation Lambdas. For long-lived integrations, prefer IAM roles over access keys entirely: an EC2 instance, Lambda function, or ECS task can assume a role and get short-lived credentials via the instance metadata service, eliminating the long-lived secret from your environment.

Enable AWS CloudTrail in the same region as your SES sending (and in the recipient regions if you use multi-region). Every SES API call gets logged with the principal, source IP, and parameters. If a key leaks, CloudTrail tells you exactly what the attacker did - which identities they tried to send from, which domains they verified, whether they touched the suppression list. Set up a CloudWatch alarm on ses:DeleteIdentity calls and on any SES action from an unfamiliar source IP.

Finally, separate the sending key from the management key. The key your application uses to send transactional email should not have ses:CreateEmailIdentity permissions. Domain verification happens once at onboarding, not continuously from production. Two keys with two scoped policies is more work to set up and dramatically smaller blast radius when one of them inevitably leaks.

FAQ

What is the minimum IAM permission needed to send email through SES?

The safe minimum is granting both ses:SendEmail and ses:SendRawEmail. The v1 API and SMTP interface require ses:SendRawEmail because every SMTP message is serialised as raw MIME. The v2 API uses ses:SendEmail. Most SDKs fall back to v1 under the hood, so listing both covers every code path.

Is AmazonSESFullAccess safe for third-party integrations?

No, not by least-privilege standards. AmazonSESFullAccess is just ses:* and grants every action including identity deletion, account-level configuration changes, and IP pool management. If the key leaks, an attacker can delete your verified domains and lock you out of sending. Use a scoped policy and restrict the resource ARN to specific identities.

How do I restrict an IAM user to send only from one domain?

Set the policy Resource element to the identity ARN, for example arn:aws:ses:us-east-1:123456789012:identity/example.com. SES rejects any SendEmail whose From address resolves to a different identity. Layer a ses:FromAddress condition key on top to lock the user to a specific mailbox like marketing@example.com.

What is the difference between IAM policies and SES sending authorization policies?

IAM policies control which principals in your AWS account can call SES APIs. Sending authorization policies are attached to a verified identity and let an external AWS account send as that identity. You need IAM policies for your own integrations. You only need sending authorization policies when a partner or tenant sends from your domain.

Do I need separate IAM permissions for SES v1 and v2?

No, both share the ses: service prefix. The difference is action names: v1 uses ses:SendEmail, ses:SendRawEmail, ses:DeleteIdentity; v2 adds ses:SendBulkEmail, ses:DeleteEmailIdentity, and the suppression list APIs. Tight policies list every action by name and verify it against the AWS Service Authorization Reference.


Mailblast is a hosted email marketing platform that runs on top of your own Amazon SES account. We connect via a scoped IAM key with the BYO-SES policy shown above - no AmazonSESFullAccess, no ses:DeleteIdentity, no surprises. You own the SES tenancy, the verified domains, and the access keys at all times.

Ready to Start Your Email Marketing Journey?

Join thousands of businesses using Mailblast to grow their audience.

← Back to Blog