《Maven实战》与本地邮件服务器

并非在研究邮件服务器实现,这两天学习用Maven,看的《Maven实战》,里面用到的邮件的代码不知咋测试,搜了下本地邮件服务器,参考下面文章,启动JAMES后,添加用户,然后就可以测试书上的代码了。有个错误是因为开着Avast导致的,不清楚为啥,反正禁用了Avast就通过了。文章写得比较早,有的代码用不起来,我做了些许改动。里面有的需要jar包,可通过Maven依赖导入。JAMES已有3.0版本,所以文章仍似乎有点过时了,暂时不管。

用JAMES实现自己的邮件服务器

简介

James是一个企业级的邮件服务器,它完全实现了smtp和pops以及nntp协议。同时,james服务器又是一个邮件应用程序平台。James的核心是Mailet API,而james服务器是一个mailet的容器。它可以让你非常容易的实现出很强大的邮件应用程序。James开源项目被广泛的应用于与邮件有关的项目中。你可以通过它来搭建自己的邮件服务器。我们可以利用Mailet API编程接口来实现自己所需的业务。James集成了Avalon应用程序框架以及Phoenix Avalon框架容器。Phoenix为james服务器提供了强大的支持。需要说明的是Avalon开源项目目前已经关闭。

快速上手

安装james

我这次使用的安装包是james 2.3.2大家可以从这里下载到。

现在让我们开始我们激动人心的james之旅。首先我们将james-binary-2.3.2.zip解压缩到你的安装目录。我们可以把这个过程理解为安装的过程。我在这里将它解压到D:\.这样我们的james就安装好了。目录为D:\james-2.3.2

准备知识 - 学习一些必要的知识

在我使用james的时候让我感觉首先理解james的应用程序结构是很重要的。否则你会在使用中感到很困惑。

它的应用程序结构是这样的:

James
  |__ apps
  |__ bin
  |__ conf
  |__ ext
  |__ lib
  |__ logs
  |__ tools

我们重点介绍一下两个文件夹bin和apps。

bin目录中的run.bat和run.sh是James的启动程序。只要记住这个重要文件就可以。

启动之后控制台显示如下:

Using PHOENIX_HOME:   D:\james-2.3.2
Using PHOENIX_TMPDIR: D:\james-2.3.2\temp
Using JAVA_HOME:      C:\Program Files\Java\jdk1.7.0_17
Phoenix 4.2
James Mail Server 2.3.2
Remote Manager Service started plain:4555
POP3 Service started plain:110
SMTP Service started plain:25
NNTP Service started plain:119
FetchMail Disabled

Apps目录下有个james的子目录这个目录是它的核心。

james
|__ SAR-INF
|__ conf
|__ logs
|__ var
    |__ mail
      |__ address-error
      |__ error
      |__ indexes
      |__ outgoing
      |__ relay-denied
      |__ spam
      |__ spool
    |__ nntp
      |__ ....
    |__ users

SAR-INF下有一个config.xml是james中的核心配置文件。

logs包含了与james有关的log。调试全靠它了。

var 包含了一些文件夹通过它们的名字我们大概也能猜测出它们的用途。

mail 主要用于存储邮件。nntp主要用于新闻服务器。

users用于存储所有邮件服务器的用户。也就是邮件地址前面的东东。如:[email protected]的pig就是所谓用户。

创建用户

我们在James上建若干用户,用来测试收发邮件。当然如果你不用james本身的用户也可以。James以telnet的方式提供了接口用来添加用户。下面我来演示一下。

首先使用telnet来连接james的remote manager。

1.telnet localhost 4555 回车
2.然后输入管理员用户名和密码(user/pwd:root/root 是默认设置,这个可以在config.xml中修改)

JAMES Remote Administration Tool 2.3.2
Please enter your login and password
Login id:
root
Password:
root
Welcome root. HELP for a list of commands

3.添加用户

adduser test1 123456
User test1 added
adduser test2 123456
User test2 added
adduser test3 123456
User test3 added

4.查看添加情况

listusers
Existing accounts 3
user: test1
user: test2

得到上面的信息说明我们已经添加成功。

发送器

这个类主要用来测试我们的邮件服务器,可以不用将其打入包中。

import java.util.Date;
import java.util.Properties;

