Bootstrap

spring boot发送邮箱,java实现邮箱发送(邮件带附件)3中方式【保姆级教程一,代码直接用】


实际开发时需要实现邮件发送,本文章实现如何从零实现邮件发送。也就是 Spring Boot 项目中如何实现邮箱发送。

Java发送邮箱的方式

1、前提:需要获取发件人邮箱的授权码,也就是打开POP3/IMAP/SMTP服务设置,拿到授权码。

2、获取到邮件服务器的 smtp 地址:

服务商smtp服务地址smtp服务端口pop3服务地址pop3服务端口
新浪: sina.comsmtp.sina.com.cn25pop3.sina.com.cn110
搜狐:sohu.comsmtp.sohu.com25pop3.sohu.com110
163:163.comsmtp.163.com25smtp.163.com110
QQ:qq.comsmtp.qq.com25 或 465 或 587smtp.qq.com110
foxmail:foxmail.comsmtp.foxmail.com25pop3.foxmail.com110
QQ企业邮箱:exmail.qq.comsmtp.exmail.qq.com995pop3.exmail.qq.com587/465
1. 基于 Javax.mail 实现

先引入依赖:

<dependency>
    <groupId>javax.mail</groupId>
    <artifactId>mail</artifactId>
    <version>1.4.7</version>
</dependency>

大致的流程:

1、创建配置项变量 Properties 对象,用于声明 smtp 相关配置;

2、创建一个Session,重写一个Authenticator,用于声明发件人邮箱地址和授权码;

3、利用 session 创建一个 MimeMessage 对象,再利用 MimeMessage 创建一个 MimeMessageHelper 对象,该对象用于设置收件人、发件人、抄送、秘密抄送、主题、内容、附件、发送时间等属性;

4、利用 Transport.send 方法发送邮件。

代码示例:

@Slf4j
public class EmailJavax {
    
    // 也可以从配置文件中取值
    // smtp服务地址
    private static final String senderSmtpHost = "smtp.qq.com";
    // 邮箱端口号
    private static final String senderSmtpPort = "465";
    // 发信人邮箱
    private static final String senderEmail = "[email protected]";
    // 发信人邮箱授权码
    private static final String senderPassword = "xxx";

