首页 > 其他分享 >基础备忘(发送htm正文带图片并且带附件的邮件)

基础备忘(发送htm正文带图片并且带附件的邮件)

时间:2023-04-28 12:00:38浏览次数:34  
标签:MimeMultipart String mailInfo htm MimeBodyPart 附件 new 备忘 邮件

需求背景如下: 发送htm正文带图片并且带附件的邮件 。如题所示,任务拆解关键字为:

  • html正文
  • 带图片
  • 带附件

先介绍普通发邮件的方式

添加maven引用

  <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-mail</artifactId>
  </dependency>
@Data
public  class MailInfo {
    /**
     * 邮件接收人
     */
    private String[] receiver;
    /**
     * 邮件主题
     */
    private String subject;
    /**
     * 邮件的文本内容
     */
    private String content;
    /**
     * 抄送人
     */
    private String[] cc;
    /**
     * 邮件附件的文件名
     */
    private String[] attachFileNames;
    /**
     * 邮件内容内嵌图片
     */
    private Map<String, URL> imageMap;
}

邮件信息实体类(包含发给谁、主题、内容、抄送人等)

    @Resource
    private JavaMailSender javaMailSender;
    @Resource
    private EmailConfig ec;
    @Value("${spring.mail.username}")
    private String fromUser;

	@Override
    public void sendSimpleTextEmail(MailInfo mailInfo) {
        try {
            SimpleMailMessage mailMessage = new SimpleMailMessage();
            //发件人
            mailMessage.setFrom(fromUser);
            //接收人
            mailMessage.setTo(mailInfo.getReceiver());
            //邮件主题
            mailMessage.setSubject(mailInfo.getSubject());
            //邮件抄送
            if(mailInfo.getCc()!=null){
                mailMessage.setCc(mailInfo.getCc());
            }
            //邮件内容
            mailMessage.setText(mailInfo.getContent());
            //发送邮件
            javaMailSender.send(mailMessage);
        } catch (Exception e) {
            log.error("邮件发送失败:{}", e.getMessage());
        }
    }

发送邮件工具类

发送简单文字内容邮件:先组装mailnfo信息然后调用sendSimpleTextEmail 方法发送即可。

html正文

从上面mailIfno实体类中可以看到 content 表示邮件的文本内容,这里是字符串信息,可以直接写入html字符串即可。不过我的实际项目需求是这块邮件内容需要根据不同的业务类型有不同的模板样式,因此在这里我引入thymeleaf模板引擎动态生成html。

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

        <dependency>
            <groupId>ognl</groupId>
            <artifactId>ognl</artifactId>
            <version>3.2</version>
        </dependency>

添加模板引擎的 maven引用

@Configuration
public class MailTemplateConfig {
    @Bean("emailTemplateEngine")
    public TemplateEngine templateEngine(){
        ClassLoaderTemplateResolver resolver = new ClassLoaderTemplateResolver();
        resolver.setPrefix("templates/");
        resolver.setSuffix(".html");
        TemplateEngine engine = new TemplateEngine();
        engine.setTemplateResolver(resolver);
        return  engine;
    }
}

模板引擎配置类,这里配置与application.yml里面配置是一样的效果

<div class="wrapper">
  <div class="content">
    <div>
      <div class="page-title">
        <img id="image0_44_3173"  width="115"  height="30" src="cid:logo" />
        <h3 class="title">- title</h3>
      </div>
      <div class="msg-title">Register Verification Code</div>
      <p class="msg-des">Continue registering with account by entering the verification code below:</p>
      <div class="msg-content">
        <div><b th:text="${code}"></b></div>
      </div>
      </div>
      <p class="msg-des">Best Regards~</p>
    </div>
  </div>
</div>
@Async
    @Override
    public void sendHtmlEmail(EmailBaseDto dto) {
        log.info("sendEmail --发送邮件开始,fromUser:{}, toUser:{}", fromUser, dto.getToUser());
        try {
            MailInfo mailInfo = new MailInfo();
            mailInfo.setReceiver(new String[]{dto.getToUser()});
            String subject="";
            switch (dto.getEmailNotificationTypeEnum()){
               
                case 用户注册验证码:
                    subject= "Verification Code" ;
                    break;
                default:
                    break;
            }
            if(StringUtils.isEmpty(subject)){
                throw  new BusinessException(RespCodeEnum.EMAIL_NOTIFICATION_TYPE_ERROR.getCode(),RespCodeEnum.EMAIL_NOTIFICATION_TYPE_ERROR.getMsg());
            }
            mailInfo.setSubject(subject);
            Context context = new Context();

            Map<String, Object> paramsMap = BeanUtil.beanToMap(dto);
            context.setVariables(paramsMap);
            String bodyString = templateEngine.process(dto.getEmailNotificationTypeEnum().getValue(), context);
            mailInfo.setContent(bodyString);
            //增加logo图片
            Map<String, URL> imageMap = this.getLogoMap();
            mailInfo.setImageMap(imageMap);
            emailUtilService.sendHtmlEmail(mailInfo);
        } catch (Exception e) {
            log.error("send  mail error", e);
            throw new BusinessException(RespCodeEnum.EMAIL_SEND_ERROR.getCode(),RespCodeEnum.EMAIL_SEND_ERROR.getMsg());
        }
    }

