天天看點

Java郵件發送詳解

文章目錄

  • ​​電子郵件​​
  • ​​傳輸協定​​
  • ​​SMTP協定​​
  • ​​POP3協定​​
  • ​​郵件收發原理​​
  • ​​Java發送郵件​​
  • ​​概述​​
  • ​​純文字郵件​​
  • ​​帶圖檔和附件的郵件​​
  • ​​JavaWeb發送郵件​​

電子郵件

要在網絡上實作郵件功能,必須要有專門的郵件伺服器。

這些郵件伺服器類似于現實生活中的郵局,它主要負責接收使用者投遞過來的郵件,并把郵件投遞到郵件接收者的電子郵箱中。

SMTP伺服器位址:一般是 ​​smtp.xxx.com​​​,​​比如163郵箱是smtp.163.com​​​,​​qq郵箱是smtp.qq.com​​。

電子郵箱(E-Mail位址)的獲得需要在郵件伺服器上進行申請。比如我們要使用QQ郵箱,就需要開通郵箱功能;

Java郵件發送詳解

傳輸協定

SMTP協定

發送郵件:

我們通常把處理使用者smtp請求(郵件發送請求)的伺服器稱之為SMTP伺服器(郵件發送伺服器)。

POP3協定

接收郵件:

我們通常把處理使用者pop3請求(郵件接收請求)的伺服器稱之為POP3伺服器(郵件接收伺服器)。

郵件收發原理

Java郵件發送詳解
  1. 首先通過smtp協定連接配接到Smtp伺服器,然後發送一封郵件給網易的郵件伺服器
  2. 網易分析發現需要去QQ的郵件伺服器,通過smtp協定将郵件轉投給QQ的Smtp伺服器
  3. QQ将接收到的郵件存儲在[email protected]這個郵件賬号的空間中
  4. 再通過Pop3協定連接配接到Pop3伺服器收取郵件
  5. [email protected]這個郵件賬号的空間中取出郵件
  6. Pop3伺服器将取出來的郵件送出去

【注意】有可能填寫的收件人位址,發件人位址等資訊都正确了,控制台也列印了正确的資訊,但是在收件箱就是收不到資訊。這是因為可能收件箱伺服器拒收了你發的郵件(比如認為你的郵件是廣告),這時候可能在垃圾箱裡能找到,可能找不到。解決辦法是重複的郵件内容不要多次發送,或者更換收件箱試試

Java發送郵件

概述

我們将用代碼完成郵件的發送。這在實際項目中應用的非常廣泛,比如注冊需要發送郵件進行賬号激活,再比如OA項目中利用郵件進行任務提醒等等。

使用Java發送 E-mail 十分簡單,但是首先你應該準備 JavaMail API 和Java Activation Framework 。

得到兩個jar包:

  • mail.jar
  • activation.jar

JavaMail 是sun公司(現以被甲骨文收購)為友善Java開發人員在應用程式中實作郵件發送和接收功能而提供的一套标準開發包,它支援一些常用的郵件協定,如前面所講的SMTP,POP3,IMAP,還有MIME等。我們在使用JavaMail API 編寫郵件時,無須考慮郵件的底層實作細節,隻要調用JavaMail 開發包中相應的API類就可以了。

我們可以先嘗試發送一封簡單的郵件,首先請確定電腦可以連接配接網絡。

  • 建立包含郵件伺服器的網絡連接配接資訊的Session對象。
  • 建立代表郵件内容的Message對象
  • 建立Transport對象,連接配接伺服器,發送Message,關閉連接配接

主要有四個核心類,我們在編寫程式時,記住這四個核心類,就很容易編寫出Java郵件處理程式,如圖所示:

Java郵件發送詳解

純文字郵件

先在項目中導入jar包

導入的就是在概述中提到的activation,jar和mail.jar包,如圖所示:

Java郵件發送詳解

QQ郵箱中擷取對應的權限

QQ郵箱需要安全驗證,我們需要擷取他對應的權限;

進入QQ郵箱–>郵箱設定–>賬戶,下滑找到POP3/IMAP/SMTP/Exchange/CardDav/CalDav服務,開啟POP3/SMTP服務,如圖所示:

Java郵件發送詳解
Java郵件發送詳解

記住這16位授權碼,然後開始編寫測試程式:

import com.sun.mail.util.MailSSLSocketFactory;

import java.util.*;
import javax.mail.*;
import javax.mail.internet.*;

