2012年10月20日土曜日

heroku+SendGrid+Play2+JavaMailでメールを送る

今回は、heroku上にホスティングしたPlayframeworkベースのアプリケーションからメールを送信してみようというお話です。
※この記事は「heroku上でPlayframework2のwelcomeページを表示させることはできた」という前提で進めます

herokuからメールを送る


まず、そもそもherokuからどうやってメールを送るの?というところから。

手段としては、外部にSMTPサーバを用意するってのが一番単純で、ググると「herokuからGMailのSMTP叩く」みたいなのは出てきます。出てくるんですが、これやるにはそのSMTPの認証情報を直書きしてpushしなきゃいけないので、「できるんだけど扱いにくいなぁ」という印象でした。うまくやる方法あるのかな?あったら教えて下さい。

で、今回はherokuアドオンに頼ることにします。

https://addons.heroku.com/sendgrid

SendGridというアドオンがあったので使ってみることにしました。
1日200通まで無料の「Starter」プランで送れるそうです。どんなメールを送るかによりますが、とりあえず試すには十分すぎるのでこれを使います。
コマンドでもWebからでもいいので、SendGrid Starterをサクっとアプリケーションに追加しちゃってください。

このSendGridというアドオンはどのような仕組みでメールを送っているかというと、

  • SMTPサーバ自体は外部にある
  • 認証情報をアドオンから環境変数に渡してくれる
  • あとはSMTP叩くだけ

という至極シンプルなものです。

これだけ書けばどうやってメール送るかは想像できるかもしれませんが、一応ひと通り書いていきます。

認証情報をPlayアプリケーションに渡す


herokuでPlayframework2ベースアプリケーションを動かすにはProcfileってのを作ったと思うので、これを編集して、環境変数をJavaシステムプロパティとしてアプリケーションに引渡します。DBを使わないメールのみ送れる一番単純なアプリだとこんな感じ。

web: target/start -Dhttp.port=${PORT} ${JAVA_OPTS} -Dmail.smtp.host=smtp.sendgrid.net -Dmail.smtp.port=587 -Dmail.smtp.auth=true -Dmail.smtp.user=${SENDGRID_USERNAME} -Dmail.smtp.pass=${SENDGRID_PASSWORD}

※1行です

SENDGRID_USERNAME、SENDGRID_PASSWORDという環境変数で認証情報が渡ってくるので、適当なプロパティ名つけて渡してやりましょう。mail.smtp.host、mail.smtp.port、mail.smtp.authについては、別にここで渡さなきゃいけないってことはないけども、設定値をハードコーディングしない的な意味でも、どうせJavaMailでPropertiesオブジェクトが必要だからこの方が楽という意味でも、システムプロパティとして渡してやった方が良いかと思います。

JavaMailでメール送信


あとはメール送るだけです。今回はJavaMail使います。

http://www.oracle.com/technetwork/java/javamail/index.html

もちろんmavenリポジトリ上にあるので、project/Build.scalaに1行追加すれば依存設定完了。

val appDependencies = Seq(
  // Add your project dependencies here,
  "javax.mail" % "mail" % "1.4.5"
)

で、あとはJavaMailから、システムプロパティの値を使ってメールを送信してやるだけ。

package controllers
import play.api._
import play.api.mvc._
object SendmailTest extends Controller {
def index = Action {
sendmail
Ok(views.html.index("ok"))
}
def sendmail = {
import java.util._
import javax.mail._
import javax.mail.internet._
val props = System.getProperties
val auth = new Authenticator {
override val getPasswordAuthentication =
new PasswordAuthentication(props.getProperty("mail.smtp.user"), props.getProperty("mail.smtp.pass"))
}
val session = Session.getInstance(props, auth)
val msg = {
val m = new MimeMessage(session)
m.setFrom(new InternetAddress("hiro@nisshiee.org"))
m.setRecipients(Message.RecipientType.TO, "hiro@nisshiee.org")
m.setSubject("This is test mail from heroku", "ISO-2022-JP")
m.setSentDate(new Date)
m.setText("これはテストメールです", "ISO-2022-JP")
m
}
Transport.send(msg)
}
}
view raw 01.scala hosted with ❤ by GitHub


※エラーハンドリングとかWebアプリ自体の認証とかせず、メール送信部分だけを記述しています

JavaMailの送信手順をScalaで記述しただけで、工夫とか何もしてませんけどね。
普通にこれで送信できます。

ね、簡単でしょ?