動的テンプレートを使用したGoとSendGridからのメールの送信方法

May 08, 2024
執筆者
Miguel Ángel Ramírez
寄稿者
Twilio の寄稿者によって表明された意見は彼ら自身のものです
レビュー担当者

本記事は、当社のTwilio Voicesプログラムの一環として、外部の寄稿者によって執筆されたものです。本記事は更新を停止しています。最新情報ではない可能性があります。あらかじめご了承ください。

動的テンプレートを使用したGoとSendGridからのメールの送信方法

SendGridでは、メールテンプレートを利用できるほか、必要に応じて独自のコードを使って、テンプレートにデータを動的に埋め込むことができます。アプリの新規ユーザーを歓迎するメッセージ、購入確認メールの送信、マーケティング目的のメッセージなど、用途に合わせてテンプレートを選択できます。

HTMLのコーディング時間を大幅に短縮できるだけでなく、見栄えの良いメールを誰でも簡単に作成できます。また、コードに直接触れる必要がないため、運用や管理もすっきりと保てます。

このチュートリアルは、Matthew Setterの「GoとSendGridを使って、30秒でメールを送信する方法」を補完するものですが、この優れた機能を活用して、店舗の経営者が領収書を送付するような手軽さでメールを送信する方法を説明します。ここでは、公式のTwilio SendGrid Golang APIライブラリも使用します。

前提条件

このチュートリアルでは、以下が必要です。

動的テンプレートの作成

左側の[Email API > 動的テンプレート]に移動し、[Create a Dynamic Template](動的テンプレートの作成)をクリックして、「purchase-receipt-template」のような名前を設定します。新しいテンプレートはリストの最上部に追加されます。まだ、作成していない場合は、最初のテンプレートとして登録されます。テンプレートを展開し、テンプレートIDをコピーして安全な場所に保管してください。次に、[Add Version](バージョンの追加)をクリックします。

Select a Design](デザインの選択)ウィザードで、[SendGrid Email Designs](SendGridメールデザイン)を選択します。次に、下にスクロールして[Retail Purchase Receipt Email Template](小売購入レシートメールテンプレート)、[選択]の順にクリックします。

その後、[Select Your Editing Experience](編集環境の選択)で[コードエディタ]オプションを選択します。

これで、片側にHTMLエディタ、もう片側にデザインを配置したテンプレートが完成しました。

テンプレートのカスタマイズ

Handlebarsを使ってテンプレートをカスタマイズし、コードから購入日、顧客名、メールアドレス、チケット番号などの動的なデータを反映させます。

デザイン側の日付をクリックすると、コード内の正確な位置に移動します。現在の値(2020年1月20日 午後5時40分)を{{purchase_date}}に置き換えます。

残りのデータについても同じ操作を行い、静的な値をHandlebarsの変数に置き換えます。デザイン内の従業員名をクリックし、既存の値を{{employee}}に置き換えます。残りの3つの要素についても同じ操作を行います。

  • 顧客 - {{customer}}
  • メール - {{email}}
  • チケット番号 - {{ticket_number}}

完了すると、メールテンプレートの該当セクションは以下のスクリーンショットのようになります。