public class SendEmail {

    public static void main(String[] args) throws Exception {

        Properties prop = new Properties();
        prop.setProperty("mail.host", "smtp.qq.com");  設定QQ郵件伺服器
        prop.setProperty("mail.transport.protocol", "smtp"); // 郵件發送協定
        prop.setProperty("mail.smtp.auth", "true"); // 需要驗證使用者名密碼

        // 關于QQ郵箱,還要設定SSL加密,加上以下代碼即可
        MailSSLSocketFactory sf = new MailSSLSocketFactory();
        sf.setTrustAllHosts(true);
        prop.put("mail.smtp.ssl.enable", "true");
        prop.put("mail.smtp.ssl.socketFactory", sf);

        //使用JavaMail發送郵件的5個步驟

        //建立定義整個應用程式所需的環境資訊的 Session 對象

        Session session = Session.getDefaultInstance(prop, new Authenticator() {
            public PasswordAuthentication getPasswordAuthentication() {
                //發件人郵件使用者名、授權碼
                return new PasswordAuthentication("[email protected]", "授權碼");
            }
        });


        //開啟Session的debug模式,這樣就可以檢視到程式發送Email的運作狀态
        session.setDebug(true);

        //2、通過session得到transport對象
        Transport ts = session.getTransport();

        //3、使用郵箱的使用者名和授權碼連上郵件伺服器
        ts.connect("smtp.qq.com", "[email protected]", "授權碼");

        //4、建立郵件

        //建立郵件對象
        MimeMessage message = new MimeMessage(session);

        //指明郵件的發件人
        message.setFrom(new InternetAddress("[email protected]"));

        //指明郵件的收件人,現在發件人和收件人是一樣的,那就是自己給自己發
        message.setRecipient(Message.RecipientType.TO, new InternetAddress("[email protected]"));

        //郵件的标題
        message.setSubject("隻包含文本的簡單郵件");

        //郵件的文本内容
        message.setContent("你好啊!", "text/html;charset=UTF-8");

        //5、發送郵件
        ts.sendMessage(message, message.getAllRecipients());

        ts.close();
    }

}      

帶圖檔和附件的郵件

先認識兩個類一個名詞:

MIME(多用途網際網路郵件擴充類型)

MimeBodyPart類

javax.mail.internet.MimeBodyPart類 表示的是一個MIME消息,它和MimeMessage類一樣都是從Part接口繼承過來。

MimeMultipart類

javax.mail.internet.MimeMultipart是抽象類 Multipart的實作子類,它用來組合多個MIME消息。一個MimeMultipart對象可以包含多個代表MIME消息的MimeBodyPart對象。

Java郵件發送詳解

建立包含内嵌圖檔的郵件

前面的例子中是單獨的使用HTML或者是純文字内容,但是有時候我們需要在純文字中使用内嵌的方式顯示一些圖檔,是以就要将純文字和内嵌圖檔單獨存放在MimeBodyPart中然後再将其存放在一個Mimemultipart對象中即可。

代碼如下:

import com.sun.mail.util.MailSSLSocketFactory;

import javax.activation.DataHandler;
import javax.activation.FileDataSource;
import javax.mail.*;
import javax.mail.internet.InternetAddress;
import javax.mail.internet.MimeBodyPart;
import javax.mail.internet.MimeMessage;
import javax.mail.internet.MimeMultipart;
import java.util.Properties;

