James+java开源项目(2)

5 Javamail邮件存储逻辑简介 
5.1 Message存储结构示意图 
James+Javamail构建邮件服务(二)(转载)
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邮件收发过程。 
James+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

 

8 Javamail的高级应用 
8.1 用Javamail实现对邮件的查找 
  在邮件的高级应用中,当遇到某个帐户中的邮件数非常多的时候,而用户往往只需要对其中的某几封邮件进行处理。倘若要把所有的邮件都取出来,再进行对应信息的判断提取,这无疑将大大加重邮件服务器的负担。为了改善这种状况,Javamail内部提供了一个专门用于邮件查找的包:javax.mail.search。这个包将通过对SearchTerm对象进行设置,而后提交给服务器,服务器端有相应的过滤器,根据SearchTerm对象的设置将邮件过滤的结果传回给客户端。以提高工作效率,减轻服务器端负担。下面就让我们一起来做一个例子说明一下我们应该如何使用search这个包吧。 
8.1.1 业务描述 
  编写一个类,实现对helloworld@localhost邮件中邮件的条件搜索功能。在本例中实现对主题中包含“测试”,发件人是chenfengcn@localhost,的邮件的搜索。 
 

  1. public class SearchMail      
  2.     private static ArrayList list=new ArrayList();      
  3.     public static void main(String[] args)      
  4.         //用户信息      
  5.         String user "helloworld"     
  6.         String password "881213"     
  7.         // 配置服务器属性      
  8.         Properties props new Properties();      
  9.         props.put("mail.smtp.host""localhost"); // smtp服务器      
  10.         props.put("mail.smtp.auth""true"); // 是否smtp认证      
  11.         props.put("mail.smtp.port""25"); // 设置smtp端口      
  12.         props.put("mail.transport.protocol""smtp"); // 发邮件协议      
  13.         props.put("mail.store.protocol""pop3"); // 收邮件协议      
  14.         //创建会话      
  15.         Session session Session.getInstance(props, null);      
  16.         Store store=null     
  17.         try      
  18.             //连接Store      
  19.             store session.getStore("pop3");      
  20.             store.connect("localhost"user, password);      
  21.             //打开Folder      
  22.             Folder folder store.getFolder("inbox");      
  23.             folder.open(Folder.READ_ONLY);      
  24.             //构造搜索规则      
  25.             SearchTerm subterm new SubjectTerm("测试");      
  26.             SearchTerm fterm new FromTerm(new InternetAddress("chenfengcn@localhost"));      
  27.             SearchTerm st=new AndTerm(subterm,fterm);      
  28.             Message[] message=folder.search(st);      
  29.             //输出搜索到的邮件的主题      
  30.             for (int 0message.length; i++)      
  31.                 System.out.println(message[i].getSubject());      
  32.                  
  33.         catch (NoSuchProviderException e)         
  34.             e.printStackTrace();      
  35.         catch (MessagingException e)         
  36.             e.printStackTrace();      
  37.              
  38.          
  39.    
  本例只展示如何使用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文件,文件位于\apps\james\SAR-INF目录下。在配置文件中找到:
 
  1. Postmaster@localhost     
  2. "true" autodetectIP="true"        
  这两项内容,把其中的localhost改成你所要配置的域名即可。 
9.2 将用户信息配置为数据库存储方式 
  James服务器提供了相当完善的配置方案,可选择将用户信息保存在文件、数据库或其他介质中。在默认的情况下,服务器将用户信息以加密形式保存于\james-2.3.1\apps\james 
  \var\users目录下的文件中。我们可以通过改变其配置信息从而改变用户信息的保存方式。在此仅以MYSQL数据库的配置方式为例说明。 
第一步: 
  将相应数据库的JDBC驱动包复制到lib目录下 
即我们需要把mysql-connector-java-3.1.13-bin.jar的MYSQL数据库驱动包复制到\james-2.3.1\lib目录下 
第二步: 
  新建数据库,建立一个用于存放James用户信息的数据库(表不用建,由James自动创建),在这里,我们假设新建的数据库为mail 
第三步: 
  配置config.xml文件,文件位于\apps\james\SAR-INF目录下。打开config.xml,找到以下内容:
