You are viewing a plain text version of this content. The canonical link for it is here.
Posted to server-dev@james.apache.org by bt...@apache.org on 2020/07/09 01:51:31 UTC

[james-project] 02/06: JAMES-3295 RemoteDelivery should attach error code to bounced mails

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 3a9c255dc441b6204060decfb170aeff90a01ba3
Author: LanKhuat <kh...@gmail.com>
AuthorDate: Tue Jul 7 10:40:09 2020 +0700

    JAMES-3295 RemoteDelivery should attach error code to bounced mails
---
 .../transport/mailets/remote/delivery/Bouncer.java |  13 ++-
 .../mailets/remote/delivery/BouncerTest.java       | 113 +++++++++++++++++++++
 2 files changed, 125 insertions(+), 1 deletion(-)

diff --git a/server/mailet/mailets/src/main/java/org/apache/james/transport/mailets/remote/delivery/Bouncer.java b/server/mailet/mailets/src/main/java/org/apache/james/transport/mailets/remote/delivery/Bouncer.java
index f2d1d3f..b979cc6 100644
--- a/server/mailet/mailets/src/main/java/org/apache/james/transport/mailets/remote/delivery/Bouncer.java
+++ b/server/mailet/mailets/src/main/java/org/apache/james/transport/mailets/remote/delivery/Bouncer.java
@@ -24,6 +24,7 @@ import java.io.StringWriter;
 import java.net.ConnectException;
 import java.net.SocketException;
 import java.net.UnknownHostException;
+import java.util.Optional;
 
 import javax.mail.MessagingException;
 import javax.mail.SendFailedException;
