blastengineはシンプルに使える開発者向けメールサービスを提供しています。何かと面倒なメール配信をシンプルに、かつ確実に送信先に届くようになります。
今回はblastengineを使って、Go言語でメール送信を行うまでの流れを解説します。
ユーザ登録する
blastengineにユーザ登録します。管理画面に入るためのユーザID、パスワードが手に入るので、ログインします(ユーザIDは後で使います)。
送信元ドメインのSPFを設定する
送信元として利用するドメイン(自分で持っているもの)の設定をします。これは任意のドメイン管理サービスで設定できますが、TXTレコードに以下のSPFを追加します。
txt @ v=spf1 include:spf.besender.jp ~all
APIキーを取得する
ログイン後、管理画面の右上にある設定メニューに移動します。
そして設定の中で、APIキーを取得します。
SMTP用のパスワードを設定する
同じくSMTPリレーの設定で、SMTP用のパスワードを設定できます。また、IPアドレスベースの認証も可能です。
プロジェクトを作成する
プロジェクトを作成します。
mkdir blastengine-go
cd blastengine-go
初期化します。
go mod init mail
SMTP経由で配信する
まずはSMTPリレーを使ってメールを送信する流れを紹介します。利用したライブラリは以下の通りです。
ライブラリをインストールする
ライブラリをインストールします。
go get github.com/wneessen/go-mail
コードの記述
mail.go
というファイルを作成します。内容は次の通りです。
package main
import (
"log"
"mime"
"github.com/wneessen/go-mail"
)
func main() {
// この中に処理を記述します
}
必要な情報
メール送信時に利用する情報を設定します。パスワードはSMTP用のパスワードを設定します。SMTPホストは smtp.engn.jp
で、ポート番号は25/587/2525より選択できます。
username := "YOUR_SMTP_USER"
password := "YOUR_SMTP_PASSWORD"
toAddress := "user@example.jp"
fromAddress := "admin@example.com"
smtpHost := "smtp.engn.jp"
smtpPort := 587
メールクライアントの作成
設定した情報に基づいて、メールクライアントを作成します。
c, err := mail.NewClient(smtpHost, mail.WithPort(smtpPort), mail.WithSMTPAuth(mail.SMTPAuthPlain),
mail.WithUsername(username), mail.WithPassword(password))
if err != nil {
log.Fatalf("メールクライアントの生成に失敗: %s", err)
}
メッセージの作成
メッセージを作成します。日本語の件名の場合は mime.BEncoding.Encode
を使ってエンコードします。
m := mail.NewMsg()
m.Subject(mime.BEncoding.Encode("UTF-8", "こんにちは from blastengine"))
m.SetBodyString(mail.TypeTextPlain, "日本語の本文")
m.SetBodyString(mail.TypeTextHTML, "<html><body>日本語の本文</body></html>")
if err := m.From(fromAddress); err != nil {
log.Fatalf("Fromアドレスの設定に失敗: %s", err)
}
if err := m.To(toAddress); err != nil {
log.Fatalf("Toアドレスの設定に失敗: %s", err)
}
メール送信
メールを送信します。
if err := c.DialAndSend(m); err != nil {
log.Fatalf("送信失敗: %s", err)
}
log.Printf("メール送信しました: %t", m.IsDelivered())
c.Close()
全体のコード
SMTP経由でメールを送信するコードは次の通りです。
package main
import (
"log"
"mime"
"github.com/wneessen/go-mail"
)
func main() {
username := "YOUR_SMTP_USER"
password := "YOUR_SMTP_PASSWORD"
toAddress := "user@example.jp"
fromAddress := "admin@example.com"
smtpHost := "smtp.engn.jp"
smtpPort := 587
c, err := mail.NewClient(smtpHost, mail.WithPort(smtpPort), mail.WithSMTPAuth(mail.SMTPAuthPlain),
mail.WithUsername(username), mail.WithPassword(password))
if err != nil {
log.Fatalf("メールクライアントの生成に失敗: %s", err)
}
m := mail.NewMsg()
m.Subject(mime.BEncoding.Encode("UTF-8", "こんにちは from blastengine"))
m.SetBodyString(mail.TypeTextPlain, "日本語の本文")
m.SetBodyString(mail.TypeTextHTML, "<html><body>日本語の本文</body></html>")
if err := m.From(fromAddress); err != nil {
log.Fatalf("Fromアドレスの設定に失敗: %s", err)
}
if err := m.To(toAddress); err != nil {
log.Fatalf("Toアドレスの設定に失敗: %s", err)
}
if err := c.DialAndSend(m); err != nil {
log.Fatalf("送信失敗: %s", err)
}
log.Printf("メール送信しました: %t", m.IsDelivered())
c.Close()
}
API経由で配信する
次にAPIを使ってHTMLメールを配信する流れを紹介します。今回利用したライブラリは以下の通りです。すべて標準ライブラリのみです。
import (
"bytes"
"crypto/sha256"
"encoding/base64"
"encoding/hex"
"encoding/json"
"fmt"
"io"
"net/http"
)
コードの記述
先ほど同じく mail.go
の中に記述していきます。
package main
import (
"bytes"
"crypto/sha256"
"encoding/base64"
"encoding/hex"
"encoding/json"
"fmt"
"io"
"net/http"
)
func main() {
// この中に処理を記述します
}
必要な情報を設定
API経由で送信する際に必要な情報は、APIエンドポイント・ユーザID・APIキーです。それぞれの情報を設定します。
apiEndpoint := "https://app.engn.jp/api/v1/deliveries/transaction"
apiUser := "YOUR_API_USER"
apiKey := "YOUR_API_KEY"
構造体の定義
APIリクエストに利用する構造体を定義します。
type MailAddress struct {
Name string `json:"name"`
Address string `json:"email"`
}
type InsertCode struct {
Key string `json:"key"`
Value string `json:"value"`
}
type ListUnsubscribe struct {
MailTo string `json:"mailto"`
Url string `json:"url"`
}
type EMail struct {
To string `json:"to"`
From MailAddress `json:"from"`
Cc []*string `json:"cc"`
Bcc []*string `json:"bcc"`
InsertCode []*InsertCode `json:"insert_code"`
Subject string `json:"subject"`
ListUnsubscribe *ListUnsubscribe `json:"list_unsubscribe"`
Encode string `json:"encode"`
TextPart string `json:"text_part"`
HtmlPart string `json:"html_part"`
}
// APIレスポンス
type Response struct {
DeliveryId int `json:"delivery_id"`
}
トークンを生成する
APIリクエストするためのトークンを生成します。手順としては次のとおりです。
- ユーザIDとAPIキーを連結する
- SHA256のハッシュを生成する
- ハッシュを全て小文字にする
- 3の文字列をBASE64エンコードする
実際のコードで言うと、次のようになります。 token
がトークンです。
// トークンの生成
hash := sha256.Sum256([]byte(apiUser + apiKey))
token := base64.URLEncoding.EncodeToString([]byte(hex.EncodeToString(hash[:])))
APIリクエストする
では実際にメールを送信します。APIのエンドポイントは https://app.engn.jp/api/v1/deliveries/transaction
になります。生成したトークンは Authorization
ヘッダーに適用します。fromのemailやtoなど、メールアドレスは利用されるものに書き換えてください。
// メールの作成
email := EMail{
To: "user@example.jp",
From: MailAddress{
Name: "管理者",
Address: "admin@example.com",
},
Subject: "テストメール from API",
Encode: "UTF-8",
TextPart: `こんにちは、これはテストメールです。`,
HtmlPart: `<html><body><h1>こんにちは、これはテストメールです。</h1></body></html>`,
}
jsonBytes, err := json.Marshal(email)
if err != nil {
panic(err)
}
fmt.Println(string(jsonBytes))
req, err := http.NewRequest("POST", apiEndpoint, bytes.NewBuffer(jsonBytes))
if err != nil {
panic(err)
}
req.Header.Set("Content-Type", "application/json")
req.Header.Set("Authorization", "Bearer "+token)
client := &http.Client{}
resp, err := client.Do(req)
if err != nil {
panic(err)
}
defer resp.Body.Close()
結果
レスポンスは以下のようになっています。
{
"delivery_id": 9
}
これを json.Unmarshal
でパースして利用します。
var response Response
err = json.Unmarshal(body, &response)
if err != nil {
panic(err)
}
fmt.Println(response.DeliveryId)
全体のコード
API経由でメールを送信するコードは次の通りです。
package main
import (
"bytes"
"crypto/sha256"
"encoding/base64"
"encoding/hex"
"encoding/json"
"fmt"
"io"
"net/http"
)
type MailAddress struct {
Name string `json:"name"`
Address string `json:"email"`
}
type InsertCode struct {
Key string `json:"key"`
Value string `json:"value"`
}
type ListUnsubscribe struct {
MailTo string `json:"mailto"`
Url string `json:"url"`
}
type EMail struct {
To string `json:"to"`
From MailAddress `json:"from"`
Cc []*string `json:"cc"`
Bcc []*string `json:"bcc"`
InsertCode []*InsertCode `json:"insert_code"`
Subject string `json:"subject"`
ListUnsubscribe *ListUnsubscribe `json:"list_unsubscribe"`
Encode string `json:"encode"`
TextPart string `json:"text_part"`
HtmlPart string `json:"html_part"`
}
type Response struct {
DeliveryId int `json:"delivery_id"`
}
func main() {
apiEndpoint := "https://app.engn.jp/api/v1/deliveries/transaction"
apiUser := "YOUR_API_USER"
apiKey := "YOUR_API_KEY"
// トークンの生成
hash := sha256.Sum256([]byte(apiUser + apiKey))
token := base64.URLEncoding.EncodeToString([]byte(hex.EncodeToString(hash[:])))
// メールの作成
email := EMail{
To: "user@example.jp",
From: MailAddress{
Name: "管理者",
Address: "admin@example.com",
},
Subject: "テストメール from API",
Encode: "UTF-8",
TextPart: `こんにちは、これはテストメールです。`,
HtmlPart: `<html><body><h1>こんにちは、これはテストメールです。</h1></body></html>`,
}
jsonBytes, err := json.Marshal(email)
if err != nil {
panic(err)
}
fmt.Println(string(jsonBytes))
req, err := http.NewRequest("POST", apiEndpoint, bytes.NewBuffer(jsonBytes))
if err != nil {
panic(err)
}
req.Header.Set("Content-Type", "application/json")
req.Header.Set("Authorization", "Bearer "+token)
client := &http.Client{}
resp, err := client.Do(req)
if err != nil {
panic(err)
}
defer resp.Body.Close()
body, _ := io.ReadAll(resp.Body)
// Parse
var response Response
err = json.Unmarshal(body, &response)
if err != nil {
panic(err)
}
fmt.Println(response.DeliveryId)
}
まとめ
クラウドサービスではSMTPポートが塞がれている場合があるので、そうした時にはAPI経由を利用してください。SMTPリレーを使えば、より信頼性高く、安定した配信が実現できるでしょう。
APIとSMTPリレー、それぞれの要件に合わせて最適な方を選択してください。