美文网首页SpringBoot专题
SpringBoot入门建站全系列(十)邮件发送功能

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

作者: 逍遥天扬 | 来源:发表于2019-06-19 12:26 被阅读22次

    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

    一、配置

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

    1.1 Maven依赖

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

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

    1.2 配置文件

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

    spring.mail.host=smtp.qq.com
    spring.mail.username=916881512@qq.com
    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 
    
    mail.from=916881512@qq.com
    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)}
         * <p>占位符使用{},内容中如果要使用{},就修改代码吧,这里不支持。
         * @param content
         *            带占位符正文
         * @param mailTypes
         *            可变参数,填充占位符
         * @throws Exception 
         */
        public void sendCompleteHtml(String content, List<MailType> 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<MailType> mailTypes) throws MessagingException, IOException {
            String bodyPrefix = "<html><body>";
            String bodySuffix = "</body></html>";
            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("<img src=\'cid:" + inlineFile.getCid() + "\' />");
                    }
                    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("<table border=\"1\" style=\"border-collapse:collapse;font-size:14px\">\n");
                sb.append("<caption align = \"left\">");
                sb.append(jsonTable.getTitle());
                sb.append("</caption>\n");
                JSONObject jsonFirst = (JSONObject) ja.get(0);
                sb.append("<tr>\n");
                for (String key : jsonFirst.keySet()) {
                    sb.append("<td>");
                    sb.append(jsonFirst.get(key));
                    sb.append("</td>\n");
                }
    
                sb.append("</tr>\n");
                ja.remove(0);
                for (Object column : ja) {
                    sb.append("<tr>\n");
                    JSONObject json = (JSONObject) column;
                    for (String key : jsonFirst.keySet()) {
                        sb.append("<td>");
                        sb.append(json.get(key));
                        sb.append("</td>\n");
                    }
    
                    sb.append("</tr>\n");
                }
    
                sb.append("</table>\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<String> to;
        private List<String> 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<String> to = new ArrayList<String>();
            private List<String> cc = new ArrayList<String>();
            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<String> toAddr) {
                to.addAll(toAddr);
                return this;
            }
    
            /**
             * 设置收件人列表
             * @param to 收件人数组
             * @return
             */
            public Builder to(List<String> 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<String> ccAddr) {
                cc.addAll(ccAddr);
                return this;
            }
    
            /**
             * 设置抄送人列表
             * @param cc
             * @return
             */
            public Builder cc(List<String> 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服务化构建

    喜欢这篇文章么,喜欢就加入我们一起讨论SpringBoot技术吧!


    品茗IT交流群

    相关文章

      网友评论

        本文标题:SpringBoot入门建站全系列(十)邮件发送功能

        本文链接:https://www.haomeiwen.com/subject/pewhqctx.html