プログラマでありたい

おっさんになっても、プログラマでありつづけたい

RubyからAmazon SESでメールを送る

 プログラムからちょこっとメールを送りたい時って、ありますよね?メールサーバを立てること自体はそれ程大変ではないですが、維持管理していくのは昨今非常に面倒くさいです。またスパム撲滅の為にプロバイダの規制が多くて、気が付いたら送れなくなっていたということもあります。
 そんな時にお薦めなのが、Amazon Simple Email Service (Amazon SES)。プログラムからメールを送るのに最適なサービスです。料金も安くて、1,000通あたりで$0.10。使わない手はないですね。ということで、Rubyから使う方法を簡単にまとめてみました。そんなに難しくないのですが、DKIM署名の辺りが面倒くさいかなぁと思います。

サインアップ

 本格的に使うには、管理コンソールからRequest Production Accessを行う必要があります。これは、任意のアドレスからメールを送る為に必要です。人間系でチェックしているようで、1〜2営業日程度必要な模様です。

 テスト程度で使う場合は、送信元メールアドレスの認証のみで大丈夫です。Verify a New Senderでメールアドレスを登録すると、確認メールが送られます。そのURLを開くと認証されます。以降、そのアドレスはSESで送る際の送信元アドレスとして使用できます。

インストール

基本的にgemでインストールだけです。簡単

# gem install aws-sdk
Fetching: uuidtools-2.1.2.gem (100%)
Fetching: multi_xml-0.4.1.gem (100%)
Fetching: httparty-0.8.1.gem (100%)
When you HTTParty, you must party hard!
Fetching: nokogiri-1.5.0.gem (100%)
Building native extensions.  This could take a while...
ERROR:  Error installing aws-sdk:
        ERROR: Failed to build gem native extension.

        /usr/local/bin/ruby192 extconf.rb
extconf.rb:10: Use RbConfig instead of obsolete and deprecated Config.
checking for libxml/parser.h... yes
checking for libxslt/xslt.h... no
-----
libxslt is missing.  please visit http://nokogiri.org/tutorials/installing_nokogiri.html for help with installing dependencies.
-----
*** extconf.rb failed ***
Could not create Makefile due to some reason, probably lack of
necessary libraries and/or headers.  Check the mkmf.log file for more
details.  You may need configuration options.

Provided configuration options:
        --with-opt-dir
        --without-opt-dir
        --with-opt-include
        --without-opt-include=${opt-dir}/include
        --with-opt-lib
        --without-opt-lib=${opt-dir}/lib
        --with-make-prog
        --without-make-prog
        --srcdir=.
        --curdir
        --ruby=/usr/local/bin/ruby192
        --with-zlib-dir
        --without-zlib-dir
        --with-zlib-include
        --without-zlib-include=${zlib-dir}/include
        --with-zlib-lib
        --without-zlib-lib=${zlib-dir}/lib
        --with-iconv-dir
        --without-iconv-dir
        --with-iconv-include
        --without-iconv-include=${iconv-dir}/include
        --with-iconv-lib
        --without-iconv-lib=${iconv-dir}/lib
        --with-xml2-dir
        --without-xml2-dir
        --with-xml2-include
        --without-xml2-include=${xml2-dir}/include
        --with-xml2-lib
        --without-xml2-lib=${xml2-dir}/lib
        --with-xslt-dir
        --without-xslt-dir
        --with-xslt-include
        --without-xslt-include=${xslt-dir}/include
        --with-xslt-lib
        --without-xslt-lib=${xslt-dir}/lib


Gem files will remain installed in /usr/local/lib/ruby/gems/1.9.1/gems/nokogiri-1.5.0 for inspection.
Results logged to /usr/local/lib/ruby/gems/1.9.1/gems/nokogiri-1.5.0/ext/nokogiri/gem_make.out


 nokogiriが足りないのでインストールしようとしたら、libxsltがないと怒られました。yumでさっくり入れることにします。今回の環境では入っていましたが、libxmlもいるようなので無ければlibxml2-develも入れておく必要がありますね。ヘッダーモジュールインストール後に再度gem installでaws-sdkのインストールは完了します。

