Spring Boot使用网易云企业邮箱发送带附件的邮件

前置准备

网易企业邮箱的smtp服务器

可通过https://qiye.163.com/help/client-profile.html查询

授权码

在网易企业邮箱登陆后->左上角设置-> 客户端设置 -> 生成授权密码

依赖

<!--        发送邮件模块-->
<dependency>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-mail</artifactId>
</dependency>
<dependency>
	<groupId>com.alibaba</groupId>
	<artifactId>easyexcel</artifactId>
	<version>3.0.2</version>
</dependency>

代码实现

使用easyExcel导出为附件(流)

easyExcel填充模板可以阅读easyExcel官方文档:

https://easyexcel.opensource.alibaba.com/docs/current/quickstart/fill

@Override
public void sendEmailAttachment(String billId, String email) {
    
    Map<String,Object> data = new HashMap<>();
    // 构建请求数据
    buildData(data,billId);

    try(InputStream fileInputStream = new ClassPathResource("excel/bill_template.xlsx").getInputStream();
        ByteArrayOutputStream outputStream = new ByteArrayOutputStream();  ) {
        ExcelWriter excelWriter = EasyExcel.write(outputStream).withTemplate(fileInputStream).build();
        // 填充信息
        WriteSheet billSheet = EasyExcel.writerSheet("***").build();
        excelWriter.fill(data, billSheet);
        // 填充列表数据
        if (data.containsKey("****") && data.get("****") instanceof List && !((List<?>) data.get("****")).isEmpty()) {
            excelWriter.fill( data.get("****"), billSheet);
        }
        // 关闭writer
        excelWriter.finish();
        outputStream.flush();
        log.info("文件已生成,包含的导出数据为:{}",data);
        // 发送邮件
        String subject = "****";
        String text = "****";
        // 直接使用ByteArrayResource,避免多次转换
        InputStreamSource attachmentSource = new ByteArrayResource(outputStream.toByteArray());
        emailService.sendEmailWithAttachment(email, subject, text,
                "****" + data.get("billNo") + ".xlsx", attachmentSource);
        
    } catch (Exception e) {
        log.error("****", e);
        throw new BusinessException("发送邮件失败: " + e.getMessage());
    }
}

private void buildData(Map<String, Object> data,String billId) {
        // 模板注意 用{} 来表示你要用的变量 如果本来就有"{","}" 特殊字符 用"\{","\}"代替
        // {} 代表普通变量 {.} 代表是list的变量
        EomsBillDetailDTO billDetail = detail(billId);
    	// 模板中的字段名
        data.put("name", billDetail.getName());
        // 列表数据
        List<Map<String, Object>> itemList = new ArrayList<>();
        for(EomsBillExpense billExpense : billDetail.getBillExpenseList()){
            Map<String, Object> item = new HashMap<>();
            item.put("expenseNo", billExpense.getExpenseNo());
            itemList.add(item);
        }
        data.put("expense", itemList);
    }

发送附件

配置文件

# 邮件地址配置
# 邮箱服务器
spring.mail.host=smtphz.qiye.163.com
spring.mail.port=25
# 企业邮箱账号
spring.mail.username=${MAIL_USERNAME:****}
#  授权码
spring.mail.password=${MAIL_PASSWORD:*****}
spring.mail.protocol=smtp
spring.mail.default-encoding=UTF-8

# SMTP 属性配置
spring.mail.properties.mail.smtp.auth=true
spring.mail.properties.mail.smtp.starttls.enable=true
spring.mail.properties.mail.smtp.starttls.required=true
spring.mail.properties.mail.smtp.connectiontimeout=5000
spring.mail.properties.mail.smtp.timeout=5000
spring.mail.properties.mail.smtp.writetimeout=5000
spring.mail.properties.mime.charset=UTF-8
spring.mail.properties.default-encoding=UTF-8
/**
 * 发送带附件的邮件(带指数重试机制)
 * @param to 收件人邮箱地址
 * @param subject 邮件主题
 * @param text 邮件内容
 * @param attachmentName 附件名称
 * @param attachmentSource 附件资源
 */
@Override
public void sendEmailWithAttachment(String to, String subject, String text,
                                    String attachmentName,  InputStreamSource attachmentSource) {
    int retryCount = 0;

    while (true) {
        try {
            MimeMessage message = mailSender.createMimeMessage();
            MimeMessageHelper helper = new MimeMessageHelper(message, true, StandardCharsets.UTF_8.name());
            helper.setFrom(mailProperties.getUsername());
            helper.setTo(to);
            helper.setSubject(subject);
            helper.setText(text);
            // 添加附件
            helper.addAttachment(attachmentName, attachmentSource,"application/vnd.openxmlformats-officedocument.spreadsheetml.sheet");
            mailSender.send(message);
            log.info("带附件邮件发送成功: {} -> {} (重试次数: {})", mailProperties.getUsername(), to, retryCount);
            // 发送成功,直接返回
            return;
        } catch (Exception e) {
            retryCount++;
            if (retryCount > MAX_RETRY_TIME) {
                log.error("带附件邮件发送失败,已达到最大重试次数({}): {}", MAX_RETRY_TIME, to, e);
                throw new BusinessException("邮件发送失败 ");
            }
            // 计算指数退避延迟时间: 1s, 2s, 4s
            long delayMs = BASE_DELAY_MS * (1L << (retryCount - 1));
            log.warn("带附件邮件发送失败,将在 {}ms 后进行第 {} 次重试: {}", delayMs, retryCount, to, e);
            
            try {
                Thread.sleep(delayMs);
            } catch (InterruptedException ie) {
                Thread.currentThread().interrupt();
                log.error("重试等待被中断: {}", to, ie);
                throw new RuntimeException("邮件发送重试被中断: " + ie.getMessage(), ie);
            }
        }
    }
}

问题

发送的附件打开为乱码

添加附件时,设置contenType

helper.addAttachment(attachmentName, attachmentSource,"application/vnd.openxmlformats-officedocument.spreadsheetml.sheet");
posted @ 2025-12-26 10:58  Lwf663  阅读(0)  评论(0)    收藏  举报