blob: fcc44f699b14ee190c27454307c673eb7bccf52a [file]
= 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]