| HTML文件 <HTML> <BODY> <FORM action="sendmail.jsp" method="post"> <TABLE align="center"> <TR> <TD width="50%"> To:<BR><INPUT name="to" size="25"> </TD> <TD width="50%"> From:<BR><INPUT name="from" size="25"> </TD> </TR> <TR> <TD colspan="2"> Subject:<BR><INPUT name="subject" size="50"> </TD> </TR> <TR> <TD colspan="2"> <P>Message:<BR> <TEXTAREA name="text" rows=25 cols=85></TEXTAREA> </P> </TD> </TR> </TABLE> <INPUT type="submit" name="cb_submit" value=" Send "> <INPUT type="reset" name="cb_reset" value=" Clear "> </FORM> </BODY> </HTML> |
| sendmail.jsp文件 <%@ page import=" Javax.mail.*, Javax.mail.internet.*, Javax.activation.*,Java.util.*"%> <html> <head> <TITLE>JavaScript/" target="_blank">JSP meets JavaMail, what a sweet combo.</TITLE> </head> <body> <% try{ Properties props = new Properties(); Session sendMailSession; Store store; Transport transport; sendMailSession = Session.getInstance(props, null); props.put("mail.smtp.host", "smtp.jspinsider.com"); Message newMessage = new MimeMessage(sendMailSession); newMessage.setFrom(new InternetAddress(request.getParameter("from"))); newMessage.setRecipient(Message.RecipientType.TO, new InternetAddress ( request.getParameter ("to"))); newMessage.setSubject(request.getParameter("subject")); newMessage.setSentDate(new Date()); newMessage.setText(request.getParameter("text")); transport = sendMailSession.getTransport("smtp"); transport.send(newMessage); %> <P>Your mail has been sent.</P> <% }catch(MessagingException m) { out.println(m.toString()); } %> </body> </html> |
| form.htm <html> <head> <meta http-equiv="Content-Type" content="text/html; charset=gb2312"> <title> JavaMail - 发送HTML邮件</title> </head> <body> <table "0" cellspacing="0" cellpadding="0"> <form method="post" action="send.jsp"> <tr> <td>SMTP主机:</td> <td><input type="text" name="smtp" size="80"></td> </tr> <tr> <td>发信人:</td> <td><input type="text" name="from" size="80"></td> </tr> <tr> <td>收信人:</td> <td><input type="text" name="to" size="80"></td> </tr> <tr> <td>抄送人:</td> <td><input type="text" name="cc" size="80"></td> </tr> <tr> <td>暗送人:</td> <td><input type="text" name="bcc" size="80"></td> </tr> <tr> <td>主题:</td> <td><input type="text" name="subject" size="80"></td> </tr> <tr> <td valign="top">内容:</td> <td><textarea name="body" rows="5" cols="80"></textarea></td> </tr> <tr> <td colspan="2" align="center"><input type="submit" value="发送"></td> </tr> </form> </table> </body> </html> send.jsp <% //变量声明 Java.lang.String smtp,from,to,cc,bcc,subject,body; //获得用户输入数据 smtp = request.getParameter("smtp"); from = request.getParameter("from"); to = request.getParameter("to"); cc = request.getParameter("cc"); bcc = request.getParameter("bcc"); subject = request.getParameter("subject"); if(subject!=null){ subject = new Java.lang.String(subject.getBytes("iso-8859-1")); } body = request.getParameter("body"); //发送邮件 mymail.mail.HTML.send(smtp,from,to,cc,bcc,subject,body); %> mymail.jaf.StringDataSource.Java package mymail.jaf; public class StringDataSource implements Javax.activation.DataSource { private Java.lang.String data; private Java.lang.String type; public StringDataSource(Java.lang.String data,Java.lang.String type){ this.data = data; this.type = type; } public Java.io.InputStream getInputStream() throws Java.io.IOException{ return new Java.io.StringBufferInputStream(data); } public Java.io.OutputStream getOutputStream() throws Java.io.IOException{ throw new Java.io.IOException("it does not support this method now!"); } public Java.lang.String getContentType(){ return type; } public Java.lang.String getName(){ return " mymail "; } } mymail.mail.HTML.Java package mymail.mail; public final class HTML { public static void send( Java.lang.String smtp, /*SMTP主机地址*/ Java.lang.String from, /*发信人*/ Java.lang.String to, /*收信人*/ Java.lang.String cc, /*抄送人*/ Java.lang.String bcc, /*暗送人*/ Java.lang.String subject, /*主题*/ Java.lang.String body /*内容*/ ) throws Java.lang.Exception { //变量声明 Java.util.Properties props; //系统属性 Javax.mail.Session mailSession; //邮件会话对象 Javax.mail.internet.MimeMessage mimeMsg; //MIME邮件对象 //设置系统属性 props = Java.lang.System.getProperties(); //获得系统属性对象 props.put("mail.smtp.host",smtp); //设置SMTP主机 //获得邮件会话对象 mailSession = Javax.mail.Session.getDefaultInstance(props,null); //创建MIME邮件对象 mimeMsg = new Javax.mail.internet.MimeMessage(mailSession); //设置发信人 mimeMsg.setFrom(new Javax.mail.internet.InternetAddress(from)); //设置收信人 if(to!=null) { mimeMsg.setRecipients(Javax.mail.Message.RecipientType.TO,Javax.mail. internet.InternetAddress.parse(to)); } //设置抄送人 if(cc!=null) { mimeMsg.setRecipients(Javax.mail.Message.RecipientType.CC,Javax.mail. internet.InternetAddress.parse(cc)); } //设置暗送人 if(bcc!=null) { mimeMsg.setRecipients(Javax.mail.Message.RecipientType.BCC,Javax.mail. internet.InternetAddress.parse(bcc)); } //设置邮件主题 //mimeMsg.setSubject(subject); mimeMsg.setSubject(subject,"gb2312"); //设置邮件内容,将邮件body部分转化为HTML格式 mimeMsg.setDataHandler(new Javax.activation.DataHandler(new mymail.jaf. StringDataSource (body,"text/html"))); //发送邮件 Javax.mail.Transport.send(mimeMsg); } } |
如何实现消息和标志的删除? 附件的获取:
消息的删除涉及到与消息相关的 Flags(标志)。不同 flag 表示不同的状态,有些标志由系统定义,而有些则由用户自己定义。下面列出在内部类 Flags.Flag 中预定义的标志:
·Flags.Flag.ANSWERED
·Flags.Flag.DELETED
·Flags.Flag.DRAFT
·Flags.Flag.FLAGGED
·Flags.Flag.RECENT
·Flags.Flag.SEEN
·Flags.Flag.USER
上述这些标志只是标准定义,并不意味着所有邮件服务器或供应商都支持所有这些标志。例如,除了删除消息标志外,POP 协议不再支持其它任何标志。检查是否存在新邮件,这不是个 POP 任务,而是内建于邮件客户机的任务。为找出哪些标志能被支持,可以用 getPermanentFlags() 向 folder 提出请求。
要删除消息,您可以设置消息的 DELETED flag:
message.setFlag(Flags.Flag.DELETED, true);
首先,请以 READ_WRITE 模式打开 folder:
folder.open(Folder.READ_WRITE);
然后,当所有消息的处理完成后,关闭 folder,并传递一个 true 值,从而擦除(expunge)有 delete 标志的消息。
folder.close(true);
一个 Folder 的 expunge() 方法可以用来删除消息。但 Sun 的 POP3 供应商不支持。其它供应商有的或许能够实现这一功能,而有的则不能。IMAP 供应商极有可能实现此功能。因为 POP 只支持单个对邮箱的访问,对 Sun 的供应商来说,您必需关闭 folder 以删除消息。
要取消标志,只要传递 false 给 setFlag() 方法就行了。想知道是否设置过标志,可以用 isSet() 检查。
如何实现认证?
想必读者已经知道 ,如果需要可以用一个 Authenticator 提示用户输入用户名和密码,而不是将用户名和密码作为字符串传递。在这里您会明确了解怎样更充分的使用Java Mail API的认证机制。
不用主机、用户名和密码与 Store 相连接,而是设置 Properties 来拥有主机,然后告诉 Session 自定义的 Authenticator 实例,如下所示: // Setup properties
Properties props = System.getProperties();
props.put("mail.pop3.host", host);
// Setup authentication, get session
Authenticator auth = new PopupAuthenticator();
Session session = Session.getDefaultInstance(props, auth);
// Get the store
Store store = session.getStore("pop3");
store.connect();
然后,创建一个 Authenticator 子类并从 getPasswordAuthentication() 方法中返回 PasswordAuthentication 对象。下面就是这样一种实现,其中用户名和密码仅占用一个域。(这不是一个 Swing 工程教程;只要将两部分输入同一个域,用逗号分隔就行。) import Javax.mail.*;
import Javax.swing.*;
import Java.util.*;
public class PopupAuthenticator extends Authenticator
{
public PasswordAuthentication getPasswordAuthentication()
{
String username, password;
String result = JOptionPane.showInputDialog("Enter 'username,password'");
StringTokenizer st = new StringTokenizer(result, ",");
username = st.nextToken();
password = st.nextToken();
return new PasswordAuthentication(username, password);
}
}
因为 PopupAuthenticator 涉及到 Swing,它会启动 AWT 的事件处理线程。这一点基本上要求您在代码中添加一个对 System.exit() 的调用来终止程序。
如何实现消息的转发?
转发消息,相对于其他功能来说,显得有些棘手。没有单独的方法可以供调用,读者必须通过对组成消息各部分的处理来组织要转发的消息。
一条邮件消息可以由多个部分组成。在处理 MIME 消息时,消息中每部分都是 BodyPart,再特殊些,是 MimeBodyPart。不同的 body part(信体部件或正文部件)结合成一个容器,名为 Multipart,再特殊些,就是 MimeMultipart。要转发一条消息,您为自己的消息正文创建一个部件,要转发的消息作为另一部件。并且将两个部件结合成一个 multipart(多部件)。然后您将这个 multipart 添加到一则已写好恰当地址的消息中,并发送。
本质上就是如此。要将一条消息内容复制到另一条,只要复制 DataHandler (JavaBeans Activation Framework 中的类)就行了。 // Create the message to forward
Message forward = new MimeMessage(session);
// Fill in header
forward.setSubject("Fwd: " + message.getSubject());
forward.setFrom(new InternetAddress(from));
forward.addRecipient(Message.RecipientType.TO, new InternetAddress(to));
// Create your new message part
BodyPart messageBodyPart = new MimeBodyPart();
messageBodyPart.setText( "Here you go with the original message:nn");
// Create a multi-part to combine the parts
Multipart multipart = new MimeMultipart();
multipart.addBodyPart(messageBodyPart);
// Create and fill part for the forwarded content
messageBodyPart = new MimeBodyPart();
messageBodyPart.setDataHandler(message.getDataHandler());
// Add part to multi part
multipart.addBodyPart(messageBodyPart);
// Associate multi-part with message
forward.setContent(multipart);
// Send message
Transport.send(forward);
怎样处理附件?
附件是邮件消息的相关资源,如通常不包含在消息正文里文本文件、电子表格或图像等。常见的邮件程序,如 Eudora 和 pine 之类,可以用 JavaMail API 将资源 attach(附加) 到您的消息上,就可以在收到消息时得到。
附件的发送:
发送附件非常像转发消息。您建立各部分以组成完整消息。完成第一部件,即消息正文后,您添加其它部件,其中每个 DataHandler 都代表附件,而不是转发消息情况下的共享处理程序。如果从文件中读附件,附件的数据源是 FileDataSource。而如果从 URL 中读时,附件的数据源是 URLDataSource。一旦存在 DataSource,只要先把它传递给 DataHandler 构造器,最后再用 setDataHandler() 把它附加到 BodyPart。假定您要保留附件的原始文件名,最终要做的是用 BodyPart 的 setFileName() 方法设置与附件相关的文件名。如下所示: // Define message
Message message = new MimeMessage(session);
message.setFrom(new InternetAddress(from));
message.addRecipient(Message.RecipientType.TO,
new InternetAddress(to));
message.setSubject("Hello JavaMail Attachment");
// Create the message part
BodyPart messageBodyPart = new MimeBodyPart();
// Fill the message
messageBodyPart.setText("Pardon Ideas");
Multipart multipart = new MimeMultipart();
multipart.addBodyPart(messageBodyPart);
// Part two is attachment
messageBodyPart = new MimeBodyPart();
DataSource source = new FileDataSource(filename);
messageBodyPart.setDataHandler(new DataHandler(source));
messageBodyPart.setFileName(filename);
multipart.addBodyPart(messageBodyPart);
// Put parts in message
message.setContent(multipart);
// Send the message
Transport.send(message);
就消息引入附件时,若程序是个 servlet (小服务程序),除告知消息发送到何处外,还必需上载附件。可以将 multipart/form-data 表单编码类型(form encoding type)用于每个上载文件的处理。 <FORM ENCTYPE="multipart/form-data"
method=post action="/myservlet">
<INPUT TYPE="file" NAME="thefile">
<INPUT TYPE="submit" VALUE="Upload">
</FORM>
注意:消息大小由 SMTP 服务器而不是 JavaMail API 来限制。如果您碰到问题,可以考虑用设置 ms 和 mx 参数的方法增大 Java 堆大小。
从消息中获取附件比发送它们棘手些,因为 MIME 没有简单的关于附件的概念。当消息包含附件时,消息的内容是个 Multipart 对象。接着,您需要处理每个 Part,获取主要内容和附件。标有从 part.getDisposition() 获得的 Part.ATTACHMENT 配置(disposition)的部件(Part)无疑就是附件。但是,没有配置(以及一个非文本 MIME 类型)和带 Part.INLINE 配置的部件也可能是附件。当配置要么是 Part.ATTACHMENT,要么是 Part.INLINE 时,这个消息部件的内容就能被保存。只要用 getFileName() 和 getInputStream() 就能分别得到原始文件名和输入流。 Multipart mp = (Multipart)message.getContent();
for (int i=0, n=multipart.getCount(); i<n; i++) {
Part part = multipart.getBodyPart(i));
String disposition = part.getDisposition();
if ((disposition != null) &&
((disposition.equals(Part.ATTACHMENT) ||
(disposition.equals(Part.INLINE))) {
saveFile(part.getFileName(), part.getInputStream());
}
}
saveFile() 方法仅依据文件名创建了一个 File,它从输入流中将字节读出,然后写入到文件中。万一文件已经存在,就在文件名后添加一个数字作为新文件名,如果这个文件名仍存在,则继续添,直到找不到这样的文件名为止。 // from saveFile()
File file = new File(filename);
for (int i=0; file.exists(); i++) {
file = new File(filename+i);
}
上面的代码涵盖了最简单的情况 - 消息中各部件恰当的标记了。要涵盖所有情况,还要在配置为空时进行处理,并且获取部件的 MIME 类型来进行相应处理。 if (disposition == null) {
// Check if plain
MimeBodyPart mbp = (MimeBodyPart)part;
if (mbp.isMimeType("text/plain")) {
// Handle plain
} else {
// Special non-attachment cases here of image/gif, text/html, ...
}
...
}
如何一次发送多个邮件?
取得必要的Transport对象并调用SendMessage()发送每一个邮件。注意在调用之间设置或改变接收者。 Message message = …;
Transport t = session.getTransport("smtp");
t.connect();
message.setRecipient(Message.RecipientType.TO,recipient1);
t.sendMessage(message,recipient);
message.setRecipient(Message.RecipientType.TO,recipient2);
t.sendMessage(message,recipient);
message.setRecipient(Message.RecipientType.TO,recipient3);
t.sendMessage(message,recipient);
t.close();
如何保存邮件?
用MimeMessage类的writeTo()方法可以实现。用Message类的对象不能实现。 FileOutputStream fos = new FileOutputStream("test.mail");
Mimemessage.writeTo(fos);
怎样发送带有图像的HTML格式邮件?
一些图像还是放在服务器上较好,让用户的邮件工具处理。读者可以将图像作为附件或HTML体发送。如果所有附件保存在同一个目录下,那么必须用不同的图像文件名以确保邮件工具不会显示其他图片。另外图像URL要用绝对路径,不能用相对路径。
如何设置∕获取邮件的优先级?
设置邮件的优先级,只需在消息头中添加"X-Priority"属性:
MimeMessage msg;
Msg.addHeader("X-Priority","1");
同样道理,要获取邮件的优先级只要获取"X-Priority"属性的值就可以了:
String priority = msg.getHeader("X-Priority");
附录:Java Mail API的基本概念
什么是Java Mail API
JavaMail API 是一个用于阅读、编写和发送电子邮件的可选包(标准扩展)。与 Eudora、pine 及 Microsoft Outlook 相似,这个包用来创建邮件用户代理(Mail User Agent,MUA) 类型程序。API 的主要用途并不在于传输、发送和转发消息;这一功能范围属于某些应用程序,如 sendmail 及其它邮件传输代理(Mail Transfer Agent,MTA)类型程序。MUA 类型的程序能让用户阅读和书写邮件,而它却依赖 MTA 处理实际发送。
什么是SMTP
SMTP(Simple Mail Transfer Protocol),即简单邮件传输协议,它定义了发送电子邮件的机制。在 JavaMail API 环境中,基于 JavaMail 的程序将和您的公司或因特网服务供应商的(Internet Service Provider's,ISP's)SMTP 服务器通信。SMTP 服务器可将消息中转至接收方 SMTP 服务器,以便最终让用户经由 POP 或 IMAP 获得。这不是要求 SMTP 服务器成为开放的中继,尽管 SMTP 服务器支持身份验证,不过还是得确保它的配置正确。像配置服务器来中继消息或添加删除邮件账号这类任务的实现,JavaMail API 中并不支持。
什么是POP
POP(Post Office Protocol),即邮局协议。目前用的是版本3,所以人们通常将它称为 POP3,RFC 1939 定义了这个协议。POP 和SMTP一样,也是一种机制,Internet上大多数人通过它得到邮件。该协议规定每个用户只能有一个邮箱的支持。这就是它所能做的,而这也造成了许多混淆。使用 POP 时,用户熟悉的许多性能并不是由 POP 协议支持的,如查看有几封新邮件消息这一性能。这些性能内建于如 Eudora 或 Microsoft Outlook 之类的程序中,它们能记住一些事,诸如最近一次收到的邮件,还能计算出有多少是新的。所以当使用 JavaMail API 时,如果读者想要这类信息,就只能由自己来计算了。
什么是IMAP
IMAP(Internet Message Access Protocol),即Internet消息访问协议,是更高级的用于接收消息的协议,在 RFC 2060 中有它的定义。目前使用的IMAP版本为4,人们习惯将它称为 IMAP4。在用到 IMAP 时,邮件服务器必需支持这个协议。不能仅仅把使用 POP 的程序用于 IMAP,并指望它支持 IMAP 所有性能。假设邮件服务器支持 IMAP,基于 JavaMail 的程序可以利用这种情况--用户在服务器上可以有多个文件夹(folder),并且这些文件夹可以被多个用户共享。
因为有这一更高级的性能,您也许会认为所有用户都会使用 IMAP。事实并不是这样。要求服务器接收新消息,在用户请求时发送到用户手中,还要在每个用户的多个文件夹中维护消息。这样虽然能将消息集中备份,但随着用户长期的邮件夹越来越大,到磁盘空间耗尽时,每个用户都会受到损失。使用 POP,就能卸载邮件服务器上保存的消息了。
什么是MIME
MIME(Multipurpose Internet Mail Extensions),即多用途Internet邮件扩展标准。它不是邮件传输协议,而是对传输内容的消息、附件及其它的内容定义了格式。这里有很多不同的RFC(Requirement of Comment)文档:RFC 822、RFC 2045、RFC 2046 和 RFC 2047。作为一个 JavaMail API 的用户,您通常不必对这些格式操心。无论如何,一定存在这些格式而且程序会用到它。