(mis-)Adventures with Amazon Simple Email Services (SES)
Amazon has recently launched a new service as part of its web-services offerings - Amazon Simple Email Service (or SES for short), an HTTP API for sending Emails. The main selling points are Amazon's usual scalability power, as well as a relatively low price point for sending Emails (10 cents per 1000 Emails, not counting bandwidth). They also promise to improve deliverability using filters and feedback loops.
Having used Sendgrid for a while at our startup, Binpress, we were overall satisfied with their service. We did have some problems with seemingly innocent Emails ending up in spam boxes, and combined with the better pricing we thought Amazon SES deserved a shot.
This ain't no rocket science
Amazon's claims of simplicity would be justified indeed if you compare it with building a complete Email sending infrastructure with similar scaling power as their own offering. However, compared to integrating competitors such as Sendgrid or any SMTP based service, SES integration is anything but simple.
Using any SMTP abstraction class, integrating an SMTP service involves passing the credentials and service endpoint IP. That's it. We use the Zend_Mail component from the Zend Framework and our code looked like this:$config = array('auth' = 'login', 'username' = 'firstname.lastname@example.org', 'password' = 'ourpassword'); $transport = new Zend_Mail_Transport_Smtp('smtp.sendgrid.net', $config); A $mail = new Zend_Mail(); // Prepare mail $mail - send($transport);
Pretty straightforward. Getting Amazon SES up and running was anything but. I ended up writing a nice SES abstraction and even a Zend_Mail transport to go with it (you can check out the code here if you are not interested in the details).
Requests and authentication
The first hurdle to overcome is using Amazon's authentication scheme. Unlike most HTTP APIs, Amazon doesn't pass a request signature as a request parameter. Instead, it uses a custom HTTP header called 'X-Amzn-Authorization' - the documentation of which is hidden in one of the inner pages of the docs as a seemingly meaningless footnote. You cannot do anything without authorizing first! this section should've been front and center and explained much more clearly.
Since we need custom headers, that immediately rules out something simple like file_get_contents() (which probably should be avoided anyway for it's simplistic error handling). My first thought was to use cURL, like I do with most HTTP APIs - however after struggling with it for around an hour, I came to realize that cURL (at least for PHP) doesn't allow you to specify custom headers that are not a part of the HTTP standard - like Amazon's authentication header.
I briefly considered using http_request(), however that requires installing a PECL extension that is not bundled with the default installation, so that was scraped. The only viable option left for me was to construct the HTTP request myself from scratch and negotiate with the SES API using socket functions. Simple, right?
Luckily, SES docs do provide example requests. Being this was the first time for me to experiment with raw HTTP requests and socket connecti
Truncated by Planet PHP, read more at the original (another 5829 bytes)