邮件列表服务经常用于为工作组提供基于email的讨论环境,订阅者通过它讨论共同感兴趣的问题。
本文提供的示例程序ListServer是一个简单的邮件列表转发服务器:它从指定帐号读取新邮件并发送给所有订阅者。Java Mail API不仅使得实现其基本功能相当简单(使用缺省的POP3和SMTP),而且保证了程序易于支持任何可能遇到的系统环境。
运行该程序需要包含以下支持文件:Java Mail (mail.jar)、JAF(activation.jar)以及缺省的POP3支持(pop3.jar),如下面DOS批命令文件所示(这些JAR文件可以从Sun的Java Mail主页下载,参见相关资源):
@echo off
PATH .;d:\jdk1.1\bin
set CLASSPATH=.;d:\jdk1.1\lib\classes.zip;activation.jar;mail.jar;pop3.jar
java ListServer %1 %2 %3 %4 %5 %6 %7 %8 %9
程序启动后先由main()过程读取命令行参数,如邮件服务器、邮件帐号、更新周期等。接下来创建ListServer实例,最后进入“读取新邮件并转发给订阅者/等待直到下一次检查时间到来”无限循环。ListServer的核心功能(即读取和转发所有新邮件)在process()过程实现,其主要操作过程为:
◆获取javax.mail.Session实例,并进而获得javax.mail.Store实例。
◆利用javax.mail.Store实例获得缺省收件箱(INBOX)javax.mail.Folder实例。
◆使用javax.mail.Folder对象提取新邮件,存储为javax.mail.Message对象数组。
◆创建javax.mail.FetchProfile以(潜在地)优化对特定邮件组成成分的提取。
请注意此处javax.mail.FetchProfile类的应用。FetchProfile类提供邮件协议提供者特有可选参数,其目的是更有效地实现邮件组成成分的预提取。Java Mail API鼓励延迟提取邮件成分——即仅在真正需要的时候才提取。这不仅有利于改善系统的响应时间,某些操作(如显示邮件标题列表)也能够从中得到好处。下面代码说明了FetchProfile的基本用法:
// 提取所有邮件的属性和标记
Message[] messages = folder.getMessages();
FetchProfile fp = new FetchProfile();
fp.add(FetchProfile.Item.ENVELOPE);
fp.add(FetchProfile.Item.FLAGS);
fp.add("X-Mailer");
folder.fetch(messages, fp);
sendMsg()过程由processMsg()调用,负责分析指定收件并将它转发给所有订阅者。它首先获得缺省Session实例,然后创建javax.mail.Transport对象发送消息:
// 设置属性并获得缺省进程实例
Properties props = new Properties();
props.put("mail.smtp.host", _smtpHost);
Session session = Session.getDefaultInstance(props, null);
......
// 发送消息
Transport transport = session.getTransport(SMTP_MAIL);
transport.connect(_smtpHost, _user, _password);
transport.sendMessage(newMessage, _toList);
邮件字段(如收件人、发件人、邮件主题和日期等)的设置方法如下:
// 创建新邮件 Address replyToList[] = { new InternetAddress(replyTo) };
Message newMessage = new MimeMessage(session);
if (_fromName != null)
newMessage.setFrom(new InternetAddress(from,
_fromName + " / " + replyTo));
else
newMessage.setFrom(new InternetAddress(from));
newMessage.setReplyTo(replyToList);
newMessage.setRecipients(Message.RecipientType.BCC, _toList);
newMessage.setSubject(subject);
newMessage.setSentDate(sentDate);
填写邮件内容应该区分其类型(纯文本和复合内容使用不同方法):
// 填写邮件内容 Object content = message.getContent(); //原邮件内容
String debugText = "主题: " + subject + ", 发送日期: " + sentDate;
if (content instanceof Multipart)
{
debugMsg("转发复合内容邮件 (" + debugText + ")");
newMessage.setContent((Multipart)message.getContent());
}
else
{
debugMsg("转发纯文本邮件 (" + debugText + ")");
newMessage.setText((String)content);
}
可以看到,javax.mail.internet.MimeMessage内容读取例程getContent()只需要一次调用就可以读取复杂的分级复合邮件。