【Java】Amazon SESを利用してメールを送信する

# はじめに

AWSのSES(Simple Email Service)を使用する機会があったため、復習も兼ねて、Javaプログラムでメール送信する方法をまとめたいと思います。
SMTPを使用する方法とAWS SDKを使用する方法を記載します。

# Amazon SESについて

- Amazon SES(Simple Email Service)はAmazonが提供するメール配信サービス
- 導入コストが低く、小規模で安価な運用が可能
- 毎月最初の 62,000 通のメールについては無料で送信できる([SES料金](https://aws.amazon.com/jp/ses/pricing/))
- AWSの他のサービスを使用することでメールログの保存や分析が可能

# 事前準備(SESコンソール)

プログラムを作成する前に下記をする必要があります。

## 送信元(From)アドレスの認証、送信先(To)アドレスの認証

>アカウントはサンドボックスと呼ばれるテスト環境に新規ユーザーとして作成されるため、確認した E メールアドレスでの E メール送受信のみができます。
未確認の E メールアドレスに E メールを送信する、1 日あたりに送信できる E メールの数を増やす、高速で E メールを送信するためには、アカウントをサンドボックスの外に移動する必要があります。

#### 手順

1. AWSにログインし、SESコンソールを開く
2. 「Email Addresses」をクリック
3. 「Verify a New Email Address」ボタンをクリック
4. 認証するメールアドレスを入力して、「Verify This Email Address」ボタンをクリック
5. 受信したメール内のリンクをクリック
6. 手順2.の画面を開くと指定したメールアドレスのVerification Statusがverified(認証済み)になっている

これでメールアドレスの認証は完了です。
「Send a Test Email」ボタンをクリックでメールが送受信できるか確認できます。

## SMTPユーザーを作成して認証情報(ユーザー名とパスワード)を取得する(**SMTPを使用する場合のみ**)

#### 手順

1. AWSにログインし、SESコンソールを開く
2. 「SMTP Settings」をクリック
3. 「Create My SMTP Credentials」ボタンをクリック
4. SMTPユーザーの名前を入力して「作成」ボタンをクリック(名前はデフォルト値でも可)
5. 「ユーザーの SMTP セキュリティ認証情報を表示」をクリック
6. 表示された認証情報をコピーして安全な場所に保存しておく or 「認証情報のダウンロード」でcsvをダウンロード

IAMコンソール > アクセス管理 > ユーザー で作成したSMTPユーザーを確認できます。

## アクセスキーIDとシークレットアクセスキーを取得(**AWS SDKを使用する場合のみ**)

#### 手順

1. AWSにログインし、IAMコンソールを開く
2. ダッシュボードのルートアクセスキーの削除のプルダウンの「セキュリティ認証情報の管理」ボタンをクリック
3. アクセスキーのプルダウンの「新しいアクセスキーの作成」ボタンをクリック
4. アクセスキーIDとシークレットアクセスキーをメモするか、キーファイルをダウンロードをする

# 動作環境

- Eclipse Version: 2020-06 (4.16.0)
- javaバージョン

```console
$ java -version
java version "1.8.0_231"
Java(TM) SE Runtime Environment (build 1.8.0_231-b11)
Java HotSpot(TM) 64-Bit Server VM (build 25.231-b11, mixed mode)
```

# Javaプログラム SMTP

1. EclipseでMavenプロジェクトを作成
2. pom.xmlにJavaMailの依存関係を追加([MvnRepository](https://mvnrepository.com/)でJavaMailを検索して最新バージョンのjarを追加)
3. メール送信プログラム作成

```java:pom.xml 
  <!-- 依存関係 -->
  <dependencies>
    <dependency>
      <groupId>com.sun.mail</groupId>
      <artifactId>javax.mail</artifactId>
      <version>1.6.2</version>
    </dependency>
  </dependencies>
```

```java:SesSmtpSample.java
public class SesSmtpSample {

	// 送信者アドレスと送信者名(SESコンソールで認証したメールアドレス)
    static final String FROM = "sender@example.com";
    static final String FROMNAME = "Sender Name";

    // 宛先アドレス(SESコンソールで認証したメールアドレス)
    static final String TO = "recipient@example.com";

    // SESコンソールで作成したSMTPユーザー名とパスワード
    static final String SMTP_USERNAME = "smtp_username";
    static final String SMTP_PASSWORD = "smtp_password";

    // SESコンソールで作成したConfig Setを指定。メールログの保存をするときなどに使用する。今回は不要なのでコメントアウト
    // static final String CONFIGSET = "ConfigSet";

    // Amazon SES SMTPのエンドポイント(リージョンがオレゴンの場合はus-west-2)
    static final String HOST = "email-smtp.us-west-2.amazonaws.com";

    // Amazon SES SMTPのエンドポイントのポート番号.
    static final int PORT = 587;

    // メール件名
    static final String SUBJECT = "Amazon SES test (SMTP interface accessed using Java)";
    // 本文
    static final String BODY = String.join(
    	    System.getProperty("line.separator"),
    	    "<h1>Amazon SES SMTP Email Test</h1>",
    	    "<p>This email was sent with Amazon SES using the ",
    	    "<a href='https://github.com/javaee/javamail'>Javamail Package</a>",
    	    " for <a href='https://www.java.com'>Java</a>."
    	);

	public static void main(String[] args) throws Exception {
		
		// SMTPサーバーを定義
		Properties props = System.getProperties();
    	props.put("mail.transport.protocol", "smtp");
    	props.put("mail.smtp.port", PORT);
    	props.put("mail.smtp.starttls.enable", "true");
    	props.put("mail.smtp.auth", "true");

    	// メールセッションの確立
    	Session session = Session.getDefaultInstance(props);

    	// メール作成
        MimeMessage msg = new MimeMessage(session);
        msg.setFrom(new InternetAddress(FROM,FROMNAME));
        msg.setRecipient(Message.RecipientType.TO, new InternetAddress(TO));
        msg.setSubject(SUBJECT);
        msg.setContent(BODY,"text/html");

        // Configuration Setを設定。今回は使用しないのでコメントアウト
        //msg.setHeader("X-SES-CONFIGURATION-SET", CONFIGSET);

        Transport transport = session.getTransport();

        // メール送信
        try {
            System.out.println("Sending...");

            // SMTPサーバに接続
            transport.connect(HOST, SMTP_USERNAME, SMTP_PASSWORD);

            // メール送信
            transport.sendMessage(msg, msg.getAllRecipients());
            System.out.println("Email sent!");
        } catch (Exception ex) {
            System.out.println("The email was not sent.");
            System.out.println("Error message: " + ex.getMessage());
        } finally {
            // 接続終了
            transport.close();
        }
	}
}

```

SMTPのエンドポイントはリージョンによって変わります。
AWSの[リファレンス](https://docs.aws.amazon.com/general/latest/gr/rande.html#ses_region)で確認できます。

# Javaプログラム AWS SDK

#### AWS Toolkit for Eclipseをインストール

1. Eclipseを起動し、「Eclipceマーケットプレイス」を開く
2. 「aws」で検索すると一番上に「AWS Toolkit for Eclipse」があるはずなので、それをインストール
3. インストール後にEclipceを再起動すると、AWSのアクセスキーIDとシークレットアクセスキーの入力が求められるため、入力する

上記の作業を行うとホームディレクトリに認証情報の共有ファイルが作成されます。
このファイルがないとAWS SDKを使用したプログラムは動かないようです。

|OS|ファイルパス|
|:---|:---|
|Windows|C:\Users\<yourUserName>\.aws\credentials|
|Linux, macOS, or Unix|~/.aws/credentials|


```:credencials
[default]
aws_access_key_id = YOUR_AWS_ACCESS_KEY_ID
aws_secret_access_key = YOUR_AWS_SECRET_ACCESS_KEY
```

#### AWS Java Projectを作成

1. 「File」メニューで「AWS Java Project」を選択
2. プロジェクト名を入力して、AWS SDK for Java Samplesで「Amazon Simple Email Service JavaMail Sample」を選択して、「完了」ボタンをクリック
3. 「AmazonSESSample.java」が作成されるので、それを編集

```java:AmazonSESSample.java
public class AmazonSESSample {

  // 送信者アドレス(SESコンソールで認証したメールアドレス)
  static final String FROM = "sender@example.com";

  // 宛先アドレス(SESコンソールで認証したメールアドレス)
  static final String TO = "ecipient@example.com";

  // SESコンソールで作成したConfig Setを指定。メールログの保存するときなどに使用する。今回は不要なのでコメントアウト
  // static final String CONFIGSET = "ConfigSet";

  // メール件名
  static final String SUBJECT = "Amazon SES test (AWS SDK for Java)";

  // 本文(HTMLメール用)
  static final String HTMLBODY = "<h1>Amazon SES test (AWS SDK for Java)</h1>"
      + "<p>This email was sent with <a href='https://aws.amazon.com/ses/'>"
      + "Amazon SES</a> using the <a href='https://aws.amazon.com/sdk-for-java/'>"
      + "AWS SDK for Java</a>";

  // 本文(HTMLメール以外)
  static final String TEXTBODY = "This email was sent through Amazon SES "
      + "using the AWS SDK for Java.";

  public static void main(String[] args) throws IOException {

    try {
      AmazonSimpleEmailService client =
          AmazonSimpleEmailServiceClientBuilder.standard()
            // リージョンを指定(US_WESST_2はオレゴン)
            .withRegion(Regions.US_WEST_2).build();
      SendEmailRequest request = new SendEmailRequest()
          .withDestination(
              new Destination().withToAddresses(TO))
          .withMessage(new Message()
              .withBody(new Body()
                  .withHtml(new Content()
                      .withCharset("UTF-8").withData(HTMLBODY))
                  .withText(new Content()
                      .withCharset("UTF-8").withData(TEXTBODY)))
              .withSubject(new Content()
                  .withCharset("UTF-8").withData(SUBJECT)))
          .withSource(FROM);
          // Configuration Setを設定。今回は使用しないのでコメントアウト
          // .withConfigurationSetName(CONFIGSET);
      client.sendEmail(request);
      System.out.println("Email sent!");
    } catch (Exception ex) {
      System.out.println("The email was not sent. Error message: "
          + ex.getMessage());
    }
  }
}
```

# おわりに

Amazon SESの日本語ドキュメントがあるため、基本的にはドキュメント通りにやっていけば問題なくメール送信できると思います。