import javax.mail.Authenticator;
import javax.mail.Message;
import javax.mail.PasswordAuthentication;
import javax.mail.Session;
import javax.mail.Transport;
import javax.mail.internet.InternetAddress;
import javax.mail.internet.MimeMessage;

public class Mail {
  private String mailServer, from, to, mailSubject, mailContent;
  private String username, password;
  private Session mailSession;
  private Properties prop;
  private Message message;

  // Authenticator auth;//认证
  public Mail() {
    // 设置邮件相关
    username = "test1";
    password = "123456";
    mailServer = "localhost";
    from = "test1@localhost";
    to = "test2@localhost";
    mailSubject = "Hello Scientist";
    mailContent = "How are you today!";
  }

  public void send() {
    EmailAuthenticator mailauth = new EmailAuthenticator(username, password);
    // 设置邮件服务器
    prop = new Properties();
    prop.put("mail.smtp.auth", "true");
    prop.put("mail.smtp.host", mailServer);
    // 产生新的Session服务
    mailSession = mailSession.getDefaultInstance(prop,
        (Authenticator) mailauth);
    message = new MimeMessage(mailSession);

    try {
      message.setFrom(new InternetAddress(from)); // 设置发件人
      message.setRecipient(Message.RecipientType.TO, new InternetAddress(
          to));// 设置收件人
      message.setSubject(mailSubject);// 设置主题
      message.setContent(mailContent, "text/plain");// 设置内容
      message.setSentDate(new Date());// 设置日期
      Transport tran = mailSession.getTransport("smtp");
      tran.connect(mailServer, username, password);
      tran.send(message, message.getAllRecipients());
      tran.close();
    } catch (Exception e) {
      e.printStackTrace();
    }
  }

  public static void main(String[] args) {
    Mail mail;
    mail = new Mail();
    System.out.println("sending......");
    mail.send();
    System.out.println("finished!");
  }
}

class EmailAuthenticator extends Authenticator {
  private String m_username = null;
  private String m_userpass = null;

  void setUsername(String username) {
    m_username = username;
  }

  void setUserpass(String userpass) {
    m_userpass = userpass;
  }

  public EmailAuthenticator(String username, String userpass) {
    super();
    setUsername(username);
    setUserpass(userpass);
  }

  public PasswordAuthentication getPasswordAuthentication() {
    return new PasswordAuthentication(m_username, m_userpass);
  }
}

实现-Matcher和Mailet编写

我先解释一下大概的流程:当james接收到一个smtp请求时首先会交给matcher来进行一系列过滤动作。然后由matcher交给相应的mailet来进行处理。James就相当于一个matcher和mailet的容器。就像tomcat之于servlet。而mailet和servlet很是相似。

我们这里要完成的功能很简单,就是当james邮件服务器接收到邮件后把发送者和邮件正文打印到控制台。我们分析这个需求发现我们需要写一个matcher以及一个mailet。matcher用来过滤,而mailet用来将邮件内容打印到控制台。为了简单起见,我这次只是继承了GenericMailet和GenericRecipientMatcher两个已经实现的mailet和matcher。具体的Matcher和Mailet的使用我以后会整理成另外一篇文章。

Matcher的实现

package com.zoey.james.mail;

import javax.mail.MessagingException;

import org.apache.mailet.MailAddress;
import org.apache.mailet.base.GenericRecipientMatcher;

/**
 * System jamesstudy Package com.yy.jamesstudy
 * 
 * @author Yang Yang Created on 2007-9-14下午02:17:07
 */
public class BizMatcher extends GenericRecipientMatcher {

  public boolean matchRecipient(MailAddress recipient)
      throws MessagingException {
    // 只接受邮件地址包含鸣人的邮件
    if (recipient.getUser().indexOf("test1") != -1) {
      return true;
    }
    return false;
  }
}

GenericRecipientMatcher是一个针对收件人进行过滤的matcher。

Mailet的实现

import java.io.IOException;

import javax.mail.MessagingException;
import javax.mail.internet.MimeMessage;

import org.apache.mailet.Mail;
import org.apache.mailet.MailAddress;
import org.apache.mailet.base.GenericMailet;

/**
 * System jamesstudy Package com.yy.jamesstudy
 * 
 * @author Yang Yang Created on 2007-9-14下午02:16:31
 */
