You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Spring Integration 5.x实现Gmail带附件邮件消费的IntegrationFlow求助

Spring Integration 5.x Gmail 邮件附件处理完整示例

针对你遇到的Mail.imapInboundAdapter无port/user/password构建方法、附件过滤逻辑错误的问题,以下是符合需求的完整可运行示例,包含Gmail邮件读取、无附件邮件标记已读、附件拆分转发的完整流程。

一、核心配置类

import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.integration.dsl.IntegrationFlow;
import org.springframework.integration.dsl.IntegrationFlows;
import org.springframework.integration.mail.ImapMailReceiver;
import org.springframework.integration.mail.dsl.Mail;
import org.springframework.integration.mail.support.DefaultMailHeaderMapper;
import org.springframework.integration.mail.support.MailHeaderMapper;
import org.springframework.mail.javamail.JavaMailSender;
import org.springframework.mail.javamail.JavaMailSenderImpl;

import javax.mail.Flags;
import javax.mail.Message;
import javax.mail.MessagingException;
import javax.mail.Part;
import java.util.Properties;

@Configuration
public class GmailIntegrationConfig {

    // 配置JavaMailSender,用于邮件连接与操作
    @Bean
    public JavaMailSender javaMailSender() {
        JavaMailSenderImpl mailSender = new JavaMailSenderImpl();
        mailSender.setHost("imap.gmail.com");
        mailSender.setPort(993);
        mailSender.setUsername("your-gmail-account@gmail.com");
        // 注意:Gmail开启两步验证需使用应用专用密码,而非原账户密码
        mailSender.setPassword("your-gmail-password-or-app-password");

        Properties props = mailSender.getJavaMailProperties();
        props.put("mail.imap.ssl.enable", "true");
        props.put("mail.imap.auth", "true");
        props.put("mail.imap.fetchsize", "10485760"); // 设置单次邮件读取大小上限(10MB)

        return mailSender;
    }

    // 配置IMAP邮件接收者,封装邮件服务器连接规则
    @Bean
    public ImapMailReceiver imapMailReceiver(JavaMailSender javaMailSender) {
        ImapMailReceiver receiver = new ImapMailReceiver("imap://imap.gmail.com/INBOX");
        receiver.setJavaMailSender(javaMailSender);
        receiver.setShouldMarkMessagesAsRead(true); // 处理后自动标记邮件为已读
        receiver.setShouldDeleteMessages(false); // 仅标记已读,不删除邮件
        receiver.setHeaderMapper(mailHeaderMapper()); // 配置邮件头信息映射
        return receiver;
    }

    // 自定义邮件头映射规则,可按需添加需要传递的头信息
    @Bean
    public MailHeaderMapper mailHeaderMapper() {
        DefaultMailHeaderMapper mapper = new DefaultMailHeaderMapper();
        mapper.setUserDefinedHeaderPrefix("mail_");
        return mapper;
    }

    // 定义完整的IntegrationFlow处理流程
    @Bean
    public IntegrationFlow gmailAttachmentProcessingFlow(ImapMailReceiver imapMailReceiver,
                                                        DocumentRegistrar documentRegistrar) {
        return IntegrationFlows.from(Mail.imapInboundAdapter(imapMailReceiver)
                        .poller(p -> p.fixedDelay(30000))) // 30秒轮询一次收件箱
                // 过滤出带附件的邮件,无附件邮件自动标记已读并跳过
                .filter(message -> {
                    Message mailMessage = (Message) message.getPayload();
                    try {
                        return mailMessage.getContentType().contains("multipart") &&
                                mailMessage.getContent() instanceof javax.mail.Multipart;
                    } catch (Exception e) {
                        // 解析异常的邮件强制标记已读
                        try {
                            mailMessage.setFlag(Flags.Flag.SEEN, true);
                        } catch (MessagingException ex) {
                            ex.printStackTrace();
                        }
                        return false;
                    }
                })
                // 拆分邮件中的附件,每个附件转为独立Message
                .split(message -> {
                    Message mailMessage = (Message) message.getPayload();
                    try {
                        javax.mail.Multipart multipart = (javax.mail.Multipart) mailMessage.getContent();
                        int partCount = multipart.getCount();
                        return java.util.stream.IntStream.range(0, partCount)
                                .mapToObj(i -> {
                                    try {
                                        javax.mail.BodyPart part = multipart.getBodyPart(i);
                                        // 判断是否为附件(排除邮件正文部分)
                                        if (Part.ATTACHMENT.equalsIgnoreCase(part.getDisposition()) ||
                                                (part.getFileName() != null && !part.getFileName().isEmpty())) {
                                            byte[] content = part.getInputStream().readAllBytes();
                                            // 构建包含附件内容和元信息的Message
                                            return org.springframework.messaging.support.MessageBuilder.withPayload(content)
                                                    .setHeader("mail_subject", mailMessage.getSubject())
                                                    .setHeader("attachment_filename", part.getFileName())
                                                    .build();
                                        }
                                        return null;
                                    } catch (Exception e) {
                                        e.printStackTrace();
                                        return null;
                                    }
                                })
                                .filter(java.util.Objects::nonNull)
                                .collect(java.util.stream.Collectors.toList());
                    } catch (Exception e) {
                        e.printStackTrace();
                        return java.util.Collections.emptyList();
                    }
                })
                // 将每个附件Message发送给documentRegistrar处理器
                .handle(documentRegistrar)
                .get();
    }
}

二、DocumentRegistrar处理器示例

import org.springframework.stereotype.Component;
import org.springframework.messaging.Message;

@Component("documentRegistrar")
public class DocumentRegistrar {

    public void processAttachment(Message<byte[]> message) {
        byte[] attachmentContent = message.getPayload();
        String filename = (String) message.getHeaders().get("attachment_filename");
        String mailSubject = (String) message.getHeaders().get("mail_subject");

        // 此处替换为你的业务逻辑:如存储附件到文件系统、写入数据库等
        System.out.println("处理附件:" + filename + ",来源邮件主题:" + mailSubject);
        System.out.println("附件大小:" + attachmentContent.length + " bytes");
    }
}

三、关键问题说明

  1. 解决Mail.imapInboundAdapter编译错误:
    Spring Integration 5.x中,Mail.imapInboundAdapter需传入ImapMailReceiver实例,邮件服务器的连接信息(地址、端口、账号密码)统一配置在JavaMailSender和ImapMailReceiver中,而非通过链式方法直接设置。

  2. 无附件邮件处理逻辑:
    被filter组件过滤的无附件邮件,会被ImapMailReceiver自动标记为已读(因配置了setShouldMarkMessagesAsRead(true)),无需额外编写标记逻辑。

  3. Gmail配置注意事项:

    • 需在Gmail账户设置中开启IMAP访问(设置→转发和POP/IMAP→IMAP访问);
    • 开启两步验证的账户,必须使用应用专用密码替代原密码;
    • 未开启两步验证的账户,需开启“不太安全的应用访问”(或使用应用密码)。

内容的提问来源于stack exchange,提问作者hotmeatballsoup

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.21 21:32:52