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.
- 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>
- 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.
- 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
- Configuration Properties Bean
@Component
@ConfigurationProperties(prefix = "spring.mail")
@Data
public class MailProps {
private String username;
}
- 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);
}
}
}
- 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>
<ult><span class="code">${code}</span></p>
<p>Valid for 10 minutes.</p>
</div>
</body>
</html>
- 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(...).