Java JavaMail通过SMPT发送邮件

概述

本讲讲述如何使用JavaMail工具包,通过SMPT协议,在Java代码中发送邮件。

一、JavaMail简介

JavaMail API提供了一个独立于平台且与协议无关的框架来构建邮件和消息传递应用程序。 JavaMail API提供了一组抽象类,用于定义组成邮件系统的对象。 它是一个可选包(标准扩展名),用于阅读,撰写和发送电子邮件。我们可以基于JavaMail开发出类似于Microsoft Outlook的应用程序。

JavaMail提供了用于构建消息传递系统接口的元素,包括系统组件和接口。 虽然此规范没有定义任何特定的实现,但JavaMail确实包含几个实现RFC822和MIME Internet消息传递标准的类。 这些类作为JavaMail类包的一部分提供。

以下是JavaMail API支持的一些协议:

  • SMTP : Simple Mail Transfer Protocol缩写。 它提供了一种传递电子邮件的机制。
  • POP : Post Office Protocol缩写。 POP是大多数人用来获取邮件的机制。 它定义了对每个用户的单个邮箱的支持。 RFC 1939定义了该协议。
  • IMAP : Internet Message Access Protocol缩写。 它是用于接收消息的高级协议。 它为每个用户提供多个邮箱支持,此外,邮箱可以由多个用户共享。 它在RFC 2060中定义。
  • MIME : Multipurpose Internet Mail Extensions缩写。 。 它不是邮件传输协议。 相反,它定义了传输内容:消息的格式,附件等。 这里有许多不同的文档:RFC 822,RFC 2045,RFC 2046和RFC 2047.作为JavaMail API的用户,您通常不需要担心这些格式。 但是,这些格式确实存在并由您的程序使用。
  • NNTP and Others :第三方提供商提供了许多协议。 其中一些是网络新闻传输协议(NNTP),安全多用途Internet邮件扩展(S/MIME)等。

JavaMail包中用于处理电子邮件的核心类是:Session,Message,Address,Authenticator,Store,Transport, Folder等。Session定义了一个基本的邮件会话,它需要从Properties中读取类似于邮件服务器,用户名和密码等信息。不过JDK中并没有包含,使用JavaMail发送邮件需要使用Sun发布的mail.jar和activtion.jar两个包。

开启邮箱客户端的SMTP协议功能

通过邮箱服务供应商,使用SMTP协议发送邮件一般需要开启权限并获取SMTP用户认证信息。
以163邮箱为例,需要在163邮箱网页上设置,并申请开启功能。然后你将获取一个密钥(记录保存下来),你的邮箱账号加上这个密钥就是接下来用于SMTP用户认证的用户名和密码。
可以参考开启客户端协议的官方文档

代码



        String username = "[email protected](这是一个邮箱)";// TODO: 按需修改 
        String password = "这是一个密码(一般在邮箱服务商上申请)";// TODO: 按需修改

        /******************************************** 第一步,设置邮箱服务器相关的链接和属性 **/
        
        //协议的配置属性
        Properties props = new Properties();
        props.put("mail.smtp.host", "smtp.163.com");//邮箱服务区地址// TODO: 按需修改

        //使用非ssl端口
        props.put("mail.smtp.port", "25");

        //使用ssl端口
//        final String SSL_FACTORY = "javax.net.ssl.SSLSocketFactory";
//        props.put("mail.smtp.socketFactory.port", "465");
//        props.put("mail.smtp.socketFactory.class", SSL_FACTORY);
//        props.put("mail.smtp.socketFactory.fallback", "false");
//        props.put("mail.smtp.starttls.enable", "true");
        //上面的 ssl端口 和 非ssl端口 二选一

        //开启smtp用户认证
        props.put("mail.smtp.auth", "true");

        //获取邮件session(此session不同于http session),传递Authenticator对象,用于用户身份认证
        Session session = Session.getInstance(props, new Authenticator() {
            @Override
            protected PasswordAuthentication getPasswordAuthentication() {
                return new PasswordAuthentication(username, password);
            }
        });


        //开启session运行时的debug日志输出
        session.setDebug(true);

        /******************************************** 第二步,开始设置邮件的属性 **/

        //Message对象,将存储我们实际发送的电子邮件信息
        MimeMessage message = new MimeMessage(session);
        //设置发件方地址
        message.setFrom(new InternetAddress("一个邮件地址"));// TODO: 按需修改
        
        /**
         * 设置接受方地址(收件方地址的情况)
         * Message.RecipientType.TO     表示主要的接收方
         * Message.RecipientType.CC     表示抄送
         * Message.RecipientType.BCC    表示密送
         * 发送给单个或多个接收方可以自由组合,或者取其一种
         */
        message.setRecipient(Message.RecipientType.TO, new InternetAddress("邮件地址1"));// TODO: 按需修改

        //同时发给多个接收方的时候用这个
        InternetAddress[] internetAddresses = new InternetAddress[2];
        internetAddresses[0] = new InternetAddress("邮件地址1");// TODO: 按需修改
        internetAddresses[1] = new InternetAddress("邮件地址2");// TODO: 按需修改
        message.setRecipients(Message.RecipientType.CC, internetAddresses);

        
        //设置邮件主题(标题)
        message.setSubject("Hello Subject", "UTF-8");


        /******************************************** 第三步,开始填充邮件的内容(邮件正文) **/

        //////////第一种形式,纯文本正文(可以设置为html格式的字符串,邮件客户端会自动解析成html)
