MavenなしでJava Webアプリケーションからメールを送信する

Servlet & JSPでWebアプリケーションを作った際に、ごり押しで解決したトピックですが、後で検証できるように備忘録的な感じで投稿してみます。

# やりたいこと
1. Azure上のサービスから、メールを送信したい
→ [Azure メール通信サービス](https://learn.microsoft.com/ja-jp/azure/communication-services/quickstarts/email/create-email-communication-resource)のリソースを[Azure Communication Service](https://learn.microsoft.com/ja-jp/azure/communication-services/quickstarts/create-communication-resource?tabs=windows&pivots=platform-azp)リソースに接続してあげる
2. Eclipseの動的WebプロジェクトでMavenを使わずになんとかやりたい
→ [azure-communication-email](https://learn.microsoft.com/ja-jp/azure/communication-services/quickstarts/email/send-email?tabs=windows%2Cconnection-string&pivots=programming-language-java)のパッケージをJARファイルで直接インストールする
3. Javaで書いたサービスからメールを送信したい
→ インストールしてきた[azure-communication-email](https://learn.microsoft.com/ja-jp/azure/communication-services/quickstarts/email/send-email?tabs=windows%2Cconnection-string&pivots=programming-language-java)パッケージのもろもろのクラスを活用する

# 1. Azure上でメール通信サービスの環境を整える
Azure Portal上でメール通信サービスを実現するためのリソースを作成してつなげていきます。

## 1.1 Azure Portalにサインインする
[Azure Portal](https://portal.azure.com/)にサインインしてください。無料試用版のアカウントの作成もできます。

## 1.2 Azure Communication Serviceのリソースを作成する
Azure Portalのホームに着いたら、[**リソースの作成**]から[**Communication Services**]を検索するなりして見つけてください。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2518330/1ab4181c-5340-f6ca-738c-a686b8cd4d7f.png)
これを作成します。サブスクリプションやリソース名などを適切なものに設定し、[**レビューと作成**]まで行って作っちゃいましょう。作成してからデプロイし終わるまでは幾分か時間がかかるので気長に待ちます。

## 1.3 メール通信サービスのリソースを作成する
Azure Portalのホームに戻って、[**リソースの作成**]から[**Email Communication Services**]を検索するなりして見つけてください。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2518330/0e00116e-b141-bf6f-cdef-4af9d7bdfcd7.png)
今度はこれを作成します。サブスクリプションやリソース名などを適切なものに設定し、[**レビューと作成**]まで行って作っちゃいましょう。作成してからデプロイし終わるまでは幾分か時間がかかるのでやっぱり気長に待ちます。

デプロイし終えたら、メールドメインを作成します。Azure Portalのホームに戻って、作成したメール通信サービスのリソースを選択します。サイドバーから[**設定**]→[**ドメインをプロビジョニングする**]を選んであげると、[**無料のAzureサブドメインを追加する**]というのが出てきます。今回は無料で全部済ませたい人間なので、[**1クリックで追加**]から追加していきましょう。Azureサブドメインの展開が済むのを待ってあげてください。

## 1.4 Azure Communication Serviceにメール通信サービスを接続する
さっき作ったAzure Communication Serviceのリソースに、メールドメインを接続します。
Azure Portalのホームに戻って、[**すべてのリソース**]から先ほど作った**Azure Communication Service**のリソースを選びます。左のサイドバーの中から[**メール**]→[**ドメイン**]を選んであげると、[**ドメインの接続**]というのが出てくるので、それをクリックします。ここで、サブスクリプションやリソースグループなどを適切に設定します。[**電子メールサービス**]は先ほど作った**メール通信サービス**のリソースを選んで、[**確認済みのドメイン**]も先ほど作ったAzureサブドメインを選べば、あとは接続して完了です。

# 2. azure-communication-emailをプロジェクトにセットアップする
ここまででAzure側の準備は終わっているので、次はプロジェクト側のセットアップを行っていきます。

## 2.1 jarファイルのダウンロード（自己責任）
今回はMavenを使わないプロジェクトで行いたいので、[Azure公式ドキュメントでのやり方](https://learn.microsoft.com/ja-jp/azure/communication-services/quickstarts/email/send-email?tabs=windows%2Cconnection-string&pivots=programming-language-java)が使えません。(pom.xmlがないため) そこで、パッケージのjarファイルを直接ダウンロードしてきて、プロジェクトのビルドパスに追加するというやり方で今回はやってみます。

今回使いたいパッケージやその依存パッケージのjarファイルはここからダウンロードできます。
 → [jar-download.com](https://jar-download.com/artifacts/com.azure/azure-communication-email)

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2518330/a649b927-f2b9-bc47-9c57-932875723dc2.png)

広告に騙されずに、[**Download azure-communication-email.jar**]までたどり着きましょう。（※**ダウンロードは自己責任でお願いします**）

## 2.2 ダウンロードしたjarファイルをlibフォルダに配置し、ビルドパスを通す
Eclipseの動的Webプロジェクトなら、`/WEB-INF/lib`フォルダが作られているかと思うので、そこへダウンロードしてきたjarファイルを配置しましょう。配置できたら、Eclipse上で追加したjarファイルを右クリックして[**ビルドパスに追加**]しましょう。
これで、プロジェクト内のJavaプログラムから`com.azure.communication.email`パッケージ内のクラスを利用できるようになります。

# 3. Javaプログラムを書いてメールを送信してみる
[Azure公式ドキュメントでのやり方](https://learn.microsoft.com/ja-jp/azure/communication-services/quickstarts/email/send-email?tabs=windows%2Cconnection-string&pivots=programming-language-java)を参考にして、Javaプログラムからメールを送信します。本記事では、`EmailClientManager`というクラスを新たに定義しておいて、後述する`sendEmail()`メソッドによってメールの送信を可能にしていきます。

## 3.1 EmailClientインスタンスの作成
Azure上のメール通信サービスに接続するためには、`EmailClient`インスタンスを作成すればよいです。`EmailClient`インスタンスを利用したいときには`EmailClientManager`のインスタンスを宣言し、フィールド`emailClient`を参照することで前述の内容を実現します。
```Java
public class EmailClientManager {
    // Field
    private EmailClient emailClient;
    private static final String CONNECTION_STRING = "<Azure Portal上でコピペしてきた接続文字列>";
    private static final String SENDER_ADDRESS = "<Azure Portal上でコピペしてきた送信用メアド>";
    
    // Constructor
    public EmailClientManager () {
        try{
            this.emailClient = new EmailClientBuilder().connectionString(CONNECTION_STRING).buildClient();
            System.out.println("メールサービスコネクションに成功");
        } catch (RuntimeException e){
            throw new RuntimeException("メールサービスコネクションに失敗", e);
        }
    }
}
```
ここで、
- `CONNECTION_STRING`: 作成した通信サービスのリソースを選んで、[**設定**]→[**キー**]から、主キーの接続文字列をコピペしてくる
- `SENDER_ADDRESS` : 作成したメール通信サービスのリソースを選んで、[**設定**]→[**ドメインをプロビジョニングする**]から作成したドメインを選択。[**Email services**]の[**MailFrom addresses**]からMailFromアドレスをコピペしてくる

で、おｋです。
(※接続文字列のハードコーディングはよくないですが、今回は割愛します。参考→[Azure Active Directoryによる認証](https://learn.microsoft.com/ja-jp/azure/communication-services/quickstarts/identity/service-principal?pivots=platform-azcli))

## 3.2 sendEmail()メソッドの作成
[Azure公式ドキュメント](https://learn.microsoft.com/ja-jp/azure/communication-services/quickstarts/email/send-email?tabs=windows%2Cconnection-string&pivots=programming-language-java#basic-email-sending)のやり方とほぼ同じ内容を書いていきます。

```Java
import java.time.Duration;

public class EmailClientManager {
    // Field
    private EmailClient emailClient;
    private static final String CONNECTION_STRING = "<Azure Portal上でコピペしてきた接続文字列>";
    private static final String SENDER_ADDRESS = "<Azure Portal上でコピペしてきた送信用メアド>";
    private static final Duration POLLER_WAIT_TIME = Duration.ofSeconds(1);   

    // Constructor
    public EmailClientManager () {
        // 省略
    }

    // Emailを送信するメソッド
    public void sendEmail (EmailMessage message) {
        // 送信元アドレスを設定
    	message.setSenderAddress(SENDER_ADDRESS);

    	try {
		    SyncPoller<EmailSendResult, EmailSendResult> poller = emailClient.beginSend(message, null);

		    PollResponse<EmailSendResult> pollResponse = null;
		    Duration timeElapsed = Duration.ofSeconds(0);

		    while (pollResponse == null
		            || pollResponse.getStatus() == LongRunningOperationStatus.NOT_STARTED
		            || pollResponse.getStatus() == LongRunningOperationStatus.IN_PROGRESS) {
		        pollResponse = poller.poll();
		        System.out.println("Email send poller status: " + pollResponse.getStatus());

		        Thread.sleep(POLLER_WAIT_TIME.toMillis());
		        timeElapsed = timeElapsed.plus(POLLER_WAIT_TIME);

		        if (timeElapsed.compareTo(POLLER_WAIT_TIME.multipliedBy(18)) >= 0) {
		            throw new RuntimeException("Polling timed out.");
		        }
		    }

		    if (poller.getFinalResult().getStatus() == EmailSendStatus.SUCCEEDED) {
		        System.out.printf("Successfully sent the email (operation id: %s)", poller.getFinalResult().getId());
		    } else {
		        throw new RuntimeException(poller.getFinalResult().getError().getMessage());
		    }
		} catch (Exception e) {
		    throw new RuntimeException("メールの送信に失敗しました", e);
		}
    }
}
```

## 3.3 EmailClientManagerを使ったサービスを作る
これで事前準備は完了したので、あとはやりたいことに合わせて`EmailClientManager`のインスタンスを作成し、メールを送信していきます。

```java
public class MailTest {
    public static void main(String[] args) {
        //  EmailClientManagerのインスタンス作成
        EmailClientManager emailClientManager = new EmailClientManager();
        
        // 本文作成
        EmailMessage message = new EmailMessage();
        message.setToRecipients("送信先メアド");
        message.setSubject("メール件名");
        message.setBodyPlainText("本文");
        // message.setBodyHtml("HTMLも行けます");
    
        // メール送信
        emailClientManager.sendEmail(message);
        return;

    }
}

```

メールの送信内容は`EmailMessage`インスタンスを作ることで簡単に設定できます。

# 参考リンク
- [Azure Communication Serviceを使用して電子メールを送信する方法](https://learn.microsoft.com/ja-jp/azure/communication-services/quickstarts/email/send-email?tabs=windows%2Cconnection-string&pivots=programming-language-java)
- [Azure Communication Serviceでメール通信サービスのリソースを作成して管理する](https://learn.microsoft.com/ja-jp/azure/communication-services/quickstarts/email/create-email-communication-resource)