public class SendImageEmail {
    public static void main(String[] args) throws Exception {

        Properties prop = new Properties();
        prop.setProperty("mail.host", "smtp.qq.com");  設定QQ郵件伺服器
        prop.setProperty("mail.transport.protocol", "smtp"); // 郵件發送協定
        prop.setProperty("mail.smtp.auth", "true"); // 需要驗證使用者名密碼

        // 關于QQ郵箱,還要設定SSL加密,加上以下代碼即可
        MailSSLSocketFactory sf = new MailSSLSocketFactory();
        sf.setTrustAllHosts(true);
        prop.put("mail.smtp.ssl.enable", "true");
        prop.put("mail.smtp.ssl.socketFactory", sf);

        //使用JavaMail發送郵件的5個步驟

        //1、建立定義整個應用程式所需的環境資訊的 Session 對象
        Session session = Session.getDefaultInstance(prop, new Authenticator() {
            public PasswordAuthentication getPasswordAuthentication() {
                //發件人郵件使用者名、授權碼
                return new PasswordAuthentication("[email protected]", "授權碼");
            }
        });


        //開啟Session的debug模式,這樣就可以檢視到程式發送Email的運作狀态
        session.setDebug(true);

        //2、通過session得到transport對象
        Transport ts = session.getTransport();

        //3、使用郵箱的使用者名和授權碼連上郵件伺服器
        ts.connect("smtp.qq.com", "[email protected]", "授權碼");

        //4、建立郵件

        //建立郵件
        MimeMessage message = new MimeMessage(session);

        // 設定郵件的基本資訊
        //發件人
        message.setFrom(new InternetAddress("[email protected]"));
        //收件人
        message.setRecipient(Message.RecipientType.TO, new InternetAddress("[email protected]"));
        //郵件标題
        message.setSubject("帶圖檔的郵件");

        // 準備郵件資料

        // 準備圖檔資料
        MimeBodyPart image = new MimeBodyPart();
        DataHandler dh = new DataHandler(new FileDataSource("src/resources/bz.jpg"));
        image.setDataHandler(dh);
        image.setContentID("bz.jpg");

        // 準備正文資料
        MimeBodyPart text = new MimeBodyPart();
        text.setContent("這是一封郵件正文帶圖檔<img src='cid:bz.jpg'>的郵件", "text/html;charset=UTF-8");

        // 描述資料關系
        MimeMultipart mm = new MimeMultipart();
        mm.addBodyPart(text);
        mm.addBodyPart(image);
        mm.setSubType("related");

        //設定到消息中,儲存修改
        message.setContent(mm);
        message.saveChanges();

        //5.發送郵件
        ts.sendMessage(message, message.getAllRecipients());
        ts.close();
    }
}      

帶圖檔和附件的複雜郵件發送

代碼如下:

import javax.activation.DataHandler;
import javax.activation.FileDataSource;
import javax.mail.*;
import javax.mail.internet.InternetAddress;
import javax.mail.internet.MimeBodyPart;
import javax.mail.internet.MimeMessage;
import javax.mail.internet.MimeMultipart;
import java.security.GeneralSecurityException;
import java.util.Properties;

public class SendFileMail {
    public static void main(String[] args) throws MessagingException, GeneralSecurityException {

        //建立一個配置檔案儲存并讀取資訊
        Properties properties = new Properties();

        //設定qq郵件伺服器
        properties.setProperty("mail.host","smtp.qq.com");
        //設定發送的協定
        properties.setProperty("mail.transport.protocol","smtp");
        //設定使用者是否需要驗證
        properties.setProperty("mail.smtp.auth", "true");


        //=================================隻有QQ存在的一個特性,需要建立一個安全的連結
        // 關于QQ郵箱,還要設定SSL加密,加上以下代碼即可
        MailSSLSocketFactory sf = new MailSSLSocketFactory();
        sf.setTrustAllHosts(true);
        properties.put("mail.smtp.ssl.enable", "true");
        properties.put("mail.smtp.ssl.socketFactory", sf);

        //=================================準備工作完畢

        //1.建立一個session會話對象;
        Session session = Session.getDefaultInstance(properties, new Authenticator() {
            @Override
            protected PasswordAuthentication getPasswordAuthentication() {
                return new PasswordAuthentication("[email protected]", "授權碼");
            }
        });

        //可以通過session開啟Dubug模式,檢視所有的過程
        session.setDebug(true);


        //2.擷取連接配接對象,通過session對象獲得Transport,需要捕獲或者抛出異常;
        Transport tp = session.getTransport();

        //3.連接配接伺服器,需要抛出異常;
        tp.connect("smtp.qq.com","[email protected]","授權碼");

        //4.連接配接上之後我們需要發送郵件;
        MimeMessage mimeMessage = imageMail(session);

        //5.發送郵件
        tp.sendMessage(mimeMessage,mimeMessage.getAllRecipients());

        //6.關閉連接配接
        tp.close();

    }


