Java Web之开发JavaMail Web应用

Java Web之开发JavaMail Web应用
write:2022-5-18

前文学习了Java Web访问数据库的方法:Java Web之访问数据库,本文介绍Java Mail Web应用的开发方法,这个应用实际上是邮件服务器的客户端程序,它是基于浏览器的客户端程序,用户通过这个平台可以登录到邮件服务器,然后进行收发邮件以及管理邮件的操作;

1. E-mail协议简介

1)发送邮件服务器:使用SMTP协议
2)接收邮件服务器 :使用POP3或IMAP协议

客户机A向客户机B发送邮件的过程:
在这里插入图片描述

1.1 SMTP简单邮件传送协议

SMTP协议:Simple Mail Transfer Protocol,即简单邮件传输协议,是Internet传送E-mail的基本协议,也是TCP/IP协议组的成员。SMTP协议解决E-mail系统如何通过一条链路,把邮件从一台机器传递到另一台机器上的问题。

1.2 POP3邮局协议

POP3(Post Office Protocol 3)即邮局协议第3版,这是 Internet接收E-mail的基本协议,也是TCP/IP协议组的成员。

基于POP3协议的E-mail系统阅读信件的过程如下:
用户通过自己所熟悉的E-mail客户端软件,例如Foxmail、Outlook Express和the Bat等,经过相应的参数设置(主要是设置POP3 邮件服务器的IP地址或者域名、用户帐号及其对应密码)后,只要选择接收邮件操作,就能够将所有的邮件从远端的邮件服务器下载到用户的本地硬盘里。邮件下载之后,用户就可以在本地阅读了。当然,用户如果想节省上网费用,也可以选择在脱机状态下慢慢地阅读邮件。

1.3 E-mail接收的新协议IMAP

IMAP(Internet Message Access Protocol),互联网消息访问协议,即直接收取邮件的协议,是与POP3不同的一种E-mail接收的新协议,比POP3协议的功能更加强大。

目前最新的版本为IMAP4。

IMAP4与POP3协议一样提供了方便的下载邮件服务,允许用户在脱机状态下阅读已经下载到本地硬盘的邮件。

但IMAP4的功能远远不只这些,它还具有以下功能:
(1)摘要浏览邮件的功能(用户可以看到摘要信息,再决定是否需要下载,如果不需要,甚至可以在服务器端就把它删除)。
(2)选择性下载附件的功能。
(3)鼓励用户把邮件一直存储在邮件服务器上(方便用户可以在不同软件上通过IMAP协议操作同一服务器端的邮件)。
(4)允许用户把远程邮件服务器上的邮箱作为信息存储工具。

2. Java Mail API简介

现在明白了发送接收邮件是以下过程:
在这里插入图片描述
其中的邮件客户程序通常是一些桌面软件,例如Foxmail、Outlook Express等,采用C/S(Client/Server)结构,但我们可以试一试用java语言编写一个邮件客户程序,需要借助Java Mail API:

Java Mail API支持各种电子邮件通信协议,如IMAP、POP3和SMTP,为Java应用程序提供了电子邮件处理的通用接口。
在这里插入图片描述
javax.mail.Session:代表邮件会话
javax.mail.Store:代表接收邮件服务器上的注册账号的存储空间
javax.mail.Folder:代表邮件夹
javax.mail.Message:代表电子邮件
javax.mail.Address:邮件地址
javax.mail.Transport:负责发送邮件
在这里插入图片描述

2.1 Java Mail API的最主要的类

(1)javax.mail.Session:Session 类定义了一个基本邮件会话,是Java Mail API最高层入口类。Session 对象从java.util.Properties 对象中获取信息,如邮件发送服务器、接受邮件协议、发送邮件协议、用户名、密码及整个应用程序中共享的其它信息。
(2)javax.mail.Store:Store类是访问接收邮件服务器上邮件账户的入口,通过Store类的getFolder方法,可以访问特定的邮件夹。
(3)javax.mail.Folder:Folder类代表了邮件夹,用于分级组织邮件,通过Folder类可以访问邮件夹中的邮件。
(4)javax.mail.Message:Message代表了电子邮件。Message类封装了邮件信息,提供了访问和设置邮件内容的方法。

