Java springboot 通过javax.mail 实现通用邮件全内容发送

1. 开发前准备

为了能够通过邮箱发送邮件,我们需要发送者邮箱去开启POP3/SMTP服务,如下图所示。

然后我们需要,去新增一个授权码,如下图所示:此时会得到一串密钥,这串密钥就是后续发送邮件所采用的密码了。

这里我们介绍一下SMTP/IMAP/POP协议的区别,这三种协议可以分为两类:SMTP是一类;POP3和IMAP是一类。
简单理解:SMTP用于服务器之间的相互通信或者客户端往服务器发送邮件;POP3和IMAP用于客户端从服务器拉取邮件。POP3跟IMAP的区别:前者很古老,功能也没有后者强大

例如:张三的邮件地址是 zhangsan@outlook.com ,李四的邮件地址是 lisi@163.com ;张三想给李四发邮件。
第一步:张三用他的邮件客户端把邮件推送到 outlook 的邮件服务器上,这里用的是SMPT协议;
第二步:outlook邮件服务器将张三的邮件转发到163的邮件服务器上,这里用的是SMTP协议
第三步:李四用他的邮件客户端从163的邮件服务器上把邮件拉取下来,这里用的是POP3或者IMAP协议。

2. 引入maven依赖

        <!-- https://mvnrepository.com/artifact/javax.mail/javax.mail-api -->
        <dependency>
            <groupId>javax.mail</groupId>
            <artifactId>javax.mail-api</artifactId>
            <version>1.6.2</version>
        </dependency>
        

        <dependency>
            <groupId>cn.hutool</groupId>
            <artifactId>hutool-all</artifactId>
            <version>5.8.18</version>
        </dependency>

        <dependency>
            <groupId>org.projectlombok</groupId>
            <artifactId>lombok</artifactId>
            <version>1.18.30</version>
        </dependency>

3. 开发邮件通用功能

3.1 定义枚举实现接口



/**
 * @author shawn
 * @date 2024年 03月 29日 16:40 16:40:44
 */
public interface MailType {
    String getMailHost();

    String getMailPort();

    String getDescription();

    String getProtocol();
}

3.2 定义常见邮箱枚举信息

3.2.1 SMTP协议枚举信息

public enum SMTP implements MailType{
        NETEASE_YEAH_SMTP("smtp.yeah.net","25","网易yeah邮箱SMTP服务器地址"),
        NETEASE_163_SMTP("smtp.163.com","25","网易163邮箱SMTP服务器地址"),
        NETEASE_126_SMTP("smtp.126.com", "25", "网易126邮箱SMTP服务器地址"),
        CMCC_139_SMTP("SMTP.139.com", "25", "移动139邮箱SMTP服务器地址"),
        TENCENT_QQ_SMTP("smtp.qq.com", "25", "腾讯QQ邮箱SMTP服务器地址"),
        TENCENT_QQ_ENTERPRISE_SMTP("smtp.exmail.qq.com", "465", "腾讯QQ企业邮箱SMTP服务器地址(SSL启用)"),
        GOOGLE_GMAIL_SMTP("smtp.gmail.com", "587", "谷歌Gmail邮箱SMTP服务器地址(SSL启用)"),
        TENCENT_FOXMAIL_SMTP("SMTP.foxmail.com", "25", "腾讯Foxmail邮箱SMTP服务器地址"),
        SINA_SMTP("smtp.sina.com.cn", "25", "新浪sina邮箱SMTP服务器地址"),
        SINA_VIP_SMTP("smtp.vip.sina.com", "25", "新浪sinaVIP邮箱SMTP服务器地址"),
        SOHU_SMTP("smtp.sohu.com", "25", "搜狐sohu邮箱SMTP服务器地址"),
        YAHOO_SMTP("smtp.mail.yahoo.com", "587", "雅虎yahoo邮箱SMTP服务器地址(SSL启用)"),
        YAHOO_CN_SMTP("smtp.mail.yahoo.com.cn", "587", "雅虎yahoo.com.cn邮箱SMTP服务器地址(SSL启用)"),
        MICROSOFT_HOTMAIL_POP3("pop3.live.com", "995", "微软HotMail邮箱POP3服务器地址(SSL启用)"),
        MICROSOFT_HOTMAIL_SMTP("smtp.live.com", "587", "微软HotMail邮箱SMTP服务器地址(SSL启用)"),
        NET263_SMTP("smtp.263.net", "25", "263.net邮箱SMTP服务器地址"),
        NET263_NET_CN_SMTP("smtp.263.net.cn", "25", "263.net.cn邮箱SMTP服务器地址"),
        X263_NET_SMTP("smtp.x263.net", "25", "x263.net邮箱SMTP服务器地址"),
        CN21_SMTP("smtp.21cn.com", "25", "21cn.com邮箱SMTP服务器地址"),
        CHINA_COM_SMTP("smtp.china.com", "25", "china.com邮箱SMTP服务器地址"),
        TOM_COM_SMTP("smtp.tom.com", "25", "tom.com邮箱SMTP服务器地址");

