| = Extending server behavior |
| :navtitle: Extending server behavior |
| |
| == Available extension mechanisms |
| |
| image::james-hexagons-extensions.png[Extension mechanisms for the James Server] |
| |
| The James Server exposes several interfaces allowing the user to write custom extensions in |
| order to extend the James Server behavior. |
| |
| Writing *Mailets* and *Matchers* allows one to supply custom components for the |
| xref:mail-processing.adoc[Mail Processing] and |
| enables to take decisions, and implement your business logic at the transport level. |
| |
| Writing xref:mailbox-listeners.adoc[Mailbox listeners] enables to |
| react to your user interaction with their mailbox. This powerful tool allows build advanced features |
| for mail delivery servers. |
| |
| Writing xref:smtp-hooks.adoc[SMTP hookd] enables to |
| add features to your SMTP server. |
| |
| Writing xref:webadmin-routes.adoc[WebAdmin routes] enables to |
| add features to the WebAdmin REST API. |
| |
| Writing xref:imap.adoc[IMAP extensions]. |
| |
| The link:https://github.com/apache/james-project/tree/master/examples[examples] are also a good reference. |
| |
| == Handling injections for your extensions |
| |
| === Injecting core components |
| |
| You can very easily inject core components into your custom extensions. |
| |
| All you need is to pass them via a constructor annotated via *@Inject*. |
| |
| For instance: |
| |
| .... |
| public class MyMailet extends GenericMailet { |
| private final UsersRepository usersRepository; |
| |
| @Inject |
| public MyMailet(UsersRepository usersRepository) { |
| this.usersRepository = usersRepository; |
| } |
| |
| @Override |
| public void service(Mail mail) throws MessagingException { |
| // Do something |
| } |
| } |
| .... |
| |
| === Injecting simple extension components |
| |
| Furthermore, concrete implementation, that are part of your extension, can be injected as well. |
| |
| Consider the following example: |
| |
| .... |
| |
| public class MyService { |
| |
| } |
| |
| public class MyMailet extends GenericMailet { |
| private final MyService myService; |
| |
| @Inject |
| public MyMailet(MyService myService) { |
| this.usersRepository = myService; |
| } |
| |
| @Override |
| public void service(Mail mail) throws MessagingException { |
| // Do something |
| } |
| } |
| .... |
| |
| === Defining custom injections for your extensions |
| |
| However, to inject an interface into your extension, you will need additional injection definitions. |
| |
| To so: |
| |
| * 1. Given an interface defined in an additional JAR: |
| |
| .... |
| public interface MyService {} |
| .... |
| |
| * 2. And an implementation of that interface, in another additional JAR: |
| |
| .... |
| public class MyServiceImpl extends MyService {} |
| .... |
| |
| * 3. We need to define a binding for MyService to be bound to MyServiceImpl |
| |
| .... |
| public class MyServiceModule extends AbstractModule { |
| @Override |
| protected void configure() { |
| bind(MyServiceImpl.class).in(Scopes.SINGLETON); |
| bind(MyService.class).to(MyServiceImpl.class); |
| } |
| } |
| .... |
| |
| Both *MyService*, *MyServiceImpl* and *MyServiceModule* needs to be in the *extensions-jars* |
| folder (potentially different jars). |
| |
| * 4. *MyServiceModule* needs to be registered in xref:distributed/configure/extensions.adoc[*extensions.properties*] |
| |
| * 5. *MyService* can then be used as part of your extensions |
| |
| .... |
| public class MyMailet extends GenericMailet { |
| private final MyService myService; |
| |
| @Inject |
| public MyMailet(MyService myService) { |
| this.usersRepository = myService; |
| } |
| |
| @Override |
| public void service(Mail mail) throws MessagingException { |
| // Do something |
| } |
| } |
| .... |
| |
| Note that overriding injection definitions of the Distributed Server for your injections is not supported. |
| |
| === Starting your components |
| |
| Sometimes you wish to 'start' your extensions. This can be achieved through defining your own `UserDefinedStartable`: |
| |
| ``` |
| public class MyStartable implements UserDefinedStartable { |
| @Override |
| public void start() { |
| // Will be called |
| } |
| } |
| ``` |
| |
| Your startable then needs to be registered within `extensions.properties`: |
| |
| ``` |
| guice.extension.startable=com.company.MyStartable |
| ``` |
| |
| == Pre-packaged extensions |
| |
| === Rate Limiting for mailet processing |
| |
| *Vendor*: Apache Foundation (James project), Apache License V2 |
| |
| link:https://github.com/apache/james-project/tree/master/server/mailet/rate-limiter[Project link] contains detailed set |
| up instructions and configuration examples as well as a pre-configured docker-compose. |
| |
| This extension ships mailets for applying advanced rate limit criteria to the email transiting through your James server. |
| It is shipped with two backends implemented: |
| |
| - *in memory*: For single server mode. |
| - *Redis*: Uses link:https://redis.io/[Redis] as a shared, fast and scalable in-memory datastore, allowing to apply rate |
| limiting in a distributed fashion. Here is the link:https://github.com/apache/james-project/tree/master/server/mailet/rate-limiter[link] to the Redis extension for rate limiting. |
| - Alternative extensions can be written and loaded into James using the xref:index.adoc#_handling_injections_for_your_extensions[Guice extension mechanism] |
| and providing custom injections for the `RateLimiterFactoryProvider` class. |
| |
| This extension ships the following mailets: |
| |
| - `PerSenderRateLimit` allows defining limits applied to the senders of emails (count of email, count of recipients, |
| size, size * recipients) |
| - `PerRecipientRateLimit` allows defining limits applied to the recipients of emails (count of email, size) |
| - `GlobalRateLimit` allows defining limits applied to all the emails (count of email, count of recipients, |
| size, size * recipients) |
| |
| Depending on their positions and the matcher they are being combined with, those rate limiting rules could be applied to |
| submitted emails, received emails or emitted email being relayed to third parties. |
| |
| ==== Throttling |
| Can use combine with `Requeue` mailet for a throttler by re-enqueue mail. |
| link:https://github.com/apache/james-project/tree/master/server/mailet/rate-limiter#throttling[link] |