Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
61 changes: 61 additions & 0 deletions examples/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,61 @@
# Examples

This submodule shows how one can work with James.

Each subprojects illustrate a specific concept.

## How to customize mail processing

At the heart of James lies the Mailet container, which allows mail processing. This is splitted into smaller units, with specific responsibilities:

- `Mailets`: Are operations performed with the mail: modifying it, performing a side-effect, etc...
- `Matchers`: Are per-recipient conditions for mailet executions
- `Processors`: Are matcher/mailet pair execution threads

Once we define the mailet container content through the mailetcontailer.xml file. Hence, we can arrange James standard
components to achieve basic logic. But what if our goals are more complex? What if we need our own processing components?

[This example](custom-mailets) shows how to write such components!

## Configure Custom Mailbox Listeners

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 ElasticSearch, updating quota of users, detecting spam emails...)

**Mailbox Listeners** allow customizing the behaviour of James used as a Mail Delivery Agent (MDA).

[This example](custom-listeners) shows how to write such components!

## Configure Custom SMTP hooks

SMTP hooks allow integrating third party systems with the SMTP stack, allows writing additional SMTP extensions, for
instance.

[This example](custom-smtp-hooks) shows how to write such components!

## Configure Custom SMTP commands

This subproject demonstrates how to write custom commands for Apache James SMTP server.

[This example](custom-smtp-command) shows how to write additional SMTP commands!

## Configure Custom WebAdmin routes

The current project demonstrates how to write custom webadmin routes for Apache James. This enables writing new
administrative features exposed over a REST API. This can allow you to write some additional features, make James
interact with third party systems, do advance reporting...

[This example](custom-webadmin-route) shows how to write additional Webadmin routes!

## Write Custom James server assembly

[This example](custom-james-assembly) demonstrates how to write a custom assembly in order to write your own tailor-made server.

This enables:

- Arbitrary composition of technologies (example JPA mailbox with Cassandra user management)
- Write any additional components
- Drop any unneeded component
- You have control on the dependencies and can reduce the classpath size
154 changes: 154 additions & 0 deletions examples/custom-james-assembly/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,154 @@
# Assemble a James server tailored to your needs

