You are viewing a plain text version of this content. The canonical link for it is here.
Posted to notifications@james.apache.org by bt...@apache.org on 2021/05/11 01:37:59 UTC

[james-project] branch master updated (a531c05 -> 071ffa9)

This is an automated email from the ASF dual-hosted git repository.

btellier pushed a change to branch master
in repository https://gitbox.apache.org/repos/asf/james-project.git.


    from a531c05  JAMES-3491 JMAP webSocket can be used to mix responses and state changes
     new 5f5d4e5  JAMES-3574 Add a unit test for the LMTP protocol
     new d47f0e9  JAMES-3574 Create a LMTP handler chain for executing the mailet container
     new 071ffa9  JAMES-3574 Document LMTP default behaviour and mailetcontainer execution

The 3 revisions listed above as "new" are entirely new to this
repository and will be described in separate emails.  The revisions
listed as "add" were already present in the repository and have only
been added to this reference.


Summary of changes:
 .../servers/pages/distributed/configure/smtp.adoc  |  24 ++-
 server/protocols/protocols-imap4/pom.xml           |   6 +
 .../james/imapserver/netty/IMAPServerTest.java     |  26 +---
 .../james/protocols/lib/mock/ConfigLoader.java     |  34 ++--
 server/protocols/protocols-lmtp/pom.xml            |  58 +++++++
 ...r.java => MailetContainerCmdHandlerLoader.java} | 168 ++++++++++----------
 .../james/lmtpserver/MailetContainerHandler.java   |  60 ++++---
 .../james/lmtpserver/NoopJamesMessageHook.java}    |   9 +-
 .../apache/james/lmtpserver/LmtpServerTest.java    | 173 +++++++++++++++++++++
 .../lmtpserver/MailetContainerHandlerTest.java     | 156 +++++++++++++++++++
 .../protocols-lmtp/src/test/resources/lmtp.xml     |  24 +--
 .../src/test/resources/lmtpmailet.xml              |  28 ++--
 src/site/xdoc/server/config-smtp-lmtp.xml          |  24 +++
 13 files changed, 603 insertions(+), 187 deletions(-)
 copy mailbox/jpa/src/test/java/org/apache/james/mailbox/jpa/quota/JPAPerUserMaxQuotaTest.java => server/protocols/protocols-library/src/test/java/org/apache/james/protocols/lib/mock/ConfigLoader.java (55%)
 copy server/protocols/protocols-lmtp/src/main/java/org/apache/james/lmtpserver/{CoreCmdHandlerLoader.java => MailetContainerCmdHandlerLoader.java} (88%)
 copy protocols/smtp/src/main/java/org/apache/james/protocols/smtp/core/fastfail/MaxRcptHandler.java => server/protocols/protocols-lmtp/src/main/java/org/apache/james/lmtpserver/MailetContainerHandler.java (52%)
 copy server/{mailet/integration-testing/src/test/java/org/apache/james/smtp/extensions/hooks/DeclinedHeloHook.java => protocols/protocols-lmtp/src/main/java/org/apache/james/lmtpserver/NoopJamesMessageHook.java} (84%)
 create mode 100644 server/protocols/protocols-lmtp/src/test/java/org/apache/james/lmtpserver/LmtpServerTest.java
 create mode 100644 server/protocols/protocols-lmtp/src/test/java/org/apache/james/lmtpserver/MailetContainerHandlerTest.java
 copy mpt/impl/smtp/cassandra/src/test/resources/mailrepositorystore.xml => server/protocols/protocols-lmtp/src/test/resources/lmtp.xml (61%)
 copy dockerfiles/run/spring/destination/conf/mailrepositorystore.xml => server/protocols/protocols-lmtp/src/test/resources/lmtpmailet.xml (57%)

---------------------------------------------------------------------
To unsubscribe, e-mail: notifications-unsubscribe@james.apache.org
For additional commands, e-mail: notifications-help@james.apache.org


[james-project] 03/03: JAMES-3574 Document LMTP default behaviour and mailetcontainer execution

Posted by bt...@apache.org.
This is an automated email from the ASF dual-hosted git repository.

btellier pushed a commit to branch master
in repository https://gitbox.apache.org/repos/asf/james-project.git

commit 071ffa9721603a3c86083807487f002517b953f0
Author: Benoit Tellier <bt...@linagora.com>
AuthorDate: Fri Apr 30 22:01:11 2021 +0700

    JAMES-3574 Document LMTP default behaviour and mailetcontainer execution
---
 .../servers/pages/distributed/configure/smtp.adoc  | 24 +++++++++++++++++++++-
 src/site/xdoc/server/config-smtp-lmtp.xml          | 24 ++++++++++++++++++++++
 2 files changed, 47 insertions(+), 1 deletion(-)

diff --git a/docs/modules/servers/pages/distributed/configure/smtp.adoc b/docs/modules/servers/pages/distributed/configure/smtp.adoc
index f9359f4..ae9f275 100644
--- a/docs/modules/servers/pages/distributed/configure/smtp.adoc
+++ b/docs/modules/servers/pages/distributed/configure/smtp.adoc
@@ -170,4 +170,26 @@ to get some examples and hints.
 
 The configuration is the same of for SMTP.
 