邮件中包含如下内容:
地址信息,包括发件人地址、收件人地址列表、抄送地址列表和广播地址列表
邮件标题
邮件发送和接收日期
邮件具体内容/正文:包括纯文本和附件两部分

Message 是个抽象类,常用的子类为 Javax.mail.internet.MimeMessage。MimeMessage 能支持MIME 类型电子邮件消息。MIME(Multipurpose Internet Mail Extensions)是一种电子邮件编码方式,它可以将发信人的电子邮件中的文本以及各种附件都打包后发送,传送时即时编码,收信人的软件收到邮件后也是即时解码还原,完全自动化,非常方便。当然先决条件是双方的软件都必须支持MIME编码,要不然发信人很方便地把信送出去了,但收信人的软件如果没有这种功能,无法把它还原,看到的也就是一大堆乱码了。  
(5)javax.mail.Address:Address代表了邮件地址,和 Message 一样,Address 也是个抽象类。常用的子类为 javax.mail.internet.InternetAddress 类。
(6)javax.mail.Transport:Transport 类根据指定的邮件发送协议(通常是 SMTP),通过指定的邮件发送服务器来发送邮件。Transport 类是抽象类,它提供了一个静态方法send(Message)来发送邮件。

2.2 获得JavaMail JAR文件

开发JavaMail应用程序需要两个JAR文件: mail.jar和activation.jar,它包含了JavaMail API中所有的接口和类。
下载地址为:https://www.oracle.com/java/technologies/java-archive-eepla-downloads.html#javamail-1.4.5-oth-JPR

3. 安装和配置Mail服务器

为了运行本课程介绍的程序,需要准备可以访问的邮件服务器,这里我们采用MerakMailServer服务器;它是一个商业服务器,支持E-mail协议;从以下网站可下载MerakMailServer的免费试用版本:http://www.javathinker.org/download/software/mailserver.zip

MerakMail服务器安装软件会自动在Window操作系统中加入邮件发送和接收服务,发送邮件采用SMTP协议,接收邮件支持POP3和IMAP协议。每次启动操作系统时,会自动运行这两项服务。

安装过程中会出现配置Domain窗口:可按照如图配置
在这里插入图片描述
MerakMail服务器的管理窗口:可以看到我们刚才创建的admin账户
在这里插入图片描述

4. 创建Java Mail应用客户程序

MailTest.java:由java语言编写的简单的邮件客户程序

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

public class MailTest{

  public static void main(String[] args)throws Exception {  //通过Java Mail API来访问邮件服务器的基本过程
    Properties props = new Properties();
    props.put("mail.smtp.host", "localhost");
    
    Session session = Session.getDefaultInstance(props); 

    String toAddr="admin@mydomain.com";
    String fromAddr="admin@mydomain.com";

    Message msg = new MimeMessage(session);
    InternetAddress[] toAddrs =InternetAddress.parse(toAddr, false);
    msg.setRecipients(Message.RecipientType.TO, toAddrs);
    msg.setSentDate(new Date());     
    msg.setSubject("hello");
    msg.setFrom(new InternetAddress(fromAddr));
    msg.setText("How are you");

    Transport.send(msg);  	  
  }
}

在访问邮件服务器之前,首先要进行初始化操作

4.1 创建Java Mail应用程序的初始化步骤

(1)设置Java Mail属性:
//set properties
Properties props = System.getProperties();
props.put(“mail.transport.protocol”, “smtp”);
props.put(“mail.store.protocol”, “imap”);
props.put(“mail.smtp.class”, “com.sun.mail.smtp.SMTPTransport”); //支持SMTP协议的具体类
props.put(“mail.imap.class”, “com.sun.mail.imap.IMAPStore”); //支持TMAP协议的类
props.put(“mail.smtp.host”, hostname); //支持SMTP协议的IP地址

(2)调用javax.mail.Session类的静态方法Session.getDefaultInstance获取Session实例,该方法将根据已经配置的Java Mail属性来创建Session实例:
Session mailsession = Session.getDefaultInstance(props, null);

