You are viewing a plain text version of this content. The canonical link for it is here.
Posted to server-dev@james.apache.org by bt...@apache.org on 2018/06/13 02:49:15 UTC

[6/8] james-project git commit: JAMES-2413 Define route for creating mail repository in webadmin

JAMES-2413 Define route for creating mail repository in webadmin


Project: http://git-wip-us.apache.org/repos/asf/james-project/repo
Commit: http://git-wip-us.apache.org/repos/asf/james-project/commit/7488a2e0
Tree: http://git-wip-us.apache.org/repos/asf/james-project/tree/7488a2e0
Diff: http://git-wip-us.apache.org/repos/asf/james-project/diff/7488a2e0

Branch: refs/heads/master
Commit: 7488a2e0d6f817d949023291a6497dd69cde3479
Parents: addce27
Author: duc <tr...@gmail.com>
Authored: Thu Jun 7 12:52:50 2018 +0700
Committer: benwa <bt...@linagora.com>
Committed: Wed Jun 13 09:43:47 2018 +0700

----------------------------------------------------------------------
 .../james/cli/DataCommandsIntegrationTest.java  |  10 +-
 .../CassandraMailRepositoryIntegrationTest.java |   5 +-
 .../java/org/apache/james/ESReporterTest.java   |   5 +-
 .../org/apache/james/utils/DataProbeImpl.java   |  10 --
 .../org/apache/james/JPAJamesServerTest.java    |   5 +-
 .../mailrepository/api/MailRepositoryStore.java |   8 +
 .../java/org/apache/james/probe/DataProbe.java  |  27 +++
 .../crypto/SMIMEDecryptIntegrationTest.java     |   5 +-
 .../transport/mailets/ContactExtractorTest.java |  19 +-
 .../transport/mailets/SpamAssassinTest.java     |   9 +-
 .../mailets/ToSenderDomainRepositoryTest.java   |  66 ++++---
 server/mailet/mailets/pom.xml                   |   5 +
 .../mailets/ToSenderDomainRepository.java       |   9 +-
 .../mailets/ToSenderDomainRepositoryTest.java   |  20 ++-
 .../james/jmap/JMAPAuthenticationTest.java      |   5 +-
 .../org/apache/james/jmap/ProvisioningTest.java |   5 +-
 .../integration/SetVacationResponseTest.java    |   5 +-
 .../integration/SpamAssassinContract.java       |  11 +-
 .../webadmin/routes/MailRepositoriesRoutes.java |  30 +++-
 .../service/MailRepositoryStoreService.java     |   3 +
 .../routes/MailRepositoriesRoutesTest.java      |  59 +++++-
 src/site/markdown/server/manage-webadmin.md     | 180 ++++++++++---------
 22 files changed, 331 insertions(+), 170 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/james-project/blob/7488a2e0/server/container/cli-integration/src/test/java/org/apache/james/cli/DataCommandsIntegrationTest.java