-By default, it is deactivated. You can activate it alongside SMTP and bind for example on port 24.
\ No newline at end of file
+By default, it is deactivated. You can activate it alongside SMTP and bind for example on port 24.
+
+The default LMTP server stores directly emails in user mailboxes, without further treatment.
+
+However we do ship an alternative handler chain allowing to execute the mailet container, thus achieving a behaviour similar
+to the default SMTP protocol. Here is how to achieve this:
+
+....
+<lmtpservers>
+    <lmtpserver enabled="true">
+        <jmxName>lmtpserver</jmxName>
+        <bind>0.0.0.0:0</bind>
+        <connectionBacklog>200</connectionBacklog>
+        <connectiontimeout>1200</connectiontimeout>
+        <connectionLimit>0</connectionLimit>
+        <connectionLimitPerIP>0</connectionLimitPerIP>
+        <maxmessagesize>0</maxmessagesize>
+        <handlerchain coreHandlersPackage="org.apache.james.lmtpserver.MailetContainerCmdHandlerLoader">
+            <handler class="org.apache.james.lmtpserver.MailetContainerCmdHandlerLoader"/>
+        </handlerchain>
+    </lmtpserver>
+</lmtpservers>
+....
\ No newline at end of file
diff --git a/src/site/xdoc/server/config-smtp-lmtp.xml b/src/site/xdoc/server/config-smtp-lmtp.xml
index f746960..42b419b 100644
--- a/src/site/xdoc/server/config-smtp-lmtp.xml
+++ b/src/site/xdoc/server/config-smtp-lmtp.xml
@@ -205,6 +205,30 @@ Correct this.
     
     <p>By default, it is deactivated. You can activate it with SMTP and bind for example on port 24.</p>
 
+      <p>The default LMTP server stores directly emails in user mailboxes, without further treatment.</p>
+
+      <p>However we do ship an alternative handler chain allowing to execute the mailet container, thus achieving a behaviour similar
+          to the default SMTP protocol. Here is how to achieve this:</p>
+
+      <pre>
+          <code>
+&lt;lmtpservers&gt;
+  &lt;lmtpserver enabled=&quot;true&quot;&gt;
+    &lt;jmxName&gt;lmtpserver&lt;/jmxName&gt;
+    &lt;bind&gt;0.0.0.0:0&lt;/bind&gt;
+    &lt;connectionBacklog&gt;200&lt;/connectionBacklog&gt;
+    &lt;connectiontimeout&gt;1200&lt;/connectiontimeout&gt;
+    &lt;connectionLimit&gt;0&lt;/connectionLimit&gt;
+    &lt;connectionLimitPerIP&gt;0&lt;/connectionLimitPerIP&gt;
+    &lt;maxmessagesize&gt;0&lt;/maxmessagesize&gt;
+    &lt;handlerchain coreHandlersPackage=&quot;org.apache.james.lmtpserver.MailetContainerCmdHandlerLoader&quot;&gt;
+      &lt;handler class=&quot;org.apache.james.lmtpserver.MailetContainerCmdHandlerLoader&quot;/&gt;
+    &lt;/handlerchain&gt;
+  &lt;/lmtpserver&gt;
+&lt;/lmtpservers&gt;
+          </code>
+      </pre>
+
   </section>
     
 </body>

---------------------------------------------------------------------
To unsubscribe, e-mail: notifications-unsubscribe@james.apache.org
For additional commands, e-mail: notifications-help@james.apache.org


[james-project] 01/03: JAMES-3574 Add a unit test for the LMTP protocol

Posted by bt...@apache.org.
This is an automated email from the ASF dual-hosted git repository.

btellier pushed a commit to branch master
in repository https://gitbox.apache.org/repos/asf/james-project.git

commit 5f5d4e5b9453d51acdc2d13e20ede73b0cec1aa5
Author: Benoit Tellier <bt...@linagora.com>
AuthorDate: Fri Apr 30 21:49:18 2021 +0700

    JAMES-3574 Add a unit test for the LMTP protocol
---
 server/protocols/protocols-imap4/pom.xml           |   6 +
 .../james/imapserver/netty/IMAPServerTest.java     |  26 +---
 .../james/protocols/lib/mock/ConfigLoader.java     |  43 +++++
 server/protocols/protocols-lmtp/pom.xml            |  58 +++++++
 .../apache/james/lmtpserver/LmtpServerTest.java    | 173 +++++++++++++++++++++
 .../protocols-lmtp/src/test/resources/lmtp.xml     |  34 ++++
 6 files changed, 316 insertions(+), 24 deletions(-)

diff --git a/server/protocols/protocols-imap4/pom.xml b/server/protocols/protocols-imap4/pom.xml
index 937f2e7..317fdbd 100644
--- a/server/protocols/protocols-imap4/pom.xml
+++ b/server/protocols/protocols-imap4/pom.xml
@@ -66,6 +66,12 @@
         </dependency>
         <dependency>
             <groupId>${james.groupId}</groupId>
+            <artifactId>james-server-protocols-library</artifactId>
+            <type>test-jar</type>
+            <scope>test</scope>
+        </dependency>
+        <dependency>
+            <groupId>${james.groupId}</groupId>
             <artifactId>james-server-testing</artifactId>
             <scope>test</scope>
         </dependency>
diff --git a/server/protocols/protocols-imap4/src/test/java/org/apache/james/imapserver/netty/IMAPServerTest.java b/server/protocols/protocols-imap4/src/test/java/org/apache/james/imapserver/netty/IMAPServerTest.java
index 2790b7e..417f5c4 100644
--- a/server/protocols/protocols-imap4/src/test/java/org/apache/james/imapserver/netty/IMAPServerTest.java
+++ b/server/protocols/protocols-imap4/src/test/java/org/apache/james/imapserver/netty/IMAPServerTest.java
@@ -23,8 +23,6 @@ import static org.assertj.core.api.Assertions.assertThat;
 import static org.assertj.core.api.Assertions.assertThatCode;
 import static org.assertj.core.api.Assertions.assertThatThrownBy;
 
-import java.io.InputStream;
-import java.nio.charset.StandardCharsets;
 import java.util.Properties;
 
 import javax.mail.Folder;
@@ -38,11 +36,6 @@ import javax.mail.search.RecipientStringTerm;
 import javax.mail.search.SearchTerm;
 import javax.mail.search.SubjectTerm;
 
-import org.apache.commons.configuration2.XMLConfiguration;
-import org.apache.commons.configuration2.builder.FileBasedConfigurationBuilder;
-import org.apache.commons.configuration2.builder.fluent.Parameters;
-import org.apache.commons.configuration2.convert.DisabledListDelimiterHandler;
-import org.apache.commons.configuration2.io.FileHandler;
 import org.apache.james.core.Username;
 import org.apache.james.imap.encode.main.DefaultImapEncoderFactory;
 import org.apache.james.imap.main.DefaultImapDecoderFactory;