(3)调用Session的getStore方法来取得Store对象,在本例中,将获取采用imap协议的Store对象:
Store store = mailsession.getStore(“imap”);

根据配置的mail.imap.class属性,可以确定这里getStore方法返回com.sun.mail.imap.IMAPStore类型的Store对象。

(4)调用Store的connect方法连接到接收邮件服务器上的特定邮件账号。调用connect方法时你应该指定接收邮件服务器名称或IP地址、(登录到邮件服务器上的)邮件账户名和口令。
store.connect(hostname,username, password);

4.2 发送邮件

创建并发送邮件:MailTest.java

// create a message
msg = new MimeMessage(mailsession);
InternetAddress[] toAddrs =InternetAddress.parse("admin@mydomain.com", false);
msg.setRecipients(Message.RecipientType.TO, toAddrs);
msg.setSubject("hello");
msg.setFrom(new InternetAddress("admin@mydomain.com"));
msg.setText("How are you");
//send a message
Transport.send(msg); //mail.smtp.host属性决定邮件发送服务器

4.3 访问邮件服务器上的特定邮件账号

打开inbox邮件夹参看邮件信息:MailTest.java

  //check inbox
   Folder folder=store.getFolder("inbox");
   folder.open(Folder.READ_WRITE);
   System.out.println("You have "+folder.getMessageCount()+" messages in inbox.");   //getMessageCount()邮件总数
   System.out.println("You have "+folder.getUnreadMessageCount()+"   unread messages in inbox.");  //getUnreadMessageCount()未读邮件总数

从邮件夹中读取信件:(邮件夹中的邮件都是排序的,第一份序号为1)

   //read first Message in inbox
   Message msg=folder.getMessage(1);   //msg:返回的第一份邮件
   System.out.println("------the first message in inbox-------");
   System.out.println("From:"+msg.getFrom()[0]);
   System.out.println("Subject:"+msg.getSubject());   //邮件标题
   System.out.println("Text:"+msg.getContent());

4.4 运行MailTest类

在helloapp目录下运行:ant runmail

build.xml文件中定义了runmail target:

 <target name="runmail" description="Run a sample"  >
    <java classname="MailTest" fork="true">
      <classpath refid="compile.classpath"/>
    </java>
  </target>

5. Java Mail Web应用的分层结构

应用的三层结构:
在这里插入图片描述

6. Java Mail Web应用的功能

登录IMAP服务器上的邮件账号
管理邮件夹(创建,删除,重命名)
查看邮件夹中的邮件信息(邮件数量,未读邮件数量)
查看邮件内容
创建和发送邮件
退出邮件系统

6.1 Javamail应用的文件清单

源代码:https://download.csdn.net/download/qq_48666555/85406313(免费)
在这里插入图片描述

6.1.2 用于保存邮件账号信息的MailUserData JavaBean

当客户登录到邮件服务器后,他的邮件账号信息保存在MailUserData对象中,MailUserData对象作为JavaBean存放在HTTP会话范围内。
在这里插入图片描述

在MailUserData中定义了如下属性,并为这些属性提供了相应的get和set方法:
URLName urlName; //客户连接邮件服务器上的邮件账号的URL
Session session; //客户当前使用的邮件会话
Store store; //客户当前使用的Store
Folder currFolder; //客户当前访问的Folder文件夹
Message currMsg; //客户当前访问的Message

MailUserData类的实用方法
在这里插入图片描述
下面来看一看MailUserData类的源代码

package mypack;

/**
 * This class is used to store session data for each user's session. It
 * is stored in the HttpSession.
 */
import javax.mail.*;
import javax.mail.internet.*;
import javax.activation.*;

public class MailUserData {
  URLName urlName;
  Session session;
  Store store;
  Folder currFolder;
  Message currMsg;

  public MailUserData() { }

  public URLName getURLName() {
    return urlName;
  }

  public void setURLName(URLName url){
    urlName=url;
  }

  public Session getSession() {
    return session;
  }

  public void setSession(Session s) {
    session = s;
  }

  public Message getCurrMsg() {
    return currMsg;
  }

  public void setCurrMsg(Message s) {
    currMsg = s;
  }

  public Store getStore() {
    return store;
  }

