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


The following commit(s) were added to refs/heads/master by this push:
     new ccb731a  JAMES-2912 RemoteDelivery: add a onSuccess processor (#776)
ccb731a is described below

commit ccb731acf93e01d389da416680ebd445dc663dbb
Author: Benoit TELLIER <[email protected]>
AuthorDate: Thu Dec 9 14:14:59 2021 +0700

    JAMES-2912 RemoteDelivery: add a onSuccess processor (#776)
    
    Convenient to emit success DSNs and track
    successful sends, eg via logging.
---
 .../docs/modules/ROOT/partials/RemoteDelivery.adoc |   6 +
 .../james/utils/MailRepositoryProbeImpl.java       |   6 +
 .../james/transport/mailets/RemoteDelivery.java    |   6 +
 .../mailets/remote/delivery/DeliveryRunnable.java  |  11 +-
 .../mailets/remote/delivery/MailDelivrer.java      |  31 ++-
 .../delivery/RemoteDeliveryConfiguration.java      |   7 +
 .../remote/delivery/DeliveryRunnableTest.java      |   3 +-
 .../mailets/remote/delivery/MailDelivrerTest.java  |   3 +-
 .../james/mailets/RemoteDeliveryOnSuccessTest.java | 235 +++++++++++++++++++++
 9 files changed, 297 insertions(+), 11 deletions(-)

diff --git 
a/server/apps/distributed-app/docs/modules/ROOT/partials/RemoteDelivery.adoc 
b/server/apps/distributed-app/docs/modules/ROOT/partials/RemoteDelivery.adoc
index 89ab13c..18c3a57 100644
--- a/server/apps/distributed-app/docs/modules/ROOT/partials/RemoteDelivery.adoc
+++ b/server/apps/distributed-app/docs/modules/ROOT/partials/RemoteDelivery.adoc
@@ -35,6 +35,12 @@ Default is 0.
 * *connectionTimeout* (optional) - an Integer for the Socket connection 
timeout in milliseconds. Default is 60000
 * *bounceProcessor* (optional) - a String containing the name of the mailet 
processor to pass messages that cannot
 be delivered to for DSN bounce processing. Default is to send a traditional 
message containing the bounce details.
+* *onSuccess* (optional) - if specified, this processor is called for each 
email successfully sent to remote third parties.
+
+When using bounceProcessor or onSuccess processors, take special care of error 
handling (see onMailetException and onMatcherException)
+ to avoid confusing situations. Also remember that on partial delivery, both 
processors will be used: *onSuccess* with successfull recipients,
+ and *bounceProcessor* with failed recipients.
+
 * *startTLS* (optional) - a Boolean (true/false) indicating whether the 
STARTTLS command (if supported by the server)
 to switch the connection to a TLS-protected connection before issuing any 
login commands. Default is false.
 * *sslEnable* (optional) - a Boolean (true/false) indicating whether to use 
SSL to connect and use the SSL port unless
diff --git 
a/server/container/guice/common/src/main/java/org/apache/james/utils/MailRepositoryProbeImpl.java
 
b/server/container/guice/common/src/main/java/org/apache/james/utils/MailRepositoryProbeImpl.java
index 2d88a87..129fabd 100644
--- 
a/server/container/guice/common/src/main/java/org/apache/james/utils/MailRepositoryProbeImpl.java
+++ 
b/server/container/guice/common/src/main/java/org/apache/james/utils/MailRepositoryProbeImpl.java
@@ -26,6 +26,7 @@ import javax.inject.Inject;
 import org.apache.james.mailrepository.api.MailKey;
 import org.apache.james.mailrepository.api.MailRepositoryStore;
 import org.apache.james.mailrepository.api.MailRepositoryUrl;
+import org.apache.mailet.Mail;
 
 import com.google.common.collect.ImmutableList;
 
@@ -55,6 +56,11 @@ public class MailRepositoryProbeImpl implements GuiceProbe {
                 .list());
     }
 
+    public Mail getMail(MailRepositoryUrl url, MailKey key) throws Exception {
+        return repositoryStore.select(url)
+                .retrieve(key);
+    }
+
     public List<MailRepositoryUrl> listRepositoryUrls() {
         return repositoryStore.getUrls()
             .collect(ImmutableList.toImmutableList());
diff --git 
a/server/mailet/mailets/src/main/java/org/apache/james/transport/mailets/RemoteDelivery.java
 
b/server/mailet/mailets/src/main/java/org/apache/james/transport/mailets/RemoteDelivery.java
index 130267d..67e95d5 100644
--- 
a/server/mailet/mailets/src/main/java/org/apache/james/transport/mailets/RemoteDelivery.java
+++ 
b/server/mailet/mailets/src/main/java/org/apache/james/transport/mailets/RemoteDelivery.java
@@ -83,6 +83,12 @@ import com.google.common.collect.HashMultimap;
  * <li><b>connectionTimeout</b> (optional) - an Integer for the Socket 
connection timeout in milliseconds. Default is 60000</li>
  * <li><b>bounceProcessor</b> (optional) - a String containing the name of the 
mailet processor to pass messages that cannot
  * be delivered to for DSN bounce processing. Default is to send a traditional 
message containing the bounce details.</li>
+ * <li><b>onSuccess</b> (optional) - if specified, this processor is called 
for each email successfully sent to remote third parties.</li>
+ *
+ * When using bounceProcessor or onSuccess processors, take special care of 
error handling (see onMailetException and onMatcherException)
+ * to avoid confusing situations. Also remember that on partial delivery, both 
processors will be used: <code>onSuccess</code> with successfull recipients,
+ * and <code>bounceProcessor</code> with failed recipients.
+ *
  * <li><b>startTLS</b> (optional) - a Boolean (true/false) indicating whether 
the STARTTLS command (if supported by the server)
  * to switch the connection to a TLS-protected connection before issuing any 
login commands. Default is false.</li>
  * <li><b>sslEnable</b> (optional) - a Boolean (true/false) indicating whether 
to use SSL to connect and use the SSL port unless
diff --git 
a/server/mailet/mailets/src/main/java/org/apache/james/transport/mailets/remote/delivery/DeliveryRunnable.java
 
b/server/mailet/mailets/src/main/java/org/apache/james/transport/mailets/remote/delivery/DeliveryRunnable.java
index 23c8802..e42f0be 100644
--- 
a/server/mailet/mailets/src/main/java/org/apache/james/transport/mailets/remote/delivery/DeliveryRunnable.java
+++ 
b/server/mailet/mailets/src/main/java/org/apache/james/transport/mailets/remote/delivery/DeliveryRunnable.java
@@ -39,6 +39,7 @@ import org.apache.mailet.MailetContext;
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
 
+import com.github.fge.lambdas.Throwing;
 import com.google.common.annotations.VisibleForTesting;
 
 import reactor.core.Disposable;
@@ -62,19 +63,20 @@ public class DeliveryRunnable implements Disposable {
     private final Bouncer bouncer;
     private final MailDelivrer mailDelivrer;
     private final Supplier<Date> dateSupplier;
+    private final MailetContext mailetContext;
     private Disposable disposable;
     private Scheduler remoteDeliveryScheduler;
 
     public DeliveryRunnable(MailQueue queue, RemoteDeliveryConfiguration 
configuration, DNSService dnsServer, MetricFactory metricFactory,
                             MailetContext mailetContext, Bouncer bouncer) {
         this(queue, configuration, metricFactory, bouncer,
-            new MailDelivrer(configuration, new 
MailDelivrerToHost(configuration, mailetContext), dnsServer, bouncer),
-            CURRENT_DATE_SUPPLIER);
+            new MailDelivrer(configuration, new 
MailDelivrerToHost(configuration, mailetContext), dnsServer, bouncer, 
mailetContext),
+            CURRENT_DATE_SUPPLIER, mailetContext);
     }
 
     @VisibleForTesting
     DeliveryRunnable(MailQueue queue, RemoteDeliveryConfiguration 
configuration, MetricFactory metricFactory, Bouncer bouncer,
-                     MailDelivrer mailDelivrer, Supplier<Date> dateSupplier) {
+                     MailDelivrer mailDelivrer, Supplier<Date> dateSupplier, 
MailetContext mailetContext) {
         this.queue = queue;
         this.configuration = configuration;
         this.outgoingMailsMetric = metricFactory.generate(OUTGOING_MAILS);
@@ -82,6 +84,7 @@ public class DeliveryRunnable implements Disposable {
         this.mailDelivrer = mailDelivrer;
         this.dateSupplier = dateSupplier;
         this.metricFactory = metricFactory;
+        this.mailetContext = mailetContext;
     }
 
     public void start() {
@@ -136,6 +139,8 @@ public class DeliveryRunnable implements Disposable {
         switch (executionResult.getExecutionState()) {
             case SUCCESS:
                 outgoingMailsMetric.increment();
+                configuration.getOnSuccess()
+                    .ifPresent(Throwing.consumer(onSuccess -> 
mailetContext.sendMail(mail, onSuccess)));
                 break;
             case TEMPORARY_FAILURE:
                 handleTemporaryFailure(mail, executionResult);
diff --git 
a/server/mailet/mailets/src/main/java/org/apache/james/transport/mailets/remote/delivery/MailDelivrer.java
 
b/server/mailet/mailets/src/main/java/org/apache/james/transport/mailets/remote/delivery/MailDelivrer.java
index b7153a4..04dfa2f 100644
--- 
a/server/mailet/mailets/src/main/java/org/apache/james/transport/mailets/remote/delivery/MailDelivrer.java
+++ 
b/server/mailet/mailets/src/main/java/org/apache/james/transport/mailets/remote/delivery/MailDelivrer.java
@@ -21,7 +21,6 @@ package org.apache.james.transport.mailets.remote.delivery;
 
 import java.io.IOException;
 import java.util.Arrays;
-import java.util.Collection;
 import java.util.HashSet;
 import java.util.Iterator;
 import java.util.List;
@@ -37,11 +36,14 @@ import org.apache.james.core.Domain;
 import org.apache.james.core.MailAddress;
 import org.apache.james.dnsservice.api.DNSService;
 import org.apache.james.dnsservice.api.TemporaryResolutionException;
+import org.apache.james.lifecycle.api.LifecycleUtil;
 import org.apache.mailet.HostAddress;
 import org.apache.mailet.Mail;
+import org.apache.mailet.MailetContext;
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
 
+import com.github.fge.lambdas.Throwing;
 import com.google.common.annotations.VisibleForTesting;
 import com.google.common.base.Preconditions;
 import com.google.common.collect.ImmutableList;
@@ -56,18 +58,20 @@ public class MailDelivrer {
     private final DnsHelper dnsHelper;
     private final MessageComposer messageComposer;
     private final Bouncer bouncer;
+    private final MailetContext mailetContext;
 
-    public MailDelivrer(RemoteDeliveryConfiguration configuration, 
MailDelivrerToHost mailDelivrerToHost, DNSService dnsServer, Bouncer bouncer) {
-        this(configuration, mailDelivrerToHost, new DnsHelper(dnsServer, 
configuration), bouncer);
+    public MailDelivrer(RemoteDeliveryConfiguration configuration, 
MailDelivrerToHost mailDelivrerToHost, DNSService dnsServer, Bouncer bouncer, 
MailetContext mailetContext) {
+        this(configuration, mailDelivrerToHost, new DnsHelper(dnsServer, 
configuration), bouncer, mailetContext);
     }
 
     @VisibleForTesting
-    MailDelivrer(RemoteDeliveryConfiguration configuration, MailDelivrerToHost 
mailDelivrerToHost, DnsHelper dnsHelper, Bouncer bouncer) {
+    MailDelivrer(RemoteDeliveryConfiguration configuration, MailDelivrerToHost 
mailDelivrerToHost, DnsHelper dnsHelper, Bouncer bouncer, MailetContext 
mailetContext) {
         this.configuration = configuration;
         this.mailDelivrerToHost = mailDelivrerToHost;
         this.dnsHelper = dnsHelper;
         this.messageComposer = new MessageComposer(configuration);
         this.bouncer = bouncer;
+        this.mailetContext = mailetContext;
     }
 
     /**
@@ -135,7 +139,22 @@ public class MailDelivrer {
             } catch (SendFailedException sfe) {
                 lastError = handleSendFailExceptionOnMxIteration(mail, sfe);
 
-                targetAddresses.removeAll(listDeliveredAddresses(sfe));
+                ImmutableList<InternetAddress> deliveredAddresses = 
listDeliveredAddresses(sfe);
+
+                configuration.getOnSuccess()
+                    .ifPresent(Throwing.consumer(onSuccess -> {
+                        Mail copy = mail.duplicate();
+                        try {
+                            copy.setRecipients(deliveredAddresses.stream()
+                                .map(Throwing.function(MailAddress::new))
+                                .collect(ImmutableList.toImmutableList()));
+                            mailetContext.sendMail(copy, onSuccess);
+                        } finally {
+                            LifecycleUtil.dispose(copy);
+                        }
+                    }));
+
+                targetAddresses.removeAll(deliveredAddresses);
             } catch (MessagingException me) {
                 lastError = handleMessagingException(mail, me);
                 if (configuration.isDebug()) {
@@ -157,7 +176,7 @@ public class MailDelivrer {
         return ExecutionResult.temporaryFailure();
     }
 
-    private Collection<InternetAddress> 
listDeliveredAddresses(SendFailedException sfe) {
+    private ImmutableList<InternetAddress> 
listDeliveredAddresses(SendFailedException sfe) {
         return Optional.ofNullable(sfe.getValidSentAddresses())
             .map(addresses ->
                 Arrays.stream(addresses)
diff --git 
a/server/mailet/mailets/src/main/java/org/apache/james/transport/mailets/remote/delivery/RemoteDeliveryConfiguration.java
 
b/server/mailet/mailets/src/main/java/org/apache/james/transport/mailets/remote/delivery/RemoteDeliveryConfiguration.java
index fa5908c..036106e 100644
--- 
a/server/mailet/mailets/src/main/java/org/apache/james/transport/mailets/remote/delivery/RemoteDeliveryConfiguration.java
+++ 
b/server/mailet/mailets/src/main/java/org/apache/james/transport/mailets/remote/delivery/RemoteDeliveryConfiguration.java
@@ -62,6 +62,7 @@ public class RemoteDeliveryConfiguration {
     public static final String MAX_RETRIES = "maxRetries";
     public static final String DELAY_TIME = "delayTime";
     public static final String DEBUG = "debug";
+    public static final String ON_SUCCESS = "onSuccess";
     public static final int DEFAULT_SMTP_TIMEOUT = 180000;
     public static final MailQueueName DEFAULT_OUTGOING_QUEUE_NAME = 
MailQueueName.of("outgoing");
     public static final int DEFAULT_CONNECTION_TIMEOUT = 60000;
@@ -88,6 +89,7 @@ public class RemoteDeliveryConfiguration {
     private final String authUser;
     private final String authPass;
     private final Properties javaxAdditionalProperties;
+    private final Optional<String> onSuccess;
 
     public RemoteDeliveryConfiguration(MailetConfig mailetConfig, DomainList 
domainList) {
         isDebug = MailetUtil.getInitParameter(mailetConfig, 
DEBUG).orElse(false);
@@ -121,6 +123,7 @@ public class RemoteDeliveryConfiguration {
         }
         isBindUsed = bindAddress != null;
         javaxAdditionalProperties = computeJavaxProperties(mailetConfig);
+        onSuccess = 
Optional.ofNullable(mailetConfig.getInitParameter(ON_SUCCESS));
     }
 
     private Properties computeJavaxProperties(MailetConfig mailetConfig) {
@@ -322,4 +325,8 @@ public class RemoteDeliveryConfiguration {
     public String getBindAddress() {
         return bindAddress;
     }
+
+    public Optional<String> getOnSuccess() {
+        return onSuccess;
+    }
 }
diff --git 
a/server/mailet/mailets/src/test/java/org/apache/james/transport/mailets/remote/delivery/DeliveryRunnableTest.java
 
b/server/mailet/mailets/src/test/java/org/apache/james/transport/mailets/remote/delivery/DeliveryRunnableTest.java
index 0990cd0..2419555 100644
--- 
a/server/mailet/mailets/src/test/java/org/apache/james/transport/mailets/remote/delivery/DeliveryRunnableTest.java
+++ 
b/server/mailet/mailets/src/test/java/org/apache/james/transport/mailets/remote/delivery/DeliveryRunnableTest.java
@@ -40,6 +40,7 @@ import org.apache.james.queue.api.MailQueue;
 import org.apache.mailet.Attribute;
 import org.apache.mailet.AttributeValue;
 import org.apache.mailet.Mail;
+import org.apache.mailet.MailetContext;
 import org.apache.mailet.base.test.FakeMail;
 import org.apache.mailet.base.test.FakeMailetConfig;
 import org.junit.jupiter.api.BeforeEach;
@@ -68,7 +69,7 @@ public class DeliveryRunnableTest {
         bouncer = mock(Bouncer.class);
         mailDelivrer = mock(MailDelivrer.class);
         mailQueue = mock(MailQueue.class);
-        testee = new DeliveryRunnable(mailQueue, configuration, metricFactory, 
bouncer, mailDelivrer, FIXED_DATE_SUPPLIER);
+        testee = new DeliveryRunnable(mailQueue, configuration, metricFactory, 
bouncer, mailDelivrer, FIXED_DATE_SUPPLIER, mock(MailetContext.class));
     }
 
     @Test
diff --git 
a/server/mailet/mailets/src/test/java/org/apache/james/transport/mailets/remote/delivery/MailDelivrerTest.java
 
b/server/mailet/mailets/src/test/java/org/apache/james/transport/mailets/remote/delivery/MailDelivrerTest.java
index 61cd095..7d711d7 100644
--- 
a/server/mailet/mailets/src/test/java/org/apache/james/transport/mailets/remote/delivery/MailDelivrerTest.java
+++ 
b/server/mailet/mailets/src/test/java/org/apache/james/transport/mailets/remote/delivery/MailDelivrerTest.java
@@ -40,6 +40,7 @@ import 
org.apache.james.dnsservice.api.TemporaryResolutionException;
 import org.apache.james.domainlist.api.DomainList;
 import org.apache.mailet.HostAddress;
 import org.apache.mailet.Mail;
+import org.apache.mailet.MailetContext;
 import org.apache.mailet.base.MailAddressFixture;
 import org.apache.mailet.base.test.FakeMail;
 import org.apache.mailet.base.test.FakeMailetConfig;
@@ -74,7 +75,7 @@ class MailDelivrerTest {
             .setProperty(RemoteDeliveryConfiguration.DEBUG, "true")
             .build(),
             mock(DomainList.class));
-        testee = new MailDelivrer(configuration, mailDelivrerToHost, 
dnsHelper, bouncer);
+        testee = new MailDelivrer(configuration, mailDelivrerToHost, 
dnsHelper, bouncer, mock(MailetContext.class));
     }
 
     @Test
diff --git 
a/server/mailet/remote-delivery-integration-testing/src/test/java/org/apache/james/mailets/RemoteDeliveryOnSuccessTest.java
 
b/server/mailet/remote-delivery-integration-testing/src/test/java/org/apache/james/mailets/RemoteDeliveryOnSuccessTest.java
new file mode 100644
index 0000000..42c6c65
--- /dev/null
+++ 
b/server/mailet/remote-delivery-integration-testing/src/test/java/org/apache/james/mailets/RemoteDeliveryOnSuccessTest.java
@@ -0,0 +1,235 @@
+/****************************************************************
+ * 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.mailets;
+
+import static org.apache.james.MemoryJamesServerMain.SMTP_AND_IMAP_MODULE;
+import static org.apache.james.mailets.configuration.Constants.DEFAULT_DOMAIN;
+import static org.apache.james.mailets.configuration.Constants.LOCALHOST_IP;
+import static org.apache.james.mailets.configuration.Constants.PASSWORD;
+import static 
org.apache.james.mailets.configuration.Constants.awaitAtMostOneMinute;
+import static 
org.apache.james.mock.smtp.server.ConfigurationClient.BehaviorsParamsBuilder.ConditionStep.anyInput;
+import static 
org.apache.james.mock.smtp.server.ConfigurationClient.BehaviorsParamsBuilder.ConditionStep.inputContaining;
+import static 
org.apache.james.mock.smtp.server.ConfigurationClient.BehaviorsParamsBuilder.ResponseStep.serviceNotAvailable;
+import static org.assertj.core.api.Assertions.assertThat;
+
+import java.io.File;
+
+import javax.mail.internet.AddressException;
+
+import org.apache.james.core.MailAddress;
+import org.apache.james.dnsservice.api.DNSService;
+import org.apache.james.dnsservice.api.InMemoryDNSService;
+import org.apache.james.mailets.configuration.CommonProcessors;
+import org.apache.james.mailets.configuration.MailetConfiguration;
+import org.apache.james.mailets.configuration.MailetContainer;
+import org.apache.james.mailets.configuration.ProcessorConfiguration;
+import org.apache.james.mailrepository.api.MailRepositoryUrl;
+import org.apache.james.mock.smtp.server.ConfigurationClient;
+import org.apache.james.mock.smtp.server.model.SMTPCommand;
+import org.apache.james.mock.smtp.server.testing.MockSmtpServerExtension;
+import org.apache.james.modules.protocols.SmtpGuiceProbe;
+import org.apache.james.transport.mailets.RemoteDelivery;
+import org.apache.james.transport.mailets.ToRepository;
+import org.apache.james.transport.matchers.All;
+import org.apache.james.utils.DataProbeImpl;
+import org.apache.james.utils.MailRepositoryProbeImpl;
+import org.apache.james.utils.SMTPMessageSender;
+import org.apache.mailet.Mail;
+import org.assertj.core.api.SoftAssertions;
+import org.junit.jupiter.api.AfterEach;
+import org.junit.jupiter.api.BeforeAll;
+import org.junit.jupiter.api.BeforeEach;
+import org.junit.jupiter.api.RepeatedTest;
+import org.junit.jupiter.api.Test;
+import org.junit.jupiter.api.extension.RegisterExtension;
+import org.junit.jupiter.api.io.TempDir;
+
+import com.github.fge.lambdas.Throwing;
+import com.google.common.collect.ImmutableList;
+
+class RemoteDeliveryOnSuccessTest {
+    public static final MailRepositoryUrl SUCCESS_REPOSITORY = 
MailRepositoryUrl.from("memory://var/mail/success/");
+
+    private static final String ANOTHER_DOMAIN = "other.com";
+    private static final String FROM = "from@" + DEFAULT_DOMAIN;
+    private static final String RECIPIENT = "touser@" + ANOTHER_DOMAIN;
+    private static final String RECIPIENT1 = "touser1@" + ANOTHER_DOMAIN;
+    private static final String RECIPIENT2 = "touser2@" + ANOTHER_DOMAIN;
+
+
+    private static MailAddress RECIPIENT1_ADDRESS;
+    private static MailAddress RECIPIENT2_ADDRESS;
+
+    private InMemoryDNSService inMemoryDNSService;
+    private ConfigurationClient mockSMTP1Configuration;
+
+    @RegisterExtension
+    public SMTPMessageSender messageSender = new 
SMTPMessageSender(DEFAULT_DOMAIN);
+    @RegisterExtension
+    public static MockSmtpServerExtension mockSmtp1 = new 
MockSmtpServerExtension();
+
+    private TemporaryJamesServer jamesServer;
+
+    @BeforeAll
+    static void setUpClass() throws AddressException {
+        RECIPIENT1_ADDRESS = new MailAddress(RECIPIENT1);
+        RECIPIENT2_ADDRESS = new MailAddress(RECIPIENT2);
+    }
+
+    @BeforeEach
+    void setUp(@TempDir File temporaryFolder) throws Exception {
+        inMemoryDNSService = new InMemoryDNSService()
+            .registerMxRecord(DEFAULT_DOMAIN, LOCALHOST_IP)
+            .registerMxRecord(ANOTHER_DOMAIN, 
mockSmtp1.getMockSmtp().getIPAddress());
+
+        jamesServer = TemporaryJamesServer.builder()
+            .withBase(SMTP_AND_IMAP_MODULE)
+            .withOverrides(binder -> 
binder.bind(DNSService.class).toInstance(inMemoryDNSService))
+            .withMailetContainer(MailetContainer.builder()
+                .putProcessor(CommonProcessors.simpleRoot())
+                .putProcessor(CommonProcessors.error())
+                .putProcessor(ProcessorConfiguration.builder()
+                    .enableJmx(false)
+                    .state("success")
+                    .addMailet(MailetConfiguration.builder()
+                        .matcher(All.class)
+                        .mailet(ToRepository.class)
+                        .addProperty("repositoryPath", 
SUCCESS_REPOSITORY.asString()))
+                    .build())
+                .putProcessor(directResolutionTransport())
+                .putProcessor(CommonProcessors.bounces()))
+            .build(temporaryFolder);
+        jamesServer.start();
+
+        jamesServer.getProbe(DataProbeImpl.class)
+            .fluent()
+            .addDomain(DEFAULT_DOMAIN)
+            .addUser(FROM, PASSWORD);
+
+        mockSMTP1Configuration = 
mockSmtp1.getMockSmtp().getConfigurationClient();
+
+        assertThat(mockSMTP1Configuration.version()).isEqualTo("0.4");
+    }
+
+    @AfterEach
+    void tearDown() {
+        mockSMTP1Configuration.clearBehaviors();
+        jamesServer.shutdown();
+    }
+
+    @Test
+    void deliveredEmailShouldTransitViaSuccessProcessor() throws Exception {
+        messageSender.connect(LOCALHOST_IP, 
jamesServer.getProbe(SmtpGuiceProbe.class).getSmtpPort())
+            .sendMessage(FROM, RECIPIENT);
+
+        awaitAtMostOneMinute.untilAsserted(() ->
+            assertThat(jamesServer.getProbe(MailRepositoryProbeImpl.class)
+                .listMailKeys(SUCCESS_REPOSITORY))
+                .hasSize(1));
+    }
+
+    @Test
+    void deliveredEmailShouldTransitViaSuccessProcessorAfterRetry() throws 
Exception {
+        mockSMTP1Configuration
+            .addNewBehavior()
+            .expect(SMTPCommand.RCPT_TO)
+            .matching(anyInput())
+            .thenRespond(serviceNotAvailable("mock response"))
+            .onlySomeTimes(1)
+            .post();
+
+        messageSender.connect(LOCALHOST_IP, 
jamesServer.getProbe(SmtpGuiceProbe.class).getSmtpPort())
+            .sendMessage(FROM, RECIPIENT);
+
+        awaitAtMostOneMinute.untilAsserted(() ->
+            assertThat(jamesServer.getProbe(MailRepositoryProbeImpl.class)
+                .listMailKeys(SUCCESS_REPOSITORY))
+                .hasSize(1));
+    }
+
+    @Test
+    void partiallyDeliveredEmailsShouldTransitViaSuccessProcessor() throws 
Exception {
+        mockSMTP1Configuration
+            .addNewBehavior()
+                .expect(SMTPCommand.RCPT_TO)
+                .matching(inputContaining(RECIPIENT1))
+                .thenRespond(serviceNotAvailable("mock response"))
+                .anyTimes()
+            .post();
+
+        messageSender.connect(LOCALHOST_IP, 
jamesServer.getProbe(SmtpGuiceProbe.class).getSmtpPort())
+            .sendMessage(FROM, ImmutableList.of(RECIPIENT1, RECIPIENT2));
+
+        MailRepositoryProbeImpl mailRepositoryProbe = 
jamesServer.getProbe(MailRepositoryProbeImpl.class);
+        awaitAtMostOneMinute.untilAsserted(() -> assertThat(mailRepositoryProbe
+                .listMailKeys(SUCCESS_REPOSITORY))
+                .hasSize(1));
+        assertThat(mailRepositoryProbe.getMail(SUCCESS_REPOSITORY, 
mailRepositoryProbe.listMailKeys(SUCCESS_REPOSITORY).get(0))
+            .getRecipients())
+            .containsOnly(RECIPIENT2_ADDRESS);
+    }
+
+    @Test
+    void partiallyDeliveredEmailsShouldTransitViaSuccessProcessorAfterRetry() 
throws Exception {
+        mockSMTP1Configuration
+            .addNewBehavior()
+                .expect(SMTPCommand.RCPT_TO)
+                .matching(inputContaining(RECIPIENT1))
+                .thenRespond(serviceNotAvailable("mock response"))
+                .onlySomeTimes(1)
+            .post();
+
+        messageSender.connect(LOCALHOST_IP, 
jamesServer.getProbe(SmtpGuiceProbe.class).getSmtpPort())
+            .sendMessage(FROM, ImmutableList.of(RECIPIENT1, RECIPIENT2));
+
+        MailRepositoryProbeImpl mailRepositoryProbe = 
jamesServer.getProbe(MailRepositoryProbeImpl.class);
+        awaitAtMostOneMinute.untilAsserted(() -> assertThat(mailRepositoryProbe
+                .listMailKeys(SUCCESS_REPOSITORY))
+                .hasSize(2));
+        Mail mail1 = mailRepositoryProbe.getMail(SUCCESS_REPOSITORY, 
mailRepositoryProbe.listMailKeys(SUCCESS_REPOSITORY).get(0));
+        Mail mail2 = mailRepositoryProbe.getMail(SUCCESS_REPOSITORY, 
mailRepositoryProbe.listMailKeys(SUCCESS_REPOSITORY).get(1));
+
+        SoftAssertions.assertSoftly(Throwing.consumer(softly -> {
+            assertThat(mail1.getRecipients()).hasSize(1);
+            assertThat(mail2.getRecipients()).hasSize(1);
+            assertThat(ImmutableList.builder()
+                .addAll(mail1.getRecipients())
+                .addAll(mail2.getRecipients())
+                .build())
+                .containsOnly(RECIPIENT1_ADDRESS, RECIPIENT2_ADDRESS);
+        }));
+    }
+
+    private ProcessorConfiguration.Builder directResolutionTransport() {
+        return ProcessorConfiguration.transport()
+            .addMailet(MailetConfiguration.BCC_STRIPPER)
+            .addMailet(MailetConfiguration.LOCAL_DELIVERY)
+            .addMailet(MailetConfiguration.builder()
+                .mailet(RemoteDelivery.class)
+                .matcher(All.class)
+                .addProperty("outgoingQueue", "outgoing")
+                .addProperty("delayTime", "3 * 10 ms")
+                .addProperty("maxRetries", "3")
+                .addProperty("maxDnsProblemRetries", "0")
+                .addProperty("deliveryThreads", "2")
+                .addProperty("sendpartial", "true")
+                .addProperty("onSuccess", "success"));
+    }
+}

---------------------------------------------------------------------
To unsubscribe, e-mail: [email protected]
For additional commands, e-mail: [email protected]

Reply via email to