springboot发送邮件,包含附件、图片

需求:发送带附件的邮件,并需要将邮件正文中的图片链接替换。

1、发送邮件的主方法

/**
 * 发送邮件主方法
 * @param outbox为发送邮件封装的对象,主要包括发送协议、收发人地址、密码等基本信息
 * @return
 */
public MailOutboxMsg sendEmail(MailOutboxMsg outbox) throws Exception{
    JavaMailSenderImpl javaMailSender = this.createMailSender(outbox);
    Properties props = this.initMailProp();
    javaMailSender.setJavaMailProperties(props);

    MimeMessage mimeMessage = javaMailSender.createMimeMessage();
    mimeMessage.addHeader("uuid", "uuid");
    MimeMessageHelper helper = new MimeMessageHelper(mimeMessage, true,"UTF-8");
    helper.setSubject(outbox.getSubject());
    helper.setFrom(outbox.getSentEmail());
    //设置邮件接收人、抄送人、密送人,均为邮件地址数组
    helper.setTo(outbox.getToEmail().split(";"));
    helper.setCc(outbox.getCcEmail().split(";"));
    helper.setBcc(outbox.getBccEmail().split(";"));
    helper.setSentDate(new Date());

    //设置邮件内容,替换图片链接
    this.parseContent(helper, outbox.getContent());
    helper.setText(outbox.getContent(), true);

    //添加附件,此处文件服务器为fastdfs,可自行替换成其他获取文件流方法
    if(CollectionUtils.isNotEmpty(outbox.getAttaches())){
        for(MailAttachMsg attach : outbox.getAttaches()){
            String attachtUrl = attach.getAttachUrl();
            String relativeUrl = attachtUrl.replace(hdfsUrlPrex, "");
            String group = relativeUrl.substring(0, relativeUrl.indexOf("/"));
            String fileName = relativeUrl.substring(relativeUrl.indexOf("/") + 1);
            // 获取hdfs上传文件流
            byte[] bytes = FastDFSClient.down(group, fileName);
            File file = this.byte2File(bytes, "./" + attach.getAttachName());
            helper.addAttachment(attach.getAttachName(), file);
            files.add(file);
        }
    }
    //发送邮件
    javaMailSender.send(mimeMessage);
    //发送成功获取邮件头,后续业务操作中会使用到
    String msgId = mimeMessage.getMessageID().replace("[", "").replace("]", "");
    outbox.setMsgId(msgId);
    return outbox;
}

2、发送前邮件属性初始化

/**
 * 初始化邮件发送sender
 * @param outbox
 * @return
 */
private JavaMailSenderImpl createMailSender(MailOutboxMsg outbox){
    JavaMailSenderImpl javaMailSender = new JavaMailSenderImpl();
    javaMailSender.setProtocol("smtp");
    javaMailSender.setHost(outbox.getSentAddress());
    javaMailSender.setPort(outbox.getSentPort());
    javaMailSender.setPassword(outbox.getPassword());
    javaMailSender.setUsername(outbox.getSentEmail());
    javaMailSender.setDefaultEncoding("utf-8");
    return javaMailSender;
}

/**
 * 初始化邮件发送properties
 * @return
 */
private Properties initMailProp(){
    Properties props = new Properties();
    props.setProperty("spring.mail.properties.mail.smtp.auth","true");
    props.setProperty("spring.mail.properties.mail.smtp.ssl.enable","true");
    props.setProperty("spring.mail.test-connection","true");
    //防止中文乱码
    props.setProperty("spring.mail.default-encoding", "GB2312");
    props.setProperty("mail.smtp.socketFactory.fallback", "true");
    props.setProperty("mail.smtp.starttls.enable", "true");
    props.setProperty("mail.mime.splitlongparameters", "false");
    return props;
}

3、解析邮件中的图片,进行替换。这个操作是避免将自身服务器链接直接暴露给其他人,也可以避免日后因为文件服务器访问权限变更,造成邮件中图片无法查看的情况