    /**
     * 邮件发送
     *
     * @param subject              邮件主题
     * @param content              邮件内容
     * @param contentIsHtml        内容是否为html格式
     * @param fromMailPersonalName 发件人昵称
     * @param toMail               收件人邮箱
     * @param ccMail               抄送人邮箱
     * @param bccMail              秘密抄送人邮箱
     * @param fileNames            文件名(本地路径)
     */
    public static void sendEmail(String subject, String content, boolean contentIsHtml, String fromMailPersonalName, String toMail, String ccMail, String bccMail, List<String> fileNames) throws GeneralSecurityException, UnsupportedEncodingException, MessagingException {
        
        // 1.创建配置项变量,用于声明 smtp 相关配置
        Properties properties = System.getProperties();
        // smtp服务地址
        properties.put("mail.smtp.host", senderSmtpHost);
        // smtp服务端口
        properties.put("mail.smtp.port", senderSmtpPort);
        // 开启验证
        properties.put("mail.smtp.auth", "true");
        // 开启TLS加密
        properties.put("mail.smtp.starttls.enable", "true");
        // 是否启用socketFactory,默认为true
        properties.put("mail.smtp.socketFactory.fallback", "true");
        MailSSLSocketFactory sf = new MailSSLSocketFactory();
        sf.setTrustAllHosts(true);
        properties.put("mail.smtp.ssl.enable", "true");
        properties.put("mail.smtp.ssl.socketFactory", sf);
        
        // 2.重写Authenticator,用于声明发件人邮箱地址和授权码
        // 建立会话,将邮箱授权码给jvm
        Session session = Session.getDefaultInstance(properties, new Authenticator() {
            @Override
            protected PasswordAuthentication getPasswordAuthentication() {
                return new PasswordAuthentication(senderEmail, senderPassword);
            }
        });
        // 设置为true可以在控制台打印发送过程,生产环境关闭
        session.setDebug(true);
        
        // 3.创建MimeMessage对象
        // 创建邮件对象
        MimeMessage message = new MimeMessage(session);
        // 创建MimeMessageHelper对象,通过MimeMessageHelper设置正文和附件,否则会导致两者显示不全
        MimeMessageHelper helper = new MimeMessageHelper(message, true, "utf-8");
        //设置发件人
        helper.setFrom(new InternetAddress(senderEmail, fromMailPersonalName));
        
        // 设置收件人,to为收件人,cc为抄送,bcc为密送
        if (StringUtils.isEmpty(toMail)) {
            log.error("邮件收件人为空");
            return;
        }
        helper.setTo(InternetAddress.parse(toMail, false));
        
        if (!StringUtils.isEmpty(ccMail)) {
            helper.setCc(InternetAddress.parse(ccMail, false));
        }
        if (!StringUtils.isEmpty(bccMail)) {
            helper.setBcc(InternetAddress.parse(bccMail, false));
        }
        // 设置邮件主题
        helper.setSubject(subject);
        //设置邮件正文内容
        helper.setText(content, contentIsHtml);
        //设置发送的日期
        helper.setSentDate(new Date());
        // 设置附件(注意这里的fileName必须是服务器本地文件名,不能是远程文件链接)
        if (!CollectionUtils.isEmpty(fileNames)) {
            for (String fileName : fileNames) {
                FileDataSource fileDataSource = new FileDataSource(fileName);
                helper.addAttachment(fileDataSource.getName(), fileDataSource);
            }
        }
        // 4.调用Transport的send方法去发送邮件
        Transport.send(message);
    }
}
// 测试:
public class Test(){
    public static void main(String[] args) throws MessagingException, GeneralSecurityException, UnsupportedEncodingException {
        // excel表格的存放位置:
        String fileName = "/xx/xx/xx/供应商接口参数.xlsx";
        
        String html = "<h1>统计数据如下所示:</h1>" +
                "<table border=\"1\">\n" +
                "  <tr>\n" +
                "    <th>月度销售额</th>\n" +
                "    <th>年度销售额</th>\n" +
                "  </tr>\n" +
                "  <tr>\n" +
                "    <td>10000</td>\n" +
                "    <td>2000000</td>\n" +
                "  </tr>\n" +
                "</table>";
        // 调方法:
        EmailJavax.sendEmail("统计数据", html, true, "发送人名字", "收件人邮箱", null, null, Collections.singletonList(fileName));
    }
}
关于附件上传的方法

附件上传有多种方式,除了上面用到的 FileDataSource 形式添加附件外,还有 文件、输入流的方式添加:

  • addAttachment(String attachmentFilename, DataSource dataSource)
  • addAttachment(String attachmentFilename, File file)
  • addAttachment(String attachmentFilename, InputStreamSource inputStreamSource)
  • addAttachment(String attachmentFilename, InputStreamSource inputStreamSource, String contentType)
2. 基于 org.apache.commons.mail 实现

commons 包中提供了 Email 抽象类,该类下实现了

  • HtmlEmail(用于HTML正文,附件邮件发送)
  • ImageHtmlEmail(用于HTML图片正文,附件邮件发送)
  • MultiPartEmail(用于附件邮件发送)
  • SimpleEmail(用于简单邮件发送)

其继承关系如图所示:

1、引入依赖:

<dependency>
    <groupId>org.apache.commons</groupId>
    <artifactId>commons-email</artifactId>
    <version>1.5</version>
</dependency>

2、实现:

@Slf4j
public class EmailCommons {
    
    // 也可以从配置文件中取值
    // smtp服务地址
    private static final String senderSmtpHost = "smtp.qq.com";
    // 邮箱端口号
    private static final String senderSmtpPort = "465";
    // 发信人邮箱
    private static final String senderEmail = "[email protected]";
    // 发信人邮箱授权码
    private static final String senderPassword = "xxx";

