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 <[email protected]> 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: [email protected] For additional commands, e-mail: [email protected]