----------------------------------------------------------------------
diff --git a/server/container/cli-integration/src/test/java/org/apache/james/cli/DataCommandsIntegrationTest.java b/server/container/cli-integration/src/test/java/org/apache/james/cli/DataCommandsIntegrationTest.java
index eeddbd0..7cb8fbd 100644
--- a/server/container/cli-integration/src/test/java/org/apache/james/cli/DataCommandsIntegrationTest.java
+++ b/server/container/cli-integration/src/test/java/org/apache/james/cli/DataCommandsIntegrationTest.java
@@ -109,8 +109,9 @@ public class DataCommandsIntegrationTest {
 
     @Test
     public void removeUserShouldWork() throws Exception {
-        dataProbe.fluentAddDomain(DOMAIN)
-            .fluentAddUser(MAIL_ADDRESS, PASSWORD);
+        dataProbe.fluent()
+            .addDomain(DOMAIN)
+            .addUser(MAIL_ADDRESS, PASSWORD);
 
         ServerCmd.doMain(new String[] {"-h", "127.0.0.1", "-p", "9999", "REMOVEUSER", MAIL_ADDRESS});
 
@@ -119,8 +120,9 @@ public class DataCommandsIntegrationTest {
 
     @Test
     public void listUsersShouldWork() throws Exception {
-        dataProbe.fluentAddDomain(DOMAIN)
-            .fluentAddUser(MAIL_ADDRESS, PASSWORD);
+        dataProbe.fluent()
+            .addDomain(DOMAIN)
+            .addUser(MAIL_ADDRESS, PASSWORD);
 
         ServerCmd.executeAndOutputToStream(new String[] {"-h", "127.0.0.1", "-p", "9999", "listusers"}, outputCapture.getPrintStream());
 

http://git-wip-us.apache.org/repos/asf/james-project/blob/7488a2e0/server/container/guice/cassandra-guice/src/test/java/org/apache/james/CassandraMailRepositoryIntegrationTest.java
----------------------------------------------------------------------
diff --git a/server/container/guice/cassandra-guice/src/test/java/org/apache/james/CassandraMailRepositoryIntegrationTest.java b/server/container/guice/cassandra-guice/src/test/java/org/apache/james/CassandraMailRepositoryIntegrationTest.java
index 836e27d..e694ec9 100644
--- a/server/container/guice/cassandra-guice/src/test/java/org/apache/james/CassandraMailRepositoryIntegrationTest.java
+++ b/server/container/guice/cassandra-guice/src/test/java/org/apache/james/CassandraMailRepositoryIntegrationTest.java
@@ -66,8 +66,9 @@ public class CassandraMailRepositoryIntegrationTest {
     @Test
     public void deniedSenderMailShouldBeStoredInCassandraMailRepositoryWhenConfigured() throws Exception {
         server.getProbe(DataProbeImpl.class)
-            .fluentAddDomain("domain.com")
-            .fluentAddUser("user@domain.com", "secret");
+            .fluent()
+            .addDomain("domain.com")
+            .addUser("user@domain.com", "secret");
 
         smtpMessageSender.connect("127.0.0.1", 1025)
             .sendMessage("denied@other.com", "user@domain.com");

http://git-wip-us.apache.org/repos/asf/james-project/blob/7488a2e0/server/container/guice/cassandra-guice/src/test/java/org/apache/james/ESReporterTest.java
----------------------------------------------------------------------
diff --git a/server/container/guice/cassandra-guice/src/test/java/org/apache/james/ESReporterTest.java b/server/container/guice/cassandra-guice/src/test/java/org/apache/james/ESReporterTest.java
index 148c42c..b0f555e 100644
--- a/server/container/guice/cassandra-guice/src/test/java/org/apache/james/ESReporterTest.java
+++ b/server/container/guice/cassandra-guice/src/test/java/org/apache/james/ESReporterTest.java
@@ -78,8 +78,9 @@ public class ESReporterTest {
         server = cassandraJmap.jmapServer();
         server.start();
         server.getProbe(DataProbeImpl.class)
-            .fluentAddDomain(DOMAIN)
-            .fluentAddUser(USERNAME, PASSWORD);
+            .fluent()
+            .addDomain(DOMAIN)
+            .addUser(USERNAME, PASSWORD);
 
         RestAssured.requestSpecification = new RequestSpecBuilder()
                 .setContentType(ContentType.JSON)

http://git-wip-us.apache.org/repos/asf/james-project/blob/7488a2e0/server/container/guice/guice-common/src/main/java/org/apache/james/utils/DataProbeImpl.java
----------------------------------------------------------------------
diff --git a/server/container/guice/guice-common/src/main/java/org/apache/james/utils/DataProbeImpl.java b/server/container/guice/guice-common/src/main/java/org/apache/james/utils/DataProbeImpl.java
index f016129..314ec07 100644
--- a/server/container/guice/guice-common/src/main/java/org/apache/james/utils/DataProbeImpl.java
+++ b/server/container/guice/guice-common/src/main/java/org/apache/james/utils/DataProbeImpl.java
@@ -58,11 +58,6 @@ public class DataProbeImpl implements GuiceProbe, DataProbe {
         usersRepository.addUser(userName, password);
     }
 
-    public DataProbeImpl fluentAddUser(String userName, String password) throws Exception {
-        addUser(userName, password);
-        return this;
-    }
-
     @Override
     public void removeUser(String username) throws Exception {
         usersRepository.removeUser(username);
@@ -83,11 +78,6 @@ public class DataProbeImpl implements GuiceProbe, DataProbe {
         domainList.addDomain(Domain.of(domain));
     }
 
-    public DataProbeImpl fluentAddDomain(String domain) throws Exception {
-        addDomain(domain);
-        return this;
-    }
-
     @Override
     public boolean containsDomain(String domain) throws Exception {
         return domainList.containsDomain(Domain.of(domain));

http://git-wip-us.apache.org/repos/asf/james-project/blob/7488a2e0/server/container/guice/jpa-guice/src/test/java/org/apache/james/JPAJamesServerTest.java
----------------------------------------------------------------------
diff --git a/server/container/guice/jpa-guice/src/test/java/org/apache/james/JPAJamesServerTest.java b/server/container/guice/jpa-guice/src/test/java/org/apache/james/JPAJamesServerTest.java
index e07727b..d99192a 100644
--- a/server/container/guice/jpa-guice/src/test/java/org/apache/james/JPAJamesServerTest.java
+++ b/server/container/guice/jpa-guice/src/test/java/org/apache/james/JPAJamesServerTest.java
@@ -78,8 +78,9 @@ public class JPAJamesServerTest extends AbstractJamesServerTest {
     @Test
     public void jpaGuiceServerShouldUpdateQuota() throws Exception {
         server.getProbe(DataProbeImpl.class)
-            .fluentAddDomain(DOMAIN)
-            .fluentAddUser(USER, PASSWORD);
+            .fluent()
+            .addDomain(DOMAIN)
+            .addUser(USER, PASSWORD);
         server.getProbe(QuotaProbesImpl.class).setGlobalMaxStorage(new SerializableQuotaValue<>(QuotaSize.size(50 * 1024)));
 
         // ~ 12 KB email

http://git-wip-us.apache.org/repos/asf/james-project/blob/7488a2e0/server/data/data-api/src/main/java/org/apache/james/mailrepository/api/MailRepositoryStore.java
----------------------------------------------------------------------
diff --git a/server/data/data-api/src/main/java/org/apache/james/mailrepository/api/MailRepositoryStore.java b/server/data/data-api/src/main/java/org/apache/james/mailrepository/api/MailRepositoryStore.java
index a454767..37f1902 100644
--- a/server/data/data-api/src/main/java/org/apache/james/mailrepository/api/MailRepositoryStore.java
+++ b/server/data/data-api/src/main/java/org/apache/james/mailrepository/api/MailRepositoryStore.java
@@ -34,6 +34,14 @@ public interface MailRepositoryStore {
     MailRepository select(String url) throws MailRepositoryStoreException;
 
     /**
+     * Create the {@link MailRepository} for the given url and return it. If the repository already exists,
+     * then no new repository is created, the old one will be returned.
+     */
+    default MailRepository create(String url) throws MailRepositoryStoreException {
+        return select(url);
+    }
+
+    /**
      * Returns the {@link MailRepository} for the given url.
      * This mail repository will not be created if it does not exist.
      */

http://git-wip-us.apache.org/repos/asf/james-project/blob/7488a2e0/server/data/data-api/src/main/java/org/apache/james/probe/DataProbe.java
----------------------------------------------------------------------
diff --git a/server/data/data-api/src/main/java/org/apache/james/probe/DataProbe.java b/server/data/data-api/src/main/java/org/apache/james/probe/DataProbe.java
index e85c06c..6832fcd 100644
--- a/server/data/data-api/src/main/java/org/apache/james/probe/DataProbe.java
+++ b/server/data/data-api/src/main/java/org/apache/james/probe/DataProbe.java
@@ -26,6 +26,33 @@ import org.apache.james.rrt.lib.Mappings;
 
 public interface DataProbe {
 
+    class FluentDataProbe {
+
+        private final DataProbe dataProbe;
+
+        private FluentDataProbe(DataProbe dataProbe) {
+            this.dataProbe = dataProbe;
+        }
+
+        public DataProbe getDataProbe() {
+            return dataProbe;
+        }
+
+        public FluentDataProbe addUser(String userName, String password) throws Exception {
+            dataProbe.addUser(userName, password);
+            return this;
+        }
+
+        public FluentDataProbe addDomain(String domain) throws Exception {
+            dataProbe.addDomain(domain);
+            return this;
+        }
+    }
+
+    default FluentDataProbe fluent() {
+        return new FluentDataProbe(this);
+    }
+
     void addUser(String userName, String password) throws Exception;
 
     void removeUser(String username) throws Exception;

http://git-wip-us.apache.org/repos/asf/james-project/blob/7488a2e0/server/mailet/integration-testing/src/test/java/org/apache/james/mailets/crypto/SMIMEDecryptIntegrationTest.java
----------------------------------------------------------------------
diff --git a/server/mailet/integration-testing/src/test/java/org/apache/james/mailets/crypto/SMIMEDecryptIntegrationTest.java b/server/mailet/integration-testing/src/test/java/org/apache/james/mailets/crypto/SMIMEDecryptIntegrationTest.java
index ba91794..0e9b4a6 100644
--- a/server/mailet/integration-testing/src/test/java/org/apache/james/mailets/crypto/SMIMEDecryptIntegrationTest.java
+++ b/server/mailet/integration-testing/src/test/java/org/apache/james/mailets/crypto/SMIMEDecryptIntegrationTest.java
@@ -85,8 +85,9 @@ public class SMIMEDecryptIntegrationTest {
             .build(temporaryFolder);
 
         jamesServer.getProbe(DataProbeImpl.class)
-            .fluentAddDomain(DEFAULT_DOMAIN)
-            .fluentAddUser(FROM, PASSWORD);
+            .fluent()
+            .addDomain(DEFAULT_DOMAIN)
+            .addUser(FROM, PASSWORD);
     }
 
     @After

http://git-wip-us.apache.org/repos/asf/james-project/blob/7488a2e0/server/mailet/integration-testing/src/test/java/org/apache/james/transport/mailets/ContactExtractorTest.java
----------------------------------------------------------------------
diff --git a/server/mailet/integration-testing/src/test/java/org/apache/james/transport/mailets/ContactExtractorTest.java b/server/mailet/integration-testing/src/test/java/org/apache/james/transport/mailets/ContactExtractorTest.java
index c29535f..e16b948 100644
--- a/server/mailet/integration-testing/src/test/java/org/apache/james/transport/mailets/ContactExtractorTest.java
+++ b/server/mailet/integration-testing/src/test/java/org/apache/james/transport/mailets/ContactExtractorTest.java
@@ -100,15 +100,16 @@ public class ContactExtractorTest {
             .withMailetContainer(mailets)
             .build(folder);
 
-        DataProbeImpl probe = jamesServer.getProbe(DataProbeImpl.class);
-        probe.fluentAddDomain(DEFAULT_DOMAIN)
-            .fluentAddUser(SENDER, PASSWORD)
-            .fluentAddUser(TO, PASSWORD)
-            .fluentAddUser(TO2, PASSWORD)
-            .fluentAddUser(CC, PASSWORD)
-            .fluentAddUser(CC2, PASSWORD)
-            .fluentAddUser(BCC, PASSWORD)
-            .fluentAddUser(BCC2, PASSWORD);
+        jamesServer.getProbe(DataProbeImpl.class)
+            .fluent()
+            .addDomain(DEFAULT_DOMAIN)
+            .addUser(SENDER, PASSWORD)
+            .addUser(TO, PASSWORD)
+            .addUser(TO2, PASSWORD)
+            .addUser(CC, PASSWORD)
+            .addUser(CC2, PASSWORD)
+            .addUser(BCC, PASSWORD)
+            .addUser(BCC2, PASSWORD);
     }
 
     @After

http://git-wip-us.apache.org/repos/asf/james-project/blob/7488a2e0/server/mailet/integration-testing/src/test/java/org/apache/james/transport/mailets/SpamAssassinTest.java
----------------------------------------------------------------------
diff --git a/server/mailet/integration-testing/src/test/java/org/apache/james/transport/mailets/SpamAssassinTest.java b/server/mailet/integration-testing/src/test/java/org/apache/james/transport/mailets/SpamAssassinTest.java
index 3c56362..cad6813 100644
--- a/server/mailet/integration-testing/src/test/java/org/apache/james/transport/mailets/SpamAssassinTest.java
+++ b/server/mailet/integration-testing/src/test/java/org/apache/james/transport/mailets/SpamAssassinTest.java
@@ -87,10 +87,11 @@ public class SpamAssassinTest {
             .build(temporaryFolder);
 
         jamesServer.getProbe(DataProbeImpl.class)
-            .fluentAddDomain(DEFAULT_DOMAIN)
-            .fluentAddUser(FROM, PASSWORD)
-            .fluentAddUser(RECIPIENT, PASSWORD)
-            .fluentAddUser(RECIPIENT2, PASSWORD);
+            .fluent()
+            .addDomain(DEFAULT_DOMAIN)
+            .addUser(FROM, PASSWORD)
+            .addUser(RECIPIENT, PASSWORD)
+            .addUser(RECIPIENT2, PASSWORD);
     }
 
     @After

http://git-wip-us.apache.org/repos/asf/james-project/blob/7488a2e0/server/mailet/integration-testing/src/test/java/org/apache/james/transport/mailets/ToSenderDomainRepositoryTest.java
----------------------------------------------------------------------
diff --git a/server/mailet/integration-testing/src/test/java/org/apache/james/transport/mailets/ToSenderDomainRepositoryTest.java b/server/mailet/integration-testing/src/test/java/org/apache/james/transport/mailets/ToSenderDomainRepositoryTest.java
index b811e8f..467f3d3 100644
--- a/server/mailet/integration-testing/src/test/java/org/apache/james/transport/mailets/ToSenderDomainRepositoryTest.java
+++ b/server/mailet/integration-testing/src/test/java/org/apache/james/transport/mailets/ToSenderDomainRepositoryTest.java
@@ -64,62 +64,71 @@ public class ToSenderDomainRepositoryTest {
 
     @Test
     public void incomingMailShouldBeStoredInCorrespondingMailRepository() throws Exception {
-        initializeJamesServer(TemporaryJamesServer.SIMPLE_MAILET_CONTAINER_CONFIGURATION
+        startJamesServerWithMailetContainer(TemporaryJamesServer.SIMPLE_MAILET_CONTAINER_CONFIGURATION
             .putProcessor(ProcessorConfiguration.root()
                 .addMailet(MailetConfiguration.builder()
                     .matcher(All.class)
                     .mailet(ToSenderDomainRepository.class)
                     .addProperty("urlPrefix", CUSTOM_REPOSITORY_PREFIX))));
+        MailRepositoryProbeImpl probe = jamesServer.getProbe(MailRepositoryProbeImpl.class);
 
         messageSender.connect(LOCALHOST_IP, SMTP_PORT)
             .sendMessage(RECIPIENT, RECIPIENT);
 
         awaitAtMostOneMinute.until(
-            () -> jamesServer.getProbe(MailRepositoryProbeImpl.class)
-                .getRepositoryMailCount(CUSTOM_REPOSITORY_PREFIX + DEFAULT_DOMAIN) == 1);
+            () -> probe.getRepositoryMailCount(CUSTOM_REPOSITORY_PREFIX + DEFAULT_DOMAIN) == 1);
+
+        assertThat(probe.getRepositoryMailCount(CUSTOM_REPOSITORY_PREFIX + DEFAULT_DOMAIN))
+            .isEqualTo(1);
     }
 
     @Test
-    public void incomingMailShouldBeStoredWhenRepositoryDoNotExistAndAllowedToCreateRepository() throws Exception {
-        initializeJamesServer(TemporaryJamesServer.SIMPLE_MAILET_CONTAINER_CONFIGURATION
+    public void incomingMailShouldBeStoredWhenRepositoryDoesNotExistAndAllowedToCreateRepository() throws Exception {
+        startJamesServerWithMailetContainer(TemporaryJamesServer.SIMPLE_MAILET_CONTAINER_CONFIGURATION
             .putProcessor(ProcessorConfiguration.root()
                 .addMailet(MailetConfiguration.builder()
                     .matcher(All.class)
                     .mailet(ToSenderDomainRepository.class)
                     .addProperty("urlPrefix", CUSTOM_REPOSITORY_PREFIX)
                     .addProperty("allowRepositoryCreation", "true"))));
+        MailRepositoryProbeImpl probe = jamesServer.getProbe(MailRepositoryProbeImpl.class);
 
         messageSender.connect(LOCALHOST_IP, SMTP_PORT)
             .sendMessage(RECIPIENT, RECIPIENT);
 
         awaitAtMostOneMinute.until(
-            () -> jamesServer.getProbe(MailRepositoryProbeImpl.class)
-                .getRepositoryMailCount(CUSTOM_REPOSITORY_PREFIX + DEFAULT_DOMAIN) == 1);
+            () -> probe.getRepositoryMailCount(CUSTOM_REPOSITORY_PREFIX + DEFAULT_DOMAIN) == 1);
+
+        assertThat(probe.getRepositoryMailCount(CUSTOM_REPOSITORY_PREFIX + DEFAULT_DOMAIN))
+            .isEqualTo(1);
     }
 
     @Test
     public void incomingMailShouldBeStoredWhenRepositoryExistsAndAllowedToCreateRepository() throws Exception {
-        initializeJamesServer(TemporaryJamesServer.SIMPLE_MAILET_CONTAINER_CONFIGURATION
+        startJamesServerWithMailetContainer(TemporaryJamesServer.SIMPLE_MAILET_CONTAINER_CONFIGURATION
             .putProcessor(ProcessorConfiguration.root()
                 .addMailet(MailetConfiguration.builder()
                     .matcher(All.class)
                     .mailet(ToSenderDomainRepository.class)
                     .addProperty("urlPrefix", CUSTOM_REPOSITORY_PREFIX)
                     .addProperty("allowRepositoryCreation", "true"))));
-        jamesServer.getProbe(MailRepositoryProbeImpl.class)
-            .createRepository(CUSTOM_REPOSITORY_PREFIX + DEFAULT_DOMAIN);
+        MailRepositoryProbeImpl probe = jamesServer.getProbe(MailRepositoryProbeImpl.class);
+
+        probe.createRepository(CUSTOM_REPOSITORY_PREFIX + DEFAULT_DOMAIN);
 
         messageSender.connect(LOCALHOST_IP, SMTP_PORT)
             .sendMessage(RECIPIENT, RECIPIENT);
 
         awaitAtMostOneMinute.until(
-            () -> jamesServer.getProbe(MailRepositoryProbeImpl.class)
-                .getRepositoryMailCount(CUSTOM_REPOSITORY_PREFIX + DEFAULT_DOMAIN) == 1);
+            () -> probe.getRepositoryMailCount(CUSTOM_REPOSITORY_PREFIX + DEFAULT_DOMAIN) == 1);
+
+        assertThat(probe.getRepositoryMailCount(CUSTOM_REPOSITORY_PREFIX + DEFAULT_DOMAIN))
+            .isEqualTo(1);
     }
 
     @Test
-    public void incomingMailShouldBeIgnoredWhenRepositoryDoNotExistAndNotAllowedToCreateRepository() throws Exception {
-        initializeJamesServer(TemporaryJamesServer.SIMPLE_MAILET_CONTAINER_CONFIGURATION
+    public void incomingMailShouldBeIgnoredWhenRepositoryDoesNotExistAndNotAllowedToCreateRepository() throws Exception {
+        startJamesServerWithMailetContainer(TemporaryJamesServer.SIMPLE_MAILET_CONTAINER_CONFIGURATION
             .putProcessor(ProcessorConfiguration.root()
                 .addMailet(MailetConfiguration.builder()
                     .matcher(All.class)
@@ -145,49 +154,56 @@ public class ToSenderDomainRepositoryTest {
 
     @Test
     public void incomingMailShouldBeStoredWhenRepositoryExistsAndNotAllowedToCreateRepository() throws Exception {
-        initializeJamesServer(TemporaryJamesServer.SIMPLE_MAILET_CONTAINER_CONFIGURATION
+        startJamesServerWithMailetContainer(TemporaryJamesServer.SIMPLE_MAILET_CONTAINER_CONFIGURATION
             .putProcessor(ProcessorConfiguration.root()
                 .addMailet(MailetConfiguration.builder()
                     .matcher(All.class)
                     .mailet(ToSenderDomainRepository.class)
                     .addProperty("urlPrefix", CUSTOM_REPOSITORY_PREFIX)
                     .addProperty("allowRepositoryCreation", "false"))));
-        jamesServer.getProbe(MailRepositoryProbeImpl.class)
-            .createRepository(CUSTOM_REPOSITORY_PREFIX + DEFAULT_DOMAIN);
+        MailRepositoryProbeImpl probe = jamesServer.getProbe(MailRepositoryProbeImpl.class);
+
+        probe.createRepository(CUSTOM_REPOSITORY_PREFIX + DEFAULT_DOMAIN);
 
         messageSender.connect(LOCALHOST_IP, SMTP_PORT)
             .sendMessage(RECIPIENT, RECIPIENT);
 
         awaitAtMostOneMinute.until(
-            () -> jamesServer.getProbe(MailRepositoryProbeImpl.class)
-                .getRepositoryMailCount(CUSTOM_REPOSITORY_PREFIX + DEFAULT_DOMAIN) == 1);
+            () -> probe.getRepositoryMailCount(CUSTOM_REPOSITORY_PREFIX + DEFAULT_DOMAIN) == 1);
+
+        assertThat(probe.getRepositoryMailCount(CUSTOM_REPOSITORY_PREFIX + DEFAULT_DOMAIN))
+            .isEqualTo(1);
     }
 
     @Test
     public void incomingMailsShouldBeStoredInCorrespondingMailRepository() throws Exception {
-        initializeJamesServer(TemporaryJamesServer.SIMPLE_MAILET_CONTAINER_CONFIGURATION
+        startJamesServerWithMailetContainer(TemporaryJamesServer.SIMPLE_MAILET_CONTAINER_CONFIGURATION
             .putProcessor(ProcessorConfiguration.root()
                 .addMailet(MailetConfiguration.builder()
                     .matcher(All.class)
                     .mailet(ToSenderDomainRepository.class)
                     .addProperty("urlPrefix", CUSTOM_REPOSITORY_PREFIX))));
+        MailRepositoryProbeImpl probe = jamesServer.getProbe(MailRepositoryProbeImpl.class);
 
         messageSender.connect(LOCALHOST_IP, SMTP_PORT)
             .sendMessage(RECIPIENT, RECIPIENT)
             .sendMessage(RECIPIENT, RECIPIENT);
 
         awaitAtMostOneMinute.until(
-            () -> jamesServer.getProbe(MailRepositoryProbeImpl.class)
-                .getRepositoryMailCount(CUSTOM_REPOSITORY_PREFIX + DEFAULT_DOMAIN) == 2);
+            () -> probe.getRepositoryMailCount(CUSTOM_REPOSITORY_PREFIX + DEFAULT_DOMAIN) == 2);
+
+        assertThat(probe.getRepositoryMailCount(CUSTOM_REPOSITORY_PREFIX + DEFAULT_DOMAIN))
+            .isEqualTo(2);
     }
 
-    private void initializeJamesServer(MailetContainer.Builder mailetContainer) throws Exception {
+    private void startJamesServerWithMailetContainer(MailetContainer.Builder mailetContainer) throws Exception {
         jamesServer = TemporaryJamesServer.builder()
             .withMailetContainer(mailetContainer)
             .build(temporaryFolder);
 
         jamesServer.getProbe(DataProbeImpl.class)
-            .fluentAddDomain(DEFAULT_DOMAIN)
-            .fluentAddUser(RECIPIENT, PASSWORD);
+            .fluent()
+            .addDomain(DEFAULT_DOMAIN)
+            .addUser(RECIPIENT, PASSWORD);
     }
 }

http://git-wip-us.apache.org/repos/asf/james-project/blob/7488a2e0/server/mailet/mailets/pom.xml
----------------------------------------------------------------------
diff --git a/server/mailet/mailets/pom.xml b/server/mailet/mailets/pom.xml
index eb72017..687df0e 100644
--- a/server/mailet/mailets/pom.xml
+++ b/server/mailet/mailets/pom.xml
@@ -236,6 +236,11 @@
             <scope>test</scope>
         </dependency>
         <dependency>
+            <groupId>org.hamcrest</groupId>
+            <artifactId>java-hamcrest</artifactId>
+            <scope>test</scope>
+        </dependency>
+        <dependency>
             <groupId>org.junit.jupiter</groupId>
             <artifactId>junit-jupiter-engine</artifactId>
             <scope>test</scope>

http://git-wip-us.apache.org/repos/asf/james-project/blob/7488a2e0/server/mailet/mailets/src/main/java/org/apache/james/transport/mailets/ToSenderDomainRepository.java
----------------------------------------------------------------------
diff --git a/server/mailet/mailets/src/main/java/org/apache/james/transport/mailets/ToSenderDomainRepository.java b/server/mailet/mailets/src/main/java/org/apache/james/transport/mailets/ToSenderDomainRepository.java
index 8f417c6..f86becc 100644
--- a/server/mailet/mailets/src/main/java/org/apache/james/transport/mailets/ToSenderDomainRepository.java
+++ b/server/mailet/mailets/src/main/java/org/apache/james/transport/mailets/ToSenderDomainRepository.java
@@ -46,7 +46,10 @@ import com.github.fge.lambdas.consumers.ThrowingConsumer;
  *  - "allowRepositoryCreation" optional, defaults to true. If true, non existing repository will be created. In case of
  *  misconfiguration, this might lead to arbitrary repository creation. If false, the incoming mails will be stored only
  *  in already existing repository. If not existing, the email will be dropped with an appropriate log warning (leading
- *  to potential data loss).
+ *  to potential data loss). In case, you want to create a repository manually, make a http PUT request to
+ *  /mailRepositories/encodedUrlOfTheRepository from web admin api.
+ *  For example http://ip:port/mailRepositories/file%3A%2F%2FmailRepo
+ *  @see <a href="https://james.apache.org/server/manage-webadmin.html">Create a mail repository</a>
  *
  *  Example:
  *
@@ -82,8 +85,8 @@ public class ToSenderDomainRepository extends GenericMailet {
 
     @Override
     public void service(Mail mail) throws MessagingException {
-        String url = urlPrefix + mail.getSender().getDomain().asString();
-        store(mail, url);
+        String repositoryUrl = urlPrefix + mail.getSender().getDomain().asString();
+        store(mail, repositoryUrl);
         if (!passThrough) {
             mail.setState(Mail.GHOST);
         }

http://git-wip-us.apache.org/repos/asf/james-project/blob/7488a2e0/server/mailet/mailets/src/test/java/org/apache/james/transport/mailets/ToSenderDomainRepositoryTest.java
----------------------------------------------------------------------
diff --git a/server/mailet/mailets/src/test/java/org/apache/james/transport/mailets/ToSenderDomainRepositoryTest.java b/server/mailet/mailets/src/test/java/org/apache/james/transport/mailets/ToSenderDomainRepositoryTest.java
index e532e90..b69807a 100644
--- a/server/mailet/mailets/src/test/java/org/apache/james/transport/mailets/ToSenderDomainRepositoryTest.java
+++ b/server/mailet/mailets/src/test/java/org/apache/james/transport/mailets/ToSenderDomainRepositoryTest.java
@@ -21,6 +21,7 @@ package org.apache.james.transport.mailets;
 
 import static org.apache.mailet.base.MailAddressFixture.JAMES_LOCAL;
 import static org.assertj.core.api.Assertions.assertThat;
+import static org.assertj.core.api.Assertions.assertThatCode;
 import static org.assertj.core.api.Assertions.assertThatThrownBy;
 import static org.mockito.Matchers.any;
 import static org.mockito.Mockito.mock;
@@ -41,9 +42,10 @@ import org.junit.jupiter.api.Test;
 
 class ToSenderDomainRepositoryTest {
 
+    private static final String MEMORY_URL_PREFIX = "memory://var/mail/dlp/";
     private static final FakeMailetConfig DEFAULT_MAILET_CONFIG = FakeMailetConfig.builder()
         .mailetName("TestConfig")
-        .setProperty("urlPrefix", "memory://var/mail/dlp/")
+        .setProperty("urlPrefix", MEMORY_URL_PREFIX)
         .build();
     private ToSenderDomainRepository mailet;
     private MockMailRepositoryStore mailRepositoryStore;
@@ -51,7 +53,7 @@ class ToSenderDomainRepositoryTest {
     @BeforeEach
     void setup() {
         mailRepositoryStore = new MockMailRepositoryStore();
-        mailRepositoryStore.add("memory://var/mail/dlp/" + JAMES_LOCAL, new MemoryMailRepository());
+        mailRepositoryStore.add(MEMORY_URL_PREFIX + JAMES_LOCAL, new MemoryMailRepository());
         mailet = new ToSenderDomainRepository(mailRepositoryStore);
     }
 
@@ -66,8 +68,10 @@ class ToSenderDomainRepositoryTest {
     }
 
     @Test
-    void initShouldNotThrowWhenUrlPrefixIsPresent() throws MessagingException {
-        mailet.init(DEFAULT_MAILET_CONFIG);
+    void initShouldNotThrowWhenUrlPrefixIsPresent() {
+        assertThatCode(
+            () -> mailet.init(DEFAULT_MAILET_CONFIG))
+            .doesNotThrowAnyException();
     }
 
     @Test
@@ -80,7 +84,7 @@ class ToSenderDomainRepositoryTest {
             .sender(MailAddressFixture.SENDER)
             .build());
 
-        MailRepository mailRepository = mailRepositoryStore.select("memory://var/mail/dlp/" + JAMES_LOCAL);
+        MailRepository mailRepository = mailRepositoryStore.select(MEMORY_URL_PREFIX + JAMES_LOCAL);
 
         assertThat(mailRepository.list())
             .extracting(mailRepository::retrieve)
@@ -93,7 +97,7 @@ class ToSenderDomainRepositoryTest {
         FakeMailetConfig mailetConfig = FakeMailetConfig.builder()
             .mailetName("TestConfig")
             .setProperty("passThrough", "false")
-            .setProperty("urlPrefix", "memory://var/mail/dlp/")
+            .setProperty("urlPrefix", MEMORY_URL_PREFIX)
             .build();
         mailet.init(mailetConfig);
 
@@ -114,7 +118,7 @@ class ToSenderDomainRepositoryTest {
         FakeMailetConfig mailetConfig = FakeMailetConfig.builder()
             .mailetName("TestConfig")
             .setProperty("passThrough", "true")
-            .setProperty("urlPrefix", "memory://var/mail/dlp/")
+            .setProperty("urlPrefix", MEMORY_URL_PREFIX)
             .build();
         mailet.init(mailetConfig);
 
@@ -169,7 +173,7 @@ class ToSenderDomainRepositoryTest {
     void initShouldSetNotPassThroughWhenPassThroughIsNotBoolean() throws Exception {
         FakeMailetConfig mailetConfig = FakeMailetConfig.builder()
             .mailetName("TestConfig")
-            .setProperty("urlPrefix", "memory://var/mail/dlp/")
+            .setProperty("urlPrefix", MEMORY_URL_PREFIX)
             .setProperty("passThrough", "not boolean")
             .build();
 

http://git-wip-us.apache.org/repos/asf/james-project/blob/7488a2e0/server/protocols/jmap-integration-testing/jmap-integration-testing-common/src/test/java/org/apache/james/jmap/JMAPAuthenticationTest.java
----------------------------------------------------------------------
diff --git a/server/protocols/jmap-integration-testing/jmap-integration-testing-common/src/test/java/org/apache/james/jmap/JMAPAuthenticationTest.java b/server/protocols/jmap-integration-testing/jmap-integration-testing-common/src/test/java/org/apache/james/jmap/JMAPAuthenticationTest.java
index eae6a4c..1f3492e 100644
--- a/server/protocols/jmap-integration-testing/jmap-integration-testing-common/src/test/java/org/apache/james/jmap/JMAPAuthenticationTest.java
+++ b/server/protocols/jmap-integration-testing/jmap-integration-testing-common/src/test/java/org/apache/james/jmap/JMAPAuthenticationTest.java
@@ -73,8 +73,9 @@ public abstract class JMAPAuthenticationTest {
         
         String domain = "domain.tld";
         jmapServer.getProbe(DataProbeImpl.class)
-            .fluentAddDomain(domain)
-            .fluentAddUser(userCredentials.getUsername(), userCredentials.getPassword());
+            .fluent()
+            .addDomain(domain)
+            .addUser(userCredentials.getUsername(), userCredentials.getPassword());
         
     }
     

http://git-wip-us.apache.org/repos/asf/james-project/blob/7488a2e0/server/protocols/jmap-integration-testing/jmap-integration-testing-common/src/test/java/org/apache/james/jmap/ProvisioningTest.java
----------------------------------------------------------------------
diff --git a/server/protocols/jmap-integration-testing/jmap-integration-testing-common/src/test/java/org/apache/james/jmap/ProvisioningTest.java b/server/protocols/jmap-integration-testing/jmap-integration-testing-common/src/test/java/org/apache/james/jmap/ProvisioningTest.java
index fcb02b5..e5d49a5 100644
--- a/server/protocols/jmap-integration-testing/jmap-integration-testing-common/src/test/java/org/apache/james/jmap/ProvisioningTest.java
+++ b/server/protocols/jmap-integration-testing/jmap-integration-testing-common/src/test/java/org/apache/james/jmap/ProvisioningTest.java
@@ -64,8 +64,9 @@ public abstract class ProvisioningTest {
             .build();
 
         jmapServer.getProbe(DataProbeImpl.class)
-            .fluentAddDomain(DOMAIN)
-            .fluentAddUser(USER, PASSWORD);
+            .fluent()
+            .addDomain(DOMAIN)
+            .addUser(USER, PASSWORD);
     }
 
     @After

http://git-wip-us.apache.org/repos/asf/james-project/blob/7488a2e0/server/protocols/jmap-integration-testing/jmap-integration-testing-common/src/test/java/org/apache/james/jmap/methods/integration/SetVacationResponseTest.java
----------------------------------------------------------------------
diff --git a/server/protocols/jmap-integration-testing/jmap-integration-testing-common/src/test/java/org/apache/james/jmap/methods/integration/SetVacationResponseTest.java b/server/protocols/jmap-integration-testing/jmap-integration-testing-common/src/test/java/org/apache/james/jmap/methods/integration/SetVacationResponseTest.java
index f86015c..d5f4257 100644
--- a/server/protocols/jmap-integration-testing/jmap-integration-testing-common/src/test/java/org/apache/james/jmap/methods/integration/SetVacationResponseTest.java
+++ b/server/protocols/jmap-integration-testing/jmap-integration-testing-common/src/test/java/org/apache/james/jmap/methods/integration/SetVacationResponseTest.java
@@ -72,8 +72,9 @@ public abstract class SetVacationResponseTest {
                 .build();
 
         jmapServer.getProbe(DataProbeImpl.class)
-            .fluentAddDomain(DOMAIN)
-            .fluentAddUser(USER, PASSWORD);
+            .fluent()
+            .addDomain(DOMAIN)
+            .addUser(USER, PASSWORD);
         accessToken = authenticateJamesUser(baseUri(jmapServer), USER, PASSWORD);
 
         await();

http://git-wip-us.apache.org/repos/asf/james-project/blob/7488a2e0/server/protocols/jmap-integration-testing/jmap-integration-testing-common/src/test/java/org/apache/james/jmap/methods/integration/SpamAssassinContract.java
----------------------------------------------------------------------
diff --git a/server/protocols/jmap-integration-testing/jmap-integration-testing-common/src/test/java/org/apache/james/jmap/methods/integration/SpamAssassinContract.java b/server/protocols/jmap-integration-testing/jmap-integration-testing-common/src/test/java/org/apache/james/jmap/methods/integration/SpamAssassinContract.java
index 358579b..8a2a62c 100644
--- a/server/protocols/jmap-integration-testing/jmap-integration-testing-common/src/test/java/org/apache/james/jmap/methods/integration/SpamAssassinContract.java
+++ b/server/protocols/jmap-integration-testing/jmap-integration-testing-common/src/test/java/org/apache/james/jmap/methods/integration/SpamAssassinContract.java
@@ -74,11 +74,12 @@ public interface SpamAssassinContract {
         RestAssured.defaultParser = Parser.JSON;
 
         james.getJmapServer().getProbe(DataProbeImpl.class)
-            .fluentAddDomain(BOBS_DOMAIN)
-            .fluentAddDomain(RECIPIENTS_DOMAIN)
-            .fluentAddUser(BOB, BOB_PASSWORD)
-            .fluentAddUser(ALICE, ALICE_PASSWORD)
-            .fluentAddUser(PAUL, PAUL_PASSWORD);
+            .fluent()
+            .addDomain(BOBS_DOMAIN)
+            .addDomain(RECIPIENTS_DOMAIN)
+            .addUser(BOB, BOB_PASSWORD)
+            .addUser(ALICE, ALICE_PASSWORD)
+            .addUser(PAUL, PAUL_PASSWORD);
     }
 
     default AccessToken accessTokenFor(GuiceJamesServer james, String user, String password) {

http://git-wip-us.apache.org/repos/asf/james-project/blob/7488a2e0/server/protocols/webadmin/webadmin-mailrepository/src/main/java/org/apache/james/webadmin/routes/MailRepositoriesRoutes.java
----------------------------------------------------------------------
diff --git a/server/protocols/webadmin/webadmin-mailrepository/src/main/java/org/apache/james/webadmin/routes/MailRepositoriesRoutes.java b/server/protocols/webadmin/webadmin-mailrepository/src/main/java/org/apache/james/webadmin/routes/MailRepositoriesRoutes.java
index c9f07cc..b60bb6f 100644
--- a/server/protocols/webadmin/webadmin-mailrepository/src/main/java/org/apache/james/webadmin/routes/MailRepositoriesRoutes.java
+++ b/server/protocols/webadmin/webadmin-mailrepository/src/main/java/org/apache/james/webadmin/routes/MailRepositoriesRoutes.java
@@ -34,6 +34,7 @@ import javax.mail.internet.MimeMessage;
 import javax.servlet.http.HttpServletResponse;
 import javax.ws.rs.DELETE;
 import javax.ws.rs.GET;
+import javax.ws.rs.PUT;
 import javax.ws.rs.Path;
 import javax.ws.rs.Produces;
 
@@ -95,6 +96,8 @@ public class MailRepositoriesRoutes implements Routes {
     public void define(Service service) {
         this.service = service;
 
+        definePutMailRepository();
+
         defineGetMailRepositories();
 
         defineListMails();
@@ -112,6 +115,31 @@ public class MailRepositoriesRoutes implements Routes {
         defineReprocessOne();
     }
 
+    @PUT
+    @Path("/{encodedUrl}")
+    @ApiOperation(value = "Create a repository")
+    @ApiResponses(value = {
+        @ApiResponse(code = HttpStatus.NO_CONTENT_204, message = "The repository is created"),
+        @ApiResponse(code = HttpStatus.INTERNAL_SERVER_ERROR_500, message = "Internal server error - Something went bad on the server side."),
+    })
+    public void definePutMailRepository() {
+        service.put(MAIL_REPOSITORIES + "/:encodedUrl", (request, response) -> {
+            String url = decodedRepositoryUrl(request);
+            try {
+                repositoryStoreService.createMailRepository(url);
+                response.status(HttpStatus.NO_CONTENT_204);
+                return Constants.EMPTY_BODY;
+            } catch (MailRepositoryStore.MailRepositoryStoreException e) {
+                throw ErrorResponder.builder()
+                    .statusCode(HttpStatus.INTERNAL_SERVER_ERROR_500)
+                    .type(ErrorResponder.ErrorType.SERVER_ERROR)
+                    .cause(e)
+                    .message(String.format("Error while creating a mail repository with url '%s'", url))
+                    .haltError();
+            }
+        }, jsonTransformer);
+    }
+
     @GET
     @Path("/{encodedUrl}/mails")
     @ApiOperation(value = "Listing all mails in a repository")
@@ -144,7 +172,7 @@ public class MailRepositoriesRoutes implements Routes {
             Offset offset = ParametersExtractor.extractOffset(request);
             Limit limit = ParametersExtractor.extractLimit(request);
             String encodedUrl = request.params("encodedUrl");
-            String url = URLDecoder.decode(encodedUrl, StandardCharsets.UTF_8.displayName());
+            String url = decodedRepositoryUrl(request);
             try {
                 return repositoryStoreService.listMails(url, offset, limit)
                     .orElseThrow(() -> ErrorResponder.builder()

http://git-wip-us.apache.org/repos/asf/james-project/blob/7488a2e0/server/protocols/webadmin/webadmin-mailrepository/src/main/java/org/apache/james/webadmin/service/MailRepositoryStoreService.java
----------------------------------------------------------------------
diff --git a/server/protocols/webadmin/webadmin-mailrepository/src/main/java/org/apache/james/webadmin/service/MailRepositoryStoreService.java b/server/protocols/webadmin/webadmin-mailrepository/src/main/java/org/apache/james/webadmin/service/MailRepositoryStoreService.java
index 6f69be3..de33041 100644
--- a/server/protocols/webadmin/webadmin-mailrepository/src/main/java/org/apache/james/webadmin/service/MailRepositoryStoreService.java
+++ b/server/protocols/webadmin/webadmin-mailrepository/src/main/java/org/apache/james/webadmin/service/MailRepositoryStoreService.java
@@ -58,6 +58,9 @@ public class MailRepositoryStoreService {
             .collect(Guavate.toImmutableList());
     }
 
+    public MailRepository createMailRepository(String repositoryUrl) throws MailRepositoryStore.MailRepositoryStoreException {
+        return mailRepositoryStore.create(repositoryUrl);
+    }
 
     public Optional<List<MailKey>> listMails(String url, Offset offset, Limit limit) throws MailRepositoryStore.MailRepositoryStoreException, MessagingException {
         Optional<MailRepository> mailRepository = Optional.ofNullable(getRepository(url));

http://git-wip-us.apache.org/repos/asf/james-project/blob/7488a2e0/server/protocols/webadmin/webadmin-mailrepository/src/test/java/org/apache/james/webadmin/routes/MailRepositoriesRoutesTest.java
----------------------------------------------------------------------
diff --git a/server/protocols/webadmin/webadmin-mailrepository/src/test/java/org/apache/james/webadmin/routes/MailRepositoriesRoutesTest.java b/server/protocols/webadmin/webadmin-mailrepository/src/test/java/org/apache/james/webadmin/routes/MailRepositoriesRoutesTest.java
index e7b57fb..7370e3c 100644
--- a/server/protocols/webadmin/webadmin-mailrepository/src/test/java/org/apache/james/webadmin/routes/MailRepositoriesRoutesTest.java
+++ b/server/protocols/webadmin/webadmin-mailrepository/src/test/java/org/apache/james/webadmin/routes/MailRepositoriesRoutesTest.java
@@ -32,7 +32,11 @@ import static org.hamcrest.Matchers.hasSize;
 import static org.hamcrest.Matchers.is;
 import static org.hamcrest.Matchers.isEmptyOrNullString;
 import static org.hamcrest.Matchers.notNullValue;
+import static org.mockito.Matchers.anyString;
 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.nio.charset.StandardCharsets;
@@ -73,12 +77,12 @@ import com.jayway.restassured.parsing.Parser;
 
 public class MailRepositoriesRoutesTest {
 
-    public static final String URL_MY_REPO = "url://myRepo";
-    public static final String URL_ESCAPED_MY_REPO = "url%3A%2F%2FmyRepo";
-    public static final String MY_REPO_MAILS = "url%3A%2F%2FmyRepo/mails";
-    public static final String CUSTOM_QUEUE = "customQueue";
-    public static final String NAME_1 = "name1";
-    public static final String NAME_2 = "name2";
+    private static final String URL_MY_REPO = "url://myRepo";
+    private static final String URL_ESCAPED_MY_REPO = "url%3A%2F%2FmyRepo";
+    private static final String MY_REPO_MAILS = "url%3A%2F%2FmyRepo/mails";
+    private static final String CUSTOM_QUEUE = "customQueue";
+    private static final String NAME_1 = "name1";
+    private static final String NAME_2 = "name2";
     private WebAdminServer webAdminServer;
     private MailRepositoryStore mailRepositoryStore;
     private MemoryMailRepository mailRepository;
@@ -111,6 +115,7 @@ public class MailRepositoriesRoutesTest {
         RestAssured.requestSpecification = WebAdminUtils.buildRequestSpecification(webAdminServer)
             .setBasePath(MailRepositoriesRoutes.MAIL_REPOSITORIES)
             .build();
+        RestAssured.enableLoggingOfRequestAndResponseIfValidationFails();
     }
 
     @After
@@ -119,6 +124,48 @@ public class MailRepositoriesRoutesTest {
     }
 
     @Test
+    public void putMailRepositoryShouldReturnOkWhenRepositoryIsCreated() throws Exception {
+        when()
+            .put(URL_ESCAPED_MY_REPO)
+        .then()
+            .statusCode(HttpStatus.NO_CONTENT_204);
+
+        verify(mailRepositoryStore).create(URL_MY_REPO);
+        verifyNoMoreInteractions(mailRepositoryStore);
+    }
+
+    @Test
+    public void putMailRepositoryShouldReturnOkWhenRepositoryAlreadyExists() throws Exception {
+        when()
+            .put(URL_ESCAPED_MY_REPO)
+        .then()
+            .statusCode(HttpStatus.NO_CONTENT_204);
+
+        when()
+            .put(URL_ESCAPED_MY_REPO)
+        .then()
+            .statusCode(HttpStatus.NO_CONTENT_204);
+
+        verify(mailRepositoryStore, times(2)).create(URL_MY_REPO);
+        verifyNoMoreInteractions(mailRepositoryStore);
+    }
+
+    @Test
+    public void putMailRepositoryShouldReturnServerErrorWhenCannotCreateRepository() throws Exception {
+        when(mailRepositoryStore.create(anyString()))
+            .thenThrow(new MailRepositoryStore.MailRepositoryStoreException("Error while selecting repository url://myRepo"));
+
+        when()
+            .put(URL_ESCAPED_MY_REPO)
+        .then()
+            .statusCode(HttpStatus.INTERNAL_SERVER_ERROR_500)
+            .body("statusCode", is(500))
+            .body("type", is(ErrorResponder.ErrorType.SERVER_ERROR.getType()))
+            .body("message", is("Error while creating a mail repository with url 'url://myRepo'"))
+            .body("details", is("Error while selecting repository url://myRepo"));
+    }
+
+    @Test
     public void getMailRepositoriesShouldReturnEmptyWhenEmpty() {
         List<Object> mailRepositories =
             when()

http://git-wip-us.apache.org/repos/asf/james-project/blob/7488a2e0/src/site/markdown/server/manage-webadmin.md
----------------------------------------------------------------------
diff --git a/src/site/markdown/server/manage-webadmin.md b/src/site/markdown/server/manage-webadmin.md
index 01d2022..1a574d3 100644
--- a/src/site/markdown/server/manage-webadmin.md
+++ b/src/site/markdown/server/manage-webadmin.md
@@ -21,26 +21,26 @@ In case of any error, the system will return an error message which is json form
 
 ## Navigation menu
 
- - [Administrating domains](#administrating-domains)
- - [Administrating users](#administrating-users)
- - [Administrating user mailboxes](#administrating-user-mailboxes)
- - [Administrating quotas by users](#administrating-quotas-by-users)
- - [Administrating quotas by domains](#administrating-quotas-by-domains)
- - [Administrating global quotas](#administrating-global-quotas)
- - [Cassandra Schema upgrades](#cassandra-schema-upgrades)
- - [Correcting ghost mailbox](#correcting-ghost-mailbox)
- - [Creating address group](#creating-address-group)
- - [Creating address forwards](#creating-address-forwards)
- - [Administrating mail repositories](#administrating-mail-repositories)
- - [Administrating mail queues](#administrating-mail-queues)
- - [Task management](#task-management)
+ - [Administrating domains](#Administrating_domains)
+ - [Administrating users](#Administrating_users)
+ - [Administrating user mailboxes](#Administrating_user_mailboxes)
+ - [Administrating quotas by users](#Administrating_quotas_by_users)
+ - [Administrating quotas by domains](#Administrating_quotas_by_domains)
+ - [Administrating global quotas](#Administrating_global_quotas)
+ - [Cassandra Schema upgrades](#Cassandra_schema_upgrades)
+ - [Correcting ghost mailbox](#Correcting_ghost_mailbox)
+ - [Creating address group](#Creating_address_group)
+ - [Creating address forwards](#Creating_address_forwards)
+ - [Administrating mail repositories](#Administrating_mail_repositories)
+ - [Administrating mail queues](#Administrating_mail_queues)
+ - [Task management](#Task_management)
 
 ## Administrating domains
 
-   - [Create a domain](#create-a-domain)
-   - [Delete a domain](#delete-a-domain)
-   - [Test if a domain exists](#test-if-a-domain-exists)
-   - [Get the list of domains](#get-the-list-of-domains)
+   - [Create a domain](#Create_a_domain)
+   - [Delete a domain](#Delete_a_domain)
+   - [Test if a domain exists](#Test_if_a_domain_exists)
+   - [Get the list of domains](#Get_the_list_of_domains)
 
 ### Create a domain
 
@@ -103,10 +103,10 @@ Response codes:
 
 ## Administrating users
 
-   - [Create a user](#create-a-user)
-   - [Updating a user password](#updating-a-user-password)
-   - [Deleting a domain](#deleting-a-user)
-   - [Retrieving the user list](#retrieving-the-user-list)
+   - [Create a user](#Create_a_user)
+   - [Updating a user password](#Updating_a_user_password)
+   - [Deleting a domain](#Deleting_a_user)
+   - [Retrieving the user list](#Retrieving_the_user_list)
 
 ### Create a user
 
@@ -165,11 +165,11 @@ Response codes:
 
 ## Administrating user mailboxes
 
- - [Creating a mailbox](#creating-a-mailbox)
- - [Deleting a mailbox and its children](#deleting-a-mailbox-and-its-children)
- - [Testing existence of a mailbox](#testing-existence-of-a-mailbox)
- - [Listing user mailboxes](#listing-user-mailboxes)
- - [Deleting_user_mailboxes](#deleting-user-mailboxes)
+ - [Creating a mailbox](#Creating_a_mailbox)
+ - [Deleting a mailbox and its children](#Deleting_a_mailbox_and_its_children)
+ - [Testing existence of a mailbox](#Testing_existence_of_a_mailbox)
+ - [Listing user mailboxes](#Listing_user_mailboxes)
+ - [Deleting_user_mailboxes](#Deleting_user_mailboxes)
 
 ### Creating a mailbox
 
@@ -261,15 +261,15 @@ Response codes:
 
 ## Administrating quotas by users
 
- - [Getting the quota for a user](#getting-the-quota-for-a-user)
- - [Updating the quota for a user](#updating-the-quota-for-a-user)
- - [Getting the quota count for a user](#getting-the-quota-count-for-a-user)
- - [Updating the quota count for a user](#updating-the-quota-count-for-a-user)
- - [Deleting the quota count for a user](#deleting-the-quota-count-for-a-user)
- - [Getting the quota size for a user](#getting-the-quota-size-for-a-user)
- - [Updating the quota size for a user](#updating-the-quota-size-for-a-user)
- - [Deleting the quota size for a user](#deleting-the-quota-size-for-a-user)
- - [Searching user by quota ratio](#searching-user-by-quota-ratio)
+ - [Getting the quota for a user](#Getting_the_quota_for_a_user)
+ - [Updating the quota for a user](#Updating_the_quota_for_a_user)
+ - [Getting the quota count for a user](#Getting_the_quota_count_for_a_user)
+ - [Updating the quota count for a user](#Updating_the_quota_count_for_a_user)
+ - [Deleting the quota count for a user](#Deleting_the_quota_count_for_a_user)
+ - [Getting the quota size for a user](#Getting_the_quota_size_for_a_user)
+ - [Updating the quota size for a user](#Updating_the_quota_size_for_a_user)
+ - [Deleting the quota size for a user](#Deleting_the_quota_size_for_a_user)
+ - [Searching user by quota ratio](#Searching_user_by_quota_ratio)
 
 ### Getting the quota for a user
 
@@ -539,14 +539,14 @@ Response codes:
 
 ## Administrating quotas by domains
 
- - [Getting the quota for a domain](#getting-the-quota-for-a-domain)
- - [Updating the quota for a domain](#updating-the-quota-for-a-domain)
- - [Getting the quota count for a domain](#getting-the-quota-count-for-a-domain)
- - [Updating the quota count for a domain](#updating-the-quota-count-for-a-domain)
- - [Deleting the quota count for a domain](#deleting-the-quota-count-for-a-domain)
- - [Getting the quota size for a domain](#getting-the-quota-size-for-a-domain)
- - [Updating the quota size for a domain](#updating-the-quota-size-for-a-domain)
- - [Deleting the quota size for a domain](#deleting-the-quota-size-for-a-domain)
+ - [Getting the quota for a domain](#Getting_the_quota_for_a_domain)
+ - [Updating the quota for a domain](#Updating_the_quota_for_a_domain)
+ - [Getting the quota count for a domain](#Getting_the_quota_count_for_a_domain)
+ - [Updating the quota count for a domain](#Updating_the_quota_count_for_a_domain)
+ - [Deleting the quota count for a domain](#Deleting_the_quota_count_for_a_domain)
+ - [Getting the quota size for a domain](#Getting_the_quota_size_for_a_domain)
+ - [Updating the quota size for a domain](#Updating_the_quota_size_for_a_domain)
+ - [Deleting the quota size for a domain](#Deleting_the_quota_size_for_a_domain)
 
 ### Getting the quota for a domain
 
@@ -727,14 +727,14 @@ Response codes:
 
 ## Administrating global quotas
 
- - [Getting the global quota](#getting-the-global-quota)
- - [Updating global quota](#updating-global-quota)
- - [Getting the global quota count](#getting-the-global-quota-count)
- - [Updating the global quota count](#updating-the-global-quota-count)
- - [Deleting the global quota count](#deleting-the-global-quota-count)
- - [Getting the global quota size](#getting-the-global-quota-size)
- - [Updating the global quota size](#updating-the-global-quota-size)
- - [Deleting the global quota size](#deleting-the-global-quota-size)
+ - [Getting the global quota](#Getting_the_global_quota)
+ - [Updating global quota](#Updating_global_quota)
+ - [Getting the global quota count](#Getting_the_global_quota_count)
+ - [Updating the global quota count](#Updating_the_global_quota_count)
+ - [Deleting the global quota count](#Deleting_the_global_quota_count)
+ - [Getting the global quota size](#Getting_the_global_quota_size)
+ - [Updating the global quota size](#Updating_the_global_quota_size)
+ - [Deleting the global quota size](#Deleting_the_global_quota_size)
 
 ### Getting the global quota
 
@@ -910,10 +910,10 @@ These schema updates can be triggered by webadmin using the Cassandra backend.
 
 Note that currently the progress can be tracked by logs.
 
- - [Retrieving current Cassandra schema version](#retrieving-current-cassandra-schema-version)
- - [Retrieving latest available Cassandra schema version](#retrieving-latest-available-cassandra-schema-version)
- - [Upgrading to a specific version](#upgrading-to-a-specific-version)
- - [Upgrading to the latest version](#upgrading-to-the-latest-version)
+ - [Retrieving current Cassandra schema version](#Retrieving_current_cassandra_schema_version)
+ - [Retrieving latest available Cassandra schema version](#Retrieving_latest_available_cassandra_schema_version)
+ - [Upgrading to a specific version](#Upgrading_to_a_specific_version)
+ - [Upgrading to the latest version](#Upgrading_to_the_latest_version)
 
 ### Retrieving current Cassandra schema version
 
@@ -1082,10 +1082,10 @@ to be configured.
 
 Note that email addresses are restricted to ASCII character set. Mail addresses not matching this criteria will be rejected.
 
- - [Listing groups](#listing-groups)
- - [Listing members of a group](#listing-members-of-a-group)
- - [Adding a group member](#adding-a-group-member)
- - [Removing a group member](#removing-a-group-member)
+ - [Listing groups](#Listing_groups)
+ - [Listing members of a group](#Listing_members_of_a_group)
+ - [Adding a group member](#Adding_a_group_member)
+ - [Removing a group member](#Removing_a_group_member)
 
 ### Listing groups
 
@@ -1170,10 +1170,10 @@ to be configured.
 
 Note that email addresses are restricted to ASCII character set. Mail addresses not matching this criteria will be rejected.
 
- - [Listing Forwards](#listing-forwards)
- - [Listing destinations in a forward](#listing-destinations-in-a-forward)
- - [Adding a new destination to a forward](#adding-a-new-destination-to-a-forward)
- - [Removing a destination of a forward](#removing-a-destination-of-a-forward)
+ - [Listing Forwards](#Listing_forwards)
+ - [Listing destinations in a forward](#Listing_destinations_in_a_forward)
+ - [Adding a new destination to a forward](#Adding_a_new_destination_to_a_forward)
+ - [Removing a destination of a forward](#Removing_a_destination_of_a_forward)
 
 ### Listing Forwards
 
@@ -1246,14 +1246,32 @@ Response codes:
 
 ## Administrating mail repositories
 
- - [Listing mail repositories](#listing-mail-repositories)
- - [Getting additional information for a mail repository](#getting-additional-information-for-a-mail-repository)
- - [Listing mails contained in a mail repository](#listing-mails-contained-in-a-mail-repository)
- - [Reading a mail details](#reading-a-mail-details)
- - [Removing a mail from a mail repository](#removing-a-mail-from-a-mail-repository)
- - [Removing all mails from a mail repository](#removing-all-mails-from-a-mail-repository)
- - [Reprocessing mails from a mail repository](#reprocessing-mails-from-a-mail-repository)
- - [Reprocessing a specific mail from a mail repository](#reprocessing-a-specific-mail-from-a-mail-repository)
+ - [Create a mail repository](#Create_a_mail_repository)
+ - [Listing mail repositories](#Listing_mail_repositories)
+ - [Getting additional information for a mail repository](#Getting_additional_information_for_a_mail_repository)
+ - [Listing mails contained in a mail repository](#Listing_mails_contained_in_a_mail_repository)
+ - [Reading a mail details](#Reading_a_mail_details)
+ - [Removing a mail from a mail repository](#Removing_a_mail_from_a_mail_repository)
+ - [Removing all mails from a mail repository](#Removing_all_mails_from_a_mail_repository)
+ - [Reprocessing mails from a mail repository](#Reprocessing_mails_from_a_mail_repository)
+ - [Reprocessing a specific mail from a mail repository](#Reprocessing_a_specific_mail_from_a_mail_repository)
+
+### Create a mail repository
+
+```
+curl -XPUT http://ip:port/mailRepositories/encodedUrlOfTheRepository
+```
+
+Resource name `encodedUrlOfTheRepository` should be the resource id of the created mail repository. Example:
+
+```
+curl -XPUT http://ip:port/mailRepositories/file%3A%2F%2FmailRepo
+```
+
+Response codes:
+
+ - 204: The repository is created
+ - 500: Internal error
 
 ### Listing mail repositories
 
@@ -1580,12 +1598,12 @@ The scheduled task will have the following type `reprocessingOneTask` and the fo
 
 ## Administrating mail queues
 
- - [Listing mail queues](#listing-mail-queues)
- - [Getting a mail queue details](#getting-a-mail-queue-details)
- - [Listing the mails of a mail queue](#listing-the-mails-of-a-mail-queue)
- - [Deleting mails from a mail queue](#deleting-mails-from-a-mail-queue)
- - [Clearing a mail queue](#clearing-a-mail-queue)
- - [Flushing mails from a mail queue](#flushing-mails-from-a-mail-queue)
+ - [Listing mail queues](#Listing_mail_queues)
+ - [Getting a mail queue details](#Getting_a_mail_queue_details)
+ - [Listing the mails of a mail queue](#Listing_the_mails_of_a_mail_queue)
+ - [Deleting mails from a mail queue](#Deleting_mails_from_a_mail_queue)
+ - [Clearing a mail queue](#Clearing_a_mail_queue)
+ - [Flushing mails from a mail queue](#Flushing_mails_from_a_mail_queue)
 
 ### Listing mail queues
 
@@ -1742,10 +1760,10 @@ Some webadmin features schedules tasks. The task management API allow to monitor
 
 Note that the `taskId` used in the following APIs is returned by other WebAdmin APIs scheduling tasks.
 
- - [Getting a task details](#getting-a-task-details)
- - [Awaiting a task](#awaiting-a-task)
- - [Cancelling a task](#cancelling-a-task)
- - [Listing tasks](#listing-tasks)
+ - [Getting a task details](#Getting_a_task_details)
+ - [Awaiting a task](#Awaiting_a_task)
+ - [Cancelling a task](#Cancelling_a_task)
+ - [Listing tasks](#Listing_tasks)
 
 ### Getting a task details
 


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