S3对象作为邮件附件发送时文档类文件丢失扩展名无法访问
故障根因
- 扩展名提取逻辑容错不足:当S3对象的key不带
.时,你代码里的extension变量不会被截断,会保留完整key值,最终生成的临时文件后缀异常;如果key带路径前缀(如data/report.csv),虽然扩展名提取不受影响,但作为临时文件前缀会引入非法字符。 File.createTempFile原生机制问题:该方法会自动在你传入的前缀、后缀之间插入随机字符串,生成的临时文件名本身就不是你期望的原始文件名,如果你后续构造邮件附件时直接复用临时文件的文件名,必然会丢失正确的文件名和扩展名。- 邮件附件未显式指定文件名:多数邮件发送框架不会主动读取文件的真实扩展名,需要你在构造附件节点时主动设置带完整扩展名的文件名,仅依赖
FileDataSource的默认属性无法保证邮件客户端能识别正确扩展名。
修复代码
try { fullObject = s3Client.getObject(new GetObjectRequest(bucketName, key)); ObjectMetadata metadata = fullObject.getObjectMetadata(); InputStream inputStream = fullObject.getObjectContent(); // 第一步:先提取纯文件名(去掉S3 key的路径前缀) String fileName = key; int lastSepIndex = fileName.lastIndexOf('/'); if (lastSepIndex >= 0) { fileName = fileName.substring(lastSepIndex + 1); } // 第二步:安全提取扩展名,无扩展名时默认用tmp,也可以根据ContentType做映射 String extension = "tmp"; int dotIndex = fileName.lastIndexOf('.'); if (dotIndex > 0) { extension = fileName.substring(dotIndex + 1); } // 第三步:创建临时文件,前缀用无路径的文件名截取前3位以上即可,避免非法字符 File file = File.createTempFile(fileName.length() >=3 ? fileName.substring(0,3) : "att", "." + extension ); try (OutputStream outputStream = new FileOutputStream(file)) { IOUtils.copy(inputStream, outputStream); } catch (Exception e) { e.printStackTrace(); } // 第四步:构造DataSource后,后续构造MimeBodyPart时必须显式设置文件名 dataSource = new FileDataSource(file); MimeBodyPart attachmentPart = new MimeBodyPart(); attachmentPart.setDataHandler(new DataHandler(dataSource)); // 重点:设置原始文件名,带完整扩展名,同时处理中文乱码问题 attachmentPart.setFileName(MimeUtility.encodeText(fileName)); attachmentsList.add(attachmentPart); } catch (Exception e) { e.printStackTrace(); }
额外注意事项
- 如果S3的key本身没有扩展名,你可以通过
metadata.getContentType()拿到的MIME类型反向映射扩展名,比如application/pdf对应pdf,application/vnd.openxmlformats-officedocument.wordprocessingml.document对应docx,进一步提升兼容性。 - 临时文件使用完后建议主动删除,避免服务器磁盘占用过多。
内容的提问来源于stack exchange,提问作者EmanAKhan
相关产品推荐
相关产品推荐