    /**
     * 邮件发送
     *
     * @param subject              邮件主题
     * @param content              邮件内容
     * @param contentIsHtml        内容是否为html格式
     * @param fromMailPersonalName 发件人昵称
     * @param toMail               收件人邮箱
     * @param ccMail               抄送人邮箱
     * @param bccMail              秘密抄送人邮箱
     * @param fileList             附件            
     */
    public static void sendEmail(String subject, String content, boolean contentIsHtml, String fromMailPersonalName, String toMail, String ccMail, String bccMail, File[] fileList) throws GeneralSecurityException, UnsupportedEncodingException, MessagingException {
        
        // 1.创建HtmlEmail对象
        HtmlEmail email = new HtmlEmail();
        // smtp服务地址
        email.setHostName(senderSmtpHost);
        // smtp服务端口
        email.setSmtpPort("mail.smtp.port", senderSmtpPort);
        email.setCharset("utf-8");
       // 邮件验证
        email.setAuthentication(senderEmail,senderPassword);
        //设置发件人
        email.setFrom(senderEmail, fromMailPersonalName);
        
        // 设置收件人,to为收件人,cc为抄送,bcc为密送
        if (StringUtils.isEmpty(toMail)) {
            log.error("邮件收件人为空");
            return;
        }
        email.addTo(toMail);
        
        if (!StringUtils.isEmpty(ccMail)) {
            email.addCc(ccMail);
        }
        if (!StringUtils.isEmpty(bccMail)) {
            email.addBcc(bccMail);
        }
        // 设置邮件主题
        email.setSubject(subject);
        //设置邮件正文内容
        if(contentIsHtml){
            email.setHtmlMsg(content);
        }else{
            email.setMsg(content);
        }
        
        // 设置附件
		if(!ObjectUtils.isEmpty(fileList)){
            for (File file : fileList) {
                EmailAttachment emailAttachment = new EmailAttachment();
                emailAttachment.setName(MimeUtility.encodeText(file.getName()));
                emailAttachment.setPath(file.getPath());
                email.attach(emailAttachment);
            }
        }
        
        // 4.调用send方法去发送邮件
        email.send();
    }
}

3、测试:

public class Test(){
    public static void main(String[] args) throws MessagingException, GeneralSecurityException, UnsupportedEncodingException {
        // excel表格的存放位置:
        String fileName = "/xx/xx/xx/供应商接口参数.xlsx";
        File file = new File(fileName);
        
        String html = "<h1>统计数据如下所示:</h1>" +
                "<table border=\"1\">\n" +
                "  <tr>\n" +
                "    <th>月度销售额</th>\n" +
                "    <th>年度销售额</th>\n" +
                "  </tr>\n" +
                "  <tr>\n" +
                "    <td>10000</td>\n" +
                "    <td>2000000</td>\n" +
                "  </tr>\n" +
                "</table>";
        EmailCommons.sendEmail("统计数据", html, true, "发送人名字", "收件人邮箱", null, null,new File[]{file} );
    }
}
常见报错

1、535 Login Fail. Please enter your authorization code to login

原因:邮箱验证设置的账号密码错误

解决:注意参数值正确性:email.setAuthentication(发件人邮箱地址,邮箱授权码);

2、MessagingException: Got bad greeting from SMTP host: smtp.qq.com, port: 465, response: [EOF]

解决:commons.mail 发送邮件时,QQ 邮箱使用默认端口 25 即可

3. 基于 spring-boot-starter-mail 实现(推荐)

1、引入依赖:

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

2、使用配置文件:

spring:
  # 配置发送邮件的配置信息
  mail:
    # 配置smtp服务主机地址
    host: smtp.qq.com
    # 发送者邮箱
    username: [email protected]
    # 配置密码,注意不是真正的密码,而是申请到的授权码
    password: jlpXXXXXdecj
    # 端口号:465或587
    port: 465
    # 默认的邮件编码为UTF-8
    default-encoding: UTF-8
    # 其他参数
    properties:
      mail:
        # 配置SSL 加密工厂
        smtp:
          ssl:
            # 本地测试,先放开ssl
            enable: true
            required: true
          # 开启debug模式,这样邮件发送过程的日志会在控制台打印出来,方便排查错误
        debug: true

3、实现:

/**
 * 发送邮件类
 */
public class SendEmailUtil {

    // 注入系统相关类
    @Autowired
    private JavaMailSender javaMailSender;
    @Autowired
    private MailProperties mailProperties;

    // 发送者邮箱
//    @Value("${spring.mail.username}")
//    private String sendMailer;

