微软 EWS 在 Spring 生态中的应用:Java 邮件发送的场景化实现

1. 核心概念
  • EWS (Exchange Web Services):微软 Exchange 提供的 Web 服务 API,支持邮件、日历、联系人等操作。
  • Spring 集成优势:利用 Spring 的依赖注入、事务管理和模块化特性,简化 EWS 的复杂配置。
2. 场景化实现步骤
2.1 添加依赖
<dependency>
    <groupId>com.microsoft.ews-java-api</groupId>
    <artifactId>ews-java-api</artifactId>
    <version>2.0</version>
</dependency>
<dependency>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-web</artifactId>
</dependency>

2.2 配置 EWS 连接
@Configuration
public class EwsConfig {
    
    @Value("${ews.username}")
    private String username;
    
    @Value("${ews.password}")
    private String password;
    
    @Value("${ews.endpoint}")
    private String endpoint;
    
    @Bean
    public ExchangeService exchangeService() throws Exception {
        ExchangeService service = new ExchangeService(ExchangeVersion.Exchange2010_SP2);
        service.setCredentials(new WebCredentials(username, password));
        service.setUrl(new URI(endpoint));
        return service;
    }
}

配置文件 (application.properties):

ews.username=your-email@domain.com
ews.password=your-password
ews.endpoint=https://outlook.office365.com/EWS/Exchange.asmx

2.3 邮件发送服务实现
@Service
public class EwsEmailService {
    
    @Autowired
    private ExchangeService exchangeService;
    
    public void sendEmail(String recipient, String subject, String body) throws Exception {
        EmailMessage msg = new EmailMessage(exchangeService);
        msg.setSubject(subject);
        msg.setBody(MessageBody.getMessageBodyFromText(body));
        msg.getToRecipients().add(recipient);
        msg.send();  // 同步发送
    }
    
    // 异步发送(适用于高并发)
    public CompletableFuture<Void> sendAsync(String recipient, String subject, String body) {
        return CompletableFuture.runAsync(() -> {
            try {
                sendEmail(recipient, subject, body);
            } catch (Exception e) {
                throw new RuntimeException("邮件发送失败", e);
            }
        });
    }
}

2.4 控制器层调用
@RestController
@RequestMapping("/email")
public class EmailController {
    
    @Autowired
    private EwsEmailService emailService;
    
    @PostMapping("/send")
    public ResponseEntity<String> send(@RequestParam String to, 
                                      @RequestParam String subject, 
                                      @RequestParam String content) {
        try {
            emailService.sendEmail(to, subject, content);
            return ResponseEntity.ok("邮件发送成功");
        } catch (Exception e) {
            return ResponseEntity.status(500).body("发送失败: " + e.getMessage());
        }
    }
}

3. 关键场景实现
场景 1:带附件的邮件
public void sendWithAttachment(String recipient, String subject, String body, File file) throws Exception {
    EmailMessage msg = new EmailMessage(exchangeService);
    msg.setSubject(subject);
    msg.setBody(MessageBody.getMessageBodyFromText(body));
    msg.getToRecipients().add(recipient);
    msg.getAttachments().addFileAttachment(file.getName(), file);
    msg.send();
}

场景 2:HTML 格式邮件
public void sendHtmlEmail(String recipient, String subject, String htmlContent) throws Exception {
    EmailMessage msg = new EmailMessage(exchangeService);
    msg.setSubject(subject);
    msg.setBody(MessageBody.getMessageBodyFromText(htmlContent));
    msg.getBody().setBodyType(BodyType.HTML);  // 关键设置
    msg.getToRecipients().add(recipient);
    msg.send();
}

场景 3:批量发送(事务性)
@Transactional
public void sendBulk(List<String> recipients, String subject, String body) {
    recipients.forEach(recipient -> {
        try {
            emailService.sendEmail(recipient, subject, body);
        } catch (Exception e) {
            throw new RuntimeException("批量发送中断", e);
        }
    });
}

4. 优化策略
  1. 连接池管理
    @Bean(destroyMethod = "close")
    public ExchangeServicePool servicePool() {
        return new ExchangeServicePool(10, () -> exchangeService());
    }
    

  2. 异常处理:捕获 ServiceRequestException 并实现重试机制:
    @Retryable(maxAttempts = 3, backoff = @Backoff(delay = 1000))
    public void sendWithRetry(String recipient, String subject, String body) throws Exception {
        sendEmail(recipient, subject, body);
    }
    

  3. 性能监控:通过 Spring AOP 记录发送耗时:
    @Around("execution(* com.example.service.EwsEmailService.send*(..))")
    public Object monitor(ProceedingJoinPoint pjp) throws Throwable {
        long start = System.currentTimeMillis();
        Object result = pjp.proceed();
        log.info("邮件发送耗时: {}ms", System.currentTimeMillis() - start);
        return result;
    }
    

5. 注意事项
  • 权限控制:确保服务账户有 SendAs 权限。
  • 安全协议:强制使用 TLS 1.2+:
    System.setProperty("https.protocols", "TLSv1.2");
    

  • 邮件限制:Exchange Online 单次发送最多 500 收件人。

实现效果:通过 Spring 的模块化设计,将 EWS 的复杂操作封装为可复用的服务组件,支持同步/异步发送、附件处理、HTML 渲染等场景,同时通过连接池和重试机制保障高可用性。

Logo

Agent 垂直技术社区,欢迎活跃、内容共建。

更多推荐