yum install libxslt-devel

サンプルコードでお勉強

git clone git://github.com/amazonwebservices/aws-sdk-for-ruby.git
cd aws-sdk-for-ruby/

残念ながら、サンプルコードの中にはSESの例は無いです!!

日本語メール(ISO-2022-JP)の送り方

# -*- encoding: utf-8 -*-
require 'rubygems'
require 'aws-sdk'
require 'nkf'

ses = AWS::SimpleEmailService.new(
  :access_key_id => 'your access key',
  :secret_access_key => 'your secret access key')


#ISO-2022-jp
body_text = NKF.nkf('-jw','本文Test')
subject = NKF.nkf('-Mw', 'タイトルTest')

ses.send_email(
  :subject => subject,
  :to => 'hoge@example.com',
  :from => 'hoge@example.com',
  :body_text => body_text,
  :body_text_charset => 'ISO-2022-JP'
)


 ちなみにGmailで受信すると下記のような文言が付きます。

hoge@example.com email-bounces.amazonses.com 経由

 これはどういうことかと言うと、送信元アドレスのドメインとメールサーバのドメインが違うので詐称に注意ということで表示しているようです。このままだとスパム扱いされる可能性が高いので、何とかする必要があります。こんな時の対応としては、一般的にはSPFレコード・Sender IDを設定、もしくはDKIM署名を付けるという方法があります。今回はDKIM署名の対応を試してみます。FAQを読むと、DKIM署名を使う場合は次のように書いてあります。
AWS Simple Email Service FAQs

また、クライアントアプリケーション内からEメールメッセージに署名することができます。単純にEメールメッセージを作成し、メッセージを DKIM 署名し、DKIM-Signature ヘッダーフィールドをメッセージの前に付け、SendRawEmail API でそれを送信します。

 アプリで自分で署名して、SendRawEmail APIで送れとのことです。
ということで署名の作成。

$ openssl genrsa -out ses.key.pem 1024
$ openssl rsa -in ses.key.pem -out ses.key.pub -pubout -outform PEM


DNS登録

Name: ses._domainkey
Type: TXT
Vale: "v=DKIM1; k=rsa; t=y; p=(ses.key.pubのバリュー部分)"


改めてSESでDKIM署名をして送信

# -*- encoding: utf-8 -*-
require 'rubygems'
require 'aws-sdk'
require 'nkf'
require 'dkim'

#ses = AWS::SimpleEmailService.new(
ses = AWS::SimpleEmailService.new(
  :access_key_id => 'your access key',
  :secret_access_key => 'your secret access key')

Dkim::domain = 'example.com'
Dkim::selector = 'ses'
Dkim::private_key = open("ses.key.pem").read

Dkim::signable_headers  = Dkim::DefaultHeaders - %w{Message-Id Resent-Message-ID Date Return-Path Bounces-To}

subject = "title"
body_text = NKF.nkf('-jw','本文Test')
subject = NKF.nkf('-Mw', 'タイトルTest')
mail = <<EMAIL
To: to@example.com
From: from@example.com
Subject: body_text

Test
EMAIL

mail_signed = Dkim.sign(mail)

ses.send_raw_email(mail_signed)

 無事送れて問題も無いようです。
個人的な感想ですが、実運用を考えるとSESでDKIM署名は必須になるのではないかと思います。しかし、現状ではsend_raw_emailで全部手書きで送るのは、中々骨が折れます。ここの部分、基本のsend_emailのオプションで何とか出来るようにしてくれないかと切に願います。

Railsで利用

 基本的には、action_mailerの部分にsesを指定すれば使えます。
Class: AWS::SimpleEmailService — AWS SDK for Ruby
environments/環境名.rbの編集

config.action_mailer.raise_delivery_errors = true
config.action_mailer.delivery_method = :amazon_ses


Enjoy!!