        private final String mailHost;
        private final String mailPort;
        private final String description;

        private final static String PROTOCOL = "SMTP";
        SMTP(String mailHost, String mailPort, String description) {
            this.mailHost = mailHost;
            this.mailPort = mailPort;
            this.description = description;
        }

        public String getMailHost() {
            return mailHost;
        }

        public String getMailPort() {
            return mailPort;
        }

        public String getDescription() {
            return description;
        }

        @Override
        public String getProtocol() {
                return PROTOCOL;
        }
}

3.2.2 POP3协议信息



public enum POP3 implements MailType{
        NETEASE_YEAH_POP3("pop.yeah.net","110","网易yeah邮箱POP3服务器地址"),
        NETEASE_163_POP3("pop.163.com","110","网易163邮箱POP3服务器地址"),
        NETEASE_126_POP3("pop.126.com", "110", "网易126邮箱POP3服务器地址"),
        CMCC_139_POP3("POP.139.com", "110", "移动139邮箱POP3服务器地址"),
        TENCENT_QQ_POP3("pop.qq.com", "110", "腾讯QQ邮箱POP3服务器地址"),
        TENCENT_QQ_ENTERPRISE_POP3("pop.exmail.qq.com", "995", "腾讯QQ企业邮箱POP3服务器地址(SSL启用)"),
        GOOGLE_GMAIL_POP3("pop.gmail.com", "995", "谷歌Gmail邮箱POP3服务器地址(SSL启用)"),
        TENCENT_FOXMAIL_POP3("POP.foxmail.com", "110", "腾讯Foxmail邮箱POP3服务器地址"),
        SINA_POP3("pop3.sina.com.cn", "110", "新浪sina邮箱POP3服务器地址"),
        SINA_VIP_POP3("pop3.vip.sina.com", "110", "新浪sinaVIP邮箱POP3服务器地址"),
        SOHU_POP3("pop3.sohu.com", "110", "搜狐sohu邮箱POP3服务器地址"),
        YAHOO_POP3("pop.mail.yahoo.com", "995", "雅虎yahoo邮箱POP3服务器地址(SSL启用)"),
        YAHOO_CN_POP3("pop.mail.yahoo.com.cn", "995", "雅虎yahoo.com.cn邮箱POP3服务器地址(SSL启用)"),
        MICROSOFT_HOTMAIL_POP3("pop3.live.com", "995", "微软HotMail邮箱POP3服务器地址(SSL启用)"),
        NET263_POP3("pop3.263.net", "110", "263.net邮箱POP3服务器地址"),
        NET263_NET_CN_POP3("pop.263.net.cn", "110", "263.net.cn邮箱POP3服务器地址"),
        X263_NET_POP3("pop.x263.net", "110", "x263.net邮箱POP3服务器地址"),
        CN21_POP3("pop.21cn.com", "110", "21cn.com邮箱POP3服务器地址"),
        CHINA_COM_POP3("pop.china.com", "110", "china.com邮箱POP3服务器地址"),
        TOM_COM_POP3("pop.tom.com", "110", "tom.com邮箱POP3服务器地址"),
        ETANG_COM_POP3("pop.etang.com", "110", "etang.com邮箱POP3服务器地址");

        private final String mailHost;
        private final String mailPort;
        private final String description;

