TFdream / blog

个人技术博客,博文写在 Issues 里。
Apache License 2.0
129 stars 18 forks source link

JavaMail 发邮件 附件中文名乱码 #339

Open TFdream opened 3 years ago

TFdream commented 3 years ago

最近项目中使用Spring boot Mail 发邮件(包含附件),在这里记录一下。

pom.xml增加依赖:

        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-mail</artifactId>
        </dependency>

发邮件代码如下:


    @Resource
    private JavaMailSenderImpl mailSender;

    public ResponseDTO send(CustomerBillSendParam param) {
        Date now = new Date();
        Long loginUserId = param.getUserId();
        Long billId = param.getBillId();
        LOG.info("甲方账单-发送确认邮件开始, loginUserId:{}, billId:{}, 参数:{}", loginUserId, billId, JsonUtils.toJson(param));

        if (StringUtils.isEmpty(param.getEmails())) {
            return ResponseDTO.invalidParam("收件人不能为空");
        }

        CustomerOrderBill billDO = customerAggBillManager.getBillById(billId);
        if (billDO == null || billDO.getIsDeleted() == DeletedEnum.DELETED.getValue()) {
            LOG.warn("甲方账单-发送确认邮件, loginUserId:{}, billId:{}, 账单不存在", loginUserId, billId);
            return ResponseDTO.failure(BIZ_CODE, "账单不存在");
        }
        if (billDO.getSendState() != ConsumerSendStateEnum.NOT_SEND.getValue()) {
            LOG.warn("甲方账单-发送确认邮件, loginUserId:{}, billId:{} 账单状态不是待发送", loginUserId, billId);
            return ResponseDTO.failure(BIZ_CODE, "账单状态不是待发送");
        }

        try {
            String[] emails = EmailUtis.parseEmails(param.getEmails());
            String[] cc = null;
            if (StringUtils.isNotEmpty(param.getCcEmails())) {
                cc = EmailUtis.parseEmails(param.getCcEmails());
            }
            //账单名称
            String billName = billDO.getName();
            String formatName = String.format("%s_%s",  billName, DateUtils.format(new Date(), DateUtils.DATE_COMPACT_FORMAT));

            //Excel文件名
            String excelFileName = String.format("%s.xlsx", formatName);
            File file = genExcelFile(param.getBillId(), excelFileName);

            MimeMessage mime = mailSender.createMimeMessage();
            MimeMessageHelper helper = new MimeMessageHelper(mime, true, StringUtils.CHARSET_UTF8);
            helper.setTo(emails);// 收件人邮箱地址
            //抄送
            if (cc != null) {
                helper.setCc(cc);
            }
            helper.setFrom(mailSender.getUsername());// 发件人
            helper.setSubject(String.format("账单确认-%s", billName));// 主题
            helper.setText(param.getContent(),true);// 正文

            // 添加附件
            String attachmentName = MimeUtility.encodeWord(excelFileName, StringUtils.CHARSET_UTF8, "B");
            helper.addAttachment(attachmentName, file);

            LOG.info("甲方账单-发送确认邮件, loginUserId:{}, billId:{} 文件名:{}, 附件名称:{}",
                    loginUserId, billId, formatName, attachmentName);

            mailSender.send(mime);
            LOG.info("甲方账单-发送确认邮件, loginUserId:{}, billId:{} 邮件发送成功", loginUserId, billId);

            int updateRows = customerAggBillManager.updateSendMail(param, billDO.getVersion(), now);
            if (updateRows < 1) {
                LOG.info("甲方账单-发送确认邮件, 更新账单发送状态失败 loginUserId:{}, billId:{}", loginUserId, billId);
                return ResponseDTO.systemError();
            }

            //同步ES
            syncEsByBillId(billId, "发送确认邮件");

            return ResponseDTO.ok();
        } catch (Exception e) {
            String msg = String.format("甲方账单-发送确认邮件异常, loginUserId:%s, billId:%s", loginUserId, billId);
            LOG.error(msg, e);
            alertManager.alertAsync(msg, msg);
        }
        return ResponseDTO.systemError();
    }

网易163邮箱显示正常,唯独使用outlook客户端打开邮件时 附件 文件名出现了乱码情况,有些时候还是显示成 xxx.bin。

Google 查了一下 这是因为编码后附件文件名过长被截断导致出现未命名或者奇怪命名。

需要在代码中增加如下配置:

    //FIXED: JavaMail 中文附件名 乱码问题
    static {
        System.setProperty("mail.mime.splitlongparameters","false");
        System.setProperty("mail.mime.charset","UTF-8");
    }

相关资料