Spring Boot アプリケーションから AWS SES でメールを送る


## はじめに

Spring Boot アプリケーションから AWS SES でメールを送る執筆時点のまとまった情報がないので書く

次を想定する

- AWS <abbr title="Simple Email Service">SES</abbr>
    - メールは API で送る。SMTP ではなく。
    - 本文などは日本語。MIME に変換して送る。
- Spring Boot 2.6
- Spring Cloud AWS 2.4
    - AWS EC2 または ECS 上で動く。認証情報は指定なくインスタンスプロファイルなどから得る
    - AWS ではないローカル環境では、認証情報は環境変数などで指定する
- Gradle 7.3
- Kotlin 1.6
- Java 17


## 依存を追加

Spring Cloud AWS 2.3 からいくつか名前や扱いが変わっています
https://spring.io/blog/2021/03/17/spring-cloud-aws-2-3-is-now-available

> the most surprising change is that now you need to include a separate Spring Cloud AWS BOM


Gradle, Kotlin では次のようになります

```kotlin
dependencyManagement {
    imports {
        mavenBom("io.awspring.cloud:spring-cloud-aws-dependencies:2.4.1")
    }
}
```

SES の話も書かれていますが、starter は見つからず、

> SES support has been extracted from the `context` module to separate `spring-cloud-aws-ses` module. There is also a dedicated starter: `spring-cloud-aws-ses-starter`.

> Could not find io.awspring.cloud:spring-cloud-aws-ses-starter:.

https://reflectoring.io/spring-cloud-aws-ses/#adding-the-dependencies を参考に、
次で動きました

```kotlin
implementation("io.awspring.cloud:spring-cloud-starter-aws-ses")
```

Spring でメールを扱うために次も加えます

```kotlin
implementation("org.springframework.boot:spring-boot-starter-mail")
```


## 設定

ここでは Java (Kotlin) で設定します。XML ではなく。

Spring でメールを扱う Spring Integration (Mail) のインターフェース JavaMailSener を実装する Bean を定義します
最小の設定を示します

```kotlin
@Configuration
class MailConfiguration {
    @Bean
    fun mailSender(): JavaMailSender {
        return SimpleEmailServiceJavaMailSender(
            AmazonSimpleEmailServiceClientBuilder.defaultClient()
        )
    }
}
```

この例では認証情報とリージョンを自動的に決定します
具体的には環境変数やインスタンスプロファイルなどいくつかの方法を順に試します

- [デフォルトの認証情報プロバイダチェーン](https://docs.aws.amazon.com/ja_jp/sdk-for-java/v2/developer-guide/credentials.html#credentials-default)
- [デフォルトリージョンプロバイダーチェーン](https://docs.aws.amazon.com/ja_jp/sdk-for-java/v2/developer-guide/java-dg-region-selection.html#automatically-determine-the-aws-region-from-the-environment)

決定方法は要件に合わない場合 [AmazonSimpleEmailServiceClientBuilder](https://docs.aws.amazon.com/AWSJavaSDK/latest/javadoc/com/amazonaws/services/simpleemail/AmazonSimpleEmailServiceClientBuilder.html) を使ってカスタマイズできます

```kotlin
    fun mailSender(): JavaMailSender {
        return SimpleEmailServiceJavaMailSender(
            AmazonSimpleEmailServiceClientBuilder.standard()
                /* withCredentials, withRegion などをメソッドチェーンして
                   カスタマイズした実装のインスタンスなどを渡す */
                .build()
        )
    }
```


## メールを送る

Bean を DI して、メールを送れます

```kotlin
@Service
class HogeServiceImpl(
    private val mailSender: JavaMailSender
): HogeService {
    override fun notifyHoge() {
        mailSender.send({ mimeMessage ->
            val helper = MimeMessageHelper(mimeMessage)
            helper.setFrom("noreply@example.com")
            helper.setTo("anyone@example.com")
            helper.setSubject("ほげについて")
            helper.setText("ほげ申し上げます")
        })
    }
}
```


## おわりに

Spring Boot アプリケーションから AWS SES でメールを送る執筆時点の状況や、設定の内容などを書いた。
Spring Cloud, Spring Integration, AWS SDK を連携して、小さい実装でメールを送れるようになった。