@@ -55,9 +48,7 @@ import org.apache.james.mailbox.store.FakeAuthenticator;
 import org.apache.james.mailbox.store.FakeAuthorizator;
 import org.apache.james.mailbox.store.StoreSubscriptionManager;
 import org.apache.james.metrics.tests.RecordingMetricFactory;
-import org.apache.james.mime4j.codec.DecoderUtil;
-import org.apache.james.mime4j.codec.EncoderUtil;
-import org.apache.james.mime4j.util.MimeUtil;
+import org.apache.james.protocols.lib.mock.ConfigLoader;
 import org.apache.james.util.ClassLoaderUtils;
 import org.apache.james.utils.TestIMAPClient;
 import org.junit.jupiter.api.AfterEach;
@@ -75,19 +66,6 @@ class IMAPServerTest {
     public static final String SMALL_MESSAGE = "header: value\r\n\r\nBODY";
     private InMemoryIntegrationResources memoryIntegrationResources;
 
-    private static XMLConfiguration getConfig(InputStream configStream) throws Exception {
-        FileBasedConfigurationBuilder<XMLConfiguration> builder = new FileBasedConfigurationBuilder<>(XMLConfiguration.class)
-            .configure(new Parameters()
-                .xml()
-                .setListDelimiterHandler(new DisabledListDelimiterHandler()));
-        XMLConfiguration xmlConfiguration = builder.getConfiguration();
-        FileHandler fileHandler = new FileHandler(xmlConfiguration);
-        fileHandler.load(configStream);
-        configStream.close();
-
-        return xmlConfiguration;
-    }
-
     @RegisterExtension
     public TestIMAPClient testIMAPClient = new TestIMAPClient();
 
@@ -119,7 +97,7 @@ class IMAPServerTest {
                 metricFactory),
             new ImapMetrics(metricFactory));
 
-        imapServer.configure(getConfig(ClassLoaderUtils.getSystemResourceAsSharedStream(configurationFile)));
+        imapServer.configure(ConfigLoader.getConfig(ClassLoaderUtils.getSystemResourceAsSharedStream(configurationFile)));
         imapServer.init();
 
         return imapServer;
diff --git a/server/protocols/protocols-library/src/test/java/org/apache/james/protocols/lib/mock/ConfigLoader.java b/server/protocols/protocols-library/src/test/java/org/apache/james/protocols/lib/mock/ConfigLoader.java
new file mode 100644
index 0000000..3c610d3
--- /dev/null
+++ b/server/protocols/protocols-library/src/test/java/org/apache/james/protocols/lib/mock/ConfigLoader.java
@@ -0,0 +1,43 @@
+/****************************************************************
+ * 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.                                           *
+ ****************************************************************/
+
+package org.apache.james.protocols.lib.mock;
+
+import java.io.InputStream;
+
+import org.apache.commons.configuration2.XMLConfiguration;
+import org.apache.commons.configuration2.builder.FileBasedConfigurationBuilder;
+import org.apache.commons.configuration2.builder.fluent.Parameters;
+import org.apache.commons.configuration2.convert.DisabledListDelimiterHandler;
+import org.apache.commons.configuration2.io.FileHandler;
+
+public class ConfigLoader {
+    public static XMLConfiguration getConfig(InputStream configStream) throws Exception {
+        FileBasedConfigurationBuilder<XMLConfiguration> builder = new FileBasedConfigurationBuilder<>(XMLConfiguration.class)
+            .configure(new Parameters()
+                .xml()
+                .setListDelimiterHandler(new DisabledListDelimiterHandler()));
+        XMLConfiguration xmlConfiguration = builder.getConfiguration();
+        FileHandler fileHandler = new FileHandler(xmlConfiguration);
+        fileHandler.load(configStream);
+        configStream.close();
+
+        return xmlConfiguration;
+    }
+}
diff --git a/server/protocols/protocols-lmtp/pom.xml b/server/protocols/protocols-lmtp/pom.xml
index 8090e67..ca07fa0 100644
--- a/server/protocols/protocols-lmtp/pom.xml
+++ b/server/protocols/protocols-lmtp/pom.xml
@@ -39,18 +39,61 @@
         </dependency>
         <dependency>
             <groupId>${james.groupId}</groupId>
+            <artifactId>apache-james-mailbox-api</artifactId>
+            <type>test-jar</type>
+            <scope>test</scope>
+        </dependency>
+        <dependency>
+            <groupId>${james.groupId}</groupId>
+            <artifactId>apache-james-mailbox-memory</artifactId>
+            <scope>test</scope>
+        </dependency>
+        <dependency>
+            <groupId>${james.groupId}</groupId>
+            <artifactId>apache-james-mailbox-memory</artifactId>
+            <type>test-jar</type>
+            <scope>test</scope>
+        </dependency>
+        <dependency>
+            <groupId>${james.groupId}</groupId>
             <artifactId>apache-mailet-api</artifactId>
         </dependency>
         <dependency>
             <groupId>${james.groupId}</groupId>
+            <artifactId>event-bus-api</artifactId>
+            <type>test-jar</type>
+            <scope>test</scope>
+        </dependency>
+        <dependency>
+            <groupId>${james.groupId}</groupId>
             <artifactId>james-server-data-api</artifactId>
         </dependency>
         <dependency>
             <groupId>${james.groupId}</groupId>
+            <artifactId>james-server-data-memory</artifactId>
+            <scope>test</scope>
+        </dependency>
+        <dependency>
+            <groupId>${james.groupId}</groupId>
+            <artifactId>james-server-dnsservice-test</artifactId>
+            <scope>test</scope>
+        </dependency>
+        <dependency>
+            <groupId>${james.groupId}</groupId>
+            <artifactId>james-server-mailetcontainer-api</artifactId>
+        </dependency>
+        <dependency>
+            <groupId>${james.groupId}</groupId>
             <artifactId>james-server-protocols-library</artifactId>
         </dependency>
         <dependency>
             <groupId>${james.groupId}</groupId>