Read this page [on the website](http://james.apache.org/howTo/custom-james-assembly.html).

The current project demonstrates how to write a custom assembly in order to write your
own tailor-made server.

This enables:

- Arbitrary composition of technologies (example JPA mailbox with Cassandra user management)
- Write any additional components
- Drop any unneeded component
- You have control on the dependencies and can reduce the classpath size

## Example: Write an IMAP+SMTP only memory server

In order to do this select the modules you wished to assemble [in the Guice building blocks](https://github.com/apache/james-project/tree/master/server/container/guice). We encourage you to have
a fine grain control of your dependencies but for the sake of simplicity this example will reuse the dependencies of an
existing James application:

```
<dependency>
<groupId>${james.groupId}</groupId>
<artifactId>james-server-memory-app</artifactId>
<version>${project.version}</version>
</dependency>
```

Once done assemble the guice modules together in a class implementing `JamesServerMain`:

```
public class CustomJamesServerMain implements JamesServerMain {
public static final Module PROTOCOLS = Modules.combine(
new IMAPServerModule(),
new ProtocolHandlerModule(),
new MailRepositoryTaskSerializationModule(),
new SMTPServerModule());

public static final Module CUSTOM_SERVER_MODULE = Modules.combine(
new MailetProcessingModule(),
new MailboxModule(),
new MemoryDataModule(),
new MemoryEventStoreModule(),
new MemoryMailboxModule(),
new MemoryMailQueueModule(),
new TaskManagerModule(),
new RawPostDequeueDecoratorModule(),
binder -> binder.bind(MailetContainerModule.DefaultProcessorsConfigurationSupplier.class)
.toInstance(BaseHierarchicalConfiguration::new));

public static final Module CUSTOM_SERVER_AGGREGATE_MODULE = Modules.combine(
CUSTOM_SERVER_MODULE,
PROTOCOLS);

public static void main(String[] args) throws Exception {
Configuration configuration = Configuration.builder()
.useWorkingDirectoryEnvProperty()
.build();

JamesServerMain.main(GuiceJamesServer.forConfiguration(configuration)
.combineWith(CUSTOM_SERVER_AGGREGATE_MODULE));
}
}
```

You need to write a minimal main method launching your guice module composition.

We do provide in this example [JIB](https://github.com/GoogleContainerTools/jib/tree/master/jib-maven-plugin) to package this custom James assembly into docker:

```
<plugin>
<groupId>com.google.cloud.tools</groupId>
<artifactId>jib-maven-plugin</artifactId>
<version>2.7.1</version>
<configuration>
<from>
<image>adoptopenjdk:11-jdk-hotspot</image>
</from>
<to>
<image>apache/james</image>
<tags>
<tag>custom-latest</tag>
</tags>
</to>
<container>
<mainClass>org.apache.james.examples.CustomJamesServerMain</mainClass>
<ports>
<port>25</port> <!-- JMAP -->
<port>143</port> <!-- IMAP -->
</ports>
<appRoot>/root</appRoot>
<jvmFlags>
<jvmFlag>-Dlogback.configurationFile=/root/conf/logback.xml</jvmFlag>
<jvmFlag>-Dworking.directory=/root/</jvmFlag>
</jvmFlags>
<creationTime>USE_CURRENT_TIMESTAMP</creationTime>
</container>
<extraDirectories>
<paths>
<path>
<from>sample-configuration</from>
<into>/root/conf</into>
</path>
</paths>
</extraDirectories>
</configuration>
<executions>
<execution>
<goals>
<goal>buildTar</goal>
</goals>
<phase>package</phase>
</execution>
</executions>
</plugin>
```

We provide a minimal [sample configuration](https://github.com/apache/james-project/tree/master/examples/custom-james-assembly/sample-configuration).

You can compile this example project:

```
mvn clean install
```

Create a keystore (default password being `james72laBalle`):

```
keytool -genkey -alias james -keyalg RSA -keystore keystore
```

Import the build result:

```
$ docker load -i target/jib-image.tar
```

Then launch your custom server with docker:

```
docker run \
-v $PWD/keystore:/root/conf/keystore \
-p 25:25 \
-p 143:143 \
-ti \
apache/james:custom-latest
```

You will see that your custom James server starts smoothly:

```
...
09:40:25.884 [INFO ] o.a.j.GuiceJamesServer - JAMES server started
```
98 changes: 98 additions & 0 deletions examples/custom-james-assembly/pom.xml
Original file line number Diff line number Diff line change
@@ -0,0 +1,98 @@
<?xml version="1.0" encoding="UTF-8"?>
<!--
Licensed to the Apache Software Foundation (ASF) under one
or more contributor license agreements. See the NOTICE file
distributed with this work for additional information
regarding copyright ownership. The ASF licenses this file
to you under the Apache License, Version 2.0 (the
"License"); you may not use this file except in compliance
with the License. You may obtain a copy of the License at

http://www.apache.org/licenses/LICENSE-2.0

Unless required by applicable law or agreed to in writing,
software distributed under the License is distributed on an
"AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
KIND, either express or implied. See the License for the
specific language governing permissions and limitations
under the License.
-->
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<parent>
<groupId>org.apache.james.examples</groupId>
<artifactId>examples</artifactId>
<version>3.7.0-SNAPSHOT</version>
</parent>

<artifactId>custom-james-assembly</artifactId>

<name>Apache James :: Examples :: Custom James server assembly</name>
<description>Assemble your own James server tailored to your needs.</description>

<dependencies>
<dependency>
<groupId>${james.groupId}</groupId>
<artifactId>james-server-memory-app</artifactId>
<version>${project.version}</version>
</dependency>
</dependencies>

<build>
<plugins>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-compiler-plugin</artifactId>
<configuration>
<source>11</source>
<target>11</target>
</configuration>
</plugin>
<plugin>
<groupId>com.google.cloud.tools</groupId>
<artifactId>jib-maven-plugin</artifactId>
<version>2.7.1</version>
<configuration>
<from>
<image>adoptopenjdk:11-jdk-hotspot</image>
</from>
<to>
<image>apache/james</image>
<tags>
<tag>custom-latest</tag>
</tags>
</to>
<container>
<mainClass>org.apache.james.examples.CustomJamesServerMain</mainClass>
<ports>
<port>25</port> <!-- JMAP -->
<port>143</port> <!-- IMAP -->
</ports>
<appRoot>/root</appRoot>
<jvmFlags>
<jvmFlag>-Dlogback.configurationFile=/root/conf/logback.xml</jvmFlag>
<jvmFlag>-Dworking.directory=/root/</jvmFlag>
</jvmFlags>
<creationTime>USE_CURRENT_TIMESTAMP</creationTime>
</container>
<extraDirectories>
<paths>
<path>
<from>sample-configuration</from>
<into>/root/conf</into>
</path>
</paths>
</extraDirectories>
</configuration>
<executions>
<execution>
<goals>
<goal>buildTar</goal>
</goals>
<phase>package</phase>
</execution>
</executions>
</plugin>
</plugins>
</build>
</project>
44 changes: 44 additions & 0 deletions examples/custom-james-assembly/sample-configuration/imapserver.xml
Original file line number Diff line number Diff line change
@@ -0,0 +1,44 @@
<?xml version="1.0"?>

<!--
Licensed to the Apache Software Foundation (ASF) under one
or more contributor license agreements. See the NOTICE file
distributed with this work for additional information
regarding copyright ownership. The ASF licenses this file
to you under the Apache License, Version 2.0 (the
"License"); you may not use this file except in compliance
with the License. You may obtain a copy of the License at

http://www.apache.org/licenses/LICENSE-2.0

Unless required by applicable law or agreed to in writing,
software distributed under the License is distributed on an
"AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
KIND, either express or implied. See the License for the
specific language governing permissions and limitations
under the License.
-->

<!-- Read https://james.apache.org/server/config-imap4.html for further details -->


<imapservers>
<imapserver enabled="true">
<jmxName>imapserver</jmxName>
<bind>0.0.0.0:143</bind>
<connectionBacklog>200</connectionBacklog>
<tls socketTLS="false" startTLS="true">
<!-- To create a new keystore execute:
keytool -genkey -alias james -keyalg RSA -keystore /path/to/james/conf/keystore
-->
<keystore>file://conf/keystore</keystore>
<secret>james72laBalle</secret>
<provider>org.bouncycastle.jce.provider.BouncyCastleProvider</provider>
</tls>
<connectionLimit>0</connectionLimit>
<connectionLimitPerIP>0</connectionLimitPerIP>
<idleTimeInterval>120</idleTimeInterval>
<idleTimeIntervalUnit>SECONDS</idleTimeIntervalUnit>
<enableIdle>true</enableIdle>
</imapserver>
</imapservers>
Loading