{"id":80,"date":"2011-09-17T19:22:13","date_gmt":"2011-09-17T17:22:13","guid":{"rendered":"http:\/\/jcoder.me\/blog\/?p=80"},"modified":"2011-11-04T20:05:13","modified_gmt":"2011-11-04T19:05:13","slug":"a-sneak-peek-into-apache-james","status":"publish","type":"post","link":"https:\/\/jcoder.me\/blog\/2011\/09\/17\/a-sneak-peek-into-apache-james\/","title":{"rendered":"A sneak peek into Apache James"},"content":{"rendered":"<p>I&#8217;ve been playing around with <a href=\"http:\/\/james.apache.org\/\" target=\"_blank\">Apache James<\/a>, a complete email server written in Java, in the last few months and I&#8217;d like to share some of my thoughts about it. (I&#8217;ll focus on version 2.3.2 as the 3.0 version is still in beta.)<\/p>\n<p><strong>In short<\/strong><br \/>\nApache James is a flexible, highly configurable and extendable email server (SMTP, POP3, IMAP4 [since James 3.0]). It can store emails and users either in the file system or in a database (e.g. MySQL, PostgreSQL, and others) and handles emails for multiple domains via mappings.<\/p>\n<p><strong>Some insights<\/strong><br \/>\nThere is a comprehensive documentation at the James website including a <a href=\"http:\/\/wiki.apache.org\/james\" target=\"_blank\">wiki<\/a>, so I will not go too much into detail here. Some of the server&#8217;s main concepts are storage, processor, matcher and mailet.<\/p>\n<p><strong>Storage<\/strong><br \/>\nBoth emails and users (and other configuration data) is persisted in the storage. James comes with a filesystem-based and a JDBC-based storage implementation, but other types of storage are possible too (e.g. LDAP, JPA and others, some of them will be provided with version 3.0).<\/p>\n<p><strong>Processor<br \/>\n<\/strong>When\u00a0an incoming email is processed by the server it is injected into a so-called <em>processor<\/em>, which is a kind of queue consisting of actions to be performed on the email. Those actions are performed by the <em>mailets<\/em>.<\/p>\n<p><strong>Mailets<\/strong><br \/>\nA mailet is similar to a servlet in a web container (like Tomcat), but it handles an incoming email instead of an HTTP request. James comes with many ready-to-go mailets, but it is very easy to implement own mailets to perform special tasks.<\/p>\n<p><strong>Matcher<\/strong><br \/>\nA matcher decides if a a mailet will be executed for an incoming email. It checks if a condition is met and tells the email engine to execute the associated mailet.<\/p>\n<p><strong>Making it work all together<\/strong><br \/>\nSounds all a little bit confusing? Actually it isn&#8217;t. This is how everything works together:<\/p>\n<ul>\n<li>The email engine receives an incoming email, wrapping it internally with an container (which provides some helpful functions)<\/li>\n<li>The email engine forwards the the wrapped email to the <em>processor<\/em>\u00a0named &#8220;root&#8221;<\/li>\n<li>The &#8220;root&#8221; processor consists of a sequence of <em>mailets<\/em>, each having a <em>matcher<\/em> associated.<\/li>\n<li>The mailet&#8217;s matcher is executed, returning whether or not the mailet should be executed.<\/li>\n<li>The matcher is then executed (or maybe not). It will &#8220;do something&#8221; with the email, e.g. a virus check, some validation, changing data, forwarding or rejecting or discarding the email, putting it into another processor, or doing some other action.<\/li>\n<li>If the email was not discarded, then the next mailet is processed, then the next, and so on.<\/li>\n<\/ul>\n<p>Actually, there is a lot more going on internally, and in many points I oversimplified things here, but I just to give you a first impression about how James works.<\/p>\n<p><strong>Why is this so great (or useful)?<\/strong><br \/>\nFor me the most interesting point is that you can completely configure and extend the way how an incoming \u00a0email is processed. You can directly interact with an incoming email: you can convert its content or forward it to a custom script or handle it any other way that you can imagine.<\/p>\n<p><strong>One example? Sure!<\/strong><br \/>\nThe following mailet adds support for an address mapping to receive emails with multiple address suffixes into one account: an email address like <code>jcoder+projectone@example.com<\/code><br \/>\nwill become <code>jcoder@example.com<\/code> (and will be delivered to the account &#8220;jcoder&#8221; then.)<\/p>\n<pre class=\"brush: java; title: ; notranslate\" title=\"\">\r\npackage me.jcoder.blog.examples.james.mailet;\r\n\r\nimport java.util.Collection;\r\nimport java.util.Iterator;\r\nimport java.util.LinkedList;\r\nimport javax.mail.MessagingException;\r\nimport org.apache.mailet.GenericMailet;\r\nimport org.apache.mailet.Mail;\r\nimport org.apache.mailet.MailAddress;\r\n\r\n\/**\r\n * Mailet to support the &quot;plus sign alias&quot; syntax in addresses, so that\r\n * name+something@domain becomes name@domain\r\n * @author jCoder\r\n *\/\r\npublic class PlusAliasSupport extends GenericMailet {\r\n    private static final String MAILET_NAME = &quot;PlusAliasSupport&quot;;\r\n\r\n    @Override\r\n    public void service(Mail mail) throws MessagingException {\r\n        if (mail == null) {\r\n            return;\r\n        }\r\n        try {\r\n            Collection recipients = mail.getRecipients();\r\n            Collection recipientsToRemove = new LinkedList();\r\n            Collection recipientsToAdd = new LinkedList();\r\n            for (Iterator itr = recipients.iterator(); itr.hasNext(); ) {\r\n                MailAddress address = (MailAddress)itr.next();\r\n                if (address == null) {\r\n                    continue;\r\n                }\r\n                String localPartStr = address.getUser();\r\n                int plusIndex = -1;\r\n                if ((localPartStr != null) &amp;&amp; ((plusIndex = localPartStr.indexOf('+')) &gt; -1)) {\r\n                    String newLocalPart = localPartStr.substring(0, plusIndex);\r\n                    MailAddress replaceAddress = new MailAddress(newLocalPart, address.getHost());\r\n                    recipientsToRemove.add(address);\r\n                    recipientsToAdd.add(replaceAddress);\r\n                }\r\n            }\r\n            recipients.removeAll(recipientsToRemove);\r\n            recipients.addAll(recipientsToAdd);\r\n        } catch (Exception ex) {\r\n        }\r\n    }\r\n\r\n    @Override\r\n    public String getMailetName() {\r\n        return MAILET_NAME;\r\n    }\r\n}\r\n<\/pre>\n<p>It&#8217;s pretty helpful to get the source code of James to take a lokk at how the provided mailets and matchers are implemented.<\/p>\n<p><strong>Some notes and tipps<\/strong><br \/>\nWhen writing matchers and mailets or running James as your (test) email server, there might be some pitfalls, so I&#8217;ll share some of the points that I came across.<\/p>\n<ul>\n<li>When writing matchers and mailets you might want to download the Mailet SDK from the James website. This is generally a good idea, <strong>but\u00a0make sure that you get the right version!<\/strong>\u00a0James 2.3.2 normally uses the Mailet 2.3 API and the website provides the 2.4 API, so things will not work. If in doubt, add the mailet API-related JARs from a James installation.<\/li>\n<li>When placing the JAR into the <code>${JAMES_DIR}\/apps\/james\/SAR_INF\/lib<\/code> folder, don&#8217;t forget to add your mailet\/matcher package name to the <code>mailetpackages<\/code> \/\u00a0<code>matcherpackages<\/code> section of the <code>config.xml<\/code> file so it can be found by the server.<\/li>\n<li>If you are going to use the JDBC-based storage, you need to put the JDBC driver for your database in a directory where the server can find it. It might not be best-practise, but I suggest to put the JDBC driver JAR into <code>${JAMES_DIR}\/lib<\/code> where it is accessable by the main server.<\/li>\n<li>The same goes for using TLS\/SSL. If you want to provide secure POP3 access, then you not only need a certificate (which is a whole other story to maybe being covered in an other posting), but you might run into some SSL-socket-related errors. One solution is to copy the <code>sunjce_provider.jar<\/code> from your Java runtime into <code>${JAMES_DIR}\/lib<\/code> as well.<\/li>\n<\/ul>\n<div>I hope that this posting gives you a first impression about the flexibility of the email server James. If you have any questions or ideas, feel free to leave a comment.<\/div>\n","protected":false},"excerpt":{"rendered":"<p>I&#8217;ve been playing around with Apache James, a complete email server written in Java, in the last few months and I&#8217;d like to share some of my thoughts about it. (I&#8217;ll focus on version 2.3.2 as the 3.0 version is &hellip; <a href=\"https:\/\/jcoder.me\/blog\/2011\/09\/17\/a-sneak-peek-into-apache-james\/\">Continue reading <span class=\"meta-nav\">&rarr;<\/span><\/a><\/p>\n","protected":false},"author":1,"featured_media":0,"comment_status":"open","ping_status":"open","sticky":false,"template":"","format":"standard","meta":{"footnotes":""},"categories":[1],"tags":[20,19,12,21],"class_list":["post-80","post","type-post","status-publish","format-standard","hentry","category-common","tag-email","tag-james","tag-java","tag-server"],"_links":{"self":[{"href":"https:\/\/jcoder.me\/blog\/wp-json\/wp\/v2\/posts\/80","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/jcoder.me\/blog\/wp-json\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/jcoder.me\/blog\/wp-json\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/jcoder.me\/blog\/wp-json\/wp\/v2\/users\/1"}],"replies":[{"embeddable":true,"href":"https:\/\/jcoder.me\/blog\/wp-json\/wp\/v2\/comments?post=80"}],"version-history":[{"count":7,"href":"https:\/\/jcoder.me\/blog\/wp-json\/wp\/v2\/posts\/80\/revisions"}],"predecessor-version":[{"id":98,"href":"https:\/\/jcoder.me\/blog\/wp-json\/wp\/v2\/posts\/80\/revisions\/98"}],"wp:attachment":[{"href":"https:\/\/jcoder.me\/blog\/wp-json\/wp\/v2\/media?parent=80"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/jcoder.me\/blog\/wp-json\/wp\/v2\/categories?post=80"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/jcoder.me\/blog\/wp-json\/wp\/v2\/tags?post=80"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}