    public static MimeMessage imageMail(Session session) throws MessagingException {

        //消息的固定資訊
        MimeMessage mimeMessage = new MimeMessage(session);

        //郵件發送人
        mimeMessage.setFrom(new InternetAddress("[email protected]"));
        //郵件接收人,可以同時發送給很多人,我們這裡隻發給自己;
        mimeMessage.setRecipient(Message.RecipientType.TO, new InternetAddress("[email protected]"));
        mimeMessage.setSubject("我也不知道是個什麼東西就發給你了"); //郵件主題


        /*
        編寫郵件内容
        1.圖檔
        2.附件
        3.文本
         */

        //圖檔
        MimeBodyPart body1 = new MimeBodyPart();
        body1.setDataHandler(new DataHandler(new FileDataSource("src/resources/yhbxb.png")));
        body1.setContentID("yhbxb.png"); //圖檔設定ID

        //文本
        MimeBodyPart body2 = new MimeBodyPart();
        body2.setContent("請注意,我不是廣告<img src='cid:yhbxb.png'>","text/html;charset=utf-8");

        //附件
        MimeBodyPart body3 = new MimeBodyPart();
        body3.setDataHandler(new DataHandler(new FileDataSource("src/resources/log4j.properties")));
        body3.setFileName("log4j.properties"); //附件設定名字

        MimeBodyPart body4 = new MimeBodyPart();
        body4.setDataHandler(new DataHandler(new FileDataSource("src/resources/1.txt")));
        body4.setFileName(""); //附件設定名字

        //拼裝郵件正文内容
        MimeMultipart multipart1 = new MimeMultipart();
        multipart1.addBodyPart(body1);
        multipart1.addBodyPart(body2);
        multipart1.setSubType("related"); //1.文本和圖檔内嵌成功!

        //new MimeBodyPart().setContent(multipart1); //将拼裝好的正文内容設定為主體
        MimeBodyPart contentText =  new MimeBodyPart();
        contentText.setContent(multipart1);

        //拼接附件
        MimeMultipart allFile =new MimeMultipart();
        allFile.addBodyPart(body3); //附件
        allFile.addBodyPart(body4); //附件
        allFile.addBodyPart(contentText);//正文
        allFile.setSubType("mixed"); //正文和附件都存在郵件中,所有類型設定為mixed;


        //放到Message消息中
        mimeMessage.setContent(allFile);
        mimeMessage.saveChanges();//儲存修改


        return mimeMessage;

    }

}      

JavaWeb發送郵件

現在很多的網站都提供有使用者注冊功能, 通常我們注冊成功之後就會收到一封來自注冊網站的郵件。郵件裡面的内容可能包含了我們的注冊的使用者名和密碼以及一個激活賬戶的超連結等資訊。今天我們也來實作一個這樣的功能,使用者注冊成功之後,就将使用者的注冊資訊以Email的形式發送到使用者的注冊郵箱當中,實作發送郵件功能就得借助于JavaMail了。

  1. 建立一個JavaWeb項目,配置tomcat的參數,然後添加jar包(記得在tomcat目錄下的common目錄下也導包,不然會報500錯誤),并且添加實體類User,Servlet類RegisterServlet,工具類Sendmail,如圖所示:
  2. User類代碼如下:
public class User {

    private String username;
    private String password;
    private String email;

    public User() {
    }

    public User(String username, String password, String email) {
        this.username = username;
        this.password = password;
        this.email = email;
    }

    public String getUsername() {
        return username;
    }
    public void setUsername(String username) {
        this.username = username;
    }
    public String getPassword() {
        return password;
    }
    public void setPassword(String password) {
        this.password = password;
    }
    public String getEmail() {
        return email;
    }
    public void setEmail(String email) {
        this.email = email;
    }

    @Override
    public String toString() {
        return "User{" +
                "username='" + username + '\'' +
                ", password='" + password + '\'' +
                ", email='" + email + '\'' +
                '}';
    }
}      
  1. 前端注冊頁面register.jsp代碼如下:
<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<html>
<head>
    <title>注冊</title>
</head>
<body>

<form action="${pageContext.request.contextPath}/RegisterServlet.do" method="post">
    使用者名:<input type="text" name="username"><br/>
    密碼:<input type="password" name="password"><br/>
    郵箱:<input type="text" name="email"><br/>
    <input type="submit" value="注冊">
</form>

</body>
</html>      
  1. 工具類Sendmail類代碼如下:
import com.sun.mail.util.MailSSLSocketFactory;

import javax.mail.*;
import javax.mail.internet.InternetAddress;
import javax.mail.internet.MimeMessage;
import java.util.Properties;

public class Sendmail extends Thread {

