java发送邮件SSL和非SSL

java发送邮件SSL和非SSL

注意:hutool工具包对邮件发送封装的非常简单了,但是他使用的是非SSL的形式发送。非SSL发送邮箱使用的25端口,但是这个端口开放是非常危险的,阿里云和腾讯云默认是关闭的。如果需要开启需要申请,最终能不能开启还是一个未知数。当然,如果你在本地测试是没有问题的,如果你的是本地服务器,那么可以不用考虑这个问题。如果是云服务器,那么自己封装邮件。详细参考第三节。

hutool发送邮件详细参考官方文档:https://www.hutool.cn/docs/#/extra/邮件工具-MailUtil

一、邮箱设置

1.1、163邮箱获取授权码

163邮箱官网:https://mail.163.com/

最主要的是要获取到授权码。

在这里插入图片描述

在这里插入图片描述

在这里插入图片描述

在这里插入图片描述

将手机扫描这个二维码,会显示一个数字和一个号码。使用注册邮箱的这个手机号发送这个数字到指定的这个号码中,点击这个我已发送。

在这里插入图片描述

在这里插入图片描述

在这里插入图片描述

这样就设置完了,如果授权码丢失了,或者是授权密码管理这里删除了,就从新在上面开启,重新获取授权码即可。

1.2、新浪邮箱获取授权码

登录地址:https://m0.mail.sina.com.cn/

在这里插入图片描述

在这里插入图片描述

点击授权码状态,点击开启会有一个手机号认证,认证通过就可以拿到授权码了。这个授权码只显示一次,如果忘记就只能重新获取。

二、码上说话

2.1、引入依赖

<!-- hutool工具包 -->
<dependency>
    <groupId>cn.hutool</groupId>
    <artifactId>hutool-all</artifactId>
    <version>5.1.4</version>
</dependency>
<!-- 邮箱工具 -->
<dependency>
    <groupId>javax.mail</groupId>
    <artifactId>mail</artifactId>
    <version>1.4.7</version>
</dependency>

如果是springboot应用,那么mail依赖可以更换为一下。

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

2.2、hutool发送简单邮件(非SSL)

  1. 发送普通文本邮件,最后一个参数可选是否添加多个附件:
MailUtil.send("hutool@foxmail.com", "测试", "邮件来自Hutool测试", false);
  1. 发送HTML格式的邮件并附带附件,最后一个参数可选是否添加多个附件:
MailUtil.send("hutool@foxmail.com", "测试", "<h1>邮件来自Hutool测试</h1>", true, FileUtil.file("d:/aaa.xml"));
  1. 群发邮件,可选HTML或普通文本,可选多个附件:
ArrayList<String> tos = CollUtil.newArrayList(
    "person1@bbb.com", 
    "person2@bbb.com", 
    "person3@bbb.com", 
    "person4@bbb.com");

MailUtil.send(tos, "测试", "邮件来自Hutool群发测试", false);

发送邮件非常简单,只需一个方法即可搞定其中按照参数顺序说明如下:

  1. tos: 对方的邮箱地址,可以是单个,也可以是多个(Collection表示)
  2. subject:标题
  3. content:邮件正文,可以是文本,也可以是HTML内容
  4. isHtml: 是否为HTML,如果是,那参数3识别为HTML内容
  5. files: 可选:附件,可以为多个或没有,将File对象加在最后一个可变参数中即可
  • 范例
 @Test
public void sendMail(){
    MailAccount account = new MailAccount();
    // 邮箱服务地址
    account.setHost("smtp.163.com");
    // 端口,针对不同服务器的端口不同
    account.setPort(25);
    // 设置是否需要用户名密码验证
    account.setAuth(true);
    // 设置为发送方,就是刚才开启授权的这个邮箱
    account.setFrom("guizhouhuibox@163.com");
    // 设置用户名,这个用户名必须是发送方的这个邮箱
    account.setUser("guizhouhuibox@163.com");
    // 授权码,既是刚才获取的那个授权码
    account.setPass("XLHBTOHQRTEXNNLE");
    // 群发
    //        MailUtil.send(account, CollUtil.newArrayList("2115g@sina.com","wm76868@sina.com"), "邮箱标题", "这是邮箱的内容区", false);
    // 单发
    //        MailUtil.send(account,"2115g@sina.com", "测试", "邮件来自Hutool测试", false);
    // 最后一个参数true:表示将内容区识别为HTML代码,但是标题不能识别
    MailUtil.send(account,"2115g@sina.com", "测试", "邮件来自Hutool测试<a href='http://www.dockone.io/article/10139'>redis延迟队列</a>", true);
}

