SpringBoot入门建站全系列(十)邮件发送功能

SpringBoot入门建站全系列(十)邮件发送功能

Spring Mail API都在org.springframework.mail及其子包org.springframework.mail.javamail中封装。

JavaMailSenderImpl: 邮件发送器,主要提供了邮件发送接口、透明创建Java Mail的MimeMessage、及邮件发送的配置(如:host/port/username/password...)。
MimeMailMessage、MimeMessageHelper:对MimeMessage进行了封装。Spring还提供了一个回调接口MimeMessagePreparator, 用于准备JavaMail的MIME信件.

SpringBoot对Email做了封装:https://docs.spring.io/spring-boot/docs/2.0.9.RELEASE/reference/htmlsingle/#boot-features-email

直接读取配置,然后我们的Service逻辑可以直接注入JavaMailSender进行邮件发送。

项目地址:
品茗IT-同步发布

品茗IT 提供在线支持:

一键快速构建Spring项目工具

一键快速构建SpringBoot项目工具

一键快速构建SpringCloud项目工具

一站式Springboot项目生成

Mysql一键生成Mybatis注解Mapper

如果大家正在寻找一个java的学习环境,或者在开发中遇到困难,可以加入我们的java学习圈,点击即可加入,共同学习,节约学习时间,减少很多在学习中遇到的难题。

一、配置

本文假设你已经引入spring-boot-starter-web。已经是个SpringBoot项目了,如果不会搭建,可以打开这篇文章看一看《SpringBoot入门建站全系列(一)项目建立》。

1.1 Maven依赖


    org.springframework.boot
    spring-boot-starter-mail


    com.alibaba
    fastjson

配置fastjson是因为我写的示例中用到了,用不到的话就可以去掉。

1.2 配置文件

application.properties 中需要添加下面的配置:

spring.mail.host=smtp.qq.com
[email protected]
spring.mail.password=xxxxx
spring.mail.port=465
spring.mail.properties.mail.smtp.auth=true
spring.mail.properties.mail.smtp.starttls.enable=true
spring.mail.properties.mail.smtp.ssl.enable=true
spring.mail.properties.mail.smtp.starttls.required=true 

[email protected]
mail.fromName=Admin

这里,

  • spring.mail.properties是额外的配置信息。

  • spring.mail.port这个很重要,我用的是465,是smtp的ssl端口,smtp一般是用25端口,但是很多云服务器把25端口禁用了,美其名曰安全。所以可以用465端口也发送邮件。如果想用25端口,后面的spring.mail.properties.*去掉即可。

  • mail.from和mail.fromName是业务逻辑需要的配置,不是SpringBoot自动装配的。

  • 其他配置文件都是见文知意了,不再说了。

SpringBoot官网配置文件说明:

# Email (MailProperties)
spring.mail.default-encoding=UTF-8 # Default MimeMessage encoding.
spring.mail.host= # SMTP server host. For instance, `smtp.example.com`.
spring.mail.jndi-name= # Session JNDI name. When set, takes precedence over other Session settings.
spring.mail.password= # Login password of the SMTP server.
spring.mail.port= # SMTP server port.
spring.mail.properties.*= # Additional JavaMail Session properties.
spring.mail.protocol=smtp # Protocol used by the SMTP server.
spring.mail.test-connection=false # Whether to test that the mail server is available on startup.
spring.mail.username= # Login user of the SMTP server.

二、发送邮件业务逻辑

发送邮件时,需要指明发送人邮箱和名称。

package com.cff.springbootwork.mail.service;

import java.io.File;
import java.io.IOException;
import java.io.UnsupportedEncodingException;
import java.util.List;

import javax.mail.MessagingException;
import javax.mail.internet.MimeMessage;
import javax.mail.internet.MimeUtility;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.PropertySource;
import org.springframework.core.io.FileSystemResource;
import org.springframework.mail.MailException;
import org.springframework.mail.javamail.JavaMailSender;
import org.springframework.mail.javamail.MimeMessageHelper;
import org.springframework.stereotype.Service;

import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONArray;
import com.alibaba.fastjson.JSONObject;
import com.alibaba.fastjson.parser.Feature;
import com.cff.springbootwork.mail.type.*;

