【Java mail】解析邮件的时候死循环

记一下遇到的一个bug

问题产生

有个读取邮件的定时任务,通过rabbitMQ异步操作的,今天突然卡住了,排查发现mq阻塞了,进一步排查发现有一封邮件解析的时候死循环了

最开始是解析邮件的时候org.apache.commons.mail.util.MimeMessageParser#getContent方法流处理死循环了,他的这个inputStream对象一直在刷新,无限长;

/**
     * Read the content of the input stream.
     *
     * @param is the input stream to process
     * @return the content of the input stream
     * @throws IOException reading the input stream failed
     */
    private byte[] getContent(final InputStream is)
        throws IOException
    {
        int ch;
        byte[] result;

        final ByteArrayOutputStream os = new ByteArrayOutputStream();
        final BufferedInputStream isReader = new BufferedInputStream(is);
        final BufferedOutputStream osWriter = new BufferedOutputStream(os);

        while ((ch = isReader.read()) != -1)
        {
            osWriter.write(ch);
        }

        osWriter.flush();
        result = os.toByteArray();
        osWriter.close();

        return result;
    }

之后我以为是解析包的问题 自己写了一套

List<DataSource> getAttachments(Message message) throws MessagingException, IOException {
        List<DataSource> result = new ArrayList<>();
        Part part = message;
        if (part.isMimeType("multipart/*")){
            Multipart multipart = (Multipart) part.getContent();
            for (int i = 0; i < multipart.getCount(); i++) {
                BodyPart bodyPart = multipart.getBodyPart(i);
                String name = bodyPart.getDataHandler().getDataSource().getName();
                if (name != null){
                    result.add(bodyPart.getDataHandler().getDataSource());
                }
            }
        }
        return result;
    }

勉强通过这一步了
但是后面解析eml文件的时候又死循环了,一时间有点不知道怎么搞了,然后自己写了个读取流,芜湖~直接打到12w多

ByteArrayOutputStream out = new ByteArrayOutputStream();
        Map<String, String> map = new HashMap<>();
        try{
            InputStream inputStream = message.getInputStream();
            System.out.println("inputstream->available--->"+inputStream.available());
            byte[] buffer = new byte[1024];
            int read ;
            int i = 0;
            while ((read = inputStream.read(buffer)) != -1){
                out.write(buffer, 0, read);
                System.out.println(i++);
            }
//            message.writeTo(out);
            byte[] bytes = out.toByteArray();
            MD5 md5 = MD5.create();
            String md5Code = md5.digestHex16(bytes);
            RequestMultipartFile multipartFile = new RequestMultipartFile(message.getSubject()+".eml", bytes);
            String attachmentUrl = fileFeign.uploadFile(companyId, userId, "email", multipartFile);
            map.put("md5Code", md5Code);
            map.put("attachmentUrl", attachmentUrl);
        }finally {
            out.close();
        }

这个时候怀疑是邮件有问题,但是邮件有问题不知道有什么问题,也不好对邮件进行过滤,之后就去查Java mail的文档
结果真有发现
文档地址

Q: Does the IMAP provider cache the retrieved data?
A: The IMAP provider fetches the data for a message from the server only when necessary. (The javax.mail.FetchProfile can be used to optimize this). The header and bodystructure information, once fetched, is always cached within the Message object. However, the content of a bodypart is not cached. So each time the content is requested by the client (either using getContent() or using getInputStream()), a new FETCH request is issued to the server. The reason for this is that the content of a message could be potentially large, and if we cache this content for a large number of messages, there is the possibility that the system may run out of memory soon since the garbage collector cannot free the referenced objects. Clients should be aware of this and must hold on to the retrieved content themselves if needed.

果然 他在我们读的时候对流进行了处理,要自己处理好流的内容,但是也可以添加链接配置来解决这个问题
最后在链接配置中添加了javax.mail.FetchProfile为FALSE以后正常了

    /**
     * 生成邮箱连接
     */
    public static Store connectEmailServer(EmailConfigVo config) throws Exception {
        Properties props = new Properties();
        props.setProperty(StoreProtocolKey, config.getStoreProtocol());
        props.setProperty("mail.imap.host", config.getReceiveServerHost());
        props.setProperty("mail.properties.mail.smtp.port", config.getSmtpPort());
        props.setProperty("mail.imap.partialfetch","false");
        Session session = Session.getInstance(props);
        Store store = session.getStore();
        //连接服务器
        store.connect(config.getReceiveServerHost(), config.getUsername(), config.getPassword());
        return store;
    }
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
要使用Java Mail 解析邮件并获取最近时间的指定邮件,可以按照以下步骤进行操作: 1. 建立与邮件服务器的连接 使用Java Mail API中的Session类,建立与邮件服务器的连接。例如: ``` Properties props = new Properties(); props.setProperty("mail.store.protocol", "imap"); props.setProperty("mail.imap.host", "imap.example.com"); props.setProperty("mail.imap.port", "993"); props.setProperty("mail.imap.ssl.enable", "true"); Session session = Session.getDefaultInstance(props, null); Store store = session.getStore("imap"); store.connect(username, password); ``` 2. 获取收件箱的Folder对象 使用Store对象获取收件箱的Folder对象。例如: ``` Folder inbox = store.getFolder("INBOX"); inbox.open(Folder.READ_ONLY); ``` 3. 获取指定日期之后的邮件 使用Folder对象的search方法和SearchTerm类,获取指定日期之后的邮件。例如: ``` Calendar cal = Calendar.getInstance(); cal.setTime(new Date()); cal.add(Calendar.DAY_OF_MONTH, -7); // 获取7天之内的邮件 SearchTerm newerThan = new ReceivedDateTerm(ComparisonTerm.GT, cal.getTime()); // 以接收时间为条件搜索邮件 Message[] messages = inbox.search(newerThan); ``` 4. 获取最近时间的邮件 使用Message数组中的最后一封邮件即为最近时间的邮件。例如: ``` Message latestMessage = messages[messages.length - 1]; ``` 5. 解析邮件内容 使用Message对象的getContent方法,获取邮件内容。例如: ``` Object content = latestMessage.getContent(); ``` 以上就是使用Java Mail解析邮件并获取最近时间的指定邮件的步骤。需要注意的是,具体实现还需要根据具体情况进行调整。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值