Spring Boot Email Integration with FreeMarker Templates

Integrating email capabilities into a Spring Boot application is straightforward with the spring-boot-starter-mail. Below is a conncise walk-through that covers dependency setup, provider credentials, template engines, and a reusable service layer.

  1. Maven Dependencies

<parent>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-parent</artifactId>
    <version>2.7.18</version>
    <relativePath/>
</parent>

<dependencies>
    <dependency>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-web</artifactId>
    </dependency>

    <dependency>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-mail</artifactId>
    </dependency>

    <dependency>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-freemarker</artifactId>
    </dependency>

    <dependency>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-thymeleaf</artifactId>
    </dependency>
</dependencies>

  1. QQ Mail Authorization

Enable POP3/SMTP in QQ Mail → Settings → Accounts. After sending the verification SMS, save the generated 16-character authorization code; it will be used as the SMTP password.

  1. SMTP Configuration

spring:
  mail:
    host: smtp.qq.com
    username: your_account@qq.com
    password: 16_char_authorization_code
    properties:
      mail:
        smtp:
          auth: true
          port: 587
          starttls:
            enable: true
            required: true

Port 587 (STARTTLS) is preferred over 25 because many cloud providers block port 25. Verify connectivity with:

$ telnet smtp.qq.com 587
  1. Configuration Properties Bean

@Component
@ConfigurationProperties(prefix = "spring.mail")
@Data
public class MailProps {
    private String username;
}

  1. Email Service Layer

public interface MailNotifier {
    void sendCode(String recipient, String verificationCode, String templateName);
}

@Service
@RequiredArgsConstructor
public class FreemarkerMailNotifier implements MailNotifier {

    private final JavaMailSender mailSender;
    private final MailProps mailProps;
    private final FreeMarkerConfigurer freeMarkerConfigurer;

    @Override
    public void sendCode(String recipient, String verificationCode, String templateName) {
        try {
            MimeMessage message = mailSender.createMimeMessage();
            MimeMessageHelper helper = new MimeMessageHelper(message, true, StandardCharsets.UTF_8.name());

            helper.setFrom(new InternetAddress(mailProps.getUsername(), "MyApp", StandardCharsets.UTF_8.name()));
            helper.setTo(recipient);
            helper.setSubject("Verification Code");

            Map<String, Object> model = Map.of("code", verificationCode);
            Template tpl = freeMarkerConfigurer.getConfiguration().getTemplate(templateName);
            String html = FreeMarkerTemplateUtils.processTemplateIntoString(tpl, model);

            helper.setText(html, true);
            mailSender.send(message);
        } catch (Exception ex) {
            throw new MailSendException("Unable to send mail", ex);
        }
    }
}

  1. FreeMarker Template

Save the following as src/main/resources/templates/verify.ftl:

<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>Verification</title>
    <style>
        body { font-family: Arial, sans-serif; margin: 0; padding: 20px; }
        .box { max-width: 600px; margin: auto; padding: 20px; border: 1px solid #ddd; border-radius: 8px; }
        .code { font-size: 32px; font-weight: bold; color: #333; background: #f7f7f7; padding: 8px 12px; border-radius: 4px; }
    </style>
</head>
<body>
    <div class="box">
        <p>Your verification code:</p>
        &ltult><span class="code">${code}</span></p>
        <p>Valid for 10 minutes.</p>
    </div>
</body>
</html>

  1. Usage Example

@RestController
@RequiredArgsConstructor
public class AuthController {
    private final MailNotifier mailNotifier;

    @PostMapping("/send-code")
    public void sendCode(@RequestParam String email) {
        String code = RandomStringUtils.randomNumeric(6);
        mailNotifier.sendCode(email, code, "verify.ftl");
    }
}

With the above setup, any controller or service can trigger a templated email by invoking mailNotifier.sendCode(...).

Tags: Spring Boot JavaMail FreeMarker smtp QQ Mail

Posted on Sat, 30 May 2026 00:39:53 +0000 by bryansu