最後に、反復処理を使用して購入済み項目表をカスタマイズします。デザインビューのリストの最初の項目をクリックすると、該当するコードセクションに移動します。次に、この項目がある表タグの前に{{#each items}}、次の項目がある表タグの直前に{{/each}}を追加します。

次に、以下のhandlebarsを項目情報に置き換えます。

  • Villa Floral(120mL) - {{this.item}}
  • 1 - {{this.quantity}}
  • $175.90 - ${{this.price}} (ドル記号を削除しない)

変更後のHTMLコードは以下のようになります。

{{#each items}}
<table border="0" cellpadding="0" cellspacing="0" align="center" width="100%" role="module" data-type="columns" style="padding:0px 40px 0px 40px;" bgcolor="#FFFFFF" data-distribution="1,1,1">
    <tbody>
      <tr role="module-content">
        <td height="100%" valign="top"><table width="173" style="width:173px; border-spacing:0; border-collapse:collapse; margin:0px 0px 0px 0px;" cellpadding="0" cellspacing="0" align="left" border="0" bgcolor="" class="column column-0">
      <tbody>
        <tr>
          <td style="padding:0px;margin:0px;border-spacing:0;"><table class="module" role="module" data-type="text" border="0" cellpadding="0" cellspacing="0" width="100%" style="table-layout: fixed;" data-muid="64573b96-209a-4822-93ec-5c5c732af15c.2" data-mc-module-version="2019-10-22">
    <tbody>
      <tr>
        <td style="padding:15px 0px 15px 0px; line-height:22px; text-align:inherit;" height="100%" valign="top" bgcolor="" role="module-content"><div><div style="font-family: inherit; text-align: center"><span style="color: #80817f; font-size: 12px">{{this.item}}</span></div><div></div></div></td>
      </tr>
    </tbody>
  </table></td>
        </tr>
      </tbody>
    </table><table width="173" style="width:173px; border-spacing:0; border-collapse:collapse; margin:0px 0px 0px 0px;" cellpadding="0" cellspacing="0" align="left" border="0" bgcolor="" class="column column-1">
      <tbody>
        <tr>
          <td style="padding:0px;margin:0px;border-spacing:0;"><table class="module" role="module" data-type="text" border="0" cellpadding="0" cellspacing="0" width="100%" style="table-layout: fixed;" data-muid="64573b96-209a-4822-93ec-5c5c732af15c.1.2" data-mc-module-version="2019-10-22">
    <tbody>
      <tr>
        <td style="padding:15px 0px 15px 0px; line-height:22px; text-align:inherit;" height="100%" valign="top" bgcolor="" role="module-content"><div><div style="font-family: inherit; text-align: center"><span style="color: #80817f; font-size: 12px">{{this.quantity}}</span></div><div></div></div></td>
      </tr>
    </tbody>
  </table></td>
        </tr>
      </tbody>
    </table><table width="173" style="width:173px; border-spacing:0; border-collapse:collapse; margin:0px 0px 0px 0px;" cellpadding="0" cellspacing="0" align="left" border="0" bgcolor="" class="column column-2">
      <tbody>
        <tr>
          <td style="padding:0px;margin:0px;border-spacing:0;"><table class="module" role="module" data-type="text" border="0" cellpadding="0" cellspacing="0" width="100%" style="table-layout: fixed;" data-muid="64573b96-209a-4822-93ec-5c5c732af15c.1.1.1" data-mc-module-version="2019-10-22">
    <tbody>
      <tr>
        <td style="padding:15px 0px 15px 0px; line-height:22px; text-align:inherit;" height="100%" valign="top" bgcolor="" role="module-content"><div><div style="font-family: inherit; text-align: center"><span style="color: #80817f; font-size: 12px">${{this.price}}</span></div><div></div></div></td>
      </tr>
    </tbody>
  </table></td>
        </tr>
      </tbody>
    </table></td>
      </tr>
    </tbody>
  </table><table class="module" role="module" data-type="divider" border="0" cellpadding="0" cellspacing="0" width="100%" style="table-layout: fixed;" data-muid="c614d8b1-248a-48ea-a30a-8dd0b2c65e10.1.2">
    <tbody>
      <tr>
        <td style="padding:0px 40px 0px 40px;" role="module-content" height="100%" valign="top" bgcolor="">
          <table border="0" cellpadding="0" cellspacing="0" align="center" width="100%" height="1px" style="line-height:1px; font-size:1px;">
            <tbody>
              <tr>
                <td style="padding:0px 0px 1px 0px;" bgcolor="#80817f"></td>
              </tr>
            </tbody>
          </table>
        </td>
      </tr>
    </tbody>
  </table>
{{/each}}

次に、2番目の固定項目({{/each}} handlebar直後の要素)を削除してください。データはすべて動的に送信されるため、この固定項目は不要になります。以下のスクリーンショットでハイライト表示されているのが確認できます。また、テンプレートのコード全体はこちらでご覧いただけます。

最後に、[保存]をクリックしてテンプレートを保存します。デザインビューの基本構造は、以下の例のようになっています。

テンプレートのテスト

動的テンプレートが正しく動作していることを確認するには、一部のデータを使ってテストすることができます。最上部のナビゲーションバーにある[{ } テストデータ]をクリックし、以下のJSONを追加します。

{
    "purchase_date": "January 20, 2020 5:40 PM",
    "employee": "Sammie",
    "customer": "Jane Doe",
    "email": "janedoe@example.com",
    "ticket_number": 123456789,
    "items": [
        {
            "item": "Some awesome product",
            "quantity": 1,
            "price": "124.5"
        },
        {
            "item": "Another awesome product",
            "quantity": 2,
            "price": "152.7"
        }
    ]
}

データはデザインビューに入力する必要があります。

アプリの構築

プロジェクトディレクトリの作成

ワークスペースにsend-email-with-templateという名前の新しいディレクトリを作成します。

mkdir send-email-with-template cd send-email-with-template

依存関係のインポート

以下のGoパッケージが必要です。

まず、新しいディレクトリ内でgo mod initを使用してGoモジュールを初期化する必要があります。

go mod init example.com/send-email-with-template

次に、go getコマンドを使用して、依存関係をインストールします。

go get github.com/joho/godotenv go get github.com/sendgrid/sendgrid-go

必要な環境変数の設定

.envという名前の新しいファイルを作成し、以下の構成を貼り付けます。

SENDGRID_API_KEY=<YOUR API KEY> SENDGRID_TEMPLATE_ID=<YOUR TEMPLATE ID> SEND_FROM_NAME=<SENDER'S NAME> SEND_FROM_ADDRESS=<SENDER'S EMAIL ADDRESS> SEND_TO_NAME=<RECIPIENT'S NAME> SEND_TO_ADDRESS=<RECIPIENT'S EMAIL ADDRESS>

ここに、SendGrid APIキー(次に作成)と以前作成したテンプレートIDを保存します。最後の4つのプレースホルダーを使用したいものに置き換えます。次に、YOUR TEMPLATE IDを、先ほど取得したテンプレートIDの値に置き換えます。

SendGrid APIキーの作成

SendGridアカウントに戻り、[設定] > [APIキー]をクリックし、[Create API Key](APIキーを作成)をクリックします。APIキーの名前を設定します。APIキーの権限については、[フルアクセス]を選択します。次に[Create & View](作成と表示)をクリックします。APIキーは一度表示されると、今後再表示されなくなります。プレースホルダーのYOUR API KEY(あなたのAPIキー)を新しく作成したキーに置き換えます。

コードの記述

環境変数を作成した後、send-email.goという名前のGoファイルを作成し、以下のコードを貼り付けます。

package main

import (
	"log"
	"net"
	"net/http"
	"os"
	"time"
	"github.com/joho/godotenv"
	"github.com/sendgrid/rest"
	sendgrid "github.com/sendgrid/sendgrid-go"
	"github.com/sendgrid/sendgrid-go/helpers/mail"
)

func main() {
    err := godotenv.Load()
    if err != nil {
        log.Panic("unable to load variables from .env file")
    }

    from := mail.NewEmail(os.Getenv("SEND_FROM_NAME"), os.Getenv("SEND_FROM_ADDRESS"))
    to := mail.NewEmail(os.Getenv("SEND_TO_NAME"), os.Getenv("SEND_TO_ADDRESS"))
    content := mail.NewContent("text/html", " ")

    m := mail.NewV3MailInit(from, "", to, content)
    m.SetTemplateID(os.Getenv("SENDGRID_TEMPLATE_ID"))

    currDateTime := time.Now().Format("January 2, 2006 3:04 PM")

    m.Personalizations[0].SetDynamicTemplateData("purchase_date", currDateTime)
    m.Personalizations[0].SetDynamicTemplateData("employee", "Sammie")
    m.Personalizations[0].SetDynamicTemplateData("customer", "Jane Doe")
    m.Personalizations[0].SetDynamicTemplateData("email", "janedoe@example.com")
    m.Personalizations[0].SetDynamicTemplateData("ticket_number", "123456789")
    items := []map[string]string{
        {
            "item": 	"Pink Pineapple Sunrise",
            "quantity": "1",
            "price":	"26.95",
        },
        {
            "item": 	"Sweet Carrot Cake",
            "quantity": "2",
            "price":	"65.9",
        },
        {
            "item": 	"Daffodil Daydreams",
            "quantity": "1",
            "price":	"26.95",
            },
    }
    m.Personalizations[0].SetDynamicTemplateData("items", items)

    request := sendgrid.GetRequest(os.Getenv("SENDGRID_API_KEY"), "/v3/mail/send", "")
    request.Method = "POST"
    request.Body = mail.GetRequestBody(m)

    client := &rest.Client {
    HTTPClient: &http.Client {
        Transport: &http.Transport {
            Proxy: http.ProxyFromEnvironment,
            DialContext: (&net.Dialer{
            Timeout:   30 * time.Second,
            KeepAlive: 30 * time.Second,
            DualStack: true,
        }).DialContext,
        TLSHandshakeTimeout:   10 * time.Second,
        ExpectContinueTimeout: 1 * time.Second,
        MaxIdleConns:      	2,
        MaxIdleConnsPerHost:   2,
        IdleConnTimeout:   	90 * time.Millisecond,
    },
    Timeout: 5 * time.Second,
    	},
    }

    response, err := client.Send(request)
    if err != nil {
        log.Fatal("error sending email:", err.Error())
    }

    if response.StatusCode < 200 || response.StatusCode >= 300 {
        log.Fatal("an unexpected error occurred:", response.StatusCode, response.Body, response.Headers)
    }
    log.Print("email successfully sent...")
}

上記のコードの解説です。メール変数が初期化され、テンプレートIDを指定してSendGridから新しいメールサービスが作成されます。次に、HTTPリクエストとREST APIクライアントを定義するための動的テンプレートデータが設定されます。最後に、メールが送信され、エラーがログに記録されるか、成功メッセージが表示されます。

コードのテスト

今度は、コードを構築して実行する必要があります。Goファイル名を引数としてgo runコマンドを実行するだけで、すべて1つの手順で実行できます。

go run send-email.go

ターミナルに確認メッセージ[email successfully sent...](メールが正常に送信されました…)と表示されます。

メールの確認

こちらのコードから送信したすべてのデータが記載されたメールが届いているはずです。

まとめ

SendGridの動的テンプレートを活用すると、変更の多いカスタムデータをコードに埋め込む必要がなくなります。ロジックの処理に集中でき、メールデザインはSendGrid側で柔軟に管理・変更できます。

Miguel Ángelは、問題解決、執筆(コードと実体験)、音楽、ビールが好きなソフトウェアエンジニアです。詳しいプロフィールは、migrmrz.devLinkedInGitHubで確認してください。