Go言語、Amazon PinpointでSMS送信機能を試してみる

はじめに

Pinpoint は、PUSH 通知だけでなくメール、SMS などに対応しています。 LINE などのカスタムチャネル対応もしているため、Pinpoint を起点に様々なサービス連携が可能なため、Amazon SNSより拡張性が高いと考えられます。

  • メール、SMS、プッシュ通知、音声
  • 通知系の全てを備えているのはPinpointのみ
  • 音声送信は東京リージョンでは不可
     バージニア北部にて設定可能なことを確認

特徴としては下記
* 対象者のセグメント分け
* メッセージングキャンペーン
* ユーザージャーニー
* テンプレートを用いた一貫性のあるメッセージング
* パーソナライズされたコンテンツ配信
* ユーザー行動の分析
* テストメッセージの送信

E メールの開封とクリックイベントの追跡 https://docs.aws.amazon.com/ja_jp/pinpoint/latest/userguide/channels-email-open-click-tracking.html

Amazon Pinpoint は、送信する各 E メールの最後に、ごく小さな、透明なイメージを追加します。このイメージは AWS サーバーでホストされています。このイメージのファイル名は、各受取人に固有です。受取人が E メールを開封すると、E メールクライアントがこのファイルを当社のサーバーからダウンロードします。E メールクライアントが当社のサーバーから追跡イメージをダウンロードすると、開封イベントとしてカウントします。

無料枠

Amazon Pinpoint では、毎月 5,000 エンドポイントのターゲット、毎月 100 万回のプッシュ通知の送信、毎月 1 億回のイベントの追跡を無料で行えます。

Amazon Pinpoint のクォータ(制限値)

Amazon Pinpoint のクォータ - Amazon Pinpoint


CLI

aws pinpoint send-messages \
--application-id 80fb90a6c****************** \
--cli-input-json file://pinpoint.json --region ap-northeast-1

pinpoint.json

{
    "ApplicationId": "80fb90a6c******************",
    "MessageRequest": {
        "Addresses": {
            "+819012345678": {
                "ChannelType": "SMS"
            }
        },
        "MessageConfiguration": {
            "SMSMessage": {
                "Body": "てすと",
                "MessageType": "PROMOTIONAL",
        "SenderId": "testsend"
            }
        }
    }
}

戻り(パラメータエラー)

{
    "MessageResponse": {
        "ApplicationId": "80fb90a6c******************",
        "RequestId": "a28ada49-****-****-****-********",
        "Result": {
            "08012345678": {
                "DeliveryStatus": "PERMANENT_FAILURE",
                "MessageId": "9q633b6gts******************",
                "StatusCode": 400,
                "StatusMessage": "Invalid PhoneNumber"
            }
        }
    }
}

指定した電話番号が誤っていたので修正し再度実行
電話番号の指定は+で始まる国コード付きの電話番号にしないと無効になります。

直した版

{
    "MessageResponse": {
        "ApplicationId": "80fb90a6c******************",
        "RequestId": "5bf917c8-****-****-****-********",
        "Result": {
            "+819012345678": {
                "DeliveryStatus": "SUCCESSFUL",
                "MessageId": "75i5gmnsar******************",
                "StatusCode": 200,
                "StatusMessage": "MessageId: 75i5gmnsar******************"
            }
        }
    }
}

コード

SMSとメール送信を同時に実行

package main

import (
    "encoding/json"
    "fmt"
    "log"

    "github.com/aws/aws-sdk-go/aws"
    "github.com/aws/aws-sdk-go/aws/credentials"
    "github.com/aws/aws-sdk-go/aws/session"
    "github.com/aws/aws-sdk-go/service/pinpoint"
)

const (
    AwsAccessKey       = "アクセスキー"
    AwsSecretAccessKey = "シークレットキー"
    AwsRegion          = "us-east-1"
    AppId              = "PinpointのプロジェクトID"
    SenderId           = "testsend" // 送信ID SMSの送信者名
)

