迁移至JakartaMail后,字节数组生成邮件附件报错求解决方案
解决JavaMail发送字节数组附件时的"Passed-in Resource contains an open stream"错误
直接用ByteArrayResource替代InputStreamResource就能解决问题,这是最优雅的方案,不需要临时文件中转。
原因分析
报错的核心问题是:InputStreamResource包装的是一个已打开的输入流,它的getInputStream()方法只会返回同一个流实例。而JavaMail在处理附件过程中,可能会多次尝试获取输入流(比如校验、读取内容),一旦流被读取过就无法再次使用,因此触发了这个错误。
而ByteArrayResource内部持有完整的字节数组,每次调用getInputStream()时都会基于该数组新建一个ByteArrayInputStream,完全满足JavaMail对“每次调用都生成新流”的要求。
修改后的代码
把你原来的附件处理代码替换成下面这段:
// 附件 byte[] data; if (emailDTO.getIsForCheckIn()) { data = pdfService.generatePDFForCheckIn(emailDTO); } else if (emailDTO.getIsForPaymentRefund()) { data = pdfService.generatePDFForRefund(emailDTO); } else { data = pdfService.generatePDFForOnlineBooking(emailDTO); } String fileName = String.format("Booking-%s.pdf", emailDTO.getOnlineRentSell().get_id()).replace(":", ""); // 直接使用ByteArrayResource包装字节数组 messageHelper.addAttachment(fileName, new ByteArrayResource(data));
为什么这个方案更好
- 不需要创建临时文件,避免了磁盘IO操作,性能更优
- 代码更简洁,不需要手动处理输入流的创建和关闭
- 完全符合Spring Mail和JavaMail的规范,不会出现流重复读取的问题
内容的提问来源于stack exchange,提问作者Hansjörg Hofer
相关产品推荐
相关产品推荐