+            <artifactId>james-server-protocols-library</artifactId>
+            <type>test-jar</type>
+            <scope>test</scope>
+        </dependency>
+        <dependency>
+            <groupId>${james.groupId}</groupId>
             <artifactId>james-server-protocols-smtp</artifactId>
             <exclusions>
                 <exclusion>
@@ -73,6 +116,16 @@
         </dependency>
         <dependency>
             <groupId>${james.groupId}</groupId>
+            <artifactId>james-server-testing</artifactId>
+            <scope>test</scope>
+        </dependency>
+        <dependency>
+            <groupId>${james.groupId}</groupId>
+            <artifactId>metrics-tests</artifactId>
+            <scope>test</scope>
+        </dependency>
+        <dependency>
+            <groupId>${james.groupId}</groupId>
             <artifactId>testing-base</artifactId>
             <scope>test</scope>
         </dependency>
@@ -93,6 +146,11 @@
             <artifactId>protocols-smtp</artifactId>
         </dependency>
         <dependency>
+            <groupId>com.google.inject</groupId>
+            <artifactId>guice</artifactId>
+            <scope>test</scope>
+        </dependency>
+        <dependency>
             <groupId>io.netty</groupId>
             <artifactId>netty</artifactId>
         </dependency>
diff --git a/server/protocols/protocols-lmtp/src/test/java/org/apache/james/lmtpserver/LmtpServerTest.java b/server/protocols/protocols-lmtp/src/test/java/org/apache/james/lmtpserver/LmtpServerTest.java
new file mode 100644
index 0000000..0de463c
--- /dev/null
+++ b/server/protocols/protocols-lmtp/src/test/java/org/apache/james/lmtpserver/LmtpServerTest.java
@@ -0,0 +1,173 @@
+/****************************************************************
+ * 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.                                           *
+ ****************************************************************/
+
+package org.apache.james.lmtpserver;
+
+import static org.apache.james.jmap.JMAPTestingConstants.DOMAIN;
+import static org.apache.james.jmap.JMAPTestingConstants.LOCALHOST_IP;
+import static org.assertj.core.api.Assertions.assertThat;
+import static org.assertj.core.api.Assertions.assertThatCode;
+
+import java.net.InetSocketAddress;
+import java.nio.ByteBuffer;
+import java.nio.channels.SocketChannel;
+import java.nio.charset.StandardCharsets;
+
+import org.apache.james.core.Domain;
+import org.apache.james.core.Username;
+import org.apache.james.dnsservice.api.DNSService;
+import org.apache.james.dnsservice.api.InMemoryDNSService;
+import org.apache.james.domainlist.api.DomainList;
+import org.apache.james.domainlist.lib.DomainListConfiguration;
+import org.apache.james.domainlist.memory.MemoryDomainList;
+import org.apache.james.filesystem.api.FileSystem;
+import org.apache.james.lmtpserver.netty.LMTPServerFactory;
+import org.apache.james.mailbox.MailboxManager;
+import org.apache.james.mailbox.MailboxSession;
+import org.apache.james.mailbox.inmemory.InMemoryMailboxManager;
+import org.apache.james.mailbox.inmemory.manager.InMemoryIntegrationResources;
+import org.apache.james.mailbox.model.MailboxPath;
+import org.apache.james.mailbox.model.MessageRange;
+import org.apache.james.mailbox.store.FakeAuthenticator;
+import org.apache.james.mailbox.store.FakeAuthorizator;
+import org.apache.james.metrics.api.MetricFactory;
+import org.apache.james.metrics.tests.RecordingMetricFactory;
+import org.apache.james.protocols.lib.mock.ConfigLoader;
+import org.apache.james.protocols.lib.mock.MockProtocolHandlerLoader;
+import org.apache.james.rrt.api.AliasReverseResolver;
+import org.apache.james.rrt.api.CanSendFrom;
+import org.apache.james.rrt.api.RecipientRewriteTable;
+import org.apache.james.rrt.api.RecipientRewriteTableConfiguration;
+import org.apache.james.rrt.lib.AliasReverseResolverImpl;
+import org.apache.james.rrt.lib.CanSendFromImpl;
+import org.apache.james.rrt.memory.MemoryRecipientRewriteTable;
+import org.apache.james.server.core.configuration.Configuration;
+import org.apache.james.server.core.filesystem.FileSystemImpl;
+import org.apache.james.user.api.UsersRepository;
+import org.apache.james.user.memory.MemoryUsersRepository;
+import org.awaitility.Awaitility;
+import org.jboss.netty.util.HashedWheelTimer;
+import org.junit.jupiter.api.AfterEach;
+import org.junit.jupiter.api.BeforeEach;
+import org.junit.jupiter.api.Test;
+
+import com.google.inject.name.Names;
+
+import reactor.core.publisher.Flux;
+
+class LmtpServerTest {
+    private InMemoryMailboxManager mailboxManager;
+    private LMTPServerFactory lmtpServerFactory;
+
+    @BeforeEach
+    void setUp()  throws Exception {
+        InMemoryDNSService dnsService = new InMemoryDNSService()
+            .registerMxRecord(Domain.LOCALHOST.asString(), "127.0.0.1")
+            .registerMxRecord("examplebis.local", "127.0.0.1")
+            .registerMxRecord("127.0.0.1", "127.0.0.1");
+        MemoryDomainList domainList = new MemoryDomainList(dnsService);
+        domainList.configure(DomainListConfiguration.builder()
+            .autoDetect(false)
+            .autoDetectIp(false)
+            .build());
+
+        domainList.addDomain(Domain.of("examplebis.local"));
+        MemoryUsersRepository usersRepository = MemoryUsersRepository.withVirtualHosting(domainList);
+
+        FakeAuthenticator authenticator = new FakeAuthenticator();
+        mailboxManager = InMemoryIntegrationResources.builder()
+            .authenticator(authenticator)
+            .authorizator(FakeAuthorizator.defaultReject())
+            .inVmEventBus()
+            .defaultAnnotationLimits()
+            .defaultMessageParser()
+            .scanningSearchIndex()
+            .noPreDeletionHooks()
+            .storeQuotaManager()
+            .build().getMailboxManager();
+
+        usersRepository.addUser(Username.of("bob@examplebis.local"), "pwd");
+
+        FileSystem fileSystem = new FileSystemImpl(Configuration.builder()
+            .workingDirectory("../")
+            .configurationFromClasspath()
+            .build().directories());
+        MemoryRecipientRewriteTable rewriteTable = new MemoryRecipientRewriteTable();
+        rewriteTable.setConfiguration(RecipientRewriteTableConfiguration.DEFAULT_ENABLED);
+        AliasReverseResolver aliasReverseResolver = new AliasReverseResolverImpl(rewriteTable);
+        CanSendFrom canSendFrom = new CanSendFromImpl(rewriteTable, aliasReverseResolver);
+        MockProtocolHandlerLoader loader = MockProtocolHandlerLoader.builder()
+            .put(binder -> binder.bind(DomainList.class).toInstance(domainList))
+            .put(binder -> binder.bind(RecipientRewriteTable.class).toInstance(rewriteTable))
+            .put(binder -> binder.bind(CanSendFrom.class).toInstance(canSendFrom))
+            .put(binder -> binder.bind(FileSystem.class).toInstance(fileSystem))
+            .put(binder -> binder.bind(DNSService.class).toInstance(dnsService))
+            .put(binder -> binder.bind(UsersRepository.class).toInstance(usersRepository))
+            .put(binder -> binder.bind(MetricFactory.class).to(RecordingMetricFactory.class))
+            .put(binder -> binder.bind(MailboxManager.class).annotatedWith(Names.named("mailboxmanager")).toInstance(mailboxManager))
+            .build();
+        lmtpServerFactory = new LMTPServerFactory(loader, fileSystem, new RecordingMetricFactory(), new HashedWheelTimer());
+
+        lmtpServerFactory.configure(ConfigLoader.getConfig(ClassLoader.getSystemResourceAsStream("lmtp.xml")));
+        lmtpServerFactory.init();
+    }
+
+    @AfterEach
+    void tearDown() {
+        lmtpServerFactory.destroy();
+    }
+
+    @Test
+    void emailsShouldWellBeReceived() throws Exception {
+        SocketChannel server = SocketChannel.open();
+        server.connect(new InetSocketAddress(LOCALHOST_IP, getLmtpPort()));
+
+        server.write(ByteBuffer.wrap(("LHLO <" + DOMAIN + ">\r\n").getBytes(StandardCharsets.UTF_8)));
+        server.write(ByteBuffer.wrap(("MAIL FROM: <bob@" + DOMAIN + ">\r\n").getBytes(StandardCharsets.UTF_8)));
+        server.write(ByteBuffer.wrap(("RCPT TO: <bo...@examplebis.local>\r\n").getBytes(StandardCharsets.UTF_8)));
+        server.write(ByteBuffer.wrap(("DATA\r\n").getBytes(StandardCharsets.UTF_8)));
+        server.read(ByteBuffer.allocate(1024)); // needed to synchronize
+        server.write(ByteBuffer.wrap(("header:value\r\n\r\nbody").getBytes(StandardCharsets.UTF_8)));
+        server.write(ByteBuffer.wrap(("\r\n").getBytes(StandardCharsets.UTF_8)));
+        server.write(ByteBuffer.wrap((".").getBytes(StandardCharsets.UTF_8)));
+        server.write(ByteBuffer.wrap(("\r\n").getBytes(StandardCharsets.UTF_8)));
+        server.write(ByteBuffer.wrap(("QUIT\r\n").getBytes(StandardCharsets.UTF_8)));
+
+        Awaitility.await()
+            .untilAsserted(() -> {
+                Username username = Username.of("bob@examplebis.local");
+                MailboxSession systemSession = mailboxManager.createSystemSession(username);
+                assertThatCode(() ->
+                    assertThat(Flux.from(mailboxManager.getMailbox(MailboxPath.inbox(username), systemSession)
+                        .listMessagesMetadata(MessageRange.all(), systemSession))
+                        .count()
+                        .block())
+                        .isEqualTo(1))
+                    .doesNotThrowAnyException();
+            });
+    }
+
+    public int getLmtpPort() {
+        return lmtpServerFactory.getServers().stream()
+            .findFirst()
+            .flatMap(server -> server.getListenAddresses().stream().findFirst())
+            .map(InetSocketAddress::getPort)
+            .orElseThrow(() -> new IllegalStateException("LMTP server not defined"));
+    }
+}
\ No newline at end of file
diff --git a/server/protocols/protocols-lmtp/src/test/resources/lmtp.xml b/server/protocols/protocols-lmtp/src/test/resources/lmtp.xml
new file mode 100644
index 0000000..7ac3705
--- /dev/null
+++ b/server/protocols/protocols-lmtp/src/test/resources/lmtp.xml
@@ -0,0 +1,34 @@
+<?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.
+ -->
+
+<lmtpservers>
+    <lmtpserver enabled="true">
+        <jmxName>lmtpserver</jmxName>
+        <bind>0.0.0.0:0</bind>
+        <connectionBacklog>200</connectionBacklog>
+        <connectiontimeout>1200</connectiontimeout>
+        <connectionLimit>0</connectionLimit>
+        <connectionLimitPerIP>0</connectionLimitPerIP>
+        <maxmessagesize>0</maxmessagesize>
+        <handlerchain>
+            <handler class="org.apache.james.lmtpserver.CoreCmdHandlerLoader"/>
+        </handlerchain>
+    </lmtpserver>
+</lmtpservers>