邮箱的服务器地址在邮箱设置这里可以看到。

在这里插入图片描述

对应端口如下

在这里插入图片描述

详细信息参考:http://help.mail.163.com/faqDetail.do?code=d7a5dc8471cd0c0e8b4b8f4f8e49998b374173cfe9171305fa1ce630d7f67ac2cda80145a1742516

2.3、自己封装SSL形式

注意:这种新式端口号为 465,而上面的非SSL端口号是25,就是因为25端口号的特殊性,所以才选择SSL发送的。

实体类封装

package com.centre.common.model;

import lombok.Getter;
import lombok.Setter;

/**
 * 发送邮箱实体类
 * @Author: Stars
 * @Date: 2021/1/10 19:00
 */
@Getter
@Setter
public class MailAccounts {

    /**
     * 邮箱地址,就是邮箱服务器的地址,在获取授权码那个页面可以获取到
     */
    private String host = "smtp.163.com" ;

    /**
     * 端口号,SSL模式
     */
    private Integer port = 465 ;

    /***
     * 设置是否需要用户名密码验证,一般为true
     */
    private Boolean auth = true;

    /***
     * 发送方地址,获取授权码的邮箱
     */
    private String from = "XXX@163.com" ;

    /**
     * 设置用户名,这个用户名必须是发送方的这个邮箱
     */
    private String user = "XXX@163.com" ;

    /***
     * 授权码,既是刚才获取的那个授权码
     */
    private String pass = "XXXXXXX" ;
    /**
     * 发送地址
     */
    private String toAddress ;
    /**
     * 发送主题
     */
    private String subject ;
    /**
     * 发送内容
     */
    private String content ;

    /**
     * 是否为HTML格式,true:是,false:不是
     */
    private Boolean isHtml = false ;

    /**
     * 发送者名称
     */
    private String personal = "XXXX";

    /**
     * 对象邮箱
     */
    private String[] to ;

    /**
     * 附件路径信息集合
     */
    private String[] fileUploadNames = null ;

    public void setTo(String ... to){
        this.to = to;
    }
    public void setFileUploadNames(String ... fileUploadNames){
        this.fileUploadNames = fileUploadNames ;
    }
}

除了 fileUploadNames附件地址和 toAddress发送地址(不用,可以删除)以外,其他字段都是需要的,但是有很多我已经设置了默认值了。

发送邮件工具

package com.centre.common.utils;

import com.centre.common.exception.BusinessException;
import com.centre.common.model.MailAccounts;

import javax.activation.DataHandler;
import javax.activation.FileDataSource;
import javax.mail.*;
import javax.mail.internet.*;
import java.io.UnsupportedEncodingException;
import java.util.Date;
import java.util.Properties;

/**
 * @Author: Stars
 * @Date: 2021/1/10 18:41
 */
public class MailSendUtils {

    /**
     * 邮箱发送
     * @param mailAccounts
     * @throws Exception
     */
    public void send(MailAccounts mailAccounts)throws Exception{
        Message message = getMessage(mailAccounts);
        // MiniMultipart类是一个容器类,包含MimeBodyPart类型的对象
        Multipart multipart = new MimeMultipart();
        // 创建一个包含HTML内容的MimeBodyPart
        BodyPart htmlOrTest = new MimeBodyPart();
        if (mailAccounts.getIsHtml()) {
            // 设置HTML内容
            htmlOrTest.setContent(mailAccounts.getContent(), "text/html; charset=utf-8");
        }else {
            htmlOrTest.setText(mailAccounts.getContent());
        }
        // 添加发送内容
        multipart.addBodyPart(htmlOrTest);
        if (mailAccounts.getFileUploadNames() != null){
            // 添加附件
            for (String fileName : mailAccounts.getFileUploadNames()) {
                addEnclosure(multipart,fileName);
            }
        }
        // 将MiniMultipart对象设置为邮件内容
        message.setContent(multipart);
        Transport.send(message);
    }