/**
 * 解析发送邮件内容中的图片
 * @param emailContent
 */
private String parseContent(MimeMessageHelper helper, String emailContent) throws Exception {
    // 获取正文图片地址
    Set<String> pics = getImgUrl(emailContent);
    // 处理每张图片,必须要先设置settext,再设置addinline,否则图片无法显示
    HashMap<String, File> imgMap = new HashMap<>();
    for (String imageUrl : pics) {
        // 正文图片
        String contentId = getRandomFileName(imageUrl);
        String relativeUrl = imageUrl.replace(hdfsUrlPrex, "");
        String group = relativeUrl.substring(0, relativeUrl.indexOf("/"));
        String fileName = relativeUrl.substring(relativeUrl.indexOf("/") + 1);
        // 获取hdfs上传文件流
        byte[] bytes = FastDFSClient.down(group, fileName);
        emailContent = emailContent.replace(imageUrl, "cid:" + contentId);
        File file = this.byte2File(bytes, "./" + relativeUrl.substring(relativeUrl.lastIndexOf("/")+1));
        files.add(file);
        imgMap.put(contentId, file);
    }
    helper.setText(emailContent,true);
    for(String contentId : imgMap.keySet()){
        helper.addInline(contentId, imgMap.get(contentId));
    }
    return emailContent;
}

/**
 * 获取图片链接
 * @param content
 * @return
 */
private Set<String> getImgUrl(String content) {
    Set<String> pics = new HashSet<>();
    String img = "";
    Pattern p_image;
    Matcher m_image;
    //     String regEx_img = "<img.*src=(.*?)[^>]*?>"; //图片链接地址
    String regEx_img = "<img.*src\\s*=\\s*(.*?)[^>]*?>";
    p_image = Pattern.compile(regEx_img, Pattern.CASE_INSENSITIVE);
    m_image = p_image.matcher(content);
    while (m_image.find()) {
        // 得到<img />数据
        img = m_image.group();
        // 匹配<img>中的src数据
        Matcher m = Pattern.compile("src\\s*=\\s*\"?(.*?)(\"|>|\\s+)").matcher(img);
        while (m.find()) {
            // 地址以hdfs路径开头
            if (m.group(1).startsWith(hdfsUrlPrex)) {
                pics.add(m.group(1));
            }
        }
    }
    return pics;
}

/**
 * 设置图片id,不能重复
 * @param hdfsUrl
 * @return
 */
private String getRandomFileName(String hdfsUrl) {
    // 获取后缀名
    String suffix = hdfsUrl.substring(hdfsUrl.lastIndexOf("."));
    // 当前系统时间+5位随机数+文件后缀名生成
    return String.valueOf(new Date().getTime()) + (int)((Math.random()*9+1)*10000) + suffix;
}

4、最后一个小方法,将字节流转换为file。我这个是从fastdfs服务器获取文件,所以需要这一步,实际情况应该比这个简单,可以直接new File即可

public File byte2File(byte[] byteArray, String targetPath) {
    InputStream in = new ByteArrayInputStream(byteArray);
    File file = new File(targetPath);
    String path = targetPath.substring(0, targetPath.lastIndexOf("/"));
    if (!file.exists()) {
        new File(path).mkdir();
    }
    FileOutputStream fos = null;
    try {
        fos = new FileOutputStream(file);
        int len = 0;
        byte[] buf = new byte[1024];
        while ((len = in.read(buf)) != -1) {
            fos.write(buf, 0, len);
        }
        fos.flush();
    } catch (Exception e) {
        e.printStackTrace();
    } finally {
        if (null != fos) {
            try {
                fos.close();
            } catch (IOException e) {
                e.printStackTrace();
            }
        }
    }
    return file;
}

 

上一篇:leetcode-101. 对称二叉树


下一篇:Xpath helper插件