Apache James(Java Apache Mail Enterprise Server)是Apache组织的子项目之一,完全采用纯Java技术开发,实现了SMTP、POP3与NNTP等多种邮件相关协议.
James也是一个邮件应用平台,可以通过Mailet扩充其功能,如Mail2SMS、Mail2Fax等。James提供了比较完善的配置方案,尤其是关于邮件内容存储和用户信息存储部分,可以选择在文件、数据库或其他介质中保存。
James性能稳定、可配置性强,还是开源项目,所有源代码不存在版权问题,因此,James在项目中的应用日益广泛,现在常用版本为2.1,但最新版本2.3已经推出.
相关信息及下载:http://james.apache.org/
安装配置:
第一步:安装JDK
请使用JDK1.3以上版本(推荐使用JDK1.4),假设安装在c:/jdk1.3
第二步:下载James,并解压
可以到Apache网站上下载james-binary-2.3.1.zip 下载将得到一个压缩文件james-2.3.zip,将此包解压到为d:/james
第三步:直接运行或需要配置JAVA_HOME
这时,可以尝试直接双击d:/james/bin/run.bat,若启动无误,将提示如下:Using PHOENIX_HOME: d:/james
------------------------------------------------------
Using PHOENIX_TMPDIR:d:/james/temp
Using JAVA_HOME:
Phoenix 4.0.1
James 2.3
Remote Manager Service started plain:4555
POP3 Service started plain:110
SMTP Service started plain:25
NNTP Service Disabled
Fetch POP Disabled
-------------------------------------------------------
也有可能启动不了,并报JAVA_HOME找不到,这时,需要指定JAVA_HOME,比较简单的方法是在d:/james/bin/run.bat中指定JAVA_HOME,修改后的run.bat如下:……
------------------------------------------------------
rem
rem Determine if JAVA_HOME is set and if so then use it
rem
set JAVA_HOME= c:/jdk1.3
if not "%JAVA_HOME%"=="" goto found_java
……
------------------------------------------------------
修改完后再运行run.bat,应该就可以正常启动了
服务器端配置
然后打开文件d:/james/apps/james/SAR-INF/config.xml(前提是已运行run.bat将产生此文件!)
在config.xml文件中,找到
<postmaster>Postmaster@localhost</postmaster>
更改为:
<postmaster>Postmaster@test.com</postmaster>
同理,找到
<servername>localhost</servername>
更改为:
<servername>test.com</servername>
名称可以任意起了.(不要忘了增加test.com机器名->C:/WINDOWS/system32/drivers/etc/hosts)
。
帐号管理
James的账号管理是通过telnet完成的,登录命令为:
------------------------------------------------------
telnet test.com 4555
------------------------------------------------------
其中test.com也可以换成IP,4555是端口号。登录时需要用户名和密码,初始的用户名和密码均为root。若登录成功,提示如下:
------------------------------------------------------
JAMES Remote Administration Tool 2.3
Please enter your login and password
Login id:
Password:
Welcome root. HELP for a list of commands
------------------------------------------------------
需要注意的是,所有敲入的命令都不显示在屏幕上。
输入help,将出现命令的帮助,信息如下:
------------------------------------------------------
JAMES Remote Administration Tool 2.1
Please enter your login and password
Login id:
Password:
Welcome root. HELP for a list of commands
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 [alias] [user] locally forwards all email for 'alias' t
o 'user'
unsetalias [alias] unsets an alias
setforwarding [username] [emailaddress] forwards a user's email to another email
address
unsetforwarding [username] removes a forward
user [repositoryname] change to another user repository
shutdown kills the current JVM (convenient when J
ames is run as a daemon)
quit close connection
------------------------------------------------------
常用的命令有listusers、countusers、adduser、deluser、setpassword等。
其中添加用户为adduser,例如:adduser test 123456
通过这个后台管理界面,管理员就可以实现账号管理及其他相应的管理功能
这只是简单的james的配置,想深入学习还得查资料.....
具体代码:
我们在Java开发中,对于发送邮件,Sun给出了JavaMail框架。但是这个框架调用比较复杂,所以出了很多封装来简化使用。比如Spring就对JavaMail进行了封装。今天介绍的是Apache的Common-email组件.
相关信息及下载:http://commons.apache.org/email/
(先添加一个用户:adduser ugly 123456)
package com.hygj.service;
import org.apache.commons.mail.EmailAttachment;
import org.apache.commons.mail.EmailException;
import org.apache.commons.mail.HtmlEmail;
import org.apache.commons.mail.MultiPartEmail;
import org.apache.commons.mail.SimpleEmail;
/**
* 使用 apache开源项目commons-email发送邮件
*
* commons-email是apache提供的一个开源的API,是对javamail的封装,因此在使用时要将javamail.jar加到 class path中,主要包括SimpleEmail,MultiPartEmail,HtmlEmail,EmailAttachment四个类
* SimpleEmail:发送简单的email,不能添加附件
* MultiPartEmail:文本邮件,可以添加多个附件
* HtmlEmail:HTML格式邮件,同时具有MultiPartEmail类所有“功能”
* EmailAttchment:附件类,可以添加本地资源,也可以指定网络上资源,在发送时自动将网络上资源下载发送
*
* @author 徐嘉伟
* Email: [email=[ft=,2,Verdana]auglyboy@163.cn]auglyboy@163.cn[/email]
*/
public class MailService {
/**
* 简单邮件测试类
*/
public void sendSimpleMail(){
//创建单一邮件对象
SimpleEmail email = new SimpleEmail();
//设置服务器
email.setHostName("test.com");
try {
//设置发送人
email.setFrom("[email=[ft=,2,Verdana]ugly@test.com]ugly@test.com[/email]", "ugly");
//设置接收人
email.addTo("[email=[ft=,2,Verdana]ugly@test.com]ugly@test.com[/email]", "ugly");
//用户验证
email.setAuthentication("ugly", "123456");
//设置邮件主题
email.setSubject("james使用");
//设置邮件内容
email.setMsg("This is a test mail!");
//发送
email.send();
} catch (EmailException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
/**
* 发送带有附件的邮件信息
*/
public void sendMultiPartMail(){
//创建附件邮件对象
MultiPartEmail multipartMail = new MultiPartEmail();
multipartMail.setHostName("test.com");
//创建一个附件(附件可以是一个本地路径也可以是一个网络url)
EmailAttachment emailAttachment = new EmailAttachment();
emailAttachment.setPath("f://附件.rar");
emailAttachment.setDescription(EmailAttachment.ATTACHMENT);
emailAttachment.setDescription("This is a attach test!");
//设置附件名称(一定要加上附件类型后缀否则会出现乱码)
//emailAttachment.setName("我是附件");
try {
multipartMail.setFrom("[email=[ft=,2,Verdana]ugly@test.com]ugly@test.com[/email]", "ugly");
multipartMail.addTo("[email=[ft=,2,Verdana]ugly@test.com]ugly@test.com[/email]", "ugly");
multipartMail.setAuthentication("ugly", "123456");
multipartMail.setSubject("附件邮件测试信息");
multipartMail.setMsg("存在附件呀");
//添加附件
multipartMail.attach(emailAttachment);
//发送
multipartMail.send();
} catch (Exception e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
/**
* 发送html格式且带有附件的邮件信息
*/
public void sendHtmlEmail(){
//创建html格式的邮件对象
HtmlEmail htmlEmail = new HtmlEmail();
htmlEmail.setHostName("test.com");
//创建一个附件
EmailAttachment emailAttachment = new EmailAttachment();
emailAttachment.setPath("f://附件.rar");
emailAttachment.setDescription(EmailAttachment.ATTACHMENT);
emailAttachment.setDescription("This is a attach test!");
emailAttachment.setName("attach.rar");
try {
htmlEmail.setFrom("ugly[email=[ft=,2,Verdana]@test.com]u@test.com[/email]", "first");
htmlEmail.addTo("ugly[email=[ft=,2,Verdana]@test.com]u@test.com[/email]", "first");
htmlEmail.setSubject("发送html格式的邮件信息");
htmlEmail.setHtmlMsg("<h1>Hello World!</h1>");
//加附件
htmlEmail.attach(emailAttachment);
htmlEmail.send();
} catch (EmailException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
/**
* @param args
*/
public static void main(String[] args) {
// TODO Auto-generated method stub
new MailService().sendHtmlEmail();
}
}
--------------------------------------------------------------------------------------------------
基本是实现了本地邮件的发送,当然你会问,能不能用james给外网(163,126,yahoo..)发邮件呢?
答案是肯定可以,修改config.xml呀。
----配置外网邮件发送----
找到并打开../james-2.3.2/apps/james/SAR-INF/config.xml文件
1. 找到<servernames autodetect="true" autodetectIP="true">
设成autodetect="false" autodetectIP="false"> autodetct设为true会自动侦测你的主机名,
设成false会用你指定的server name. autodetectIP设为true会为你的servername加上ip.
2. 设置servername 将默认的为localhost改成你的server名字 如king.cn, 然后打开
C:/WINDOWS/system32/drivers/etc/hosts文件,添加 127.0.0.1 test.com
3. 注释掉
<mailet match="RemoteAddrNotInNetwork=127.0.0.1" class="ToProcessor">
<processor> relay-denied </processor>
<notice>550 - Requested action not taken: relaying denied</notice>
</mailet>
4. 配置DNS Server
在cmd中用ipconfig /all 命令查看你的dns server ip
DNS Servers . . . . . . . . . . . : 202.96.209.6
192.168.1.1
查找并修改处信息
<dnsserver>
<servers>
<!--Enter ip address of your DNS server, one IP address per server -->
<server>127.0.0.1</server>
<server>202.102.152.3</server>
</servers>
<!-- Change autodiscover to false if you would like to turn off autodiscovery -->
<!-- and set the DNS servers manually in the <servers> section -->
<autodiscover>false</autodiscover>
<authoritative>false</authoritative>
<!-- Maximum number of entries to maintain in the DNS cache -->
<maxcachesize>50000</maxcachesize>
</dnsserver>
同时设置autodiscover为false
5.重启server
----用户名密码加密问题-----
通过telnet添加新用户时,比如adduser holen 123456,你可以查看数据库中的记录,第一个字段是holen,第二字段是密码,但密码并非123456,而一串“乱码”(zhwQUMTwdMqWfm/h0biB51Gf)——这是加密码后的密码内容,再看后面的字段是“SHA”,显然用的是SHA加密方式。
通过telnet方式添加新用户,用户密码将自动加密,然后插入数据库中。但通过telnet方式进行用户管理有着诸多不便,尽管你可以借助James的一个RMI工具包,提高效率,但仍然没有本质改变,当需要用作商业用途时,你更不能要求你的客户熟记那一堆命令符。
一般我们可以做一个Web前端,通过网页形式,添加修改用户,界面友好,傻瓜化使用,如263或163一样。若这样做,我们就需要直接操作数据库,添加用户记录或修改删除用户记录了。但别忘了,James默认对用户密码是加密的,既然我们要直接操作数据库,那么我们只有两个选择:要么我们研究其密码机制,添加记录时,我们对新增用户的密码进行同样加密,要么我们去掉James的加密机制,使其明码保存。
这两种选择都是可行的。我们从Apache网站下载James的源码包,下载后的文件为james-src.zip,通过分析源码,我们发现,与用户密码相关的文件是DefaultUser.java,部分源码如下:
package org.apache.james.userrepository;
/**
* Method to verify passwords.
*
* @param pass the String that is claimed to be the password for this user
* @return true if the hash of pass with the current algorithm matches
* the stored hash.
*/
public boolean verifyPassword(String pass) {
try {
String hashGuess = DigestUtil.digestString(pass, algorithm);
return hashedPassword.equals(hashGuess);
} catch (NoSuchAlgorithmException nsae) {
throw new RuntimeException("Security error: " + nsae);
}
}
/**
* Sets new password from String. No checks made on guessability of
* password.
*
* @param newPass the String that is the new password.
* @return true if newPass successfuly hashed
*/
public boolean setPassword(String newPass) {
try {
hashedPassword = DigestUtil.digestString(newPass, algorithm);
return true;
} catch (NoSuchAlgorithmException nsae) {
throw new RuntimeException("Security error: " + nsae);
}
}
第一个方法verifyPassword()是用来做密码认证,传入的参数是明文密码,通过DigestUtil.digestString()方法,转换成密文密码,然后与数据库中密码作比较,返回比较结果。请注意这里的DigestUtil.digestString()方法,在后面还在提到。
第二个方法setPassword()是用于密码转换的,把明文转成密文,用的同样是DigestUtil.digestString()方法。
谈到这里,相信你应该知道怎么在自己的程序中进行密码转换和密码认证了吧!其实并不是要你自己去写一个SHA的加密算法,既然James已经提供了此功能,你调用便是了。
应该注意的是,用上面的方法应当先导入james.jar、mail.jar(james-2.3.2/work/james-1252566991062/SAR-INF/lib),否则报错啦!
代码如下:
package com.xyl.test;
import java.security.NoSuchAlgorithmException;
import java.util.logging.Level;
import java.util.logging.Logger;
import org.apache.james.security.DigestUtil;
/**
* 实现james加密
* @author Xu-yan-li
*/
public class Test {
public static void main(String[] args){
try {
String pwd = DigestUtil.digestString("123456789", "SHA");//密码SHA加密
System.out.println(pwd+"==================================================");
} catch (NoSuchAlgorithmException ex) {
Logger.getLogger(Test.class.getName()).log(Level.SEVERE, null, ex);
}
}
}
还有一种情况,开发者需要在数据库中必须用明文保存密码,这样就不必在自己写的程序中进行密码转换了,而且当多个应用系统采用统一用户模型时,最好只有一个用户实例。要实现这个需求,就只能修改James源代码了,把verifyPassword()方法和setPassword()改成:
public boolean verifyPassword(String pass) {
return hashedPassword.equals(pass);
}
public boolean setPassword(String newPass) {
hashedPassword = newPass;
return true;
}
其实就是把转换过程去掉,保存和认证就都采用明文进行了。
你要是觉得SHA方式不妥,也可以挂接别的加密方式,同样是修改这两个方法。
注意,当你修改了James的源码后,你需要用Ant重新build James项目,build后将在james-2.1-src/dist/james-2.1/apps下面找到新生成的james.sar文件。把该文件覆盖James原来james.sar,并删除与james.sar同级的james目录,重启动james即可。建议保留原来的config.xml,免得又配一次。
通过以上探讨,我们明白了如何通过Web方式进行用户注册和用户登记等。需要说明一点是,James自动生成的users表中只有7个字段,而且都是系统需要使用的。一般注册时需要输入的信息项比较多,这时建议开发者自己再建一个新表USERINFO,用username把两个表关联起来,不建议修改users表的内容(如果想试试,请参考file &://conf/sqlResources.xml)。