| <!-- |
| 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> |
| <html> |
| <head> |
| <meta charset="utf-8"/> |
| <title>Apache James</title> |
| |
| <link rel="stylesheet" type="text/css" href="/assets/css/main.css"> |
| <link rel="stylesheet" type="text/css" href="/assets/css/font-awesome.min.css"> |
| <link rel="stylesheet" type="text/css" href="/assets/css/ie8.css"> |
| <link rel="stylesheet" type="text/css" href="/assets/css/ie9.css"> |
| <link rel="shortcut icon" href="/images/james-logo.png"> |
| </head> |
| <body> |
| <!-- |
| 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. |
| --> |
| |
| <div id="wrapper"> |
| <div class="apache_ref"> |
| <a href="https://www.apache.org" alt="apache foundation link"><img src="https://www.apache.org/foundation/press/kit/asf_logo.svg" title="apache foundation logo"/></a> |
| </div> |
| <div class="apache_ref_mobile"> |
| <a href="https://www.apache.org" alt="apache foundation link">The Apache Software Foundation</a> |
| </div> |
| <div class="apache_ref_left"> |
| <a href="https://www.apache.org/events/current-event.html" alt="apache foundation event"><img src="https://www.apache.org/events/current-event-234x60.png" title="apache foundation event logo"/></a> |
| </div> |
| <div class="apache_ref_left_mobile"> |
| <a href="https://www.apache.org/events/current-event.html" alt="apache foundation event"><img src="https://www.apache.org/events/current-event-234x60.png" title="apache foundation event logo"/></a> |
| </div> |
| |
| <!-- |
| 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. |
| --> |
| |
| <header id="header" class="alt"> |
| <div class="logo"><a href="/index.html" alt="Apache James"><img src="/images/james.svg" alt="james logo"/></a></div> |
| <h1 class="hidden">James Enterprise Mail Server</h1> |
| <h2>Emails at the heart of your business logic</h2> |
| </header> |
| |
| <!-- |
| 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. |
| --> |
| |
| <!-- Main --> |
| <div id="main"> |
| |
| <!-- Introduction --> |
| <section id="intro" class="main special"> |
| <div class=""> |
| <div class="content align-left"> |
| <header class="major"> |
| <h1>How to customize mail processing</h1> |
| </header> |
| <header class="major"> |
| <h2><b>Mail processing component overview</b></h2> |
| </header> |
| <p class="align-left">At the heart of James lies the Mailet container, which allows mail processing. This is |
| splitted into smaller units, with specific responsibilities: |
| |
| </p> |
| |
| <ul class="no-padding"> |
| <li><b>Mailets:</b> Are operations performed with the mail: modifying it, performing a side-effect, etc...</li> |
| <li><b>Matchers:</b> Are per-recipient conditions for mailet executions</li> |
| <li><b>Processors:</b> Are matcher/mailet pair execution threads</li> |
| </ul> |
| |
| <p> Read <a href="/server/feature-mailetcontainer.html">this</a> for more explanations of mailet container concepts.</p> |
| |
| <p>Once we define the mailet container content through the <a href="/server/config-mailetcontainer.html">mailetcontailer.xml</a> file. |
| Hence, we can arrange James standard components listed <a href="/server/3/dev-provided-mailets.html">here</a> to achieve basic logic. But what if our goals are more |
| complex? What if we need our own processing components?</p> |
| |
| <p>This page will propose a 'hands on practice' how-to using James 3.7.3. We will implement a custom mailet and a custom matcher, |
| then deploy it in a James server.</p> |
| |
| <p>We need to choose our use case. We will, when a mail is delayed over one day, write a mail to the original sender |
| to inform him about the delay, say that we are sorry, and send him a promotion code...<pre></pre></p> |
| |
| |
| <header class="major"> |
| <h2><b>Writing custom mailets and matchers</b></h2> |
| </header> |
| |
| <p>None of the matchers and mailets available in James allows us to implement what we want. We will have to |
| write our own mailet and matcher in a separated maven project depending on James Mailet API.</p> |
| |
| <p>We will write a <a href="https://github.com/apache/james-project/blob/master/examples/custom-mailets/src/main/java/org/apache/james/examples/custom/mailets/IsDelayedForMoreThan.java">IsDelayedForMoreThan</a> matcher with a configurable delay. If the Sent Date of incoming emails is older than specified delay, then the emails |
| should be matched (return all mail recipients). Otherwise, we just return an empty list of recipients.</p> |
| |
| <p>To ease our Job, we can rely on the <b>org.apache.james.apache-mailet-base</b> maven project, which provides us a <b>GenericMatcher</b> that we can extend.</p> |
| |
| <p>Here is the dependency:</p> |
| |
| <pre><code><dependency> |
| <groupId>org.apache.james</groupId> |
| <artifactId>apache-mailet-base</artifactId> |
| </dependency></code></pre> |
| |
| <p>The main method of a matcher is the <b>match</b> method:</p> |
| |
| <pre><code>Collection<MailAddress> match(Mail mail) throws MessagingException;</code></pre> |
| |
| <p>For us, it becomes, with <b>maxDelay</b> being previously configured:</p> |
| |
| <pre><code>private final Clock clock; |
| private Duration maxDelay; |
| |
| @Override |
| public Collection<MailAddress> match(Mail mail) throws MessagingException { |
| Date sentDate = mail.getMessage().getSentDate(); |
| |
| if (clock.instant().isAfter(sentDate.toInstant().plusMillis(maxDelay.toMillis()))) { |
| return ImmutableList.copyOf(mail.getRecipients()); |
| } |
| return ImmutableList.of(); |
| }</code></pre> |
| |
| <p><b>GenericMatcher</b> exposes us the condition that had been configured. We will use it to compute <b>maxDelay</b>. |
| We can do it in the <b>init()</b> method exposed by the generic matcher:</p> |
| |
| <pre><code> |
| public static final TimeConverter.Unit DEFAULT_UNIT = TimeConverter.Unit.HOURS; |
| |
| @Override |
| public void init() { |
| String condition = getCondition(); |
| maxDelay = Duration.ofMillis(TimeConverter.getMilliSeconds(condition, DEFAULT_UNIT)); |
| }</code></pre> |
| |
| <p>Now, let's take a look at the <a href="https://github.com/apache/james-project/blob/master/examples/custom-mailets/src/main/java/org/apache/james/examples/custom/mailets/SendPromotionCode.java">SendPromotionCode</a> mailet. Of course, we want to write a generic mailet |
| with a configurable reason (why are we sending the promotion code). To keep things simple, only one promotion |
| code will be used, and will be written in the configuration. We can here also simply extend the |
| <b>GenericMailet</b> helper class.</p> |
| |
| <p>The main method of a mailet is the <b>service</b> method:</p> |
| |
| <pre><code>void service(Mail mail) throws MessagingException</code></pre> |
| |
| <p>For us, it becomes, with <b>reason</b> and <b>promotionCode</b> being previously configured:</p> |
| |
| <pre><code>public static final boolean REPLY_TO_SENDER_ONLY = false; |
| |
| private String reason; |
| private String promotionCode; |
| |
| @Override |
| public void service(Mail mail) throws MessagingException { |
| MimeMessage response = (MimeMessage) mail.getMessage() |
| .reply(REPLY_TO_SENDER_ONLY); |
| |
| response.setText(reason + "\n\n" + |
| "Here is the following promotion code that you can use on your next order: " + promotionCode); |
| |
| MailAddress sender = getMailetContext().getPostmaster(); |
| ImmutableList<MailAddress> recipients = ImmutableList.of(mail.getSender()); |
| |
| getMailetContext() |
| .sendMail(sender, recipients, response); |
| }</code></pre> |
| |
| <p>Note that we can interact with the mail server through the mailet context for sending mails, knowing postmaster, etc...</p> |
| |
| <p><b>GenericMailet</b> exposes us the 'init parameters' that had been configured for this mailet. We will |
| use it to retrieve <b>reason</b> and <b>promotionCode</b>. |
| We can do it in the <b>init()</b> method exposed by the generic mailet:</p> |
| |
| <pre><code> @Override |
| public void init() throws MessagingException { |
| reason = getInitParameter("reason"); |
| promotionCode = getInitParameter("promotionCode"); |
| |
| if (Strings.isNullOrEmpty(reason)) { |
| throw new MessagingException("'reason' is compulsory"); |
| } |
| if (Strings.isNullOrEmpty(promotionCode)) { |
| throw new MessagingException("'promotionCode' is compulsory"); |
| } |
| }</code></pre> |
| |
| <p>You can retrieve the sources of this mini-project on <a href="https://github.com/apache/james-project/tree/master/examples/custom-mailets">GitHub</a></p> |
| |
| <header class="major"> |
| <h2><b>Loading custom mailets with James</b></h2> |
| </header> |
| |
| <p>Now is the time we will run James with our awesome matcher and mailet configured.</p> |
| |
| <p>First, we will need to compile our project with <code>mvn clean install</code>. A jar will be outputted in the target directory.</p> |
| |
| <p>Then, we will write the <code>mailetcontainer.xml</code> file expressing the logic we want:</p> |
| |
| <pre><code> |
| <mailetcontainer enableJmx="true"> |
| |
| <context> |
| <postmaster>postmaster@localhost</postmaster> |
| </context> |
| |
| <spooler> |
| <threads>20</threads> |
| </spooler> |
| |
| <processors> |
| <processor state="root" enableJmx="true"> |
| <mailet match="All" class="PostmasterAlias"/> |
| <mailet match="org.apache.james.examples.custom.mailets.IsDelayedForMoreThan=1 day" |
| class="org.apache.james.examples.custom.mailets.SendPromotionCode"> |
| <reason>Your email had been delayed for a long time. Because we are sorry about it, please find the |
| following promotion code.</reason> |
| <promotionCode>1542-2563-5469</promotionCode> |
| </mailet> |
| <!-- Rest of the configuration --> |
| </processor> |
| |
| <!-- Other processors --> |
| </processors> |
| </mailetcontainer></code></pre> |
| |
| <p>Finally, we will start a James server using that. We will rely on docker default image for simplicity. |
| We need to be using the <b>mailetcontainer.xml</b> configuration that we had been writing and position |
| the jar in the <b>extensions-jars</b> folder (specific to guice). This can be achieved with the following command:</p> |
| |
| <pre><code>docker run -p "25:25" -p "143:143" \ |
| -v "$PWD/src/main/resources/mailetcontainer.xml:/root/conf/mailetcontainer.xml" \ |
| -v "$PWD/target/custom-mailets.jar:/root/extensions-jars/custom-mailets.jar" \ |
| apache/james:memory-latest --generate-keystore</code></pre> |
| |
| </div> |
| <footer class="major"> |
| <ul class="actions align-center"> |
| <li><a href="index.html" class="button">go back to other how-tos</a></li> |
| </ul> |
| </footer> |
| </div> |
| </section> |
| |
| </div> |
| |
| |
| <!-- |
| 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. |
| --> |
| |
| <footer id="footer" class="major"> |
| <section> |
| <h2>James</h2> |
| <ul class="no-padding"> |
| <li class="no-padding"><a href="https://james.apache.org/#intro" class="active">About</a></li> |
| <li class="no-padding"><a href="https://james.apache.org/#first">Get Started</a></li> |
| <li class="no-padding"><a href="https://james.apache.org/#posts">Last Posts</a></li> |
| <li class="no-padding"><a href="https://james.apache.org/#second">Community</a></li> |
| <li class="no-padding"><a href="https://james.apache.org/#third">Contribute</a></li> |
| <li class="no-padding"><a href="https://james.apache.org/"><span class="fa fa-external-link"></span> Documentation</a></li> |
| </ul> |
| </section> |
| <section> |
| <h2>Connect</h2> |
| <ul class="icons"> |
| <li><a href="https://james.apache.org/mail.html" class="icon fa-envelope-o alt"><span class="label">Mailing-list</span></a></li> |
| <li><a href="https://gitter.im/apache/james-project" class="icon fa-wechat alt"><span class="label">Gitter</span></a></li> |
| <li><a href="https://github.com/apache/james-project" class="icon fa-github alt"><span class="label">GitHub</span></a></li> |
| <li><a href="https://twitter.com/ApacheJames" class="icon fa-twitter alt"><span class="label">Twitter</span></a></li> |
| <li><a href="https://james.apache.org/support.html" class="icon fa-briefcase alt"><span class="label">Support</span></a></li> |
| <li><a href="http://www.apache.org/events/current-event" class="icon fa-calendar alt"><span class="label">Apache Foundation events</span></a></li> |
| </ul> |
| </section> |
| <section class="legal-section"> |
| <h2>Copyright</h2> |
| Apache James and related projects are trademarks of the Apache Software Foundation.<br/> |
| <a href="https://www.apache.org/">Copyright 2006-2021 The Apache Software Foundation. All Rights Reserved.</a><br/> |
| <a href="https://www.apache.org/licenses/">License</a><br/> |
| <a href="https://www.apache.org/foundation/sponsorship.html">Donate</a> to support the Apache Foundation<br/> |
| <a href="https://www.apache.org/foundation/thanks.html">Thanks</a><br/> |
| Design: <a href="https://html5up.net">HTML5 UP</a><br/> |
| Thanks to <a href="http://www.neoma-interactive.com/">Neoma by Linagora</a> for the website design |
| </section> |
| </footer> |
| </div> |
| |
| </body> |
| </html> |