Java で Amazon SES SMTP を使用してメールを送信する

会員がログインパスワードを忘れたとき、登録してあるメールアドレスにメールを送信してその中のリンクを押すとパスワードがリセットされる、というのをやりたかったので、AWS 上のWebアプリにメール送信機能を実装。

メール送信機能は jar ファイルにして部品化。

プログラミングより AWS の設定が面倒臭い気がしました。

#1.環境
VS Code
Java Extension Pack
Spring Boot Extension Pack

#2.SMTP認証情報の習得

以下の URL の内容の通り、AWS のコンソールにログインして「Amazon SES コンソールを使用して Amazon SES SMTP 認証情報を取得する」の1～6を実施してSMTPユーザー名とSMTPパスワードを取得します。

取得するとメールサーバー名とポート番号も表示されます。

https://docs.aws.amazon.com/ja_jp/ses/latest/DeveloperGuide/smtp-credentials.html

#3.Gradle Project の作成

VS Code のコマンドパレットで「Spring Initializr: Generate a Gradle Project」 → 「Java」 → 「任意のGroupId」 → 「任意のArtifactId」 → 「任意のバージョン」 → 「dependenceies は空白」を選択して Gradle Project を作成します。
（別に Spring Boot じゃなくてもいいですけど…）

#4.依存関係の追加とか

Amazon SES SMTP を使用してメールを送信するために必要な javax.mail.jar を取得するため、build.gradle ファイルに依存関係を追加します。

```gradle:build.gradle
dependencies {
	implementation 'org.springframework.boot:spring-boot-starter-web'
	compileOnly 'com.sun.mail:javax.mail:1.6.2' //←追加★
	testImplementation('org.springframework.boot:spring-boot-starter-test') {
		exclude group: 'org.junit.vintage', module: 'junit-vintage-engine'
	}
}

//↓ついでに追加★
bootJar {
    enabled = false
}
jar {
    enabled = true
	baseName = 'aws-ses-send'
	version = ''
	from configurations.compileClasspath.collect { it.isDirectory() ? it : zipTree(it) }
}
```

#5.実装

AWSのサイトのコードをほぼそのまま使います。

```java:AmazonSES.java
package com.xxx.aws;

import java.util.Properties;

import javax.mail.Message;
import javax.mail.Session;
import javax.mail.Transport;
import javax.mail.internet.InternetAddress;
import javax.mail.internet.MimeMessage;

public class AmazonSES {

    // Replace sender@example.com with your "From" address.
    // This address must be verified.
    static final String FROM = "送信元メールアドレス";
    static final String FROMNAME = "送信元名";
	
    // Replace recipient@example.com with a "To" address. If your account 
    // is still in the sandbox, this address must be verified.
    // static final String TO = "recipient@example.com";
    
    // Replace smtp_username with your Amazon SES SMTP user name.
    static final String SMTP_USERNAME = "SMTPユーザー名";
    
    // Replace smtp_password with your Amazon SES SMTP password.
    static final String SMTP_PASSWORD = "SMTPパスワード";
    
    // The name of the Configuration Set to use for this message.
    // If you comment out or remove this variable, you will also need to
    // comment out or remove the header below.
    // static final String CONFIGSET = "ConfigSet"; //←不要ならコメントアウト★
    
    // Amazon SES SMTP host name. This example uses the 米国西部 (オレゴン) region.
    // See https://docs.aws.amazon.com/ses/latest/DeveloperGuide/regions.html#region-endpoints
    // for more information.
    static final String HOST = "メールサーバー名";
    
    // The port you will connect to on the Amazon SES SMTP endpoint. 
    static final int PORT = ポート番号;
    
    // 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 void send(String to,
								String subject,
								String body) throws Exception {

        // Create a Properties object to contain connection configuration information.
    	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");

        // Create a Session object to represent a mail session with the specified properties. 
    	Session session = Session.getDefaultInstance(props);

        // Create a message with the specified information. 
        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");
        
        // Add a configuration set header. Comment or delete the 
        // next line if you are not using a configuration set
        // msg.setHeader("X-SES-CONFIGURATION-SET", CONFIGSET);//←不要ならコメントアウト★
            
        // Create a transport.
        Transport transport = session.getTransport();
                    
        // Send the message.
        try
        {
            System.out.println("Sending...");
            
            // Connect to Amazon SES using the SMTP username and password you specified above.
            transport.connect(HOST, SMTP_USERNAME, SMTP_PASSWORD);
        	
            // Send the email.
            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
        {
            // Close and terminate the connection.
            transport.close();
        }
    }
}
```

https://docs.aws.amazon.com/ja_jp/ses/latest/DeveloperGuide/send-using-smtp-java.html

#6.送信元として有効なメールアドレスをAWSに登録する

以下の URL の内容の通り、AWS のコンソールにログインして「Amazon SES コンソールを使用して E メールアドレスを検証する」の1～7を実施して、送信元として有効なメールアドレスを登録します。

この手順が終わったメールアドレスのみ送信元メールアドレスとして使えます。

https://docs.aws.amazon.com/ja_jp/ses/latest/DeveloperGuide/verify-email-addresses-procedure.html

#7.送信先の制限を外す

この状態だと、送信先を自由に選択してメールを送ることはできません。

送信先のメールアドレスも送信元同様、送信先としてメールを送信できるか事前に検証してOKになってないる必要があります。

「サンドボックスの中にいる」という状況です。

送信先を自由に選択してメールを送るには「サンドボックスの外に出る」必要があります。

以下の URL の内容の通り、AWS のコンソールにログインして「Amazon SES サンドボックス外への移動」の1～9を実施して、サポートセンターから許可をもらいます。

https://docs.aws.amazon.com/ja_jp/ses/latest/DeveloperGuide/request-production-access.html

許可がもらえれば送信先の事前検証は不要になります。

#8.実行

VS Code のターミナルから以下のコマンドを実装して、jar ファイルを作成します。

```
.\gradlew build
```

作成した jar ファイルを呼び出し元のプロジェクトに配置して、実装した send メソッドを呼べばメール送信できます。

以上です。