Sending E-Mail via Amazon SES over SMTP with IAM Roles
TL;DR: As of the date this post was published, sending e-mail via Amazon Simple E-mail Service (SES) over SMTP with IAM role credentials does not seem to work.
Earlier this week, I set out to wire up a Django application with Amazon SES for sending e-mail. Because the application is going to live in Amazon Elastic Compute Cloud (EC2), I decided to make use of IAM roles to provide the application with the credentials it needs to authenticate with SES. Unfortunately, the SMTP endpoint does not seem to accept the IAM role credentials.
IAM Roles
IAM roles are an elegant way to setup an EC2 instance for API access to other Amazon Web Services. All API requests must be signed with an access key and secret key, so it is usually up to you to populate the EC2 instance with the proper credentials. However, if you make use of IAM roles, an automatically rotated set of keys is provided to the instance via its metadata service:
$ curl http://169.254.169.254/latest/meta-data/iam/security-credentials/s3access
{
"Code" : "Success",
"LastUpdated" : "2012-04-26T16:39:16Z",
"Type" : "AWS-HMAC",
"AccessKeyId" : "AKIAIOSFODNN7EXAMPLE",
"SecretAccessKey" : "wJalrXUtnFEMI/K7MDENG/bPxRfiCYEXAMPLEKEY",
"Token" : "token",
"Expiration" : "2012-04-27T22:39:16Z"
}
Deriving SES SMTP Credentials
Once your application retrieves a set of keys from the metadata service, SecretAccessKey
needs to go through a little bit of a transformation before it can be used with the SES SMTP endpoint. Amazon’s pseudocode for the transformation algorithm follows:
key = AWS Secret Access Key;
message = "SendRawEmail";
versionInBytes = 0x02;
signatureInBytes = HmacSha256(message, key);
signatureAndVer = Concatenate(versionInBytes, signatureInBytes);
smtpPassword = Base64(signatureAndVer);
And for good measure, a translation of that into Python (for use with Django):
SES_SMTP_CONVERSION_HMAC_MESSAGE = 'SendRawEmail'
SES_SMTP_CONVERSION_VERSION = '\x02'
def hash_smtp_pass_from_secret_key(key):
h = hmac.new(key.encode('utf-8'),
SES_SMTP_CONVERSION_HMAC_MESSAGE,
digestmod=hashlib.sha256)
return base64.b64encode("{0}{1}".format(SES_SMTP_CONVERSION_VERSION,
h.digest()))
(Credit: Charles Lavery, Steve Lamb)
Authentication Credentials Invalid
After launching an EC2 instance associated with an IAM role that allows ses:SendEmail
, pulling credentials via the metadata service, and transforming the provided SecretAccessKey
, you’ll notice that the SMTP endpoint still returns 535 Authentication Credentials Invalid
.
I tried several approaches to make things work, but always without success. I even compiled the Java implementation of the transformation algorithm provided by AWS to compare inputs and outputs. Alas, I simply don’t think IAM role credentials work with the SES SMTP endpoint.