The Apache Software Foundation

Configure Custom Listeners

This document will help you understand what is Mailbox Listener. Then you will have a chance to implement your own Mailbox Listener and configure it to use it in James server.

  • What is Mailbox Listener
  • How to use a custom Mailbox Listener in James

What is Mailbox Listener

Mailbox Listener is a component in James Mailbox System. Each time an action is applied on a mailbox(adding, deleting), or on an email(adding, deleting, updating flags...), then an event representing that action is generated and delivered to all the Listeners that had been registered before. After receiving events, listeners retrieve information from the events then execute their business (Indexing emails in OpenSearch, updating quota of users, detecting spam emails...)

There are two kinds of Listener registration:

  • Group Registration: a Group Registration will listen for all events fired and will deliver each event only once per group within a distributed topology. That means if there are three listeners registered to the same group, each time an event is fired, only one of these three listeners can receive that event. You can write your own custom Listener and configure James to register it as a Group Registration.
  • Key Registration: a Key Registration will listen only for events it is interested in, and with each event fired to a Key Registration, it will be delivered to all registered listeners. That means if there are three listeners registered to the same key, each time an event is fired, all of three listeners will receive that event. At the moment, James doesn't support to configure custom Listener for Key Registration. This feature is used internally to implement things like IMAP IDLE aka notifications. Therefore, it's not exposed through configurations as it makes little sense

How to use a custom Mailbox Listener in James

prerequisite: custom Mailbox Listeners can only work with James Guice products.

Use the custom SetCustomFlagOnBigMessages in James

Once you have a custom Listener, it's very simple to setup James with that Listener. In this example, we will use the SetCustomFlagOnBigMessages which will listen events fired after emails are appended to users mailboxes, then for each email added event, determine the size of added email by getting size information from the event. If the size of the email is greater than or equals 1 MB, then SetCustomFlagOnBigMessages will add a "BIG_MESSAGE" flag to that email

Starting James with SetCustomFlagOnBigMessages

You can retrieve the sources of this mini-project on GitHub

We will take the simplest James InMemory version for the example

First, we will need to compile our project with mvn clean install. A jar will be outputted in the target directory.

Second, we will write the listeners.xml file expressing the logic we want. In this case, we want to use only the BigMessageListener.


<listeners>
    <listener>
        <class>org.apache.james.examples.custom.listeners.SetCustomFlagOnBigMessages</class>
    </listener>
</listeners>
                

Finally, we will start a James server using that. We will rely on docker default image for simplicity. We need to be using the listeners.xml configuration that we had been writing and position the jar in the extensions-jars folder (specific to guice). This can be achieved with the following command:

docker run -p "25:25" -p "143:143" \
               -v "$PWD/src/main/resources/listeners.xml:/root/conf/listeners.xml" \
               -v "$PWD/target/custom-listeners:/root/extensions-jars/custom-listeners" \
        apache/james:memory-latest --generate-keystore

Verifying the result of the setup

Now that we have a proper James server on our local machine with custom listeners loaded, we are able to use them. To verify our work, here is this simple scenario:

  • Use James CLI to create user1@james.local/password1
  • Use James CLI to create user2@james.local/password2
  • Use a mail client to connect to user1, send a big email to use2
  • Use IMAP command to see the flags of the email user2 had received

Use James CLI to provision users


$ docker exec -it james /bin/bash
$ java -jar james-cli.jar AddUser user1@james.local password1
$ java -jar james-cli.jar AddUser user2@james.local password2
$ exit
                

Use thunderbird or any mail client on your local machine to connect with user1 and user2. The configuration should point to smpt server at localhost:25, and imap server at localhost:143. Use these credentials: user1@james.local/password1 and user2@james.local/password2

After that, use user1@james.local account to sent a big email to user2@james.local, the size of the emails should be greater than 1 MB. One of the simplest ways is to attach a picture bigger than 1MB to the mail.

If the mail client had sent a mail to user2@james.local, then you can see that this email appeared in user2 INBOX. We can see its flags by using the following IMAP command on your local host.


$ openssl s_client -connect localhost:993

# Login by user2
A1 LOGIN user2@james.local password2

# Select user2's INBOX
A1 SELECT INBOX

# Search for all emails in user2's INBOX. The result should be: * SEARCH 1. Where 1 is the UID of the email which had been sent before
A1 UID SEARCH ALL

# Display all flags of that email. The result should be: * 1 FETCH (FLAGS (\Recent \Seen BIG_MESSAGE)). You can see that BIG_MESSAGE has appeared
A1 FETCH 1 (FLAGS)
                

That's it, we are now sure that our SetCustomFlagOnBigMessages worked ! Now that you have learned how to set up a custom Listener, you can follow this setup to add your own !