  public void setStore(Store s) {
    store = s;
  }

  public Folder getCurrFolder() {
    return currFolder;
  }

  public void setCurrFolder(Folder f) {
    currFolder = f;
  }

  public void doDeleteFolder(String foldername )throws Exception {

    //can't delete reserved folder
    if(foldername.equalsIgnoreCase("inbox")||  //存放接收到的邮件
               foldername.equalsIgnoreCase("trash")||  //存放已经删除的邮件
               foldername.equalsIgnoreCase("draft")||  //存放草稿邮件
               foldername.equalsIgnoreCase("sendbox")){   //存放已经发送的邮件,这四个是系统预留的邮件夹,有特定用途,不能让用户删除
      throw new Exception("Cann't delete reserved folder");
    }

    Folder folder=store.getFolder(foldername);
    if(!folder.exists())throw new Exception("This folder does not exists");
    if(folder.isOpen())folder.close(true);
    folder.delete(true);
  }

  public void doCreateFolder(String foldername)throws Exception {
    if(foldername==null || foldername.equals(""))
      throw new Exception("You do not input new folder name when creating folder");
    Folder folder=store.getFolder(foldername);
    if(folder.exists())throw new Exception("This folder already exists");
    folder.create(Folder.HOLDS_MESSAGES);
  }

  public void doRenameFolder(String fromname,String toname)throws Exception {

    if(toname==null || toname.equals(""))
      throw new Exception("You do not input new folder name when renaming folder");
    
    //can't rename reserved folder
    if(fromname.equalsIgnoreCase("inbox")||
         fromname.equalsIgnoreCase("trash")||
         fromname.equalsIgnoreCase("draft")||
         fromname.equalsIgnoreCase("sendbox")||
         toname.equalsIgnoreCase("inbox")||
         toname.equalsIgnoreCase("trash")||
         toname.equalsIgnoreCase("draft")||
         toname.equalsIgnoreCase("sendbox")){
       throw new Exception("Cann't rename reserved folder");
    }

    Folder folderFrom=store.getFolder(fromname);
    Folder folderTo=store.getFolder(toname);
    if(!folderFrom.exists())throw new Exception("This folder does not exists");
    if(folderFrom.isOpen())folderFrom.close(true);

    folderFrom.renameTo(folderTo);
  }

  public void doDeleteMessage(int arrayOpt[],Folder f)throws Exception {   //删除特定文件夹f里的若份邮件  arrayOpt[]:邮件序号
    for(int i=0;i<arrayOpt.length;i++){

      if(arrayOpt[i]==0)continue;
      Message msg=f.getMessage(i+1);
      if(!f.getName().equals("Trash")){
        Message[] m=new Message[1];
        m[0]=msg;
        Folder Trash=store.getFolder("Trash");
        f.copyMessages(m,Trash);
        msg.setFlag(Flags.Flag.DELETED, true);
      }else{
        msg.setFlag(Flags.Flag.DELETED, true);
      }
    }
    f.expunge();   //出现DETELE标志的邮件,则永久删除该邮件
  }

  public Message doAssembleMessage(PMessage msg)throws Exception {
    return doAssembleMessage(msg.getTo(),msg.getCC(),msg.getBCC(),msg.getSubject(),msg.getText());
  }

  public Message doAssembleMessage(String to,String cc,String bcc,String subj,String text)throws Exception {

    Message msg = new MimeMessage(session);
    InternetAddress[] toAddrs = null, ccAddrs = null, bccAddrs=null;

    if (to != null) {
      toAddrs = InternetAddress.parse(to, false);
      msg.setRecipients(Message.RecipientType.TO, toAddrs);
    }else
      throw new MessagingException("No \"To\" address specified");

    if (cc != null) {
	ccAddrs = InternetAddress.parse(cc, false);
	msg.setRecipients(Message.RecipientType.CC, ccAddrs);
    }

    if (bcc != null) {
	bccAddrs = InternetAddress.parse(bcc, false);
	msg.setRecipients(Message.RecipientType.BCC, bccAddrs);
    }

    if (subj != null)
	msg.setSubject(subj);

    msg.setFrom(new InternetAddress(urlName.getUsername() + "@" +
					        urlName.getHost()));

    if (text != null)
	msg.setText(text);

    return msg;
  }
  
