使用Spring Boot发送邮件【联系表单示例】

首先

参考这个页面后,我设法成功地使用Spring Boot 2发送电子邮件,但在点击“发送”按钮时遇到错误,或者因为点击太多次而发送了大量的邮件,经历了各种困难。因此,我想分享我自己改进的代码。

Maven 依赖

这次使用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>

范例

应用程序配置文件

本次使用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

观看

这是一个简单的问题查询表格。我们使用了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 – JavaScript

这是在按下发送按钮时执行的脚本。

$(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);
            }
        });
    });
});

模型

这是一个用于临时存储表单数据的模型。

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

控制器

表单显示

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文件,并进行操作确认。

(Paraphrased sentence may vary depending on the context. This is one possible interpretation in Chinese.)

我创建了一个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来实现定期执行任务(邮件发送)这个想法。

bannerAds