func main() {
    // クライアントの生成
    creds := credentials.NewStaticCredentials(AwsAccessKey, AwsSecretAccessKey, "")
    sess, _ := session.NewSession(&aws.Config{
        Credentials: creds,
        Region:      aws.String(AwsRegion),
    })

    client := pinpoint.New(sess)

    // メッセージ作成
    text := "Pinpoint サンプルメッセージ"

    // サブスクリプションのプロトコルごとにメッセージを指定
    messageJson := map[string]string{
        "default": text,
        "sms":     "SMSのメッセージ\n" + text,
        "email":   "E メールのメッセージ\n" + text,
    }
    // メッセージ構造体はJSON文字列にする
    bytes, err := json.Marshal(messageJson)
    if err != nil {
        fmt.Println("JSON marshal Error: ", err)
    }
    message := string(bytes)

    // Pinpoint送信
    pin := &pinpoint.SendMessagesInput{
        ApplicationId: aws.String(AppId),
        MessageRequest: &pinpoint.MessageRequest{
            Addresses: map[string]*pinpoint.AddressConfiguration{
                "+819012345678": &pinpoint.AddressConfiguration{ // 電話番号を指定
                    ChannelType: aws.String(pinpoint.ChannelTypeSms),
                },
                "your-mail@mail.com": &pinpoint.AddressConfiguration{ // メールアドレスを指定
                    ChannelType: aws.String(pinpoint.ChannelTypeEmail),
                },
            },
            MessageConfiguration: &pinpoint.DirectMessageConfiguration{
                SMSMessage: &pinpoint.SMSMessage{
                    Body:        aws.String(text),     // 本文
                    SenderId:    aws.String(SenderId), // 送信ID SMSの送信者名
                    MessageType: aws.String(pinpoint.MessageTypePromotional),
                },
                EmailMessage: &pinpoint.EmailMessage{
                    FromAddress: aws.String("sender@mail.com"), // 送信者アドレス
                    SimpleEmail: &pinpoint.SimpleEmail{
                        Subject: &pinpoint.SimpleEmailPart{ // 件名
                            Charset: aws.String("utf-8"),
                            Data:    aws.String("subject"),
                        },
                        HtmlPart: &pinpoint.SimpleEmailPart{
                            Charset: aws.String("utf-8"),
                            Data:    aws.String("<HTML>html message</html>"),
                        },
                        TextPart: &pinpoint.SimpleEmailPart{
                            Charset: aws.String("utf-8"),
                            Data:    aws.String("text message"),
                        },
                    },
                },
            },
        },
    }


    result, _ := client.SendMessages(pin)
    log.Println(result.MessageResponse.Result)
}


解説

SendMessagesInputの構造体が結構複雑です。
感覚的には以下
* Addressesのmapで送信対象を指定(mapのキーが電話番号だったり、メールアドレスだったりなのが) * MessageConfigurationにてプロトコル毎に送信内容を設定

あまり情報がないので、実装見ながら必要なtypeを掘り下げて、
値を設定していく感じで実装できます。
ポイントとしてはstringの値などがポインタなため、直接文字列を設定してもエラーになってしまう点です。
回避策としては別途変数を宣言した上で代入時にポインタを渡すか、
上記の実装のように、awsが提供しているポインタに変換する関数を噛ませることでポインタ渡しができます。

値の設定がやり辛いのですが、案件で使っているgo-swaggerが生成するコードもポインタで定義しているので、
きっとライブラリ的には良い実装なんだろうと納得させています。
おそらくメモリ効率が良いのではと思いますが。


Amazon SNSAmazon Pinpointの差異

公式より

https://aws.amazon.com/jp/pinpoint/faqs/

Q: 現在、Amazon SNSAmazon Simple Email Service (SES) を使用している場合、Amazon Pinpoint に切り替えることによってどんなメリットがありますか? Amazon SNSAmazon SES の一般的なユースケースでは、それぞれのメッセージの対象者、コンテンツ、配信スケジュールを管理するためにアプリケーションをセットアップする必要があります。Amazon Pinpoint を使用すると、メッセージテンプレート、配信スケジュール、対象を絞ったセグメント、全面的なキャンペーンを作成できます。

https://docs.aws.amazon.com/pinpoint/latest/apireference/welcome.html

AmazonPinpointとAmazonSimple Email Service(SES)のどちらを選択するか 購入確認やパスワードリセットメッセージなど、大量のトランザクションメールを送信する場合は、AmazonSESの使用を検討してください。Amazon SESにはAPISMTPインターフェースがあり、どちらもアプリケーションやサービスからメールを送信するのに適しています。また、電子メールの受信機能、構成セット、送信認証機能など、追加の電子メール機能も提供します。 Amazon SESには、Salesforceなどの顧客関係管理(CRM)サービスなど、既存のサードパーティアプリケーションと統合できるSMTPインターフェイスも含まれています。アマゾンSESを使用して電子メールを送信する方法の詳細については、以下を参照してくださいアマゾンSESのAPI v2の 詳細については、を。


送信の制限

初期状態では1ドル分以上のSMSが送れないようになっています。
1ドルの制限はコンソールから変更可能です。


参考情報

SendMessage(CLIhttps://docs.aws.amazon.com/cli/latest/reference/pinpoint/send-messages.html

SDK Example https://docs.aws.amazon.com/pinpoint/latest/developerguide/send-messages-sms.html

SDK Document Go https://docs.aws.amazon.com/sdk-for-go/api/service/pinpoint/#Pinpoint.SendMessages

REST API Document https://docs.aws.amazon.com/pinpoint/latest/apireference/apps-application-id-messages.html