Java发送邮件 – 颖儿的博客

在Java 平台发送邮件就要用到JavaMail API,这个JavaMail API不包含在Java SE(Java 标准版)当中。Java MailAPI是作为Java EE(Java 企业版)规范的一部分,同时官方也提供了该规范的实现,即类库,jar文件。

要在Java程序中使用JavaMail API去实现发送邮件的操作,那么首先就要引入JavaMail API的类库,即获取相应的jar文件,并将其放到适当的类加载路径(classpath)当中,以便我们开发的应用程序代码可以引用这些API实现。下面内容先介绍一下JavaMail API的版本变更历史和其依赖的类库的变化,然后给出程序示例代码。

初识JavaMail

最初是从菜鸟教程网站的一篇关于Java 发送邮件的文章开始接触JavaMail的,不过发现通过菜鸟教程网站文章提供的JavaMail API jar下载链接获得的jar文件不可用,于是就开始了寻根问底之旅。在这个过程中,又进一步加深了对一些基础概念的理解,例如jar(java archive)、classpath(class search path)。 另一方面又对Java平台的变迁对开发者的实际影响有了直接的体会(Java 8到Java 11),最后就是再次感受到Maven在依赖管理方法给开发者带来的便利。

后来发现菜鸟下载的JavaMail API的jar还是可以用的,之前可能是因为没有设置好本地邮件服务器,所以测试失败了。关于设置本地邮件服务器,下次再说。

JavaMail 版本变迁

JavaMail 依赖于 JAF(JavaBeans Activation Framework) 1.0.2,但建议使用JAF 1.1或更新版本。当前JAF最新版是1.2.1。注意 JAF 1.1 包含在JDK 1.6.0_10及其后版本的JDK中(直到JDK 1.8)。 然后JAF 1.2.0 包含在JDK 9中,不过是隐藏的。最后在JDK 11中已经移除了JAF,不过可以独立下载。 (参考自下文)

While JavaMail will work with JAF 1.0.2, we recommend the use of JAF 1.1
or newer.  JAF 1.2.1 is currently the newest version.  Note that JAF 1.1
is included in JDK 1.6 and JAF 1.1.1 is included in JDK 1.6.0_10 and
later.  JAF 1.2.0 is included but hidden in JDK 9 and has been removed
from JDK 11.  JAF 1.2.1 is available separately (see below).

JavaMail API 和 JavaBeans Activation Framework本来都是属于Java EE规范的东西,后来Java EE转到了Jakarta EE,成为了Eclipse Enterprise for Java(EE4J)的项目,所以后续版本的JavaMail 和 JAF的项目网页地址如下:

简单示例

项目目录结构

java-mail-demos
│  file.txt(发送带附件的邮件的测试文件)
│
├─lib(依赖的库)
│      activation-1.1.1.jar
│      mail-1.4.5.jar
│
├─out(生成的类文件)
│  └─com
│      └─yingiul
│              SendEmail.class
│              SendEmail2$1.class
│              SendEmail2.class
│              SendFileEmail.class
│              SendHTMLEmail.class
│
└─src(源代码)
 └─com
     └─yingiul
             SendEmail.java
             SendEmail2.java
             SendFileEmail.java
             SendHTMLEmail.java

