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 2022/03/28 07:23:52 UTC

[james-project] branch master updated: JAMES-3729 LocalDelivery error handling is non-standard (#936)

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 fff209a  JAMES-3729 LocalDelivery error handling is non-standard (#936)
fff209a is described below

commit fff209a0f9cd50c35fbec1596c9d6fa261c9d808
Author: vttran <vt...@linagora.com>
AuthorDate: Mon Mar 28 14:23:48 2022 +0700

    JAMES-3729 LocalDelivery error handling is non-standard (#936)
---
 .../james/transport/mailets/LocalDelivery.java     |  1 +
 .../transport/mailets/delivery/MailDispatcher.java | 44 ++++++++---
 .../mailets/delivery/MailDispatcherTest.java       | 85 ++++++++++++++++++++++
 3 files changed, 118 insertions(+), 12 deletions(-)

diff --git a/server/mailet/mailets/src/main/java/org/apache/james/transport/mailets/LocalDelivery.java b/server/mailet/mailets/src/main/java/org/apache/james/transport/mailets/LocalDelivery.java
index b6ac485..3b11028 100644
--- a/server/mailet/mailets/src/main/java/org/apache/james/transport/mailets/LocalDelivery.java
+++ b/server/mailet/mailets/src/main/java/org/apache/james/transport/mailets/LocalDelivery.java
@@ -77,6 +77,7 @@ public class LocalDelivery extends GenericMailet {
                 .metric(metricFactory.generate(LOCAL_DELIVERED_MAILS_METRIC_NAME))
                 .build())
             .consume(getInitParameter("consume", true))
+            .onMailetException(getInitParameter("onMailetException", Mail.ERROR))
             .mailetContext(getMailetContext())
             .build();
     }
diff --git a/server/mailet/mailets/src/main/java/org/apache/james/transport/mailets/delivery/MailDispatcher.java b/server/mailet/mailets/src/main/java/org/apache/james/transport/mailets/delivery/MailDispatcher.java
index b8cb379..c191d95 100644
--- a/server/mailet/mailets/src/main/java/org/apache/james/transport/mailets/delivery/MailDispatcher.java
+++ b/server/mailet/mailets/src/main/java/org/apache/james/transport/mailets/delivery/MailDispatcher.java
@@ -59,13 +59,15 @@ public class MailDispatcher {
     }
 
     public static class Builder {
-        static final boolean CONSUME = true;
+        static final boolean DEFAULT_CONSUME = true;
+        static final String DEFAULT_ERROR_PROCESSOR = Mail.ERROR;
         private MailStore mailStore;
-        private Optional<Boolean> consume = Optional.empty();
+        private Boolean consume;
         private MailetContext mailetContext;
+        private String onMailetException;
 
         public Builder consume(boolean consume) {
-            this.consume = Optional.of(consume);
+            this.consume = consume;
             return this;
         }
 
@@ -79,27 +81,39 @@ public class MailDispatcher {
             return this;
         }
 
+        public Builder onMailetException(String onMailetException) {
+            this.onMailetException = onMailetException;
+            return this;
+        }
+
         public MailDispatcher build() {
             Preconditions.checkNotNull(mailStore);
             Preconditions.checkNotNull(mailetContext);
-            return new MailDispatcher(mailStore, consume.orElse(CONSUME), mailetContext);
+            return new MailDispatcher(mailStore, mailetContext,
+                Optional.ofNullable(consume).orElse(DEFAULT_CONSUME),
+                Optional.ofNullable(onMailetException).orElse(DEFAULT_ERROR_PROCESSOR));
         }
-
     }
 
     private final MailStore mailStore;
-    private final boolean consume;
     private final MailetContext mailetContext;
+    private final boolean consume;
+    private final boolean ignoreError;
+    private final boolean propagate;
+    private final String errorProcessor;
 
-    private MailDispatcher(MailStore mailStore, boolean consume, MailetContext mailetContext) {
+    private MailDispatcher(MailStore mailStore, MailetContext mailetContext, boolean consume, String onMailetException) {
         this.mailStore = mailStore;
         this.consume = consume;
         this.mailetContext = mailetContext;
+        this.errorProcessor = onMailetException;
+        this.ignoreError = onMailetException.equalsIgnoreCase("ignore");
+        this.propagate = onMailetException.equalsIgnoreCase("propagate");
     }
 
     public void dispatch(Mail mail) throws MessagingException {
-        List<MailAddress> errors =  customizeHeadersAndDeliver(mail);
-        if (!errors.isEmpty()) {
+        List<MailAddress> errors = customizeHeadersAndDeliver(mail);
+        if (!errors.isEmpty() && !ignoreError) {
             // If there were errors, we redirect the email to the ERROR
             // processor.
             // In order for this server to meet the requirements of the SMTP
@@ -112,10 +126,13 @@ public class MailDispatcher {
                 .sender(mail.getMaybeSender())
                 .addRecipients(errors)
                 .mimeMessage(mail.getMessage())
-                .state(Mail.ERROR)
+                .state(errorProcessor)
                 .build();
-            mailetContext.sendMail(newMail);
-            LifecycleUtil.dispose(newMail);
+            try {
+                mailetContext.sendMail(newMail);
+            } finally {
+                LifecycleUtil.dispose(newMail);
+            }
         }
         if (consume) {
             // Consume this message
@@ -145,6 +162,9 @@ public class MailDispatcher {
                     Throwing.consumer(savedHeaders -> restoreHeaders(mail.getMessage(), savedHeaders)))
                     .onErrorResume(ex -> {
                         LOGGER.error("Error while storing mail. This is a final exception.", ex);
+                        if (propagate) {
+                            return Mono.error(ex);
+                        }
                         return Mono.just(recipient);
                     }))
             .collectList()
diff --git a/server/mailet/mailets/src/test/java/org/apache/james/transport/mailets/delivery/MailDispatcherTest.java b/server/mailet/mailets/src/test/java/org/apache/james/transport/mailets/delivery/MailDispatcherTest.java
index d00e156..744893c 100644
--- a/server/mailet/mailets/src/test/java/org/apache/james/transport/mailets/delivery/MailDispatcherTest.java
+++ b/server/mailet/mailets/src/test/java/org/apache/james/transport/mailets/delivery/MailDispatcherTest.java
@@ -20,6 +20,7 @@
 package org.apache.james.transport.mailets.delivery;
 
 import static org.assertj.core.api.Assertions.assertThat;
+import static org.assertj.core.api.Assertions.assertThatThrownBy;
 import static org.mockito.ArgumentMatchers.any;
 import static org.mockito.Mockito.doReturn;
 import static org.mockito.Mockito.mock;
@@ -336,6 +337,90 @@ class MailDispatcherTest {
         assertThat(mail.getMessage().getHeader(TEST_HEADER_NAME)).containsOnly(headerValue);
     }
 
+    @Test
+    void errorsShouldBeIgnoredWhenConfigIsProvided() throws Exception {
+        MailDispatcher testee = MailDispatcher.builder()
+            .mailetContext(fakeMailContext)
+            .mailStore(mailStore)
+            .onMailetException("ignore")
+            .build();
+
+        doReturn(Mono.error(new MessagingException()))
+            .when(mailStore)
+            .storeMail(any(MailAddress.class), any(Mail.class));
+
+        FakeMail mail = FakeMail.builder()
+            .name("name")
+            .sender(MailAddressFixture.OTHER_AT_JAMES)
+            .mimeMessage(MimeMessageBuilder.mimeMessageBuilder()
+                .setMultipartWithBodyParts(
+                    MimeMessageBuilder.bodyPartBuilder()
+                        .data("toto")))
+            .recipients(MailAddressFixture.ANY_AT_JAMES)
+            .state("state")
+            .build();
+
+        testee.dispatch(mail);
+
+        assertThat(fakeMailContext.getSentMails()).isEmpty();
+    }
+
+    @Test
+    void errorShouldFlowToTheErrorProcessor() throws Exception {
+        MailDispatcher testee = MailDispatcher.builder()
+            .mailetContext(fakeMailContext)
+            .mailStore(mailStore)
+            .onMailetException("errorProcessor1")
+            .build();
+
+        doReturn(Mono.error(new MessagingException()))
+            .when(mailStore)
+            .storeMail(any(MailAddress.class), any(Mail.class));
+
+        FakeMail mail = FakeMail.builder()
+            .name("name")
+            .sender(MailAddressFixture.OTHER_AT_JAMES)
+            .mimeMessage(MimeMessageBuilder.mimeMessageBuilder()
+                .setMultipartWithBodyParts(
+                    MimeMessageBuilder.bodyPartBuilder()
+                        .data("toto")))
+            .recipients(MailAddressFixture.ANY_AT_JAMES)
+            .state("state")
+            .build();
+
+        testee.dispatch(mail);
+
+        assertThat(fakeMailContext.getSentMails()).hasSize(1)
+            .allSatisfy(sentMail -> assertThat(sentMail.getState()).isEqualTo("errorProcessor1"));
+    }
+
+    @Test
+    void dispatchShouldThrowWhenOnMailetExceptionIsPropagate() throws Exception {
+        MailDispatcher testee = MailDispatcher.builder()
+            .mailetContext(fakeMailContext)
+            .mailStore(mailStore)
+            .onMailetException("propagate")
+            .build();
+
+        doReturn(Mono.error(new MessagingException()))
+            .when(mailStore)
+            .storeMail(any(MailAddress.class), any(Mail.class));
+
+        FakeMail mail = FakeMail.builder()
+            .name("name")
+            .sender(MailAddressFixture.OTHER_AT_JAMES)
+            .mimeMessage(MimeMessageBuilder.mimeMessageBuilder()
+                .setMultipartWithBodyParts(
+                    MimeMessageBuilder.bodyPartBuilder()
+                        .data("toto")))
+            .recipients(MailAddressFixture.ANY_AT_JAMES)
+            .state("state")
+            .build();
+
+        assertThatThrownBy(()-> testee.dispatch(mail))
+            .isInstanceOf(Exception.class);
+    }
+
     public static class AccumulatorHeaderMailStore implements MailStore {
         private final ArrayListMultimap<MailAddress, String[]> headerValues;
         private final String headerName;

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