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 2021/01/25 02:58:25 UTC
[james-project] 02/03: JAMES-3432 DSN generation integration tests
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 ee50340dc0677475cdffed6dc4ccf7e2501f6d31
Author: RĂ©mi Kowalski <rk...@linagora.com>
AuthorDate: Mon Jan 18 15:05:16 2021 +0100
JAMES-3432 DSN generation integration tests
- DSN failures are enabled by default
https://tools.ietf.org/html/rfc3461#section-4.1
```
For compatibility with SMTP clients that do not use the NOTIFY
facility, the absence of a NOTIFY parameter in a RCPT command may be
interpreted as either NOTIFY=FAILURE or NOTIFY=FAILURE,DELAY.
```
- Disable tests failing due to known limitations
- We cannot generate relay success notifications as RemoteDelivery lacks
a success callback
- Use RemoteDelivery error callback (bounces processor)
---
.../james/smtp/dsn/DSNLocalIntegrationTest.java | 336 ++++++++++++++++++++
.../james/smtp/dsn/DSNRemoteIntegrationTest.java | 343 +++++++++++++++++++++
2 files changed, 679 insertions(+)
diff --git a/server/mailet/integration-testing/src/test/java/org/apache/james/smtp/dsn/DSNLocalIntegrationTest.java b/server/mailet/integration-testing/src/test/java/org/apache/james/smtp/dsn/DSNLocalIntegrationTest.java
new file mode 100644
index 0000000..7c6ac8a
--- /dev/null
+++ b/server/mailet/integration-testing/src/test/java/org/apache/james/smtp/dsn/DSNLocalIntegrationTest.java
@@ -0,0 +1,336 @@
+/****************************************************************
+ * 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.smtp.dsn;
+
+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 java.io.File;
+import java.io.IOException;
+import java.util.concurrent.TimeUnit;
+
+import org.apache.commons.net.smtp.AuthenticatingSMTPClient;
+import org.apache.james.dnsservice.api.DNSService;
+import org.apache.james.dnsservice.api.InMemoryDNSService;
+import org.apache.james.mailets.TemporaryJamesServer;
+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.mailets.configuration.SmtpConfiguration;
+import org.apache.james.modules.protocols.ImapGuiceProbe;
+import org.apache.james.modules.protocols.SmtpGuiceProbe;
+import org.apache.james.smtpserver.dsn.DSNEhloHook;
+import org.apache.james.smtpserver.dsn.DSNMailParameterHook;
+import org.apache.james.smtpserver.dsn.DSNMessageHook;
+import org.apache.james.smtpserver.dsn.DSNRcptParameterHook;
+
+import org.apache.james.transport.mailets.DSNBounce;
+import org.apache.james.transport.mailets.LocalDelivery;
+import org.apache.james.transport.mailets.RecipientRewriteTable;
+import org.apache.james.transport.mailets.ToProcessor;
+import org.apache.james.transport.matchers.All;
+import org.apache.james.transport.matchers.DSNFailureRequested;
+import org.apache.james.transport.matchers.DSNSuccessRequested;
+import org.apache.james.transport.matchers.RecipientIs;
+import org.apache.james.utils.DataProbeImpl;
+import org.apache.james.utils.SMTPMessageSender;
+import org.apache.james.utils.TestIMAPClient;
+import org.assertj.core.api.Assertions;
+import org.awaitility.Awaitility;
+import org.awaitility.Duration;
+import org.awaitility.core.ConditionFactory;
+import org.junit.jupiter.api.AfterEach;
+import org.junit.jupiter.api.BeforeEach;
+import org.junit.jupiter.api.Test;
+import org.junit.jupiter.api.extension.RegisterExtension;
+import org.junit.jupiter.api.io.TempDir;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+class DSNLocalIntegrationTest {
+ private static final Logger LOGGER = LoggerFactory.getLogger(DSNLocalIntegrationTest.class);
+
+ private static final String FROM = "from@" + DEFAULT_DOMAIN;
+ private static final String RECIPIENT = "touser@" + DEFAULT_DOMAIN;
+ private static final String FAILING_RECIPIENT = "failing@" + DEFAULT_DOMAIN;
+ public static final ConditionFactory AWAIT_NO_MESSAGE = Awaitility.with().pollDelay(new Duration(2, TimeUnit.SECONDS)).timeout(Duration.FIVE_SECONDS);
+
+ private InMemoryDNSService inMemoryDNSService;
+
+ @RegisterExtension
+ public TestIMAPClient testIMAPClient = new TestIMAPClient();
+ @RegisterExtension
+ public SMTPMessageSender messageSender = new SMTPMessageSender(DEFAULT_DOMAIN);
+
+ private TemporaryJamesServer jamesServer;
+
+ @BeforeEach
+ void setUp(@TempDir File temporaryFolder) throws Exception {
+ inMemoryDNSService = new InMemoryDNSService()
+ .registerMxRecord(DEFAULT_DOMAIN, LOCALHOST_IP);
+
+ 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(localDelivery())
+ .putProcessor(ProcessorConfiguration.bounces()
+ .enableJmx(false)
+ .addMailet(MailetConfiguration.builder()
+ .matcher(DSNFailureRequested.class)
+ .mailet(DSNBounce.class)
+ .addProperty("defaultStatus", "5.0.0")
+ .addProperty("action", "failed")
+ .addProperty("prefix", "[FAILURE]")
+ .addProperty("messageString", "Your message failed to be delivered")
+ )))
+ .withSmtpConfiguration(SmtpConfiguration.builder()
+ .addHook(DSNEhloHook.class.getName())
+ .addHook(DSNMailParameterHook.class.getName())
+ .addHook(DSNRcptParameterHook.class.getName())
+ .addHook(DSNMessageHook.class.getName()))
+ .build(temporaryFolder);
+ jamesServer.start();
+
+ jamesServer.getProbe(DataProbeImpl.class)
+ .fluent()
+ .addDomain(DEFAULT_DOMAIN)
+ .addUser(FROM, PASSWORD)
+ .addUser(FAILING_RECIPIENT, PASSWORD)
+ .addUser(RECIPIENT, PASSWORD);
+
+ }
+
+ private ProcessorConfiguration.Builder localDelivery() {
+ return ProcessorConfiguration.transport()
+ .addMailet(MailetConfiguration.BCC_STRIPPER)
+ .addMailet(MailetConfiguration.builder()
+ .matcher(All.class)
+ .mailet(RecipientRewriteTable.class))
+ .addMailet(MailetConfiguration.builder()
+ .matcher(RecipientIs.class).matcherCondition(FAILING_RECIPIENT)
+ .mailet(ToProcessor.class)
+ .addProperty("processor", ProcessorConfiguration.STATE_BOUNCES))
+ .addMailet(MailetConfiguration.builder()
+ .matcher(All.class)
+ .mailet(LocalDelivery.class)
+ .addProperty("consume", "false"))
+ .addMailet(MailetConfiguration.builder()
+ .matcher(DSNSuccessRequested.class)
+ .mailet(DSNBounce.class)
+ .addProperty("defaultStatus", "2.0.0")
+ .addProperty("action", "delivered")
+ .addProperty("prefix", "[SUCCESS]")
+ .addProperty("messageString", "Your message was successfully delivered")
+ );
+ }
+
+ @Test
+ void givenAMailWithNoNotifyWhenItSucceedsThenNoDsnIsSentBack() throws IOException {
+ AuthenticatingSMTPClient smtpClient = new AuthenticatingSMTPClient("TLS", "UTF-8");
+
+ try {
+ smtpClient.connect("localhost", jamesServer.getProbe(SmtpGuiceProbe.class).getSmtpPort().getValue());
+ smtpClient.ehlo(DEFAULT_DOMAIN);
+ smtpClient.mail("<" + FROM + ">");
+ smtpClient.rcpt("<" + RECIPIENT + ">");
+ smtpClient.sendShortMessageData("A short message...");
+ } finally {
+ smtpClient.disconnect();
+ }
+
+ testIMAPClient.connect(LOCALHOST_IP, jamesServer.getProbe(ImapGuiceProbe.class).getImapPort())
+ .login(FROM, PASSWORD)
+ .select(TestIMAPClient.INBOX)
+ .awaitNoMessage(AWAIT_NO_MESSAGE);
+ }
+
+ @Test
+ void givenAMailWithNotifyNeverWhenItSucceedThenNoDsnIsSentBack() throws IOException {
+ AuthenticatingSMTPClient smtpClient = new AuthenticatingSMTPClient("TLS", "UTF-8");
+
+ try {
+ smtpClient.connect("localhost", jamesServer.getProbe(SmtpGuiceProbe.class).getSmtpPort().getValue());
+ smtpClient.ehlo(DEFAULT_DOMAIN);
+ smtpClient.mail("<" + FROM + ">");
+ smtpClient.rcpt("<" + RECIPIENT + "> NOTIFY=NEVER");
+ smtpClient.sendShortMessageData("A short message...");
+ } finally {
+ smtpClient.disconnect();
+ }
+
+ testIMAPClient.connect(LOCALHOST_IP, jamesServer.getProbe(ImapGuiceProbe.class).getImapPort())
+ .login(FROM, PASSWORD)
+ .select(TestIMAPClient.INBOX)
+ .awaitNoMessage(AWAIT_NO_MESSAGE);
+ }
+
+ @Test
+ void givenAMailWithNotifySuccessWhenItSucceedThenADsnSuccessIsSentBack() throws IOException {
+ AuthenticatingSMTPClient smtpClient = new AuthenticatingSMTPClient("TLS", "UTF-8");
+
+ try {
+ smtpClient.connect("localhost", jamesServer.getProbe(SmtpGuiceProbe.class).getSmtpPort().getValue());
+ smtpClient.ehlo(DEFAULT_DOMAIN);
+ smtpClient.mail("<" + FROM + ">");
+ smtpClient.rcpt("<" + RECIPIENT + "> NOTIFY=SUCCESS");
+ smtpClient.sendShortMessageData("A short message...");
+ } finally {
+ smtpClient.disconnect();
+ }
+
+ String dsnMessage = testIMAPClient.connect(LOCALHOST_IP, jamesServer.getProbe(ImapGuiceProbe.class).getImapPort())
+ .login(FROM, PASSWORD)
+ .select(TestIMAPClient.INBOX)
+ .awaitMessageCount(awaitAtMostOneMinute, 1)
+ .readFirstMessage();
+
+ Assertions.assertThat(dsnMessage).contains("Subject: [SUCCESS]");
+ Assertions.assertThat(dsnMessage).contains("Status: 2.0.0");
+ Assertions.assertThat(dsnMessage).contains("Your message was successfully delivered\n" +
+ "Delivered recipient(s):\n" +
+ "touser@james.org");
+ }
+
+ @Test
+ void givenAMailWithNotifyFailureWhenItSucceedThenNoDsnIsSentBack() throws IOException {
+ AuthenticatingSMTPClient smtpClient = new AuthenticatingSMTPClient("TLS", "UTF-8");
+
+ try {
+ smtpClient.connect("localhost", jamesServer.getProbe(SmtpGuiceProbe.class).getSmtpPort().getValue());
+ smtpClient.ehlo(DEFAULT_DOMAIN);
+ smtpClient.mail("<" + FROM + ">");
+ smtpClient.rcpt("<" + RECIPIENT + "> NOTIFY=FAILURE");
+ smtpClient.sendShortMessageData("A short message...");
+ } finally {
+ smtpClient.disconnect();
+ }
+
+ testIMAPClient.connect(LOCALHOST_IP, jamesServer.getProbe(ImapGuiceProbe.class).getImapPort())
+ .login(FROM, PASSWORD)
+ .select(TestIMAPClient.INBOX)
+ .awaitNoMessage(AWAIT_NO_MESSAGE);
+ }
+
+ @Test
+ void givenAMailWithNoNotifyWhenItFailsThenADSNBounceIsSentBack() throws IOException {
+ AuthenticatingSMTPClient smtpClient = new AuthenticatingSMTPClient("TLS", "UTF-8");
+
+ try {
+ smtpClient.connect("localhost", jamesServer.getProbe(SmtpGuiceProbe.class).getSmtpPort().getValue());
+ smtpClient.ehlo(DEFAULT_DOMAIN);
+ smtpClient.mail("<" + FROM + ">");
+ smtpClient.rcpt("<" + FAILING_RECIPIENT + ">");
+ smtpClient.sendShortMessageData("A short message...");
+ } finally {
+ smtpClient.disconnect();
+ }
+
+ String dsnMessage = testIMAPClient.connect(LOCALHOST_IP, jamesServer.getProbe(ImapGuiceProbe.class).getImapPort())
+ .login(FROM, PASSWORD)
+ .select(TestIMAPClient.INBOX)
+ .awaitMessageCount(awaitAtMostOneMinute, 1)
+ .readFirstMessage();
+
+ Assertions.assertThat(dsnMessage).contains("Subject: [FAILURE]");
+ Assertions.assertThat(dsnMessage).contains("Status: 5.0.0");
+ Assertions.assertThat(dsnMessage).contains("Your message failed to be delivered\n" +
+ "Failed recipient(s):\n" +
+ "failing@james.org");
+ }
+
+ @Test
+ void givenAMailWithNotifyNeverWhenItFailsThenNoEmailIsSentBack() throws IOException, InterruptedException {
+ AuthenticatingSMTPClient smtpClient = new AuthenticatingSMTPClient("TLS", "UTF-8");
+
+ try {
+ smtpClient.connect("localhost", jamesServer.getProbe(SmtpGuiceProbe.class).getSmtpPort().getValue());
+ smtpClient.ehlo(DEFAULT_DOMAIN);
+ smtpClient.mail("<" + FROM + ">");
+ smtpClient.rcpt("<" + FAILING_RECIPIENT + "> NOTIFY=NEVER");
+ smtpClient.sendShortMessageData("A short message...");
+ } finally {
+ smtpClient.disconnect();
+ }
+
+ testIMAPClient.connect(LOCALHOST_IP, jamesServer.getProbe(ImapGuiceProbe.class).getImapPort())
+ .login(FROM, PASSWORD)
+ .select(TestIMAPClient.INBOX)
+ .awaitNoMessage(AWAIT_NO_MESSAGE);
+ }
+
+ @Test
+ void givenAMailWithNotifySuccessWhenItFailsThenNoBounceIsSentBack() throws IOException {
+ AuthenticatingSMTPClient smtpClient = new AuthenticatingSMTPClient("TLS", "UTF-8");
+
+ try {
+ smtpClient.connect("localhost", jamesServer.getProbe(SmtpGuiceProbe.class).getSmtpPort().getValue());
+ smtpClient.ehlo(DEFAULT_DOMAIN);
+ smtpClient.mail("<" + FROM + ">");
+ smtpClient.rcpt("<" + FAILING_RECIPIENT + "> NOTIFY=SUCCESS");
+ smtpClient.sendShortMessageData("A short message...");
+ } finally {
+ smtpClient.disconnect();
+ }
+
+ testIMAPClient.connect(LOCALHOST_IP, jamesServer.getProbe(ImapGuiceProbe.class).getImapPort())
+ .login(FROM, PASSWORD)
+ .select(TestIMAPClient.INBOX)
+ .awaitNoMessage(AWAIT_NO_MESSAGE);
+ }
+
+ @Test
+ void givenAMailWithNotifyFailureWhenItFailsThenADsnBounceIsSentBack() throws IOException {
+ AuthenticatingSMTPClient smtpClient = new AuthenticatingSMTPClient("TLS", "UTF-8");
+
+ try {
+ smtpClient.connect("localhost", jamesServer.getProbe(SmtpGuiceProbe.class).getSmtpPort().getValue());
+ smtpClient.ehlo(DEFAULT_DOMAIN);
+ smtpClient.mail("<" + FROM + ">");
+ smtpClient.rcpt("<" + FAILING_RECIPIENT + "> NOTIFY=FAILURE");
+ smtpClient.sendShortMessageData("A short message...");
+ } finally {
+ smtpClient.disconnect();
+ }
+
+ String dsnMessage = testIMAPClient.connect(LOCALHOST_IP, jamesServer.getProbe(ImapGuiceProbe.class).getImapPort())
+ .login(FROM, PASSWORD)
+ .select(TestIMAPClient.INBOX)
+ .awaitMessageCount(awaitAtMostOneMinute, 1)
+ .readFirstMessage();
+
+ Assertions.assertThat(dsnMessage).contains("Subject: [FAILURE]");
+ Assertions.assertThat(dsnMessage).contains("Status: 5.0.0");
+ Assertions.assertThat(dsnMessage).contains("Your message failed to be delivered\n" +
+ "Failed recipient(s):\n" +
+ "failing@james.org");
+ }
+
+ @AfterEach
+ void tearDown() {
+ jamesServer.shutdown();
+ }
+}
diff --git a/server/mailet/integration-testing/src/test/java/org/apache/james/smtp/dsn/DSNRemoteIntegrationTest.java b/server/mailet/integration-testing/src/test/java/org/apache/james/smtp/dsn/DSNRemoteIntegrationTest.java
new file mode 100644
index 0000000..a99202c
--- /dev/null
+++ b/server/mailet/integration-testing/src/test/java/org/apache/james/smtp/dsn/DSNRemoteIntegrationTest.java
@@ -0,0 +1,343 @@
+/****************************************************************
+ * 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.smtp.dsn;
+
+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.ResponseStep.doesNotAcceptAnyMail;
+import static org.apache.james.mock.smtp.server.model.Condition.MATCH_ALL;
+import static org.apache.james.mock.smtp.server.model.SMTPCommand.RCPT_TO;
+import static org.apache.james.util.docker.Images.MOCK_SMTP_SERVER;
+import static org.assertj.core.api.Assertions.assertThat;
+
+import java.io.File;
+import java.util.concurrent.TimeUnit;
+
+import org.apache.commons.net.smtp.AuthenticatingSMTPClient;
+import org.apache.james.dnsservice.api.DNSService;
+import org.apache.james.dnsservice.api.InMemoryDNSService;
+import org.apache.james.mailets.TemporaryJamesServer;
+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.mailets.configuration.SmtpConfiguration;
+import org.apache.james.mock.smtp.server.ConfigurationClient;
+import org.apache.james.mock.smtp.server.model.SMTPExtension;
+import org.apache.james.mock.smtp.server.model.SMTPExtensions;
+import org.apache.james.modules.protocols.ImapGuiceProbe;
+import org.apache.james.modules.protocols.SmtpGuiceProbe;
+import org.apache.james.smtpserver.dsn.DSNEhloHook;
+import org.apache.james.smtpserver.dsn.DSNMailParameterHook;
+import org.apache.james.smtpserver.dsn.DSNMessageHook;
+import org.apache.james.smtpserver.dsn.DSNRcptParameterHook;
+import org.apache.james.transport.mailets.DSNBounce;
+import org.apache.james.transport.mailets.LocalDelivery;
+import org.apache.james.transport.mailets.RecipientRewriteTable;
+import org.apache.james.transport.mailets.RemoteDelivery;
+import org.apache.james.transport.matchers.All;
+import org.apache.james.transport.matchers.DSNFailureRequested;
+import org.apache.james.transport.matchers.RecipientIsLocal;
+import org.apache.james.util.Host;
+import org.apache.james.util.docker.DockerContainer;
+import org.apache.james.utils.DataProbeImpl;
+import org.apache.james.utils.SMTPMessageSender;
+import org.apache.james.utils.TestIMAPClient;
+import org.assertj.core.api.Assertions;
+import org.awaitility.Awaitility;
+import org.awaitility.Duration;
+import org.awaitility.core.ConditionFactory;
+import org.junit.jupiter.api.AfterEach;
+import org.junit.jupiter.api.BeforeEach;
+import org.junit.jupiter.api.Disabled;
+import org.junit.jupiter.api.Test;
+import org.junit.jupiter.api.extension.RegisterExtension;
+import org.junit.jupiter.api.io.TempDir;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+class DSNRemoteIntegrationTest {
+ private static final Logger LOGGER = LoggerFactory.getLogger(DSNRemoteIntegrationTest.class);
+
+ 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 ConditionFactory AWAIT_NO_MESSAGE = Awaitility.with().pollDelay(new Duration(2, TimeUnit.SECONDS)).timeout(Duration.FIVE_SECONDS);
+
+ private InMemoryDNSService inMemoryDNSService;
+ private ConfigurationClient mockSMTPConfiguration;
+
+ @RegisterExtension
+ public static DockerContainer mockSmtp = DockerContainer.fromName(MOCK_SMTP_SERVER)
+ .withLogConsumer(outputFrame -> LOGGER.debug("MockSMTP 1: " + outputFrame.getUtf8String()));
+
+ @RegisterExtension
+ public TestIMAPClient testIMAPClient = new TestIMAPClient();
+ @RegisterExtension
+ public SMTPMessageSender messageSender = new SMTPMessageSender(DEFAULT_DOMAIN);
+
+ private TemporaryJamesServer jamesServer;
+
+ @BeforeEach
+ void setUp(@TempDir File temporaryFolder) throws Exception {
+ inMemoryDNSService = new InMemoryDNSService()
+ .registerMxRecord(DEFAULT_DOMAIN, LOCALHOST_IP)
+ .registerMxRecord(ANOTHER_DOMAIN, mockSmtp.getContainerIp());
+
+ 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(directResolutionTransport())
+ .putProcessor(ProcessorConfiguration.builder().state("relay-bounces")
+ .enableJmx(false)
+ .addMailet(MailetConfiguration.builder()
+ .matcher(DSNFailureRequested.class)
+ .mailet(DSNBounce.class)
+ .addProperty("defaultStatus", "5.0.0")
+ .addProperty("action", "failed")
+ .addProperty("prefix", "[FAILURE]")
+ .addProperty("messageString", "Your message failed to be delivered")))
+ .putProcessor(CommonProcessors.bounces()))
+ .withSmtpConfiguration(SmtpConfiguration.builder()
+ .addHook(DSNEhloHook.class.getName())
+ .addHook(DSNMailParameterHook.class.getName())
+ .addHook(DSNRcptParameterHook.class.getName())
+ .addHook(DSNMessageHook.class.getName()))
+ .build(temporaryFolder);
+ jamesServer.start();
+
+ jamesServer.getProbe(DataProbeImpl.class)
+ .fluent()
+ .addDomain(DEFAULT_DOMAIN)
+ .addUser(FROM, PASSWORD);
+ mockSMTPConfiguration = configurationClient(mockSmtp);
+ mockSMTPConfiguration.setSMTPExtensions(SMTPExtensions.of(SMTPExtension.of("dsn")));
+
+ assertThat(mockSMTPConfiguration.version()).isEqualTo("0.2");
+ }
+
+ private ProcessorConfiguration.Builder directResolutionTransport() {
+ return ProcessorConfiguration.transport()
+ .addMailet(MailetConfiguration.BCC_STRIPPER)
+ .addMailet(MailetConfiguration.builder()
+ .matcher(All.class)
+ .mailet(RecipientRewriteTable.class))
+ .addMailet(MailetConfiguration.builder()
+ .mailet(LocalDelivery.class)
+ .matcher(RecipientIsLocal.class))
+ .addMailet(MailetConfiguration.builder()
+ .mailet(RemoteDelivery.class)
+ .matcher(All.class)
+ .addProperty("sendpartial", "true")
+ .addProperty("bounceProcessor", "relay-bounces"));
+ }
+
+ @Test
+ void givenAMailWithNoNotifyWhenItSucceedsThenNoEmailIsSentBack() throws Exception {
+ AuthenticatingSMTPClient smtpClient = new AuthenticatingSMTPClient("TLS", "UTF-8");
+
+ try {
+ smtpClient.connect("localhost", jamesServer.getProbe(SmtpGuiceProbe.class).getSmtpPort().getValue());
+ smtpClient.ehlo(DEFAULT_DOMAIN);
+ smtpClient.mail("<" + FROM + ">");
+ smtpClient.rcpt("<" + RECIPIENT + ">");
+ smtpClient.sendShortMessageData("A short message...");
+ } finally {
+ smtpClient.disconnect();
+ }
+
+ testIMAPClient.connect(LOCALHOST_IP, jamesServer.getProbe(ImapGuiceProbe.class).getImapPort())
+ .login(FROM, PASSWORD)
+ .select(TestIMAPClient.INBOX)
+ .awaitNoMessage(AWAIT_NO_MESSAGE);
+ }
+
+ @Test
+ void givenAMailWithNotifyNeverWhenItSucceedThenNoDsnIsSentBack() throws Exception {
+ AuthenticatingSMTPClient smtpClient = new AuthenticatingSMTPClient("TLS", "UTF-8");
+
+ try {
+ smtpClient.connect("localhost", jamesServer.getProbe(SmtpGuiceProbe.class).getSmtpPort().getValue());
+ smtpClient.ehlo(DEFAULT_DOMAIN);
+ smtpClient.mail("<" + FROM + ">");
+ smtpClient.rcpt("<" + RECIPIENT + "> NOTIFY=NEVER");
+ smtpClient.sendShortMessageData("A short message...");
+ } finally {
+ smtpClient.disconnect();
+ }
+
+ testIMAPClient.connect(LOCALHOST_IP, jamesServer.getProbe(ImapGuiceProbe.class).getImapPort())
+ .login(FROM, PASSWORD)
+ .select(TestIMAPClient.INBOX)
+ .awaitNoMessage(AWAIT_NO_MESSAGE);
+ }
+
+ @Disabled("JAMES-3431 DSN relayed notifications cannot be generated as RemoteDelivery lacks a 'success' callback")
+ @Test
+ void givenAMailWithNotifySuccessWhenItSucceedThenADsnSuccessIsSentBack() throws Exception {
+ AuthenticatingSMTPClient smtpClient = new AuthenticatingSMTPClient("TLS", "UTF-8");
+
+ try {
+ smtpClient.connect("localhost", jamesServer.getProbe(SmtpGuiceProbe.class).getSmtpPort().getValue());
+ smtpClient.ehlo(DEFAULT_DOMAIN);
+ smtpClient.mail("<" + FROM + ">");
+ smtpClient.rcpt("<" + RECIPIENT + "> NOTIFY=SUCCESS");
+ smtpClient.sendShortMessageData("A short message...");
+ } finally {
+ smtpClient.disconnect();
+ }
+
+ String dsnMessage = testIMAPClient.connect(LOCALHOST_IP, jamesServer.getProbe(ImapGuiceProbe.class).getImapPort())
+ .login(FROM, PASSWORD)
+ .select(TestIMAPClient.INBOX)
+ .awaitMessageCount(awaitAtMostOneMinute, 1)
+ .readFirstMessage();
+
+ Assertions.assertThat(dsnMessage).contains("Subject: [SUCCESS]");
+ Assertions.assertThat(dsnMessage).contains("Status: 2.0.0");
+ Assertions.assertThat(dsnMessage).contains("Your message was successfully delivered\n" +
+ "Delivered recipient(s):\n" +
+ "touser@other.com");
+ }
+
+ @Test
+ void givenAMailWithNotifyFailureWhenItSucceedThenNoEmailIsSentBack() throws Exception {
+ AuthenticatingSMTPClient smtpClient = new AuthenticatingSMTPClient("TLS", "UTF-8");
+
+ try {
+ smtpClient.connect("localhost", jamesServer.getProbe(SmtpGuiceProbe.class).getSmtpPort().getValue());
+ smtpClient.ehlo(DEFAULT_DOMAIN);
+ smtpClient.mail("<" + FROM + ">");
+ smtpClient.rcpt("<" + RECIPIENT + "> NOTIFY=FAILURE");
+ smtpClient.sendShortMessageData("A short message...");
+ } finally {
+ smtpClient.disconnect();
+ }
+
+ testIMAPClient.connect(LOCALHOST_IP, jamesServer.getProbe(ImapGuiceProbe.class).getImapPort())
+ .login(FROM, PASSWORD)
+ .select(TestIMAPClient.INBOX)
+ .awaitNoMessage(AWAIT_NO_MESSAGE);
+ }
+
+ @Test
+ void givenAMailWithNoNotifyWhenItFailsThenADSNBounceIsSentBack() throws Exception {
+ AuthenticatingSMTPClient smtpClient = new AuthenticatingSMTPClient("TLS", "UTF-8");
+ mockSMTPConfiguration.addNewBehavior()
+ .expect(RCPT_TO)
+ .matching(MATCH_ALL)
+ .thenRespond(doesNotAcceptAnyMail("mock response"))
+ .anyTimes()
+ .post();
+
+ try {
+ smtpClient.connect("localhost", jamesServer.getProbe(SmtpGuiceProbe.class).getSmtpPort().getValue());
+ smtpClient.ehlo(DEFAULT_DOMAIN);
+ smtpClient.mail("<" + FROM + ">");
+ smtpClient.rcpt("<" + RECIPIENT + ">");
+ smtpClient.sendShortMessageData("A short message...");
+ } finally {
+ smtpClient.disconnect();
+ }
+
+ String dsnMessage = testIMAPClient.connect(LOCALHOST_IP, jamesServer.getProbe(ImapGuiceProbe.class).getImapPort())
+ .login(FROM, PASSWORD)
+ .select(TestIMAPClient.INBOX)
+ .awaitMessageCount(awaitAtMostOneMinute, 1)
+ .readFirstMessage();
+
+ Assertions.assertThat(dsnMessage).contains("Subject: [FAILURE]");
+ Assertions.assertThat(dsnMessage).contains("Status: 521 mock response");
+ Assertions.assertThat(dsnMessage).contains("Your message failed to be delivered\n" +
+ "Failed recipient(s):\n" +
+ "touser@other.com");
+ }
+
+ @Test
+ void givenAMailWithNotifyNeverWhenItFailsThenNoEmailIsSentBack() throws Exception {
+ AuthenticatingSMTPClient smtpClient = new AuthenticatingSMTPClient("TLS", "UTF-8");
+
+ try {
+ smtpClient.connect("localhost", jamesServer.getProbe(SmtpGuiceProbe.class).getSmtpPort().getValue());
+ smtpClient.ehlo(DEFAULT_DOMAIN);
+ smtpClient.mail("<" + FROM + ">");
+ smtpClient.rcpt("<" + RECIPIENT + "> NOTIFY=NEVER");
+ smtpClient.sendShortMessageData("A short message...");
+ } finally {
+ smtpClient.disconnect();
+ }
+
+ testIMAPClient.connect(LOCALHOST_IP, jamesServer.getProbe(ImapGuiceProbe.class).getImapPort())
+ .login(FROM, PASSWORD)
+ .select(TestIMAPClient.INBOX)
+ .awaitNoMessage(AWAIT_NO_MESSAGE);
+ }
+
+ @Test
+ void givenAMailWithNotifyFailureWhenItFailsThenADsnBounceIsSentBack() throws Exception {
+ AuthenticatingSMTPClient smtpClient = new AuthenticatingSMTPClient("TLS", "UTF-8");
+ mockSMTPConfiguration.addNewBehavior()
+ .expect(RCPT_TO)
+ .matching(MATCH_ALL)
+ .thenRespond(doesNotAcceptAnyMail("mock response"))
+ .anyTimes()
+ .post();
+
+ try {
+ smtpClient.connect("localhost", jamesServer.getProbe(SmtpGuiceProbe.class).getSmtpPort().getValue());
+ smtpClient.ehlo(DEFAULT_DOMAIN);
+ smtpClient.mail("<" + FROM + ">");
+ smtpClient.rcpt("<" + RECIPIENT + "> NOTIFY=FAILURE");
+ smtpClient.sendShortMessageData("A short message...");
+ } finally {
+ smtpClient.disconnect();
+ }
+
+ String dsnMessage = testIMAPClient.connect(LOCALHOST_IP, jamesServer.getProbe(ImapGuiceProbe.class).getImapPort())
+ .login(FROM, PASSWORD)
+ .select(TestIMAPClient.INBOX)
+ .awaitMessageCount(awaitAtMostOneMinute, 1)
+ .readFirstMessage();
+
+ Assertions.assertThat(dsnMessage).contains("Subject: [FAILURE]");
+ Assertions.assertThat(dsnMessage).contains("Status: 521 mock response");
+ Assertions.assertThat(dsnMessage).contains("Your message failed to be delivered\n" +
+ "Failed recipient(s):\n" +
+ "touser@other.com");
+ }
+
+ @AfterEach
+ void tearDown() {
+ jamesServer.shutdown();
+ mockSMTPConfiguration.cleanServer();
+ }
+
+ private ConfigurationClient configurationClient(DockerContainer mockSmtp) {
+ return ConfigurationClient.from(
+ Host.from(mockSmtp.getHostIp(),
+ mockSmtp.getMappedPort(8000)));
+ }
+}
---------------------------------------------------------------------
To unsubscribe, e-mail: notifications-unsubscribe@james.apache.org
For additional commands, e-mail: notifications-help@james.apache.org