Implementing a stand alone Email Server – Getting Started with Apache James

7

Using email as a decoupled integration mechanism for applications is a fairly crude and simplistic yet effective approach. Messaging infrastructures – MOM – were all the rage, and still are as part of the ESB architectures and products. The idea is simple: a message sent, it is queued and will be delivered to a receiver. At a simpler and more cost-effective end of the spectrum, Email can be used for much the same purpose. A message is sent and held in an email server. A receiving application can poll the email server for recently received messages, read them and act upon them. One of the attractions of using Email is that most popular programming languages and environments know how to send emails, over the SMTP protocol to email servers anywhere on the internet; SMTP is almost as omnipresent as the HTTP protocol. Take for example the Java Mail API and the Oracle utl_smpt and utl_mail (10g) PL/SQL Packages.

In the second part of a series in which I intend to implement a business process – handling the registration for a conference on SOA and BPEL – using a BPEL Container, I will set up my own specialized mail server for the decoupling of the interaction between my website that allows users to register – also see the first part in this series: Generic Service – HTML Form Post to Email Servlet – and the backoffice process that handles the registration. For this, I will use Apache James, an open source News and Mail Server. Using the Java Mail API we will programmatically check for the arrival of new emails and read their contents.....

Why a stand alone mailserver?

I do not want – and our mail administrator certainly does not want – the email conversations between my applications (in reality service calls) to put additional strain on and clutter up the corporate email server. Besides, having a stand alone mailserver allows me to perform administrative tasks that otherwise I would not have permissions for. In addition, I can perform demonstrations on my laptop without any connection to the outside world – sending and receiving emails locally.

Getting Started with Apache James

1. Go to the home page of Apache James. Here we read: "The Apache Java Enterprise Mail Server (a.k.a. Apache James) is a 100% pure Java SMTP and POP3 Mail server and NNTP News server.
We have designed James to be a complete and portable enterprise mail
engine solution based on currently available open protocols. James is also a mail application platform. We have developed a Java API to let you write Java code to process emails that we call the mailet API. A mailet can generate an automatic reply, update a database, prevent spam, build a message archive, or whatever you can imagine. A matcher
determines whether your mailet should process an email in the server.
The James project hosts the Mailet API, and James provides an
implementation of this mail application platform API." Sounds fine for our purposes.

2. Download the latest stable release: 2.2.0 from http://james.apache.org/download.cgi

Following the instructions on the James Wiki, I try to set up the email server as quickly as I can.

3. Extract the downloaded zip-file to local directory w:\james. Run W:\james\james-2.2.0\bin\run.bat. The console shows:

4. Kill the process (either do kill or ctrl-c or whatever you
want). Starting James once was necessary to extract its directory
structure and expose the configuration files to edit.

5. After shutting down James for the first time, you’ll find a file in the
james-2.1-2/apps/james/SAR-INF folder called config.xml, which you
should take a look at. The first thing you would normally change is the
administrator account, which is set to root, with the password root, by
default. We’ll leave it alone for development but it would be unwise to
leave it configured this way in a production system for obvious
reasons. The next thing to change is usually the DNS server address,
which is necessary if James is to operate as a complete e-mail server.
We’ll leave this alone as well, given that all our tests will be run
from localhost, but again this is an important setting that you should
be aware of. The rest of the default settings are fine, given our
development objectives, though it’s important to understand the
configuration file. You can find more information in the documentation
provided in the james-2.1.2/docs directory.

6. Start James again using bin/run.sh or bin\run.bat. Let’s create a test user. On Windows open a second Command Console. Type: telnet localhost 4555 and login with login id root  and password root. Now we are connected to the James administration console, as the server administrator.

7.  I want to set up the COA mail account, to be used for interaction between the COA-WEB application and the COA-back office. (COA stands for Conference Organization Administration). I type: "adduser coa coa". This creates a new user account for user coa with password coa. Not secure but it will do for development. I then add two more accounts: coa-web and coa-backoffice.