@Service
public class MailService {
    private final Logger logger = LoggerFactory.getLogger(this.getClass());
    static final String DELIM_STR = "{}";

    @Autowired
    private JavaMailSender javaMailSender;
    
    @Value("${mail.from}")
    private String from;
    
    @Value("${mail.fromName}")
    private String fromName;
    
    /**
     * 简单发送html内容
     * 
     * @param to
     *            指定收件人
     * @param subject
     *            主题
     * @param content
     *            内容
     * @param isHtml
     *            是否是html
     */
    public void sendSimpleMail(String to, String subject, String content, boolean isHtml) {
        MimeMessage message = javaMailSender.createMimeMessage();
        try {
            MimeMessageHelper helper = new MimeMessageHelper(message, true);
            helper.setFrom(from,fromName);
            helper.setTo(to);
            helper.setSubject(subject);
            helper.setText(content, isHtml);
            javaMailSender.send(message);
            logger.info("html邮件发送成功");
        } catch (MessagingException e) {
            logger.error("发送html邮件时发生异常!", e);
        } catch (UnsupportedEncodingException e) {
            logger.error("发送html邮件时发生异常!", e);
        }

    }

    /**
     * 简单发送内嵌文件方法
     * 
     * @param to
     *            指定收件人
     * @param subject
     *            主题
     * @param content
     *            内容
     * @param rscPath
     *            资源路径(文件路径)
     * @param rscId
     *            资源标识
     */
    public void sendInlineResourceMail(String to, String subject, String content, String rscPath, String rscId) {
        MimeMessage message = javaMailSender.createMimeMessage();

        try {
            MimeMessageHelper helper = new MimeMessageHelper(message, true);
            helper.setFrom(from,fromName);
            helper.setTo(to);
            helper.setSubject(subject);
            helper.setText(content, true);

            FileSystemResource res = new FileSystemResource(new File(rscPath));
            helper.addInline(rscId, res);

            javaMailSender.send(message);
            logger.info("嵌入静态资源的邮件已经发送。");
        } catch (MessagingException e) {
            logger.error("发送嵌入静态资源的邮件时发生异常!", e);
        } catch (UnsupportedEncodingException e) {
            logger.error("发送嵌入静态资源的邮件时发生异常!", e);
        }
    }

    /**
     * 简单发送附件方法
     * 
     * @param to
     *            指定收件人
     * @param subject
     *            主题
     * @param content
     *            内容
     * @param filePath
     *            附件地址,可传递多个
     */
    public void sendAttachmentsMail(String to, String subject, String content, String[] filePaths) {
        System.getProperties().setProperty("mail.mime.splitlongparameters", "false");

        MimeMessage message = javaMailSender.createMimeMessage();
        try {
            MimeMessageHelper helper = new MimeMessageHelper(message, true, "utf-8");
            helper.setFrom(from,fromName);
            helper.setTo(to);
            helper.setSubject(subject);
            helper.setText(content, true);

            for (String filePath : filePaths) {
                FileSystemResource file = new FileSystemResource(new File(filePath));
                String fileName = filePath.substring(filePath.lastIndexOf(File.separator) + 1);
                helper.addAttachment(MimeUtility.encodeText(fileName), file);
            }

            javaMailSender.send(message);
            logger.info("带附件的邮件已经发送。");
        } catch (MessagingException e) {
            logger.error("发送带附件的邮件时发生异常!", e);
        } catch (UnsupportedEncodingException e) {
            e.printStackTrace();
        }
    }

