blob: 88665891dac62f47a704efcc0c17f431eaf9bc46 [file] [log] [blame]
<?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.
-->
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<!-- Generated by Apache Maven Doxia at 2021-11-12 -->
<html xmlns="http://www.w3.org/1999/xhtml" xml:lang="en" lang="en">
<head>
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8" />
<title>Apache James Project &#x2013; Apache James Server 3 - Writing a Custom Mailet</title>
<style type="text/css" media="all">
@import url("../css/james.css");
@import url("../css/maven-base.css");
@import url("../css/maven-theme.css");
@import url("../css/site.css");
@import url("../js/jquery/css/custom-theme/jquery-ui-1.8.5.custom.css");
@import url("../js/jquery/css/print.css");
@import url("../js/fancybox/jquery.fancybox-1.3.4.css");
</style>
<script type="text/javascript" src="../js/jquery/js/jquery-1.4.2.min.js"></script>
<script type="text/javascript" src="../js/jquery/js/jquery-ui-1.8.5.custom.min.js"></script>
<script type="text/javascript" src="../js/fancybox/jquery.fancybox-1.3.4.js"></script>
<link rel="stylesheet" href="../css/print.css" type="text/css" media="print" />
<meta name="Date-Revision-yyyymmdd" content="20211112" />
<meta http-equiv="Content-Language" content="en" />
<!-- Google Analytics -->
<script type="text/javascript">
var _gaq = _gaq || [];
_gaq.push(['_setAccount', 'UA-1384591-1']);
_gaq.push(['_trackPageview']);
(function() {
var ga = document.createElement('script'); ga.type = 'text/javascript'; ga.async = true;
ga.src = ('https:' == document.location.protocol ? 'https://ssl' : 'http://www') + '.google-analytics.com/ga.js';
var s = document.getElementsByTagName('script').item(0); s.parentNode.insertBefore(ga, s);
})();
</script>
</head>
<body class="composite">
<div id="banner">
<a href="../index.html" id="bannerLeft" title="james-logo.png">
<img src="../images/logos/james-logo.png" alt="James Project" />
</a>
<a href="https://www.apache.org/index.html" id="bannerRight">
<img src="images/logos/asf_logo_small.png" alt="The Apache Software Foundation" />
</a>
<div class="clear">
<hr/>
</div>
</div>
<div id="breadcrumbs">
<div class="xleft">
<span id="publishDate">Last Published: 2021-11-12</span>
</div>
<div class="xright"> <a href="../index.html" title="Home">Home</a>
|
<a href="../documentation.html" title="James">James</a>
|
<a href="../mime4j/index.html" title="Mime4J">Mime4J</a>
|
<a href="../jsieve/index.html" title="jSieve">jSieve</a>
|
<a href="../jspf/index.html" title="jSPF">jSPF</a>
|
<a href="../jdkim/index.html" title="jDKIM">jDKIM</a>
</div>
<div class="clear">
<hr/>
</div>
</div>
<div id="leftColumn">
<div id="navcolumn">
<h5>James components</h5>
<ul>
<li class="collapsed">
<a href="../documentation.html" title="About James">About James</a>
</li>
<li class="expanded">
<a href="../server/index.html" title="Server">Server</a>
<ul>
<li class="none">
<a href="../server/advantages.html" title="Advantages">Advantages</a>
</li>
<li class="none">
<a href="../server/objectives.html" title="Objectives">Objectives</a>
</li>
<li class="expanded">
<a href="../server/quick-start.html" title="User Manual">User Manual</a>
<ul>
<li class="collapsed">
<a href="../server/features.html" title="1. Features">1. Features</a>
</li>
<li class="none">
<a href="../server/packaging.html" title="2. Packaging">2. Packaging</a>
</li>
<li class="collapsed">
<a href="../server/install.html" title="3. Install James">3. Install James</a>
</li>
<li class="collapsed">
<a href="../server/config.html" title="4. Configure James">4. Configure James</a>
</li>
<li class="collapsed">
<a href="../server/manage.html" title="5. Manage">5. Manage</a>
</li>
<li class="collapsed">
<a href="../server/monitor.html" title="6. Monitor">6. Monitor</a>
</li>
<li class="collapsed">
<a href="../server/upgrade.html" title="7. Upgrade">7. Upgrade</a>
</li>
<li class="expanded">
<a href="../server/dev.html" title="8. Developers Corner">8. Developers Corner</a>
<ul>
<li class="none">
<a href="../server/dev-build.html" title="Build from source">Build from source</a>
</li>
<li class="none">
<a href="../server/dev-database-schema.html" title="Database Schema">Database Schema</a>
</li>
<li class="expanded">
<a href="../server/dev-extend.html" title="Develop Extensions">Develop Extensions</a>
<ul>
<li class="none">
<strong>Mailet</strong>
</li>
<li class="none">
<a href="../server/dev-extend-matcher.html" title="Matcher">Matcher</a>
</li>
<li class="none">
<a href="../server/dev-extend-smtp-hook.html" title="SMTP Hook">SMTP Hook</a>
</li>
</ul>
</li>
<li class="collapsed">
<a href="../server/dev-provided.html" title="Provided Extensions">Provided Extensions</a>
</li>
</ul>
</li>
</ul>
</li>
<li class="none">
<a href="../mail.html#James_Mailing_lists" title="Mailing Lists">Mailing Lists</a>
</li>
<li class="none">
<a href="../server/release-notes.html" title="Release Notes">Release Notes</a>
</li>
<li class="none">
<a href="../server/apidocs/index.html" title="Javadoc">Javadoc</a>
</li>
<li class="none">
<a href="https://issues.apache.org/jira/browse/JAMES" title="Issue Tracker">Issue Tracker</a>
</li>
<li class="none">
<a href="https://github.com/apache/james-project" title="Sources">Sources</a>
</li>
<li class="none">
<a href="../server/rfcs.html" title="RFCs">RFCs</a>
</li>
<li class="none">
<a href="../download.cgi#Apache_James_Server" title="Download releases">Download releases</a>
</li>
</ul>
</li>
<li class="collapsed">
<a href="../mailet/index.html" title="Mailets">Mailets</a>
</li>
<li class="collapsed">
<a href="../mailbox/index.html" title="Mailbox">Mailbox</a>
</li>
<li class="collapsed">
<a href="../protocols/index.html" title="Protocols">Protocols</a>
</li>
<li class="collapsed">
<a href="../mpt/index.html" title="MPT">MPT</a>
</li>
</ul>
<h5>Apache Software Foundation</h5>
<ul>
<li>
<strong>
<a title="ASF" href="http://www.apache.org/">ASF</a>
</strong>
</li>
<li>
<a title="Get Involved" href="http://www.apache.org/foundation/getinvolved.html">Get Involved</a>
</li>
<li>
<a title="FAQ" href="http://www.apache.org/foundation/faq.html">FAQ</a>
</li>
<li>
<a title="License" href="http://www.apache.org/licenses/" >License</a>
</li>
<li>
<a title="Sponsorship" href="http://www.apache.org/foundation/sponsorship.html">Sponsorship</a>
</li>
<li>
<a title="Thanks" href="http://www.apache.org/foundation/thanks.html">Thanks</a>
</li>
<li>
<a title="Security" href="http://www.apache.org/security/">Security</a>
</li>
</ul>
<a href="http://maven.apache.org/" title="Built by Maven" class="poweredBy">
<img class="poweredBy" alt="Built by Maven" src="../images/logos/maven-feather.png" />
</a>
</div>
</div>
<div id="bodyColumn">
<div id="contentBox">
<section>
<h2><a name="Writing_a_Custom_Mailet"></a>Writing a Custom Mailet</h2>
<p>
Implementing a custom mailet is generally a simple task, most of whose complexity
lies in coding the actual work to be done by the mailet. This is largely due to the
simplicity of the Mailet interface and the fact that a GenericMailet class is provided
as part of the Mailet package.
</p>
<p>
In this discussion we will assume that any mailet being implemented is a subclass of
GenericMailet. The GenericMailet class serves to abstract away of the configuration and
logging details. While it provides a noop implementation of the init() and destroy() methods,
these can be easily overridden to provide useful functionality.
</p>
<p>
In general, the only four methods that you should need to implement are init(), destroy(),
getMailetInfo(), and service(Mail). And only the last is required in all cases.
</p>
<section>
<h3><a name="Configuration"></a>Configuration</h3>
<p>
As described in the <a href="config-mailetcontainer.html">SpoolManager configuration
section</a>, mailets are configured with a set of String (name, value) pairs. These values are
passed into the Mailet upon initialization (although the details of this process are hidden by
the GenericMailet implementation). GenericMailet provides access to this configuration
information through use of the getInitParameter(String) method. Passing in the name of the
requested configuration value will yield the value if set, and null otherwise. Configuration
values are available inside the init(), destroy(), and service(Mail) methods.
</p>
</section>
<section>
<h3><a name="Logging"></a>Logging</h3>
<p>
There is a simple logging mechanism provided by the Mailet API. It does not support
logging levels, so any log filtering will have to be implemented in the Mailet code.
Logging is done by calling one of the two logging methods on GenericMailet - log(String)
or log(String,Throwable). Logging is available inside the init(), destroy(), and service(Mail)
methods.
</p>
<p>
Please note that the log() method logs with DEBUG level. You will need to define that DEBUG level
in the log4j.properties.
</p>
<p>
The value of getMailetInfo() for the Mailet is prepended to the log entries for that
Mailet. So it may be desirable for you to override this method so you can distinguish mailet
log entries by Mailet.
</p>
<p>
Alternatively, you can instantiate your own logger and log with different level, as show in the
following snippet (don't forget to update the log4j.properties so you log are taken into account).
</p>
<div class="source">
<pre>
package com.test;
import javax.mail.MessagingException;
import org.apache.mailet.Mail;
import org.apache.mailet.base.GenericMailet;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
public class MyMailet extends GenericMailet{
private static final Logger logger = LoggerFactory.getLogger(MyMailet.class);
@Override
public void service(Mail mail) throws MessagingException {
log(&quot;log via mailet logger with INFO level&quot;);
logger.info(&quot;Log via slf4j with INFO level !!! Add log4j.logger.com.test=INFO, CONS, FILE in the log4j.properties&quot;);
logger.debug(&quot;Log via slf4j with DEBUG level !!! Add log4j.logger.com.test=DEBUG, CONS, FILE in the log4j.properties&quot;);
}
}
</pre></div>
</section>
<section>
<h3><a name="Initialization"></a>Initialization</h3>
<p>
As part of the Mailet lifecycle, a Mailet is guaranteed to be initialized immediately after
being instantiated. This happens once and only once for each Mailet instance. The
Initialization phase is where configuration parsing and per-Mailet resource creation generally
take place. Depending on your Mailet, it may or may not be necessary to do any initialization
of the mailet. Initialization logic is implemented by overriding the init() method of
GenericMailet.
</p>
</section>
<section>
<h3><a name="Servicing"></a>Servicing</h3>
<p>
The bulk of the Mailet logic is expected to be invoked from the service(Mail) method. This
method is invoked each time a mail message is to be processed by the mailet. The message is
passed in as an instance of the Mail interface, which is part of the Mailet API.</p>
<p>The Mail interface is essentially a light wrapper around JavaMail's MimeMessage class with a
few important differences. See the Javadoc for the interface for a description of the additional
methods available on this wrapper.
</p>
</section>
<section>
<h3><a name="Destruction"></a>Destruction</h3>
<p>
As part of the Mailet lifecycle, a Mailet is guaranteed to be destroyed when the container
cleans up the Mailet. This happens once and only once for each Mailet instance. The
Destruction phase is where per-Mailet resource release generally takes place. Depending
on your Mailet, it may or may not be necessary to do any destruction
of the mailet. Destruction logic is implemented by overriding the destroy() method of
GenericMailet.
</p>
</section>
</section>
<section>
<h2><a name="Deploying_a_Custom_Mailet"></a>Deploying a Custom Mailet</h2>
<p>
Once a Mailet has been successfully implemented there are only a couple of
additional steps necessary to actually deploy the Mailet.
</p>
<section>
<h3><a name="Adding_Your_Mailet_to_the_Classpath"></a>Adding Your Mailet to the Classpath</h3>
<p>
The Mailet must be added to James' classpath so that the Mailet can be loaded by James. There
are two ways to add a custom Mailet to the classpath so that James will be able to load the
Mailet. These are:
</p>
<p>
1a. Download the source distribution, add a jar file containing the custom files to the lib
directory of the unpacked source distribution, and build a new .tar.gz/zip file by following the
directions <a href="build-instructions.html">here</a>. This new tar.gz/zip file will now
include your custom classes.
</p>
<p>
or
</p>
<p>
1b. Place a jar file containing the custom class files in
/path/to/james/conf/lib/ subdirectory with JAMES-Spring or /path/to/james/conf/extensions-jars/ subdirectory with JAMES-Guice.
</p>
<p>
2. The mailetpackages entity is no longer required, the class attribute of mailets and matchers now takes a fully qualified class name e.g.
<p>
</p>
<div class="source">
<pre>
&lt;mailet match=&quot;All&quot; class=&quot;com.your.company.MyMailet&quot;/&gt;
</pre></div>
After that, restart James server.
</section>
<section>
<h3><a name="Add_custom_Guice_injections_for_extensions"></a>Add custom Guice injections for extensions</h3>
<p>Upon injections, the user can reference additional guice modules, that are going to be used only upon extensions instantiation.
In order to do that:</p>
<p> 1. Place the jar containing the guice module that should be used to instantiate your extensions within the /extensions-jars folder</p>
<p> 2. Register your module fully qualified class name within <a class="externalLink" href="https://github.com/apache/james-project/blob/master/server/apps/distributed-app/sample-configuration/extensions.properties">
extensions.properties</a> under the guice.extension.module key.</p>
</section>
<section>
<h3><a name="James_Configuration"></a>James Configuration</h3>
<p>Configuration of the processor chain is discussed
<a href="config-mailetcontainer.html">elsewhere</a> in this documentation. The
details of configuring mailet deployment is discussed at length. Here we will only comment
that it is important to add the appropriate mailet package for your custom mailet to the
&lt;mailetpackages&gt; list and that the name of your mailet should not conflict with any of
the mailets described <a href="dev-provided-mailets.html">here</a>.
</p>
</section>
</section>
</div>
</div>
<div class="clear">
<hr/>
</div>
<div id="footer">
<div class="xright">Copyright &#169; 2006-2021
<a href="https://www.apache.org/">The Apache Software Foundation</a>.
All Rights Reserved.
</div>
<div class="clear">
<hr/>
</div>
</div>
</body>
</html>