//        String textBody = "hello, this email was sent via JavaMail.";
//        message.setText(textBody, "UTF-8");


        //////////第二种形式,MIME形式的正文(可以给邮件添加附件,或者给html添加关联的附件等)
        Multipart multipart = new MimeMultipart();


        BodyPart htmlTextpart = new MimeBodyPart();
        //html中内嵌图片,通过网页urlimg方式(这种方式图片数据在互联网上)
        String htmlImageUrl = "//pic.cnblogs.com/avatar/2062798/20200614130312.png";// TODO: 按需修改
        String body = "<h1>Hello</h1><p><img src=\"" + htmlImageUrl + "\" alt=\"图片加载失败,请尝试刷新页面\" referrerpolicy=\"no-referrer\"></p>";
        //html中内嵌图片,通过附件附件方式(这种方式图片数据在邮件中)
        body += "<h1>Hello2</h1><p><img src=\"cid:img01\" alt=\"图片加载失败,请尝试刷新页面\" referrerpolicy=\"no-referrer\"></p>";
        htmlTextpart.setContent(body, "text/html;charset=utf-8");
        multipart.addBodyPart(htmlTextpart);
        //打开要嵌入的文件
        File file = new File("C:\\Users\\user\\Pictures\\Camera Roll\\image.jpg");// TODO: 按需修改
        InputStream inputStream = new FileInputStream(file);
        BodyPart imagepart = new MimeBodyPart();
        imagepart.setFileName("一张平平无奇的图片.jpg");//
        imagepart.setDataHandler(new DataHandler(new ByteArrayDataSource(inputStream, "image/jpeg")));
        imagepart.setHeader("Content-ID", "<img02>");//value要和图片的cid对应才能嵌入在html中,否则就会变成附件
        multipart.addBodyPart(imagepart);

        //邮件的附件(图片不设置header就是附件)
        BodyPart attachment = new MimeBodyPart();
        attachment.setFileName("一张平平无奇的图片.jpg");//
        attachment.setDataHandler(new DataHandler(new ByteArrayDataSource(inputStream, "image/jpeg")));
        multipart.addBodyPart(attachment);

        //要调用setContent填入正文信息,和纯文本的形式不同
        message.setContent(multipart);

        //通过Transport类发送邮件(这时候才开始有网络连接)
        Transport.send(message);

maven依赖

<dependency>
    <groupId>javax.mail</groupId>   
    <artifactId>javax.mail-api</artifactId>
    <version>1.6.2</version>
</dependency>
<dependency>
    <groupId>com.sun.mail</groupId>
    <artifactId>javax.mail</artifactId>
    <version>1.6.2</version>
</dependency>      

什么是SMTP

SMTP(Simple Mail Transfer Protocol)即简单邮件传输协议,它是一组用于由源地址到目的地址传送邮件
的规则,由它来控制信件的中转方式。SMTP协议属于TCP/IP协议簇,它帮助每台计算机在发送或中转信件
时找到下一个目的地。通过SMTP协议所指定的服务器,就可以把E-mail寄到收信人的服务器上了,整个过程
只要几分钟。SMTP服务器则是遵循SMTP协议的发送邮件服务器,用来发送或中转发出的电子邮件。SMTP
是一种TCP协议支持的提供可靠且有效电子邮件传输的应用层协议。

什么是MIME

MIME, 全称为“Multipurpose Internet Mail Extensions”, 比较确切的中文名称为“多用途互联网邮件扩展”。它是当前广泛应用的一种电子邮件技术规范,基本内容定义于RFC 2045-2049
什么是MIME类型?-在把输出结果传送到浏览器上的时候,浏览器必须启动适当的应用程序来处理这个输出文档。这可以通过多种类型MIME(多功能网际邮件扩充协议)来完成。在HTTP中,MIME类型被定义在Content-Type header中。

MIME不属于一个邮件传输协议,它只是对SMTP的一个扩展,不能替代SMTP协议,至于为啥要替换SMTP了。主要是因为SMTP协议在传输报文时,只能够传输7位的ASCII格式的报文,不支持那些不使用7位ASCII格式的语种,同时它也不支持语音和视频数据的传输,因此我们需要一个辅助性协议帮忙传输报文,它就是MIME。

参考

JavaMail – 教程
廖雪峰教程 – 发送email
SMTP增强状态代码注册表
JavaMail–基础类详解
使用JavaMail发送邮件,465端口开启ssl加密传输
JavaMail配置属性
SMTP协议介绍

如果有不对的地方感谢指出