Help us understand the problem. What is going on with this article?

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

はじめに

こちらのページを参考にしながらSpring Boot 2を使ってメールを送信することにどうにか成功したのですが、途中送信ボタンを押した時にエラーが発生したり、クリックしすぎて大量にメールが送られたりと色々苦労したので、自分なりに改善したコードを共有したいと思います。

Maven Dependencies

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

<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を使用します

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 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です。

$(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

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

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

フォーム表示用

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";
    }
}

メール送信用

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関数を作成し、テストしてみます。

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

送信ボタンを一度押すと、複数回押せないようにボタンを一旦無効化します
Screen Shot 2019-03-24 at 2.13.14 pm.png

送信が成功すると以下のメッセージが表示されます
Screen Shot 2019-03-24 at 2.13.25 pm.png

無事メールが送信されました!
Screen Shot 2019-03-24 at 2.17.33 pm.png

次のステップ

今度は定期的なタスク(メール送信)実行をSpringで実現してみたいと思います。

Why not register and get more from Qiita?
  1. We will deliver articles that match you
    By following users and tags, you can catch up information on technical fields that you are interested in as a whole
  2. you can read useful information later efficiently
    By "stocking" the articles you like, you can search right away
Comments
No comments
Sign up for free and join this conversation.
If you already have a Qiita account
Why do not you register as a user and use Qiita more conveniently?
You need to log in to use this function. Qiita can be used more conveniently after logging in.
You seem to be reading articles frequently this month. Qiita can be used more conveniently after logging in.
  1. We will deliver articles that match you
    By following users and tags, you can catch up information on technical fields that you are interested in as a whole
  2. you can read useful information later efficiently
    By "stocking" the articles you like, you can search right away
ユーザーは見つかりませんでした