基于 Spring Boot 的邮件管理器系统代码
概述
基于 Spring Boot 的邮件管理器系统,该系统可以部署在 1Panel 服务器上,以 JAR 包形式运行,并使用 MySQL 作为数据库存储邮件相关数据。系统将实现邮件的发送、接收、管理等功能,并提供用户友好的界面。
一、项目初始化与依赖配置
1. 创建Spring Boot项目
使用 Spring Initializr 创建一个新的 Spring Boot 项目,选择以下依赖:
Spring Web
Spring Data JPA
MySQL Driver
Spring Mail
Lombok
2. 配置pom.xml文件
<dependencies>
<!-- Spring Boot Starter Web -->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
<!-- Spring Boot Starter Mail -->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-mail</artifactId>
</dependency>
<!-- Spring Data JPA -->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-data-jpa</artifactId>
</dependency>
<!-- MySQL Connector -->
<dependency>
<groupId>mysql</groupId>
<artifactId>mysql-connector-java</artifactId>
<scope>runtime</scope>
</dependency>
<!-- Lombok -->
<dependency>
<groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId>
<optional>true</optional>
</dependency>
<!-- Thymeleaf for email templates -->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-thymeleaf</artifactId>
</dependency>
</dependencies>
<build>
<plugins>
<plugin>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-maven-plugin</artifactId>
<configuration>
<mainClass>com.example.mailmanager.MailManagerApplication</mainClass>
</configuration>
</plugin>
</plugins>
</build>二、数据库配置
1. 配置MySQL连接
在application.properties或application.yml中配置 MySQL 数据库连接信息:
# MySQL数据库配置
spring.datasource.url=jdbc:mysql://localhost:3306/mail_manager?useUnicode=true&characterEncoding=utf-8&useSSL=false&serverTimezone=GMT%2B8
spring.datasource.username=root
spring.datasource.password=yourpassword
spring.datasource.driver-class-name=com.mysql.cj.jdbc.Driver
# JPA配置
spring.jpa.hibernate.ddl-auto=update
spring.jpa.show-sql=true
spring.jpa.properties.hibernate.dialect=org.hibernate.dialect.MySQL5InnoDBDialect2. 创建邮件相关实体类
@Entity
@Data
@NoArgsConstructor
@AllArgsConstructor
public class EmailAccount {
@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
private Long id;
private String email;
private String password;
private String smtpHost;
private Integer smtpPort;
private String imapHost;
private Integer imapPort;
private Boolean active;
private LocalDateTime createdAt;
}
@Entity
@Data
@NoArgsConstructor
@AllArgsConstructor
public class EmailMessage {
@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
private Long id;
@ManyToOne
private EmailAccount sender;
private String recipients;
private String subject;
private String content;
private LocalDateTime sentAt;
private Boolean hasAttachment;
private String status; // SENT, FAILED, DRAFT
}
@Entity
@Data
@NoArgsConstructor
@AllArgsConstructor
public class EmailTemplate {
@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
private Long id;
private String name;
private String subject;
private String content;
private LocalDateTime createdAt;
private LocalDateTime updatedAt;
}三、邮件服务实现
1. 邮件发送服务
@Service
@RequiredArgsConstructor
public class EmailService {
private final JavaMailSender mailSender;
private final TemplateEngine templateEngine;
private final EmailAccountRepository emailAccountRepository;
// 发送简单邮件
public void sendSimpleEmail(String from, String to, String subject, String text) {
SimpleMailMessage message = new SimpleMailMessage();
message.setFrom(from);
message.setTo(to);
message.setSubject(subject);
message.setText(text);
mailSender.send(message);
}
// 发送HTML邮件
public void sendHtmlEmail(String from, String to, String subject, String templateName,
Context context) throws MessagingException {
MimeMessage message = mailSender.createMimeMessage();
MimeMessageHelper helper = new MimeMessageHelper(message, true);
String htmlContent = templateEngine.process(templateName, context);
helper.setFrom(from);
helper.setTo(to);
helper.setSubject(subject);
helper.setText(htmlContent, true);
mailSender.send(message);
}
// 发送带附件的邮件
public void sendEmailWithAttachment(String from, String to, String subject, String text,
String attachmentPath) throws MessagingException {
MimeMessage message = mailSender.createMimeMessage();
MimeMessageHelper helper = new MimeMessageHelper(message, true);
helper.setFrom(from);
helper.setTo(to);
helper.setSubject(subject);
helper.setText(text);
FileSystemResource file = new FileSystemResource(new File(attachmentPath));
helper.addAttachment(file.getFilename(), file);
mailSender.send(message);
}
// 异步发送邮件
@Async
public void sendAsyncEmail(String from, String to, String subject, String text) {
sendSimpleEmail(from, to, subject, text);
}
}2. 邮件接收服务
@Service
public class EmailReceiverService {
public List<EmailMessage> receiveEmails(String username, String password, String host,
String protocol, int port) {
List<EmailMessage> messages = new ArrayList<>();
Properties props = new Properties();
props.put("mail.store.protocol", protocol);
props.put("mail." + protocol + ".host", host);
props.put("mail." + protocol + ".port", port);
props.put("mail." + protocol + ".ssl.enable", "true");
try {
Session session = Session.getInstance(props, null);
Store store = session.getStore();
store.connect(username, password);
Folder inbox = store.getFolder("INBOX");
inbox.open(Folder.READ_ONLY);
Message[] emailMessages = inbox.getMessages();
for (Message message : emailMessages) {
EmailMessage emailMessage = convertToEmailMessage(message);
messages.add(emailMessage);
}
inbox.close(false);
store.close();
} catch (Exception e) {
e.printStackTrace();
}
return messages;
}
private EmailMessage convertToEmailMessage(Message message) throws MessagingException, IOException {
EmailMessage emailMessage = new EmailMessage();
emailMessage.setSubject(message.getSubject());
emailMessage.setContent(getTextFromMessage(message));
emailMessage.setRecipients(Arrays.toString(message.getAllRecipients()));
emailMessage.setSentAt(message.getSentDate().toInstant().atZone(ZoneId.systemDefault()).toLocalDateTime());
return emailMessage;
}
private String getTextFromMessage(Message message) throws MessagingException, IOException {
if (message.isMimeType("text/plain")) {
return message.getContent().toString();
} else if (message.isMimeType("multipart/*")) {
Multipart multipart = (Multipart) message.getContent();
for (int i = 0; i < multipart.getCount(); i++) {
BodyPart bodyPart = multipart.getBodyPart(i);
if (bodyPart.isMimeType("text/plain")) {
return bodyPart.getContent().toString();
}
}
}
return "";
}
}四、邮件配置管理
1. 邮件服务器配置
在application.properties中添加邮件服务器配置:
# 邮件服务器配置
spring.mail.host=smtp.example.com
spring.mail.port=587
spring.mail.username=your_email@example.com
spring.mail.password=your_password
spring.mail.protocol=smtp
spring.mail.properties.mail.smtp.auth=true
spring.mail.properties.mail.smtp.starttls.enable=true
spring.mail.default-encoding=UTF-82. 多邮件账户管理
@Service
@RequiredArgsConstructor
public class EmailAccountService {
private final EmailAccountRepository emailAccountRepository;
public EmailAccount addEmailAccount(EmailAccount account) {
account.setCreatedAt(LocalDateTime.now());
account.setActive(true);
return emailAccountRepository.save(account);
}
public List<EmailAccount> getAllActiveAccounts() {
return emailAccountRepository.findByActive(true);
}
public void deactivateAccount(Long accountId) {
emailAccountRepository.findById(accountId).ifPresent(account -> {
account.setActive(false);
emailAccountRepository.save(account);
});
}
public JavaMailSender getMailSenderForAccount(Long accountId) {
return emailAccountRepository.findById(accountId)
.map(this::createMailSender)
.orElseThrow(() -> new RuntimeException("Account not found"));
}
private JavaMailSender createMailSender(EmailAccount account) {
JavaMailSenderImpl mailSender = new JavaMailSenderImpl();
mailSender.setHost(account.getSmtpHost());
mailSender.setPort(account.getSmtpPort());
mailSender.setUsername(account.getEmail());
mailSender.setPassword(account.getPassword());
Properties props = mailSender.getJavaMailProperties();
props.put("mail.transport.protocol", "smtp");
props.put("mail.smtp.auth", "true");
props.put("mail.smtp.starttls.enable", "true");
props.put("mail.debug", "true");
return mailSender;
}
}五、REST API设计
1. 邮件发送API
@RestController
@RequestMapping("/api/emails")
@RequiredArgsConstructor
public class EmailController {
private final EmailService emailService;
private final EmailAccountService emailAccountService;
private final EmailMessageRepository emailMessageRepository;
@PostMapping("/send")
public ResponseEntity<String> sendEmail(@RequestBody EmailRequest request) {
try {
emailService.sendSimpleEmail(request.getFrom(), request.getTo(),
request.getSubject(), request.getContent());
// 保存发送记录
EmailMessage message = new EmailMessage();
message.setRecipients(request.getTo());
message.setSubject(request.getSubject());
message.setContent(request.getContent());
message.setSentAt(LocalDateTime.now());
message.setStatus("SENT");
emailMessageRepository.save(message);
return ResponseEntity.ok("Email sent successfully");
} catch (Exception e) {
return ResponseEntity.status(HttpStatus.INTERNAL_SERVER_ERROR)
.body("Failed to send email: " + e.getMessage());
}
}
@PostMapping("/send-template")
public ResponseEntity<String> sendTemplateEmail(@RequestBody TemplateEmailRequest request) {
try {
Context context = new Context();
context.setVariables(request.getVariables());
emailService.sendHtmlEmail(request.getFrom(), request.getTo(),
request.getSubject(), request.getTemplateName(), context);
return ResponseEntity.ok("Template email sent successfully");
} catch (Exception e) {
return ResponseEntity.status(HttpStatus.INTERNAL_SERVER_ERROR)
.body("Failed to send template email: " + e.getMessage());
}
}
@GetMapping("/received")
public ResponseEntity<List<EmailMessage>> getReceivedEmails(
@RequestParam Long accountId,
@RequestParam(defaultValue = "imap") String protocol) {
EmailAccount account = emailAccountService.getAccountById(accountId)
.orElseThrow(() -> new RuntimeException("Account not found"));
List<EmailMessage> messages = emailService.receiveEmails(
account.getEmail(),
account.getPassword(),
account.getImapHost(),
protocol,
account.getImapPort());
return ResponseEntity.ok(messages);
}
}
@Data
class EmailRequest {
private String from;
private String to;
private String subject;
private String content;
}
@Data
class TemplateEmailRequest {
private String from;
private String to;
private String subject;
private String templateName;
private Map<String, Object> variables;
}2. 邮件账户管理API
@RestController
@RequestMapping("/api/accounts")
@RequiredArgsConstructor
public class EmailAccountController {
private final EmailAccountService emailAccountService;
@PostMapping
public ResponseEntity<EmailAccount> addAccount(@RequestBody EmailAccount account) {
return ResponseEntity.ok(emailAccountService.addEmailAccount(account));
}
@GetMapping
public ResponseEntity<List<EmailAccount>> getAllAccounts() {
return ResponseEntity.ok(emailAccountService.getAllActiveAccounts());
}
@DeleteMapping("/{id}")
public ResponseEntity<Void> deactivateAccount(@PathVariable Long id) {
emailAccountService.deactivateAccount(id);
return ResponseEntity.noContent().build();
}
}六、邮件模板管理
1. 邮件模板服务
@Service
@RequiredArgsConstructor
public class EmailTemplateService {
private final EmailTemplateRepository emailTemplateRepository;
public EmailTemplate createTemplate(EmailTemplate template) {
template.setCreatedAt(LocalDateTime.now());
template.setUpdatedAt(LocalDateTime.now());
return emailTemplateRepository.save(template);
}
public EmailTemplate updateTemplate(Long id, EmailTemplate template) {
return emailTemplateRepository.findById(id)
.map(existing -> {
existing.setName(template.getName());
existing.setSubject(template.getSubject());
existing.setContent(template.getContent());
existing.setUpdatedAt(LocalDateTime.now());
return emailTemplateRepository.save(existing);
})
.orElseThrow(() -> new RuntimeException("Template not found"));
}
public List<EmailTemplate> getAllTemplates() {
return emailTemplateRepository.findAll();
}
public Optional<EmailTemplate> getTemplateById(Long id) {
return emailTemplateRepository.findById(id);
}
public void deleteTemplate(Long id) {
emailTemplateRepository.deleteById(id);
}
}2. 邮件模板API
@RestController
@RequestMapping("/api/templates")
@RequiredArgsConstructor
public class EmailTemplateController {
private final EmailTemplateService emailTemplateService;
@PostMapping
public ResponseEntity<EmailTemplate> createTemplate(@RequestBody EmailTemplate template) {
return ResponseEntity.ok(emailTemplateService.createTemplate(template));
}
@PutMapping("/{id}")
public ResponseEntity<EmailTemplate> updateTemplate(
@PathVariable Long id, @RequestBody EmailTemplate template) {
return ResponseEntity.ok(emailTemplateService.updateTemplate(id, template));
}
@GetMapping
public ResponseEntity<List<EmailTemplate>> getAllTemplates() {
return ResponseEntity.ok(emailTemplateService.getAllTemplates());
}
@GetMapping("/{id}")
public ResponseEntity<EmailTemplate> getTemplateById(@PathVariable Long id) {
return emailTemplateService.getTemplateById(id)
.map(ResponseEntity::ok)
.orElse(ResponseEntity.notFound().build());
}
@DeleteMapping("/{id}")
public ResponseEntity<Void> deleteTemplate(@PathVariable Long id) {
emailTemplateService.deleteTemplate(id);
return ResponseEntity.noContent().build();
}
}七、系统部署到1Panel服务器
1. 打包项目为JAR文件
在项目根目录下执行以下 Maven 命令打包项目:
mvn clean package这将生成一个可执行的 JAR 文件,通常位于target目录下,文件名格式为mail-manager-<version>.jar。
2. 部署到1Panel服务器
上传 JAR 文件:
将生成的 JAR 文件上传到 1Panel 服务器的指定目录,例如
/opt/mail-manager/
创建启动脚本: 在 JAR 文件所在目录创建
start.sh脚本:#!/bin/bash nohup java -jar mail-manager-1.0.0.jar --spring.profiles.active=prod > mail-manager.log 2>&1 & echo $! > mail-manager.pid创建停止脚本: 创建
stop.sh脚本:#!/bin/bash PID=$(cat mail-manager.pid) kill $PID设置文件权限:
chmod +x start.sh stop.sh配置 1Panel 应用:
登录 1Panel 管理界面
导航到 "应用管理"
创建新的应用,选择 "自定义应用"
配置应用名称、启动命令等:
启动命令:
/opt/mail-manager/start.sh工作目录:
/opt/mail-manager/
保存配置
启动应用:
在 1Panel 的应用管理界面找到刚创建的应用
点击 "启动" 按钮
3. 数据库配置
确保 MySQL 服务已在 1Panel 服务器上运行,并创建了mail_manager数据库。可以使用 1Panel 的数据库管理工具创建数据库和用户。
八、系统安全与优化
1. 安全配置
@Configuration
@EnableWebSecurity
public class SecurityConfig extends WebSecurityConfigurerAdapter {
@Override
protected void configure(HttpSecurity http) throws Exception {
http
.csrf().disable()
.authorizeRequests()
.antMatchers("/api/**").authenticated()
.anyRequest().permitAll()
.and()
.httpBasic();
}
@Bean
public PasswordEncoder passwordEncoder() {
return new BCryptPasswordEncoder();
}
}2. 性能优化
@Configuration
@EnableAsync
public class AsyncConfig implements AsyncConfigurer {
@Override
public Executor getAsyncExecutor() {
ThreadPoolTaskExecutor executor = new ThreadPoolTaskExecutor();
executor.setCorePoolSize(5);
executor.setMaxPoolSize(10);
executor.setQueueCapacity(25);
executor.setThreadNamePrefix("MailExecutor-");
executor.initialize();
return executor;
}
}3. 邮件发送重试机制
@Service
public class EmailSenderWithRetry {
private static final int MAX_RETRIES = 3;
private static final long INITIAL_BACKOFF = 1000; // 1 second
private final JavaMailSender mailSender;
public EmailSenderWithRetry(JavaMailSender mailSender) {
this.mailSender = mailSender;
}
public void sendWithRetry(SimpleMailMessage message) throws MailException {
int attempt = 0;
while (attempt < MAX_RETRIES) {
try {
mailSender.send(message);
return;
} catch (MailException e) {
attempt++;
if (attempt == MAX_RETRIES) {
throw e;
}
try {
long backoff = INITIAL_BACKOFF * (1 << (attempt - 1));
Thread.sleep(backoff);
} catch (InterruptedException ie) {
Thread.currentThread().interrupt();
throw new MailSendException("Interrupted during retry", ie);
}
}
}
}
}九、系统测试
1. 单元测试
@SpringBootTest
public class EmailServiceTest {
@Autowired
private EmailService emailService;
@Test
public void testSendSimpleEmail() {
assertDoesNotThrow(() -> {
emailService.sendSimpleEmail(
"test@example.com",
"recipient@example.com",
"Test Subject",
"Test Content"
);
});
}
@Test
public void testSendHtmlEmail() {
Context context = new Context();
context.setVariable("name", "John Doe");
assertDoesNotThrow(() -> {
emailService.sendHtmlEmail(
"test@example.com",
"recipient@example.com",
"Test HTML Subject",
"email-template",
context
);
});
}
}2. 集成测试
@SpringBootTest
@AutoConfigureMockMvc
public class EmailControllerTest {
@Autowired
private MockMvc mockMvc;
@Test
public void testSendEmailEndpoint() throws Exception {
EmailRequest request = new EmailRequest();
request.setFrom("test@example.com");
request.setTo("recipient@example.com");
request.setSubject("Test Subject");
request.setContent("Test Content");
mockMvc.perform(post("/api/emails/send")
.contentType(MediaType.APPLICATION_JSON)
.content(new ObjectMapper().writeValueAsString(request)))
.andExpect(status().isOk())
.andExpect(content().string("Email sent successfully"));
}
}十、系统监控与管理
1. Spring Boot Actuator配置
在application.properties中添加:
# Actuator配置
management.endpoints.web.exposure.include=health,info,metrics
management.endpoint.health.show-details=always
management.metrics.tags.application=mail-manager2. 自定义健康检查
@Component
public class EmailServiceHealthIndicator implements HealthIndicator {
private final EmailService emailService;
public EmailServiceHealthIndicator(EmailService emailService) {
this.emailService = emailService;
}
@Override
public Health health() {
try {
emailService.sendSimpleEmail(
"healthcheck@example.com",
"healthcheck@example.com",
"Health Check",
"This is a health check email"
);
return Health.up().build();
} catch (Exception e) {
return Health.down()
.withDetail("error", e.getMessage())
.build();
}
}
}总结
本文详细介绍了如何开发一个基于 Spring Boot 的邮件管理器系统,包括系统设计、数据库配置、邮件服务实现、REST API 设计、模板管理、系统部署到 1Panel 服务器等内容。该系统具有以下特点:
模块化设计:系统分为邮件发送、接收、账户管理、模板管理等模块,结构清晰
多账户支持:可以管理多个邮件账户,灵活切换发送账户
模板支持:支持使用 Thymeleaf 模板引擎发送 HTML 格式邮件
异步处理:邮件发送采用异步方式,提高系统响应速度
安全性:集成 Spring Security,提供基本的 API 保护
易于部署:支持以 JAR 包形式部署到 1Panel 服务器
数据库支持:使用 MySQL 存储邮件账户、模板和发送记录