Azure Communication Services でメール通知をやってみる


# やりたいこと

Azure Communication Services を触る機会があったので、その内容をまとめます。
今回は、まだプレビュー段階ではありますが E-mail Communication Services を使ってみたので、その内容です。

# Azure Communication Services とは

https://learn.microsoft.com/ja-jp/azure/communication-services/overview

公式ドキュメントより

> Azure Communication Services はクラウドベースのサービスです。用意されている REST API およびクライアント ライブラリ SDK を利用することで、通信を手軽にアプリケーションに組み込むことができます。 基になる技術 (メディアのエンコードやテレフォニーなど) の専門家でなくても、アプリケーションに通信を追加できます。
Azure Communication Services では、さまざまな通信形式がサポートされています。
・音声およびビデオによる通話
・リッチ テキスト チャット
・SMS
・電子メール

:::note info
一般的なシナリオとして、ユーザに SMS やメールを発信することや、リアルタイムのチャットを提供することが挙げられている。SMS やメール発信の仕組みなどを手軽に実現できるサービスというのが個人的な理解 (こういったサービスを使わない場合を経験したことがないので、どれだけ手軽になっているのか分かりませんが…)。
:::

## E-mail Communication Services とは

https://learn.microsoft.com/ja-jp/azure/communication-services/concepts/email/email-overview

公式ドキュメントより
> Azure Communication Services のメールは、Azure Communication Services プラットフォームで大量のトランザクション、および一括とマーケティングのメールを簡易化し、Application-to-Person (A2P) ユース ケースを有効にする新しいプリミティブです。 Azure Communication Services のメールは、実稼働対応のメール SDK オプションを使用して、アプリケーションへのメール機能の統合を簡素化します。 メールを使用すると、SMS やその他の通信チャネルと組み合わせたコミュニケーション モダリティの豊富なコラボレーションが可能になり、希望される通信チャネルで顧客に到達するのに役立つコラボレーション アプリケーションを構築できます。

主要な機能として以下
> ・Azure マネージド ドメイン - 顧客が事前にプロビジョニングされたドメイン (xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx.azurecomm.net) からメールを送信できます
・カスタム ドメイン - 顧客が、自分の確認済みドメイン (notify.contoso.com) からメールを送信できます。
・送信者認証のサポート - プラットフォームでは、遷移中にメール認証結果を保持する ARC (Authenticated Received Chain) サポートを使用したAzure マネージド ドメインとカスタム ドメインの両方の SPF (Sender Policy Framework) と DKIM (ドメイン キー識別メール) の設定サポートが有効になっています。
・メール スパム保護と不正行為の検出 - プラットフォームは、すべてのメッセージに対してメールの検疫を実行し、マルウェア、URL ブロック、コンテンツ ヒューリスティックを検出するための既存のトランスポート ルールを有効にすることで、Microsoft Defender コンポーネントを活用した包括的なメール保護を提供します。
・メールの分析 - Azure Insights を使用したメールの分析。 GDPR 要件を満たすために、診断と監査の目的でメッセージ ID と受信者情報を含む要求レベルのログを出力します。
・エンゲージメント追跡 - バウンス、ブロック、開く、およびクリックを追跡します。

# 使ってみる

上記リソースと Azure Functions で指定されたメールアドレスにメールを送信する API を作ってみる。
大まかな手順は以下。

1. Azure Communication Services (ACS) のリソースを作る
1. E-mail Communication Services (ECS) のリソースを作る
    1. ECS に Azure マネージドドメインを追加する
    1. ACS に ECS を接続する
1. メール送信のコードを書く
1. Azure Functions にコードをデプロイする
1. HTTP のリクエストを投げてメールが送信されるか確認する

:::note info
ACS, ECS などの略称はこの記事内のものです。正式な略称は不明です…
:::

## ACS のリソースを作る

公式ドキュメントに沿って進める。

https://learn.microsoft.com/ja-jp/azure/communication-services/quickstarts/create-communication-resource?tabs=windows&pivots=platform-azp

## ECS のリソースを作る

:::note warn
E-mail Communication Services は現在プレビュー機能です。
SLA なしに提供されているので、使用する環境にはご注意ください。
:::

