如何在Spring Boot应用中实现Outlook新邮件持续监听与附件下载?
实现方案总览
可选实现库
- Jakarta Mail(原JavaMail):通用邮件协议实现,支持IMAP/SMTP等标准协议,适配绝大多数支持IMAP的邮件服务包括Outlook,无需额外对接第三方API
- Spring Integration Mail:Spring生态封装的邮件处理模块,可实现邮件通道监听、自动消费,适合集成到Spring Boot项目
- Microsoft Graph Java SDK:微软官方提供的Outlook/Exchange服务API,支持现代身份认证,适合企业级Outlook 365场景的深度集成
基于Jakarta Mail + Spring Boot 示例实现
前置要求
Outlook账号开启IMAP协议,个人账号需在安全设置中开启应用密码(替代普通登录密码),企业账号需确认管理员开放IMAP访问权限
第一步:引入依赖
<dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-mail</artifactId> </dependency> <dependency> <groupId>com.sun.mail</groupId> <artifactId>jakarta.mail</artifactId> <version>2.0.1</version> </dependency>
第二步:配置application.yml
mail: outlook: host: imap.outlook.com port: 993 username: 你的Outlook邮箱地址 password: 你的应用密码/邮箱密码 ssl-enable: true # 音频附件存储路径 audio-save-path: /data/email-audio/ # 定时任务间隔 单位毫秒 fetch-interval: 30000
第三步:核心处理代码
import jakarta.mail.*; import jakarta.mail.internet.MimeBodyPart; import jakarta.mail.search.FlagTerm; import org.springframework.beans.factory.annotation.Value; import org.springframework.scheduling.annotation.EnableScheduling; import org.springframework.scheduling.annotation.Scheduled; import org.springframework.stereotype.Component; import java.io.File; import java.util.Properties; @Component @EnableScheduling public class OutlookMailListener { @Value("${mail.outlook.host}") private String imapHost; @Value("${mail.outlook.port}") private Integer imapPort; @Value("${mail.outlook.username}") private String username; @Value("${mail.outlook.password}") private String password; @Value("${mail.outlook.ssl-enable}") private Boolean sslEnable; @Value("${mail.outlook.audio-save-path}") private String audioSavePath; // 支持的音频格式后缀,可自行扩展 private static final String[] AUDIO_SUFFIX = {"mp3", "wav", "flac", "aac", "ogg"}; @Scheduled(fixedRateString = "${mail.outlook.fetch-interval}") public void fetchUnreadMail() { Store store = null; Folder inbox = null; try { // 1. 配置IMAP连接参数 Properties props = new Properties(); props.put("mail.store.protocol", "imaps"); props.put("mail.imaps.host", imapHost); props.put("mail.imaps.port", imapPort); props.put("mail.imaps.ssl.enable", sslEnable); props.put("mail.imaps.auth", "true"); // 2. 连接邮箱服务器 Session session = Session.getInstance(props); store = session.getStore("imaps"); store.connect(username, password); // 3. 打开收件箱,读写模式 inbox = store.getFolder("INBOX"); inbox.open(Folder.READ_WRITE); // 4. 搜索所有未读邮件 Message[] unreadMessages = inbox.search(new FlagTerm(new Flags(Flags.Flag.SEEN), false)); for (Message message : unreadMessages) { // 5. 处理邮件附件 Object content = message.getContent(); if (content instanceof Multipart multipart) { for (int i = 0; i < multipart.getCount(); i++) { BodyPart bodyPart = multipart.getBodyPart(i); if (Part.ATTACHMENT.equalsIgnoreCase(bodyPart.getDisposition())) { String fileName = bodyPart.getFileName(); // 校验是否为音频文件 if (isAudioFile(fileName)) { // 下载到本地路径 File saveDir = new File(audioSavePath); if (!saveDir.exists()) saveDir.mkdirs(); File saveFile = new File(saveDir, System.currentTimeMillis() + "_" + fileName); ((MimeBodyPart) bodyPart).saveFile(saveFile); } } } } // 6. 标记邮件为已读 message.setFlag(Flags.Flag.SEEN, true); } } catch (Exception e) { e.printStackTrace(); } finally { // 7. 关闭资源 try { if (inbox != null) inbox.close(false); if (store != null) store.close(); } catch (MessagingException e) { e.printStackTrace(); } } } /** * 校验是否为音频文件 */ private boolean isAudioFile(String fileName) { if (fileName == null || fileName.isEmpty()) return false; String lowerFileName = fileName.toLowerCase(); for (String suffix : AUDIO_SUFFIX) { if (lowerFileName.endsWith("." + suffix)) { return true; } } return false; } }
注意事项
- 若使用企业版Outlook 365且开启了多因素认证,建议切换为Microsoft Graph SDK实现,避免IMAP协议认证失败
- 生产环境建议增加邮件Message-ID持久化逻辑,避免因标记已读失败导致的附件重复下载
- 可根据实际需求调整定时任务执行间隔,避免频繁请求邮件服务器被限制访问
- 附件下载逻辑可增加大小校验、MIME类型二次校验提升安全性
内容的提问来源于stack exchange,提问作者YoBuss
相关产品推荐
相关产品推荐

