Spring Bootでメール送信【お問い合わせフォームサンプル】

#はじめに
[こちら](https://www.saka-en.com/java/spring-boot-email-send/)のページを参考にしながらSpring Boot 2を使ってメールを送信することにどうにか成功したのですが、途中送信ボタンを押した時にエラーが発生したり、クリックしすぎて大量にメールが送られたりと色々苦労したので、自分なりに改善したコードを共有したいと思います。

## Maven Dependencies
今回はspring-boot-starter-mailを利用してメールを送信します。
Ajaxを利用するために、jQueryのwebjarも追加してます。

```xml
<dependencies>
  <dependency>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-mail</artifactId>
  </dependency>
  <dependency>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-thymeleaf</artifactId>
  </dependency>		
  <dependency>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-web</artifactId>
  </dependency>
  <dependency>
    <groupId>org.projectlombok</groupId>
    <artifactId>lombok</artifactId>
    <optional>true</optional>
  </dependency>  
  <dependency>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-test</artifactId>
    <scope>test</scope>
  </dependency>
  <dependency>
    <groupId>org.webjars</groupId>
    <artifactId>bootstrap</artifactId>
    <version>4.3.1</version>
  </dependency>
  <dependency>
    <groupId>org.webjars</groupId>
    <artifactId>jquery</artifactId>
    <version>3.3.1-2</version>
  </dependency>
</dependencies>
```

#サンプル

##application.properties
今回はGmailを使用します

```properties
spring.mail.host=smtp.gmail.com
spring.mail.port=587
spring.mail.username={your_gmail_account}
spring.mail.password={your_app_password}
spring.mail.properties.mail.smtp.auth=true
spring.mail.properties.mail.smtp.starttls.enable=true
```

##View
簡単なお問い合わせフォームです。ThymeleaftとBootstrapを使用しています。

```html
<html xmlns:th="http://www.thymeleaf.org">
<head>
  <meta charset="utf-8">
  <link rel="stylesheet" media="all" 
        th:href="@{/webjars/bootstrap/4.3.1/css/bootstrap.min.css}">
  <script th:src="@{/webjars/jquery/3.3.1-2/jquery.min.js}"></script>
  <script src="js/script.js"></script>
  <title>Send email with Spring Boot</title>
</head>
<body>
  <div class="container">
    <h1 class="pb-2 mt-4 mb-2 border-bottom border-primary">
      お問い合わせ
    </h1>
    <div>
      <p>以下を入力して送信ボタンをクリックしてください。</p>
      <form name="contactform" id="contactform" role="form">
        <div class="form-group">
          <label for="inputName" class="col-sm-3">お名前</label>
          <div class="col-sm-9">
            <input type="text" class="form-control" name="name" 
                   placeholder="お名前" value="">
          </div>
        </div>
        <div class="form-group">
          <label for="inputEmail" class="col-sm-3">メールアドレス</label>
          <div class="col-sm-9">
            <input type="email" class="form-control" name="email" 
                   placeholder="メールアドレス" value="">
          </div>
        </div>
        <div class="form-group">
          <label for="inputMessage" class="col-sm-3">お問い合わせ内容</label>
          <div class="col-sm-9">
            <textarea class="form-control" name="message" rows="5">
            </textarea>
          </div>
        </div>
        <div class="text-center">
          <button type="button" name="btnSubmit" 
                  class="btn btn-success" id="btnSend">送信する</button>
        </div>
      </form>
    </div>
  </div>
</body>
</html>
```

##JavaScript
送信ボタンが押された際に実行されるscriptです。

```js
$(document).ready(function() {
	$('#btnSend').click(function() {
		$("#btnSend").prop("disabled", true);
		// フォームのデータをJSONに変換
		var rawData = $('#contactform').serializeArray();
		var data = {};
		jQuery.each(rawData, function(i, e) {
			data[e.name] = e.value;
		});
		// Ajaxを使ってメールを送信
		$.ajax({
			type: "POST",
			url: "./sendmail",
			dataType: "json",
			data: JSON.stringify(data),
			contentType: 'application/json',
			scriptCharset: 'utf-8',
			success: function(outdata, dataType) {
				if (outdata[0] == "OK") alert("メール送信しました");
				$("#btnSend").prop("disabled", false);
			},
			error: function(XMLHttpRequest, textStatus, errorThrown) {
				alert("Error : " + errorThrown);
				$("#btnSend").prop("disabled", false);
			}
		});
	});
});
```

##Model
フォームデータを一時的に格納するためのモデルです。

```java
package jp.co.e3sys.model;

import lombok.Getter;
import lombok.Setter;

@Getter
@Setter
public class ContactForm {
	private String name;
	private String email;
	private String message;
}
```

##Controller
フォーム表示用

```java
package jp.co.e3sys.controller;

import org.springframework.stereotype.Controller;
import org.springframework.ui.Model;
import org.springframework.web.bind.annotation.GetMapping;

@Controller
public class IndexController {
	@GetMapping("/")
	String index(Model model) {
		return "index";
	}
}
```
メール送信用

```java
package jp.co.e3sys.controller;

import java.util.Arrays;
import java.util.List;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.http.MediaType;
import org.springframework.mail.MailSender;
import org.springframework.mail.SimpleMailMessage;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;
import org.springframework.web.bind.annotation.ResponseBody;
import org.springframework.web.bind.annotation.RestController;

import jp.co.e3sys.model.ContactForm;

@RestController
public class SendMailController {
	@Autowired
	private MailSender mailSender;
	
	@RequestMapping(value="/sendmail", method=RequestMethod.POST, consumes=MediaType.APPLICATION_JSON_VALUE)
	@ResponseBody
	public List<String> sendmail(@RequestBody ContactForm form) {
		String body = "お名前: " + form.getName() + "\n" + 
				"メールアドレス: " + form.getEmail() + "\n" + 
				"メッセージ: \n" + form.getMessage();
		SimpleMailMessage msg = new SimpleMailMessage();
		msg.setFrom(form.getEmail());
		msg.setTo("xxx@gmail.com"); // 適宜変更してください
		msg.setSubject("お問い合わせがありました");
		msg.setText("お問い合わせは下記の通りです。\n\n---------------------------\n" + body + "\n---------------------------");
		mailSender.send(msg);
		return Arrays.asList("OK");
	}
}
```

##Application.javaを作成し、動作確認
main関数を作成し、テストしてみます。

```java
package com.example.app;

import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.context.annotation.ComponentScan;

@SpringBootApplication
@ComponentScan("com.example.controller") //コントローラのパッケージが別の場合
public class Application {

	public static void main(String[] args) {
		SpringApplication.run(Application.class, args);
	}
}
```

まずこんな感じで入力してみます。
![Screen Shot 2019-03-24 at 2.12.53 pm.png](https://qiita-image-store.s3.amazonaws.com/0/326104/7d431ba0-cde9-c60f-f14b-fa3ad281144a.png)

送信ボタンを一度押すと、複数回押せないようにボタンを一旦無効化します
![Screen Shot 2019-03-24 at 2.13.14 pm.png](https://qiita-image-store.s3.amazonaws.com/0/326104/07d4130b-f0c8-5722-762e-024cf1c0c51e.png)


送信が成功すると以下のメッセージが表示されます
![Screen Shot 2019-03-24 at 2.13.25 pm.png](https://qiita-image-store.s3.amazonaws.com/0/326104/bbfec7bd-73dd-7077-0ba7-75a890100be0.png)



無事メールが送信されました！
![Screen Shot 2019-03-24 at 2.17.33 pm.png](https://qiita-image-store.s3.amazonaws.com/0/326104/86ba1892-c143-f1f2-77fb-f079fbba9d09.png)


#次のステップ
今度は定期的なタスク（メール送信）実行をSpringで実現してみたいと思います。