public class BizMaillet extends GenericMailet {
  public void service(Mail mail) {
    MailAddress ma = mail.getSender();
    System.out.println("sender:" + ma.toInternetAddress().toString());
    try {
      MimeMessage mm = mail.getMessage();
      System.out.println("content:" + (String) mm.getContent().toString());
    } catch (IOException e) {
      e.printStackTrace();
    } catch (MessagingException e) {
      e.printStackTrace();
    }
  }
}

GenericMailet是一个mailet的基本实现。

编译

我们把这两个java文件的class文件编译成一个名字为:jamesstudy.jar的jar文件。

发布-Matcher和Mailet以及config.xml

1.发布jar文件

我们把这个jar文件发布到D:\james-2.3.2\apps\james\SAR-INF\lib

注意:如果没有找到相关目录,则需要先启动一遍james,相关的文件夹才会被创建。还有一点需要特别说明:lib目录是通过我们手动创建的。

2.将Matcher和Mailet发布到config.xml中,config.xml在james-2.3.2\apps\james\SAR-INF\下

1)我们首先找到如下内容

<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>

2)加入包声明

<mailetpackages>
  <mailetpackage>com.yy.jamesstudy</mailetpackage>
  <mailetpackage>org.apache.james.transport.mailets</mailetpackage>
  <mailetpackage>org.apache.james.transport.mailets.smime</mailetpackage>
</mailetpackage>
<matcherpackages>
  <matcherpackage>com.yy.jamesstudy</mailetpackage>
  <matcherpackage>org.apache.james.transport.matchers</mailetpackage>
  <matcherpackage>org.apache.james.transport.matchers.smime</mailetpackage>
</mailetpackage>

3)加入Matcher和Mailet的关联关系

找到<processor name="root"></processor>元素在它的下面加入

<mailet match="BizMatcher" class="BizMaillet"/>

Mailet元素代表了一个matcher和一个mailet的组合。Match属性:是指matcher的类名。而class属性:是指mailet的类名。

最后别忘了,保存退出。并且重新启动james服务器。

测试- 验证我们的mail应用程序

我们主要通过mail类来测试我们的应用。还记得我们刚才写的那个mail类吗?!在那个类中我们初始化了相关的信息.

username = "test1";
password = "123456";
mailServer = "localhost";
From = "test1@localhost";
To = "test2@localhost";
mailSubject = "Hello Scientist";
MailContent = "How are you today!";

发件人是test1,收件人是test2.

这两个用户我们在前面都已经创建完毕。我们用他们来测试james的邮件收发以及mailet api的应用。

根据需求假设我们发给james服务器(这里是james的默认配置:localhost)的邮件的收件人是鸣人。那么我们就能通过matcher监测到这封邮件,并且调用相应的mailet来进行处理。由mailet打印出相应的邮件发送者和正文。运行Mail类后得到:

Using PHOENIX_HOME:   D:\james-2.3.2
Using PHOENIX_TMPDIR: D:\james-2.3.2\temp
Using JAVA_HOME:      C:\Program Files\Java\jdk1.7.0_17
Phoenix 4.2
James Mail Server 2.3.2
Remote Manager Service started plain:4555
POP3 Service started plain:110
SMTP Service started plain:25
NNTP Service started plain:119
FetchMail Disabled

sender:kakaxi@localhost
content:How are you today!

总结

最终我们看到发送者和正文的信息。That’s all ! 大功告成。

其实james的功能是非常非常强大的,尤其是它的Mailet API能够帮助我们完成很多与邮件有关的工作如过滤垃圾邮件。用它我们甚至可以搭建我们自己的企业邮件服务器。我们最近的项目中就使用到了。我们通过james接收到的邮件,然后用matcher找到我们想要处理的邮件,然后通过mailet做一些业务上的处理。这篇文章涵盖的面很小。如果大家有兴趣可以研究一下james项目。Config.xml实际上是最重要的文件,如果你把它研究透彻了那么就算把Mailet API研究透了。以后我可能会写一篇相关的文章,在这就不多说了。希望这篇文章能够对大家有所启发!有所帮助!祝大家工作顺利!

你可能感兴趣的:(《Maven实战》与本地邮件服务器)