    /**
     * 添加附件
     * @param multipart
     * @param fileName 附件所在的地址
     * @throws Exception
     */
    private void addEnclosure(Multipart multipart,String fileName) throws Exception{
            BodyPart adjunct = new MimeBodyPart();
            FileDataSource fileDataSource = new FileDataSource(fileName);
            adjunct.setDataHandler(new DataHandler(fileDataSource));
            adjunct.setFileName(changeEncode(fileDataSource.getName()));
            multipart.addBodyPart(adjunct);
    }
    /**
     * 进行base64加密,防止中文乱码
     * */
    public String changeEncode(String str) {
        try {
            str = MimeUtility.encodeText(new String(str.getBytes(), "UTF-8"),
                    "UTF-8", "B"); // "B"代表Base64
        } catch (UnsupportedEncodingException e) {
            e.printStackTrace();
        }
        return str;
    }

    private Message getMessage(MailAccounts mailAccounts) throws Exception{
        Properties properties = System.getProperties() ;
        properties.setProperty("mail.smtp.host", mailAccounts.getHost());
        properties.setProperty("mail.smtp.auth", mailAccounts.getAuth().toString());
        properties.setProperty("mail.smtp.user", mailAccounts.getFrom());
        properties.setProperty("mail.smtp.pass", mailAccounts.getPass());
        properties.put("mail.smtp.socketFactory.class", "javax.net.ssl.SSLSocketFactory");  //使用JSSE的SSL socketfactory来取代默认的socketfactory
        properties.put("mail.smtp.socketFactory.fallback", "false");  // 只处理SSL的连接,对于非SSL的连接不做处理
        properties.put("mail.smtp.port", mailAccounts.getPort());
        properties.put("mail.smtp.socketFactory.port", mailAccounts.getPort());

        // 根据邮件会话属性和密码验证器构造一个发送邮件的session
        Session session = Session.getInstance(properties, new Authenticator(){
            protected PasswordAuthentication getPasswordAuthentication() {
                return new PasswordAuthentication(properties.getProperty("mail.smtp.user"),properties.getProperty("mail.smtp.pass"));
            }
        });
        session.setDebug(true);
        Message message = new MimeMessage(session);
        //消息发送的主题
        message.setSubject(mailAccounts.getSubject());
        //消息的发送者
        message.setFrom(new InternetAddress(properties.getProperty("mail.smtp.user"),mailAccounts.getPersonal()));
        if (mailAccounts.getTo().length <= 0){
            throw new BusinessException("收件人不能为空!!");
        }
        for (String strAdd : mailAccounts.getTo()) {
            // 创建邮件的接收者地址,并设置到邮件消息中
            message.setRecipient(Message.RecipientType.TO,new InternetAddress(strAdd));
        }
        // 消息发送的时间
        message.setSentDate(new Date());
        return message ;
    }
}

测试

public static void main(String[] args) {
    MailAccounts mailAccounts = new MailAccounts();
    mailAccounts.setTo("2115g@sina.com");
    mailAccounts.setSubject("这是发送主题");
    mailAccounts.setContent("<u>这是发送内容</u>");
    mailAccounts.setIsHtml(true);
    mailAccounts.setFileUploadNames("D:\\我靠.txt","D:\\admin.txt");
    try {
        new MailSendUtils().send(mailAccounts);
    }catch (Exception e){
        e.printStackTrace();
    }
}

这样就可以了,我个人推荐使用SSL的形式发送邮件,虽然工具封装的稍微有点复杂。但是可以直接copy我写好的去使用就行了,几乎可以满足要求了。

评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值