8. Send an email to our new user account. The simplest way to do so is from a telnet session, like this: telnet localhost 25 to open a new telnet session, connect to port 25 – the SMTP port:

 

Note: to end the message, type ENTER followed by the period followed by another ENTER. 

When we take a look at the file system in the James directory structure, we can see that an Inbox is created for the COA user account. It contains the email we just so primitively sent:

Looking in the file reveals the email itself:

 

9. A more refined alternative is for example from Java using the Emailer class from the article Generic Service – HTML Form Post to Email Servlet:

package nl.amis.util;<br /><br />import java.util.Properties;<br /><br />import javax.mail.Address;<br />import javax.mail.Message;<br />import javax.mail.Session;<br />import javax.mail.Transport;<br />import javax.mail.internet.InternetAddress;<br />import javax.mail.internet.MimeMessage;<br /><br /><br />public class EmailSender {<br />    public EmailSender() {<br />    }<br /><br />    public static void sendEmail( String to, String subject, String from, String content) throws Exception{<br />        Properties props = new Properties();<br />        props.setProperty(&quot;mail.transport.protocol&quot;, &quot;smtp&quot;);<br />        props.setProperty(&quot;mail.host&quot;, &quot;localhost&quot;); <br />        props.setProperty(&quot;mail.user&quot;, &quot;coa-web&quot;); <br />        props.setProperty(&quot;mail.password&quot;, &quot;&quot;);<br /><br />        Session mailSession = Session.getDefaultInstance(props, null);<br />        Transport transport = mailSession.getTransport();<br /><br />        MimeMessage message = new MimeMessage(mailSession);<br />        message.addFrom(new Address[] { new InternetAddress(&quot;coa-web@localhost&quot;,from)});  // the reply to email address and a logical descriptor of the sender of the email!<br /><br />        message.setSubject(subject);<br />        message.setContent(content, &quot;text/plain&quot;);<br />        message.addRecipient(Message.RecipientType.TO,<br />             new InternetAddress(to));<br /><br />        transport.connect();<br />        transport.sendMessage(message,<br />            message.getRecipients(Message.RecipientType.TO));<br />        transport.close();<br />        }<br />        <br />        public static void main (String[] args) throws Exception {<br />            String content = &quot;Some test content.&quot;;<br />            EmailSender.sendEmail(&quot;coa-backoffice@localhost&quot;,&quot;An interesting message&quot;,&quot;THE APP&quot;,content);<br />        }<br />   }<br /><br />&nbsp;

10. Now it is all working, I want to step up to the world of the GUI MailClient. Let’s get Thunderbird! 

The Thunderbird Email Client

Thunderbird ( see http://www.mozilla.com/thunderbird/ ) is a free Email Client from the Mozilla Foundation. Its 6.0 Mb download contains an EXE file that can be run to install Thunderbird like a breeze. Thunderbird can be used to access many mail-servers – IMAP and POP protocol – including Microsoft Exchange and Apache James. Note: getting Thunderbird downloaded and installed took less than three minutes. It can import alls kinds of meta-data from my Outlook Client, including contacts, addresses etc. Thunderbird also has support for RSS Feeds and Newsgroups.

You can setup multiple email accounts in Thunderbird. I start by setting up one for the coa-backoffice email account created earlier in James:

 

 

 

Thunderbird now connects to the mailserver@localhost, which is our Apache James instance. It reads out the account information for coa-backoffice, and runs into the email sent earlier from our little Java class EmailSender:

 

Let’s make it a little more interesting. We return to the case introduced in the article Generic Service – HTML Form Post to Email Servlet – the website (just a static HTML Document) that posts a form with Conference Visitor registration details to a servlet that uses the EmaiSender class to send an email to an account on mailserver that is monitored by a back office process. The HTML Form:

 

I made a few trivial changes to the document as it was in the previous article, to have it send the email to the coa-backoffice@localhost address:

<code>          &lt;form action=&quot;http://10.0.0.156:8988/COA_WEB-ViewController-context-root/htmlpost2emailservlet&quot; method=&quot;post&quot;<br />                enctype=&quot;application/x-www-form-urlencoded&quot;&gt;<br />            &lt;input type=&quot;hidden&quot; name=&quot;email_addressee&quot;<br />                   value=&quot;coa-backoffice@localhost&quot;/&gt;<br />            &lt;input type=&quot;hidden&quot; name=&quot;email_subject&quot;<br />                   value=&quot;Conference Registration&quot;/&gt;<br />            &lt;input type=&quot;hidden&quot; name=&quot;email_sender&quot;<br />                   value=&quot;COA-WEB&quot;/&gt;<br /><br /></code>

After submitting the registration form, the following email is found in Thunderbird: 

Programmatically access an email account

So far we have used a very primitive way of inspecing our email account (by browsing the mailserver’s file system) and a very slick way (using the Thunderbird mail client). However, if we want to use email to initiate business processes, we also need programmatic access to the email account. Let’s see how to do that.

Using the article by Claude Dugay, I can quickly develop a class that connects to the James Email-server and reads out the messages in the inbox for the coa-backoffice user:

package nl.amis.util;<br /><br />import java.io.*;<br />import java.util.*;<br />import javax.mail.*;<br />import javax.mail.internet.*;<br /><br /
>public class EmailClient<b
r />  extends Authenticator<br />{<br />  public static final int SHOW_MESSAGES = 1;<br />  public static final int CLEAR_MESSAGES = 2;<br />  public static final int SHOW_AND_CLEAR =<br />    SHOW_MESSAGES + CLEAR_MESSAGES;<br />  <br />  protected String from;<br />  protected Session session;<br />  protected PasswordAuthentication authentication;<br />  <br />  public EmailClient(String user, String host)   {<br />    this(user, host, false);<br />  }<br />  <br />  public EmailClient(String user, String host, boolean debug)  {<br />    from = user + '@' + host;<br />    authentication = new PasswordAuthentication(user, user);<br />    Properties props = new Properties();<br />    props.put(&quot;mail.user&quot;, user);<br />    props.put(&quot;mail.host&quot;, host);<br />    props.put(&quot;mail.debug&quot;, debug ? &quot;true&quot; : &quot;false&quot;);<br />    props.put(&quot;mail.store.protocol&quot;, &quot;pop3&quot;);<br />    props.put(&quot;mail.transport.protocol&quot;, &quot;smtp&quot;);<br />    session = Session.getInstance(props, this);<br />  }<br />  <br />  public PasswordAuthentication getPasswordAuthentication()  {<br />    return authentication;<br />  }<br />   <br />  public void checkInbox(int mode)<br />    throws MessagingException, IOException  {<br />    if (mode == 0) return;<br />    boolean show = (mode &amp; SHOW_MESSAGES) &gt; 0;<br />    boolean clear = (mode &amp; CLEAR_MESSAGES) &gt; 0;<br />    String action =<br />      (show ? &quot;Show&quot; : &quot;&quot;) +<br />      (show &amp;&amp; clear ? &quot; and &quot; : &quot;&quot;) +<br />      (clear ? &quot;Clear&quot; : &quot;&quot;);<br />    System.out.println(action + &quot; INBOX for &quot; + from);<br />    Store store = session.getStore();<br />    store.connect();<br />    Folder root = store.getDefaultFolder();<br />    Folder inbox = root.getFolder(&quot;Inbox&quot;);<br />    inbox.open(Folder.READ_WRITE);<br />    Message[] msgs = inbox.getMessages();<br />    if (msgs.length == 0 &amp;&amp; show)<br />    {<br />      System.out.println(&quot;No messages in inbox&quot;);<br />    }<br />    for (int i = 0; i &lt; msgs.length; i++)<br />    {<br />      MimeMessage msg = (MimeMessage)msgs[i];<br />      if (show)<br />      {<br />        System.out.println(&quot;    From: &quot; + msg.getFrom()[0]);<br />        System.out.println(&quot; Subject: &quot; + msg.getSubject());<br />        System.out.println(&quot; Content: &quot; + msg.getContent());<br />      }<br />      if (clear)<br />      {<br />        msg.setFlag(Flags.Flag.DELETED, true);<br />      }<br />    }<br />    inbox.close(true);<br />    store.close();<br />    System.out.println();<br />  }<br />  public static void main(String[] args) throws Exception{<br />      // CREATE CLIENT INSTANCES<br />      EmailClient emailClient = new EmailClient(&quot;coa-backoffice&quot;, &quot;localhost&quot;, false);<br />         <br />      // LIST MESSAGES FOR email client<br />      emailClient.checkInbox(EmailClient.SHOW_MESSAGES);<br />  }<br />} <br />

The result of running this EmailClient class:

Show INBOX for coa-backoffice@localhost<br />    From: COA-WEB &lt;coa-web@localhost&gt;<br /> Subject: Conference Registration<br /> Content: country=Netherlands<br />email_sender=COA-WEB<br />nomeat=Y<br />telephone=030-6016000<br />Address=Voorweg 146<br />y=45<br />receive_emails=Y<br />postal_code=2716 NK<br />email=jellema@amis.nl<br />email_addressee=coa-backoffice@localhost<br />fax=030-6016001<br />name=Lucas Jellema<br />x=27<br />city=Zoetermeer<br />email_subject=Conference Registration<br /><br />Process exited with exit code 0.<br />

Resources

Working with James, Part 1: An introduction to Apache’s James enterprise e-mail server – Claude Duguay 10 June 2003 on IBM Developer Works

Apache James Wiki – Quickstart

Apache James Home Page

Business Case of the Conference Organisation Administration – Generic Service – HTML Form Post to Email Servlet 

Share.

About Author

Lucas Jellema, active in IT (and with Oracle) since 1994. Oracle ACE Director for Fusion Middleware. Consultant, trainer and instructor on diverse areas including Oracle Database (SQL & PLSQL), Service Oriented Architecture, BPM, ADF, Java in various shapes and forms and many other things. Author of the Oracle Press book: Oracle SOA Suite 11g Handbook. Frequent presenter on conferences such as JavaOne, Oracle OpenWorld, ODTUG Kaleidoscope, Devoxx and OBUG. Presenter for Oracle University Celebrity specials.

7 Comments

  1. when i run your program i get following error with
    i have made appropriate changes like username,etc
    Exception in thread “main” com.sun.mail.smtp.SMTPSendFailedException: 550 The address is not valid.
    ;
    nested exception is:
    com.sun.mail.smtp.SMTPSenderFailedException: 550 The address is not valid.

  2. I recently came across your blog and have been reading along. I thought I would leave my first comment. I don’t know what to say except that I have enjoyed reading. I was searching regarding mail servers and landed here. Although this is an old blog this content is very informative now also. Thanks for the post.

  3. Beautiful article…it got me started with James. Also, the case study being worked out is extremely useful. thanks a lot for sharing these. AMIS rocks!

  4. I had a bit of a problem suddenly with sending emails on my local XP machine – and even with telnet localhost 25.

    I have not been able so far to determine what I have changed in my Windows settings, but I could resolve the issue by changing the port number for the SMTP server. The default port of 25 is protected by Windows; when I changed it to 8765

    (in the file JAMES_HOME\sar-inf\config.xml:

    8765

    )

    and added the line:
    props.setProperty(“mail.smtp.port”, “8765”);
    to my Java Class, I was back in business.

    Lucas

  5. This Article helped me a lot to understand the structure of James email server. Thanks!!