James+Javamail构建邮件服务(一)
本文描述如何使用James搭建具备一定邮件过滤、邮件操作功能的邮件服务器,以及使用Javamail实现对James服务器邮件的收发功能。
1关于James与Javamail
Apache James(Java Apache Mail Enterprise Server)是Apache组织的子项目之一,完全采用纯Java技术开发,实现了SMTP、POP3与NNTP等多种邮件相关协议。James是一个 邮件应用平台,可以通过Mailet扩充其功能,如Mail2SMS、Mail2Fax等。James提供了比较完善的配置方案,尤其是关于邮件内容存储 和用户信息存储部分,可以选择在文件、数据库或其他介质中保存。James性能稳定、可配置性强,还是开源项目,所有源代码不存在版权问题,因 此,James在项目中的应用日益广泛。
Javamail API是一个用于阅读、编写和发送电子消息的可选包(标准扩展),可以用来建立基于标准的电子邮件客户机,它支持各种因特网邮件协议,包括:SMTP、POP、IMAP、MIME、NNTP、S/MIME及其它协议。
在本文档中,我们使用James 2.3.1+Javamail 1.4.1作为介绍蓝本。
2 James服务器快速入门
我们可以从Apache James的官方站点下载到我们所需要的James服务器及源码
James服务器(ZIP版)下载地址:
http://apache.mirror.phpchina.com/james/server/binaries/james-binary-2.3.1.zip
James源码下载地址:
http://apache.mirror.phpchina.com/james/server/source/james-2.3.1-src.zip
其他版本的服务器及源码可到官方下载页面下载:
http://james.apache.org/download.cgi
2.1启动James
第一步:
将james-binary-2.3.1.zip解压到纯英文目录下
第二步:
运行bin目录下的run.bat(在运行之前请确保您的Java环境变量已配置成功,否则将提示运行失败)
显示以下内容表示James服务器已启动成功:
服务器启动成功后,将自动在apps目录下根据james.sar文件生成相应的James发布文件包,我们后面讨论的配置文件config.xml即存在于此发布文件包中。
2.2用Telnet管理用户
用cmd进入MS-DOS,输入telnet localhost 4555 (注:localhost是邮件服务器名,4555是管理端口,可在appsjamesSAR-INFconfig.xml文件中配置,在此我们使用其默认配置)
然后输入用户名和密码(在配置文件config.xml中,默认为用户名:root密码:root)
出现如下信息说明登陆成功:
登陆成功后,我们就可以开始对用户信息进行增、删、查、改等操作了。
常用的用户信息操作命令参见下表:
? Currently implemented commands: 常用实现命令
? help display this help 显示帮助信息
? listusers display existing accounts 显示现有账户
? countusers display the number of existing accounts显示现有账户数量
? adduser [username] [password] add a new user 添加一个新用户
? verify [username] verify if specified user exist 核实指定用户是否存在
? deluser [username] delete existing user 删除存在的用户
? setpassword [username] [password] sets a user’s password 设置用户密码
? setalias [user] [alias] locally forwards all email for ‘user’ to ‘alias’ 设置邮箱别名
? showalias [username] shows a user’s current email alias显示别名
? unsetalias [user] unsets an alias for ‘user’ 删除用户别名
? setforwarding [username] [emailaddress] forwards a user’s email to another email address 转发用户的电子邮件地址到另一个电子邮件地址
? showforwarding [username] shows a user’s current email forwarding显示用户的当前邮件转发
? unsetforwarding [username] removes a forward 删除转发
? user [repositoryname] change to another user repository 改变另一个用户库
? shutdown kills the current JVM (convenient when James is run as a daemon) 关闭当前的服务
? quit close connection 关闭连接
我们可以输入命令:adduser chenfengcn 881213来添加一个的邮件用户,则其用户名为:chenfengcn,密码为:881213,邮箱地址 为:chenfengcn@localhost(用户名后的域名跟服务器配置的域名相同,在config.xml文件中配置,我们将在后面部分讨论如何配 置邮件服务器域名)。这样,我们就完成了一个最简单的邮件服务器的搭建操作。下面就让我们使用Foxmail来测试一下我们的邮箱帐户是否真正可以使用 吧。
2.3使用Foxmail测试邮箱帐户
打开Foxmail,点击“邮箱”->“新建邮箱帐户”
电子邮件地址:chenfengcn@localhost
密码为:881213
POP3服务器:localhost
SMTP服务器:localhost
其余选项均使用默认即可,新建完成后,Foxmail将发送一测试邮件到我们新建的邮箱里,点击“收取”,即可收取我们邮件帐户里面的邮件了。当收到Foxmail发送的测试邮件,就说明我们的邮件帐户可以正常使用了。
作为程序设计人员,我们当然希望能使用自己写的程序来测试我们的邮件服务器是否搭建成功,而不是Foxmail。下面就让我们用Javamail来实现这一切吧。
James+Javamail构建邮件服务(二)
电子邮件开发2009-11-30 10:15:30阅读21评论0字号:大中小
3 Javamail快速入门
进行Javamail开发需要用到两个包:mail.jar和activation.jar,在开始Javamail编程之前,请自己将这两个包添加到IDE的Build path中或将这两个包的路径配置到环境变量中。
3.1使用Javamail向James的邮箱帐户发送邮件
3.1.1业务描述
本例将使用Javamail实现邮件的发送功能。发送邮件需要配置邮件服务器属性信息,配置邮件接收地址,使用SMTP认证获得会话(Session),构建邮件体(MimeMessage),发送邮件。具体编码如下:
3.1.2编码实现
发送邮件需要两个类:一个是SMTP用户身份认证类(James在默认情况下,是需要SMTP身份认证的);另一个就是我们的邮件发送类,为简 单起见,我们直接将邮件的相关信息,如:标题、内容、发送者、接收者等信息直接写在类中,运行main()函数即发送。当然,你同样可以为自己的邮件发送 系统构造一个邮件发送介面,通过Servlet将相关参数传递至后台进行处理与发送。其主要代码也就是此main()函数中的内容,故不赘述。
SmtpAuth.java用户身份认证代码
Java代码
package com.newland.javamail.sample1;
/**
* 用于身份认证
* @author Chen.Feng(Kevin)<br>
* mail:chenfengcn@yeah.net<br>
* qq:67758633
*/
class SmtpAuth extends javax.mail.Authenticator {
private String user, password;
/**
*
* @param getuser
* @param getpassword
*/
public void setUserinfo(String getuser, String getpassword) {
user = getuser;
password = getpassword;
}
protected javax.mail.PasswordAuthentication getPasswordAuthentication() {
return new javax.mail.PasswordAuthentication(user, password);
}
public String getPassword() {
return password;
}
public void setPassword(String password) {
this.password = password;
}
public String getUser() {
return user;
}
public void setUser(String user) {
this.user = user;
}
}
SendMail.java发送邮件代码
Java代码
package com.newland.javamail.sample1;
import java.util.Properties;
import javax.activation.DataHandler;
import javax.activation.DataSource;
import javax.activation.FileDataSource;
import javax.mail.Message;
import javax.mail.MessagingException;
import javax.mail.Session;
import javax.mail.Transport;
import javax.mail.URLName;
import javax.mail.internet.AddressException;
import javax.mail.internet.InternetAddress;
import javax.mail.internet.MimeBodyPart;
import javax.mail.internet.MimeMessage;
import javax.mail.internet.MimeMultipart;
/**
* 使用Javamail实现邮件发送功能
* @author Chen.Feng(Kevin)<br>
* mail:chenfengcn@yeah.net<br>
* qq:67758633
*
*/
public class SendMail {
public SendMail() {
// TODO Auto-generated constructor stub
}
public static void main(String[] args) {
// 初始化信息
String sender = “chenfengcn”;
String password = “881213”;
String smtpServer = “localhost”;
String recipient = “chenfengcn@localhost”;
String subject = “测试邮件主题”;
String fileAttachment = “”; //附件
String content = “测试邮件内容”;
// 配置服务器属性
Properties proper = new Properties();
proper.put(“mail.smtp.host”, smtpServer); // smtp服务器
proper.put(“mail.smtp.auth”, “true”); // 是否smtp认证
proper.put(“mail.smtp.port”, “25”); // 设置smtp端口
proper.put(“mail.transport.protocol”, “smtp”); // 发邮件协议
proper.put(“mail.store.protocol”, “pop3”); // 收邮件协议
// 配置邮件接收地址
InternetAddress[] receiveAddress = new InternetAddress[1];
try {
receiveAddress[0] = new InternetAddress(recipient);
} catch (AddressException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
// smtp认证,获取Session
SmtpAuth sa = new SmtpAuth();
sa.setUserinfo(sender, password);
Session session = Session.getInstance(proper, sa);
session.setPasswordAuthentication(new URLName(smtpServer), sa
.getPasswordAuthentication());
// 构建邮件体
MimeMessage sendMess = new MimeMessage(session);
MimeBodyPart mbp = new MimeBodyPart();
MimeMultipart mmp = new MimeMultipart();
try {
// 邮件文本内容
mbp.setContent(content, “text/plain; charset=GBK”);
mmp.addBodyPart(mbp);
// 附件处理
if(fileAttachment!=null&&fileAttachment!=””){
DataSource source = new FileDataSource(fileAttachment);
String name = source.getName();
mbp = new MimeBodyPart();
mbp.setDataHandler(new DataHandler(source));
mbp.setFileName(name);
mmp.addBodyPart(mbp);
}
// 邮件整体
sendMess.setSubject(subject);
sendMess.setContent(mmp);
// 发送邮件
sendMess.setFrom(new InternetAddress(sender));
sendMess.setRecipients(Message.RecipientType.TO, receiveAddress);
Transport.send(sendMess);
System.out.println(“发送成功”);
} catch (MessagingException ex) {
ex.printStackTrace();
}
}
}
值得一提的是,本程序已经实现了带附件邮件的发送功能,如果要发送带附件的邮件,则只需要将附件的路径传到fileAttachment变量中就可 以了。邮件发送成功后,程序将在后台打印出“发送成功”,这样我们就完成了邮件发送功能。那么,我们应该如何检验服务器是否确实收到我们发送的测试邮件 呢?Javamail可以发送邮件,当然也能接收邮件啦,下面让我们一起使用Javamail编写邮件接收功能来检验吧。
3.2使用Javamail接收邮件
3.2.1业务描述
在上一节,我们已经向James的chenfengcn用户发送了一封测试邮件,我们应该如何使用Javamail来收取这封邮件呢?
为读取邮件,必须首先设置服务器属性(Properties),获取一个会话(Session),然后获取并连接邮箱所在的存储器(Store对象),打开该用户的邮箱(Folder),获取所希望阅读的消息,最后关闭目录和连接。
下面的程序实现了接收chenfengcn@localhost邮箱中所有邮件,并将发送人和主题打印出来。
3.2.2编码实现
Java代码
package com.newland.javamail.sample1;
import java.util.Properties;
import javax.mail.Folder;
import javax.mail.Message;
import javax.mail.MessagingException;
import javax.mail.NoSuchProviderException;
import javax.mail.Session;
import javax.mail.Store;
/**
* 使用Javamail实现邮件接收功能
* @author Chen.Feng(Kevin)<br>
* mail:chenfengcn@yeah.net<br>
* qq:67758633
*
*/
public class ReceiveMail {
public ReceiveMail() {
}
public static void main(String[] args) {
// 初始化主机
String host = “localhost”;
String username = “chenfengcn”;
String password = “881213”;
// 配置服务器属性
Properties props = new Properties();
props.put(“mail.smtp.host”, “localhost”); // smtp服务器
props.put(“mail.smtp.auth”, “true”); // 是否smtp认证
props.put(“mail.smtp.port”, “25”); // 设置smtp端口
props.put(“mail.transport.protocol”, “smtp”); // 发邮件协议
props.put(“mail.store.protocol”, “pop3”); // 收邮件协议
// 获取会话
Session session = Session.getDefaultInstance(props, null);
// 获取Store对象,使用POP3协议,也可能使用IMAP协议
try {
Store store = session.getStore(“pop3”);
// 连接到邮件服务器
store.connect(host, username, password);
// 获取该用户Folder对象,并以只读方式打开
Folder folder = store.getFolder(“inbox”);
folder.open(Folder.READ_ONLY);
// 检索所有邮件,按需填充
Message message[] = folder.getMessages();
for (int i = 0; i < message.length; i++) {
// 打印出每个邮件的发件人和主题
System.out.println(i + “:” + message[i].getFrom()[0] + “ ”
+ message[i].getSubject());
}
folder.close(false);
store.close();
} catch (NoSuchProviderException e) {
// TODO Auto-generated catch block
e.printStackTrace();
} catch (MessagingException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
}
程序运行成功后,将会把chenfengcn用户的邮件从James服务器中取出,并将此邮箱中所有邮件的发件人、主题打印在后台。若要打印该邮件的内容等信息,则只要将message[i]对象中的邮件内容等信息读取出来就可以了。
注:鉴于邮件的存储结构(将在第五章介绍),读取邮件附件是一个比较复杂的过程,因为邮件的文本内容和附件信息都是保存在BodyPart对象 中的,BodyPart用于标识类型的标记不明确,造成对附件的判断较为复杂。对于附件的操作本人将在今后的改进版本中加以介绍。
James+Javamail构建邮件服务(三)
电子邮件开发 2009-11-30 10:17:09 阅读30 评论0 字号:大中小
4 Mailet快速入门
Mailet API是一个用来创建邮件处理程序的简单的API,它被配置在邮件服务器端执行,分匹配器Matcher和Mailet的接口两种,匹配器根据特定的条件匹配邮件消息,并触发相应的Mailet.
Mailet这个词是跟Servlet相似,功能也相似,他们的共同之处都是在服务器端触发并执行,只是Servlet的Matcher通常是 url的pattern,跟Servlet的接口一样,Mailet也有init()方法,service()方法和destroy()方法.即他们都有 类似的生命周期. Mailet的简单可编程接口可以用来做一些邮件处理,比如反垃圾邮件,检查邮件病毒以及邮件博客等等,利用移动设备可发送email的功能,可以做到手 机通过mail发送信息到邮件服务器交给Mailet处理,形成移动博客的模型.
Mailet的运行需要mailet-2.3.jar和mailet-api-2.3.jar两个包的支持,James本身就有这两个包,可不作修改,但在开发的时候还是需要开发者自己将这两个包导入到工程的Build path中或配置到系统环境变量中。
4.1 用Mailet做一个Hello的例子
4.1.1 业务描述
我们要实现当外部发送给James服务器中名字含hello的邮箱时,服务器在这封邮件的主题前加入“Hello”,并在服务器后台输出 “Received a piece of Email”。如前所述,Mailet包括匹配器Matcher和Mailet两种接口,现在就让我们用Mailet API实现这两个接口吧。
4.1.2 编码实现
匹配器BizMatcher.java
Java代码
package com.newland.james.mailet.sample1;
import org.apache.mailet.GenericRecipientMatcher;
import org.apache.mailet.MailAddress;
/**
* Mailet匹配器
* @author Chen.Feng(Kevin)<br>
* mail:chenfengcn@yeah.net<br>
* qq:67758633
*
*/
public class BizMatcher extends GenericRecipientMatcher {
public boolean matchRecipient(MailAddress recipient) {
// 邮件地址必须包含hello的
if (recipient.getUser().indexOf("hello") != -1) {
return true;
}
return false;
}
}
BizMaillet.java
Java代码
package com.newland.james.mailet.sample1;
import java.io.IOException;
import javax.mail.MessagingException;
import javax.mail.internet.MimeMessage;
import org.apache.mailet.GenericMailet;
import org.apache.mailet.Mail;
/**
* Mailet处理程序
* @author Chen.Feng(Kevin)<br>
* mail:chenfengcn@yeah.net<br>
* qq:67758633
*
*/
public class BizMaillet extends GenericMailet {
public void init() throws MessagingException {
}
public void service(Mail mail) throws MessagingException {
MimeMessage mmp;
mmp = (MimeMessage) mail.getMessage();
mmp.setSubject("Hello "+mmp.getSubject());
System.out.println("Received a piece of Email");
}
}
4.1.3 配置部署
Mailet跟Servlet一样,是服务器端程序,是不能直接在客户端运行的,必须要部署到服务器端方可生效。部署具体步骤如下:
1、 将我们编写的Matcher和Mailet打包成jar文件;
2、 在james-2.3.1appsjamesSAR-INF目录下新建一个lib文件夹;
3、 将打包好的jar文件复制到刚刚新建的lib文件夹下;
4、 打开config.xml配置文件,找到以下这段代码:
Xml代码
<mailetpackages>
<mailetpackage>org.apache.james.transport.mailets</mailetpackage>
<mailetpackage>org.apache.james.transport.mailets.smime</mailetpackage></mailetpackages>
<matcherpackages>
<matcherpackage>org.apache.james.transport.matchers</matcherpackage>
<matcherpackage>org.apache.james.transport.matchers.smime</matcherpackage></matcherpackages>
前半部分是用于配置Mailet包所在位置,后半部分是用于配置Matcher包所在位置,我们把我们刚编写的Mailet和Matcher所在位置配置进去就可以了。配置后的结果如下:
Xml代码
<mailetpackages>
<mailetpackage>com.newland.james.mailet.sample1</mailetpackage>
<mailetpackage>org.apache.james.transport.mailets</mailetpackage>
<mailetpackage>org.apache.james.transport.mailets.smime</mailetpackage>
</mailetpackages>
<matcherpackages>
<matcherpackage>com.newland.james.mailet.sample1</matcherpackage>
<matcherpackage>org.apache.james.transport.matchers</matcherpackage>
<matcherpackage>org.apache.james.transport.matchers.smime</matcherpackage>
</matcherpackages>
这样就完成了包的配置。我们都知道,Mailet的工作过程是:首先由Matcher来匹配所接收到的邮件,然后提交给相应的Mailet处 理,但是哪个匹配器对应哪个Mailet呢?我们还需要配置Mailet的对应关系。同样在config.xml中找到下面的代码:
Xml代码
<mailet match="All" class="PostmasterAlias"/>
在这段代码下面加入我们自己的Mailet:
Xml代码
<mailet match="All" class="PostmasterAlias"/>
Xml代码
<mailet match="BizMatcher" class="BizMaillet"/>
这样就完成了我们自定义的Mailet的配置部署工作了。重启James服务器,则此Mailet即可生效。
4.1.4 测试Mailet
前面我们已经完成了Mailet的编码和部署工作,现在就让我们来测试一下我们的Mailet是否生效吧。首先,需要在James服务器上新建一个名称含Hello的用户。前面已介绍过新建用户的方法了,在此就不重复叙述了。
使用adduser helloworld 881213命令新建一个helloworld用户。
使用第三章所谈及的“使用Javamail向James的邮箱帐户发送邮件”来向helloworld@localhost发送一封邮件(当 然,你同样可以使用Foxmail或Outlook向此地址发送邮件),邮件发送成功后,James服务器后台将输出“Receive a piece of email”。运行效果如下图所示:
这就说明我们的Mailet已经部署成功了.
James+Javamail构建邮件服务(四)
电子邮件开发 2009-11-30 10:17:55 阅读53 评论0 字号:大中小
关键字: james javamail mailet java 邮件
5 Javamail邮件存储逻辑简介
5.1 Message存储结构示意图
Message是邮件发送的最终对象,我们一般使用他的子类对象MimeMessage,其子类对象里包含有邮件的MessageID、 Subject、Flag、From、Sender、Content等信息,Content是邮件的内容体,其一般是一个Multipart对象(或其子 类对象MimeMultipart),所有的邮件内容都存在于Multipart中的。一个Multipart包含有一个或多个BodyPart对象(或 其子类对象MimeBodyPart),BodyPart对象用于存储邮件的内容,可以是文本形式,也可以是附件形式。
6 常用Javamail API简介
核心JavaMail API可以分为两部分,一部分由七个类组成:Session、Message、Address、Authenticator、Transport、 Store及Folder,它们都来自Javamail API顶级包(但开发者需要使用的具体子类可能在javax.mail.internet包内)。可以用这些类完成大量常见的电子邮件任务,包括发送消 息、检索消息、删除消息、认证、回复消息、转发消息、管理附件、处理基于HTML文件格式的消息以及搜索或过滤邮件列表,这类任务主要属于MTA范畴。下 图描绘了Javamail邮件收发过程。
下面给出这七个核心类的简单介绍,以使读者能对Javamail框架有一个大体了解:
6.1 javax.mail.Session
Session类定义了一个基本邮件会话,它是Javamail API最高层入口类,所有其它类都必须经由Session对象才得以生效。Session对象管理配置选项和用于与邮件系统交互的用户认证信息,它使用 java.util.Properties对象获取信息,如邮件服务器、用户名、密码及整个应用程序中共享的其它信息。
Session类的构造器是私有的,它不能被继承,也不能使用new语句来创建实例,但它提供了两个表态方法getInstance和getDefaultInstance来获取Session实例,前者创建一个独立的会话,否则获取缺省的共享会话。
API明细:/javamail-1.4.1/docs/javadocs/javax/mail/Session.html
6.2 javax.mail.Message
获得Session对象后,可以开始继续创建要发送的邮件消息,这由Message类来完成,Message实现了Part接口,它表示一个邮 件消息,包含一系列属性(attribute)和一个消息内容(content)。消息属性标识了消息地址信息,定义了消息内容的结构(包括内容类型); 消息内容使用DataHandler对象包装实际数据。当邮件消息位于目录(folder)中时,系统还使用一个标志位集合来描述它的状态。
Message是抽象类,实际使用时必需用一个子类代替以表示具体的邮件格式。比如说,Javamail API提供了MimeMessage(位于javax.mail.internet.MimeMessage包)类,该类扩展自Message,实现了 RFC822和MIME标准。Message的子类通常通过字节流构建其实例,相应的,它们也可以生成字节流来传输自身。
API明细:/javamail-1.4.1/docs/javadocs/javax/mail/Message.html
6.3 javax.mail.Address
Address类表示电子邮件地址,它是一个抽象类。其子类(最经常使用的子类是javax.mail.internet.InternetAddress)提供具体实现,且通常可串行化。
在创建了Session和Message,并设置了消息内容后,可以用Address确定邮件消息的发送者和接收者地址。
API明细:/javamail-1.4.1/docs/javadocs/javax/mail/Address.html
6.4 javax.mail.Authenticator
Authenticator代表一个可以为网络连接获取认证信息的对象,它通常通过提示用户输入用户名和密码来收集认证信息,使连接可以访问受 保护的资源。对于Javamail API来说,这些资源就是邮件服务器。Javamail Authenticator在javax.mail包中,它和java.net中同名的类Authenticator不同。
要使用Authenticator,必须先创建一个它的子类实例,并且在会话对象创建时为会话注册该Authenticator对象。在需要认 证的时候,就会通知Authenticator。程序可以弹出窗口,也可以从配置文件中(虽然没有加密是不安全的)读取用户名和密码,并使用它们作为构造 函数参数创建一个PasswordAuthentication对象返回给调用程序。
API明细:/javamail-1.4.1/docs/javadocs/javax/mail/Authenticator.html
6.5 javax.mail.Transport
消息发送的最后步骤是使用Transport类。该类使用指定协议发送消息(通常是SMTP)。Transport是抽象类,它的工作方式与 Session有些类似,可以通过静态方法或实例方法发送消息。Transport继承自Service类,而后者提供了很多通用方法,如命名传输、连接 服务器、监听传输事件等等。
API明细:/javamail-1.4.1/docs/javadocs/javax/mail/Transport.html
6.6 javax.mail.Store
Store是一个抽象类,它模拟了消息存储器及其内部目录(Folder)访问协议,以存储和读取消息,其子类提供具体实现。
Store定义的存储器包括一个分层的目录体系,消息存储在目录内,。客户程序可以通过获取一个实现了数据库访问协议的Store对象来访问消息存储器,绝大多数存储器要求用户在访问前提供认证信息,connect方法执行了该认证过程。
Store store = session.getStore("pop3");//指定协议
store.connect(host,usename,password);//
API明细:/javamail-1.4.1/docs/javadocs/javax/mail/Store.html
6.7 javax.mail.Folder
Folder是一个抽象类,用于分级组织邮件,其子类提供针对具体协议的实现。Folder代表的目录可以容纳消息或子目录,存储在目录内的消 息被顺序计数(从1开始到消息总数),该顺序被称为“邮箱顺序”,通常基于邮件消息到达目录的顺序。邮件顺序的变动将改变消息的序列号,这种情况仅发生在 客户程序调用Expunge方法擦除目录内设置了Flags.Flag.DELETED标志位的消息时。执行擦除操作后,目录内消息将重新编号。
客户程序可以通过消息序列号或直接通过相应的Message对象应用目录中的消息,由于消息序列号在会话中很可能改变,因此应尽可能保存Message对象而非序列号来反复引用对象。
连接到Store之后,接下来可以获取一个文件夹(Folder)。该文件夹必须先使用open()方法打开,然后才能读取里面的消息:
Folder folder = store.getDefaultFolder();
//或 : Folder folder = store.getFolder("inbox");
folder.open(Folder.READ_WRITE);
Message message[] = folder.getMessage();
open()方法指定了要打开的文件夹及打开方式(如Folder.READ_WRITE)。 inbox是POP3唯一可以使用的文件夹。如果使用IMAP,还可以用其它的文件夹。获得Message之后,就可以用getContent()获得其 内容,或者用writeTo()将内容写入输出流。getContent()方法之能得到消息内容,而writeTo()的输出却包含消息头.读完邮件之 后要关闭与Folder和Store的连接:
folder.close(aBoolean);
store.close();
API明细:/javamail-1.4.1/docs/javadocs/javax/mail/Folder.html
7 常用Mailet API简介
Mailet主要包含两个包:org.apache.mailet和org.apache.mailet.dates
7.1 org.apache.mailet
此包主要用于匹配器和Mailet的编写。自定义的Mailet类需要继承org.apache.mailet.GenericMailet, 自定义的Matcher类需要继承org.apache.mailet.GenericMatcher或 org.apache.mailet.GenericRecipientMatcher。例子详见第四章Mailet快速入门。
API明细:/MailetSDK/javadocs/org/apache/mailet/package-summary.html
7.2 org.apache.mailet.dates
此包主要用于邮件中的日期格式的转换。
API明细:/MailetSDK/javadocs/org/apache/mailet/dates/package-summary.html
James+Javamail构建邮件服务(五)
电子邮件开发 2009-11-30 10:18:50 阅读33 评论0 字号:大中小
关键字: james javamail mailet java 邮件
8 Javamail的高级应用
8.1 用Javamail实现对邮件的查找
在邮件的高级应用中,当遇到某个帐户中的邮件数非常多的时候,而用户往往只需要对其中的某几封邮件进行处理。倘若要把所有的邮件都取出来,再进 行对应信息的判断提取,这无疑将大大加重邮件服务器的负担。为了改善这种状况,Javamail内部提供了一个专门用于邮件查找的 包:javax.mail.search。这个包将通过对SearchTerm对象进行设置,而后提交给服务器,服务器端有相应的过滤器,根据 SearchTerm对象的设置将邮件过滤的结果传回给客户端。以提高工作效率,减轻服务器端负担。下面就让我们一起来做一个例子说明一下我们应该如何使 用search这个包吧。
8.1.1 业务描述
编写一个类,实现对helloworld@localhost邮件中邮件的条件搜索功能。在本例中实现对主题中包含“测试”,发件人是chenfengcn@localhost,的邮件的搜索。
8.1.2 编码实现
Java代码
package com.newland.javamail.sample1;
import java.util.ArrayList;
import java.util.Properties;
import javax.mail.Folder;
import javax.mail.Message;
import javax.mail.MessagingException;
import javax.mail.NoSuchProviderException;
import javax.mail.Session;
import javax.mail.Store;
import javax.mail.internet.InternetAddress;
import javax.mail.search.AndTerm;
import javax.mail.search.FromTerm;
import javax.mail.search.SearchTerm;
import javax.mail.search.SubjectTerm;
/**
* 使用Javamail的Search包实现对邮件的搜索功能
* @author Chen.Feng(Kevin)<br>
* mail:chenfengcn@yeah.net<br>
* qq:67758633
*
*/
public class SearchMail {
private static ArrayList<SearchTerm> list=new ArrayList();
public static void main(String[] args) {
//用户信息
String user = "helloworld";
String password = "881213";
// 配置服务器属性
Properties props = new Properties();
props.put("mail.smtp.host", "localhost"); // smtp服务器
props.put("mail.smtp.auth", "true"); // 是否smtp认证
props.put("mail.smtp.port", "25"); // 设置smtp端口
props.put("mail.transport.protocol", "smtp"); // 发邮件协议
props.put("mail.store.protocol", "pop3"); // 收邮件协议
//创建会话
Session session = Session.getInstance(props, null);
Store store=null;
try {
//连接Store
store = session.getStore("pop3");
store.connect("localhost", user, password);
//打开Folder
Folder folder = store.getFolder("inbox");
folder.open(Folder.READ_ONLY);
//构造搜索规则
SearchTerm subterm = new SubjectTerm("测试");
SearchTerm fterm = new FromTerm(new InternetAddress("chenfengcn@localhost"));
SearchTerm st=new AndTerm(subterm,fterm);
Message[] message=folder.search(st);
//输出搜索到的邮件的主题
for (int i = 0; i < message.length; i++) {
System.out.println(message[i].getSubject());
}
} catch (NoSuchProviderException e) {
// TODO Auto-generated catch block
e.printStackTrace();
} catch (MessagingException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
}
本例只展示如何使用Javamail的Search包实现对邮件的搜索功能,在实际应用中,Search包中还存在许多功能相当完备的API,若对这部分内容有兴趣可自行参考Javamail API。
API明细:/javamail-1.4.1/docs/javadocs/javax/mail/search/package-frame.html
9 James邮件服务器的高级应用与配置
9.1 配置邮箱域名
配置config.xml文件,文件位于appsjamesSAR-INF目录下。在配置文件中找到:
Java代码
<postmaster>Postmaster@localhost</postmaster>
<servernames autodetect="true" autodetectIP="true">
<!-- CONFIRM? -->
<servername>localhost</servername>
</servernames>
这两项内容,把其中的localhost改成你所要配置的域名即可。
9.2 将用户信息配置为数据库存储方式
James服务器提供了相当完善的配置方案,可选择将用户信息保存在文件、数据库或其他介质中。在默认的情况下,服务器将用户信息以加密形式保存于james-2.3.1appsjames
varusers目录下的文件中。我们可以通过改变其配置信息从而改变用户信息的保存方式。在此仅以MYSQL数据库的配置方式为例说明。
第一步:
将相应数据库的JDBC驱动包复制到lib目录下
即我们需要把mysql-connector-java-3.1.13-bin.jar的MYSQL数据库驱动包复制到james-2.3.1lib目录下
第二步:
新建数据库,建立一个用于存放James用户信息的数据库(表不用建,由James自动创建),在这里,我们假设新建的数据库为mail
第三步:
配置config.xml文件,文件位于appsjamesSAR-INF目录下。打开config.xml,找到以下内容:
Java代码
<repository name="LocalUsers" class="org.apache.james.userrepository.UsersFileRepository">
<destination URL="file://var/users/"/>
? </repository>
把这部分内容修改为:
Java代码
<repository name="LocalUsers" class="org.apache.james.userrepository.JamesUsersJdbcRepository" destinationURL="db://maildb/users">
<sqlFile>file://conf/sqlResources.xml</sqlFile>
</repository>
第四步:
找到MySQL配置位置
Java代码
<!-- Example, connecting to a MySQL database called "mail" on localhost-->
<!-- -->
<!-- The max value is the maximum number of concurrent connections James will -->
<!-- open to this database-->
<!-- If you see "SQLException: Giving up... no connections available." in your -->
<!-- log files or bounced mail you should increase this value -->
<!--
<data-source name="maildb" class="org.apache.james.util.dbcp.JdbcDataSource">
<driver>com.mysql.jdbc.Driver</driver>
<dburl>jdbc:mysql://127.0.0.1/mail?autoReconnect=true</dburl>
<user>username</user>
<password>password</password>
<max>20</max>
</data-source>
-->
首先,去掉data-source标签前后的注释标识(”<!-- -->”),然后按照你的实际情况配置好相应的数据库信息(包括URL、用户名、密码、最大连接数)。然后保存,重新启动James。James会 在数据库中自动创建users表用于存放邮箱的用户信息。这样配置以后,我们除了可以通过telnet操作用户信息外,同样可以通过此users表来操作 用户信息。
值得注意的是,James的用户密码使用的是SHA单向加密算法,若需添加用户或对用户密码进行修改,则会遇到SHA的加密问题。我们应该如何 来解决这个问题呢?查看James的源码中org.apache.james.userrepository包中的DefaultUser.java文 件,我们可以发现,James中提供verifyPassword()和setPassword()两个方法,verifyPassword()是用来做 密码认证的,而setPassword()则是用来实现密码转换的,即将明文密码转换成密文。通过仔细研究这两个方法,可以很容易地实现将自己的密码进行 SHA加密了。
9.3 通过操作数据库实现用户信息操作
在上一节我们讨论了可以将James的用户信息配置到数据库中使用,但会存在SHA加密的问题,在这一节里,我们将讨论如何来解决这个问题,从而真正实现通过操作数据库来操作James服务器的用户信息。
9.3.1 业务描述
本例是基于上一节“将用户信息配置为数据库存储方式”后,通过操作数据库,即:对数据库的信息进行增、删、查、改等操作。本例只实现用户信息的添加,关键在于使用James源码包中提供的SHA加密算法实现用户密码的加密,其余功能跟一般数据库操作无异,故不赘述。
9.3.2 编码实现
用户添加类:AddUserByDB.java
Java代码
package com.newland.james.user.sample1;
import java.security.NoSuchAlgorithmException;
import java.sql.Connection;
import java.sql.DriverManager;
import java.sql.SQLException;
import org.apache.james.security.DigestUtil;
/**
* 通过操作数据库来添加James用户
*
* @author Chen.Feng(Kevin)<br>
* mail:chenfengcn@yeah.net<br>
* qq:67758633
*/
public class AddUserByDB {
public static void main(String[] args) {
// 连接数据库
String driverName = "com.mysql.jdbc.Driver";
String dbURL = "jdbc:mysql://localhost/mail?autoReconnect=true";
String userName = "root";
String userPwd = "881213";
Connection conn = null;
try {
Class.forName(driverName);
conn = DriverManager.getConnection(dbURL, userName, userPwd);
} catch (ClassNotFoundException e) {
e.printStackTrace();
} catch (SQLException e) {
e.printStackTrace();
}
// 构造并执行SQL语句,关键在于DigestUtil.digestString("881213", "SHA"),实现对密码的SHA加密
// 注:用户信息的后四个属性需要使用('SHA',0,NULL,0,null)此四个默认值,若用错,则新建用户可能不能使用
String sql = "";
try {
sql = "insert into users values('hello','"
+ DigestUtil.digestString("881213", "SHA")
+ "','SHA',0,NULL,0,null)";
conn.createStatement().executeUpdate(sql);
conn.close();
System.out.println("用户添加成功");
} catch (NoSuchAlgorithmException e) {
// TODO Auto-generated catch block
e.printStackTrace();
} catch (SQLException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
}
上述程序成功运行后,系统将在数据库添加一条hello用户的记录,那么我们应该如何测试此用户是否真正创建成功并可使用呢?方法有很多,可以使 用前面所述的,通过Telnet命令中的listusers来查看,当然,同样也可以使用Foxmail将此用户添加进去,帐户能正常接收到 Foxmail发送的邮件即表明此用户可正常使用了。
在此例子编写的过程中要注意以下两点:1、用户信息的后四个属性需要使用('SHA',0,NULL,0,null)此四个默认值,若用错,则 新建用户可能不能使用;2、在程序运行过程中,需要使用到james-2.3.1.jar包和相应的数据库驱动包,在程序运行前请确保这些包已添加到相关 的位置。
这里收件箱和发件箱还是用文件存储的,如果你需要检索,你可以再设置为mysql存储
找到<inboxRepository>这一项,此面默认的内容为注释掉
<inboxRepository>
<repository destinationURL="file://var/mail/inboxes/" type="MAIL"/>
</inboxRepository>
找到下面内容去掉注释
<inboxRepository>
<repository destinationURL="db://maildb/inbox/" type="MAIL"/>
</inboxRepository>
9.4 通过Java调用Telnet实现用户信息操作(未完成)
通过前面的介绍,我们可以很方便地通过Telnet或数据库方式来对James的用户信息进行操作,Telnet是相对外部的较慢的方式,如果 我们要实现批量添加或批量修改用户信息,使用外部的Telnet来操作就很难实现了。好在Apache组织提供了在Java里调用Telnet的方法 (即:commons-net-1.4.1.jar包),在此,我们主要展示如何使用Apache的net包实现添加一个James服务器用户,当然,你 同样可以使用此技术进行查询James里的用户、修改用户信息等James的Telnet命令提供的所有功能。
9.4.1 业务描述
本例将展示如何在Java里调用Telnet命令实现James邮件用户的添加。当然,你同样可以使用此技术执行其他可以使用Telnet进行的操作。
9.4.2 编码实现
AddUserByTelnet.java
Java代码
package com.newland.james.user.sample1;
import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
import java.io.OutputStreamWriter;
import java.net.SocketException;
import org.apache.commons.net.telnet.TelnetClient;
/**
* 通过Java调用Telnet命令添加James用户
*
* @author Chen.Feng(Kevin)<br>
* mail:chenfengcn@yeah.net<br>
* qq:67758633
*
*/
public class AddUserByTelnet {
//设置回车换行
public static final String LINE_SEPARATOR = System.getProperties()
.getProperty("line.separator");
public static void main(String[] args) {
BufferedReader m_reader;
OutputStreamWriter m_writer;
TelnetClient m_telnetClient = new TelnetClient();
try {
//设置Telnet超时
m_telnetClient.setDefaultTimeout(1000);
//设置Telnet服务器地址及端口
m_telnetClient.connect("localhost", 4555);
//创建读取缓冲对象
m_reader = new BufferedReader(new InputStreamReader(m_telnetClient
.getInputStream()));
//创建用于发送Telnet命令对象
m_writer = new OutputStreamWriter(m_telnetClient.getOutputStream());
//不断接收登陆成功的信号,超时抛出异常,则跳至一下条代码执行
try {
for (;;) {
System.out.println(m_reader.readLine());
}
} catch (Exception e) {
}
//输入James服务器用户名,此为管理员用户名,而非普通用户,默认为root
m_writer.write("root" + LINE_SEPARATOR);
m_writer.flush();
System.out.println(m_reader.readLine());
//输入root用户密码
m_writer.write("root" + LINE_SEPARATOR);
m_writer.flush();
System.out.println(m_reader.readLine());
//输入Telnet命令添加用户
m_writer.write("adduser helloman 881213" + LINE_SEPARATOR);
m_writer.flush();
System.out.println(m_reader.readLine());
//输出用户列表
m_writer.write("listusers" + LINE_SEPARATOR);
m_writer.flush();
//显示用户列表
try {
for (;;) {
System.out.println(m_reader.readLine());
}
} catch (Exception e) {
}
} catch (SocketException e) {
// TODO Auto-generated catch block
e.printStackTrace();
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
}
10 常见问题与解决
10.1 Javamail常见问题
1、接收或发送邮件时,提示如下报错:
Exception in thread "main" java.lang.NoClassDefFoundError: com/sun/mail/util/LineInputStream
at javax.mail.Session.loadProvidersFromStream(Session.java:928)
at javax.mail.Session.access$000(Session.java:174)
at javax.mail.Session$1.load(Session.java:870)
at javax.mail.Session.loadResource(Session.java:1084)
at javax.mail.Session.loadProviders(Session.java:889)
at javax.mail.Session.<init>(Session.java:210)
at javax.mail.Session.getInstance(Session.java:232)
at com.newland.javamail.sample1.ReceiveMail.main(ReceiveMail.java:41)