0
0

blastengineを使ってGo言語でメールを送信する

Posted at

blastengineはシンプルに使える開発者向けメールサービスを提供しています。何かと面倒なメール配信をシンプルに、かつ確実に送信先に届くようになります。

今回はblastengineを使って、Go言語でメール送信を行うまでの流れを解説します。

ユーザ登録する

blastengineにユーザ登録します。管理画面に入るためのユーザID、パスワードが手に入るので、ログインします(ユーザIDは後で使います)。

getting-started-4.jpg

送信元ドメインのSPFを設定する

送信元として利用するドメイン(自分で持っているもの)の設定をします。これは任意のドメイン管理サービスで設定できますが、TXTレコードに以下のSPFを追加します。

txt @ v=spf1 include:spf.besender.jp ~all

APIキーを取得する

ログイン後、管理画面の右上にある設定メニューに移動します。

getting-started-6.jpg

そして設定の中で、APIキーを取得します。

getting-started-5.png

SMTP用のパスワードを設定する

同じくSMTPリレーの設定で、SMTP用のパスワードを設定できます。また、IPアドレスベースの認証も可能です。

image.png

プロジェクトを作成する

プロジェクトを作成します。

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リクエストするためのトークンを生成します。手順としては次のとおりです。

  1. ユーザIDとAPIキーを連結する
  2. SHA256のハッシュを生成する
  3. ハッシュを全て小文字にする
  4. 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リレー、それぞれの要件に合わせて最適な方を選択してください。

エンジニア向けメール配信システム「ブラストエンジン」

0
0
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
0
0