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 ro...@apache.org on 2018/01/10 10:14:34 UTC

[34/53] [abbrv] james-project git commit: JAMES-2277 respect naming conventions

http://git-wip-us.apache.org/repos/asf/james-project/blob/52c18ef6/server/mailet/mailets/src/test/java/org/apache/james/transport/mailets/remote/delivery/MailDelivrerTest.java
----------------------------------------------------------------------
diff --git a/server/mailet/mailets/src/test/java/org/apache/james/transport/mailets/remote/delivery/MailDelivrerTest.java b/server/mailet/mailets/src/test/java/org/apache/james/transport/mailets/remote/delivery/MailDelivrerTest.java
new file mode 100644
index 0000000..7ece906
--- /dev/null
+++ b/server/mailet/mailets/src/test/java/org/apache/james/transport/mailets/remote/delivery/MailDelivrerTest.java
@@ -0,0 +1,446 @@
+/****************************************************************
+ * 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.transport.mailets.remote.delivery;
+
+import static org.assertj.core.api.Assertions.assertThat;
+import static org.mockito.Matchers.any;
+import static org.mockito.Matchers.eq;
+import static org.mockito.Mockito.mock;
+import static org.mockito.Mockito.times;
+import static org.mockito.Mockito.verify;
+import static org.mockito.Mockito.verifyNoMoreInteractions;
+import static org.mockito.Mockito.when;
+
+import java.io.IOException;
+
+import javax.mail.Address;
+import javax.mail.MessagingException;
+import javax.mail.SendFailedException;
+import javax.mail.internet.InternetAddress;
+
+import org.apache.james.dnsservice.api.TemporaryResolutionException;
+import org.apache.james.domainlist.api.DomainList;
+import org.apache.mailet.HostAddress;
+import org.apache.mailet.Mail;
+import org.apache.mailet.base.MailAddressFixture;
+import org.apache.mailet.base.test.FakeMail;
+import org.apache.mailet.base.test.FakeMailetConfig;
+import org.junit.Before;
+import org.junit.Test;
+
+import com.google.common.collect.ImmutableList;
+import com.google.common.collect.UnmodifiableIterator;
+import com.sun.mail.smtp.SMTPSenderFailedException;
+
+@SuppressWarnings("deprecation")
+public class MailDelivrerTest {
+    public static final String MX1_HOSTNAME = "mx1." + MailAddressFixture.JAMES2_APACHE_ORG;
+    public static final String MX2_HOSTNAME = "mx2." + MailAddressFixture.JAMES2_APACHE_ORG;
+    public static final String SMTP_URI2 = "protocol://userid:password@host:119/file1";
+    public static final String SMTP_URI1 = "protocol://userid:password@host:119/file2";
+    public static final HostAddress HOST_ADDRESS_1 = new HostAddress(MX1_HOSTNAME, SMTP_URI1);
+    public static final HostAddress HOST_ADDRESS_2 = new HostAddress(MX2_HOSTNAME, SMTP_URI2);
+
+    private MailDelivrer testee;
+    private Bouncer bouncer;
+    private DnsHelper dnsHelper;
+    private MailDelivrerToHost mailDelivrerToHost;
+
+    @Before
+    public void setUp() {
+        bouncer = mock(Bouncer.class);
+        dnsHelper = mock(DnsHelper.class);
+        mailDelivrerToHost = mock(MailDelivrerToHost.class);
+        RemoteDeliveryConfiguration configuration = new RemoteDeliveryConfiguration(FakeMailetConfig.builder()
+            .setProperty(RemoteDeliveryConfiguration.DELIVERY_THREADS, "1")
+            .setProperty(RemoteDeliveryConfiguration.MAX_DNS_PROBLEM_RETRIES, "3")
+            .setProperty(RemoteDeliveryConfiguration.DEBUG, "true")
+            .build(),
+            mock(DomainList.class));
+        testee = new MailDelivrer(configuration, mailDelivrerToHost, dnsHelper, bouncer);
+    }
+
+    @Test
+    public void handleSenderFailedExceptionShouldReturnTemporaryFailureByDefault() throws Exception {
+        Mail mail = FakeMail.builder().recipients(MailAddressFixture.ANY_AT_JAMES, MailAddressFixture.OTHER_AT_JAMES).build();
+
+        SendFailedException sfe = new SendFailedException();
+        ExecutionResult executionResult = testee.handleSenderFailedException(mail, sfe);
+
+        assertThat(executionResult).isEqualTo(ExecutionResult.temporaryFailure(sfe));
+    }
+
+    @Test
+    public void handleSenderFailedExceptionShouldReturnTemporaryFailureWhenNotServerException() throws Exception {
+        Mail mail = FakeMail.builder().recipients(MailAddressFixture.ANY_AT_JAMES, MailAddressFixture.OTHER_AT_JAMES).build();
+
+        SendFailedException sfe = new SMTPSenderFailedException(new InternetAddress(MailAddressFixture.OTHER_AT_JAMES.asString()), "Comand", 400, "An temporary error");
+        ExecutionResult executionResult = testee.handleSenderFailedException(mail, sfe);
+
+        assertThat(executionResult).isEqualTo(ExecutionResult.temporaryFailure(sfe));
+    }
+
+    @Test
+    public void handleSenderFailedExceptionShouldReturnPermanentFailureWhenServerException() throws Exception {
+        Mail mail = FakeMail.builder().recipients(MailAddressFixture.ANY_AT_JAMES, MailAddressFixture.OTHER_AT_JAMES).build();
+
+        SendFailedException sfe = new SMTPSenderFailedException(new InternetAddress(MailAddressFixture.OTHER_AT_JAMES.asString()), "Comand", 505, "An temporary error");
+        ExecutionResult executionResult = testee.handleSenderFailedException(mail, sfe);
+
+        assertThat(executionResult).isEqualTo(ExecutionResult.permanentFailure(sfe));
+    }
+
+    @Test
+    public void handleSenderFailedExceptionShouldReturnPermanentFailureWhenInvalidAndNotValidUnsent() throws Exception {
+        Mail mail = FakeMail.builder().recipients(MailAddressFixture.ANY_AT_JAMES, MailAddressFixture.OTHER_AT_JAMES).build();
+
+        Address[] validSent = {};
+        Address[] validUnsent = {};
+        Address[] invalid = {new InternetAddress(MailAddressFixture.ANY_AT_JAMES.asString())};
+        SendFailedException sfe = new SendFailedException("Message",
+            new Exception(),
+            validSent,
+            validUnsent,
+            invalid);
+        ExecutionResult executionResult = testee.handleSenderFailedException(mail, sfe);
+
+        assertThat(executionResult).isEqualTo(ExecutionResult.permanentFailure(sfe));
+    }
+
+    @Test
+    public void handleSenderFailedExceptionShouldReturnTemporaryFailureWhenValidUnsent() throws Exception {
+        Mail mail = FakeMail.builder().recipients(MailAddressFixture.ANY_AT_JAMES, MailAddressFixture.OTHER_AT_JAMES).build();
+
+        Address[] validSent = {};
+        Address[] validUnsent = {new InternetAddress(MailAddressFixture.OTHER_AT_JAMES.asString())};
+        Address[] invalid = {};
+        SendFailedException sfe = new SendFailedException("Message",
+            new Exception(),
+            validSent,
+            validUnsent,
+            invalid);
+        ExecutionResult executionResult = testee.handleSenderFailedException(mail, sfe);
+
+        assertThat(executionResult).isEqualTo(ExecutionResult.temporaryFailure(sfe));
+    }
+
+    @Test
+    public void handleSenderFailedExceptionShouldReturnTemporaryFailureWhenInvalidAndValidUnsent() throws Exception {
+        Mail mail = FakeMail.builder().recipients(MailAddressFixture.ANY_AT_JAMES, MailAddressFixture.OTHER_AT_JAMES).build();
+
+        Address[] validSent = {};
+        Address[] validUnsent = {new InternetAddress(MailAddressFixture.OTHER_AT_JAMES.asString())};
+        Address[] invalid = {new InternetAddress(MailAddressFixture.ANY_AT_JAMES.asString())};
+        SendFailedException sfe = new SendFailedException("Message",
+            new Exception(),
+            validSent,
+            validUnsent,
+            invalid);
+        ExecutionResult executionResult = testee.handleSenderFailedException(mail, sfe);
+
+        assertThat(executionResult).isEqualTo(ExecutionResult.temporaryFailure(sfe));
+    }
+
+    @Test
+    public void handleSenderFailedExceptionShouldSetRecipientToInvalidWhenOnlyInvalid() throws Exception {
+        Mail mail = FakeMail.builder().recipients(MailAddressFixture.ANY_AT_JAMES, MailAddressFixture.OTHER_AT_JAMES).build();
+
+        Address[] validSent = {};
+        Address[] validUnsent = {};
+        Address[] invalid = {new InternetAddress(MailAddressFixture.ANY_AT_JAMES.asString())};
+        SendFailedException sfe = new SendFailedException("Message",
+            new Exception(),
+            validSent,
+            validUnsent,
+            invalid);
+        testee.handleSenderFailedException(mail, sfe);
+
+        assertThat(mail.getRecipients()).containsOnly(MailAddressFixture.ANY_AT_JAMES);
+    }
+
+    @Test
+    public void handleSenderFailedExceptionShouldSetRecipientToValidUnsentWhenOnlyValidUnsent() throws Exception {
+        Mail mail = FakeMail.builder().recipients(MailAddressFixture.ANY_AT_JAMES, MailAddressFixture.OTHER_AT_JAMES).build();
+
+        Address[] validSent = {};
+        Address[] validUnsent = {new InternetAddress(MailAddressFixture.OTHER_AT_JAMES.asString())};
+        Address[] invalid = {};
+        SendFailedException sfe = new SendFailedException("Message",
+            new Exception(),
+            validSent,
+            validUnsent,
+            invalid);
+        testee.handleSenderFailedException(mail, sfe);
+
+        assertThat(mail.getRecipients()).containsOnly(MailAddressFixture.OTHER_AT_JAMES);
+    }
+
+    @Test
+    public void handleSenderFailedExceptionShouldSetRecipientToValidUnsentWhenValidUnsentAndInvalid() throws Exception {
+        Mail mail = FakeMail.builder().recipients(MailAddressFixture.ANY_AT_JAMES, MailAddressFixture.OTHER_AT_JAMES).build();
+
+        Address[] validSent = {};
+        Address[] validUnsent = {new InternetAddress(MailAddressFixture.OTHER_AT_JAMES.asString())};
+        Address[] invalid = {new InternetAddress(MailAddressFixture.ANY_AT_JAMES.asString())};
+        SendFailedException sfe = new SendFailedException("Message",
+            new Exception(),
+            validSent,
+            validUnsent,
+            invalid);
+        testee.handleSenderFailedException(mail, sfe);
+
+        assertThat(mail.getRecipients()).containsOnly(MailAddressFixture.OTHER_AT_JAMES);
+    }
+
+    @Test
+    public void handleSenderFailedExceptionShouldBounceInvalidAddressesOnBothInvalidAndValidUnsent() throws Exception {
+        Mail mail = FakeMail.builder().recipients(MailAddressFixture.ANY_AT_JAMES, MailAddressFixture.OTHER_AT_JAMES).build();
+
+        Address[] validSent = {};
+        Address[] validUnsent = {new InternetAddress(MailAddressFixture.OTHER_AT_JAMES.asString())};
+        Address[] invalid = {new InternetAddress(MailAddressFixture.ANY_AT_JAMES.asString())};
+        SendFailedException sfe = new SendFailedException("Message",
+            new Exception(),
+            validSent,
+            validUnsent,
+            invalid);
+        testee.handleSenderFailedException(mail, sfe);
+
+        verify(bouncer).bounce(mail, sfe);
+        verifyNoMoreInteractions(bouncer);
+    }
+
+    @Test
+    public void deliverShouldReturnTemporaryFailureOnTemporaryResolutionException() throws Exception {
+        Mail mail = FakeMail.builder().recipients(MailAddressFixture.ANY_AT_JAMES, MailAddressFixture.OTHER_AT_JAMES).build();
+
+        when(dnsHelper.retrieveHostAddressIterator(MailAddressFixture.JAMES_APACHE_ORG)).thenThrow(new TemporaryResolutionException());
+
+        ExecutionResult executionResult = testee.deliver(mail);
+
+        assertThat(executionResult.getExecutionState()).isEqualTo(ExecutionResult.ExecutionState.TEMPORARY_FAILURE);
+    }
+
+    @Test
+    public void deliverShouldReturnTemporaryErrorWhenFirstDNSProblem() throws Exception {
+        Mail mail = FakeMail.builder().recipients(MailAddressFixture.ANY_AT_JAMES, MailAddressFixture.OTHER_AT_JAMES).build();
+
+        UnmodifiableIterator<HostAddress> empty = ImmutableList.<HostAddress>of().iterator();
+        when(dnsHelper.retrieveHostAddressIterator(MailAddressFixture.JAMES_APACHE_ORG)).thenReturn(empty);
+
+        ExecutionResult executionResult = testee.deliver(mail);
+
+        assertThat(executionResult.getExecutionState()).isEqualTo(ExecutionResult.ExecutionState.TEMPORARY_FAILURE);
+    }
+
+    @Test
+    public void deliverShouldReturnTemporaryErrorWhenToleratedDNSProblem() throws Exception {
+        Mail mail = FakeMail.builder().recipients(MailAddressFixture.ANY_AT_JAMES, MailAddressFixture.OTHER_AT_JAMES).build();
+        DeliveryRetriesHelper.incrementRetries(mail);
+
+        UnmodifiableIterator<HostAddress> empty = ImmutableList.<HostAddress>of().iterator();
+        when(dnsHelper.retrieveHostAddressIterator(MailAddressFixture.JAMES_APACHE_ORG)).thenReturn(empty);
+
+        ExecutionResult executionResult = testee.deliver(mail);
+
+        assertThat(executionResult.getExecutionState()).isEqualTo(ExecutionResult.ExecutionState.TEMPORARY_FAILURE);
+    }
+
+    @Test
+    public void deliverShouldReturnPermanentErrorWhenLimitDNSProblemReached() throws Exception {
+        Mail mail = FakeMail.builder().recipients(MailAddressFixture.ANY_AT_JAMES, MailAddressFixture.OTHER_AT_JAMES).build();
+        DeliveryRetriesHelper.incrementRetries(mail);
+        DeliveryRetriesHelper.incrementRetries(mail);
+        DeliveryRetriesHelper.incrementRetries(mail);
+
+        UnmodifiableIterator<HostAddress> empty = ImmutableList.<HostAddress>of().iterator();
+        when(dnsHelper.retrieveHostAddressIterator(MailAddressFixture.JAMES_APACHE_ORG)).thenReturn(empty);
+
+        ExecutionResult executionResult = testee.deliver(mail);
+
+        assertThat(executionResult.getExecutionState()).isEqualTo(ExecutionResult.ExecutionState.PERMANENT_FAILURE);
+    }
+
+    @Test
+    public void deliverShouldReturnPermanentErrorWhenLimitDNSProblemExceeded() throws Exception {
+        Mail mail = FakeMail.builder().recipients(MailAddressFixture.ANY_AT_JAMES, MailAddressFixture.OTHER_AT_JAMES).build();
+
+        DeliveryRetriesHelper.incrementRetries(mail);
+        DeliveryRetriesHelper.incrementRetries(mail);
+        DeliveryRetriesHelper.incrementRetries(mail);
+        DeliveryRetriesHelper.incrementRetries(mail);
+
+        UnmodifiableIterator<HostAddress> empty = ImmutableList.<HostAddress>of().iterator();
+        when(dnsHelper.retrieveHostAddressIterator(MailAddressFixture.JAMES_APACHE_ORG)).thenReturn(empty);
+
+        ExecutionResult executionResult = testee.deliver(mail);
+
+        assertThat(executionResult.getExecutionState()).isEqualTo(ExecutionResult.ExecutionState.PERMANENT_FAILURE);
+    }
+
+    @Test
+    public void deliverShouldWork() throws Exception {
+        Mail mail = FakeMail.builder().recipients(MailAddressFixture.ANY_AT_JAMES, MailAddressFixture.OTHER_AT_JAMES).build();
+
+        UnmodifiableIterator<HostAddress> dnsEntries = ImmutableList.of(
+            HOST_ADDRESS_1,
+            HOST_ADDRESS_2).iterator();
+        when(dnsHelper.retrieveHostAddressIterator(MailAddressFixture.JAMES_APACHE_ORG)).thenReturn(dnsEntries);
+        when(mailDelivrerToHost.tryDeliveryToHost(any(Mail.class), any(InternetAddress[].class), any(HostAddress.class)))
+            .thenReturn(ExecutionResult.success());
+        ExecutionResult executionResult = testee.deliver(mail);
+
+        verify(mailDelivrerToHost, times(1)).tryDeliveryToHost(any(Mail.class), any(InternetAddress[].class), any(HostAddress.class));
+        assertThat(executionResult.getExecutionState()).isEqualTo(ExecutionResult.ExecutionState.SUCCESS);
+    }
+
+    @Test
+    public void deliverShouldAbortWhenServerError() throws Exception {
+        Mail mail = FakeMail.builder().recipients(MailAddressFixture.ANY_AT_JAMES, MailAddressFixture.OTHER_AT_JAMES).build();
+
+        UnmodifiableIterator<HostAddress> dnsEntries = ImmutableList.of(
+            HOST_ADDRESS_1,
+            HOST_ADDRESS_2).iterator();
+        when(dnsHelper.retrieveHostAddressIterator(MailAddressFixture.JAMES_APACHE_ORG)).thenReturn(dnsEntries);
+        when(mailDelivrerToHost.tryDeliveryToHost(any(Mail.class), any(InternetAddress[].class), any(HostAddress.class)))
+            .thenThrow(new MessagingException("500 : Horrible way to manage Server Return code"));
+        ExecutionResult executionResult = testee.deliver(mail);
+
+        verify(mailDelivrerToHost, times(1)).tryDeliveryToHost(any(Mail.class), any(InternetAddress[].class), any(HostAddress.class));
+        assertThat(executionResult.getExecutionState()).isEqualTo(ExecutionResult.ExecutionState.PERMANENT_FAILURE);
+    }
+
+    @Test
+    public void deliverShouldAbortWithTemporaryWhenMessagingExceptionCauseUnknown() throws Exception {
+        Mail mail = FakeMail.builder().recipients(MailAddressFixture.ANY_AT_JAMES, MailAddressFixture.OTHER_AT_JAMES).build();
+
+        UnmodifiableIterator<HostAddress> dnsEntries = ImmutableList.of(
+            HOST_ADDRESS_1,
+            HOST_ADDRESS_2).iterator();
+        when(dnsHelper.retrieveHostAddressIterator(MailAddressFixture.JAMES_APACHE_ORG)).thenReturn(dnsEntries);
+        when(mailDelivrerToHost.tryDeliveryToHost(any(Mail.class), any(InternetAddress[].class), any(HostAddress.class)))
+            .thenThrow(new MessagingException("400 : Horrible way to manage Server Return code"));
+        ExecutionResult executionResult = testee.deliver(mail);
+
+        verify(mailDelivrerToHost, times(1)).tryDeliveryToHost(any(Mail.class), any(InternetAddress[].class), any(HostAddress.class));
+        assertThat(executionResult.getExecutionState()).isEqualTo(ExecutionResult.ExecutionState.TEMPORARY_FAILURE);
+    }
+
+    @Test
+    public void deliverShouldTryTwiceOnIOException() throws Exception {
+        Mail mail = FakeMail.builder().recipients(MailAddressFixture.ANY_AT_JAMES, MailAddressFixture.OTHER_AT_JAMES).build();
+
+        UnmodifiableIterator<HostAddress> dnsEntries = ImmutableList.of(
+            HOST_ADDRESS_1,
+            HOST_ADDRESS_2).iterator();
+        when(dnsHelper.retrieveHostAddressIterator(MailAddressFixture.JAMES_APACHE_ORG)).thenReturn(dnsEntries);
+        when(mailDelivrerToHost.tryDeliveryToHost(any(Mail.class), any(InternetAddress[].class), eq(HOST_ADDRESS_1)))
+            .thenThrow(new MessagingException("400 : Horrible way to manage Server Return code", new IOException()));
+        when(mailDelivrerToHost.tryDeliveryToHost(any(Mail.class), any(InternetAddress[].class), eq(HOST_ADDRESS_2)))
+            .thenReturn(ExecutionResult.success());
+        ExecutionResult executionResult = testee.deliver(mail);
+
+        verify(mailDelivrerToHost, times(2)).tryDeliveryToHost(any(Mail.class), any(InternetAddress[].class), any(HostAddress.class));
+        assertThat(executionResult.getExecutionState()).isEqualTo(ExecutionResult.ExecutionState.SUCCESS);
+    }
+
+    @Test
+    public void deliverShouldAbortWhenServerErrorSFE() throws Exception {
+        Mail mail = FakeMail.builder().recipients(MailAddressFixture.ANY_AT_JAMES, MailAddressFixture.OTHER_AT_JAMES).build();
+
+        UnmodifiableIterator<HostAddress> dnsEntries = ImmutableList.of(
+            HOST_ADDRESS_1,
+            HOST_ADDRESS_2).iterator();
+        when(dnsHelper.retrieveHostAddressIterator(MailAddressFixture.JAMES_APACHE_ORG)).thenReturn(dnsEntries);
+        when(mailDelivrerToHost.tryDeliveryToHost(any(Mail.class), any(InternetAddress[].class), any(HostAddress.class)))
+            .thenThrow(new SMTPSenderFailedException(new InternetAddress(MailAddressFixture.ANY_AT_JAMES.toString()), "command", 505, "Big failure"));
+        ExecutionResult executionResult = testee.deliver(mail);
+
+        verify(mailDelivrerToHost, times(1)).tryDeliveryToHost(any(Mail.class), any(InternetAddress[].class), any(HostAddress.class));
+        assertThat(executionResult.getExecutionState()).isEqualTo(ExecutionResult.ExecutionState.PERMANENT_FAILURE);
+    }
+
+    @Test
+    public void deliverShouldAttemptDeliveryOnlyOnceIfNoMoreValidUnsent() throws Exception {
+        Mail mail = FakeMail.builder().recipients(MailAddressFixture.ANY_AT_JAMES, MailAddressFixture.OTHER_AT_JAMES).build();
+
+        UnmodifiableIterator<HostAddress> dnsEntries = ImmutableList.of(
+            HOST_ADDRESS_1,
+            HOST_ADDRESS_2).iterator();
+        when(dnsHelper.retrieveHostAddressIterator(MailAddressFixture.JAMES_APACHE_ORG)).thenReturn(dnsEntries);
+        when(mailDelivrerToHost.tryDeliveryToHost(any(Mail.class), any(InternetAddress[].class), any(HostAddress.class)))
+            .thenThrow(new SendFailedException());
+        ExecutionResult executionResult = testee.deliver(mail);
+
+        verify(mailDelivrerToHost, times(1)).tryDeliveryToHost(any(Mail.class), any(InternetAddress[].class), any(HostAddress.class));
+        assertThat(executionResult.getExecutionState()).isEqualTo(ExecutionResult.ExecutionState.TEMPORARY_FAILURE);
+    }
+
+    @Test
+    public void deliverShouldAttemptDeliveryOnBothMXIfStillRecipients() throws Exception {
+        Mail mail = FakeMail.builder().recipients(MailAddressFixture.ANY_AT_JAMES, MailAddressFixture.OTHER_AT_JAMES).build();
+        Address[] validSent = {};
+        Address[] validUnsent = {new InternetAddress(MailAddressFixture.OTHER_AT_JAMES.asString())};
+        Address[] invalid = {};
+        SendFailedException sfe = new SendFailedException("Message",
+            new Exception(),
+            validSent,
+            validUnsent,
+            invalid);
+
+        UnmodifiableIterator<HostAddress> dnsEntries = ImmutableList.of(
+            HOST_ADDRESS_1,
+            HOST_ADDRESS_2).iterator();
+        when(dnsHelper.retrieveHostAddressIterator(MailAddressFixture.JAMES_APACHE_ORG)).thenReturn(dnsEntries);
+        when(mailDelivrerToHost.tryDeliveryToHost(any(Mail.class), any(InternetAddress[].class), any(HostAddress.class)))
+            .thenThrow(sfe);
+        ExecutionResult executionResult = testee.deliver(mail);
+
+        verify(mailDelivrerToHost, times(2)).tryDeliveryToHost(any(Mail.class), any(InternetAddress[].class), any(HostAddress.class));
+        assertThat(executionResult.getExecutionState()).isEqualTo(ExecutionResult.ExecutionState.TEMPORARY_FAILURE);
+    }
+
+    @Test
+    public void deliverShouldWorkIfOnlyMX2Valid() throws Exception {
+        Mail mail = FakeMail.builder().recipients(MailAddressFixture.ANY_AT_JAMES, MailAddressFixture.OTHER_AT_JAMES).build();
+        Address[] validSent = {};
+        Address[] validUnsent = {new InternetAddress(MailAddressFixture.OTHER_AT_JAMES.asString())};
+        Address[] invalid = {};
+        SendFailedException sfe = new SendFailedException("Message",
+            new Exception(),
+            validSent,
+            validUnsent,
+            invalid);
+
+        UnmodifiableIterator<HostAddress> dnsEntries = ImmutableList.of(
+            HOST_ADDRESS_1,
+            HOST_ADDRESS_2).iterator();
+        when(dnsHelper.retrieveHostAddressIterator(MailAddressFixture.JAMES_APACHE_ORG)).thenReturn(dnsEntries);
+        when(mailDelivrerToHost.tryDeliveryToHost(any(Mail.class), any(InternetAddress[].class), eq(HOST_ADDRESS_1)))
+            .thenThrow(sfe);
+        when(mailDelivrerToHost.tryDeliveryToHost(any(Mail.class), any(InternetAddress[].class), eq(HOST_ADDRESS_2)))
+            .thenReturn(ExecutionResult.success());
+        ExecutionResult executionResult = testee.deliver(mail);
+
+        verify(mailDelivrerToHost, times(2)).tryDeliveryToHost(any(Mail.class), any(InternetAddress[].class), any(HostAddress.class));
+        assertThat(executionResult.getExecutionState()).isEqualTo(ExecutionResult.ExecutionState.SUCCESS);
+    }
+
+}

http://git-wip-us.apache.org/repos/asf/james-project/blob/52c18ef6/server/mailet/mailets/src/test/java/org/apache/james/transport/mailets/remote/delivery/RemoteDeliveryConfigurationTest.java
----------------------------------------------------------------------
diff --git a/server/mailet/mailets/src/test/java/org/apache/james/transport/mailets/remote/delivery/RemoteDeliveryConfigurationTest.java b/server/mailet/mailets/src/test/java/org/apache/james/transport/mailets/remote/delivery/RemoteDeliveryConfigurationTest.java
new file mode 100644
index 0000000..f8aef3e
--- /dev/null
+++ b/server/mailet/mailets/src/test/java/org/apache/james/transport/mailets/remote/delivery/RemoteDeliveryConfigurationTest.java
@@ -0,0 +1,940 @@
+/****************************************************************
+ * 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.transport.mailets.remote.delivery;
+
+import static org.assertj.core.api.Assertions.assertThat;
+import static org.mockito.Mockito.mock;
+import static org.mockito.Mockito.when;
+
+import java.util.Properties;
+
+import org.apache.james.domainlist.api.DomainList;
+import org.apache.mailet.base.test.FakeMailetConfig;
+import org.assertj.core.data.MapEntry;
+import org.junit.Rule;
+import org.junit.Test;
+import org.junit.rules.ExpectedException;
+
+public class RemoteDeliveryConfigurationTest {
+
+    @Rule
+    public ExpectedException expectedException = ExpectedException.none();
+
+    @Test
+    public void isDebugShouldBeFalseByDefault() {
+        FakeMailetConfig mailetConfig = FakeMailetConfig.builder()
+            .setProperty(RemoteDeliveryConfiguration.DELIVERY_THREADS, "1")
+            .build();
+
+        assertThat(new RemoteDeliveryConfiguration(mailetConfig, mock(DomainList.class)).isDebug()).isFalse();
+    }
+
+    @Test
+    public void isDebugShouldBeTrueIfSpecified() {
+        FakeMailetConfig mailetConfig = FakeMailetConfig.builder()
+            .setProperty(RemoteDeliveryConfiguration.DELIVERY_THREADS, "1")
+            .setProperty(RemoteDeliveryConfiguration.DEBUG, "true")
+            .build();
+
+        assertThat(new RemoteDeliveryConfiguration(mailetConfig, mock(DomainList.class)).isDebug()).isTrue();
+    }
+
+    @Test
+    public void isDebugShouldBeFalseIfSpecified() {
+        FakeMailetConfig mailetConfig = FakeMailetConfig.builder()
+            .setProperty(RemoteDeliveryConfiguration.DELIVERY_THREADS, "1")
+            .setProperty(RemoteDeliveryConfiguration.DEBUG, "false")
+            .build();
+
+        assertThat(new RemoteDeliveryConfiguration(mailetConfig, mock(DomainList.class)).isDebug()).isFalse();
+    }
+
+    @Test
+    public void isDebugShouldBeFalseIfParsingException() {
+        FakeMailetConfig mailetConfig = FakeMailetConfig.builder()
+            .setProperty(RemoteDeliveryConfiguration.DELIVERY_THREADS, "1")
+            .setProperty(RemoteDeliveryConfiguration.DEBUG, "invalid")
+            .build();
+
+        assertThat(new RemoteDeliveryConfiguration(mailetConfig, mock(DomainList.class)).isDebug()).isFalse();
+    }
+
+    @Test
+    public void getSmtpTimeoutShouldReturnDefault() {
+        FakeMailetConfig mailetConfig = FakeMailetConfig.builder()
+            .setProperty(RemoteDeliveryConfiguration.DELIVERY_THREADS, "1")
+            .build();
+
+        assertThat(new RemoteDeliveryConfiguration(mailetConfig, mock(DomainList.class)).getSmtpTimeout())
+            .isEqualTo(RemoteDeliveryConfiguration.DEFAULT_SMTP_TIMEOUT);
+    }
+
+    @Test
+    public void getSmtpTimeoutShouldReturnProvidedValue() {
+        int value = 150000;
+        FakeMailetConfig mailetConfig = FakeMailetConfig.builder()
+            .setProperty(RemoteDeliveryConfiguration.DELIVERY_THREADS, "1")
+            .setProperty(RemoteDeliveryConfiguration.TIMEOUT, String.valueOf(value))
+            .build();
+
+        assertThat(new RemoteDeliveryConfiguration(mailetConfig, mock(DomainList.class)).getSmtpTimeout())
+            .isEqualTo(value);
+    }
+
+    @Test
+    public void getSmtpTimeoutShouldReturnDefaultIfParsingException() {
+        FakeMailetConfig mailetConfig = FakeMailetConfig.builder()
+            .setProperty(RemoteDeliveryConfiguration.DELIVERY_THREADS, "1")
+            .setProperty(RemoteDeliveryConfiguration.TIMEOUT, "invalid")
+            .build();
+
+        assertThat(new RemoteDeliveryConfiguration(mailetConfig, mock(DomainList.class)).getSmtpTimeout())
+            .isEqualTo(RemoteDeliveryConfiguration.DEFAULT_SMTP_TIMEOUT);
+    }
+
+    @Test
+    public void getSmtpTimeoutShouldReturnProvidedValueWhenZero() {
+        FakeMailetConfig mailetConfig = FakeMailetConfig.builder()
+            .setProperty(RemoteDeliveryConfiguration.DELIVERY_THREADS, "1")
+            .setProperty(RemoteDeliveryConfiguration.TIMEOUT, "0")
+            .build();
+
+        assertThat(new RemoteDeliveryConfiguration(mailetConfig, mock(DomainList.class)).getSmtpTimeout())
+            .isEqualTo(0);
+    }
+
+    @Test
+    public void getSmtpTimeoutShouldReturnProvidedValueWhenNegativeNumber() {
+        FakeMailetConfig mailetConfig = FakeMailetConfig.builder()
+            .setProperty(RemoteDeliveryConfiguration.DELIVERY_THREADS, "1")
+            .setProperty(RemoteDeliveryConfiguration.TIMEOUT, "-1")
+            .build();
+
+        assertThat(new RemoteDeliveryConfiguration(mailetConfig, mock(DomainList.class)).getSmtpTimeout())
+            .isEqualTo(-1);
+    }
+
+    @Test
+    public void getOutGoingQueueNameShouldReturnDefault() {
+        FakeMailetConfig mailetConfig = FakeMailetConfig.builder()
+            .setProperty(RemoteDeliveryConfiguration.DELIVERY_THREADS, "1")
+            .build();
+
+        assertThat(new RemoteDeliveryConfiguration(mailetConfig, mock(DomainList.class)).getOutGoingQueueName())
+            .isEqualTo(RemoteDeliveryConfiguration.DEFAULT_OUTGOING_QUEUE_NAME);
+    }
+
+    @Test
+    public void getOutGoingQueueNameShouldReturnProvidedValue() {
+        String value = "value";
+        FakeMailetConfig mailetConfig = FakeMailetConfig.builder()
+            .setProperty(RemoteDeliveryConfiguration.DELIVERY_THREADS, "1")
+            .setProperty(RemoteDeliveryConfiguration.OUTGOING, value)
+            .build();
+
+        assertThat(new RemoteDeliveryConfiguration(mailetConfig, mock(DomainList.class)).getOutGoingQueueName())
+            .isEqualTo(value);
+    }
+
+    @Test
+    public void getConnectionTimeoutShouldReturnDefault() {
+        FakeMailetConfig mailetConfig = FakeMailetConfig.builder()
+            .setProperty(RemoteDeliveryConfiguration.DELIVERY_THREADS, "1")
+            .build();
+
+        assertThat(new RemoteDeliveryConfiguration(mailetConfig, mock(DomainList.class)).getConnectionTimeout())
+            .isEqualTo(RemoteDeliveryConfiguration.DEFAULT_CONNECTION_TIMEOUT);
+    }
+
+    @Test
+    public void getConnectionTimeoutShouldReturnProvidedValue() {
+        int value = 150000;
+        FakeMailetConfig mailetConfig = FakeMailetConfig.builder()
+            .setProperty(RemoteDeliveryConfiguration.DELIVERY_THREADS, "1")
+            .setProperty(RemoteDeliveryConfiguration.CONNECTIONTIMEOUT, String.valueOf(value))
+            .build();
+
+        assertThat(new RemoteDeliveryConfiguration(mailetConfig, mock(DomainList.class)).getConnectionTimeout())
+            .isEqualTo(value);
+    }
+
+    @Test
+    public void getConnectionTimeoutShouldReturnDefaultIfParsingException() {
+        FakeMailetConfig mailetConfig = FakeMailetConfig.builder()
+            .setProperty(RemoteDeliveryConfiguration.DELIVERY_THREADS, "1")
+            .setProperty(RemoteDeliveryConfiguration.CONNECTIONTIMEOUT, "invalid")
+            .build();
+
+        assertThat(new RemoteDeliveryConfiguration(mailetConfig, mock(DomainList.class)).getConnectionTimeout())
+            .isEqualTo(RemoteDeliveryConfiguration.DEFAULT_CONNECTION_TIMEOUT);
+    }
+
+    @Test
+    public void getConnectionTimeoutShouldReturnProvidedValueWhenZero() {
+        FakeMailetConfig mailetConfig = FakeMailetConfig.builder()
+            .setProperty(RemoteDeliveryConfiguration.DELIVERY_THREADS, "1")
+            .setProperty(RemoteDeliveryConfiguration.CONNECTIONTIMEOUT, "0")
+            .build();
+
+        assertThat(new RemoteDeliveryConfiguration(mailetConfig, mock(DomainList.class)).getConnectionTimeout())
+            .isEqualTo(0);
+    }
+
+    @Test
+    public void getConnectionTimeoutShouldReturnProvidedValueWhenNegativeNumber() {
+        FakeMailetConfig mailetConfig = FakeMailetConfig.builder()
+            .setProperty(RemoteDeliveryConfiguration.DELIVERY_THREADS, "1")
+            .setProperty(RemoteDeliveryConfiguration.CONNECTIONTIMEOUT, "-1")
+            .build();
+
+        assertThat(new RemoteDeliveryConfiguration(mailetConfig, mock(DomainList.class)).getConnectionTimeout())
+            .isEqualTo(-1);
+    }
+
+    @Test
+    public void isSendPartialShouldBeFalseByDefault() {
+        FakeMailetConfig mailetConfig = FakeMailetConfig.builder()
+            .setProperty(RemoteDeliveryConfiguration.DELIVERY_THREADS, "1")
+            .build();
+
+        assertThat(new RemoteDeliveryConfiguration(mailetConfig, mock(DomainList.class)).isSendPartial()).isFalse();
+    }
+
+    @Test
+    public void isSendPartialShouldBeTrueIfSpecified() {
+        FakeMailetConfig mailetConfig = FakeMailetConfig.builder()
+            .setProperty(RemoteDeliveryConfiguration.DELIVERY_THREADS, "1")
+            .setProperty(RemoteDeliveryConfiguration.SENDPARTIAL, "true")
+            .build();
+
+        assertThat(new RemoteDeliveryConfiguration(mailetConfig, mock(DomainList.class)).isSendPartial()).isTrue();
+    }
+
+    @Test
+    public void isSendPartialShouldBeFalseIfSpecified() {
+        FakeMailetConfig mailetConfig = FakeMailetConfig.builder()
+            .setProperty(RemoteDeliveryConfiguration.DELIVERY_THREADS, "1")
+            .setProperty(RemoteDeliveryConfiguration.SENDPARTIAL, "false")
+            .build();
+
+        assertThat(new RemoteDeliveryConfiguration(mailetConfig, mock(DomainList.class)).isSendPartial()).isFalse();
+    }
+
+    @Test
+    public void isSendPartialShouldBeFalseIfParsingException() {
+        FakeMailetConfig mailetConfig = FakeMailetConfig.builder()
+            .setProperty(RemoteDeliveryConfiguration.DELIVERY_THREADS, "1")
+            .setProperty(RemoteDeliveryConfiguration.SENDPARTIAL, "invalid")
+            .build();
+
+        assertThat(new RemoteDeliveryConfiguration(mailetConfig, mock(DomainList.class)).isSendPartial()).isFalse();
+    }
+
+    @Test
+    public void getBounceProcessorShouldReturnNullByDefault() {
+        FakeMailetConfig mailetConfig = FakeMailetConfig.builder()
+            .setProperty(RemoteDeliveryConfiguration.DELIVERY_THREADS, "1")
+            .build();
+
+        assertThat(new RemoteDeliveryConfiguration(mailetConfig, mock(DomainList.class)).getBounceProcessor())
+            .isNull();
+    }
+
+    @Test
+    public void getBounceProcessorShouldReturnProvidedValue() {
+        String value = "value";
+        FakeMailetConfig mailetConfig = FakeMailetConfig.builder()
+            .setProperty(RemoteDeliveryConfiguration.DELIVERY_THREADS, "1")
+            .setProperty(RemoteDeliveryConfiguration.BOUNCE_PROCESSOR, value)
+            .build();
+
+        assertThat(new RemoteDeliveryConfiguration(mailetConfig, mock(DomainList.class)).getBounceProcessor())
+            .isEqualTo(value);
+    }
+
+    @Test
+    public void isStartTLSShouldBeFalseByDefault() {
+        FakeMailetConfig mailetConfig = FakeMailetConfig.builder()
+            .setProperty(RemoteDeliveryConfiguration.DELIVERY_THREADS, "1")
+            .build();
+
+        assertThat(new RemoteDeliveryConfiguration(mailetConfig, mock(DomainList.class)).isStartTLS()).isFalse();
+    }
+
+    @Test
+    public void isStartTLSShouldBeTrueIfSpecified() {
+        FakeMailetConfig mailetConfig = FakeMailetConfig.builder()
+            .setProperty(RemoteDeliveryConfiguration.DELIVERY_THREADS, "1")
+            .setProperty(RemoteDeliveryConfiguration.START_TLS, "true")
+            .build();
+
+        assertThat(new RemoteDeliveryConfiguration(mailetConfig, mock(DomainList.class)).isStartTLS()).isTrue();
+    }
+
+    @Test
+    public void isStartTLSShouldBeFalseIfSpecified() {
+        FakeMailetConfig mailetConfig = FakeMailetConfig.builder()
+            .setProperty(RemoteDeliveryConfiguration.DELIVERY_THREADS, "1")
+            .setProperty(RemoteDeliveryConfiguration.START_TLS, "false")
+            .build();
+
+        assertThat(new RemoteDeliveryConfiguration(mailetConfig, mock(DomainList.class)).isStartTLS()).isFalse();
+    }
+
+    @Test
+    public void isStartTLSShouldBeFalseIfParsingException() {
+        FakeMailetConfig mailetConfig = FakeMailetConfig.builder()
+            .setProperty(RemoteDeliveryConfiguration.DELIVERY_THREADS, "1")
+            .setProperty(RemoteDeliveryConfiguration.START_TLS, "invalid")
+            .build();
+
+        assertThat(new RemoteDeliveryConfiguration(mailetConfig, mock(DomainList.class)).isStartTLS()).isFalse();
+    }
+
+    @Test
+    public void isSSLEnableShouldBeFalseByDefault() {
+        FakeMailetConfig mailetConfig = FakeMailetConfig.builder()
+            .setProperty(RemoteDeliveryConfiguration.DELIVERY_THREADS, "1")
+            .build();
+
+        assertThat(new RemoteDeliveryConfiguration(mailetConfig, mock(DomainList.class)).isSSLEnable()).isFalse();
+    }
+
+    @Test
+    public void isSSLEnableShouldBeTrueIfSpecified() {
+        FakeMailetConfig mailetConfig = FakeMailetConfig.builder()
+            .setProperty(RemoteDeliveryConfiguration.DELIVERY_THREADS, "1")
+            .setProperty(RemoteDeliveryConfiguration.SSL_ENABLE, "true")
+            .build();
+
+        assertThat(new RemoteDeliveryConfiguration(mailetConfig, mock(DomainList.class)).isSSLEnable()).isTrue();
+    }
+
+    @Test
+    public void isSSLEnableShouldBeFalseIfSpecified() {
+        FakeMailetConfig mailetConfig = FakeMailetConfig.builder()
+            .setProperty(RemoteDeliveryConfiguration.DELIVERY_THREADS, "1")
+            .setProperty(RemoteDeliveryConfiguration.SSL_ENABLE, "false")
+            .build();
+
+        assertThat(new RemoteDeliveryConfiguration(mailetConfig, mock(DomainList.class)).isSSLEnable()).isFalse();
+    }
+
+    @Test
+    public void isSSLEnableShouldBeFalseIfParsingException() {
+        FakeMailetConfig mailetConfig = FakeMailetConfig.builder()
+            .setProperty(RemoteDeliveryConfiguration.DELIVERY_THREADS, "1")
+            .setProperty(RemoteDeliveryConfiguration.SSL_ENABLE, "invalid")
+            .build();
+
+        assertThat(new RemoteDeliveryConfiguration(mailetConfig, mock(DomainList.class)).isSSLEnable()).isFalse();
+    }
+
+    @Test
+    public void isBindUsedShouldBeFalseByDefault() {
+        FakeMailetConfig mailetConfig = FakeMailetConfig.builder()
+            .setProperty(RemoteDeliveryConfiguration.DELIVERY_THREADS, "1")
+            .setProperty(RemoteDeliveryConfiguration.BIND, "127.0.0.1:25")
+            .build();
+
+        assertThat(new RemoteDeliveryConfiguration(mailetConfig, mock(DomainList.class)).isBindUsed()).isTrue();
+    }
+
+    @Test
+    public void getBindAddressShouldBeNullByDefault() {
+        FakeMailetConfig mailetConfig = FakeMailetConfig.builder()
+            .setProperty(RemoteDeliveryConfiguration.DELIVERY_THREADS, "1")
+            .build();
+
+        assertThat(new RemoteDeliveryConfiguration(mailetConfig, mock(DomainList.class)).getBindAddress()).isNull();
+    }
+
+    @Test
+    public void getBindAddressShouldReturnProvidedValue() {
+        String value = "127.0.0.1:25";
+        FakeMailetConfig mailetConfig = FakeMailetConfig.builder()
+            .setProperty(RemoteDeliveryConfiguration.DELIVERY_THREADS, "1")
+            .setProperty(RemoteDeliveryConfiguration.BIND, value)
+            .build();
+
+        assertThat(new RemoteDeliveryConfiguration(mailetConfig, mock(DomainList.class)).getBindAddress()).isEqualTo(value);
+    }
+
+    @Test
+    public void getDnsProblemRetryShouldReturnDefault() {
+        FakeMailetConfig mailetConfig = FakeMailetConfig.builder()
+            .setProperty(RemoteDeliveryConfiguration.DELIVERY_THREADS, "1")
+            .build();
+
+        assertThat(new RemoteDeliveryConfiguration(mailetConfig, mock(DomainList.class)).getDnsProblemRetry())
+            .isEqualTo(RemoteDeliveryConfiguration.DEFAULT_DNS_RETRY_PROBLEM);
+    }
+
+    @Test
+    public void getDnsProblemRetryShouldReturnProvidedValue() {
+        int value = 4;
+        FakeMailetConfig mailetConfig = FakeMailetConfig.builder()
+            .setProperty(RemoteDeliveryConfiguration.DELIVERY_THREADS, "1")
+            .setProperty(RemoteDeliveryConfiguration.MAX_DNS_PROBLEM_RETRIES, String.valueOf(value))
+            .build();
+
+        assertThat(new RemoteDeliveryConfiguration(mailetConfig, mock(DomainList.class)).getDnsProblemRetry())
+            .isEqualTo(value);
+    }
+
+    @Test
+    public void constructorShouldThrowOnInvalidDnsRetries() {
+        FakeMailetConfig mailetConfig = FakeMailetConfig.builder()
+            .setProperty(RemoteDeliveryConfiguration.DELIVERY_THREADS, "1")
+            .setProperty(RemoteDeliveryConfiguration.MAX_DNS_PROBLEM_RETRIES, "invalid")
+            .build();
+
+        expectedException.expect(NumberFormatException.class);
+
+        new RemoteDeliveryConfiguration(mailetConfig, mock(DomainList.class));
+    }
+
+    @Test
+    public void getDnsProblemRetryShouldReturnProvidedValueWhenZero() {
+        FakeMailetConfig mailetConfig = FakeMailetConfig.builder()
+            .setProperty(RemoteDeliveryConfiguration.DELIVERY_THREADS, "1")
+            .setProperty(RemoteDeliveryConfiguration.MAX_DNS_PROBLEM_RETRIES, "0")
+            .build();
+
+        assertThat(new RemoteDeliveryConfiguration(mailetConfig, mock(DomainList.class)).getDnsProblemRetry())
+            .isEqualTo(0);
+    }
+
+    @Test
+    public void getDnsProblemRetryShouldReturnProvidedValueWhenEmpty() {
+        FakeMailetConfig mailetConfig = FakeMailetConfig.builder()
+            .setProperty(RemoteDeliveryConfiguration.DELIVERY_THREADS, "1")
+            .setProperty(RemoteDeliveryConfiguration.MAX_DNS_PROBLEM_RETRIES, "")
+            .build();
+
+        assertThat(new RemoteDeliveryConfiguration(mailetConfig, mock(DomainList.class)).getDnsProblemRetry())
+            .isEqualTo(0);
+    }
+
+    @Test
+    public void getDnsProblemRetryShouldReturnProvidedValueWhenNegativeNumber() {
+        FakeMailetConfig mailetConfig = FakeMailetConfig.builder()
+            .setProperty(RemoteDeliveryConfiguration.DELIVERY_THREADS, "1")
+            .setProperty(RemoteDeliveryConfiguration.MAX_DNS_PROBLEM_RETRIES, "-1")
+            .build();
+
+        assertThat(new RemoteDeliveryConfiguration(mailetConfig, mock(DomainList.class)).getDnsProblemRetry())
+            .isEqualTo(-1);
+    }
+
+    @Test
+    public void constructorShouldThrowOnNonSpecifiedThreadCount() {
+        FakeMailetConfig mailetConfig = FakeMailetConfig.builder()
+            .build();
+
+        expectedException.expect(NumberFormatException.class);
+
+        new RemoteDeliveryConfiguration(mailetConfig, mock(DomainList.class)).getWorkersThreadCount();
+    }
+
+    @Test
+    public void getWorkersThreadCountShouldReturnProvidedValue() {
+        int value = 36;
+        FakeMailetConfig mailetConfig = FakeMailetConfig.builder()
+            .setProperty(RemoteDeliveryConfiguration.DELIVERY_THREADS, String.valueOf(value))
+            .build();
+
+        assertThat(new RemoteDeliveryConfiguration(mailetConfig, mock(DomainList.class)).getWorkersThreadCount())
+            .isEqualTo(value);
+    }
+
+    @Test
+    public void constructorShouldThrowOnInvalidThreadCount() {
+        FakeMailetConfig mailetConfig = FakeMailetConfig.builder()
+            .setProperty(RemoteDeliveryConfiguration.DELIVERY_THREADS, "invalid")
+            .build();
+
+        expectedException.expect(NumberFormatException.class);
+
+        new RemoteDeliveryConfiguration(mailetConfig, mock(DomainList.class)).getWorkersThreadCount();
+    }
+
+    @Test
+    public void isUsePriorityShouldBeFalseByDefault() {
+        FakeMailetConfig mailetConfig = FakeMailetConfig.builder()
+            .setProperty(RemoteDeliveryConfiguration.DELIVERY_THREADS, "1")
+            .build();
+
+        assertThat(new RemoteDeliveryConfiguration(mailetConfig, mock(DomainList.class)).isUsePriority()).isFalse();
+    }
+
+    @Test
+    public void isUsePriorityShouldBeTrueIfSpecified() {
+        FakeMailetConfig mailetConfig = FakeMailetConfig.builder()
+            .setProperty(RemoteDeliveryConfiguration.DELIVERY_THREADS, "1")
+            .setProperty(RemoteDeliveryConfiguration.USE_PRIORITY, "true")
+            .build();
+
+        assertThat(new RemoteDeliveryConfiguration(mailetConfig, mock(DomainList.class)).isUsePriority()).isTrue();
+    }
+
+    @Test
+    public void isUsePriorityShouldBeFalseIfSpecified() {
+        FakeMailetConfig mailetConfig = FakeMailetConfig.builder()
+            .setProperty(RemoteDeliveryConfiguration.DELIVERY_THREADS, "1")
+            .setProperty(RemoteDeliveryConfiguration.USE_PRIORITY, "false")
+            .build();
+
+        assertThat(new RemoteDeliveryConfiguration(mailetConfig, mock(DomainList.class)).isUsePriority()).isFalse();
+    }
+
+    @Test
+    public void isUsePriorityShouldBeFalseIfParsingException() {
+        FakeMailetConfig mailetConfig = FakeMailetConfig.builder()
+            .setProperty(RemoteDeliveryConfiguration.DELIVERY_THREADS, "1")
+            .setProperty(RemoteDeliveryConfiguration.USE_PRIORITY, "invalid")
+            .build();
+
+        assertThat(new RemoteDeliveryConfiguration(mailetConfig, mock(DomainList.class)).isUsePriority()).isFalse();
+    }
+
+    @Test
+    public void getHeloNameProviderShouldCallDomainListByDefault() throws Exception {
+        DomainList domainList = mock(DomainList.class);
+        String value = "value";
+        when(domainList.getDefaultDomain()).thenReturn(value);
+        FakeMailetConfig mailetConfig = FakeMailetConfig.builder()
+            .setProperty(RemoteDeliveryConfiguration.DELIVERY_THREADS, "1")
+            .build();
+
+        assertThat(new RemoteDeliveryConfiguration(mailetConfig, domainList).getHeloNameProvider().getHeloName())
+            .isEqualTo(value);
+    }
+
+    @Test
+    public void getHeloNameProviderShouldTakeCareOfProvidedValue() {
+        String value = "value";
+        FakeMailetConfig mailetConfig = FakeMailetConfig.builder()
+            .setProperty(RemoteDeliveryConfiguration.DELIVERY_THREADS, "1")
+            .setProperty(RemoteDeliveryConfiguration.HELO_NAME, value)
+            .build();
+
+        assertThat(new RemoteDeliveryConfiguration(mailetConfig, mock(DomainList.class)).getHeloNameProvider().getHeloName())
+            .isEqualTo(value);
+    }
+
+    @Test
+    public void getJavaxAdditionalPropertiesShouldBeEmptyByDefault() {
+        FakeMailetConfig mailetConfig = FakeMailetConfig.builder()
+            .setProperty(RemoteDeliveryConfiguration.DELIVERY_THREADS, "1")
+            .build();
+
+        assertThat(new RemoteDeliveryConfiguration(mailetConfig, mock(DomainList.class)).getJavaxAdditionalProperties())
+            .isEmpty();
+    }
+
+    @Test
+    public void getJavaxAdditionalPropertiesShouldTakeOneEntryIntoAccount() {
+        String key1 = RemoteDeliveryConfiguration.JAVAX_PREFIX + "property1";
+        String value1 = "value1";
+        FakeMailetConfig mailetConfig = FakeMailetConfig.builder()
+            .setProperty(RemoteDeliveryConfiguration.DELIVERY_THREADS, "1")
+            .setProperty(key1, value1)
+            .build();
+
+        assertThat(new RemoteDeliveryConfiguration(mailetConfig, mock(DomainList.class)).getJavaxAdditionalProperties())
+            .containsOnly(MapEntry.entry(key1, value1));
+    }
+
+    @Test
+    public void getJavaxAdditionalPropertiesShouldTakeTwoEntriesIntoAccount() {
+        String key1 = RemoteDeliveryConfiguration.JAVAX_PREFIX + "property1";
+        String value1 = "value1";
+        String key2 = RemoteDeliveryConfiguration.JAVAX_PREFIX + "property2";
+        String value2 = "value2";
+        FakeMailetConfig mailetConfig = FakeMailetConfig.builder()
+            .setProperty(RemoteDeliveryConfiguration.DELIVERY_THREADS, "1")
+            .setProperty(key1, value1)
+            .setProperty(key2, value2)
+            .build();
+
+        assertThat(new RemoteDeliveryConfiguration(mailetConfig, mock(DomainList.class)).getJavaxAdditionalProperties())
+            .containsOnly(MapEntry.entry(key1, value1), MapEntry.entry(key2, value2));
+    }
+
+    @Test
+    public void constructorShouldThrowOnNullValueJavaxProperty() {
+        expectedException.expect(NullPointerException.class);
+
+        String key1 = RemoteDeliveryConfiguration.JAVAX_PREFIX + "property1";
+        FakeMailetConfig mailetConfig = FakeMailetConfig.builder()
+            .setProperty(RemoteDeliveryConfiguration.DELIVERY_THREADS, "1")
+            .setProperty(key1, null)
+            .build();
+
+        new RemoteDeliveryConfiguration(mailetConfig, mock(DomainList.class));
+    }
+
+    @Test
+    public void getJavaxAdditionalPropertiesShouldTakeOneEmptyEntryIntoAccount() {
+        String key1 = RemoteDeliveryConfiguration.JAVAX_PREFIX + "property1";
+        FakeMailetConfig mailetConfig = FakeMailetConfig.builder()
+            .setProperty(RemoteDeliveryConfiguration.DELIVERY_THREADS, "1")
+            .setProperty(key1, "")
+            .build();
+
+        assertThat(new RemoteDeliveryConfiguration(mailetConfig, mock(DomainList.class)).getJavaxAdditionalProperties())
+            .containsOnly(MapEntry.entry(key1, ""));
+    }
+
+    @Test
+    public void getGatewayServerShouldBeNullByDefault() {
+        FakeMailetConfig mailetConfig = FakeMailetConfig.builder()
+            .setProperty(RemoteDeliveryConfiguration.DELIVERY_THREADS, "1")
+            .build();
+
+        assertThat(new RemoteDeliveryConfiguration(mailetConfig, mock(DomainList.class)).getGatewayServer()).isEmpty();
+    }
+
+    @Test
+    public void getGatewayServerShouldReturnProvidedValue() {
+        String value = "127.0.0.1";
+        FakeMailetConfig mailetConfig = FakeMailetConfig.builder()
+            .setProperty(RemoteDeliveryConfiguration.DELIVERY_THREADS, "1")
+            .setProperty(RemoteDeliveryConfiguration.GATEWAY, value)
+            .build();
+
+        assertThat(new RemoteDeliveryConfiguration(mailetConfig, mock(DomainList.class)).getGatewayServer())
+            .containsOnly(value);
+    }
+
+    @Test
+    public void getGatewayServerShouldReturnProvidedValues() {
+        String value1 = "127.0.0.1";
+        String value2 = "domain";
+        FakeMailetConfig mailetConfig = FakeMailetConfig.builder()
+            .setProperty(RemoteDeliveryConfiguration.DELIVERY_THREADS, "1")
+            .setProperty(RemoteDeliveryConfiguration.GATEWAY, value1 + ',' + value2)
+            .build();
+
+        assertThat(new RemoteDeliveryConfiguration(mailetConfig, mock(DomainList.class)).getGatewayServer())
+            .containsOnly(value1, value2);
+    }
+
+    @Test
+    public void getGatewayServerShouldReturnGatewayWithGatewayPort() {
+        String server = "127.0.0.1";
+        String port = "2525";
+        FakeMailetConfig mailetConfig = FakeMailetConfig.builder()
+            .setProperty(RemoteDeliveryConfiguration.DELIVERY_THREADS, "1")
+            .setProperty(RemoteDeliveryConfiguration.GATEWAY, server)
+            .setProperty(RemoteDeliveryConfiguration.GATEWAY_PORT, port)
+            .build();
+
+        assertThat(new RemoteDeliveryConfiguration(mailetConfig, mock(DomainList.class)).getGatewayServer())
+            .containsOnly(server + ':' + port);
+    }
+
+    @Test
+    public void getGatewayServerShouldOnlyOverridePortsNotInitiallySet() {
+        String server1 = "127.0.0.1:23432";
+        String server2 = "domain";
+        String port = "2525";
+        FakeMailetConfig mailetConfig = FakeMailetConfig.builder()
+            .setProperty(RemoteDeliveryConfiguration.DELIVERY_THREADS, "1")
+            .setProperty(RemoteDeliveryConfiguration.GATEWAY, server1 + ',' + server2)
+            .setProperty(RemoteDeliveryConfiguration.GATEWAY_PORT, port)
+            .build();
+
+        assertThat(new RemoteDeliveryConfiguration(mailetConfig, mock(DomainList.class)).getGatewayServer())
+            .containsOnly(server1, server2 + ':' + port);
+    }
+
+    @Test
+    public void getAuthUserShouldBeNullByDefault() {
+        FakeMailetConfig mailetConfig = FakeMailetConfig.builder()
+            .setProperty(RemoteDeliveryConfiguration.DELIVERY_THREADS, "1")
+            .build();
+
+        assertThat(new RemoteDeliveryConfiguration(mailetConfig, mock(DomainList.class)).getAuthUser()).isNull();
+    }
+
+    @Test
+    public void getAuthUserShouldBeNullWhenGatewayIsNotSpecified() {
+        FakeMailetConfig mailetConfig = FakeMailetConfig.builder()
+            .setProperty(RemoteDeliveryConfiguration.DELIVERY_THREADS, "1")
+            .setProperty(RemoteDeliveryConfiguration.GATEWAY_USERNAME, "name")
+            .build();
+
+        assertThat(new RemoteDeliveryConfiguration(mailetConfig, mock(DomainList.class)).getAuthUser()).isNull();
+    }
+
+    @Test
+    public void getAuthUserShouldReturnSpecifiedValueWhenGatewaySpecified() {
+        String value = "name";
+        FakeMailetConfig mailetConfig = FakeMailetConfig.builder()
+            .setProperty(RemoteDeliveryConfiguration.DELIVERY_THREADS, "1")
+            .setProperty(RemoteDeliveryConfiguration.GATEWAY_USERNAME, value)
+            .setProperty(RemoteDeliveryConfiguration.GATEWAY, "127.0.0.1")
+            .build();
+
+        assertThat(new RemoteDeliveryConfiguration(mailetConfig, mock(DomainList.class)).getAuthUser()).isEqualTo(value);
+    }
+
+    @Test
+    public void getAuthUserShouldReturnSpecifiedEmptyValueWhenGatewaySpecified() {
+        String value = "";
+        FakeMailetConfig mailetConfig = FakeMailetConfig.builder()
+            .setProperty(RemoteDeliveryConfiguration.DELIVERY_THREADS, "1")
+            .setProperty(RemoteDeliveryConfiguration.GATEWAY_USERNAME, value)
+            .setProperty(RemoteDeliveryConfiguration.GATEWAY, "127.0.0.1")
+            .build();
+
+        assertThat(new RemoteDeliveryConfiguration(mailetConfig, mock(DomainList.class)).getAuthUser()).isEqualTo(value);
+    }
+
+    @Test
+    public void getAuthUserShouldReturnSpecifiedCompatibilityValueWhenGatewaySpecified() {
+        String value = "name";
+        FakeMailetConfig mailetConfig = FakeMailetConfig.builder()
+            .setProperty(RemoteDeliveryConfiguration.DELIVERY_THREADS, "1")
+            .setProperty(RemoteDeliveryConfiguration.GATEWAY_USERNAME_COMPATIBILITY, value)
+            .setProperty(RemoteDeliveryConfiguration.GATEWAY, "127.0.0.1")
+            .build();
+
+        assertThat(new RemoteDeliveryConfiguration(mailetConfig, mock(DomainList.class)).getAuthUser()).isEqualTo(value);
+    }
+
+    @Test
+    public void getAuthUserShouldReturnSpecifiedEmptyCompatibilityValueWhenGatewaySpecified() {
+        String value = "";
+        FakeMailetConfig mailetConfig = FakeMailetConfig.builder()
+            .setProperty(RemoteDeliveryConfiguration.DELIVERY_THREADS, "1")
+            .setProperty(RemoteDeliveryConfiguration.GATEWAY_USERNAME_COMPATIBILITY, value)
+            .setProperty(RemoteDeliveryConfiguration.GATEWAY, "127.0.0.1")
+            .build();
+
+        assertThat(new RemoteDeliveryConfiguration(mailetConfig, mock(DomainList.class)).getAuthUser()).isEqualTo(value);
+    }
+
+    @Test
+    public void getAuthUserShouldReturnSpecifiedValueWhenValueAndCompatibilitySpecified() {
+        String value = "name";
+        String compatibilityValue = "compatibilityValue";
+        FakeMailetConfig mailetConfig = FakeMailetConfig.builder()
+            .setProperty(RemoteDeliveryConfiguration.DELIVERY_THREADS, "1")
+            .setProperty(RemoteDeliveryConfiguration.GATEWAY_USERNAME, value)
+            .setProperty(RemoteDeliveryConfiguration.GATEWAY_USERNAME_COMPATIBILITY, compatibilityValue)
+            .setProperty(RemoteDeliveryConfiguration.GATEWAY, "127.0.0.1")
+            .build();
+
+        assertThat(new RemoteDeliveryConfiguration(mailetConfig, mock(DomainList.class)).getAuthUser()).isEqualTo(value);
+    }
+
+    @Test
+    public void getAuthPassShouldBeNullByDefault() {
+        FakeMailetConfig mailetConfig = FakeMailetConfig.builder()
+            .setProperty(RemoteDeliveryConfiguration.DELIVERY_THREADS, "1")
+            .build();
+
+        assertThat(new RemoteDeliveryConfiguration(mailetConfig, mock(DomainList.class)).getAuthPass()).isNull();
+    }
+
+    @Test
+    public void getAuthPassShouldBeNullWhenGatewayIsNotSpecified() {
+        FakeMailetConfig mailetConfig = FakeMailetConfig.builder()
+            .setProperty(RemoteDeliveryConfiguration.DELIVERY_THREADS, "1")
+            .setProperty(RemoteDeliveryConfiguration.GATEWAY_PASSWORD, "name")
+            .build();
+
+        assertThat(new RemoteDeliveryConfiguration(mailetConfig, mock(DomainList.class)).getAuthPass()).isNull();
+    }
+
+    @Test
+    public void getAuthPassShouldReturnSpecifiedValueWhenGatewaySpecified() {
+        String value = "name";
+        FakeMailetConfig mailetConfig = FakeMailetConfig.builder()
+            .setProperty(RemoteDeliveryConfiguration.DELIVERY_THREADS, "1")
+            .setProperty(RemoteDeliveryConfiguration.GATEWAY_PASSWORD, value)
+            .setProperty(RemoteDeliveryConfiguration.GATEWAY, "127.0.0.1")
+            .build();
+
+        assertThat(new RemoteDeliveryConfiguration(mailetConfig, mock(DomainList.class)).getAuthPass()).isEqualTo(value);
+    }
+
+    @Test
+    public void getAuthPassShouldReturnSpecifiedEmptyValueWhenGatewaySpecified() {
+        String value = "";
+        FakeMailetConfig mailetConfig = FakeMailetConfig.builder()
+            .setProperty(RemoteDeliveryConfiguration.DELIVERY_THREADS, "1")
+            .setProperty(RemoteDeliveryConfiguration.GATEWAY_PASSWORD, value)
+            .setProperty(RemoteDeliveryConfiguration.GATEWAY, "127.0.0.1")
+            .build();
+
+        assertThat(new RemoteDeliveryConfiguration(mailetConfig, mock(DomainList.class)).getAuthPass()).isEqualTo(value);
+    }
+
+    @Test
+    public void getMaxRetriesShouldReturnProvidedValue() {
+        int value = 36;
+        FakeMailetConfig mailetConfig = FakeMailetConfig.builder()
+            .setProperty(RemoteDeliveryConfiguration.DELIVERY_THREADS, "1")
+            .setProperty(RemoteDeliveryConfiguration.MAX_RETRIES, String.valueOf(value))
+            .build();
+
+        assertThat(new RemoteDeliveryConfiguration(mailetConfig, mock(DomainList.class)).getMaxRetries()).isEqualTo(value);
+    }
+
+    @Test
+    public void getMaxRetriesShouldReturnOneWhenZero() {
+        int value = 0;
+        FakeMailetConfig mailetConfig = FakeMailetConfig.builder()
+            .setProperty(RemoteDeliveryConfiguration.DELIVERY_THREADS, "1")
+            .setProperty(RemoteDeliveryConfiguration.MAX_RETRIES, String.valueOf(value))
+            .build();
+
+        assertThat(new RemoteDeliveryConfiguration(mailetConfig, mock(DomainList.class)).getMaxRetries()).isEqualTo(1);
+    }
+
+    @Test
+    public void getMaxRetriesShouldReturnOneWhenNegativeNumber() {
+        int value = -1;
+        FakeMailetConfig mailetConfig = FakeMailetConfig.builder()
+            .setProperty(RemoteDeliveryConfiguration.DELIVERY_THREADS, "1")
+            .setProperty(RemoteDeliveryConfiguration.MAX_RETRIES, String.valueOf(value))
+            .build();
+
+        assertThat(new RemoteDeliveryConfiguration(mailetConfig, mock(DomainList.class)).getMaxRetries()).isEqualTo(1);
+    }
+
+    @Test
+    public void getMaxRetriesShouldReturnDefaultWhenNoySpecified() {
+        FakeMailetConfig mailetConfig = FakeMailetConfig.builder()
+            .setProperty(RemoteDeliveryConfiguration.DELIVERY_THREADS, "1")
+            .build();
+
+        assertThat(new RemoteDeliveryConfiguration(mailetConfig, mock(DomainList.class)).getMaxRetries())
+            .isEqualTo(RemoteDeliveryConfiguration.DEFAULT_MAX_RETRY);
+    }
+
+    @Test
+    public void getDelayTimesShouldReturnDefault() {
+        FakeMailetConfig mailetConfig = FakeMailetConfig.builder()
+            .setProperty(RemoteDeliveryConfiguration.DELIVERY_THREADS, "1")
+            .build();
+
+        assertThat(new RemoteDeliveryConfiguration(mailetConfig, mock(DomainList.class)).getDelayTimes())
+            .containsOnly(Delay.DEFAULT_DELAY_TIME, Delay.DEFAULT_DELAY_TIME, Delay.DEFAULT_DELAY_TIME, Delay.DEFAULT_DELAY_TIME, Delay.DEFAULT_DELAY_TIME);
+    }
+
+    @Test
+    public void getDelayTimesShouldWorkWithDefaultConfiguration() {
+        FakeMailetConfig mailetConfig = FakeMailetConfig.builder()
+            .setProperty(RemoteDeliveryConfiguration.DELIVERY_THREADS, "1")
+            .setProperty(RemoteDeliveryConfiguration.DELAY_TIME, "5000, 100000, 500000")
+            .build();
+
+        assertThat(new RemoteDeliveryConfiguration(mailetConfig, mock(DomainList.class)).getDelayTimes())
+            .containsOnly(5000L, 100000L, 500000L);
+    }
+
+    @Test
+    public void createFinalJavaxPropertiesShouldProvidePropertiesWithMinimalConfiguration() {
+        String helo = "domain.com";
+        FakeMailetConfig mailetConfig = FakeMailetConfig.builder()
+            .setProperty(RemoteDeliveryConfiguration.DELIVERY_THREADS, "1")
+            .setProperty(RemoteDeliveryConfiguration.HELO_NAME, helo)
+            .build();
+
+        Properties properties = new RemoteDeliveryConfiguration(mailetConfig, mock(DomainList.class)).createFinalJavaxProperties();
+
+
+        assertThat(properties)
+            .containsOnly(MapEntry.entry("mail.smtp.ssl.enable", "false"),
+                MapEntry.entry("mail.smtp.sendpartial", "false"),
+                MapEntry.entry("mail.smtp.allow8bitmime", "true"),
+                MapEntry.entry("mail.smtp.ehlo", "true"),
+                MapEntry.entry("mail.smtp.connectiontimeout", "60000"),
+                MapEntry.entry("mail.smtp.localhost", helo),
+                MapEntry.entry("mail.smtp.timeout", "180000"),
+                MapEntry.entry("mail.debug", "false"),
+                MapEntry.entry("mail.smtp.starttls.enable", "false"));
+    }
+
+    @Test
+    public void createFinalJavaxPropertiesShouldProvidePropertiesWithFullConfigurationWithoutGateway() {
+        String helo = "domain.com";
+        int connectionTimeout = 1856;
+        FakeMailetConfig mailetConfig = FakeMailetConfig.builder()
+            .setProperty(RemoteDeliveryConfiguration.DELIVERY_THREADS, "1")
+            .setProperty(RemoteDeliveryConfiguration.SSL_ENABLE, "true")
+            .setProperty(RemoteDeliveryConfiguration.SENDPARTIAL, "true")
+            .setProperty(RemoteDeliveryConfiguration.CONNECTIONTIMEOUT, String.valueOf(connectionTimeout))
+            .setProperty(RemoteDeliveryConfiguration.START_TLS, "true")
+            .setProperty(RemoteDeliveryConfiguration.HELO_NAME, helo)
+            .build();
+
+        Properties properties = new RemoteDeliveryConfiguration(mailetConfig, mock(DomainList.class)).createFinalJavaxProperties();
+
+
+        assertThat(properties)
+            .containsOnly(MapEntry.entry("mail.smtp.ssl.enable", "true"),
+                MapEntry.entry("mail.smtp.sendpartial", "true"),
+                MapEntry.entry("mail.smtp.allow8bitmime", "true"),
+                MapEntry.entry("mail.smtp.ehlo", "true"),
+                MapEntry.entry("mail.smtp.connectiontimeout", String.valueOf(connectionTimeout)),
+                MapEntry.entry("mail.smtp.localhost", helo),
+                MapEntry.entry("mail.smtp.timeout", "180000"),
+                MapEntry.entry("mail.debug", "false"),
+                MapEntry.entry("mail.smtp.starttls.enable", "true"));
+    }
+
+    @Test
+    public void createFinalJavaxPropertiesShouldProvidePropertiesWithFullConfigurationWithGateway() {
+        String helo = "domain.com";
+        int connectionTimeout = 1856;
+        FakeMailetConfig mailetConfig = FakeMailetConfig.builder()
+            .setProperty(RemoteDeliveryConfiguration.DELIVERY_THREADS, "1")
+            .setProperty(RemoteDeliveryConfiguration.SSL_ENABLE, "true")
+            .setProperty(RemoteDeliveryConfiguration.SENDPARTIAL, "true")
+            .setProperty(RemoteDeliveryConfiguration.CONNECTIONTIMEOUT, String.valueOf(connectionTimeout))
+            .setProperty(RemoteDeliveryConfiguration.START_TLS, "true")
+            .setProperty(RemoteDeliveryConfiguration.HELO_NAME, helo)
+            .setProperty(RemoteDeliveryConfiguration.GATEWAY, "gateway.domain.com")
+            .setProperty(RemoteDeliveryConfiguration.GATEWAY_USERNAME, "user")
+            .setProperty(RemoteDeliveryConfiguration.GATEWAY_PASSWORD, "password")
+            .build();
+
+        Properties properties = new RemoteDeliveryConfiguration(mailetConfig, mock(DomainList.class)).createFinalJavaxProperties();
+
+
+        assertThat(properties)
+            .containsOnly(MapEntry.entry("mail.smtp.ssl.enable", "true"),
+                MapEntry.entry("mail.smtp.sendpartial", "true"),
+                MapEntry.entry("mail.smtp.allow8bitmime", "true"),
+                MapEntry.entry("mail.smtp.ehlo", "true"),
+                MapEntry.entry("mail.smtp.connectiontimeout", String.valueOf(connectionTimeout)),
+                MapEntry.entry("mail.smtp.localhost", helo),
+                MapEntry.entry("mail.smtp.timeout", "180000"),
+                MapEntry.entry("mail.debug", "false"),
+                MapEntry.entry("mail.smtp.starttls.enable", "true"),
+                MapEntry.entry("mail.smtp.auth", "true"));
+    }
+}

http://git-wip-us.apache.org/repos/asf/james-project/blob/52c18ef6/server/mailet/mailets/src/test/java/org/apache/james/transport/mailets/remote/delivery/RemoteDeliveryRunningTest.java
----------------------------------------------------------------------
diff --git a/server/mailet/mailets/src/test/java/org/apache/james/transport/mailets/remote/delivery/RemoteDeliveryRunningTest.java b/server/mailet/mailets/src/test/java/org/apache/james/transport/mailets/remote/delivery/RemoteDeliveryRunningTest.java
new file mode 100644
index 0000000..11d5f79
--- /dev/null
+++ b/server/mailet/mailets/src/test/java/org/apache/james/transport/mailets/remote/delivery/RemoteDeliveryRunningTest.java
@@ -0,0 +1,80 @@
+/****************************************************************
+ * 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.transport.mailets.remote.delivery;
+
+import static org.mockito.Mockito.mock;
+import static org.mockito.Mockito.verify;
+import static org.mockito.Mockito.when;
+
+import java.util.concurrent.CountDownLatch;
+import java.util.concurrent.TimeUnit;
+
+import org.apache.james.dnsservice.api.DNSService;
+import org.apache.james.domainlist.api.DomainList;
+import org.apache.james.metrics.api.MetricFactory;
+import org.apache.james.queue.api.MailQueue;
+import org.apache.james.queue.api.MailQueueFactory;
+import org.apache.james.transport.mailets.RemoteDelivery;
+import org.apache.mailet.base.test.FakeMailetConfig;
+import org.junit.After;
+import org.junit.Before;
+import org.junit.Test;
+
+public class RemoteDeliveryRunningTest {
+
+    public static final String QUEUE_NAME = "queueName";
+    private RemoteDelivery remoteDelivery;
+    private MailQueue mailQueue;
+    private CountDownLatch countDownLatch;
+
+    @Before
+    public void setUp() throws Exception {
+        countDownLatch = new CountDownLatch(1);
+        MailQueueFactory mailQueueFactory = mock(MailQueueFactory.class);
+        remoteDelivery = new RemoteDelivery(mock(DNSService.class), mock(DomainList.class), mailQueueFactory,
+            mock(MetricFactory.class), RemoteDelivery.ThreadState.START_THREADS);
+
+        mailQueue = mock(MailQueue.class);
+        when(mailQueueFactory.getQueue(QUEUE_NAME)).thenReturn(mailQueue);
+    }
+
+    @Test
+    public void remoteDeliveryShouldStart() throws Exception {
+        when(mailQueue.deQueue()).thenAnswer(invocation -> {
+            countDownLatch.countDown();
+            Thread.sleep(TimeUnit.SECONDS.toMillis(20));
+            return null;
+        });
+        remoteDelivery.init(FakeMailetConfig.builder()
+            .setProperty(RemoteDeliveryConfiguration.DELIVERY_THREADS, "1")
+            .setProperty(RemoteDeliveryConfiguration.OUTGOING, QUEUE_NAME)
+            .setProperty(RemoteDeliveryConfiguration.HELO_NAME, "Hello_name")
+            .build());
+
+        countDownLatch.await();
+        verify(mailQueue).deQueue();
+    }
+
+    @After
+    public void tearDown() throws InterruptedException {
+        remoteDelivery.destroy();
+    }
+
+}

http://git-wip-us.apache.org/repos/asf/james-project/blob/52c18ef6/server/mailet/mailets/src/test/java/org/apache/james/transport/mailets/remote/delivery/RemoteDeliveryTest.java
----------------------------------------------------------------------
diff --git a/server/mailet/mailets/src/test/java/org/apache/james/transport/mailets/remote/delivery/RemoteDeliveryTest.java b/server/mailet/mailets/src/test/java/org/apache/james/transport/mailets/remote/delivery/RemoteDeliveryTest.java
new file mode 100644
index 0000000..7d76ebc
--- /dev/null
+++ b/server/mailet/mailets/src/test/java/org/apache/james/transport/mailets/remote/delivery/RemoteDeliveryTest.java
@@ -0,0 +1,207 @@
+/****************************************************************
+ * 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.transport.mailets.remote.delivery;
+
+import static org.assertj.core.api.Assertions.assertThat;
+import static org.mockito.Mockito.mock;
+import static org.mockito.Mockito.when;
+
+import java.util.List;
+import java.util.concurrent.TimeUnit;
+
+import javax.mail.MessagingException;
+
+import org.apache.commons.lang.NotImplementedException;
+import org.apache.james.dnsservice.api.DNSService;
+import org.apache.james.domainlist.api.DomainList;
+import org.apache.james.metrics.api.MetricFactory;
+import org.apache.james.queue.api.MailPrioritySupport;
+import org.apache.james.queue.api.MailQueue;
+import org.apache.james.queue.api.MailQueueFactory;
+import org.apache.james.transport.mailets.RemoteDelivery;
+import org.apache.mailet.Mail;
+import org.apache.mailet.base.MailAddressFixture;
+import org.apache.mailet.base.test.FakeMail;
+import org.apache.mailet.base.test.FakeMailetConfig;
+import org.junit.Before;
+import org.junit.Test;
+
+import com.google.common.base.Throwables;
+import com.google.common.collect.ImmutableList;
+import com.google.common.collect.Lists;
+
+public class RemoteDeliveryTest {
+
+    public static final String MAIL_NAME = "mail_name";
+
+    private static class FakeMailQueue implements MailQueue {
+        private final List<Mail> enqueuedMail;
+
+        private FakeMailQueue() {
+            this.enqueuedMail = Lists.newArrayList();
+        }
+
+        @Override
+        public void enQueue(Mail mail, long delay, TimeUnit unit) throws MailQueueException {
+            enQueue(mail);
+        }
+
+        @Override
+        public void enQueue(Mail mail) throws MailQueueException {
+            try {
+                enqueuedMail.add(FakeMail.fromMail(mail));
+            } catch (MessagingException e) {
+                throw Throwables.propagate(e);
+            }
+        }
+
+        @Override
+        public MailQueueItem deQueue() throws MailQueueException, InterruptedException {
+            throw new NotImplementedException();
+        }
+
+        public List<Mail> getEnqueuedMail() {
+            return ImmutableList.copyOf(enqueuedMail);
+        }
+    }
+
+    private RemoteDelivery remoteDelivery;
+    private FakeMailQueue mailQueue;
+
+    @Before
+    public void setUp() {
+        MailQueueFactory queueFactory = mock(MailQueueFactory.class);
+        mailQueue = new FakeMailQueue();
+        when(queueFactory.getQueue(RemoteDeliveryConfiguration.OUTGOING)).thenReturn(mailQueue);
+        remoteDelivery = new RemoteDelivery(mock(DNSService.class), mock(DomainList.class), queueFactory, mock(MetricFactory.class), RemoteDelivery.ThreadState.DO_NOT_START_THREADS);
+    }
+
+    @Test
+    public void remoteDeliveryShouldAddEmailToSpool() throws Exception {
+        remoteDelivery.init(FakeMailetConfig.builder()
+            .setProperty(RemoteDeliveryConfiguration.DELIVERY_THREADS, "1")
+            .build());
+
+        Mail mail = FakeMail.builder().name(MAIL_NAME).recipients(MailAddressFixture.ANY_AT_JAMES).build();
+        remoteDelivery.service(mail);
+
+        assertThat(mailQueue.getEnqueuedMail()).containsOnly(FakeMail.builder()
+            .name(MAIL_NAME + RemoteDelivery.NAME_JUNCTION + MailAddressFixture.JAMES_APACHE_ORG)
+            .recipient(MailAddressFixture.ANY_AT_JAMES)
+            .build());
+    }
+
+    @Test
+    public void remoteDeliveryShouldSplitMailsByServerWhenNoGateway() throws Exception {
+        remoteDelivery.init(FakeMailetConfig.builder()
+            .setProperty(RemoteDeliveryConfiguration.DELIVERY_THREADS, "1")
+            .build());
+
+        Mail mail = FakeMail.builder()
+            .name(MAIL_NAME)
+            .recipients(MailAddressFixture.ANY_AT_JAMES, MailAddressFixture.ANY_AT_JAMES2, MailAddressFixture.OTHER_AT_JAMES)
+            .build();
+        remoteDelivery.service(mail);
+
+        assertThat(mailQueue.getEnqueuedMail()).containsOnly(
+            FakeMail.builder()
+                .name(MAIL_NAME + RemoteDelivery.NAME_JUNCTION + MailAddressFixture.JAMES_APACHE_ORG)
+                .recipients(MailAddressFixture.ANY_AT_JAMES, MailAddressFixture.OTHER_AT_JAMES)
+                .build(),
+            FakeMail.builder()
+                .name(MAIL_NAME + RemoteDelivery.NAME_JUNCTION + MailAddressFixture.JAMES2_APACHE_ORG)
+                .recipients(MailAddressFixture.ANY_AT_JAMES2)
+                .build());
+    }
+
+    @Test
+    public void remoteDeliveryShouldNotSplitMailsByServerWhenGateway() throws Exception {
+        remoteDelivery.init(FakeMailetConfig.builder()
+            .setProperty(RemoteDeliveryConfiguration.DELIVERY_THREADS, "1")
+            .setProperty(RemoteDeliveryConfiguration.GATEWAY, MailAddressFixture.JAMES_LOCAL)
+            .build());
+
+        Mail mail = FakeMail.builder()
+            .name(MAIL_NAME)
+            .recipients(MailAddressFixture.ANY_AT_JAMES, MailAddressFixture.ANY_AT_JAMES2, MailAddressFixture.OTHER_AT_JAMES)
+            .build();
+        remoteDelivery.service(mail);
+
+        assertThat(mailQueue.getEnqueuedMail()).containsOnly(
+            FakeMail.builder()
+                .name(MAIL_NAME)
+                .recipients(MailAddressFixture.ANY_AT_JAMES, MailAddressFixture.ANY_AT_JAMES2, MailAddressFixture.OTHER_AT_JAMES)
+                .build());
+    }
+
+    @Test
+    public void remoteDeliveryShouldGhostMails() throws Exception {
+        remoteDelivery.init(FakeMailetConfig.builder()
+            .setProperty(RemoteDeliveryConfiguration.DELIVERY_THREADS, "1")
+            .build());
+
+        Mail mail = FakeMail.builder().name(MAIL_NAME).recipients(MailAddressFixture.ANY_AT_JAMES).build();
+        remoteDelivery.service(mail);
+
+        assertThat(mail.getState()).isEqualTo(Mail.GHOST);
+    }
+
+    @Test
+    public void remoteDeliveryShouldAddPriorityIfSpecified() throws Exception {
+        remoteDelivery.init(FakeMailetConfig.builder()
+            .setProperty(RemoteDeliveryConfiguration.DELIVERY_THREADS, "1")
+            .setProperty(RemoteDeliveryConfiguration.USE_PRIORITY, "true")
+            .build());
+
+        Mail mail = FakeMail.builder().name(MAIL_NAME).recipients(MailAddressFixture.ANY_AT_JAMES).build();
+        remoteDelivery.service(mail);
+
+        assertThat(mailQueue.getEnqueuedMail()).containsOnly(FakeMail.builder()
+            .name(MAIL_NAME + RemoteDelivery.NAME_JUNCTION + MailAddressFixture.JAMES_APACHE_ORG)
+            .attribute(MailPrioritySupport.MAIL_PRIORITY, MailPrioritySupport.HIGH_PRIORITY)
+            .recipient(MailAddressFixture.ANY_AT_JAMES)
+            .build());
+    }
+
+    @Test
+    public void remoteDeliveryShouldNotForwardMailsWithNoRecipients() throws Exception {
+        remoteDelivery.init(FakeMailetConfig.builder()
+            .setProperty(RemoteDeliveryConfiguration.DELIVERY_THREADS, "1")
+            .build());
+
+        Mail mail = FakeMail.builder().name(MAIL_NAME).build();
+        remoteDelivery.service(mail);
+
+        assertThat(mailQueue.getEnqueuedMail()).isEmpty();
+    }
+
+    @Test
+    public void remoteDeliveryShouldNotForwardMailsWithNoRecipientsWithGateway() throws Exception {
+        remoteDelivery.init(FakeMailetConfig.builder()
+            .setProperty(RemoteDeliveryConfiguration.DELIVERY_THREADS, "1")
+            .setProperty(RemoteDeliveryConfiguration.GATEWAY, MailAddressFixture.JAMES_LOCAL)
+            .build());
+
+        Mail mail = FakeMail.builder().name(MAIL_NAME).build();
+        remoteDelivery.service(mail);
+
+        assertThat(mailQueue.getEnqueuedMail()).isEmpty();
+    }
+}

http://git-wip-us.apache.org/repos/asf/james-project/blob/52c18ef6/server/mailet/mailets/src/test/java/org/apache/james/transport/mailets/remote/delivery/RepeatTest.java
----------------------------------------------------------------------
diff --git a/server/mailet/mailets/src/test/java/org/apache/james/transport/mailets/remote/delivery/RepeatTest.java b/server/mailet/mailets/src/test/java/org/apache/james/transport/mailets/remote/delivery/RepeatTest.java
new file mode 100644
index 0000000..a25dd18
--- /dev/null
+++ b/server/mailet/mailets/src/test/java/org/apache/james/transport/mailets/remote/delivery/RepeatTest.java
@@ -0,0 +1,56 @@
+/****************************************************************
+ * 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.transport.mailets.remote.delivery;
+
+import static org.assertj.core.api.Assertions.assertThat;
+
+import org.junit.Rule;
+import org.junit.Test;
+import org.junit.rules.ExpectedException;
+
+public class RepeatTest {
+
+    public static final String ELEMENT = "a";
+    @Rule
+    public ExpectedException expectedException = ExpectedException.none();
+
+    @Test
+    public void repeatShouldThrowOnNegativeTimes() {
+        expectedException.expect(IllegalArgumentException.class);
+
+        Repeat.repeat(new Object(), -1);
+    }
+
+    @Test
+    public void repeatShouldReturnEmptyListOnZeroTimes() {
+        assertThat(Repeat.repeat(new Object(), 0)).isEmpty();
+    }
+
+    @Test
+    public void repeatShouldWorkWithOneElement() {
+        assertThat(Repeat.repeat(ELEMENT, 1)).containsExactly(ELEMENT);
+    }
+
+    @Test
+    public void repeatShouldWorkWithTwoElements() {
+        assertThat(Repeat.repeat(ELEMENT, 2)).containsExactly(ELEMENT, ELEMENT);
+    }
+
+}

http://git-wip-us.apache.org/repos/asf/james-project/blob/52c18ef6/server/mailet/mailets/src/test/java/org/apache/james/transport/mailets/remoteDelivery/AddressesArrayToMailAddressListConverterTest.java
----------------------------------------------------------------------
diff --git a/server/mailet/mailets/src/test/java/org/apache/james/transport/mailets/remoteDelivery/AddressesArrayToMailAddressListConverterTest.java b/server/mailet/mailets/src/test/java/org/apache/james/transport/mailets/remoteDelivery/AddressesArrayToMailAddressListConverterTest.java
deleted file mode 100644
index df7e94c..0000000
--- a/server/mailet/mailets/src/test/java/org/apache/james/transport/mailets/remoteDelivery/AddressesArrayToMailAddressListConverterTest.java
+++ /dev/null
@@ -1,66 +0,0 @@
-/****************************************************************
- * 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.transport.mailets.remoteDelivery;
-
-import static org.assertj.core.api.Assertions.assertThat;
-
-import javax.mail.Address;
-import javax.mail.internet.InternetAddress;
-
-import org.apache.mailet.base.MailAddressFixture;
-import org.junit.Test;
-
-public class AddressesArrayToMailAddressListConverterTest {
-
-    private static final String WRONG_INTERNET_ADDRESS = "!!";
-
-    @Test
-    public void getAddressesAsMailAddressShouldReturnEmptyOnNull() {
-        assertThat(AddressesArrayToMailAddressListConverter.getAddressesAsMailAddress(null)).isEmpty();
-    }
-
-    @Test
-    public void getAddressesAsMailAddressShouldReturnEmptyOnEmpty() {
-        assertThat(AddressesArrayToMailAddressListConverter.getAddressesAsMailAddress(new Address[]{})).isEmpty();
-    }
-
-    @Test
-    public void getAddressesAsMailAddressShouldWorkWithSingleValue() throws Exception {
-        assertThat(AddressesArrayToMailAddressListConverter.getAddressesAsMailAddress(new Address[]{
-            new InternetAddress(MailAddressFixture.ANY_AT_JAMES.toString())}))
-            .containsOnly(MailAddressFixture.ANY_AT_JAMES);
-    }
-
-    @Test
-    public void getAddressesAsMailAddressShouldWorkWithTwoValues() throws Exception {
-        assertThat(AddressesArrayToMailAddressListConverter.getAddressesAsMailAddress(new Address[]{
-            new InternetAddress(MailAddressFixture.ANY_AT_JAMES.toString()),
-            new InternetAddress(MailAddressFixture.OTHER_AT_JAMES.toString())}))
-            .containsOnly(MailAddressFixture.ANY_AT_JAMES, MailAddressFixture.OTHER_AT_JAMES);
-    }
-
-    @Test
-    public void getAddressesAsMailAddressShouldFilterErrorMailAddress() throws Exception {
-        assertThat(AddressesArrayToMailAddressListConverter.getAddressesAsMailAddress(new Address[]{
-            new InternetAddress(MailAddressFixture.ANY_AT_JAMES.toString()),
-            new InternetAddress(WRONG_INTERNET_ADDRESS)}))
-            .containsOnly(MailAddressFixture.ANY_AT_JAMES);
-    }
-}


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