Go言語、Amazon SNSでSMS・メール配信機能を試してみる

Amazon SNSとは

正式名称:Amazon Simple Notification Service
https://aws.amazon.com/jp/sns/

フルマネージド型 pub/sub メッセージングサービス
AWSのサービス間の連携に使われたり、
電子メール、SMS、およびモバイルプッシュ通知へのメッセージ配信も可能

連携できるAWSサービスは以下

※ 音声配信はAmazon SNSでは扱っていません。
Amazon PinpointやAmazon Connectなどで実現できそうです。


コード

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/sns"
)

const (
    AwsAccessKey       = "AWSアクセスキー"
    AwsSecretAccessKey = "AWSシークレットキー"
    AwsRegion          = "us-east-1"
)

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

    if err != nil {
        log.Fatal(err)
    }

    client := sns.New(sess)

    // メッセージの作成
    pin := &sns.PublishInput{}
    pin.SetMessage("SMS エンドポイントのサンプルメッセージ")
    // E.164 形式の電話番号(国コードを指定します。今回は日本の場合は、[+81]を指定。090や080の最初の0は取り除く)
    pin.SetPhoneNumber("+81xxxxxxxxxx")

    // SMS送信
    result, err := client.Publish(pin)
    if err != nil {
        log.Fatal(err)
    }

    fmt.Printf("Result: %s", result.String())
}


解説

PublishInput構造体にメッセージをセットし、Publishするのが基本動作
SetMessage:メッセージ本文
SetPhoneNumber:電話番号

PublishInputには、TopicArnかTargetArn、またはPhoneNumberのいずれかを設定する必要があります。
メールの場合はPhoneNumber以外のいずれかを指定

AWSセッションの作成の際に、リージョンの指定をしています。
こちらは「us-east-1」固定とします。
詳細は下記「サンドボックス内でのSMS送信における注意点」に記載していますが、
サンドボックスのためus-east-1以外での確認が出来なくなっています。
他のリージョンを指定しても一見成功しますが、メッセージが送られてきません。


サンドボックス内でのSMS送信における注意点

SMSの場合、サブスクリプション登録していなくても送ることができます。
初回のサービス利用時はサンドボックス環境と言って事前に検証済みの番号にしか配信できません。
配信の設定はAWSのコンソールより設定します。

https://console.aws.amazon.com/sns/v3/home?region=us-east-1#/mobile/text-messaging

注意すべきはリージョンはバージニア北部でしか設定できないのでリージョンを確認してください。
Amazon SNSのテキストメッセージング (SMS)のページを開きます。
「電話番号を追加」をクリックし、電話番号を追加します。 f:id:katutoki:20210926181300p:plain

電話番号はE.164 形式で記述します。
+2桁の国コード + 電話番号
日本の場合は、[+81]を指定。090や080の最初の0は取り除く)
例)090-1234-5678 の場合 +81 80 1234 5678 となります。
f:id:katutoki:20210926181452p:plain

番号入力後、検証コードを入力することになるので、
スマホの通知を確認し、検証コードを入力することで検証完了となります。 f:id:katutoki:20210926182217p:plain

スマホでの検証コードの表示。表示はワンタイムパスワードとなっています。 f:id:katutoki:20210926182429p:plain:w200:h300

テキストメッセージング (SMS)のページにて検証ステータスが検証済みとなっていれば成功です。


SMSの発信(トピック指定)

   // ~ 中略(メッセージの作成より前は上と同様) ~

    // メッセージの作成
    text := "共通のサンプルメッセージです。"

    // サブスクリプションのプロトコルごとにメッセージを指定
    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)

    pin := &sns.PublishInput{
        MessageStructure: aws.String("json"), // MessageStructureにjsonを指定
        TopicArn:         aws.String(TopicARN),
    }

    // 配信
    result, err := client.Publish(pin)
    if err != nil {
        fmt.Println("Publish Error: ", err)
    }

    log.Println(result.GoString())
}

※この場合、同じトピックに指定したサブスクリプションにまとめて配信できるので実用的な気がします。
 ここではSMS送信とメール送信用のテキストを指定しています。


解説

PublishInput構造体にメッセージをセットし、Publishするのが基本動作なのは変わらず
Message:メッセージ本文(json形式)
MessageStructure:メッセージ本文がjson形式であることを指定
TopicArn: SNSトピックのARN

トピックを指定した送信の場合、トピックとサブスクリプションの作成が必要です。

SMS送信したい場合、サブスクリプションプロトコルにSMSを指定し、エンドポイントとして送りたい電話番号を指定します。
先ほど検証済みにした電話番号を指定します。別な番号で確認したい場合は検証済みの電話番号に追加が必要です。


メール送信したい場合、サブスクリプションプロトコルにEメールを指定し、エンドポイントとして送りたいemailアドレスを設定します。

また、トピックの種類にはスタンダードとFIFOの2種類あります。
SMSやメール送信するためにはスタンダードを選択します。


SMS送信における注意点

1送信単位は160文字。

160文字を超えてもメッセージとしては1度に配信されますが、内部的には送りたい文字数÷160回数分配信したとみなされるようです。
無料枠として月100万回配信可能ですが、SMSは無料枠ではないので注意

1送信当たり、$0.07451