---------------------------------------------------------------------
To unsubscribe, e-mail: notifications-unsubscribe@james.apache.org
For additional commands, e-mail: notifications-help@james.apache.org


[james-project] 02/03: JAMES-3574 Create a LMTP handler chain for executing the mailet container

Posted by bt...@apache.org.
This is an automated email from the ASF dual-hosted git repository.

btellier pushed a commit to branch master
in repository https://gitbox.apache.org/repos/asf/james-project.git

commit d47f0e9d543793bdf9708d05e4c8b86ff15ea397
Author: Benoit Tellier <bt...@linagora.com>
AuthorDate: Fri Apr 30 21:52:24 2021 +0700

    JAMES-3574 Create a LMTP handler chain for executing the mailet container
---
 .../MailetContainerCmdHandlerLoader.java           |  84 +++++++++++
 .../james/lmtpserver/MailetContainerHandler.java   |  59 ++++++++
 .../james/lmtpserver/NoopJamesMessageHook.java     |  32 +++++
 .../lmtpserver/MailetContainerHandlerTest.java     | 156 +++++++++++++++++++++
 .../src/test/resources/lmtpmailet.xml              |  34 +++++
 5 files changed, 365 insertions(+)

diff --git a/server/protocols/protocols-lmtp/src/main/java/org/apache/james/lmtpserver/MailetContainerCmdHandlerLoader.java b/server/protocols/protocols-lmtp/src/main/java/org/apache/james/lmtpserver/MailetContainerCmdHandlerLoader.java
new file mode 100644
index 0000000..f86289b
--- /dev/null
+++ b/server/protocols/protocols-lmtp/src/main/java/org/apache/james/lmtpserver/MailetContainerCmdHandlerLoader.java
@@ -0,0 +1,84 @@
+/****************************************************************
+ * 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.                                           *
+ ****************************************************************/
+
+package org.apache.james.lmtpserver;
+
+import java.util.LinkedList;
+import java.util.List;
+import java.util.stream.Stream;
+
+import org.apache.james.protocols.api.handler.CommandDispatcher;
+import org.apache.james.protocols.api.handler.CommandHandlerResultLogger;
+import org.apache.james.protocols.lib.handler.HandlersPackage;
+import org.apache.james.protocols.lmtp.core.LhloCmdHandler;
+import org.apache.james.protocols.lmtp.core.WelcomeMessageHandler;
+import org.apache.james.protocols.smtp.core.ExpnCmdHandler;
+import org.apache.james.protocols.smtp.core.NoopCmdHandler;
+import org.apache.james.protocols.smtp.core.PostmasterAbuseRcptHook;
+import org.apache.james.protocols.smtp.core.QuitCmdHandler;
+import org.apache.james.protocols.smtp.core.ReceivedDataLineFilter;
+import org.apache.james.protocols.smtp.core.RsetCmdHandler;
+import org.apache.james.protocols.smtp.core.VrfyCmdHandler;
+import org.apache.james.protocols.smtp.core.esmtp.MailSizeEsmtpExtension;
+import org.apache.james.protocols.smtp.core.log.HookResultLogger;
+import org.apache.james.smtpserver.AuthRequiredToRelayRcptHook;
+import org.apache.james.smtpserver.JamesDataCmdHandler;
+import org.apache.james.smtpserver.JamesMailCmdHandler;
+import org.apache.james.smtpserver.JamesRcptCmdHandler;
+import org.apache.james.smtpserver.fastfail.ValidRcptHandler;
+
+/**
+ * This class allows creating a LMTP server executing the mailet container
+ */
+public class MailetContainerCmdHandlerLoader implements HandlersPackage {
+
+    private final List<String> commands = new LinkedList<>();
+
+
+    public MailetContainerCmdHandlerLoader() {
+        Stream.of(
+            WelcomeMessageHandler.class,
+            CommandDispatcher.class,
+            JamesDataCmdHandler.class,
+            ExpnCmdHandler.class,
+            LhloCmdHandler.class,
+            JamesMailCmdHandler.class,
+            NoopCmdHandler.class,
+            QuitCmdHandler.class,
+            JamesRcptCmdHandler.class,
+            ValidRcptHandler.class,
+            RsetCmdHandler.class,
+            VrfyCmdHandler.class,
+            MailSizeEsmtpExtension.class,
+            AuthRequiredToRelayRcptHook.class,
+            PostmasterAbuseRcptHook.class,
+            ReceivedDataLineFilter.class,
+            MailetContainerHandler.class,
+            CommandHandlerResultLogger.class,
+            NoopJamesMessageHook.class,
+            HookResultLogger.class)
+        .map(Class::getName)
+        .forEachOrdered(commands::add);
+    }
+
+    @Override
+    public List<String> getHandlers() {
+        return commands;
+    }
+}
diff --git a/server/protocols/protocols-lmtp/src/main/java/org/apache/james/lmtpserver/MailetContainerHandler.java b/server/protocols/protocols-lmtp/src/main/java/org/apache/james/lmtpserver/MailetContainerHandler.java
new file mode 100644
index 0000000..fcb58c0
--- /dev/null
+++ b/server/protocols/protocols-lmtp/src/main/java/org/apache/james/lmtpserver/MailetContainerHandler.java
@@ -0,0 +1,59 @@
+/****************************************************************
+ * 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.                                           *
+ ****************************************************************/
+
+package org.apache.james.lmtpserver;
+
+import javax.inject.Inject;
+import javax.mail.MessagingException;
+
+import org.apache.james.mailetcontainer.api.MailProcessor;
+import org.apache.james.protocols.api.Response;
+import org.apache.james.protocols.smtp.SMTPResponse;
+import org.apache.james.protocols.smtp.SMTPRetCode;
+import org.apache.james.protocols.smtp.SMTPSession;
+import org.apache.james.protocols.smtp.core.AbstractHookableCmdHandler;
+import org.apache.james.protocols.smtp.dsn.DSNStatus;
+import org.apache.james.protocols.smtp.hook.HookResult;
+import org.apache.james.protocols.smtp.hook.HookReturnCode;
+import org.apache.james.smtpserver.DataLineJamesMessageHookHandler;
+import org.apache.mailet.Mail;
+
+public class MailetContainerHandler extends DataLineJamesMessageHookHandler {
+    private final MailProcessor mailProcessor;
+
+    @Inject
+    public MailetContainerHandler(MailProcessor mailProcessor) {
+        this.mailProcessor = mailProcessor;
+    }
+
+    @Override
+    protected Response processExtensions(SMTPSession session, Mail mail) {
+        try {
+            mailProcessor.service(mail);
+
+            return AbstractHookableCmdHandler.calcDefaultSMTPResponse(HookResult.builder()
+                .hookReturnCode(HookReturnCode.ok())
+                .smtpReturnCode(SMTPRetCode.MAIL_OK)
+                .smtpDescription(DSNStatus.getStatus(DSNStatus.SUCCESS, DSNStatus.CONTENT_OTHER) + " Message received")
+                .build());
+        } catch (MessagingException e) {
+            return new SMTPResponse(SMTPRetCode.LOCAL_ERROR, DSNStatus.getStatus(DSNStatus.TRANSIENT, DSNStatus.UNDEFINED_STATUS) + "Temporary error deliver message");
+        }
+    }
+}
diff --git a/server/protocols/protocols-lmtp/src/main/java/org/apache/james/lmtpserver/NoopJamesMessageHook.java b/server/protocols/protocols-lmtp/src/main/java/org/apache/james/lmtpserver/NoopJamesMessageHook.java
new file mode 100644
index 0000000..d6719a7
--- /dev/null
+++ b/server/protocols/protocols-lmtp/src/main/java/org/apache/james/lmtpserver/NoopJamesMessageHook.java
@@ -0,0 +1,32 @@
+/****************************************************************
+ * 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.                                           *
+ ****************************************************************/
+
+package org.apache.james.lmtpserver;
+
+import org.apache.james.protocols.smtp.SMTPSession;
+import org.apache.james.protocols.smtp.hook.HookResult;
+import org.apache.james.smtpserver.JamesMessageHook;
+import org.apache.mailet.Mail;
+
+public class NoopJamesMessageHook implements JamesMessageHook {
+    @Override
+    public HookResult onMessage(SMTPSession session, Mail mail) {
+        return HookResult.DECLINED;
+    }
+}
diff --git a/server/protocols/protocols-lmtp/src/test/java/org/apache/james/lmtpserver/MailetContainerHandlerTest.java b/server/protocols/protocols-lmtp/src/test/java/org/apache/james/lmtpserver/MailetContainerHandlerTest.java
new file mode 100644
index 0000000..98ecfb9
--- /dev/null
+++ b/server/protocols/protocols-lmtp/src/test/java/org/apache/james/lmtpserver/MailetContainerHandlerTest.java
@@ -0,0 +1,156 @@
+/****************************************************************
+ * 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.                                           *
+ ****************************************************************/
+
+package org.apache.james.lmtpserver;
+
+import static org.apache.james.jmap.JMAPTestingConstants.DOMAIN;
+import static org.apache.james.jmap.JMAPTestingConstants.LOCALHOST_IP;
+import static org.assertj.core.api.Assertions.assertThat;
+
+import java.net.InetSocketAddress;
+import java.nio.ByteBuffer;
+import java.nio.channels.SocketChannel;
+import java.nio.charset.StandardCharsets;
+import java.util.ArrayList;
+import java.util.List;
+
+import org.apache.james.core.Domain;
+import org.apache.james.core.Username;
+import org.apache.james.dnsservice.api.DNSService;
+import org.apache.james.dnsservice.api.InMemoryDNSService;
+import org.apache.james.domainlist.api.DomainList;
+import org.apache.james.domainlist.lib.DomainListConfiguration;
+import org.apache.james.domainlist.memory.MemoryDomainList;
+import org.apache.james.filesystem.api.FileSystem;
+import org.apache.james.lmtpserver.netty.LMTPServerFactory;
+import org.apache.james.mailetcontainer.api.MailProcessor;
+import org.apache.james.metrics.api.MetricFactory;
+import org.apache.james.metrics.tests.RecordingMetricFactory;
+import org.apache.james.protocols.lib.mock.ConfigLoader;
+import org.apache.james.protocols.lib.mock.MockProtocolHandlerLoader;
+import org.apache.james.rrt.api.AliasReverseResolver;
+import org.apache.james.rrt.api.CanSendFrom;
+import org.apache.james.rrt.api.RecipientRewriteTable;
+import org.apache.james.rrt.api.RecipientRewriteTableConfiguration;
+import org.apache.james.rrt.lib.AliasReverseResolverImpl;
+import org.apache.james.rrt.lib.CanSendFromImpl;
+import org.apache.james.rrt.memory.MemoryRecipientRewriteTable;
+import org.apache.james.server.core.configuration.Configuration;
+import org.apache.james.server.core.filesystem.FileSystemImpl;
+import org.apache.james.user.api.UsersRepository;
+import org.apache.james.user.memory.MemoryUsersRepository;
+import org.apache.mailet.Mail;
+import org.awaitility.Awaitility;
+import org.jboss.netty.util.HashedWheelTimer;
+import org.junit.jupiter.api.AfterEach;
+import org.junit.jupiter.api.BeforeEach;
+import org.junit.jupiter.api.Test;
+
+class MailetContainerHandlerTest {
+    static class RecordingMailProcessor implements MailProcessor {
+        private final ArrayList<Mail> mails = new ArrayList<>();
+
+        @Override
+        public void service(Mail mail) {
+            mails.add(mail);
+        }
+
+        public List<Mail> getMails() {
+            return mails;
+        }
+    }
+
+    private RecordingMailProcessor recordingMailProcessor;
+    private LMTPServerFactory lmtpServerFactory;
+
+    @BeforeEach
+    void setUp()  throws Exception {
+        InMemoryDNSService dnsService = new InMemoryDNSService()
+            .registerMxRecord(Domain.LOCALHOST.asString(), "127.0.0.1")
+            .registerMxRecord("examplebis.local", "127.0.0.1")
+            .registerMxRecord("127.0.0.1", "127.0.0.1");
+        MemoryDomainList domainList = new MemoryDomainList(dnsService);
+        domainList.configure(DomainListConfiguration.builder()
+            .autoDetect(false)
+            .autoDetectIp(false)
+            .build());
+        recordingMailProcessor = new RecordingMailProcessor();
+
+        domainList.addDomain(Domain.of("examplebis.local"));
+        MemoryUsersRepository usersRepository = MemoryUsersRepository.withVirtualHosting(domainList);
+
+        usersRepository.addUser(Username.of("bob@examplebis.local"), "pwd");
+
+        FileSystem fileSystem = new FileSystemImpl(Configuration.builder()
+            .workingDirectory("../")
+            .configurationFromClasspath()
+            .build().directories());
+        MemoryRecipientRewriteTable rewriteTable = new MemoryRecipientRewriteTable();
+        rewriteTable.setConfiguration(RecipientRewriteTableConfiguration.DEFAULT_ENABLED);
+        AliasReverseResolver aliasReverseResolver = new AliasReverseResolverImpl(rewriteTable);
+        CanSendFrom canSendFrom = new CanSendFromImpl(rewriteTable, aliasReverseResolver);
+        MockProtocolHandlerLoader loader = MockProtocolHandlerLoader.builder()
+            .put(binder -> binder.bind(DomainList.class).toInstance(domainList))
+            .put(binder -> binder.bind(RecipientRewriteTable.class).toInstance(rewriteTable))
+            .put(binder -> binder.bind(CanSendFrom.class).toInstance(canSendFrom))
+            .put(binder -> binder.bind(MailProcessor.class).toInstance(recordingMailProcessor))
+            .put(binder -> binder.bind(FileSystem.class).toInstance(fileSystem))
+            .put(binder -> binder.bind(DNSService.class).toInstance(dnsService))
+            .put(binder -> binder.bind(UsersRepository.class).toInstance(usersRepository))
+            .put(binder -> binder.bind(MetricFactory.class).to(RecordingMetricFactory.class))
+            .build();
+        lmtpServerFactory = new LMTPServerFactory(loader, fileSystem, new RecordingMetricFactory(), new HashedWheelTimer());
+
+        lmtpServerFactory.configure(ConfigLoader.getConfig(ClassLoader.getSystemResourceAsStream("lmtpmailet.xml")));
+        lmtpServerFactory.init();
+    }
+
+    @AfterEach
+    void tearDown() {
+        lmtpServerFactory.destroy();
+    }
+
+    @Test
+    void emailShouldTriggerTheMailProcessing() throws Exception {
+        SocketChannel server = SocketChannel.open();
+        server.connect(new InetSocketAddress(LOCALHOST_IP, getLmtpPort()));
+
+        server.write(ByteBuffer.wrap(("LHLO <" + DOMAIN + ">\r\n").getBytes(StandardCharsets.UTF_8)));
+        server.write(ByteBuffer.wrap(("MAIL FROM: <bob@" + DOMAIN + ">\r\n").getBytes(StandardCharsets.UTF_8)));
+        server.write(ByteBuffer.wrap(("RCPT TO: <bo...@examplebis.local>\r\n").getBytes(StandardCharsets.UTF_8)));
+        server.write(ByteBuffer.wrap(("DATA\r\n").getBytes(StandardCharsets.UTF_8)));
+        server.read(ByteBuffer.allocate(1024)); // needed to synchronize
+        server.write(ByteBuffer.wrap(("header:value\r\n\r\nbody").getBytes(StandardCharsets.UTF_8)));
+        server.write(ByteBuffer.wrap(("\r\n").getBytes(StandardCharsets.UTF_8)));
+        server.write(ByteBuffer.wrap((".").getBytes(StandardCharsets.UTF_8)));
+        server.write(ByteBuffer.wrap(("\r\n").getBytes(StandardCharsets.UTF_8)));
+        server.write(ByteBuffer.wrap(("QUIT\r\n").getBytes(StandardCharsets.UTF_8)));
+
+        Awaitility.await()
+            .untilAsserted(() -> assertThat(recordingMailProcessor.getMails()).hasSize(1));
+    }
+
+    public int getLmtpPort() {
+        return lmtpServerFactory.getServers().stream()
+            .findFirst()
+            .flatMap(server -> server.getListenAddresses().stream().findFirst())
+            .map(InetSocketAddress::getPort)
+            .orElseThrow(() -> new IllegalStateException("LMTP server not defined"));
+    }
+}
\ No newline at end of file
diff --git a/server/protocols/protocols-lmtp/src/test/resources/lmtpmailet.xml b/server/protocols/protocols-lmtp/src/test/resources/lmtpmailet.xml
new file mode 100644
index 0000000..3b1d4e1
--- /dev/null
+++ b/server/protocols/protocols-lmtp/src/test/resources/lmtpmailet.xml
@@ -0,0 +1,34 @@
+<?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.
+ -->
+
+<lmtpservers>
+    <lmtpserver enabled="true">
+        <jmxName>lmtpserver</jmxName>
+        <bind>0.0.0.0:0</bind>
+        <connectionBacklog>200</connectionBacklog>
+        <connectiontimeout>1200</connectiontimeout>
+        <connectionLimit>0</connectionLimit>
+        <connectionLimitPerIP>0</connectionLimitPerIP>
+        <maxmessagesize>0</maxmessagesize>
+        <handlerchain coreHandlersPackage="org.apache.james.lmtpserver.MailetContainerCmdHandlerLoader">
+            <handler class="org.apache.james.lmtpserver.MailetContainerCmdHandlerLoader"/>
+        </handlerchain>
+    </lmtpserver>
+</lmtpservers>

---------------------------------------------------------------------
To unsubscribe, e-mail: notifications-unsubscribe@james.apache.org
For additional commands, e-mail: notifications-help@james.apache.org