    /**
     * 邮件发送1
     *
     * @param subject              邮件主题
     * @param content              邮件内容
     * @param contentIsHtml        内容是否为html格式
     * @param fromMailPersonalName 发件人昵称
     * @param toMail               收件人邮箱
     * @param ccMail               抄送人邮箱
     * @param bccMail              秘密抄送人邮箱
     * @param fileNames            文件名(本地文件名)
     */
    public static void sendEmail(String subject, String content, boolean contentIsHtml, String fromMailPersonalName,
                          String toMail, String ccMail, String bccMail, List<String> fileNames) throws MessagingException, UnsupportedEncodingException {
        // true 代表支持复杂的类型
        MimeMessage mimeMessage = javaMailSender.createMimeMessage();
        MimeMessageHelper helper = new MimeMessageHelper(mimeMessage, true);
        /* 邮件发信人:两种写法:
        1. 定义成员变量获取application.yml的username属性
            @Value("${spring.mail.username}")
            private String sendMailer;
            helper.setFrom(sendMailer,发件人名称)
        2. 注入系统类的对象,然后调方法获取,获取的值也是application.yml文件中的值
            @Autowired
            private MailProperties mailProperties;
            helper.setFrom(mailProperties.getUsername(),发件人名称);
        */
        helper.setFrom(mailProperties.getUsername(), fromMailPersonalName);
        // 邮件收信人  1或多个
        helper.setTo(toMail);
        if (!ObjectUtils.isEmpty(ccMail)) {
            // 邮件抄送人
            helper.setCc(ccMail);
        }
        if (!ObjectUtils.isEmpty(bccMail)) {
            // 邮件私密抄送人
            helper.setBcc(bccMail);
        }
        // 邮件主题
        helper.setSubject(subject);
        // 邮件内容   contentIsHtml值为 true 代表支持html
        helper.setText(content, contentIsHtml);

        // 设置附件(注意这里的fileName必须是服务器本地文件名,不能是远程文件链接)
        if (!CollectionUtils.isEmpty(fileNames)) {
            for (String fileName : fileNames) {
                // 添加邮件附件
                FileDataSource fileDataSource = new FileDataSource(fileName);
                helper.addAttachment(fileDataSource.getName(), fileDataSource);
            }
        }
        // 发送邮件
        javaMailSender.send(mimeMessage);
    }

    /**
     * 邮件发送2 -- 方法优化 -- 文件对象
     *
     * @param subject              邮件主题
     * @param content              邮件内容
     * @param contentIsHtml        内容是否为html格式
     * @param fromMailPersonalName 发件人昵称
     * @param toMail               收件人邮箱
     * @param ccMail               抄送人邮箱
     * @param bccMail              秘密抄送人邮箱
     * @param files                文件对象
     */
    public static void sendEmail(String subject, String content, boolean contentIsHtml, String fromMailPersonalName,
                          String toMail, String ccMail, String bccMail, File[] files) throws MessagingException, UnsupportedEncodingException {
        MimeMessage message = javaMailSender.createMimeMessage();
        MimeMessageHelper helper = new MimeMessageHelper(message, true);
        helper.setFrom(mailProperties.getUsername(), fromMailPersonalName);
        helper.setTo(toMail);
        if (!ObjectUtils.isEmpty(ccMail)) {
            helper.setCc(ccMail);
        }
        if (!ObjectUtils.isEmpty(bccMail)) {
            helper.setBcc(bccMail);
        }
        helper.setSubject(subject);
        helper.setText(content, contentIsHtml);
        // 设置附件,不能是远程文件
        if (!ObjectUtils.isEmpty(files)) {
            for (File file : files) {
                helper.addAttachment(file.getName(), file);
            }
        }
        javaMailSender.send(message);
    }