@@ -41,6 +42,7 @@ public class Bouncer {
     private static final Logger LOGGER = LoggerFactory.getLogger(Bouncer.class);
 
     public static final AttributeName DELIVERY_ERROR = AttributeName.of("delivery-error");
+    public static final AttributeName DELIVERY_ERROR_CODE = AttributeName.of("delivery-error-code");
     private final RemoteDeliveryConfiguration configuration;
     private final MailetContext mailetContext;
 
@@ -54,6 +56,7 @@ public class Bouncer {
             LOGGER.debug("Null Sender: no bounce will be generated for {}", mail.getName());
         } else {
             if (configuration.getBounceProcessor() != null) {
+                computeErrorCode(ex).ifPresent(mail::setAttribute);
                 mail.setAttribute(new Attribute(DELIVERY_ERROR, AttributeValue.of(getErrorMsg(ex))));
                 try {
                     mailetContext.sendMail(mail, configuration.getBounceProcessor());
@@ -66,6 +69,14 @@ public class Bouncer {
         }
     }
 
+    private Optional<Attribute> computeErrorCode(Exception ex) {
+        return Optional.ofNullable(ex)
+            .filter(e -> e instanceof MessagingException)
+            .map(MessagingException.class::cast)
+            .map(EnhancedMessagingException::new)
+            .flatMap(EnhancedMessagingException::getReturnCode)
+            .map(code -> new Attribute(DELIVERY_ERROR_CODE, AttributeValue.of(code)));
+    }
 
     private void bounceWithMailetContext(Mail mail, Exception ex) {
         LOGGER.debug("Sending failure message {}", mail.getName());
@@ -115,7 +126,7 @@ public class Bouncer {
     }
 
     private String sanitizeExceptionMessage(Exception e) {
-        if (e.getMessage() == null) {
+        if (e == null || e.getMessage() == null) {
             return "null";
         } else {
             return e.getMessage().trim();
diff --git a/server/mailet/mailets/src/test/java/org/apache/james/transport/mailets/remote/delivery/BouncerTest.java b/server/mailet/mailets/src/test/java/org/apache/james/transport/mailets/remote/delivery/BouncerTest.java
index 57e93dc..c759b9d 100644
--- a/server/mailet/mailets/src/test/java/org/apache/james/transport/mailets/remote/delivery/BouncerTest.java
+++ b/server/mailet/mailets/src/test/java/org/apache/james/transport/mailets/remote/delivery/BouncerTest.java
@@ -20,8 +20,10 @@
 package org.apache.james.transport.mailets.remote.delivery;
 
 import static org.apache.james.transport.mailets.remote.delivery.Bouncer.DELIVERY_ERROR;
+import static org.apache.james.transport.mailets.remote.delivery.Bouncer.DELIVERY_ERROR_CODE;
 import static org.assertj.core.api.Assertions.assertThat;
 import static org.mockito.Mockito.mock;
+import static org.mockito.Mockito.when;
 
 import java.net.ConnectException;
 import java.net.SocketException;
@@ -42,12 +44,15 @@ import org.apache.mailet.base.test.FakeMailetConfig;
 import org.junit.Before;
 import org.junit.Test;
 
+import com.sun.mail.smtp.SMTPSendFailedException;
+
 public class BouncerTest {
     private static final String HELLO_NAME = "hello_name";
     private static final FakeMailetConfig DEFAULT_REMOTE_DELIVERY_CONFIG = FakeMailetConfig.builder()
         .setProperty(RemoteDeliveryConfiguration.HELO_NAME, HELLO_NAME)
         .build();
     private static final String BOUNCE_PROCESSOR = "bounce_processor";
+    public static final int SMTP_ERROR_CODE_521 = 521;
 
     private FakeMailContext mailetContext;
 
@@ -417,4 +422,112 @@ public class BouncerTest {
         assertThat(mailetContext.getSentMails()).containsOnly(expected);
         assertThat(mailetContext.getBouncedMails()).isEmpty();
     }
+
+    @Test
+    public void bounceShouldAttachErrorCodeWhenSmtpError() throws Exception {
+        RemoteDeliveryConfiguration configuration = new RemoteDeliveryConfiguration(
+            FakeMailetConfig.builder()
+                .setProperty(RemoteDeliveryConfiguration.HELO_NAME, HELLO_NAME)
+                .setProperty(RemoteDeliveryConfiguration.BOUNCE_PROCESSOR, BOUNCE_PROCESSOR)
+                .build(),
+            mock(DomainList.class));
+        Bouncer testee = new Bouncer(configuration, mailetContext);
+
+        Mail mail = FakeMail.builder().name("name").state(Mail.DEFAULT)
+            .sender(MailAddressFixture.ANY_AT_JAMES)
+            .build();
+
+        SMTPSendFailedException ex = mock(SMTPSendFailedException.class);
+        when(ex.getReturnCode()).thenReturn(SMTP_ERROR_CODE_521);
+
+        testee.bounce(mail, ex);
+
+        FakeMailContext.SentMail expected = FakeMailContext.sentMailBuilder()
+            .sender(MailAddressFixture.ANY_AT_JAMES)
+            .attribute(new Attribute(DELIVERY_ERROR, AttributeValue.of("null")))
+            .attribute(new Attribute(DELIVERY_ERROR_CODE, AttributeValue.of(SMTP_ERROR_CODE_521)))
+            .state(BOUNCE_PROCESSOR)
+            .fromMailet()
+            .build();
+        assertThat(mailetContext.getSentMails()).containsOnly(expected);
+        assertThat(mailetContext.getBouncedMails()).isEmpty();
+    }
+
+    @Test
+    public void bounceShouldNotAttachErrorCodeWhenNotMessagingException() throws Exception {
+        RemoteDeliveryConfiguration configuration = new RemoteDeliveryConfiguration(
+            FakeMailetConfig.builder()
+                .setProperty(RemoteDeliveryConfiguration.HELO_NAME, HELLO_NAME)
+                .setProperty(RemoteDeliveryConfiguration.BOUNCE_PROCESSOR, BOUNCE_PROCESSOR)
+                .build(),
+            mock(DomainList.class));
+        Bouncer testee = new Bouncer(configuration, mailetContext);
+
+        Mail mail = FakeMail.builder().name("name").state(Mail.DEFAULT)
+            .sender(MailAddressFixture.ANY_AT_JAMES)
+            .build();
+
+        testee.bounce(mail, new Exception());
+
+        FakeMailContext.SentMail expected = FakeMailContext.sentMailBuilder()
+            .sender(MailAddressFixture.ANY_AT_JAMES)
+            .attribute(new Attribute(DELIVERY_ERROR, AttributeValue.of("null")))
+            .state(BOUNCE_PROCESSOR)
+            .fromMailet()
+            .build();
+        assertThat(mailetContext.getSentMails()).containsOnly(expected);
+        assertThat(mailetContext.getBouncedMails()).isEmpty();
+    }
+
+    @Test
+    public void bounceShouldNotAttachErrorCodeWhenNotSmtpError() throws Exception {
+        RemoteDeliveryConfiguration configuration = new RemoteDeliveryConfiguration(
+            FakeMailetConfig.builder()
+                .setProperty(RemoteDeliveryConfiguration.HELO_NAME, HELLO_NAME)
+                .setProperty(RemoteDeliveryConfiguration.BOUNCE_PROCESSOR, BOUNCE_PROCESSOR)
+                .build(),
+            mock(DomainList.class));
+        Bouncer testee = new Bouncer(configuration, mailetContext);
+
+        Mail mail = FakeMail.builder().name("name").state(Mail.DEFAULT)
+            .sender(MailAddressFixture.ANY_AT_JAMES)
+            .build();
+
+        testee.bounce(mail, new MessagingException("not smtp related"));
+
+        FakeMailContext.SentMail expected = FakeMailContext.sentMailBuilder()
+            .sender(MailAddressFixture.ANY_AT_JAMES)
+            .attribute(new Attribute(DELIVERY_ERROR, AttributeValue.of("not smtp related")))
+            .state(BOUNCE_PROCESSOR)
+            .fromMailet()
+            .build();
+        assertThat(mailetContext.getSentMails()).containsOnly(expected);
+        assertThat(mailetContext.getBouncedMails()).isEmpty();
+    }
+
+    @Test
+    public void bounceShouldAttachNullErrorMessageWhenNoException() throws Exception {
+        RemoteDeliveryConfiguration configuration = new RemoteDeliveryConfiguration(
+            FakeMailetConfig.builder()
+                .setProperty(RemoteDeliveryConfiguration.HELO_NAME, HELLO_NAME)
+                .setProperty(RemoteDeliveryConfiguration.BOUNCE_PROCESSOR, BOUNCE_PROCESSOR)
+                .build(),
+            mock(DomainList.class));
+        Bouncer testee = new Bouncer(configuration, mailetContext);
+
+        Mail mail = FakeMail.builder().name("name").state(Mail.DEFAULT)
+            .sender(MailAddressFixture.ANY_AT_JAMES)
+            .build();
+
+        testee.bounce(mail, null);
+
+        FakeMailContext.SentMail expected = FakeMailContext.sentMailBuilder()
+            .sender(MailAddressFixture.ANY_AT_JAMES)
+            .attribute(new Attribute(DELIVERY_ERROR, AttributeValue.of("null")))
+            .state(BOUNCE_PROCESSOR)
+            .fromMailet()
+            .build();
+        assertThat(mailetContext.getSentMails()).containsOnly(expected);
+        assertThat(mailetContext.getBouncedMails()).isEmpty();
+    }
 }


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