截取部分html片段展示动态生成邮件模板html字符串,其中 <div><b th:text="${code}"></b></div> 是模板thymeleaf的语法

   @Resource(name = "emailTemplateEngine")
    private TemplateEngine templateEngine;

省略……

Context context = new Context();
            Map<String, Object> paramsMap = BeanUtil.beanToMap(emailApprovalNotificationDto);
            context.setVariables(paramsMap);
String bodyString = templateEngine.process(dto.getEmailNotificationTypeEnum().getValue(), context);
        mailInfo.setContent(bodyString)

这里面 Map<String, Object> paramsMap 是对应着前面模板引擎中<div><b th:text="${code}"></b></div>动态参数内容,如 code 那么在 paramsMap 需要有与之对应的键。最后再调用templateEngine.process` 渲染成html字符串。

带附件

    public MimeBodyPart createAttachment(String filename) throws Exception {
        //创建保存附件的MimeBodyPart对象,并加入附件内容和相应的信息
        MimeBodyPart attachPart = new MimeBodyPart();
        FileDataSource fsd = new FileDataSource(filename);
        attachPart.setDataHandler(new DataHandler(fsd));
        attachPart.setFileName(fsd.getName());
        return attachPart;
    }
  MimeMultipart allMultipart = new MimeMultipart();
	allMultipart.addBodyPart(contentPart);
            //创建用于组合邮件正文和附件的MimeMultipart对象
            for (int i = 0; i < mailInfo.getAttachFileNames().length; i++) {
                allMultipart.addBodyPart(createAttachment(mailInfo.getAttachFileNames()[i]));
            }

从本地文件路径读取文件,并创建MimeBodyPart对象,像附件、图片啥的都是要构建这个对象MimeBodyPart,下图是类图关系。

image

带图片

MimeMultipart allMultipart = new MimeMultipart();
MimeBodyPart contentPart = createContent(mailInfo.getContent(), mailInfo.getImageMap());
public MimeBodyPart createContent(String body, Map<String, URL> map) throws Exception {
        //创建代表组合Mime消息的MimeMultipart对象,将该MimeMultipart对象保存到MimeBodyPart对象
        MimeBodyPart contentPart = new MimeBodyPart();
        MimeMultipart contentMultipart = new MimeMultipart("related");

        //创建用于保存HTML正文的MimeBodyPart对象,并将它保存到MimeMultipart中
        MimeBodyPart htmlBodyPart = new MimeBodyPart();
        htmlBodyPart.setContent(body, "text/html;charset=UTF-8");
        contentMultipart.addBodyPart(htmlBodyPart);

        if (map != null && map.size() > 0) {
            Set<Map.Entry<String, URL>> set = map.entrySet();
            for (Map.Entry<String, URL> entry : set) {
                //创建用于保存图片的MimeBodyPart对象,并将它保存到MimeMultipart中
                MimeBodyPart gifBodyPart = new MimeBodyPart();
                URLDataSource uds=new URLDataSource(entry.getValue());

                gifBodyPart.setDataHandler(new DataHandler(uds));
                gifBodyPart.setContentID(entry.getKey());    //cid的值
                contentMultipart.addBodyPart(gifBodyPart);
            }
        }

        //将MimeMultipart对象保存到MimeBodyPart对象
        contentPart.setContent(contentMultipart);
        return contentPart;
    }

同上面的带附件一样,也是构建MimeBodyPart,但是需要注意的是 MimeMultipart contentMultipart = new MimeMultipart("related"); 其中 MimeMultipart 有不同的 subtype,默认是mixed 表示类似带附件那种(附件与正文分开),另一种则是 related 既附件与content是有关联关系的,也就是咱们现在要做的正文中嵌入图片。

可以看到图片这个 MimeBodyPart中,存在一对方法

                gifBodyPart.setContentID(entry.getKey());    //cid的值
				gifBodyPart.setDataHandler(new DataHandler(uds));

其中 setContentID 中的cid值与我们前面 html模板字符串中 <b th:text="${code}"></b> 对应,即:在此示例中setContentID 方法里面 entry.getKey的值为字符串 code然后JavaMailSender在发送的时候会通过keygifBodyPart中查找key=codeDataHandler信息。gifBodyPart.setDataHandler(new DataHandler(uds)); 如下所示这里的 DataHandler有 DataSource类型的构造方法

    public DataHandler(DataSource ds) {
	// save a reference to the incoming DS
	dataSource = ds;
	oldFactory = factory; // keep track of the factory
    }

同时DataSource有两个实现类 FileDataSourceURLDataSource 其中FileDataSource 是读取本地文件路径时使用的,URLDataSource 是为了外部网络资源或者springboot打包成jar后本地路径无法直接取到时使用的。

springboot打jar后,本地ide环境可以正常取到resource下资源,但是部署后取不到只能用流的方式读取,而spring-boot-starter-mail又没有提供流的实现入参,因此可以用 URLDataSource 实现类传入resource下的url地址,由spring-boot-starter-mail发送时去读。

image

总是有些基础内容用过就忘掉了,缺少总结记录。在此记录下来便于以后查找也为遇到类似问题的人一个小小的帮助。

标签:MimeMultipart,String,mailInfo,htm,MimeBodyPart,附件,new,备忘,邮件
From: https://www.cnblogs.com/falcon-fei/p/17350279.html

相关文章

  • 网页截图,html2canvas简单示例
     <divid="box"><p>asd4a5s6fa6s5f1asf</p><imgstyle="width:200px"src="xxxxxx.png"/><buttonstyle="width:100px;height:30px"onclick="prtsc()">pr......
  • 从零开始构建HTML 5 Web页面
    HTML5是时下Web开发领域炒得火热的一个术语,是的,很多人都看好它,也有很多业内知名公司开始正式使用HTML5重新构建自己的网站,如YouTube开始使用HTML5视频,Google已经弃用自家的Gears,开始全面拥抱HTML5实现离线解决方案,各大浏览器厂家也纷纷开始支持HTML5,连被人诟病的微软也声称要......
  • 认识HTML5的WebSocket
    在HTML5规范中,我最喜欢的Web技术就是正迅速变得流行的WebSocketAPI。WebSocket提供了一个受欢迎的技术,以替代我们过去几年一直在用的Ajax技术。这个新的API提供了一个方法,从客户端使用简单的语法有效地推动消息到服务器。让我们看一看HTML5的WebSocketAPI:它可用于客户端、服务器......
  • cshtml和html的区别从语法和功能上来看
    https://www.lookxue.com/blog/o61302ve.htmlcshtml和html的区别:1.cshtml是一种混合式的文件,它将html、javascript和C#代码结合在一起,而html只是一种纯静态的文件;2.cshtml可以使用C#代码进行逻辑处理,而html不能;3.cshtml中可以使用Razor语法,而html中不能;4.cshtml可以使用@......
  • html表格相关属性
    <!DOCTYPEhtml><html>   <head>      <metacharset="UTF-8">      <title>表头标签</title>   </head>   <body>      <tablealign="center"border="1"cellpadding="0"......
  • HTML中script 标签中的那些属性
    在HTML中,<script>标签用于嵌入或引用JavaScript代码。在<script>标签中,有两个属性可以用来控制脚本的加载和执行方式:async和defer。当然这也是常见的一道面试题,async 和 defer的作用和区别。async和defer属性都可以用于异步加载脚本,从而避免了在加......
  • java 后台给前台传值,html:select,html:text等加载页面显示默认值的方法
    后台写request.setAttribute("dateCreated","黑色头发");前台接收:html:text<html:textproperty="dateCreated"value="${dateCreated}"/>html:select<html:selectproperty="accountsUser"va......
  • java js JavaScript 设置html:radio的默认选中, js也可以用el表达式
    <html:radioproperty="consumptionClass"value="花了">花了</html:radio><html:radioproperty="consumptionClass"value="赚了">赚了</html:radio><html:radioproperty="consumptionClass"va......
  • html超链接
    html超链接​外部链接腾讯 target打开窗口的方式默认的值_self当前窗口打开页面_blank新窗口打开页面 百度​<h4>内部链接</h4><ahref="第一次使用工具.html">工具介绍</a><h4>空链接</h4><ahref="#">公司地址</a><h4>下载链接地......
  • Html 每个属性的意义
    <!DOCTYPEhtml><html>   <head>      <metacharset="utf-8">      <title>利用工具做的第一个页面</title>//注释网页顶端介绍   </head>   <body>      <p><h1>如果说是JQuery是手工作坊,那么Vue.js就像是一座工厂,<br/&g......