    /**
     * 完整发送邮件方法,需要调用setMailMessage方法配置邮件 {@link #setMailMessage(MailMessage)}
     * 

占位符使用{},内容中如果要使用{},就修改代码吧,这里不支持。 * @param content * 带占位符正文 * @param mailTypes * 可变参数,填充占位符 * @throws Exception */ public void sendCompleteHtml(String content, List mailTypes, MailMessage mailMessage) throws Exception { System.getProperties().setProperty("mail.mime.splitlongparameters", "false"); if (mailMessage.getFrom() == null || "".equals(mailMessage.getFrom())) { mailMessage.setFrom(from); mailMessage.setFromName(fromName); } MimeMessage message = javaMailSender.createMimeMessage(); MimeMessageHelper helper = new MimeMessageHelper(message, true); helper.setFrom(mailMessage.getFrom()); helper.setTo(mailMessage.getTo()); if (mailMessage.getCc() != null && mailMessage.getCc().length > 0) helper.setCc(mailMessage.getCc()); helper.setSubject(mailMessage.getSubject()); String msg = getContent(content, mailTypes); helper.setText(msg, true); for (MailType item : mailTypes) { switch (item.getType()) { case MailType.TYPE_FILE: if (item != null) { InlineFile inlineFile = (InlineFile) item; helper.addInline(inlineFile.getCid(), new File(inlineFile.getFilePath())); } break; case MailType.TYPE_ATTACH: if (item != null) { AttachFile attachFile = (AttachFile) item; helper.addAttachment(MimeUtility.encodeText(attachFile.getFileName()), new File(attachFile.getFilePath())); } break; } } try{ javaMailSender.send(message); }catch(MailException e){ logger.error("邮件发送过程出错,重发一次。",e); javaMailSender.send(message); } logger.info("完整的邮件已经发送。"); } /** * 解析占位符 * * @param content * 字符串,带占位符{},有多少个{},就要有多少个MailType * @param mailTypes * MailType填充参数, 注:换行需主动添加 * @return 解析后的正文 * @throws MessagingException * @throws IOException */ private String getContent(String content, List mailTypes) throws MessagingException, IOException { String bodyPrefix = ""; String bodySuffix = ""; StringBuffer sb = new StringBuffer(); sb.append(bodyPrefix); for (MailType item : mailTypes) { if (content.length() < 1) break; int index = content.indexOf(DELIM_STR); if (index == -1) break; sb.append(content.substring(0, index)); switch (item.getType()) { case MailType.TYPE_FILE: if (item != null) { InlineFile inlineFile = (InlineFile) item; sb.append(""); } break; case MailType.TYPE_TEXT: TextString textString = (TextString) item; sb.append(textString.getText()); break; case MailType.TYPE_JSON: JsonTable json = (JsonTable) item; sb.append(genReportData(json)); break; } content = content.substring(index + 2); } sb.append(content); sb.append(bodySuffix); return sb.toString(); } /** * 根据Json字符串,生成有序的表格 * * @param jsonTable * json转table实体 * @return 表格字符串 * @throws IOException */ private String genReportData(JsonTable jsonTable) throws IOException { JSONArray ja = (JSONArray) JSON.parse(jsonTable.getData(), Feature.OrderedField); StringBuilder sb = new StringBuilder(); try { sb.append("

\n"); sb.append("\n"); JSONObject jsonFirst = (JSONObject) ja.get(0); sb.append("\n"); for (String key : jsonFirst.keySet()) { sb.append("\n"); } sb.append("\n"); ja.remove(0); for (Object column : ja) { sb.append("\n"); JSONObject json = (JSONObject) column; for (String key : jsonFirst.keySet()) { sb.append("\n"); } sb.append("\n"); } sb.append("
"); sb.append(jsonTable.getTitle()); sb.append("
"); sb.append(jsonFirst.get(key)); sb.append("
"); sb.append(json.get(key)); sb.append("
\n"); } catch (Exception e) { e.printStackTrace(); } return sb.toString(); } public String getFrom() { return from; } public void setFrom(String from) { this.from = from; } public JavaMailSender getJavaMailSender() { return javaMailSender; } public void setJavaMailSender(JavaMailSender javaMailSender) { this.javaMailSender = javaMailSender; } public String getFromName() { return fromName; } public void setFromName(String fromName) { this.fromName = fromName; } }

这里的MailService定义了多种邮件发送方式,包含普通文本、html、内嵌图片、附件、表格等。因此需要我们定义多种实体。

三、测试

新建一个MailRest,用来测试邮件发送:

package com.cff.springbootwork.mail.web;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;
import org.springframework.web.bind.annotation.RestController;

import com.cff.springbootwork.mail.service.MailService;


@RestController
@RequestMapping("/mail")
public class MailRest {
    @Autowired
    MailService mailService;
    
    @RequestMapping(value = "/mail/{to}", method = { RequestMethod.GET })
    public String mail(@PathVariable("to") String to) {
        String content = "直接登录网页  看发邮件吗,不能发的话 asdasd";
        mailService.sendSimpleMail(to, content, content, true);
        return "hello,world";
    }
    
}

四、过程中用到的邮件类型实体

MailMessage邮件实体:

package com.cff.springbootwork.mail.type;

import java.util.ArrayList;
import java.util.List;

/**
 * mail实体,使用Builder生成   例: new MailMessage.Builder().to(to).build();
 * @author fufei
 *  
 */
public class MailMessage {
    private String from;
    private String fromName;
    private List to;
    private List cc;
    private String subject;

    MailMessage(Builder builder) {
        this.from = builder.from;
        this.to = builder.to;
        this.cc = builder.cc;
        this.subject = builder.subject;
        this.fromName = builder.fromName;
    }

    public static class Builder {
        private String from;
        private String fromName;
        private List to = new ArrayList();
        private List cc = new ArrayList();
        private String subject;

        public Builder() {

        }

        /**
         * 添加发送人信息,为空则需要调用方主动设置
         * @param from 发送人邮件字符串
         * @return
         */
        public Builder from(String from) {
            this.from = from;
            return this;
        }
        
        /**
         * 添加发送人信息,为空则需要调用方主动设置
         * @param from 发送人邮件字符串
         * @return
         */
        public Builder fromName(String fromName) {
            this.fromName = fromName;
            return this;
        }

        /**
         * 添加收件人
         * @param toAddr String
         * @return
         */
        public Builder addTo(String toAddr) {
            to.add(toAddr);
            return this;
        }
        
        /**
         * 添加收件人列表
         * @param toAddr String
         * @return
         */
        public Builder addTo(List toAddr) {
            to.addAll(toAddr);
            return this;
        }

        /**
         * 设置收件人列表
         * @param to 收件人数组
         * @return
         */
        public Builder to(List to) {
            this.to = to;
            return this;
        }

        /**
         * 添加抄送人
         * @param ccAddr
         * @return
         */
        public Builder addCc(String ccAddr) {
            cc.add(ccAddr);
            return this;
        }
        
        /**
         * 添加抄送人列表
         * @param ccAddr
         * @return
         */
        public Builder addCc(List ccAddr) {
            cc.addAll(ccAddr);
            return this;
        }

        /**
         * 设置抄送人列表
         * @param cc
         * @return
         */
        public Builder cc(List cc) {
            this.cc = cc;
            return this;
        }

        /**
         * 设置主题
         * @param subject
         * @return
         */
        public Builder subject(String subject) {
            this.subject = subject;
            return this;
        }
        
        /**
         * 生成MailMessage
         * @return MailMessage
         */
        public MailMessage build() {
            if (to.size() < 1)
                throw new IllegalStateException("邮件接收人为空!");
            return new MailMessage(this);
        }
    }

    public String getFrom() {
        return from;
    }

    public void setFrom(String from) {
        this.from = from;
    }

    public String getFromName() {
        return fromName;
    }

    public void setFromName(String fromName) {
        this.fromName = fromName;
    }

    public String[] getTo() {
        String[] array = new String[to.size()];
        String[] s = to.toArray(array);
        return s;
    }

    public String[] getCc() {
        if (cc.size() < 1)
            return null;
        String[] array = new String[cc.size()];
        String[] s = cc.toArray(array);
        return s;
    }

    public String getSubject() {
        return subject;
    }
}

MailType邮件类型接口:

package com.cff.springbootwork.mail.type;

/**
 * 邮件类型
 * @author fufei
 *
 */
public abstract class MailType {
    public final static char TYPE_FILE = 'F';
    public final static char TYPE_ATTACH = 'A';
    public final static char TYPE_TEXT = 'T';
    public final static char TYPE_JSON = 'J';

    public abstract char getType();
}

详细完整的邮件类型,可以访问品茗IT-博客《SpringBoot入门建站全系列(十)邮件发送功能》进行查看

快速构建项目

Spring组件化构建

SpringBoot组件化构建

SpringCloud服务化构建

喜欢这篇文章么,喜欢就加入我们的Java学习圈(点击加入或下方扫码)一起讨论SpringBoot技术吧!

品茗IT交流群

你可能感兴趣的:(SpringBoot入门建站全系列(十)邮件发送功能)