これも公式ドキュメントに沿って進める。

https://learn.microsoft.com/ja-jp/azure/communication-services/quickstarts/email/create-email-communication-resource

### ECS に Azure マネージドドメインを追加する

これも公式ドキュメントに沿って。

https://learn.microsoft.com/ja-jp/azure/communication-services/quickstarts/email/add-azure-managed-domains

必要に応じて差出人のアドレスや表示名を変更する。

### ACS に ECS を接続する

これも公式ドキュメント。

https://learn.microsoft.com/ja-jp/azure/communication-services/quickstarts/email/connect-email-communication-resource

## メール送信のコードを書く

これも (以下略

https://learn.microsoft.com/ja-jp/azure/communication-services/quickstarts/email/send-email?pivots=programming-language-python

:::note info
ここでは Python で書いていきます。
:::

書き上げた Python コードを実行すると、指定したメールアドレスに対して作成したドメインからのメールが届く。

## Azure Functions にコードをデプロイする

Azure Functions のリソースは事前に作成しておく (作成方法は検索すれば出てくると思います！)。必要に応じて認証レベルも設定する。
今回は HTTP リクエストで呼び出したいので、HTTP trigger のテンプレートで作成する。[メール送信のコード書く](#メール送信のコードを書く) で書いたコードを Functions 用に修正する。
以下が今回作成した Functions 用のコード。クエリパラメータもしくはリクエストボディ内の `mail` に送信するメールアドレスを指定する形。お試しでやっているだけなので、`GET` や `POST` も特に区別はしていない (HTTP trigger のテンプレートに沿っただけ)。接続文字列もハードコーディングしちゃっている。

``` python
import logging

import azure.functions as func
from azure.communication.email import EmailClient, EmailContent, EmailAddress, EmailRecipients, EmailMessage

CONNECTION_STRING = '<YOUR CONNECTION STRING>' # ひとまずハードコーディング

def main(req: func.HttpRequest) -> func.HttpResponse:
    logging.info('Python HTTP trigger function processed a request.')

    # check parameters
    mail = req.params.get('mail')   # mail field in request query
    if not mail:
        try:
            req_body = req.get_json()
        except ValueError:
            pass
        else:
            mail = req_body.get('mail') # mail field in request body
    logging.info(f'mail to: {mail}')

    if not mail:
        res = '{"message": "You need a mail field in request query or body"}'
        return func.HttpResponse(res, status_code=400)
    else: 
        email_client = EmailClient.from_connection_string(CONNECTION_STRING)

        content = EmailContent(
            subject="Welcome to Azure Communication Services Email",
            plain_text="This email message is sent from Azure Communication Services Email using the Python SDK."
        )

        address = EmailAddress(email=mail)
        recipient = EmailRecipients(to=[address])

        message = EmailMessage(
                    sender="<YOUR EMAIL DOMAIN>",
                    content=content,
                    recipients=recipient
                )

        email_client.send(message) # send an e-mail
        return func.HttpResponse(f"An e-mail to {mail} will be sent.")
```

`func start` でローカルで Functions を立ち上げてリクエストを投げてみる。リクエスト投げるのには、[REST Client](https://qiita.com/toshi0607/items/c4440d3fbfa72eac840c) という VSCode の拡張機能が便利。
正しく `mail` パラメータを設定していると以下のようなレスポンスが返ってくる。

``` HTTP
HTTP/1.1 200 OK
Connection: close
Content-Type: text/plain; charset=utf-8
Date: ***, ** *** **** **:**:** GMT
Server: Kestrel
Transfer-Encoding: chunked

An e-mail to <THE EMAIL ADDRESS YOU SPECIFIED IN CODE> will be sent.
```

ローカルで動作確認したら Azure 上にデプロイする (方法は Let's google it!) 。デプロイ後に URL が定まるので、そこに対してローカルの時と同様にリクエストを投げる。うまく動作すれば指定したメールアドレス宛にメールが届くはず！

# ということで

何らかの通知を行うためのメール通知機能を実装できた。ACS の他の通知 (SMS など) も試せれば記事にしようと思います。

以上です！