分为4个源文件,以下是详细代码:

  • SendEmail.java

    package com.yingiul;
      
    import javax.mail.Message;
    import javax.mail.MessagingException;
    import javax.mail.Session;
    import javax.mail.Transport;
    import javax.mail.internet.InternetAddress;
    import javax.mail.internet.MimeMessage;
    import java.util.Properties;
      
    public class SendEmail
    {
        public static void main(String [] args)
        {
            // 收件人邮箱地址
            String to = "[email protected]";
      
            // 发件人邮箱地址
            String from = "[email protected]";
      
            // 指定发送邮件服务器主机为 localhost
            String host = "localhost";
      
            // 获取系统属性
            Properties properties = System.getProperties();
      
            // 设置邮件服务器
            properties.setProperty("mail.smtp.host", host);
      
            // 获取默认session对象
            Session session = Session.getDefaultInstance(properties);
      
            try{
                // 创建默认的 MimeMessage 对象
                MimeMessage message = new MimeMessage(session);
      
                // Set From: 设置发件人邮箱地址
                message.setFrom(new InternetAddress(from));
      
                // Set To: 设置收件人邮箱地址
                message.addRecipient(Message.RecipientType.TO,
                        new InternetAddress(to));
      
                // Set Subject: 设置邮件主题
                message.setSubject("这是邮件的主题!");
      
                // 设置邮件正文内容
                message.setText("This is actual message");
      
                // 发送消息(即发送邮件)
                Transport.send(message);
                System.out.println("Sent message successfully....");
            }catch (MessagingException mex) {
                mex.printStackTrace();
            }
        }
    }
    

    在命令行终端进入项目根目录(xxxjava-mail-demos),然后运行以下命令:

    javac -classpath lib*;src -d out srccomyingiulSendEmail.java

    java -classpath lib*;out com.yingiul.SendEmail

  • SendEmail2.java

    package com.yingiul;
    //需要用户名密码的邮件发送实例
    //文件名 SendEmail2.java
    //本实例以QQ邮箱为例,你需要在QQ邮箱后台设置-账户,生成授权码,作为应用程序登录QQ邮箱的密码
      
    import javax.mail.*;
    import javax.mail.internet.InternetAddress;
    import javax.mail.internet.MimeMessage;
    import java.util.Properties;
      
      
      
    public class SendEmail2 {
        public static void main(String[] args) {
            // 收件人电子邮箱
            String to = "[email protected]";
      
            // 发件人电子邮箱
            String from = "[email protected]";
      
            // 指定发送邮件服务器的主机为 smtp.qq.com
            String host = "smtp.qq.com";  //QQ 邮件服务器
      
            // 获取系统属性
            Properties properties = System.getProperties();
      
            // 设置邮件服务器
            properties.setProperty("mail.smtp.host", host);
      
            properties.put("mail.smtp.auth", "true");
            // 获取默认session对象
            Session session = Session.getDefaultInstance(properties, new Authenticator() {
                public PasswordAuthentication getPasswordAuthentication() {
                    return new PasswordAuthentication("[email protected]", "xxxpasswordxxx"); //发件人邮件用户名、授权码
                }
            });
      
            try {
                // 创建默认的 MimeMessage 对象
                MimeMessage message = new MimeMessage(session);
      
                // Set From: 设置发件人邮箱地址
                message.setFrom(new InternetAddress(from));
      
                // Set To: 设置收件人邮箱地址
                message.addRecipient(Message.RecipientType.TO,
                        new InternetAddress(to));
      
                // Set Subject: 设置邮件主题
                message.setSubject("这是邮件主题——测试QQ邮箱发送邮件");
      
                // 设置消息体
                message.setText("这是发给你的测试邮件!");
      
                // 发送消息
                Transport.send(message);
                System.out.println("成功从QQ邮箱发送邮件!");
            } catch (MessagingException mex) {
                mex.printStackTrace();
            }
        }
    }
    

    javac -classpath lib*;src -d out srccomyingiulSendEmail2.java

    java -classpath lib*;out com.yingiul.SendEmail2

  • SendFileEmail.java

    package com.yingiul;
      
    import javax.mail.BodyPart;
    import javax.mail.Message;
    import javax.mail.MessagingException;
    import javax.mail.Multipart;
    import javax.mail.Session;
    import javax.mail.Transport;
    import javax.mail.internet.InternetAddress;
    import javax.mail.internet.MimeBodyPart;
    import javax.mail.internet.MimeMessage;
    import javax.mail.internet.MimeMultipart;
      
    import java.util.Properties;
      
    import javax.activation.*;
      
    public class SendFileEmail {
        public static void main(String[] args) {
      
            // 收件人电子邮箱
            String to = "[email protected]";
      
            // 发件人电子邮箱
            String from = "[email protected]";
      
            // 指定发送邮件的主机为 localhost
            String host = "localhost";
      
            // 获取系统属性
            Properties properties = System.getProperties();
      
            // 设置邮件服务器
            properties.setProperty("mail.smtp.host", host);
      
            // 获取默认的 Session 对象。
            Session session = Session.getDefaultInstance(properties);
      
            try {
                // 创建默认的 MimeMessage 对象。
                MimeMessage message = new MimeMessage(session);
      
                // Set From: 设置发件人邮箱地址
                message.setFrom(new InternetAddress(from));
      
                // Set To: 设置收件人邮箱地址
                message.addRecipient(Message.RecipientType.TO,
                        new InternetAddress(to));
      
                // Set Subject: 设置邮件主题
                message.setSubject("这是邮件的主题!");
      
                // 创建消息部分
                BodyPart messageBodyPart = new MimeBodyPart();
      
                // 消息
                messageBodyPart.setText("邮件正文");
      
                // 创建多重消息
                Multipart multipart = new MimeMultipart();
      
                // 设置文本消息部分
                multipart.addBodyPart(messageBodyPart);
      
                // 附件部分
                messageBodyPart = new MimeBodyPart();
                String filename = "file.txt";
                DataSource source = new FileDataSource(filename);
                messageBodyPart.setDataHandler(new DataHandler(source));
                messageBodyPart.setFileName(filename);
                multipart.addBodyPart(messageBodyPart);
      
                // 发送完整消息
                message.setContent(multipart);
      
                // 发送消息
                Transport.send(message);
                System.out.println("附件邮件发送成功……");
            } catch (MessagingException mex) {
                mex.printStackTrace();
            }
        }
    }
    

    javac -classpath lib*;src -d out srccomyingiulSendFileEmail.java

    java -classpath lib*;out com.yingiul.SendFileEmail

  • SendHTMLEmail.java

    package com.yingiul;
      
    import javax.mail.Message;
    import javax.mail.MessagingException;
    import javax.mail.Session;
    import javax.mail.Transport;
    import javax.mail.internet.InternetAddress;
    import javax.mail.internet.MimeMessage;
    import java.util.Properties;
       
    public class SendHTMLEmail
    {
       public static void main(String [] args)
       {
           
          // 收件人电子邮箱
          String to = "[email protected]";
       
          // 发件人电子邮箱
          String from = "[email protected]";
       
          // 指定发送邮件的主机为 localhost
          String host = "localhost";
       
          // 获取系统属性
          Properties properties = System.getProperties();
       
          // 设置邮件服务器
          properties.setProperty("mail.smtp.host", host);
       
          // 获取默认的 Session 对象。
          Session session = Session.getDefaultInstance(properties);
       
          try{
             // 创建默认的 MimeMessage 对象。
             MimeMessage message = new MimeMessage(session);
       
             // Set From: 设置发件人邮箱地址
             message.setFrom(new InternetAddress(from));
       
             // Set To: 设置收件人邮箱地址
             message.addRecipient(Message.RecipientType.TO,
                                      new InternetAddress(to));
       
             // Set Subject: 头字段
             message.setSubject("这是邮件主题。");
       
             // 发送 HTML 消息, 可以插入html标签
             message.setContent("<h1>How are you doing?</h1>",
                                "text/html" );
       
             // 发送消息
             Transport.send(message);
             System.out.println("HTML邮件发送成功....");
          }catch (MessagingException mex) {
             mex.printStackTrace();
          }
       }
    }
    

    javac -classpath lib*;src -d out srccomyingiulSendHTMLEmail.java

    java -classpath lib*;out com.yingiul.SendHTMLEmail

附录

  • javac 编译错误:编码UTF8/GBK的不可映射字符

如果Java源代码文件编码格式为GBK,且在中文版Windows的命令行提示符编译.java文件,一般不会报错。但如果Java源代码文件编码格式为UTF-8,且在中文版Windows的命令行提示符编译.java文件,就会报错:错误: 编码GBK的不可映射字符 这个错误,可以通过增加javac的命令行选项-encoding解决,即将-encoding选项的值设置为utf-8,就会按照utf-8的编码去编译源码。 例如:

javac -encoding utf-8 -classpath lib*;src -d out srccomyingiulSendEmail.java
java -classpath lib*;out com.yingiul.SendEmail
  • 关于Maven的使用

pom.xml文件当中添加<dependencies>这里面是各种依赖</dependencies> ,然后添加<dependency>groupdId,artifactId,version,三个合一作为某个依赖的坐标</denpendency>。最新版的Jakarta Mail坐标如下

<dependency>
    <groupId>com.sun.mail</groupId>
    <artifactId>jakarta.mail</artifactId>
    <version>1.6.3</version>
</dependency>

前面的示例代码可以直接替换成为最新版Jakarta Mail