        private final static String PROTOCOL = "POP";
        POP3(String mailHost, String mailPort, String description) {
            this.mailHost = mailHost;
            this.mailPort = mailPort;
            this.description = description;
        }

        public String getMailHost() {
            return mailHost;
        }

        public String getMailPort() {
            return mailPort;
        }

        public String getDescription() {
            return description;
        }

        @Override
        public String getProtocol() {
                return PROTOCOL;
        }
}

3.2.3 邮件发送实体类

import com.middlewares.tools.constant.MailType;
import lombok.Data;

import javax.validation.constraints.NotBlank;
import javax.validation.constraints.NotEmpty;
import javax.validation.constraints.NotNull;
import java.util.List;

/**
 * @author shawn
 * @date 2024年 03月 29日 16:57 16:57:01
 */
@Data
public class MailInfo {
    /**
     * 邮件服务商
     */
    @NotNull(message = "邮件服务商不能为空")
    private MailType mailType;
    /**
     * 邮件发送方
     */
    @NotBlank(message = "邮件发送方不能为空")
    private String username;
    /**
     * 邮件密钥
     */
    @NotBlank(message = "邮件密钥不能为空")
    private String secreteKey;

    /**
     * 邮件主题
     */
    private String subject;

    /**
     * 邮件纯文本内容
     */
    private String content;
    /**
     * 邮件富文本类容
     */
    private String htmlContent;
    /**
     * 邮件接收方
     */
    @NotEmpty(message = "邮件接收方不能为空")
    private List<String> receivers;
    /**
     * 邮件抄送方
     */
    private List<String> copyTos;
    /**
     * 邮件附件
     */
    private List<String> urls;

}

3.3 编写邮件发送工具类,支持多接收者、多抄送者、主题、文本、富文本、附件(url)发送

import cn.hutool.json.JSONUtil;
import com.middlewares.common.core.utils.StringUtils;
import com.middlewares.common.core.utils.file.FileUtils;
import com.middlewares.tools.constant.MailType;
import com.middlewares.tools.constant.SMTP;
import com.middlewares.tools.domain.MailInfo;
import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Component;
import org.springframework.validation.annotation.Validated;

import javax.activation.DataHandler;
import javax.mail.*;
import javax.mail.internet.*;
import java.net.MalformedURLException;
import java.net.URL;
import java.util.*;
import java.util.concurrent.ConcurrentHashMap;

/**
 * 邮箱工具类
 *
 * @author shawn
 * @date 2024年 03月 29日 16:17 16:17:27
 */
@Slf4j
@Component
public class MailUtil {


    private final ConcurrentHashMap<MailInfo, Session> sessionMap = new ConcurrentHashMap<>();

    private Session getSession(MailInfo mailInfo) {
        // First check (without locking)
        Session session = sessionMap.get(mailInfo);
        if (Objects.isNull(session)) {
            synchronized (this) {
                // Second check (with locking)
                session = sessionMap.get(mailInfo);
                if (Objects.isNull(session)) {
                    // Assume createSession() is a method that creates a new Session instance
                    session = createSession(mailInfo);
                    sessionMap.put(mailInfo, session);
                }
            }
        }
        return session;
    }

    // Dummy method for creating a session. You should implement this according to your needs.
    private Session createSession(MailInfo mailInfo) {
        // Implementation to create a new Session instance based on the mailType
        MailType mailType = mailInfo.getMailType();
        Properties props = new Properties();
        props.put("mail."+mailType.getProtocol().toLowerCase()+".auth", "true");//	是否需要用户认证
        props.put("mail."+mailType.getProtocol().toLowerCase()+".starttls.enale", "true");//	启用TlS加密
        props.put("mail."+mailType.getProtocol().toLowerCase()+".host", mailType.getMailHost());
        props.put("mail."+mailType.getProtocol().toLowerCase()+".port", mailType.getMailPort());
        return Session.getInstance(props, new Authenticator() {
            @Override
            protected PasswordAuthentication getPasswordAuthentication() {
                return new PasswordAuthentication(mailInfo.getUsername(), mailInfo.getSecreteKey());
            }
        });
    }


