gomailを使ってローカルではmailhog・本番(Heroku)ではsendgridでメール送信する

メール送信機能をgoのアプリケーションにつけようと思ったけど、どうやってやろうかなー、と。で、ローカルではdockerでメールサーバー用意して、本番ではsendgridで行うようにした。

メール送信のパッケージにはgomailというものを使ってやるかな。

gomailを使ってメール送信する

以下のパッケージを使ってgoでメール送信をしようと思う。star数結構あるしね。ただ、コミットが数年前だったりするからなんとも言えない。

github.com

$ go get gopkg.in/gomail.v2

実装

とりあえず、サクッと試したいなら以下の記事にように書くと動くと思われる。

qiita.com

ローカルではmailhogを使う

ローカルでいちいちメール飛ばすのは怖いからブラウザでメールが確認できるものを使おう。mailhogだ。 dockerでアプリケーションを立ち上げているんだけど、mailhogにもimageがあるから別でコンテナを立ち上げて使うようにする。

docker-compose.ymlにmailhogの記述をする。

  mailhog:
    image: mailhog/mailhog
    ports:
      - "8025:8025"

これでdocker-compose upして、ブラウザで8025番ポートでアクセスすればこんな画面になる。

f:id:utr066:20190703105425p:plain

mailhogを使ってメール送信をすると、この画面にどんなメールが送信されたのかという内容が表示される。

あとは下記のSend()内にあるようなプログラムを書けば、メールがMailhogで確認できた。

package mailer

import (
  gomail "gopkg.in/gomail.v2"
)

type GoMailer struct {
    Message *gomail.Message
}

func NewMailer() *GoMailer {
    return &GoMailer{
        Message: gomail.NewMessage(),
    }
}

func (mailer *GoMailer) Send() {
    mailer.Message.SetHeader("From", "test@example.com")
    mailer.Message.SetHeader("To", "test@example.com")
    mailer.Message.SetHeader("Subject", "Hello!")
    mailer.Message.SetBody("text/plain", "Hello!")

    d := gomail.Dialer{Host: "mailhog", Port: 1025}
    if err := d.DialAndSend(mailer.Message); err != nil {
        panic(err)
    }
}

Host名は、docker-composeで指定したコンテナ名。Portは1025番で待ち受けているみたいね。

f:id:utr066:20190703105821p:plain

本番環境(heroku)ではsendgridを使う

今回はherokuでgoのアプリケーションを使っているから、herokuのアドオンを使ってメール送信しようと思う。まあ、メール送信といったらSendgridだよね。アドオン使うけど、別にアドオン使わないでもSendgridのAPI_KEYなんかを使えばメール送信できるはず。

heroku公式にアドオンの追加方法が書いてあるから、これを参考にやる。

devcenter.heroku.com

$ heroku addons:create sendgrid:starter

アドオンを追加したらsendgridのusernameとpasswordが勝手に発行されるっぽいね。以下でSENDGRID_USERNAMESENDGRID_PASSWORDが参照できる。

$ heroku config:get SENDGRID_USERNAME
$ heroku config:get SENDGRID_PASSWORD

ドキュメントを読んでいると、API_KEYを使ったメール送信方法が書いてあるけど、今回はAPI_KEYは使わないでいきたいんだよなあ。(ローカル用と本番用の記述が結構変わってしまいそうなので・・・)

なんかActionMailerの実装方法はちょっと載っているから、それを参考にしてgomailを使った実装する。やっぱりRailsでHeroku使う人が多いんだろうなあ。

   var d *gomail.Dialer
    if os.Getenv("ENV") == "prod" {
        d = gomail.NewDialer("smtp.sendgrid.net", 587, os.Getenv("SENDGRID_USERNAME"), os.Getenv("SENDGRID_PASSWORD"))
    } else {
        d = gomail.NewDialer("mailhog", 1025, "", "")
    }
    if err := d.DialAndSend(mailer.Message); err != nil {
        panic(err)
    }

ちょっと記述変えた。本番環境では、sendgridを使ってローカル環境ではmailhogを使う。

gomailにNewDialerという関数があるんだけど、これ使えなかったから調べたら以下で解決した。dep問題だったか。

github.com

で、このsendgrid使ったメール送信処理を自分のアドレスに向けて実行すれば、メールが受信されるはず。ただ、すぐ来るわけじゃなくてちょっとラグがあるね。

メール送信のアクティビティは、herokuの管理画面からsendgridアドオンへ飛んで確認することができるみたいね。

f:id:utr066:20190703131141p:plain

まとめ

うーん、最初からAPI_KEY使う方針で考えた方が楽だったかもな。あとgomailコードの中見ないとあんま使い方わからんかもしれん。