    /**
     * 邮件发送3 -- 方法优化 -- 使用流
     *
     * @param subject              邮件主题
     * @param content              邮件内容
     * @param contentIsHtml        内容是否为html格式
     * @param fromMailPersonalName 发件人昵称
     * @param toMail               收件人邮箱
     * @param ccMail               抄送人邮箱
     * @param bccMail              秘密抄送人邮箱
     * @param fileName             文件名称
     * @param fileInput            文件流
     */
    public static void sendEmail(String subject, String content, boolean contentIsHtml, String fromMailPersonalName,
                          String toMail, String ccMail, String bccMail, String fileName, InputStreamSource fileInput) throws MessagingException, UnsupportedEncodingException {
        MimeMessage message = javaMailSender.createMimeMessage();
        MimeMessageHelper helper = new MimeMessageHelper(message, true);
        helper.setFrom(mailProperties.getUsername(), fromMailPersonalName);
        helper.setTo(toMail);
        if (!ObjectUtils.isEmpty(ccMail)) {
            helper.setCc(ccMail);
        }
        if (!ObjectUtils.isEmpty(bccMail)) {
            helper.setBcc(bccMail);
        }
        helper.setSubject(subject);
        helper.setText(content, contentIsHtml);
        // 设置附件,不能是远程文件
        if (fileInput != null) {
            helper.addAttachment(fileName, fileInput);
        }
        javaMailSender.send(message);

    }
}

关于邮件发送的方法参数: 上面几个方法,最后接收附件的参数都不一样,说明可以灵活变化

  • sendEmail(xxx, List<String> fileNames):可以接收多个附件,其中传的时候,就是附件的绝对路径
  • sendEmail(xxx, File[] files):可以接收多个附件,传的时候,就是附件的文件对象
  • sendEmail(xxx, InputStreamSource fileInput):接收一个附件,传的时候,就是附件的流

5、测试:

/**
 * excel表格生成工具
 */
public class ExcelUtil {

    /**
     * 生成excel文件
     *
     * @param fileName excel文件路径
     * @param dataList 数据列表
     * @param clazz    导出对象类
     * @param <T>
     * @return
     */
    public static <T> File generateExcel(String fileName, List<T> dataList, Class<T> clazz) {
        // 生成文件
        File file = new File(fileName);
        // 单sheet写入
        EasyExcel.write(file, clazz).sheet("XXX").doWrite(dataList);
        return file;
    }

    /**
     * 生成excel文件 -- 方法优化 -- 用流
     *
     * @param dataList 数据列表
     * @param clazz 导出对象类
     * @param <T>
     * @return
     */
    public static <T> ByteArrayOutputStream generateExcel(List<T> dataList, Class<T> clazz) {
        ByteArrayOutputStream out = new ByteArrayOutputStream();
        // 单excel写入
        EasyExcel.write(out, clazz).sheet("XXX").doWrite(dataList);
        return out;
    }
    
}
public class Test(){
    public static void main(String[] args) throws MessagingException, GeneralSecurityException, UnsupportedEncodingException {
        
        String content = "客户统计数据如附件所示";
       
        // 测试邮件发送1
        // excel表格的存放位置:
        String fileName = "/xx/xx/xx/供应商接口参数.xlsx";
        String html = "<h1>统计数据如下所示:</h1>" +
                "<table border=\"1\">\n" +
                "  <tr>\n" +
                "    <th>月度销售额</th>\n" +
                "    <th>年度销售额</th>\n" +
                "  </tr>\n" +
                "  <tr>\n" +
                "    <td>10000</td>\n" +
                "    <td>2000000</td>\n" +
                "  </tr>\n" +
                "</table>";
        SendEmailUtil.sendEmail("统计数据", html, true, "发送人名字", "收件人邮箱", null, null, Arrays.asList(fileName));
        
        // 测试邮件发送2
        File excel = ExcelUtil.generateExcel("文件名", 表格映射的实体类对象, 表格映射的实体类.class);
        SendEmailUtil.sendEmail("统计数据", content, false, "发送人名字", "收件人邮箱", null, null, new File[]{excel});
        
       	// 测试邮件发送3
        ByteArrayOutputStream bos = ExcelUtil.generateExcel(userInfos, UserInfo.class);
        SendEmailUtil.sendEmail("统计数据", content, false, "发送人名字", "收件人邮箱", null, null, fileName, new ByteArrayResource(bos.toByteArray()));
    }
}

注意: 实现 excel 生成,然后发送邮箱 的代码,可以查看这篇文章:生成 excel 并发送邮箱

至此!文章的内容结束!!记得关注收藏,有更多精彩内容!!!

;