    /**
     * 邮件发送
     *
     * @param mailInfo
     * @return {@link String}
     */
    public boolean send(@Validated MailInfo mailInfo) {
        /* 1. 获取通讯session */
        Session session = getSession(mailInfo);
        session.setDebug(true); // 展示debug发送信息

        /* 2. 定义收发双方信息*/
        MimeMessage message = new MimeMessage(session);
        try {
            /* 2.1 发送方*/
            message.setFrom(new InternetAddress(mailInfo.getUsername()));
            /* 2.2 定义接收方/抄送方*/
            List<String> adds = mailInfo.getReceivers();
            Address[] mailAddress = new Address[adds.size()];
            for (int i = 0; i < adds.size(); i++) {
                InternetAddress address = new InternetAddress(adds.get(i));
                mailAddress[i] = address;
            }
            message.setRecipients(Message.RecipientType.TO, mailAddress);

            if (StringUtils.isNotEmpty(mailInfo.getCopyTos())) {

                List<String> cs = mailInfo.getCopyTos();
                Address[] csAddress = new Address[cs.size()];
                for (int i = 0; i < cs.size(); i++) {
                    InternetAddress address = new InternetAddress(cs.get(i));
                    csAddress[i] = address;
                }
                message.setRecipients(Message.RecipientType.CC, csAddress);
            }
            /* 3 设定发送内容*/
            /* 3.1 主题*/
            if (StringUtils.isNotEmpty(mailInfo.getSubject())) {
                message.setSubject(mailInfo.getSubject());
            }
            /* 3.2 文本内容 */
            if (StringUtils.isNotEmpty(mailInfo.getContent())) {
                message.setText(mailInfo.getContent());
            }
            Multipart multipart = null;
            /* 3.2 富文本内容 */
            if (StringUtils.isNotEmpty(mailInfo.getHtmlContent())) {
                BodyPart textPart = new MimeBodyPart();
                textPart.setContent(mailInfo.getHtmlContent(), "text/html;charset=utf-8");
                multipart = new MimeMultipart();
                multipart.addBodyPart(textPart);
            }
            /* 3.3 附件内容 */
            if (StringUtils.isNotEmpty(mailInfo.getUrls())) {
                if (multipart == null) {
                    multipart = new MimeMultipart();
                }
                List<String> urls = mailInfo.getUrls();
                for (String url : urls) {
                    BodyPart filePart = new MimeBodyPart();
                    /* 设置文件显示名*/
                    filePart.setFileName(FileUtils.getName(url));
                    filePart.setDataHandler(new DataHandler(new URL(url)));
                    multipart.addBodyPart(filePart);
                }
            }

            /* 4 装填信息&发送邮件 */
            if (Objects.nonNull(multipart) && multipart.getCount() > 0) {
                message.setContent(multipart);
            }

            Transport.send(message);
        } catch (MessagingException e) {
            e.printStackTrace();
            log.error("邮件发送失败,邮件内容:{}", JSONUtil.toJsonStr(mailInfo));
            return false;
        } catch (MalformedURLException e) {
            e.printStackTrace();
            log.error("url格式异常,邮件内容:{}", JSONUtil.toJsonStr(mailInfo));
            return false;
        }
        return true;
    }

    public static void main(String[] args) {
        MailUtil mailUtil = new MailUtil();
        MailInfo info = new MailInfo();
        info.setMailType(SMTP.NETEASE_YEAH_SMTP);

        info.setUsername("发送方邮箱");
        info.setSecreteKey("发送方密钥");
        info.setSubject("测试邮件");
        info.setContent("纯文本内容");
        String html ="<h1>h1标题</h1>" +
                "<hr/>" +
                "<img src=\"http://124.221.104.183:9501/statics/2024/02/22/are%20you%20ok_20240222155729A010.png\"/>";
        info.setHtmlContent(html);
        info.setReceivers(new ArrayList<>(Collections.singletonList("接收者邮箱")));
        info.setUrls(new ArrayList<>(Arrays.asList("http://124.221.104.183:9501/statics/2024/02/22/%E6%B0%B4%E5%8D%B0%E5%9B%BE%E7%89%87(20240222155232)_20240222155233A009.jpg","http://124.221.104.183:9501/statics/2024/02/22/c%E8%AF%AD%E8%A8%80_20240222155854A012.jpeg")));
        mailUtil.send(info);
    }

  • 10
    点赞
  • 10
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值