James之——添加自定义处理过程

6 篇文章 0 订阅

//————————————————————

修改记录:

2018.06.25 初次发布

//————————————————————

注:文中James是基于2.3.2开发的


Why?

    James提供了信件的收发功能,但是没有提供收发记录的存储,这样不利于对信件和数据的流向进行跟踪,存在风险。

    本文将介绍如何通过添加自定义的处理过程,将James收发信件的记录都存储到一张数据库表中(关于数据量过大,优化问题此处不进行拓展讨论,有兴趣的同学可以研究下)。


What?

    简单介绍下James的处理过程,详情参见James官方文档。

    James的处理过程主要是通过Matcher和Mailet进行匹配、处理的,下面是官方对Mailet和Matcher的介绍。

    原文地址: Mailet API

The Mailet API is a simple API used to build mail processing applications. James is a Mailet container, allowing administrators to deploy Mailets (both custom and pre-made) to carry out a variety of complex mail processing tasks. In the default configuration James uses Mailets to carry out a number of tasks that are carried out deep in the source code of other mail servers (i.e. list processing, remote and local delivery).

As it stands today, the Mailet API defines interfaces for both Matchers and Mailets.

Matchers, as their name would suggest, match mail messages against certain conditions. They return some subset (possibly the entire set) of the original recipients of the message if there is a match. An inherent part of the Matcher contract is that a Matcher should not induce any changes in a message under evaluation.

    可见,James将Matcher匹配上的信件转交给对应的Mailet进行处理,所以,咱们只需要加上自己的Matcher和Mailet即可。

 

How?

1、添加自定义Matcher:

    只需要继承GenericRecipientMatcher并实现匹配方法matchRecipient即可。在org.apache.james.transport包下新加一个MyMatcher类,并继承GenericRecipientMatcher。因为需要对所有的信件添加记录,故所有该方法返回值为true。如下图所示:



2、添加自定义Mailet:

    与Matcher类似,Mailet只需要继承GenericMailet并实现处理方法service即可。

2.1 MyMailet类:

  package org.apache.james.transport.mailets;

  public class MyMailet extends GenericMailet{
    private Log logger = LogFactory.getLog(getClass());
    
    @Override
    public void service(Mail mail) throws MessagingException {
      MimeMessage message = mail.getMessage();
      
      String sender = mail.getSender().toInternetAddress().getAddress();
      String subject = message.getSubject();
      String receiver = StringUtils.join(mail.getRecipients(), ",");
      Date sentDate = message.getSentDate();
      ByteArrayInputStream messageBody = null;
      //获取信件原始报文
      ByteArrayOutputStream baoStream = new ByteArrayOutputStream();
          try {
              message.writeTo(baoStream);
              messageBody = new ByteArrayInputStream(baoStream.toByteArray());
          } catch (IOException e) {
              logger.error("读取邮件原始内容出错", e);
          } catch (MessagingException e) {
              logger.error("读取邮件原始内容出错", e);
          } finally {
              if(baoStream != null){
                  try {
                      baoStream.close();
                  } catch (IOException e) {
                      logger.error("关闭资源失败", e);
                  }
              }
          }
          
          JdbcUtils util = new JdbcUtils();
          boolean success = util.insertLog(subject, sender, receiver, sentDate, messageBody);
          if(!success){
            logger.error("添加收发件记录失败");
          }
    }
  }

2.2 JdbcUtils类:

注:需在项目lib下添加jar包,并完成数据库连接的获取方法:mysql-connector

  /**
   * 获取UUID
   * @return 
   * @author lusq
   */
  public static String getId(){
      String s = UUID.randomUUID().toString();
      return s.substring(0, 8) + s.substring(9, 13) + s.substring(14, 18) + s.substring(19, 23) + s.substring(24);
  }


  /**
   * 添加收发信件记录
   * @param subject 主题
   * @param sender 发件人
   * @param receiver 收件人
   * @param sentDate 发件时间
   * @param messageBody 原始报文
   * @return 是否成功添加记录
   * @author sqlu
   */
  public boolean insertLog(String subject, String sender, String receiver, Date sentDate, ByteArrayInputStream messageBody){
    boolean success = false;
      DruidPooledConnection conn = getConn();
      String sql = "insert ignore into logs (`id`,`subject`,`sender`,`receiver`,`sent_date`,`message_body`) values(?,?,?,?,?,?)";
      
      try {
          this.pst = conn.prepareStatement(sql);
          this.pst.setString(1, JdbcUtils.getId());//获取UUID
          this.pst.setString(2, subject);
          this.pst.setString(3, sender);
          this.pst.setString(4, receiver);
          this.pst.setString(5, new SimpleDateFormat("yyyy-MM-dd HH:mm:ss").format(sentDate));
          //信件原始报文
          this.pst.setBinaryStream(6, messageBody, messageBody.available());
          
          success = this.pst.execute();
      } catch (SQLException e) {
          logger.error("记录邮件日志错误:"+e.getMessage());
      } finally{
          closeConn(conn);
      }
      
      return success;
  }


2.3 建表sql:

CREATE TABLE IF NOT EXISTS `logs`(
  `id` VARCHAR(32) NOT NULL PRIMARY KEY,
  `subject` VARCHAR(256) COMMENT '主题',
  `sender` VARCHAR(256) COMMENT '发件人',
  `receiver` VARCHAR(256) COMMENT '收件人',
  `sent_date` DATETIME COMMENT '发件时间',
  `message_body` LONGBLOB COMMENT '信件原始报文',
  KEY `idx_sender` (`sender`),
  KEY `idx_sent_date` (`sent_date`)
) ENGINE=INNODB DEFAULT CHARSET=utf8 COMMENT '收发信件记录表';


3、构建:

    James-2.3是以ant进行自动化构建的,右击项目的build.xml,选中"Run As",选中第一个"Ant Build",当console中输出下面的内容时,标识构建成功,james.sar文件路径为:dist/james-版本号/apps/james.sar。



4、添加到James处理流程中:

    上面已经准备好了Matcher和Mailet,那怎样才能让James知道在收发件时需要调用它们呢?

    答案是:修改配置文件。

    一开始引入的James官方文档中有这样一句话: 

James is a Mailet container

    Mailet与James的关系是不是似曾相识?有些同学可能已经想到了: Servlet与Tomcat的关系。

    后者通过web.xml进行配置,而前者则通过config.xml进行配置。

    config.xml在项目中的路径为:src/conf/james-config.xml,部署后的路径为:apps\james\SAR-INF\config.xml。

    这里需要注意下:第一次部署(并启动)后会将james.sar解压到当前路径,包括配置文件,以后启动都不会重新解压,存在一个问题:在项目中修改了james-config.xml并重新编译,但是部署之后发现配置"不生效",现在想到的有两种方法:

    1)重新部署前删除掉原先的解压文件夹(因邮箱后缀需要重新配,故不太推荐)

    2)重新部署后,手动修改配置文件(虽然繁琐,但能保证之前的配置不变)

    下面将以第二种方法进行修改配置文件。在部署并启动James后,修改config.xml文件:

    因James不论是收件还是发件,都会先将信件先传递给root这个processor进行处理,所以,只需将配置添加到其节点下即可:



5、校验:

    复制新生成的james.sar到james部署路径下的apps/下,并确认已经修改config.xml。

    启动james,并向其中一个用户发送一封邮件,即可在logs表中看到一条新的记录:





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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值