This isn't a long, or especially interesting post, it just describes something I needed to do the other day, and couldn't explicitly find anywhere that described how to do it. As the title suggests, it shows how to create and AWS IAM policy that allows an IAM role used by CodeBuild for continuous integration to call the AWS Simple Email Service (SES) mailbox simulator. What a mouthful.
tl;dr; Click here to jump to the policy.
The AWS SES mailbox simulator
If you're working with the AWS SES service, then the mailbox simulator is a great tool. It allows you to test sending email without actually sending email. Consequently you get none of the risk of reputation damage due to bounces, being marked as spam, or simply accidentally sending mail when you don't need to.
On top of the safety aspect, the mailbox simulator lets you test out a variety of scenarios. By sending emails to a special email address through SES, you can make SES respond as though the email is rejected, bounced, or marked as spam for example. That lets you test how your application/infrastructure handles these events, without needing the events themselves to occur. The mailbox simulator integrates with your SNS WebHooks and inbound mailboxes to generate events as though emails were really sent.
As an example (and as we'll refer to them later), these are the currently available mailbox addresses, and a brief description of their behaviour:
success@simulator.amazonses.com
- accepts the emailbounce@simulator.amazonses.com
- generates a hard bounce notificationooto@simulator.amazonses.com
- generates an "out of office" (i.e. soft bounce) notificationcomplaint@simulator.amazonses.com
- generates a complaint notification, as if a user marked your email as spamsuppressionlist@simulator.amazonses.com
- rejects the email as though the recipient is on the SES suppression list
I was building out an application that was integrating with SES. To test the various scenarios, I created a number of integration tests which would call the mailbox simulator with each of those emails, and verify that the application responded correctly. Everything was working correctly, so I pushed my code to the build server, and waited for CodeBuild to build the app.
User is not authorized to perform ses:SendEmail
Unfortunately, while the build passed, my integration tests did not. After a bit of trial and error, I finally got the tests to print some useful logs, and found the following AWS SDK error :
MyEmailApp.EmailProvider Error
Error sending email with AWS SES: Amazon.SimpleEmail.AmazonSimpleEmailServiceException:
User `arn:aws:sts::123456789:assumed-role/codebuild-service-role/AWSCodeBuild-1614d5f-b7d1-adc53-dd94-09ea3b2864ec' is not authorized to perform `ses:SendEmail' on resource `arn:aws:ses:eu-west-1:123456789:identity/example.com'
---> Amazon.Runtime.Internal.HttpErrorResponseException: Exception of type 'Amazon.Runtime.Internal.HttpErrorResponseException' was thrown.
Luckily, although verbose, the error is fairly self-explanatory. The role that the CodeBuild agent is using (defined when you create the CodeBuild job) doesn't have permission to send email with the configured identity.
Configuring SES in general is a mammoth job so check the docs for details. In short, you can have multiple sending identities, and the role assigned to the application must have the
ses:SendEmail
for that identity to send email with SES.
With the problem identified, the question was how to enable the CodeBuild role to send email to the simulator. The key point was that I only wanted it to be able to send to the simulator. I didn't want our CI build to be able to accidentally start sending real emails out!
Unfortunately, it wasn't easy to find anything about this directly. Luckily, there are example policies for controlling access to SES in general, and one of these got me 90% of the way there.
Enabling ses:SendEmail
for the mailbox simulator
As with most of AWS, you can finely control access to all the features of SES based on a user's role by using policies. The SES policies also allow a number of useful conditionals, for controlling when to apply the policy. For example, you can instruct SES to only allow a role to send emails during specific hours.
In our case, it's the ability to restrict the recipient's email address that we need. The following IAM policy allows the user to send emails, but only when the recipient address ends with @simulator.amazonses.com
:
{
"Version": "2012-10-17",
"Statement": [
{
"Sid": "AllowSendingEmailsToSimulatorWithSES",
"Effect": "Allow",
"Action": "ses:SendEmail",
"Resource": "*",
"Condition": {
"ForAllValues:StringLike": {
"ses:Recipients": "*@simulator.amazonses.com"
}
}
}
]
}
Applying this policy to the CodeBuild role inside IAM meant the integration tests could call the mailbox simulator as part of the build. However, if the integration tests ever try to send to a real recipient, whether by accident or intentionally, it'll get a permission error at runtime.
This could also be useful outside of the continuous integration context I was using it for. For example you may decide you don't want your developers to be able to send real emails with the "production" identity, but you want them to to be able to test against the mailbox simulator. If so, then you could combine this policy with a condition that restricts the ses:FromAddress
field, as shown in the documentation samples.
Summary
The mailbox simulator is a really useful tool for testing out the various scenarios your app will face when you're integrating with SES. If you want to call the simulator as part of a continuous integration build, then you'll need to make sure that the IAM user/role that is running the build has permission to send emails with SES. The policy I showed in this post restricts the user to using the simulator only, so there's no chance of accidentally sending real email as part of your build.