    //用于給使用者發送郵件的郵箱
    private String from = "[email protected]";
    //郵箱的使用者名
    private String username = "[email protected]";
    //郵箱的密碼
    private String password = "授權碼";
    //發送郵件的伺服器位址
    private String host = "smtp.qq.com";

    private User user;
    public Sendmail(User user){
        this.user = user;
    }

    //重寫run方法的實作,在run方法中發送郵件給指定的使用者
    @Override
    public void run() {
        try{
            Properties prop = new Properties();
            prop.setProperty("mail.host", host);
            prop.setProperty("mail.transport.protocol", "smtp");
            prop.setProperty("mail.smtp.auth", "true");

            // 關于QQ郵箱,還要設定SSL加密,加上以下代碼即可
            MailSSLSocketFactory sf = new MailSSLSocketFactory();
            sf.setTrustAllHosts(true);
            prop.put("mail.smtp.ssl.enable", "true");
            prop.put("mail.smtp.ssl.socketFactory", sf);

            //1、建立定義整個應用程式所需的環境資訊的 Session 對象
            Session session = Session.getDefaultInstance(prop, new Authenticator() {
                public PasswordAuthentication getPasswordAuthentication() {
                    //發件人郵件使用者名、授權碼
                    return new PasswordAuthentication("[email protected]", "授權碼");
                }
            });

            //開啟Session的debug模式,這樣就可以檢視到程式發送Email的運作狀态
            session.setDebug(true);

            //2、通過session得到transport對象
            Transport ts = session.getTransport();

            //3、使用郵箱的使用者名和授權碼連上郵件伺服器
            ts.connect(host, username, password);

            //4、建立郵件
            MimeMessage message = new MimeMessage(session);
            message.setFrom(new InternetAddress(from)); //發件人
            message.setRecipient(Message.RecipientType.TO, new InternetAddress(user.getEmail())); //收件人
            message.setSubject("使用者注冊郵件"); //郵件的标題

            String info = "恭喜您注冊成功,您的使用者名:" + user.getUsername() + ",您的密碼:" + user.getPassword() + ",請妥善保管,如有問題請聯系網站客服!!";

            message.setContent(info, "text/html;charset=UTF-8");
            message.saveChanges();

            //發送郵件
            ts.sendMessage(message, message.getAllRecipients());
            ts.close();
        }catch (Exception e) {
            throw new RuntimeException(e);
        }
    }
}      
  1. Servlet類RegisterServlet類代碼如下:
import javax.servlet.ServletException;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;

public class RegisterServlet extends HttpServlet {
    @Override
    protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
        try {
            //接收使用者請求,封裝成對象
            String username = request.getParameter("username");
            String password = request.getParameter("password");
            String email = request.getParameter("email");
            User user = new User(username,password,email);

            //使用者注冊成功之後,給使用者發送一封郵件
            //我們使用線程來專門發送郵件,防止出現耗時,和網站注冊人數過多的情況;
            Sendmail send = new Sendmail(user);
            //啟動線程,線程啟動之後就會執行run方法來發送郵件
            send.start();

            //注冊使用者
            request.setAttribute("message", "注冊成功,我們已經發了一封帶了注冊資訊的電子郵件,請查收!如網絡不穩定,可能過會兒才能收到!!");
            request.getRequestDispatcher("info.jsp").forward(request, response);
        } catch (Exception e) {
            e.printStackTrace();
            request.setAttribute("message", "注冊失敗!!");
            request.getRequestDispatcher("info.jsp").forward(request, response);
        }
    }


    @Override
    protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
        doGet(req, resp);
    }
}      
  1. 配置web.xml,代碼如下:
<?xml version="1.0" encoding="UTF-8"?>
<web-app xmlns="http://xmlns.jcp.org/xml/ns/javaee"
         xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
         xsi:schemaLocation="http://xmlns.jcp.org/xml/ns/javaee http://xmlns.jcp.org/xml/ns/javaee/web-app_4_0.xsd"
         version="4.0">
    <servlet>
        <servlet-name>register</servlet-name>
        <servlet-class>com.kuang.servlet.RegisterServlet</servlet-class>
    </servlet>
    
    <servlet-mapping>
        <servlet-name>register</servlet-name>
        <url-pattern>/RegisterServlet.do</url-pattern>
    </servlet-mapping>
</web-app>      
  1. 編寫回報頁面info.jsp,代碼如下:
<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<html>
<head>
    <title>提示資訊</title>
</head>
<body>
    ${message}
</body>
</html>