Usando o Amazon Simple E-mail Service com ActionMailer no Rails


Leia em 3 minutos

Enviar e-mail em aplicações web é uma tarefa comum, mas sempre temos que decidir como elas serão enviadas: servidor SMTP, GMail, Sendmail, serviços como Postmark e Mad Mimi… Todos eles são alternativas viáveis, algumas mais simples, outras nem tanto assim.

No final de 2010 a Amazon lançou o Amazon SES (Simple E-mail Service), um serviço que permite enviar e-mails usando um webservice da Amazon. Obviamente o serviço é pago, mas com um preço muito justo: apenas 0.10 USD por cada mil mensagens enviadas.

Mesmo sendo pago o Amazon SES tem um modelo um pouco diferente. Você precisa solicitar acesso para envio em massa. Neste processo é necessário informar o site que usará o webservice e quantidade de mensagens que você espera enviar diariamente. Após a aprovação, que no meu caso não demorou muito mais que 30 minutos, você ainda não poderá enviar a quantidade de e-mails solicitada; a quota diária é aumentada com o passar do tempo, seguindo a tabela abaixo:

Note que você precisa efetivamente consumir sua quota para que os valores sejam aumentados.

Configurando o Amazon SES

O primeiro passo é baixar os arquivos que você usará na linha de comando. Acesse o endereço http://aws.amazon.com/developertools/Amazon-SES, baixe os scripts e descompacte o arquivo baixado.

No diretório, terão alguns scripts (sic) Perl para configurar o Amazon SES. Mas antes de usá-los, você precisa criar um arquivo contendo suas credenciais da Amazon. Acesse o endereço http://aws-portal.amazon.com/gp/aws/developer/account/index.html?action=access-key para ver suas chaves de acesso (Access Key e Secret Key). Crie um arquivo chamado aws-credentials utilizando o formato abaixo.

AWSAccessKeyId=022QF06E7MXBSH9DHM02
AWSSecretKey=kWcrlUX5JEDGM/LtmEENI/aVmYvHNif5zB+d9+ct

O próximo passo é verificar o e-mail que será utilizado para enviar as mensagens. Vá ao diretório contendo os scripts e execute o seguinte comando:

$ ./ses-verify-email-address.pl -k aws-credentials -v seu@email.com.br

Você receberá uma mensagem da Amazon com um endereço para confirmar esse e-mail cadastrado. Depois que você fez esta confirmação, já poderá enviar e-mail de testes apenas para os endereços confirmados. Você pode testar o e-mail com o comando abaixo:

$ echo Hello Amazon SES | ./ses-send-email.pl -k aws-credentials -s \
"Testando Amazon SES" -f seu@email.com.br seu@email.com.br

Se tudo deu certo, você receberá a mensagem em pouco tempo.

Configurando o Ruby on Rails

Para usar o Amazon SES no Ruby precisaremos de uma biblioteca chamada Amazon SES Mailer. Para instalá-la, execute o comando abaixo.

$ gem install amazon-ses-mailer

Depois de instalado, você pode criar um arquivo de configuração contendo suas credenciais usadas naquele arquivo aws-credentials. Crie um arquivo config/aws.yml com o seguinte conteúdo:

secret_key: "kWcrlUX5JEDGM/LtmEENI/aVmYvHNif5zB+d9+ct"
access_key: "022QF06E7MXBSH9DHM02"

Agora, você não vai querer configurar o ambiente de desenvolvimento com o Amazon SES. Mesmo sendo barato, não faz sentido pagar por algo que pode ser feito gratuitamente. Então, no arquivo config/environments/production.rb, adicione as seguintes linhas:

config.after_initialize do
  ActionMailer::Base.tap do |am|
    credentials = YAML.load_file(config.root.join("config/aws.yml")).symbolize_keys
    am.delivery_method = AmazonSes::Mailer.new(credentials)
    am.perform_deliveries = true
  end
end

No trecho acima estamos definindo o método de envio como sendo uma instância da classe AmazonSes::Mailer, que implementa a interface do ActionMailer. Na prática, só é preciso definir os métodos SomeClass#initialize(options) e SomeClass#deliver!(mail).

Para o ambiente de desenvolvimento, eu uso o Sendmail como método de envio. Eu gosto de receber os e-mails enquanto desenvolvo. Neste caso, faço duas coisas. Primeiro, adiciono as configurações ao arquivo config/environments/development.rb.

config.after_initialize do
  ActionMailer::Base.tap do |am|
    am.register_interceptor(MyApp::MailerInterceptor)
    am.delivery_method = :sendmail
    am.perform_deliveries = true
    am.raise_delivery_errors = true
  end
end

Perceba que estou definindo a opção ActionMailer::Base.register_interceptor. Este é um excelente modo de interceptar os e-mails que serão enviados, permitindo manipular os cabeçalhos e remetentes, por exemplo. Antes de criar a classe MyApp::MailerInterceptor, vamos adicionar o diretório lib ao load path; isso permitirá organizar nosso código sem muito esforço. No arquivo config/application.rb, adicione algo como isto:

module MyApp
  class Application < Rails::Application
    config.autoload_paths << config.root.join("lib")
  end
end

Agora, crie o arquivo lib/my_app/mailer_interceptor.rb. Ele será responsável por interceptar as mensagens, alterando o remetente para o seu próprio e-mail. O objeto que será usado como interceptador só precisa implementar o método delivering_email.

module MyApp
  module MailerInterceptor
    def self.delivering_email(email)
      email.body.raw_source << "\n\nEnviado originalmente para #{email.to.to_sentence}\n\n"
      email.to = "dev@email.com"
    end
  end
end

Pronto! Agora você tem uma aplicação que envia e-mails utilizando o Amazon SES e, de quebra, ainda consegue visualizar as mensagens enviadas em modo de desenvolvimento sem gastar nenhum centavo.