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