Java代码 
  1. "LocalUsers" class="org.apache.james.userrepository.UsersFileRepository"    
  2. "file://var/users/"/>     
  •     
  把这部分内容修改为: 
  1. "LocalUsers" class="org.apache.james.userrepository.JamesUsersJdbcRepository" destinationURL="db://maildb/users"    
  2.     file://conf/sqlResources.xml         
  第四步: 
  找到MySQL配置位置
 
  首先,去掉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 编码实现 
        
  1. public class AddUserByDB      
  2.     public static void main(String[] args)      
  3.         // 连接数据库      
  4.         String driverName "com.mysql.jdbc.Driver"     
  5.         String dbURL "jdbc:mysql://localhost/mail?autoReconnect=true"     
  6.         String userName "root"     
  7.         String userPwd "881213"     
  8.         Connection conn null     
  9.         try      
  10.             Class.forName(driverName);      
  11.             conn DriverManager.getConnection(dbURL, userName, userPwd);      
  12.         catch (ClassNotFoundException e)      
  13.             e.printStackTrace();      
  14.         catch (SQLException e)      
  15.             e.printStackTrace();      
  16.              
  17.         // 构造并执行SQL语句,关键在于DigestUtil.digestString("881213", "SHA"),实现对密码的SHA加密      
  18.         // 注:用户信息的后四个属性需要使用('SHA',0,NULL,0,null)此四个默认值,若用错,则新建用户可能不能使用      
  19.         String sql ""     
  20.         try      
  21.             sql "insert into users values('hello','"     
  22.                     DigestUtil.digestString("881213""SHA"     
  23.                     "','SHA',0,NULL,0,null)"     
  24.             conn.createStatement().executeUpdate(sql);      
  25.             conn.close();      
  26. System.out.println("用户添加成功");      
  27.         catch (NoSuchAlgorithmException e)          
  28.             e.printStackTrace();      
  29.         catch (SQLException e)         
  30.             e.printStackTrace();      
  31.              
  32.          
  33.    
  上述程序成功运行后,系统将在数据库添加一条hello用户的记录,那么我们应该如何测试此用户是否真正创建成功并可使用呢?方法有很多,可以使用前面所述的,通过Telnet命令中的listusers来查看,当然,同样也可以使用Foxmail将此用户添加进去,帐户能正常接收到Foxmail发送的邮件即表明此用户可正常使用了。 
  在此例子编写的过程中要注意以下两点:1、用户信息的后四个属性需要使用('SHA',0,NULL,0,null)此四个默认值,若用错,则新建用户可能不能使用;2、在程序运行过程中,需要使用到james-2.3.1.jar包和相应的数据库驱动包,在程序运行前请确保这些包已添加到相关的位置。 
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 编码实现 
  1. public class AddUserByTelnet      
  2.     //设置回车换行      
  3.     public static final String LINE_SEPARATOR System.getProperties()      
  4.             .getProperty("line.separator");      
  5.     public static void main(String[] args)      
  6.         BufferedReader m_reader;      
  7.         OutputStreamWriter m_writer;      
  8.         TelnetClient m_telnetClient new TelnetClient();      
  9.         try      
  10.             //设置Telnet超时      
  11.             m_telnetClient.setDefaultTimeout(1000);      
  12.             //设置Telnet服务器地址及端口      
  13.             m_telnetClient.connect("localhost"4555);      
  14.             //创建读取缓冲对象      
  15.             m_reader new BufferedReader(new InputStreamReader(m_telnetClient      
  16.                     .getInputStream()));      
  17.             //创建用于发送Telnet命令对象      
  18.             m_writer new OutputStreamWriter(m_telnetClient.getOutputStream());      
  19.             //不断接收登陆成功的信号,超时抛出异常,则跳至一下条代码执行      
  20.             try      
  21.                 for (;;)      
  22.                     System.out.println(m_reader.readLine());      
  23.                      
  24.             catch (Exception e)      
  25.                  
  26.             //输入James服务器用户名,此为管理员用户名,而非普通用户,默认为root      
  27.             m_writer.write("root" LINE_SEPARATOR);      
  28.             m_writer.flush();      
  29.             System.out.println(m_reader.readLine());      
  30.             //输入root用户密码      
  31.             m_writer.write("root" LINE_SEPARATOR);      
  32.             m_writer.flush();      
  33.             System.out.println(m_reader.readLine());      
  34.             //输入Telnet命令添加用户      
  35.             m_writer.write("adduser helloman 881213" LINE_SEPARATOR);      
  36.             m_writer.flush();      
  37.             System.out.println(m_reader.readLine());      
  38.             //输出用户列表      
  39.             m_writer.write("listusers" LINE_SEPARATOR);      
  40.             m_writer.flush();      
  41.             //显示用户列表      
  42.             try      
  43.                 for (;;)      
  44.                     System.out.println(m_reader.readLine());      
  45.                      
  46.             catch (Exception e)      
  47.                  
  48.         catch (SocketException e)        
  49.             e.printStackTrace();      
  50.         catch (IOException e)         
  51.             e.printStackTrace();      
  52.              
  53.          
  54.    
 



  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值