ElixirからSendGridを利用してメール送信する方法

はじめに
今回はElixirからSendGridを利用してメール送信する方法をいくつかご紹介します。SendGridでは7つの言語向けに公式ライブラリを提供していますが、残念ながらこの中にElixirは含まれていません。
Elixirのパッケージ管理ツール「hex」で検索すると、bamboo、swoosh、sendgridといった3rdパーティ製パッケージが見つかります。bambooとswooshはいずれもSMTPを利用したメール送信に特化したパッケージです。一方、sendgridはWeb APIベースのパッケージで、メール送信含めその他の様々なSendGridの機能をAPI経由で利用できるのが特徴です。今回は、ダウンロード実績の大きいbambooとWeb APIベースのsendgridをご紹介します。
サンプルコード
各パッケージを使ってメール送信するサンプルコードを作成しました。インストール方法や実行方法については各リポジトリのREADMEをご確認ください。
- sendgridjp-bamboo-example
bambooパッケージを利用したサンプルコードです。bamboo 0.8.0を前提としています。 - sendgridjp-elixir-example
sendgridパッケージを利用したサンプルコードです。sendgrid 1.4.0を前提としています。
いずれも以下の環境で動作確認をしています。
- Erlang/OTP 19.3
- Elixir 1.4.4
bambooパッケージ
bambooに含まれるSendgridAdapterを利用したシンプルなメール送信のサンプルコードは次の通りです。SendgridAdapterを利用することでテンプレート指定と置換設定を行うこともできます。
def single_email_to_a_single_recipient do
from = %SendgridjpBambooExample.User{name: "送信者名", email: "from@example.com"}
new_email()
|> to("to@example.com")
|> from(from)
|> subject("[sendgridjp-bamboo-example] フクロウのお名前はfullnameさん")
|> text_body("familyname さんは何をしていますか?\r\n 彼はplaceにいます。")
|> html_body("<strong> familyname さんは何をしていますか?</strong><br />彼はplaceにいます。")
|> substitute("fullname", "田中 太郎")
|> substitute("familyname", "田中")
|> substitute("place", "中野")
end
基本的にbambooは1回のリクエストで1通のメールを送信する使い方が想定されているので、素のSMTPを利用して大量のメール配信を行うにはリクエストを繰り返す必要があります。そこで、SendGrid独自のX-SMTPAPIヘッダを利用して1回のリクエストで大量のメールを配信できるようにしてみました。X-SMTPAPIヘッダを利用したサンプルは次の通りです。
def single_email_to_multiple_recipients do
from = %SendgridjpBambooExample.User{name: "送信者名", email: "from@example.com"}
smtpapi = %{
"to" => ["to1@example.com", "to2@example.com", "to3@example.com"],
"sub" => %{
"fullname" => ["田中 太郎", "佐藤 次郎", "鈴木 三郎"],
"familyname" => ["田中", "佐藤", "鈴木"],
"place" => ["office", "home", "office"]
},
"section" => %{
"office" => "中野",
"home" => "目黒"
}
}
new_email()
|> to("dummy@example.com") # 実際の宛先はx-smtpapiで指定。これはダミー
|> from(from)
|> subject("[sendgridjp-bamboo-example] フクロウのお名前はfullnameさん")
|> text_body("familyname さんは何をしていますか?\r\n 彼はplaceにいます。")
|> html_body("<strong> familyname さんは何をしていますか?</strong><br />彼はplaceにいます。")
|> put_private("x-smtpapi", smtpapi)
end
bambooはアダプタ方式を採用しているため、アダプタを切り替えることでSendGrid以外の様々なメール配信サービス経由で送信することができます。何らかの理由でSendGridが利用できなくなった場合など、可用性の確保に向いていると言えます(ただし、切り替えを容易にするには各アダプタ特有の機能は利用できません)。
sendgridパッケージ
次にsendgridパッケージを利用したメール送信のサンプルコードは次の通りです。
def send_to_a_single_recipient do
alias SendGrid.{Mailer, Email}
image = File.read!("./gif.gif")
encoded = :base64.encode(image)
attachment = %{
:content => encoded,
:type => "image/gif",
:filename => "gif.gif",
:disposition => "attachment"
}
email =
Email.build()
|> Email.add_to("to@example.com")
|> Email.put_from("from@example.com", "送信者名")
|> Email.put_subject("[sendgrid-elixir-example] フクロウのお名前はfullnameさん")
|> Email.put_text("familyname さんは何をしていますか?\r\n 彼はplaceにいます。")
|> Email.put_html("<strong> familyname さんは何をしていますか?</strong><br />彼はplaceにいます。")
|> Email.add_substitution("fullname", "田中 太郎")
|> Email.add_substitution("familyname", "田中")
|> Email.add_substitution("place", "中野")
|> Email.add_header("X-Sent-Using", "SendGrid-API")
|> Email.add_attachment(attachment)
Mailer.send(email)
end
sendgridパッケージもbambooと同様、1回のリクエストで1通のメールを送信する使い方が想定されているので、1回のリクエストで大量のメール配信を行うには、直接Web APIにアクセスする必要があります。幸い、sendgridパッケージはHTTPoisonというHTTPクライアント機能を呼び出せるので、SendGridのWeb APIを直接コールできます。
1回のリクエストで複数の宛先にメールを送信するサンプルコードは次の通りです。ちょっと複雑になってしまいますが、こうすることでWeb APIの機能を全て利用できます。
def send_to_multiple_recipients do
image = File.read!("./gif.gif")
encoded = :base64.encode(image)
attachment = %{
:content => encoded,
:type => "image/gif",
:filename => "gif.gif",
:disposition => "attachment"
}
base_url = "/v3/mail/send"
json = %{
personalizations: [
%{
to: [%{email: "to1@example.com"}],
substitutions: %{
"fullname" => "田中 太郎",
"familyname" => "田中",
"place" => "office"
}
},
%{
to: [%{email: "to2@example.com"}],
substitutions: %{
"fullname" => "佐藤 次郎",
"familyname" => "佐藤",
"place" => "home"
}
},
%{
to: [%{email: "to3@example.com"}],
substitutions: %{
"fullname" => "鈴木 三郎",
"familyname" => "鈴木",
"place" => "office"
}
}
],
subject: "[sendgrid-elixir-example] フクロウのお名前はfullnameさん",
from: %{
email: "from@example.com",
name: "送信者名"
},
content: [
%{
type: "text/plain",
value: "familyname さんは何をしていますか?\r\n 彼はplaceにいます。"
},
%{
type: "text/html",
value: "<strong> familyname さんは何をしていますか?</strong><br />彼はplaceにいます。"
}
],
sections: %{
"office" => "中野",
"home" => "目黒"
},
headers: %{"X-Sent-Using" => "SendGrid-API"},
attachments: [attachment]
} |> Poison.encode!
SendGrid.post!(base_url, json)
end
また、バウンスリストを取得するサンプルコードは次の通りです。
def get_bounces do base_url = "/v3/suppression/bounces" SendGrid.get!(base_url) end
さいごに
それぞれ特徴があるのでどちらが優れていると言った比較はできませんが、うまく組み合わせて利用することで、SendGridの機能をフル活用することができると思います。SendGridのフリートライアル(無期限)へのお申込みはこちらからどうぞ!