  public void doSendMessage(PMessage pmsg)throws Exception {

    Message msg=doAssembleMessage(pmsg);

    //send message
    Transport.send(msg);

    //save message in sendbox folder
    Folder f=store.getFolder("SendBox");
    if(!f.isOpen())f.open(Folder.READ_WRITE);
    doAppendMessage(msg,f);
  }
    
  public void doAppendMessage(Message msg, Folder f)throws Exception{
    Message m[]=new Message[1];
    m[0]=msg;
    f.appendMessages(m);
  }

  public void doSaveMessage(PMessage pmsg)throws Exception {
    Message msg=doAssembleMessage(pmsg);
    //save message in draft folder
    Folder f=store.getFolder("Draft");
    if(!f.isOpen())f.open(Folder.READ_WRITE);
    doAppendMessage(msg,f);
  }

  public void doMoveMessage(String toFolderName)throws Exception {
    Folder folderFrom=currFolder;
    Folder folderTo=store.getFolder(toFolderName);
    if(!folderTo.exists())throw new Exception("Folder does not exist");
    Message[] m=new Message[1];
    m[0]=currMsg;
    folderFrom.copyMessages(m,folderTo);
    currMsg.setFlag(Flags.Flag.DELETED, true);
    folderFrom.expunge();
  }
}

6.1.3 登录IMAP服务器上的邮件账号(login.jsp)

在邮件服务器已经配置好的环境下,登录邮件账号,因为login.jsp表单的action是提交到connect.jsp处理,connect.jsp负责根据用户的登录信息连接邮件服务器上的账号,如果连接成功,该请求又转发到listallfolders.jsp
在这里插入图片描述

6.1.4 管理邮件夹(listallfolders.jsp)

listallfolders.jsp显示用户的邮件夹信息,并提供了一些功能:
在这里插入图片描述

6.1.5 查看邮件夹中的邮件信息(listonefolder.jsp)

listonefolder.jsp显示用户指定邮件夹的信息
在这里插入图片描述

6.1.6 查看邮件内容(showmessage.jsp)

在这里插入图片描述

6.1.7 创建和发送邮件(compose.jsp)

在这里插入图片描述

6.1.8 退出邮件系统(logout.jsp)

<%@ include file="common.jsp" %>
<%
String username=mud.getURLName().getUsername();
mud.getStore().close();  //断开与接收邮件服务器的连接
session.invalidate();  //结束HTTP会话
%>
<html><head><title>Logout</title></head><body>
<h3>Goodbye,<%=username%>!</h3><br>
<strong><a href="login.jsp">Login again</a></strong>
</body></html>

在这里插入图片描述

7. 总结

在这里插入图片描述

8. 练习题

  1. 问题:以下哪些属于接收邮件的协议?(多选)
    选项:
    (A)POP3
    (B)SMTP
    (C)HTTP
    (D)IMAP4
    答案:A,D

  2. 问题:以下哪个协议允许管理远程邮件服务器上的邮件夹?(单选)
    选项:
    (A)POP3
    (B)SMTP
    (C)HTTP
    (D)IMAP4
    答案:D

  3. 问题:以下哪些方法属于javax.mail.Store类的方法?(多选)
    选项:
    (A)connect(String host,String user,String password)
    (B)getFolder(String name)
    (C)send(Message msg)
    (D)setText(String txt)
    (E)close()

答案:A,B,E
(A)connect(String host,String user,String password) //建立与邮件服务器的连接
(B)getFolder(String name) //获得参数名的邮件
(C)send(Message msg) //Transport类的静态方法,负责放松邮件
(D)setText(String txt) //Message类的静态方法,负责设置纯文本内容
(E)close() //断开与邮件服务器的连接

  1. 问题:Folder类的expunge()方法有什么作用?(单选)
    选项:
    (A)永久删除邮件夹中所有设置了DELETE标记的邮件
    (B)永久删除邮件夹中所有的邮件
    (C)给邮件夹中所有邮件加上DELETE标记
    (D)取消邮件夹中所有邮件的DELETE标记

答案:A

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值