《JAVAWeb应用程序》教案第四章JavaMail和Servlet目标★掌握使用JavaMailAPI编程★理解JavaMail会话和消息★理解Transport对象★掌握如何创建一个发送电子邮件的Servlet重点★如何使用JavaMail的接口和类★如何使用Servlet发送邮件,列出和读取邮件★创建Muilti-part邮件难点★读取带附件的邮件1.回顾2.知识点讲解2.1电子邮件工作原理案例讲解电子邮件与普通邮件有类似的地方,发信者注明收件人的姓名与地址(即邮件地址),发送方服务器把邮件传到收件方服务器,收件方服务器再把邮件发到收件人的邮箱中。如下图所示:更进一步的解释涉及到以下几个概念:MUA--MailUserAgent,邮件用户代理,帮助用户读写邮件;MTA--MailTransportAgent,邮件传输代理,负责把邮件由一个服务器传到另一个服务器或邮件投递代理;MDA--MailDeliveryAgent,邮件投递代理,把邮件放到用户的邮箱里。整个邮件传输过程如下:目前使用的SMTP协议是存储转发协议,意味着它允许邮件通过一系列的服务器发送到最终目的地。服务器在一个队列中存储到达的邮件,等待发送到下一个目的地。下一个目的地可以是本地用户,或者是另一个邮件服务器,如下图所示。如果下游的服务器暂时不可用,MTA就暂时在队列中保存信件,并在以后尝试发送。2.1.1常用邮件协议什么是SMTP?SMTP(SimpleMailTransferProtocol)协议是为了保证电子邮件的可靠和高效传送。TCP/IP协议的应用层中包含有SMTP协议,但事实上它与传输系统和机制无关,仅要求一个可靠的数据流通道。它可以工作在TCP上,也可以工作在NCP,NITS等协议上。在TCP上,它使用端口25进行传输。SMTP的一个重要特点是可以在可交互的通信系统中转发邮件。SMTP工作原理?SMTP提供了一种邮件传输的机制,当收件方和发件方都在一个网络上时,可以把邮件直传给对方;当双方不在同一个网络上时,需要通过一个或几个中间服务器转发。SMTP首先由发件方提出申请,要求与接收方SMTP建立双向的通信渠道,收件方可以是最终收件人也可以是中间转发的服务器。收件方服务器确认可以建立连接后,双发就可以开始通信。下面是SMTP的模型示意图。发件方SMTP向收件方发处MAIL命令,告知发件方的身份;如果收件方接受,就会回答OK。发件方再发出RCPT命令,告知收件人的身份,收件方SMTP确认是否接收或转发,如果同意就回答OK;接下来就可以进行数据传输了。通信过程中,发件方SMTP与收件方SMTP采用对话式的交互方式,发件方提出要求,收件方进行确认,确认后才进行下一步的动作。整个过程由发件方控制,有时需要确认几回才可以。为了保证回复命令的有效,SMTP要求发件方必须提供接收方的服务器及邮箱。邮件的命令和答复有严格的语法定义,并且回复具有相应的数字代码。所有的命令由ASCII码组成。命令代码是大小写无关的,如MAIL和mail﹑mAIL是等效的。POPPOP的含义是邮局协议,当前的版本为3,也称作POP3,该协议是在RFC1939中定义的。POP是Internet上的大多数人用来接收邮件的机制。它为每个用户的每个邮箱定义支持,这是它所做的全部工作,也是大多数问题的根源。在使用POP协议时,人们熟悉的很多功能,如查看收到了多少新邮件消息的功能,POP根本不支持。这些功能都内置到诸如Eudora或MicrosoftOutlook之类的邮件程序中,能为您记住接收的上一封邮件,以及计算有多少新邮件这类信息。因此,使用JavaMailAPI时,如果想获取这类信息,将需要由自己进行计算。IMAPIMAP是用于接收消息的更加高级的协议,它是在RFC2060中定义的。IMAP的含义是“Internet消息访问协议”,当前版本是第4版,也称作IMAP4。使用IMAP时,您的邮件服务器必须支持该协议。您不能只是简单地把程序转变为支持IMAP,而不是支持POP,就指望能支持IMAP中的一切。假定您的邮件服务器支持IMAP,那么基于JavaMail的程序就可利用在服务器上拥有多个文件夹的用户,并且这些文件夹可以被多个用户共享的功能。由于IMAP协议具有更高级的功能,您也许会想IMAP应该被每一个人使用,但事实不是这样。因为IMAP会加重邮件服务器的负荷,它需要服务器接收新消息,发送消息给请求的用户,并在多个文件夹中为每个用户维护这些消息。而这要集中备份,因而长期下去用户的文件夹会变得越来越大,当磁盘空间用光了时,每个人都会遭受损失。而使用POP协议时,已保存消息可以解除服务器的重负。MIMEMIME的含义是“多用途的网际邮件扩充协议”。它不是一种邮件传输协议,相反,它定义传输的内容:消息的格式、附件等。许多文档都定义了MIME协议,包含:RFC822、RFC2045、RFC2046和RFC2047。作为JavaMailAPI的用户,一般不需要担心这些格式。但是,这些格式确实存在,并为您的程序所用。2.2JavaMailAPI案例讲解其中,1~~4行称作信件信头(messageheader)6~~10行描述信件要表达的内容,称为信体(messagebody)。第5行是空行,根据RFC822的要求,信头和信体之间必须加入一空行。i[i]信头通常包含字段From,To,Subject和Date,有的邮件还包含cc,bcc等字段。2.2.1Session类Session类定义了一个基本的邮件会话。通过该会话可让别的工作顺利执行。Session对象利用java.util.Properties对象获取诸如邮件服务器、用户名、密码等信息,以及其他可在整个应用程序中共享的信息。Session类的构造器是私有的。您可以获得一个可被getDefaultInstance()方法共享的单一的默认会话:Propertiesprops=newProperties();//fillpropswithanyinformationSessionsession=Session.getDefaultInstance(props,null);或者,您可以用getInstance()方法创建一个独特的会话:Propertiesprops=newProperties();//fillpropswithanyinformationSessionsession=Session.getInstance(props,null);这两种情形下的null参数都是一种Authenticator对象,它不是在此时使用的。详细信息请参阅其后的“Autherticator”一节。在大多数情况下,使用共享会话就足够了,即使为多个用户邮箱处理邮件会话也是如此。您可以在通信过程的后面一步添加上用户名和密码的组合,并保持所有的一切是独立的。2.2.2Message类一旦创建了自己的Session对象,就是该去创建要发送的消息的时候了。这时就要用到消息类型。作为一个抽象类,您必须操作一个子类,在大多数情况下,该子类是javax.mail.internet.MimeMessage。一个MimeMessage是一种理解MIME类型和报头的消息。消息的报头被严格限制成只能使用US-ASCII字符,尽管非ASCII字符可以被编码到某些报头字段中。电子邮件格式:1.From:user1@domain1.com2.To:user2@domain2.com3.Subject:Explainationofmailformat4.Date:Thu,1Apr1999.10:00:00GMT5.你好,李逵7.这封邮件向你介绍电子邮件的格式8.----9.Thanks10.Bob可以通过将Session对象传递给MimeMessage构造器的方法来创建消息:MimeMessagemessage=newMimeMessage(session);注意:还有其他的构造器,像用于创建消息的源于RFC822格式化的输入流的构造器。一旦创建了消息,就可以设置其各个部分,如Message(消息)实现Part(部分)接口(以MimeMessage实现MimePart)。设置内容的基本机制是setContent()方法,它带有表示内容和MIME类型的参数:message.setContent(Hello,text/plain);但是,如果正在使用MimeMessage,并且您的消息是纯文本,那么您就可以使用setText()方法。该方法只需要一个表示实际内容的参数,默认的MIME类型为纯文本:message.setText(Hello);对于纯文本消息,setText()方法更常常被用来设置内容。要发送其他类型的消息,如HTML消息,就要使用setContent方法()。现在用的更多的是HTML消息。要设置主题,可以使用setSubject()方法:message.setSubject(First);2.2.3Address类一旦创建了会话和消息,并为消息填充了内容,就需要用Address类为您的信件标上地址了。同Message类一样,Address类也是一种抽象类。您可以使用javax.mail.internet.InternetAddress类。要创建只带有电子邮件地址的地址,可以把电子邮件地址传递给Address类的构造器:Addressaddress=newInternetAddress(president@whitehouse.gov);如果想让一个名字出现在电子邮件地址后,也可以将其传递给构造器:Addressaddress=newInternetAddress(president@whitehouse.gov,GeorgeBush);您要为消息的from(发送者)字段和to(接收者)字段创建地址对象。除非您的邮件服务器阻止这样做,否则要在发送的消息中注明该消息的发送者。一旦创建好了地址,有两种方法可让您将地址与消息连接起来。为了鉴别发送者,您可以使用setFrom()和setReplyTo()方法。message.setFrom(address)如果您的消息需要显示多个地址来源,则可以使用addFrom()方法:Addressaddress[]=...;message.addFrom(address);为了鉴别消息接收者,您可以使用addRecipient()方法。该方法除了需要一个地址参数外,还需要一个Message.RecipientType属性(消息的接收类型)。message.addRecipient(type,address)地址的3种预定义类型如下:·Message.RecipientType.TO·Message.RecipientType.CC·Message.RecipientType.BCC因此,如果一条消息将发送给副总统,同时还将发送该消息的副本给第一夫人,则采用下面的代码:AddresstoAddress=newInternetAddress(vice.president@whitehouse.gov);AddressccAddress=newInternetAddress(first.lady@whitehouse.gov);message.addRecipient(Message.RecipientType.TO,toAddress);message.addRecipient(Message.RecipientType.CC,ccAddress);JavaMailAPI没有提供检查电子邮件地址有效性的机制。您可以自己编写支持扫描有效字符(在RFC822文档中所定义的)的程序或检验MX(邮件交换)记录,这些都超越了JavaMailAPI的范围。2.2.4Authenticator类与java.net类一样,JavaMailAPI可以利用Authenticator(验证程序)类通过用户名和密码来访问受保护的资源。对于JavaMailAP