基于 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.propertiesapplication.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.MySQL5InnoDBDialect

2. 创建邮件相关实体类

@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-8

2. 多邮件账户管理

@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服务器

  1. 上传 JAR 文件

    • 将生成的 JAR 文件上传到 1Panel 服务器的指定目录,例如/opt/mail-manager/

  2. 创建启动脚本: 在 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
  3. 创建停止脚本: 创建stop.sh脚本:

    #!/bin/bash
    PID=$(cat mail-manager.pid)
    kill $PID
  4. 设置文件权限

    chmod +x start.sh stop.sh
  5. 配置 1Panel 应用

    • 登录 1Panel 管理界面

    • 导航到 "应用管理"

    • 创建新的应用,选择 "自定义应用"

    • 配置应用名称、启动命令等:

      • 启动命令:/opt/mail-manager/start.sh

      • 工作目录:/opt/mail-manager/

    • 保存配置

  6. 启动应用

    • 在 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-manager

2. 自定义健康检查

@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 服务器等内容。该系统具有以下特点:

  1. 模块化设计:系统分为邮件发送、接收、账户管理、模板管理等模块,结构清晰

  2. 多账户支持:可以管理多个邮件账户,灵活切换发送账户

  3. 模板支持:支持使用 Thymeleaf 模板引擎发送 HTML 格式邮件

  4. 异步处理:邮件发送采用异步方式,提高系统响应速度

  5. 安全性:集成 Spring Security,提供基本的 API 保护

  6. 易于部署:支持以 JAR 包形式部署到 1Panel 服务器

  7. 数据库支持:使用 MySQL 存储邮件账户、模板和发送记录


基于 Spring Boot 的邮件管理器系统代码
https://uniomo.com/archives/ji-yu-spring-boot-de-you-jian-guan-li-qi-xi-tong-dai-ma
作者
雨落秋垣
发布于
2025年10月24日
许可协议