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 2019/02/15 13:30:35 UTC

[james-project] branch master updated (9c836c5 -> 8682fbf)

This is an automated email from the ASF dual-hosted git repository.

rouazana pushed a change to branch master
in repository https://gitbox.apache.org/repos/asf/james-project.git.


    from 9c836c5  JAMES-2649 Add additonal infos to CassandraMappingsSolveInconsistenciesTask
     new 23e94c4  JAMES-2578 Fix warning using Mailet new API
     new 429e9b1  JAMES-2578 Fix warning using Mailet new API
     new ea3e231  DO NOT REVIEW JAMES-2630 Migrate lasts CompletableFutur to Reactor #2156
     new 04efa19  JAMES-2630 Add CassandraAsyncExecutor.executeRows
     new 27d071f  JAMES-2579 Revise openjpa version in guice jpa doc
     new 3a4fe51  JAMES-2651 JPAEntityManagerModule supports username password
     new 8682fbf  JAMES-2651 User mariaDB in smtp JPA mariaDB test

The 7 revisions listed above as "new" are entirely new to this
repository and will be described in separate emails.  The revisions
listed as "add" were already present in the repository and have only
been added to this reference.


Summary of changes:
 .../cassandra/init/CassandraTableManager.java      |   4 +-
 .../init/SessionWithInitializedTablesFactory.java  |   6 +-
 .../migration/CassandraMigrationService.java       |   4 +-
 .../cassandra/utils/CassandraAsyncExecutor.java    |  40 +--
 .../versions/CassandraSchemaVersionDAO.java        |  22 +-
 .../versions/CassandraSchemaVersionManager.java    |   2 +-
 .../SessionWithInitializedTablesFactoryTest.java   |   3 +-
 .../migration/CassandraMigrationServiceTest.java   |  28 +-
 .../backends/cassandra/utils/PaggingTest.java      |  26 +-
 .../versions/CassandraSchemaVersionDAOTest.java    |  15 +-
 .../CassandraSchemaVersionManagerTest.java         |  19 +-
 .../apache/james/backends/jpa/JPAConstants.java    |  26 --
 .../eventstore/cassandra/EventStoreDao.java        |  15 +-
 .../mailbox/cassandra/mail/CassandraACLMapper.java |   2 +-
 .../cassandra/mail/CassandraApplicableFlagDAO.java |   4 +-
 .../cassandra/mail/CassandraAttachmentDAO.java     |  15 +-
 .../cassandra/mail/CassandraAttachmentDAOV2.java   |   4 +-
 .../cassandra/mail/CassandraAttachmentMapper.java  |   7 +-
 .../mail/CassandraAttachmentMessageIdDAO.java      |  24 +-
 .../mail/CassandraAttachmentOwnerDAO.java          |  27 +-
 .../cassandra/mail/CassandraDeletedMessageDAO.java |  12 +-
 .../cassandra/mail/CassandraFirstUnseenDAO.java    |   6 +-
 .../cassandra/mail/CassandraMailboxCounterDAO.java |  14 +-
 .../cassandra/mail/CassandraMailboxDAO.java        |  12 +-
 .../cassandra/mail/CassandraMailboxMapper.java     |   6 +-
 .../mail/CassandraMailboxPathDAOImpl.java          |  22 +-
 .../cassandra/mail/CassandraMailboxPathV2DAO.java  |   6 +-
 .../cassandra/mail/CassandraMailboxRecentsDAO.java |   6 +-
 .../cassandra/mail/CassandraMessageDAO.java        |  16 +-
 .../cassandra/mail/CassandraMessageIdDAO.java      |  61 ++--
 .../mail/CassandraMessageIdToImapUidDAO.java       |   8 +-
 .../cassandra/mail/CassandraMessageMapper.java     |  14 +-
 .../cassandra/mail/CassandraModSeqProvider.java    |   2 +-
 .../cassandra/mail/CassandraUidProvider.java       |   2 +-
 .../mail/CassandraUserMailboxRightsDAO.java        |  13 +-
 .../migration/AttachmentMessageIdCreation.java     |  38 ++-
 .../mail/migration/AttachmentV2Migration.java      |  39 ++-
 .../mail/migration/MailboxPathV2Migration.java     |  42 +--
 .../mail/task/MailboxMergingTaskRunner.java        |   4 +-
 .../cassandra/mail/CassandraAttachmentDAOTest.java |  16 +-
 .../mail/CassandraAttachmentFallbackTest.java      |  14 +-
 ...va => CassandraAttachmentMessageIdDAOTest.java} |  57 ++--
 .../mail/CassandraAttachmentOwnerDAOTest.java      |  13 +-
 .../cassandra/mail/CassandraMailboxDAOTest.java    |   4 +-
 .../mail/CassandraMailboxPathDAOImplTest.java      |  10 +-
 .../cassandra/mail/CassandraMessageDAOTest.java    |  22 +-
 .../cassandra/mail/CassandraMessageIdDAOTest.java  |  62 ++--
 .../mail/CassandraUserMailboxRightsDAOTest.java    |   6 +-
 .../migration/AttachmentMessageIdCreationTest.java |  23 +-
 .../mail/migration/AttachmentV2MigrationTest.java  |  27 +-
 .../mail/migration/MailboxPathV2MigrationTest.java |  11 +-
 .../api/src/main/java/org/apache/mailet/Mail.java  |  12 +-
 .../java/org/apache/mailet/ContractMailTest.java   |   2 +-
 .../james/transport/mailets/AbstractSign.java      |  12 +-
 .../transport/mailets/ICALToJsonAttribute.java     |   7 +
 .../transport/mailets/ICALToJsonAttributeTest.java | 313 ++++++++++---------
 .../transport/mailets/ICalendarParserTest.java     |  43 ++-
 .../transport/mailets/AmqpForwardAttribute.java    |  61 ++--
 .../transport/mailets/RemoveMailAttribute.java     |  18 +-
 .../james/transport/mailets/StripAttachment.java   |  44 +--
 .../james/transport/matchers/HasException.java     |  17 +-
 .../transport/matchers/SMTPAuthSuccessful.java     |  10 +-
 .../james/transport/matchers/SMTPAuthUserIs.java   |  12 +-
 .../mailets/AmqpForwardAttributeTest.java          |  23 +-
 .../transport/mailets/ContactExtractorTest.java    |  35 ++-
 .../mailets/MailAttributesToMimeHeadersTest.java   |  47 +--
 .../transport/mailets/MimeDecodingMailetTest.java  |  32 +-
 .../mailets/RemoveAllMailAttributesTest.java       |   7 +-
 .../transport/mailets/SetMailAttributeTest.java    |  28 +-
 .../transport/mailets/StripAttachmentTest.java     | 136 ++++++---
 .../matchers/AbstractHasMailAttributeTest.java     |  24 +-
 .../james/transport/matchers/HasExceptionTest.java |  16 +-
 .../transport/matchers/HasMailAttributeTest.java   |   2 +-
 .../HasMailAttributeWithValueRegexTest.java        |   2 +-
 .../matchers/HasMailAttributeWithValueTest.java    |   6 +-
 .../transport/matchers/SMTPAuthSuccessfulTest.java |   4 +-
 .../transport/matchers/SMTPAuthUserIsTest.java     |   7 +-
 .../apache/mailet/base/test/FakeMailContext.java   |  53 ++--
 .../apache/james/metrics/api/MetricFactory.java    |   5 -
 .../james/blob/cassandra/CassandraBlobsDAO.java    |   8 +-
 .../james/blob/union/UnionBlobStoreTest.java       |   7 +-
 .../org/apache/james/server/core/MailImpl.java     |   6 -
 .../apache/james/CassandraVersionCheckingTest.java |  13 +-
 server/container/guice/jpa-common-guice/pom.xml    |  10 +
 .../james/modules/data/JPAConfiguration.java       | 142 +++++++--
 .../james/modules/data/JPAEntityManagerModule.java |  21 +-
 ...estJPAConfigurationModuleWithSqlValidation.java |  80 ++++-
 .../james/modules/data/JPAConfigurationTest.java   | 163 ++++++++++
 ...ithAuthenticatedDatabaseSqlValidationTest.java} |  10 +-
 ...tabaseAuthenticaticationSqlValidationTest.java} |  10 +-
 .../james/JPAJamesServerWithSqlValidationTest.java |  10 +-
 .../java/org/apache/james/JPAConfiguration.java    | 107 -------
 .../java/org/apache/james/JPAJamesServerTest.java  |  13 +-
 .../apache/james/TestJPAConfigurationModule.java   |  10 +-
 .../apache/james/GuiceLifecycleHeathCheckTest.java |  14 +-
 .../org/apache/james/utils/JmapGuiceProbe.java     |   4 +-
 .../apache/james/util/CompletableFutureUtil.java   | 103 -------
 .../org/apache/james/util/FluentFutureStream.java  | 166 ----------
 .../james/util/CompletableFutureUtilTest.java      | 340 ---------------------
 .../apache/james/util/FluentFutureStreamTest.java  | 293 ------------------
 .../domainlist/cassandra/CassandraDomainList.java  |  25 +-
 .../cassandra/CassandraMailRepositoryUrlStore.java |   6 +-
 .../james/mailrepository/cassandra/UrlsDao.java    |  28 +-
 .../rrt/cassandra/CassandraMappingsSourcesDAO.java |   9 +-
 .../cassandra/CassandraRecipientRewriteTable.java  |   2 +-
 .../CassandraRecipientRewriteTableDAO.java         |   9 +-
 .../sieve/cassandra/CassandraActiveScriptDAO.java  |   6 +-
 .../james/sieve/cassandra/CassandraSieveDAO.java   |  24 +-
 .../sieve/cassandra/CassandraSieveQuotaDAO.java    |  29 +-
 .../sieve/cassandra/CassandraSieveRepository.java  |  99 +++---
 .../user/cassandra/CassandraUsersRepository.java   |  21 +-
 .../CassandraMailRepositoryUrlStoreExtension.java  |   4 +-
 .../CassandraRecipientRewriteTableV6Test.java      |   4 +-
 .../CassandraRecipientRewriteTableV7Test.java      |   4 +-
 .../james/rrt/cassandra/CassandraStepdefs.java     |   2 +-
 .../sieve/cassandra/CassandraSieveDAOTest.java     |  11 +-
 .../cassandra/CassandraSieveQuotaDAOTest.java      |  40 +--
 .../mailrepository/jdbc/JDBCMailRepository.java    |  25 +-
 .../cassandra/access/CassandraAccessTokenDAO.java  |  13 +-
 .../access/CassandraAccessTokenRepository.java     |  12 +-
 .../vacation/CassandraNotificationRegistry.java    |  10 +-
 .../vacation/CassandraNotificationRegistryDAO.java |  12 +-
 .../cassandra/vacation/CassandraVacationDAO.java   |  12 +-
 .../vacation/CassandraVacationRepository.java      |  11 +-
 .../jmap/api/access/AccessTokenRepository.java     |  10 +-
 .../jmap/api/vacation/NotificationRegistry.java    |   9 +-
 .../jmap/api/vacation/VacationRepository.java      |   6 +-
 .../memory/access/MemoryAccessTokenRepository.java |  17 +-
 .../vacation/MemoryNotificationRegistry.java       |  14 +-
 .../memory/vacation/MemoryVacationRepository.java  |  12 +-
 .../jmap/api/access/AccessTokenRepositoryTest.java |  21 +-
 .../vacation/AbstractNotificationRegistryTest.java |  28 +-
 .../vacation/AbstractVacationRepositoryTest.java   |  70 ++---
 .../james/transport/mailets/SpamAssassinTest.java  |  20 +-
 .../james/mailetcontainer/impl/ProcessorUtil.java  |   4 +-
 .../impl/camel/CamelMailetProcessor.java           |   2 +-
 .../mailetcontainer/impl/camel/MatcherMatch.java   |   2 +-
 .../impl/camel/MatcherSplitter.java                |   9 +-
 .../lib/AbstractStateMailetProcessorTest.java      |   3 +-
 .../mailets/AbstractRecipientRewriteTable.java     |   9 +-
 .../james/transport/mailets/RemoteDelivery.java    |   2 +-
 .../james/transport/mailets/SpamAssassin.java      |   7 +-
 .../james/transport/mailets/WithPriority.java      |  15 +-
 .../mailets/managesieve/ManageSieveMailet.java     |   2 +-
 .../mailets/remote/delivery/DeliveryRunnable.java  |   2 +-
 .../james/transport/matchers/IsMarkedAsSpam.java   |   2 +-
 .../james/transport/mailets/SpamAssassinTest.java  |  10 +-
 .../james/transport/mailets/WithPriorityTest.java  |  13 +-
 .../mailets/WithStorageDirectiveTest.java          |  18 +-
 .../mailets/delivery/SieveIntegrationTest.java     | 168 +++++-----
 .../managesieve/ManageSieveMailetTestCase.java     |  12 +-
 .../remote/delivery/RemoteDeliveryTest.java        |  17 +-
 .../james/transport/matchers/dlp/DlpTest.java      |   9 +-
 .../mailrepository/MailRepositoryContract.java     |  10 +-
 .../cassandra/CassandraMailRepository.java         |   2 +-
 .../cassandra/CassandraMailRepositoryCountDAO.java |  11 +-
 .../cassandra/CassandraMailRepositoryKeysDAO.java  |   2 +-
 .../cassandra/CassandraMailRepositoryMailDAO.java  |  29 +-
 .../CassandraMailRepositoryMailDaoV2.java          |   6 +-
 .../CassandraMailRepositoryCountDAOTest.java       |  12 +-
 .../CassandraMailRepositoryMailDAOTest.java        |   8 +-
 ...aMailRepositoryWithFakeImplementationsTest.java |   2 +-
 .../james/jmap/crypto/AccessTokenManagerImpl.java  |  16 +-
 .../org/apache/james/jmap/mailet/SentByJmap.java   |  10 +-
 .../apache/james/jmap/mailet/VacationMailet.java   |   8 +-
 .../jmap/methods/GetVacationResponseMethod.java    |   2 +-
 .../jmap/methods/SetVacationResponseMethod.java    |   4 +-
 .../org/apache/james/jmap/send/MailMetadata.java   |   5 +-
 .../java/org/apache/james/jmap/send/MailSpool.java |   6 +-
 .../james/jmap/send/PostDequeueDecorator.java      |  39 ++-
 .../james/jmap/AuthenticationFilterTest.java       |   4 +-
 .../jmap/crypto/AccessTokenManagerImplTest.java    |  89 ++++--
 .../apache/james/jmap/mailet/SentByJmapTest.java   |   6 +-
 .../james/jmap/mailet/VacationMailetTest.java      |  38 ++-
 .../jmap/mailet/filter/JMAPFilteringExtension.java |   2 +-
 .../jmap/mailet/filter/JMAPFilteringFixture.java   |   4 +-
 .../jmap/mailet/filter/JMAPFilteringTest.java      |  70 +++--
 .../methods/GetVacationResponseMethodTest.java     |   9 +-
 .../methods/SetVacationResponseMethodTest.java     |   6 +-
 .../org/apache/james/jmap/send/MailSpoolTest.java  |   6 +-
 .../james/jmap/send/PostDequeueDecoratorTest.java  |  43 +--
 .../AddDefaultAttributesMessageHook.java           |   4 +-
 .../james/smtpserver/MailPriorityHandler.java      |   4 +-
 .../smtpserver/fastfail/SpamAssassinHandler.java   |   4 +-
 .../james/smtpserver/SpamAssassinHandlerTest.java  |  21 +-
 .../routes/CassandraMigrationRoutesTest.java       |  25 +-
 .../org/apache/james/webadmin/dto/MailDto.java     |   8 +-
 .../queue/activemq/ActiveMQMailQueueItem.java      |   2 +-
 .../james/queue/activemq/ActiveMQSupport.java      |   3 +-
 .../james/queue/api/MailPrioritySupport.java       |  23 +-
 .../api/DelayedPriorityMailQueueContract.java      |   8 +-
 .../apache/james/queue/api/MailQueueContract.java  |  25 +-
 .../queue/api/ManageableMailQueueContract.java     |  17 +-
 .../james/queue/api/PriorityMailQueueContract.java |  44 +--
 .../api/PriorityManageableMailQueueContract.java   |  26 +-
 .../org/apache/james/queue/jms/JMSMailQueue.java   |  24 +-
 .../james/queue/library/MailQueueManagement.java   |  19 +-
 .../rabbitmq/view/cassandra/BrowseStartDAO.java    |  15 +-
 .../view/cassandra/CassandraMailQueueBrowser.java  |   6 +-
 .../cassandra/CassandraMailQueueMailDelete.java    |  10 +-
 .../view/cassandra/CassandraMailQueueView.java     |   2 +-
 .../rabbitmq/view/cassandra/DeletedMailsDAO.java   |   4 +-
 .../rabbitmq/view/cassandra/EnqueuedMailsDAO.java  |  16 +-
 src/site/markdown/server/install/guice-jpa.md      |   2 +-
 third-party/spamassassin/pom.xml                   |   4 +
 .../james/spamassassin/SpamAssassinResult.java     |  34 ++-
 .../spamassassin/SpamAssassinInvokerTest.java      |  12 +-
 .../james/spamassassin/SpamAssassinResultTest.java |  20 +-
 208 files changed, 2313 insertions(+), 2838 deletions(-)
 delete mode 100644 backends-common/jpa/src/main/java/org/apache/james/backends/jpa/JPAConstants.java
 copy mailbox/cassandra/src/test/java/org/apache/james/mailbox/cassandra/mail/{CassandraAttachmentDAOV2Test.java => CassandraAttachmentMessageIdDAOTest.java} (54%)
 create mode 100644 server/container/guice/jpa-common-guice/src/test/java/org/apache/james/modules/data/JPAConfigurationTest.java
 copy server/container/guice/jpa-guice/src/test/java/org/apache/james/{JPAJamesServerWithSqlValidationTest.java => JPAJamesServerWithAuthenticatedDatabaseSqlValidationTest.java} (82%)
 copy server/container/guice/jpa-guice/src/test/java/org/apache/james/{JPAJamesServerWithSqlValidationTest.java => JPAJamesServerWithNoDatabaseAuthenticaticationSqlValidationTest.java} (82%)
 delete mode 100644 server/container/guice/jpa-smtp-common/src/main/java/org/apache/james/JPAConfiguration.java
 delete mode 100644 server/container/util/src/main/java/org/apache/james/util/CompletableFutureUtil.java
 delete mode 100644 server/container/util/src/main/java/org/apache/james/util/FluentFutureStream.java
 delete mode 100644 server/container/util/src/test/java/org/apache/james/util/CompletableFutureUtilTest.java
 delete mode 100644 server/container/util/src/test/java/org/apache/james/util/FluentFutureStreamTest.java


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


[james-project] 07/07: JAMES-2651 User mariaDB in smtp JPA mariaDB test

Posted by ro...@apache.org.
This is an automated email from the ASF dual-hosted git repository.

rouazana pushed a commit to branch master
in repository https://gitbox.apache.org/repos/asf/james-project.git

commit 8682fbfaa07ce22989130721bd59109617a250c5
Author: tran tien duc <dt...@linagora.com>
AuthorDate: Mon Feb 11 14:34:17 2019 +0700

    JAMES-2651 User mariaDB in smtp JPA mariaDB test
    
    - Before that, test Module used `JPATestCluster` which is using embedded
    Derby, remove this module. While this test module is suppose to bind an
    entity manager pointing to mariaDB.
    - Remove another duplicated JPAConfiguration.
    - Remove unneeded JPAConstants class.
---
 .../apache/james/backends/jpa/JPAConstants.java    |  26 -----
 .../java/org/apache/james/JPAConfiguration.java    | 107 ---------------------
 .../java/org/apache/james/JPAJamesServerTest.java  |  13 +--
 .../apache/james/TestJPAConfigurationModule.java   |  10 +-
 4 files changed, 7 insertions(+), 149 deletions(-)

diff --git a/backends-common/jpa/src/main/java/org/apache/james/backends/jpa/JPAConstants.java b/backends-common/jpa/src/main/java/org/apache/james/backends/jpa/JPAConstants.java
deleted file mode 100644
index f90b032..0000000
--- a/backends-common/jpa/src/main/java/org/apache/james/backends/jpa/JPAConstants.java
+++ /dev/null
@@ -1,26 +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.backends.jpa;
-
-public class JPAConstants {
-
-    public static final int VALIDATION_NO_TIMEOUT = -1;
-
-}
diff --git a/server/container/guice/jpa-smtp-common/src/main/java/org/apache/james/JPAConfiguration.java b/server/container/guice/jpa-smtp-common/src/main/java/org/apache/james/JPAConfiguration.java
deleted file mode 100644
index 62e96c3..0000000
--- a/server/container/guice/jpa-smtp-common/src/main/java/org/apache/james/JPAConfiguration.java
+++ /dev/null
@@ -1,107 +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;
-
-import org.apache.james.backends.jpa.JPAConstants;
-
-import com.google.common.annotations.VisibleForTesting;
-import com.google.common.base.Preconditions;
-
-public class JPAConfiguration {
-
-    public static Builder builder() {
-        return new Builder();
-    }
-
-    public static class Builder {
-        private String driverName;
-        private String driverURL;
-        private boolean testOnBorrow;
-        private int validationQueryTimeoutSec = JPAConstants.VALIDATION_NO_TIMEOUT;
-        private String validationQuery;
-
-
-        public Builder driverName(String driverName) {
-            this.driverName = driverName;
-            return this;
-        }
-
-        public Builder driverURL(String driverURL) {
-            this.driverURL = driverURL;
-            return this;
-        }
-
-        public Builder testOnBorrow(boolean testOnBorrow) {
-            this.testOnBorrow = testOnBorrow;
-            return this;
-        }
-
-        public Builder validationQueryTimeoutSec(int validationQueryTimeoutSec) {
-            this.validationQueryTimeoutSec = validationQueryTimeoutSec;
-            return this;
-        }
-
-        public Builder validationQuery(String validationQuery) {
-            this.validationQuery = validationQuery;
-            return this;
-        }
-
-        public JPAConfiguration build() {
-            Preconditions.checkNotNull(driverName);
-            Preconditions.checkNotNull(driverURL);
-            return new JPAConfiguration(driverName, driverURL, testOnBorrow, validationQueryTimeoutSec, validationQuery);
-        }
-    }
-
-    private final String driverName;
-    private final String driverURL;
-    private final boolean testOnBorrow;
-    private final int validationQueryTimeoutSec;
-    private final String validationQuery;
-
-    @VisibleForTesting
-    JPAConfiguration(String driverName, String driverURL, boolean testOnBorrow, int validationQueryTimeoutSec, String validationQuery) {
-        this.driverName = driverName;
-        this.driverURL = driverURL;
-        this.testOnBorrow = testOnBorrow;
-        this.validationQueryTimeoutSec = validationQueryTimeoutSec;
-        this.validationQuery = validationQuery;
-    }
-
-    public String getDriverName() {
-        return driverName;
-    }
-
-    public String getDriverURL() {
-        return driverURL;
-    }
-
-    public boolean isTestOnBorrow() {
-        return testOnBorrow;
-    }
-
-    public int getValidationQueryTimeoutSec() {
-        return validationQueryTimeoutSec;
-    }
-
-    public String getValidationQuery() {
-        return validationQuery;
-    }
-
-}
diff --git a/server/container/guice/jpa-smtp-mariadb/src/test/java/org/apache/james/JPAJamesServerTest.java b/server/container/guice/jpa-smtp-mariadb/src/test/java/org/apache/james/JPAJamesServerTest.java
index e2e5528..b344ba5 100644
--- a/server/container/guice/jpa-smtp-mariadb/src/test/java/org/apache/james/JPAJamesServerTest.java
+++ b/server/container/guice/jpa-smtp-mariadb/src/test/java/org/apache/james/JPAJamesServerTest.java
@@ -27,15 +27,8 @@ import java.nio.ByteBuffer;
 import java.nio.channels.SocketChannel;
 import java.nio.charset.Charset;
 
-import javax.persistence.EntityManagerFactory;
-
-import org.apache.james.backends.jpa.JpaTestCluster;
-import org.apache.james.domainlist.jpa.model.JPADomain;
-import org.apache.james.mailrepository.jpa.JPAUrl;
 import org.apache.james.modules.protocols.SmtpGuiceProbe;
-import org.apache.james.rrt.jpa.model.JPARecipientRewrite;
 import org.apache.james.server.core.configuration.Configuration;
-import org.apache.james.user.jpa.model.JPAUser;
 import org.junit.After;
 import org.junit.Before;
 import org.junit.Rule;
@@ -74,11 +67,7 @@ public class JPAJamesServerTest {
 
         return GuiceJamesServer.forConfiguration(configuration)
                 .combineWith(JPAJamesServerMain.JPA_SERVER_MODULE, JPAJamesServerMain.PROTOCOLS)
-                .overrideWith(
-                        new TestJPAConfigurationModule(mariaDBUrl),
-                        (binder) -> binder.bind(EntityManagerFactory.class)
-                            .toInstance(JpaTestCluster.create(JPAUser.class, JPADomain.class, JPARecipientRewrite.class, JPAUrl.class)
-                                    .getEntityManagerFactory()));
+                .overrideWith(new TestJPAConfigurationModule(mariaDBUrl));
     }
 
     @After
diff --git a/server/container/guice/jpa-smtp-mariadb/src/test/java/org/apache/james/TestJPAConfigurationModule.java b/server/container/guice/jpa-smtp-mariadb/src/test/java/org/apache/james/TestJPAConfigurationModule.java
index 1270b8f..070d398 100644
--- a/server/container/guice/jpa-smtp-mariadb/src/test/java/org/apache/james/TestJPAConfigurationModule.java
+++ b/server/container/guice/jpa-smtp-mariadb/src/test/java/org/apache/james/TestJPAConfigurationModule.java
@@ -19,17 +19,17 @@
 
 package org.apache.james;
 
-import java.io.FileNotFoundException;
-
 import javax.inject.Singleton;
 
-import org.apache.commons.configuration.ConfigurationException;
+import org.apache.james.modules.data.JPAConfiguration;
 
 import com.google.inject.AbstractModule;
 import com.google.inject.Provides;
 
 public class TestJPAConfigurationModule extends AbstractModule {
 
+    private static final String MARIA_USERNAME = "test";
+    private static final String MARIA_PASSWORD = "test";
     private static final String JDBC_EMBEDDED_DRIVER = org.mariadb.jdbc.Driver.class.getName();
     private final String mariaDBUrl;
 
@@ -43,10 +43,12 @@ public class TestJPAConfigurationModule extends AbstractModule {
 
     @Provides
     @Singleton
-    JPAConfiguration provideConfiguration() throws FileNotFoundException, ConfigurationException {
+    JPAConfiguration provideConfiguration() {
         return JPAConfiguration.builder()
                 .driverName(JDBC_EMBEDDED_DRIVER)
                 .driverURL(mariaDBUrl)
+                .username(MARIA_USERNAME)
+                .password(MARIA_PASSWORD)
                 .build();
     }
 }


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


[james-project] 02/07: JAMES-2578 Fix warning using Mailet new API

Posted by ro...@apache.org.
This is an automated email from the ASF dual-hosted git repository.

rouazana pushed a commit to branch master
in repository https://gitbox.apache.org/repos/asf/james-project.git

commit 429e9b15939d452338b4388760f94d0ca1f14a3e
Author: Gautier DI FOLCO <gd...@linagora.com>
AuthorDate: Tue Feb 5 15:48:29 2019 +0100

    JAMES-2578 Fix warning using Mailet new API
---
 .../api/src/main/java/org/apache/mailet/Mail.java  |  12 +-
 .../james/transport/mailets/AbstractSign.java      |  12 +-
 .../transport/mailets/ICALToJsonAttributeTest.java |   5 +-
 .../transport/mailets/ICalendarParserTest.java     |  15 ++-
 .../transport/mailets/AmqpForwardAttribute.java    |  61 +++++----
 .../james/transport/mailets/StripAttachment.java   |  44 ++++---
 .../james/transport/matchers/HasException.java     |  17 ++-
 .../transport/matchers/SMTPAuthSuccessful.java     |  10 +-
 .../james/transport/matchers/SMTPAuthUserIs.java   |  12 +-
 .../mailets/AmqpForwardAttributeTest.java          |  23 ++--
 .../transport/mailets/ContactExtractorTest.java    |  35 ++++--
 .../mailets/MailAttributesToMimeHeadersTest.java   |  47 +++----
 .../transport/mailets/MimeDecodingMailetTest.java  |  32 +++--
 .../transport/mailets/SetMailAttributeTest.java    |   9 +-
 .../transport/mailets/StripAttachmentTest.java     | 136 +++++++++++++--------
 .../matchers/AbstractHasMailAttributeTest.java     |  24 ++--
 .../james/transport/matchers/HasExceptionTest.java |  16 ++-
 .../transport/matchers/HasMailAttributeTest.java   |   2 +-
 .../HasMailAttributeWithValueRegexTest.java        |   2 +-
 .../matchers/HasMailAttributeWithValueTest.java    |   6 +-
 .../transport/matchers/SMTPAuthSuccessfulTest.java |   4 +-
 .../transport/matchers/SMTPAuthUserIsTest.java     |   7 +-
 .../james/transport/mailets/SpamAssassinTest.java  |  20 +--
 .../james/mailetcontainer/impl/ProcessorUtil.java  |   4 +-
 .../lib/AbstractStateMailetProcessorTest.java      |   3 +-
 .../james/transport/mailets/RemoteDelivery.java    |   2 +-
 .../james/transport/mailets/SpamAssassin.java      |   7 +-
 .../james/transport/mailets/WithPriority.java      |  15 ++-
 .../mailets/managesieve/ManageSieveMailet.java     |   2 +-
 .../mailets/remote/delivery/DeliveryRunnable.java  |   2 +-
 .../james/transport/matchers/IsMarkedAsSpam.java   |   2 +-
 .../james/transport/mailets/SpamAssassinTest.java  |  10 +-
 .../james/transport/mailets/WithPriorityTest.java  |  13 +-
 .../managesieve/ManageSieveMailetTestCase.java     |  12 +-
 .../remote/delivery/RemoteDeliveryTest.java        |   2 +-
 .../james/transport/matchers/dlp/DlpTest.java      |   9 +-
 .../mailrepository/MailRepositoryContract.java     |  10 +-
 .../org/apache/james/jmap/mailet/SentByJmap.java   |  10 +-
 .../org/apache/james/jmap/send/MailMetadata.java   |   5 +-
 .../java/org/apache/james/jmap/send/MailSpool.java |   6 +-
 .../james/jmap/send/PostDequeueDecorator.java      |  39 ++++--
 .../apache/james/jmap/mailet/SentByJmapTest.java   |   6 +-
 .../jmap/mailet/filter/JMAPFilteringExtension.java |   2 +-
 .../jmap/mailet/filter/JMAPFilteringFixture.java   |   4 +-
 .../jmap/mailet/filter/JMAPFilteringTest.java      |  70 ++++++-----
 .../org/apache/james/jmap/send/MailSpoolTest.java  |   6 +-
 .../james/jmap/send/PostDequeueDecoratorTest.java  |  43 ++++---
 .../AddDefaultAttributesMessageHook.java           |   4 +-
 .../james/smtpserver/MailPriorityHandler.java      |   4 +-
 .../smtpserver/fastfail/SpamAssassinHandler.java   |   4 +-
 .../james/smtpserver/SpamAssassinHandlerTest.java  |  21 ++--
 .../james/queue/api/MailPrioritySupport.java       |  23 ++--
 .../api/DelayedPriorityMailQueueContract.java      |   8 +-
 .../apache/james/queue/api/MailQueueContract.java  |  24 ++--
 .../james/queue/api/PriorityMailQueueContract.java |  44 ++++---
 .../api/PriorityManageableMailQueueContract.java   |  26 ++--
 .../org/apache/james/queue/jms/JMSMailQueue.java   |   8 +-
 third-party/spamassassin/pom.xml                   |   4 +
 .../james/spamassassin/SpamAssassinResult.java     |  34 +++---
 .../spamassassin/SpamAssassinInvokerTest.java      |  12 +-
 .../james/spamassassin/SpamAssassinResultTest.java |  20 +--
 61 files changed, 634 insertions(+), 437 deletions(-)

diff --git a/mailet/api/src/main/java/org/apache/mailet/Mail.java b/mailet/api/src/main/java/org/apache/mailet/Mail.java
index afe75f8..34b4e19 100644
--- a/mailet/api/src/main/java/org/apache/mailet/Mail.java
+++ b/mailet/api/src/main/java/org/apache/mailet/Mail.java
@@ -82,9 +82,17 @@ public interface Mail extends Serializable, Cloneable {
     String DEFAULT = "root";
     String ERROR = "error";
     String TRANSPORT = "transport";
-    String SMTP_AUTH_USER_ATTRIBUTE_NAME = "org.apache.james.SMTPAuthUser";
     String SENT_BY_MAILET = "org.apache.james.SentByMailet";
-    String MAILET_ERROR_ATTRIBUTE_NAME = "org.apache.james.MailetError";
+
+    AttributeName SMTP_AUTH_USER = AttributeName.of("org.apache.james.SMTPAuthUser");
+    AttributeName MAILET_ERROR = AttributeName.of("org.apache.james.MailetError");
+
+    @Deprecated
+    String SMTP_AUTH_USER_ATTRIBUTE_NAME = SMTP_AUTH_USER.asString();
+
+    @Deprecated
+    String MAILET_ERROR_ATTRIBUTE_NAME = MAILET_ERROR.asString();
+
     /**
      * Returns the name of this message.
      * 
diff --git a/mailet/crypto/src/main/java/org/apache/james/transport/mailets/AbstractSign.java b/mailet/crypto/src/main/java/org/apache/james/transport/mailets/AbstractSign.java
index 461250d..42bd5f2 100644
--- a/mailet/crypto/src/main/java/org/apache/james/transport/mailets/AbstractSign.java
+++ b/mailet/crypto/src/main/java/org/apache/james/transport/mailets/AbstractSign.java
@@ -24,6 +24,7 @@ package org.apache.james.transport.mailets;
 import java.io.IOException;
 import java.lang.reflect.Constructor;
 import java.util.Enumeration;
+import java.util.Optional;
 
 import javax.inject.Inject;
 import javax.mail.MessagingException;
@@ -39,6 +40,7 @@ import org.apache.james.transport.KeyHolder;
 import org.apache.james.transport.SMIMEAttributeNames;
 import org.apache.james.user.api.UsersRepository;
 import org.apache.james.user.api.UsersRepositoryException;
+import org.apache.mailet.AttributeUtils;
 import org.apache.mailet.Mail;
 import org.apache.mailet.base.GenericMailet;
 import org.apache.mailet.base.RFC2822Headers;
@@ -561,14 +563,16 @@ public abstract class AbstractSign extends GenericMailet {
         }
 
         MailAddress reversePath = mail.getMaybeSender().get();
-        
-        String authUser = (String) mail.getAttribute(Mail.SMTP_AUTH_USER_ATTRIBUTE_NAME);
+
+        Optional<String> fetchedAuthUser = AttributeUtils.getValueAndCastFromMail(mail, Mail.SMTP_AUTH_USER, String.class);
         // was the sender user SMTP authorized?
-        if (authUser == null) {
+        if (!fetchedAuthUser.isPresent()) {
             LOGGER.info("Can not sign mail for sender <{}> as he is not a SMTP authenticated user", mail.getMaybeSender().asString());
             return false;
         }
-        
+
+        String authUser = fetchedAuthUser.get();
+
         // The sender is the postmaster?
         if (Objects.equal(getMailetContext().getPostmaster(), reversePath)) {
             // should not sign postmaster sent messages?
diff --git a/mailet/icalendar/src/test/java/org/apache/james/transport/mailets/ICALToJsonAttributeTest.java b/mailet/icalendar/src/test/java/org/apache/james/transport/mailets/ICALToJsonAttributeTest.java
index 685497c..a95b797 100644
--- a/mailet/icalendar/src/test/java/org/apache/james/transport/mailets/ICALToJsonAttributeTest.java
+++ b/mailet/icalendar/src/test/java/org/apache/james/transport/mailets/ICALToJsonAttributeTest.java
@@ -26,7 +26,6 @@ import java.io.ByteArrayInputStream;
 import java.nio.charset.StandardCharsets;
 import java.util.List;
 import java.util.Map;
-import java.util.Optional;
 import java.util.stream.Collectors;
 
 import javax.mail.MessagingException;
@@ -51,8 +50,8 @@ import net.fortuna.ical4j.data.CalendarBuilder;
 import net.fortuna.ical4j.model.Calendar;
 
 public class ICALToJsonAttributeTest {
-    public static final MailAddress SENDER = MailAddressFixture.ANY_AT_JAMES;
-    public static final Class<Map<String, byte[]>> MAP_STRING_BYTES_CLASS = (Class<Map<String, byte[]>>) (Object) Map.class;
+    private static final MailAddress SENDER = MailAddressFixture.ANY_AT_JAMES;
+    private static final Class<Map<String, byte[]>> MAP_STRING_BYTES_CLASS = (Class<Map<String, byte[]>>) (Object) Map.class;
 
     @Rule
     public ExpectedException expectedException = ExpectedException.none();
diff --git a/mailet/icalendar/src/test/java/org/apache/james/transport/mailets/ICalendarParserTest.java b/mailet/icalendar/src/test/java/org/apache/james/transport/mailets/ICalendarParserTest.java
index 8f15ddb..2c8cb0e 100644
--- a/mailet/icalendar/src/test/java/org/apache/james/transport/mailets/ICalendarParserTest.java
+++ b/mailet/icalendar/src/test/java/org/apache/james/transport/mailets/ICalendarParserTest.java
@@ -56,6 +56,7 @@ public class ICalendarParserTest {
         "END:VCALENDAR";
 
     private static final String WRONG_ICAL_VALUE = "anyValue";
+    public static final Class<Map<String, Calendar>> MAP_STRING_CALENDAR_CLASS = (Class<Map<String, Calendar>>) (Object) Map.class;
 
     @Rule
     public ExpectedException expectedException = ExpectedException.none();
@@ -224,11 +225,13 @@ public class ICalendarParserTest {
 
         mailet.service(mail);
 
-        Map<String, Calendar> expectedCalendars = (Map<String, Calendar>)mail.getAttribute(DESTINATION_CUSTOM_ATTRIBUTE);
+        Optional<Map<String, Calendar>> expectedCalendars = AttributeUtils.getValueAndCastFromMail(mail, DESTINATION_CUSTOM_ATTRIBUTE_NAME, MAP_STRING_CALENDAR_CLASS);
         Map.Entry<String, Calendar> expectedCalendar = Maps.immutableEntry("key2", new Calendar());
 
-        assertThat(expectedCalendars).hasSize(1)
-            .containsExactly(expectedCalendar);
+        assertThat(expectedCalendars).hasValueSatisfying(calendars ->
+            assertThat(calendars)
+                .hasSize(1)
+                .containsExactly(expectedCalendar));
     }
 
     @Test
@@ -256,7 +259,9 @@ public class ICalendarParserTest {
 
         mailet.service(mail);
 
-        Map<String, Calendar> expectedCalendars = (Map<String, Calendar>)mail.getAttribute(DESTINATION_CUSTOM_ATTRIBUTE);
-        assertThat(expectedCalendars).hasSize(1);
+        Optional<Map<String, Calendar>> expectedCalendars = AttributeUtils.getValueAndCastFromMail(mail, DESTINATION_CUSTOM_ATTRIBUTE_NAME, MAP_STRING_CALENDAR_CLASS);
+        assertThat(expectedCalendars).hasValueSatisfying(calendars ->
+                assertThat(calendars)
+                        .hasSize(1));
     }
 }
diff --git a/mailet/standard/src/main/java/org/apache/james/transport/mailets/AmqpForwardAttribute.java b/mailet/standard/src/main/java/org/apache/james/transport/mailets/AmqpForwardAttribute.java
index 750adc6..671dad1 100644
--- a/mailet/standard/src/main/java/org/apache/james/transport/mailets/AmqpForwardAttribute.java
+++ b/mailet/standard/src/main/java/org/apache/james/transport/mailets/AmqpForwardAttribute.java
@@ -20,13 +20,16 @@
 package org.apache.james.transport.mailets;
 
 import java.io.IOException;
-import java.io.Serializable;
 import java.nio.charset.StandardCharsets;
 import java.util.List;
 import java.util.Map;
+import java.util.Optional;
 import java.util.concurrent.TimeoutException;
 import java.util.stream.Stream;
 
+import org.apache.mailet.Attribute;
+import org.apache.mailet.AttributeName;
+import org.apache.mailet.AttributeValue;
 import org.apache.mailet.Mail;
 import org.apache.mailet.MailetException;
 import org.apache.mailet.base.GenericMailet;
@@ -69,7 +72,7 @@ public class AmqpForwardAttribute extends GenericMailet {
     public static final String ROUTING_KEY_DEFAULT_VALUE = "";
 
     private String exchange;
-    private String attribute;
+    private AttributeName attribute;
     private ConnectionFactory connectionFactory;
     @VisibleForTesting String routingKey;
 
@@ -86,11 +89,12 @@ public class AmqpForwardAttribute extends GenericMailet {
                     + " parameter was provided.");
         }
         routingKey = getInitParameter(ROUTING_KEY_PARAMETER_NAME, ROUTING_KEY_DEFAULT_VALUE);
-        attribute = getInitParameter(ATTRIBUTE_PARAMETER_NAME);
-        if (Strings.isNullOrEmpty(attribute)) {
+        String rawAttribute = getInitParameter(ATTRIBUTE_PARAMETER_NAME);
+        if (Strings.isNullOrEmpty(rawAttribute)) {
             throw new MailetException("No value for " + ATTRIBUTE_PARAMETER_NAME
                     + " parameter was provided.");
         }
+        attribute = AttributeName.of(rawAttribute);
         connectionFactory = new ConnectionFactory();
         try {
             connectionFactory.setUri(uri);
@@ -106,12 +110,34 @@ public class AmqpForwardAttribute extends GenericMailet {
 
     @Override
     public void service(Mail mail) throws MailetException {
-        if (mail.getAttribute(attribute) == null) {
-            return;
+        mail.getAttribute(attribute)
+            .map(Throwing.function(this::getAttributeContent).sneakyThrow())
+            .ifPresent(this::sendContent);
+    }
+
+    private Stream<byte[]> getAttributeContent(Attribute attribute) throws MailetException {
+        return extractAttributeValueContent(attribute.getValue().value())
+                .orElseThrow(() -> new MailetException("Invalid attribute found into attribute "
+                    + this.attribute.asString() + "class Map or List or String expected but "
+                    + attribute.toString() + " found."));
+    }
+
+    private Optional<Stream<byte[]>> extractAttributeValueContent(Object attributeContent) {
+        if (attributeContent instanceof Map) {
+            return Optional.of(((Map<String, byte[]>) attributeContent).values().stream());
         }
-        Stream<byte[]> content = getAttributeContent(mail);
+        if (attributeContent instanceof List) {
+            return Optional.of(((List<AttributeValue<byte[]>>) attributeContent).stream().map(AttributeValue::value));
+        }
+        if (attributeContent instanceof String) {
+            return Optional.of(Stream.of(((String) attributeContent).getBytes(StandardCharsets.UTF_8)));
+        }
+        return Optional.empty();
+    }
+
+    private void sendContent(Stream<byte[]> content) {
         try {
-            sendContent(content);
+            trySendContent(content);
         } catch (IOException e) {
             LOGGER.error("IOException while writing to AMQP: {}", e.getMessage(), e);
         } catch (TimeoutException e) {
@@ -121,24 +147,7 @@ public class AmqpForwardAttribute extends GenericMailet {
         }
     }
 
-    @SuppressWarnings("unchecked")
-    private Stream<byte[]> getAttributeContent(Mail mail) throws MailetException {
-        Serializable attributeContent = mail.getAttribute(attribute);
-        if (attributeContent instanceof Map) {
-            return ((Map<String, byte[]>) attributeContent).values().stream();
-        }
-        if (attributeContent instanceof List) {
-            return ((List<byte[]>) attributeContent).stream();
-        }
-        if (attributeContent instanceof String) {
-            return Stream.of(((String) attributeContent).getBytes(StandardCharsets.UTF_8));
-        }
-        throw new MailetException("Invalid attribute found into attribute "
-                + attribute + "class Map or List or String expected but "
-                + attributeContent.getClass() + " found.");
-    }
-
-    private void sendContent(Stream<byte[]> content) throws IOException, TimeoutException {
+    private void trySendContent(Stream<byte[]> content) throws IOException, TimeoutException {
         Connection connection = null;
         Channel channel = null;
         try {
diff --git a/mailet/standard/src/main/java/org/apache/james/transport/mailets/StripAttachment.java b/mailet/standard/src/main/java/org/apache/james/transport/mailets/StripAttachment.java
index c77f935..45d23ae 100644
--- a/mailet/standard/src/main/java/org/apache/james/transport/mailets/StripAttachment.java
+++ b/mailet/standard/src/main/java/org/apache/james/transport/mailets/StripAttachment.java
@@ -33,7 +33,9 @@ import java.util.Locale;
 import java.util.Map;
 import java.util.Optional;
 import java.util.UUID;
+import java.util.function.Function;
 import java.util.regex.Pattern;
+import java.util.stream.Collectors;
 
 import javax.mail.BodyPart;
 import javax.mail.Message;
@@ -48,6 +50,10 @@ import org.apache.commons.io.IOUtils;
 import org.apache.james.javax.MultipartUtil;
 import org.apache.james.mime4j.codec.DecodeMonitor;
 import org.apache.james.mime4j.codec.DecoderUtil;
+import org.apache.mailet.Attribute;
+import org.apache.mailet.AttributeName;
+import org.apache.mailet.AttributeUtils;
+import org.apache.mailet.AttributeValue;
 import org.apache.mailet.Mail;
 import org.apache.mailet.MailetException;
 import org.apache.mailet.base.GenericMailet;
@@ -86,6 +92,8 @@ import com.google.common.collect.ImmutableList;
 public class StripAttachment extends GenericMailet {
     private static final Logger LOGGER = LoggerFactory.getLogger(StripAttachment.class);
 
+    @SuppressWarnings("unchecked")
+    private static final Class<List<AttributeValue<String>>> LIST_OF_STRINGS = (Class<List<AttributeValue<String>>>)(Object) List.class;
     private static final String MULTIPART_MIME_TYPE = "multipart/*";
     public static final String PATTERN_PARAMETER_NAME = "pattern";
     public static final String NOTPATTERN_PARAMETER_NAME = "notpattern";
@@ -100,8 +108,8 @@ public class StripAttachment extends GenericMailet {
     public static final String REMOVE_NONE = "no";
     public static final String REMOVE_ALL = "all";
     public static final String REMOVE_MATCHED = "matched";
-    public static final String REMOVED_ATTACHMENTS_ATTRIBUTE_KEY = "org.apache.james.mailet.standard.mailets.StripAttachment.removed";
-    public static final String SAVED_ATTACHMENTS_ATTRIBUTE_KEY = "org.apache.james.mailet.standard.mailets.StripAttachment.saved";
+    public static final AttributeName REMOVED_ATTACHMENTS = AttributeName.of("org.apache.james.mailet.standard.mailets.StripAttachment.removed");
+    public static final AttributeName SAVED_ATTACHMENTS = AttributeName.of("org.apache.james.mailet.standard.mailets.StripAttachment.saved");
 
     public static final boolean DECODE_FILENAME_DEFAULT_VALUE = false;
 
@@ -314,7 +322,7 @@ public class StripAttachment extends GenericMailet {
                 shouldRemove = true;
             }
         }
-        storeFileNameAsAttribute(mail, fileName, shouldRemove);
+        storeFileNameAsAttribute(mail, AttributeValue.of(fileName), shouldRemove);
         return shouldRemove;
     }
 
@@ -324,21 +332,23 @@ public class StripAttachment extends GenericMailet {
 
     private void storeBodyPartAsFile(BodyPart bodyPart, Mail mail, String fileName) throws Exception {
         if (directoryName != null) {
-            Optional<String> filename = saveAttachmentToFile(bodyPart, Optional.of(fileName));
-            if (filename.isPresent()) {
-                addFilenameToAttribute(mail, filename.get(), SAVED_ATTACHMENTS_ATTRIBUTE_KEY);
-            }
+            saveAttachmentToFile(bodyPart, Optional.of(fileName)).ifPresent(filename ->
+                    addFilenameToAttribute(mail, AttributeValue.of(filename), SAVED_ATTACHMENTS)
+            );
         }
     }
 
-    private void addFilenameToAttribute(Mail mail, String filename, String attributeName) {
-        @SuppressWarnings("unchecked")
-        List<String> attributeValues = (List<String>) mail.getAttribute(attributeName);
-        if (attributeValues == null) {
-            attributeValues = new ArrayList<>();
-            mail.setAttribute(attributeName, (Serializable) attributeValues);
-        }
-        attributeValues.add(filename);
+    private void addFilenameToAttribute(Mail mail, AttributeValue<String> attributeValue, AttributeName attributeName) {
+        Function<List<AttributeValue<String>>, List<AttributeValue<?>>> typeWeakner = values ->
+                values.stream().map(value -> (AttributeValue<?>) value).collect(Collectors.toList());
+
+        ImmutableList.Builder<AttributeValue<?>> attributeValues = ImmutableList.<AttributeValue<?>>builder()
+                .addAll(AttributeUtils
+                    .getValueAndCastFromMail(mail, attributeName, LIST_OF_STRINGS)
+                    .map(typeWeakner)
+                    .orElse(new ArrayList<>()));
+        attributeValues.add(attributeValue);
+        mail.setAttribute(new Attribute(attributeName, AttributeValue.of(attributeValues.build())));
     }
 
     private void storeBodyPartAsMailAttribute(BodyPart bodyPart, Mail mail, String fileName) throws IOException, MessagingException {
@@ -359,9 +369,9 @@ public class StripAttachment extends GenericMailet {
         fileNamesToPartContent.put(fileName, byteArrayOutputStream.toByteArray());
     }
 
-    private void storeFileNameAsAttribute(Mail mail, String fileName, boolean hasToBeStored) {
+    private void storeFileNameAsAttribute(Mail mail, AttributeValue<String> fileName, boolean hasToBeStored) {
         if (hasToBeStored) {
-            addFilenameToAttribute(mail, fileName, REMOVED_ATTACHMENTS_ATTRIBUTE_KEY);
+            addFilenameToAttribute(mail, fileName, REMOVED_ATTACHMENTS);
         }
     }
 
diff --git a/mailet/standard/src/main/java/org/apache/james/transport/matchers/HasException.java b/mailet/standard/src/main/java/org/apache/james/transport/matchers/HasException.java
index 4fc5183..de73946 100644
--- a/mailet/standard/src/main/java/org/apache/james/transport/matchers/HasException.java
+++ b/mailet/standard/src/main/java/org/apache/james/transport/matchers/HasException.java
@@ -20,10 +20,13 @@
 package org.apache.james.transport.matchers;
 
 import java.util.Collection;
+import java.util.Optional;
 
 import javax.mail.MessagingException;
 
 import org.apache.james.core.MailAddress;
+import org.apache.mailet.Attribute;
+import org.apache.mailet.AttributeValue;
 import org.apache.mailet.Mail;
 import org.apache.mailet.base.GenericMatcher;
 
@@ -67,13 +70,15 @@ public class HasException extends GenericMatcher {
      */
     @Override
     public Collection<MailAddress> match(Mail mail) throws MessagingException {
-        Object exceptionValue = mail.getAttribute(Mail.MAILET_ERROR_ATTRIBUTE_NAME);
+        Optional<Attribute> exceptionValue = mail.getAttribute(Mail.MAILET_ERROR);
 
-        if (exceptionValue != null && exceptionClass.isAssignableFrom(exceptionValue.getClass())) {
-            return mail.getRecipients();
-        } else {
-            return ImmutableList.of();
-        }
+        return exceptionValue
+            .map(Attribute::getValue)
+            .map(AttributeValue::value)
+            .map(Object::getClass)
+            .filter(exceptionClass::isAssignableFrom)
+            .map(ignored -> mail.getRecipients())
+            .orElse(ImmutableList.of());
     }
 
     @Override
diff --git a/mailet/standard/src/main/java/org/apache/james/transport/matchers/SMTPAuthSuccessful.java b/mailet/standard/src/main/java/org/apache/james/transport/matchers/SMTPAuthSuccessful.java
index 2ef9a43..9e23a4e 100644
--- a/mailet/standard/src/main/java/org/apache/james/transport/matchers/SMTPAuthSuccessful.java
+++ b/mailet/standard/src/main/java/org/apache/james/transport/matchers/SMTPAuthSuccessful.java
@@ -47,11 +47,9 @@ public class SMTPAuthSuccessful extends GenericMatcher {
 
     @Override
     public Collection<MailAddress> match(Mail mail) {
-        String authUser = (String) mail.getAttribute(Mail.SMTP_AUTH_USER_ATTRIBUTE_NAME);
-        if (authUser != null) {
-            return mail.getRecipients();
-        } else {
-            return ImmutableList.of();
-        }
+        return mail
+            .getAttribute(Mail.SMTP_AUTH_USER)
+            .map(ignored -> mail.getRecipients())
+            .orElse(ImmutableList.of());
     }
 }
diff --git a/mailet/standard/src/main/java/org/apache/james/transport/matchers/SMTPAuthUserIs.java b/mailet/standard/src/main/java/org/apache/james/transport/matchers/SMTPAuthUserIs.java
index 3e2284b..89c00f1 100644
--- a/mailet/standard/src/main/java/org/apache/james/transport/matchers/SMTPAuthUserIs.java
+++ b/mailet/standard/src/main/java/org/apache/james/transport/matchers/SMTPAuthUserIs.java
@@ -25,6 +25,7 @@ import java.util.Collection;
 import java.util.StringTokenizer;
 
 import org.apache.james.core.MailAddress;
+import org.apache.mailet.AttributeUtils;
 import org.apache.mailet.Mail;
 import org.apache.mailet.base.GenericMatcher;
 
@@ -57,11 +58,10 @@ public class SMTPAuthUserIs extends GenericMatcher {
 
     @Override
     public Collection<MailAddress> match(Mail mail) {
-        String authUser = (String) mail.getAttribute(Mail.SMTP_AUTH_USER_ATTRIBUTE_NAME);
-        if (authUser != null && users.contains(authUser)) {
-            return mail.getRecipients();
-        } else {
-            return null;
-        }
+        return AttributeUtils
+            .getValueAndCastFromMail(mail, Mail.SMTP_AUTH_USER, String.class)
+            .filter(users::contains)
+            .map(ignored -> mail.getRecipients())
+            .orElse(null);
     }
 }
diff --git a/mailet/standard/src/test/java/org/apache/james/transport/mailets/AmqpForwardAttributeTest.java b/mailet/standard/src/test/java/org/apache/james/transport/mailets/AmqpForwardAttributeTest.java
index 6b959cf..c490b0f 100644
--- a/mailet/standard/src/test/java/org/apache/james/transport/mailets/AmqpForwardAttributeTest.java
+++ b/mailet/standard/src/test/java/org/apache/james/transport/mailets/AmqpForwardAttributeTest.java
@@ -29,10 +29,14 @@ import static org.mockito.Mockito.when;
 
 import java.io.IOException;
 import java.nio.charset.StandardCharsets;
+import java.util.Optional;
 import java.util.concurrent.TimeoutException;
 
 import javax.mail.MessagingException;
 
+import org.apache.mailet.Attribute;
+import org.apache.mailet.AttributeName;
+import org.apache.mailet.AttributeValue;
 import org.apache.mailet.Mail;
 import org.apache.mailet.MailetContext;
 import org.apache.mailet.MailetException;
@@ -56,12 +60,13 @@ import com.rabbitmq.client.ShutdownSignalException;
 
 class AmqpForwardAttributeTest {
 
-    private static final String MAIL_ATTRIBUTE = "ampq.attachments";
+    private static final AttributeName MAIL_ATTRIBUTE = AttributeName.of("ampq.attachments");
     private static final String EXCHANGE_NAME = "exchangeName";
     private static final String ROUTING_KEY = "routingKey";
     private static final String AMQP_URI = "amqp://host";
     private static final byte[] ATTACHMENT_CONTENT = "Attachment content".getBytes(StandardCharsets.UTF_8);
-    private static final ImmutableMap<String, byte[]> ATTRIBUTE_CONTENT = ImmutableMap.of("attachment1.txt", ATTACHMENT_CONTENT);
+    private static final ImmutableMap<String, byte[]> ATTRIBUTE_VALUE = ImmutableMap.of("attachment1.txt", ATTACHMENT_CONTENT);
+    private static final Optional<Attribute> ATTRIBUTE_CONTENT = Optional.of(new Attribute(MAIL_ATTRIBUTE, AttributeValue.ofAny(ATTRIBUTE_VALUE)));
 
     private AmqpForwardAttribute mailet;
     private MailetContext mailetContext;
@@ -80,7 +85,7 @@ class AmqpForwardAttributeTest {
                 .setProperty("uri", AMQP_URI)
                 .setProperty("exchange", EXCHANGE_NAME)
                 .setProperty("routing_key", ROUTING_KEY)
-                .setProperty("attribute", MAIL_ATTRIBUTE)
+                .setProperty("attribute", MAIL_ATTRIBUTE.asString())
                 .build();
     }
 
@@ -124,7 +129,7 @@ class AmqpForwardAttributeTest {
                 .mailetContext(mailetContext)
                 .setProperty("uri", "bad-uri")
                 .setProperty("exchange", EXCHANGE_NAME)
-                .setProperty("attribute", MAIL_ATTRIBUTE)
+                .setProperty("attribute", MAIL_ATTRIBUTE.asString())
                 .build();
         assertThatThrownBy(() -> mailet.init(customMailetConfig))
             .isInstanceOf(MailetException.class);
@@ -142,7 +147,7 @@ class AmqpForwardAttributeTest {
                 .mailetContext(mailetContext)
                 .setProperty("uri", AMQP_URI)
                 .setProperty("exchange", EXCHANGE_NAME)
-                .setProperty("attribute", MAIL_ATTRIBUTE)
+                .setProperty("attribute", MAIL_ATTRIBUTE.asString())
                 .build();
         mailet.init(customMailetConfig);
 
@@ -162,7 +167,7 @@ class AmqpForwardAttributeTest {
         when(connectionFactory.newConnection()).thenReturn(connection);
         mailet.setConnectionFactory(connectionFactory);
         Mail mail = mock(Mail.class);
-        when(mail.getAttribute(MAIL_ATTRIBUTE)).thenReturn(null);
+        when(mail.getAttribute(MAIL_ATTRIBUTE)).thenReturn(Optional.empty());
 
         mailet.service(mail);
 
@@ -173,7 +178,7 @@ class AmqpForwardAttributeTest {
     public void serviceShouldThrowWhenAttributeContentIsNotAMapAListOrAString() throws MessagingException {
         mailet.init(mailetConfig);
         Mail mail = mock(Mail.class);
-        when(mail.getAttribute(MAIL_ATTRIBUTE)).thenReturn(2);
+        when(mail.getAttribute(MAIL_ATTRIBUTE)).thenReturn(Optional.of(new Attribute(MAIL_ATTRIBUTE, AttributeValue.of(2))));
 
         assertThatThrownBy(() -> mailet.service(mail))
             .isInstanceOf(MailetException.class);
@@ -246,7 +251,7 @@ class AmqpForwardAttributeTest {
         when(connectionFactory.newConnection()).thenReturn(connection);
         mailet.setConnectionFactory(connectionFactory);
         Mail mail = mock(Mail.class);
-        when(mail.getAttribute(MAIL_ATTRIBUTE)).thenReturn(ImmutableList.of(ATTACHMENT_CONTENT));
+        when(mail.getAttribute(MAIL_ATTRIBUTE)).thenReturn(Optional.of(new Attribute(MAIL_ATTRIBUTE, AttributeValue.of(ImmutableList.of(AttributeValue.ofSerializable(ATTACHMENT_CONTENT))))));
         BasicProperties expectedProperties = new AMQP.BasicProperties();
 
         mailet.service(mail);
@@ -267,7 +272,7 @@ class AmqpForwardAttributeTest {
         mailet.setConnectionFactory(connectionFactory);
         Mail mail = mock(Mail.class);
         String content = "Attachment content";
-        when(mail.getAttribute(MAIL_ATTRIBUTE)).thenReturn(content);
+        when(mail.getAttribute(MAIL_ATTRIBUTE)).thenReturn(Optional.of(new Attribute(MAIL_ATTRIBUTE, AttributeValue.of(content))));
         BasicProperties expectedProperties = new AMQP.BasicProperties();
 
         mailet.service(mail);
diff --git a/mailet/standard/src/test/java/org/apache/james/transport/mailets/ContactExtractorTest.java b/mailet/standard/src/test/java/org/apache/james/transport/mailets/ContactExtractorTest.java
index 83b9ddb..fdfe437 100644
--- a/mailet/standard/src/test/java/org/apache/james/transport/mailets/ContactExtractorTest.java
+++ b/mailet/standard/src/test/java/org/apache/james/transport/mailets/ContactExtractorTest.java
@@ -30,6 +30,7 @@ import javax.mail.internet.MimeMessage;
 
 import org.apache.james.core.builder.MimeMessageBuilder;
 import org.apache.james.util.MimeMessageUtil;
+import org.apache.mailet.AttributeName;
 import org.apache.mailet.MailetContext;
 import org.apache.mailet.MailetException;
 import org.apache.mailet.base.test.FakeMail;
@@ -44,7 +45,7 @@ import com.fasterxml.jackson.databind.ObjectMapper;
 
 public class ContactExtractorTest {
 
-    private static final String ATTRIBUTE = "ExtractedContacts";
+    private static final AttributeName ATTRIBUTE_NAME = AttributeName.of("ExtractedContacts");
     private static final String SENDER = "sender@james.org";
     private static final String TO = "to@james.org";
 
@@ -60,7 +61,7 @@ public class ContactExtractorTest {
         mailetConfig = FakeMailetConfig.builder()
                 .mailetName("Test")
                 .mailetContext(mailetContext)
-                .setProperty(ContactExtractor.Configuration.ATTRIBUTE, ATTRIBUTE)
+                .setProperty(ContactExtractor.Configuration.ATTRIBUTE, ATTRIBUTE_NAME.asString())
                 .build();
     }
 
@@ -119,7 +120,8 @@ public class ContactExtractorTest {
         String expectedMessage = "{\"userEmail\" : \"" + SENDER + "\", \"emails\" : [ \"" + TO + "\" ]}";
         mailet.service(mail);
 
-        assertThatJson(mail.getAttribute(ATTRIBUTE).toString()).isEqualTo(expectedMessage);
+        assertThat(mail.getAttribute(ATTRIBUTE_NAME)).hasValueSatisfying(json ->
+            assertThatJson(json.getValue().value().toString()).isEqualTo(expectedMessage));
     }
 
     @Test
@@ -138,7 +140,8 @@ public class ContactExtractorTest {
         String expectedMessage = "{\"userEmail\" : \"" + SENDER + "\", \"emails\" : [ \"To <" + TO + ">\" ]}";
         mailet.service(mail);
 
-        assertThatJson(mail.getAttribute(ATTRIBUTE).toString()).isEqualTo(expectedMessage);
+        assertThat(mail.getAttribute(ATTRIBUTE_NAME)).hasValueSatisfying(json ->
+                assertThatJson(json.getValue().value().toString()).isEqualTo(expectedMessage));
     }
 
     @Test
@@ -157,7 +160,8 @@ public class ContactExtractorTest {
         String expectedMessage = "{\"userEmail\" : \"" + SENDER + "\", \"emails\" : [ \"Benoît TELLIER <te...@linagora.com>\" ]}";
         mailet.service(mail);
 
-        assertThatJson(mail.getAttribute(ATTRIBUTE).toString()).isEqualTo(expectedMessage);
+        assertThat(mail.getAttribute(ATTRIBUTE_NAME)).hasValueSatisfying(json ->
+                assertThatJson(json.getValue().value().toString()).isEqualTo(expectedMessage));
     }
 
     @Test
@@ -177,7 +181,8 @@ public class ContactExtractorTest {
         String expectedMessage = "{\"userEmail\" : \"" + SENDER + "\", \"emails\" : [ \"\\\"recip >> Frédéric RECIPIENT\\\" <fr...@example.com>\" ]}";
         mailet.service(mail);
 
-        assertThatJson(mail.getAttribute(ATTRIBUTE).toString()).isEqualTo(expectedMessage);
+        assertThat(mail.getAttribute(ATTRIBUTE_NAME)).hasValueSatisfying(json ->
+                assertThatJson(json.getValue().value().toString()).isEqualTo(expectedMessage));
     }
 
     @Test
@@ -197,7 +202,8 @@ public class ContactExtractorTest {
         String expectedMessage = "{\"userEmail\" : \"" + SENDER + "\", \"emails\" : [ \"User 1 <us...@example.com>\", \"\\\"recip >> Frédéric RECIPIENT\\\" <fr...@example.com>\" ]}";
         mailet.service(mail);
 
-        assertThatJson(mail.getAttribute(ATTRIBUTE).toString()).isEqualTo(expectedMessage);
+        assertThat(mail.getAttribute(ATTRIBUTE_NAME)).hasValueSatisfying(json ->
+                assertThatJson(json.getValue().value().toString()).isEqualTo(expectedMessage));
     }
 
     @Test
@@ -217,7 +223,8 @@ public class ContactExtractorTest {
         String expectedMessage = "{\"userEmail\" : \"" + SENDER + "\", \"emails\" : [ \"\\\"User, the first one\\\" <us...@example.com>\" ]}";
         mailet.service(mail);
 
-        assertThatJson(mail.getAttribute(ATTRIBUTE).toString()).isEqualTo(expectedMessage);
+        assertThat(mail.getAttribute(ATTRIBUTE_NAME)).hasValueSatisfying(json ->
+                assertThatJson(json.getValue().value().toString()).isEqualTo(expectedMessage));
     }
 
     @Test
@@ -236,7 +243,8 @@ public class ContactExtractorTest {
         String expectedMessage = "{\"userEmail\" : \"" + SENDER + "\", \"emails\" : [ \"To <" + TO + ">\" ]}";
         mailet.service(mail);
 
-        assertThatJson(mail.getAttribute(ATTRIBUTE).toString()).isEqualTo(expectedMessage);
+        assertThat(mail.getAttribute(ATTRIBUTE_NAME)).hasValueSatisfying(json ->
+                assertThatJson(json.getValue().value().toString()).isEqualTo(expectedMessage));
     }
 
     @Test
@@ -255,7 +263,8 @@ public class ContactExtractorTest {
         String expectedMessage = "{\"userEmail\" : \"" + SENDER + "\", \"emails\" : [ \"To <" + TO + ">\" ]}";
         mailet.service(mail);
 
-        assertThatJson(mail.getAttribute(ATTRIBUTE).toString()).isEqualTo(expectedMessage);
+        assertThat(mail.getAttribute(ATTRIBUTE_NAME)).hasValueSatisfying(json ->
+                assertThatJson(json.getValue().value().toString()).isEqualTo(expectedMessage));
     }
 
     @Test
@@ -271,7 +280,8 @@ public class ContactExtractorTest {
 
         mailet.service(mail);
 
-        assertThatJson(mail.getAttribute(ATTRIBUTE)).isEqualTo(null);
+        assertThat(mail.getAttribute(ATTRIBUTE_NAME))
+            .isEmpty();
     }
 
     @Test
@@ -287,7 +297,8 @@ public class ContactExtractorTest {
 
         mailet.service(mail);
 
-        assertThat(mail.getAttribute(ATTRIBUTE)).isNull();
+        assertThat(mail.getAttribute(ATTRIBUTE_NAME))
+            .isEmpty();
     }
 
     @Test
diff --git a/mailet/standard/src/test/java/org/apache/james/transport/mailets/MailAttributesToMimeHeadersTest.java b/mailet/standard/src/test/java/org/apache/james/transport/mailets/MailAttributesToMimeHeadersTest.java
index 3b9e845..deef219 100644
--- a/mailet/standard/src/test/java/org/apache/james/transport/mailets/MailAttributesToMimeHeadersTest.java
+++ b/mailet/standard/src/test/java/org/apache/james/transport/mailets/MailAttributesToMimeHeadersTest.java
@@ -25,6 +25,9 @@ import static org.assertj.core.api.Assertions.assertThatThrownBy;
 import javax.mail.MessagingException;
 
 import org.apache.james.core.builder.MimeMessageBuilder;
+import org.apache.mailet.Attribute;
+import org.apache.mailet.AttributeName;
+import org.apache.mailet.AttributeValue;
 import org.apache.mailet.Mailet;
 import org.apache.mailet.base.test.FakeMail;
 import org.apache.mailet.base.test.FakeMailetConfig;
@@ -39,11 +42,13 @@ class MailAttributesToMimeHeadersTest {
     private static final String HEADER_NAME1 = "JUNIT";
     private static final String HEADER_NAME2 = "JUNIT2";
 
-    private static final String MAIL_ATTRIBUTE_VALUE1 = "test1";
-    private static final String MAIL_ATTRIBUTE_VALUE2 = "test2";
+    private static final AttributeName MAIL_ATTRIBUTE_NAME1 = AttributeName.of("org.apache.james.test");
+    private static final AttributeValue<String> MAIL_ATTRIBUTE_VALUE1 = AttributeValue.of("test1");
+    private static final Attribute MAIL_ATTRIBUTE1 = new Attribute(MAIL_ATTRIBUTE_NAME1, MAIL_ATTRIBUTE_VALUE1);
 
-    private static final String MAIL_ATTRIBUTE_NAME1 = "org.apache.james.test";
-    private static final String MAIL_ATTRIBUTE_NAME2 = "org.apache.james.test2";
+    private static final AttributeName MAIL_ATTRIBUTE_NAME2 = AttributeName.of("org.apache.james.test2");
+    private static final AttributeValue<String> MAIL_ATTRIBUTE_VALUE2 = AttributeValue.of("test2");
+    private static final Attribute MAIL_ATTRIBUTE2 = new Attribute(MAIL_ATTRIBUTE_NAME2, MAIL_ATTRIBUTE_VALUE2);
 
     @BeforeEach
     void setup() {
@@ -76,16 +81,16 @@ class MailAttributesToMimeHeadersTest {
         FakeMailetConfig mailetConfig = FakeMailetConfig.builder()
             .mailetName("Test")
             .setProperty("simplemapping",
-                MAIL_ATTRIBUTE_NAME1 + "; " + HEADER_NAME1 +
-                    "," + MAIL_ATTRIBUTE_NAME2 + "; " + HEADER_NAME2 +
+                MAIL_ATTRIBUTE_NAME1.asString() + "; " + HEADER_NAME1 +
+                    "," + MAIL_ATTRIBUTE_NAME2.asString() + "; " + HEADER_NAME2 +
                     "," + "another.attribute" + "; " + "Another-Header")
             .build();
 
         mailet.init(mailetConfig);
 
         FakeMail mockedMail = MailUtil.createMockMail2Recipients(MailUtil.createMimeMessage());
-        mockedMail.setAttribute(MAIL_ATTRIBUTE_NAME1, MAIL_ATTRIBUTE_VALUE1);
-        mockedMail.setAttribute(MAIL_ATTRIBUTE_NAME2, MAIL_ATTRIBUTE_VALUE2);
+        mockedMail.setAttribute(MAIL_ATTRIBUTE1);
+        mockedMail.setAttribute(MAIL_ATTRIBUTE2);
 
         mailet.service(mockedMail);
         assertThat(mockedMail.getMessage().getHeader("another.attribute")).isNull();
@@ -96,16 +101,16 @@ class MailAttributesToMimeHeadersTest {
         FakeMailetConfig mailetConfig = FakeMailetConfig.builder()
             .mailetName("Test")
             .setProperty("simplemapping",
-                MAIL_ATTRIBUTE_NAME1 + "; " + HEADER_NAME1)
+                MAIL_ATTRIBUTE_NAME1.asString() + "; " + HEADER_NAME1)
             .build();
 
         mailet.init(mailetConfig);
 
         FakeMail mockedMail = MailUtil.createMockMail2Recipients(MailUtil.createMimeMessage());
-        mockedMail.setAttribute(MAIL_ATTRIBUTE_NAME1, MAIL_ATTRIBUTE_VALUE1);
+        mockedMail.setAttribute(MAIL_ATTRIBUTE1);
 
         mailet.service(mockedMail);
-        assertThat(mockedMail.getMessage().getHeader(HEADER_NAME1)).containsExactly(MAIL_ATTRIBUTE_VALUE1);
+        assertThat(mockedMail.getMessage().getHeader(HEADER_NAME1)).containsExactly(MAIL_ATTRIBUTE_VALUE1.value());
     }
 
     @Test
@@ -113,39 +118,39 @@ class MailAttributesToMimeHeadersTest {
         FakeMailetConfig mailetConfig = FakeMailetConfig.builder()
                 .mailetName("Test")
                 .setProperty("simplemapping", 
-                        MAIL_ATTRIBUTE_NAME1 + "; " + HEADER_NAME1 +
-                        "," + MAIL_ATTRIBUTE_NAME2 + "; " + HEADER_NAME2 + 
+                        MAIL_ATTRIBUTE_NAME1.asString() + "; " + HEADER_NAME1 +
+                        "," + MAIL_ATTRIBUTE_NAME2.asString() + "; " + HEADER_NAME2 +
                         "," + "another.attribute" + "; " + "Another-Header")
                 .build();
         mailet.init(mailetConfig);
         
         FakeMail mockedMail = MailUtil.createMockMail2Recipients(MailUtil.createMimeMessage());
-        mockedMail.setAttribute(MAIL_ATTRIBUTE_NAME1, MAIL_ATTRIBUTE_VALUE1);
-        mockedMail.setAttribute(MAIL_ATTRIBUTE_NAME2, MAIL_ATTRIBUTE_VALUE2);
-        mockedMail.setAttribute("unmatched.attribute", "value");
+        mockedMail.setAttribute(MAIL_ATTRIBUTE1);
+        mockedMail.setAttribute(MAIL_ATTRIBUTE2);
+        mockedMail.setAttribute(Attribute.convertToAttribute("unmatched.attribute", "value"));
 
         mailet.service(mockedMail);
 
-        assertThat(mockedMail.getMessage().getHeader(HEADER_NAME1)).containsExactly(MAIL_ATTRIBUTE_VALUE1);
-        assertThat(mockedMail.getMessage().getHeader(HEADER_NAME2)).containsExactly(MAIL_ATTRIBUTE_VALUE2);
+        assertThat(mockedMail.getMessage().getHeader(HEADER_NAME1)).containsExactly(MAIL_ATTRIBUTE_VALUE1.value());
+        assertThat(mockedMail.getMessage().getHeader(HEADER_NAME2)).containsExactly(MAIL_ATTRIBUTE_VALUE2.value());
     }
 
     @Test
     void shouldAddAttributeIntoHeadersWhenHeaderAlreadyPresent() throws MessagingException {
         FakeMailetConfig mailetConfig = FakeMailetConfig.builder()
                 .mailetName("Test")
-                .setProperty("simplemapping", MAIL_ATTRIBUTE_NAME1 + "; " + HEADER_NAME1)
+                .setProperty("simplemapping", MAIL_ATTRIBUTE_NAME1.asString() + "; " + HEADER_NAME1)
                 .build();
         mailet.init(mailetConfig);
 
         FakeMail mockedMail = MailUtil.createMockMail2Recipients(MimeMessageBuilder.mimeMessageBuilder()
             .addHeader(HEADER_NAME1, "first value")
             .build());
-        mockedMail.setAttribute(MAIL_ATTRIBUTE_NAME1, MAIL_ATTRIBUTE_VALUE1);
+        mockedMail.setAttribute(MAIL_ATTRIBUTE1);
         
         mailet.service(mockedMail);
 
-        assertThat(mockedMail.getMessage().getHeader(HEADER_NAME1)).containsExactly("first value", MAIL_ATTRIBUTE_VALUE1);
+        assertThat(mockedMail.getMessage().getHeader(HEADER_NAME1)).containsExactly("first value", MAIL_ATTRIBUTE_VALUE1.value());
     }
 
     
diff --git a/mailet/standard/src/test/java/org/apache/james/transport/mailets/MimeDecodingMailetTest.java b/mailet/standard/src/test/java/org/apache/james/transport/mailets/MimeDecodingMailetTest.java
index dc62744..685c375 100644
--- a/mailet/standard/src/test/java/org/apache/james/transport/mailets/MimeDecodingMailetTest.java
+++ b/mailet/standard/src/test/java/org/apache/james/transport/mailets/MimeDecodingMailetTest.java
@@ -24,9 +24,14 @@ import static org.mockito.Mockito.mock;
 
 import java.nio.charset.StandardCharsets;
 import java.util.Map;
+import java.util.Optional;
 
 import javax.mail.MessagingException;
 
+import org.apache.mailet.Attribute;
+import org.apache.mailet.AttributeName;
+import org.apache.mailet.AttributeUtils;
+import org.apache.mailet.AttributeValue;
 import org.apache.mailet.MailetContext;
 import org.apache.mailet.MailetException;
 import org.apache.mailet.base.test.FakeMail;
@@ -42,7 +47,8 @@ import com.google.common.collect.ImmutableMap;
 
 class MimeDecodingMailetTest {
 
-    private static final String MAIL_ATTRIBUTE = "mime.attachments";
+    private static final AttributeName MAIL_ATTRIBUTE = AttributeName.of("mime.attachments");
+    private static final Class<Map<String, byte[]>> MAP_STRING_BYTES_CLASS = (Class<Map<String, byte[]>>) (Object) Map.class;
 
     private MailetContext mailetContext;
     private MimeDecodingMailet testee;
@@ -82,12 +88,12 @@ class MimeDecodingMailetTest {
         FakeMailetConfig mailetConfig = FakeMailetConfig.builder()
                 .mailetName("Test")
                 .mailetContext(mailetContext)
-                .setProperty(MimeDecodingMailet.ATTRIBUTE_PARAMETER_NAME, MAIL_ATTRIBUTE)
+                .setProperty(MimeDecodingMailet.ATTRIBUTE_PARAMETER_NAME, MAIL_ATTRIBUTE.asString())
                 .build();
         testee.init(mailetConfig);
 
         FakeMail mail = FakeMail.defaultFakeMail();
-        mail.setAttribute(MAIL_ATTRIBUTE, ImmutableList.of());
+        mail.setAttribute(new Attribute(MAIL_ATTRIBUTE, AttributeValue.of(ImmutableList.of())));
 
         testee.service(mail);
     }
@@ -97,12 +103,13 @@ class MimeDecodingMailetTest {
         FakeMailetConfig mailetConfig = FakeMailetConfig.builder()
                 .mailetName("Test")
                 .mailetContext(mailetContext)
-                .setProperty(MimeDecodingMailet.ATTRIBUTE_PARAMETER_NAME, MAIL_ATTRIBUTE)
+                .setProperty(MimeDecodingMailet.ATTRIBUTE_PARAMETER_NAME, MAIL_ATTRIBUTE.asString())
                 .build();
         testee.init(mailetConfig);
 
         FakeMail mail = FakeMail.defaultFakeMail();
-        mail.setAttribute(MAIL_ATTRIBUTE, ImmutableMap.of("1", "2"));
+        AttributeValue<Map<String, AttributeValue<?>>> value = AttributeValue.of(ImmutableMap.of("1", AttributeValue.of("2")));
+        mail.setAttribute(new Attribute(MAIL_ATTRIBUTE, value));
 
         testee.service(mail);
     }
@@ -112,14 +119,14 @@ class MimeDecodingMailetTest {
         FakeMailetConfig mailetConfig = FakeMailetConfig.builder()
                 .mailetName("Test")
                 .mailetContext(mailetContext)
-                .setProperty(MimeDecodingMailet.ATTRIBUTE_PARAMETER_NAME, MAIL_ATTRIBUTE)
+                .setProperty(MimeDecodingMailet.ATTRIBUTE_PARAMETER_NAME, MAIL_ATTRIBUTE.asString())
                 .build();
         testee.init(mailetConfig);
 
         FakeMail mail = FakeMail.defaultFakeMail();
 
         testee.service(mail);
-        assertThat(mail.getAttribute(MAIL_ATTRIBUTE)).isNull();
+        assertThat(mail.getAttribute(MAIL_ATTRIBUTE)).isEmpty();
     }
 
     @Test
@@ -128,7 +135,7 @@ class MimeDecodingMailetTest {
         FakeMailetConfig mailetConfig = FakeMailetConfig.builder()
                 .mailetName("Test")
                 .mailetContext(mailetContext)
-                .setProperty(MimeDecodingMailet.ATTRIBUTE_PARAMETER_NAME, MAIL_ATTRIBUTE)
+                .setProperty(MimeDecodingMailet.ATTRIBUTE_PARAMETER_NAME, MAIL_ATTRIBUTE.asString())
                 .build();
         testee.init(mailetConfig);
 
@@ -138,12 +145,15 @@ class MimeDecodingMailetTest {
                 + "Content-Type: application/octet-stream; charset=utf-8\r\n\r\n"
                 + text;
         String expectedKey = "mimePart1";
-        mail.setAttribute(MAIL_ATTRIBUTE, ImmutableMap.of(expectedKey, content.getBytes(StandardCharsets.UTF_8)));
+        AttributeValue<?> value = AttributeValue.ofAny(ImmutableMap.of(expectedKey, content.getBytes(StandardCharsets.UTF_8)));
+        mail.setAttribute(new Attribute(MAIL_ATTRIBUTE, value));
 
         byte[] expectedValue = text.getBytes(StandardCharsets.UTF_8);
         testee.service(mail);
 
-        Map<String, byte[]> processedAttribute = (Map<String, byte[]>) mail.getAttribute(MAIL_ATTRIBUTE);
-        assertThat(processedAttribute).containsExactly(MapEntry.entry(expectedKey, expectedValue));
+        Optional<Map<String, byte[]>> processedAttribute = AttributeUtils.getValueAndCastFromMail(mail, MAIL_ATTRIBUTE, MAP_STRING_BYTES_CLASS);
+        assertThat(processedAttribute).hasValueSatisfying(map ->
+            assertThat(map)
+                .containsExactly(MapEntry.entry(expectedKey, expectedValue)));
     }
 }
diff --git a/mailet/standard/src/test/java/org/apache/james/transport/mailets/SetMailAttributeTest.java b/mailet/standard/src/test/java/org/apache/james/transport/mailets/SetMailAttributeTest.java
index 7edd609..4556744 100644
--- a/mailet/standard/src/test/java/org/apache/james/transport/mailets/SetMailAttributeTest.java
+++ b/mailet/standard/src/test/java/org/apache/james/transport/mailets/SetMailAttributeTest.java
@@ -85,18 +85,21 @@ class SetMailAttributeTest {
     
     @Test
     void shouldOverwriteAttributeWhenAttributeAlreadyPresent() throws MessagingException {
+        AttributeName name = AttributeName.of("org.apache.james.junit1");
+        Attribute mailAttribute = new Attribute(name, AttributeValue.of("foo"));
+        Attribute replacedAttribute = new Attribute(name, AttributeValue.of("bar"));
         FakeMailetConfig mailetConfig = FakeMailetConfig.builder()
                 .mailetName("Test")
-                .setProperty("org.apache.james.junit1", "bar")
+                .setProperty(name.asString(), (String) replacedAttribute.getValue().value())
                 .build();
         
         mailet.init(mailetConfig);
         
         Mail mail = MailUtil.createMockMail2Recipients(MimeMessageUtil.defaultMimeMessage());
-        mail.setAttribute("org.apache.james.junit1", "foo");
+        mail.setAttribute(mailAttribute);
         
         mailet.service(mail);
 
-        assertThat(mail.getAttribute("org.apache.james.junit1")).isEqualTo("bar");
+        assertThat(mail.getAttribute(name)).contains(replacedAttribute);
     }
 }
diff --git a/mailet/standard/src/test/java/org/apache/james/transport/mailets/StripAttachmentTest.java b/mailet/standard/src/test/java/org/apache/james/transport/mailets/StripAttachmentTest.java
index aefc067..36da780 100644
--- a/mailet/standard/src/test/java/org/apache/james/transport/mailets/StripAttachmentTest.java
+++ b/mailet/standard/src/test/java/org/apache/james/transport/mailets/StripAttachmentTest.java
@@ -29,7 +29,6 @@ import java.io.File;
 import java.io.IOException;
 import java.nio.charset.StandardCharsets;
 import java.util.Collection;
-import java.util.List;
 import java.util.Map;
 import java.util.Optional;
 
@@ -40,22 +39,31 @@ import javax.mail.internet.MimeBodyPart;
 import javax.mail.internet.MimeMessage;
 import javax.mail.internet.MimeMultipart;
 
+import com.github.fge.lambdas.Throwing;
+import com.github.fge.lambdas.consumers.ConsumerChainer;
 import org.apache.commons.io.IOUtils;
 import org.apache.james.core.builder.MimeMessageBuilder;
 import org.apache.james.junit.TemporaryFolderExtension;
 import org.apache.james.junit.TemporaryFolderExtension.TemporaryFolder;
 import org.apache.james.transport.mailets.StripAttachment.OutputFileName;
+import org.apache.mailet.AttributeName;
+import org.apache.mailet.AttributeUtils;
+import org.apache.mailet.AttributeValue;
 import org.apache.mailet.Mail;
 import org.apache.mailet.Mailet;
 import org.apache.mailet.MailetException;
 import org.apache.mailet.base.test.FakeMail;
 import org.apache.mailet.base.test.FakeMailetConfig;
+import org.assertj.core.api.Assertions;
 import org.junit.jupiter.api.Test;
 import org.junit.jupiter.api.extension.ExtendWith;
 
 @ExtendWith(TemporaryFolderExtension.class)
 class StripAttachmentTest {
 
+    private static Class<Collection<AttributeValue<String>>> COLLECTION_STRING_CLASS = (Class<Collection<AttributeValue<String>>>) (Object) Collection.class;
+    private static Class<Map<String, byte[]>> MAP_STRING_BYTES_CLASS = (Class<Map<String, byte[]>>) (Object) Map.class;
+
     private static final String EXPECTED_ATTACHMENT_CONTENT = "#¤ãàé";
     private static final Optional<String> ABSENT_MIME_TYPE = Optional.empty();
     private static final String CONTENT_TRANSFER_ENCODING_VALUE = "8bit";
@@ -117,14 +125,15 @@ class StripAttachmentTest {
 
         mailet.service(mail);
 
-        @SuppressWarnings("unchecked")
-        Collection<String> savedAttachments = (Collection<String>) mail.getAttribute(StripAttachment.SAVED_ATTACHMENTS_ATTRIBUTE_KEY);
-        assertThat(savedAttachments).isNotNull();
-        assertThat(savedAttachments).hasSize(1);
-
-        String attachmentFilename = savedAttachments.iterator().next();
+        Optional<Collection<AttributeValue<String>>> savedAttachments = AttributeUtils.getValueAndCastFromMail(mail, StripAttachment.SAVED_ATTACHMENTS, COLLECTION_STRING_CLASS);
+        assertThat(savedAttachments)
+            .isPresent()
+            .hasValueSatisfying(attachments -> {
+                assertThat(attachments).hasSize(1);
 
-        assertThat(new File(temporaryFolder.getFolderPath() + attachmentFilename)).hasContent(expectedAttachmentContent);
+                String attachmentFilename = attachments.iterator().next().value();
+                assertThat(new File(temporaryFolder.getFolderPath() + attachmentFilename)).hasContent(expectedAttachmentContent);
+            });
     }
 
     @Test
@@ -151,9 +160,11 @@ class StripAttachmentTest {
 
         mailet.service(mail);
 
-        @SuppressWarnings("unchecked")
-        List<String> removedAttachments = (List<String>) mail.getAttribute(StripAttachment.REMOVED_ATTACHMENTS_ATTRIBUTE_KEY);
-        assertThat(removedAttachments).containsOnly(expectedFileName);
+        Optional<Collection<AttributeValue<String>>> removedAttachments = AttributeUtils.getValueAndCastFromMail(mail, StripAttachment.REMOVED_ATTACHMENTS, COLLECTION_STRING_CLASS);
+        assertThat(removedAttachments)
+            .isPresent()
+            .hasValueSatisfying(attachments ->
+                assertThat(attachments).containsOnly(AttributeValue.of(expectedFileName)));
     }
 
     private MimeMessageBuilder.BodyPartBuilder createAttachmentBodyPart(String body, String fileName, MimeMessageBuilder.Header... headers) {
@@ -188,18 +199,21 @@ class StripAttachmentTest {
 
         mailet.service(mail);
 
-        @SuppressWarnings("unchecked")
-        Collection<String> savedAttachments = (Collection<String>) mail.getAttribute(StripAttachment.SAVED_ATTACHMENTS_ATTRIBUTE_KEY);
-        assertThat(savedAttachments).isNotNull();
-        assertThat(savedAttachments).hasSize(2);
+        Optional<Collection<AttributeValue<String>>> savedAttachments = AttributeUtils.getValueAndCastFromMail(mail, StripAttachment.SAVED_ATTACHMENTS, COLLECTION_STRING_CLASS);
+        assertThat(savedAttachments)
+            .isPresent()
+            .hasValueSatisfying(attachments -> {
+                assertThat(attachments).hasSize(2);
 
-        String attachmentFilename = retrieveFilenameStartingWith(savedAttachments, "temp_filname");
-        assertThat(attachmentFilename).isNotNull();
-        assertThat(new File(temporaryFolder.getFolderPath() + attachmentFilename)).hasContent(expectedAttachmentContent);
+                String attachmentFilename = retrieveFilenameStartingWith(attachments, "temp_filname");
+                assertThat(attachmentFilename).isNotNull();
+                assertThat(new File(temporaryFolder.getFolderPath() + attachmentFilename)).hasContent(expectedAttachmentContent);
+            });
     }
 
-    private String retrieveFilenameStartingWith(Collection<String> savedAttachments, String filename) {
+    private String retrieveFilenameStartingWith(Collection<AttributeValue<String>> savedAttachments, String filename) {
         return savedAttachments.stream()
+                .map(AttributeValue::value)
                 .filter(attachmentFilename -> attachmentFilename.startsWith(filename))
                 .findFirst()
                 .get();
@@ -222,16 +236,19 @@ class StripAttachmentTest {
 
         mailet.service(mail);
 
-        @SuppressWarnings("unchecked")
-        Collection<String> savedAttachments = (Collection<String>) mail.getAttribute(StripAttachment.SAVED_ATTACHMENTS_ATTRIBUTE_KEY);
-        assertThat(savedAttachments).isNotNull();
-        assertThat(savedAttachments).hasSize(1);
+        Optional<Collection<AttributeValue<String>>> savedAttachments = AttributeUtils.getValueAndCastFromMail(mail, StripAttachment.SAVED_ATTACHMENTS, COLLECTION_STRING_CLASS);
+        assertThat(savedAttachments)
+            .isPresent()
+            .hasValueSatisfying(attachments -> {
+                assertThat(attachments).hasSize(1);
 
-        String name = savedAttachments.iterator().next();
+                String name = attachments.iterator().next().value();
+
+                assertThat(name.startsWith("e_Pubblicita_e_vietata_Milano9052")).isTrue();
+
+                assertThat(new File(temporaryFolder.getFolderPath() + name)).hasContent(expectedAttachmentContent);
+            });
 
-        assertThat(name.startsWith("e_Pubblicita_e_vietata_Milano9052")).isTrue();
-        
-        assertThat(new File(temporaryFolder.getFolderPath() + name)).hasContent(expectedAttachmentContent);
     }
 
     @Test
@@ -260,13 +277,19 @@ class StripAttachmentTest {
 
         mailet.service(mail);
 
-        @SuppressWarnings("unchecked")
-        Map<String, byte[]> saved = (Map<String, byte[]>) mail.getAttribute(customAttribute);
-        assertThat(saved).hasSize(1);
-        assertThat(saved).containsKey(expectedKey);
-        MimeBodyPart savedBodyPart = new MimeBodyPart(new ByteArrayInputStream(saved.get(expectedKey)));
-        String content = IOUtils.toString(savedBodyPart.getInputStream(), StandardCharsets.UTF_8);
-        assertThat(content).isEqualTo(EXPECTED_ATTACHMENT_CONTENT);
+        Optional<Map<String, byte[]>> savedValue = AttributeUtils.getValueAndCastFromMail(mail, AttributeName.of(customAttribute), MAP_STRING_BYTES_CLASS);
+        ConsumerChainer<Map<String, byte[]>> assertValue = Throwing.consumer(saved -> {
+            assertThat(saved)
+                    .hasSize(1)
+                    .containsKeys(expectedKey);
+
+            MimeBodyPart savedBodyPart = new MimeBodyPart(new ByteArrayInputStream(saved.get(expectedKey)));
+            String content = IOUtils.toString(savedBodyPart.getInputStream(), StandardCharsets.UTF_8);
+            assertThat(content).isEqualTo(EXPECTED_ATTACHMENT_CONTENT);
+        });
+        assertThat(savedValue)
+                .isPresent()
+                .hasValueSatisfying(assertValue.sneakyThrow());
     }
 
     @Test
@@ -292,13 +315,19 @@ class StripAttachmentTest {
 
         mailet.service(mail);
 
-        @SuppressWarnings("unchecked")
-        Map<String, byte[]> saved = (Map<String, byte[]>) mail.getAttribute(customAttribute);
-        assertThat(saved).hasSize(1);
-        assertThat(saved).containsKey(expectedKey);
-        MimeBodyPart savedBodyPart = new MimeBodyPart(new ByteArrayInputStream(saved.get(expectedKey)));
-        String content = IOUtils.toString(savedBodyPart.getInputStream(), StandardCharsets.UTF_8);
-        assertThat(content).isEqualTo(EXPECTED_ATTACHMENT_CONTENT);
+        Optional<Map<String, byte[]>> savedValue = AttributeUtils.getValueAndCastFromMail(mail, AttributeName.of(customAttribute), MAP_STRING_BYTES_CLASS);
+        ConsumerChainer<Map<String, byte[]>> assertValue = Throwing.consumer(saved -> {
+            assertThat(saved)
+                    .hasSize(1)
+                    .containsKeys(expectedKey);
+
+            MimeBodyPart savedBodyPart = new MimeBodyPart(new ByteArrayInputStream(saved.get(expectedKey)));
+            String content = IOUtils.toString(savedBodyPart.getInputStream(), StandardCharsets.UTF_8);
+            assertThat(content).isEqualTo(EXPECTED_ATTACHMENT_CONTENT);
+        });
+        assertThat(savedValue)
+            .isPresent()
+            .hasValueSatisfying(assertValue.sneakyThrow());
     }
 
     @Test
@@ -583,9 +612,11 @@ class StripAttachmentTest {
         boolean actual = mailet.processMultipartPartMessage(mimeMessage, mail);
         //Then
         assertThat(actual).isTrue();
-        @SuppressWarnings("unchecked")
-        List<String> values = (List<String>)mail.getAttribute(StripAttachment.SAVED_ATTACHMENTS_ATTRIBUTE_KEY);
-        assertThat(values).hasSize(2);
+        Optional<Collection<AttributeValue<String>>> removedAttachments = AttributeUtils.getValueAndCastFromMail(mail, StripAttachment.SAVED_ATTACHMENTS, COLLECTION_STRING_CLASS);
+        assertThat(removedAttachments)
+            .isPresent()
+            .hasValueSatisfying(attachments ->
+                    assertThat(attachments).hasSize(2));
     }
 
     @Test
@@ -618,9 +649,12 @@ class StripAttachmentTest {
         
         //Then
         assertThat(actual).isTrue();
-        @SuppressWarnings("unchecked")
-        Map<String, byte[]> values = (Map<String, byte[]>)mail.getAttribute(customAttribute);
-        assertThat(values).hasSize(2);
+        Optional<Map<String, byte[]>> savedValue = AttributeUtils.getValueAndCastFromMail(mail, AttributeName.of(customAttribute), MAP_STRING_BYTES_CLASS);
+        assertThat(savedValue)
+                .isPresent()
+                .hasValueSatisfying(saved ->
+                    Assertions.assertThat(saved)
+                            .hasSize(2));
     }
 
     @Test
@@ -726,9 +760,11 @@ class StripAttachmentTest {
         boolean actual = mailet.processMultipartPartMessage(mimeMessage, mail);
         //Then
         assertThat(actual).isTrue();
-        @SuppressWarnings("unchecked")
-        List<String> values = (List<String>)mail.getAttribute(StripAttachment.SAVED_ATTACHMENTS_ATTRIBUTE_KEY);
-        assertThat(values).hasSize(1);
+        Optional<Collection<AttributeValue<String>>> removedAttachments = AttributeUtils.getValueAndCastFromMail(mail, StripAttachment.SAVED_ATTACHMENTS, COLLECTION_STRING_CLASS);
+        assertThat(removedAttachments)
+            .isPresent()
+            .hasValueSatisfying(attachments ->
+                    assertThat(attachments).hasSize(1));
     }
 
     @Test
diff --git a/mailet/standard/src/test/java/org/apache/james/transport/matchers/AbstractHasMailAttributeTest.java b/mailet/standard/src/test/java/org/apache/james/transport/matchers/AbstractHasMailAttributeTest.java
index 652955a..ecd1692 100644
--- a/mailet/standard/src/test/java/org/apache/james/transport/matchers/AbstractHasMailAttributeTest.java
+++ b/mailet/standard/src/test/java/org/apache/james/transport/matchers/AbstractHasMailAttributeTest.java
@@ -29,6 +29,7 @@ import java.util.Collection;
 import javax.mail.MessagingException;
 
 import org.apache.james.core.MailAddress;
+import org.apache.mailet.Attribute;
 import org.apache.mailet.Matcher;
 import org.apache.mailet.base.GenericMatcher;
 import org.apache.mailet.base.test.FakeMail;
@@ -43,26 +44,16 @@ public abstract class AbstractHasMailAttributeTest {
 
     protected Matcher matcher;
 
-    static final String MAIL_ATTRIBUTE_NAME = "org.apache.james.test.junit";
+    static final Attribute MAIL_ATTRIBUTE = Attribute.convertToAttribute("org.apache.james.test.junit", "true");
+    private Attribute mailAttribute = Attribute.convertToAttribute("org.apache.james", "false");
 
-    static final String MAIL_ATTRIBUTE_VALUE = "true";
-
-    private String mailAttributeName = "org.apache.james";
-
-    private String mailAttributeValue = "false";
-
-    void setMailAttributeName(String mailAttributeName) {
-        this.mailAttributeName = mailAttributeName;
-    }
-
-    void setMailAttributeValue(String mailAttributeValue) {
-        this.mailAttributeValue = mailAttributeValue;
+    void setMailAttribute(Attribute mailAttribute) {
+        this.mailAttribute = mailAttribute;
     }
 
     void setupMockedMail() throws MessagingException {
         mockedMail = MailUtil.createMockMail2Recipients();
-        mockedMail.setAttribute(mailAttributeName,
-                mailAttributeValue);
+        mockedMail.setAttribute(mailAttribute);
     }
 
     void setupMatcher() throws MessagingException {
@@ -90,8 +81,7 @@ public abstract class AbstractHasMailAttributeTest {
     }
 
     protected void init() {
-        setMailAttributeName(MAIL_ATTRIBUTE_NAME);
-        setMailAttributeValue(MAIL_ATTRIBUTE_VALUE);
+        setMailAttribute(MAIL_ATTRIBUTE);
     }
 
     void setupAll() throws MessagingException {
diff --git a/mailet/standard/src/test/java/org/apache/james/transport/matchers/HasExceptionTest.java b/mailet/standard/src/test/java/org/apache/james/transport/matchers/HasExceptionTest.java
index 3392e65..ff30cd4 100644
--- a/mailet/standard/src/test/java/org/apache/james/transport/matchers/HasExceptionTest.java
+++ b/mailet/standard/src/test/java/org/apache/james/transport/matchers/HasExceptionTest.java
@@ -23,13 +23,17 @@ import static org.assertj.core.api.Assertions.assertThat;
 import static org.assertj.core.api.Assertions.assertThatThrownBy;
 
 import javax.mail.MessagingException;
+import javax.mail.internet.AddressException;
 import javax.mail.internet.MimeMessage;
 
+import org.apache.mailet.Attribute;
+import org.apache.mailet.AttributeValue;
 import org.apache.mailet.Mail;
 import org.apache.mailet.Matcher;
 import org.apache.mailet.base.test.FakeMail;
 import org.apache.mailet.base.test.FakeMatcherConfig;
 import org.apache.mailet.base.test.MailUtil;
+
 import org.junit.jupiter.api.BeforeEach;
 import org.junit.jupiter.api.Test;
 
@@ -47,7 +51,7 @@ public class HasExceptionTest {
 
     @Test
     public void matchShouldReturnAddressesWhenSpecifiedExceptionHasOccurred() throws MessagingException {
-        mockedMail.setAttribute(Mail.MAILET_ERROR_ATTRIBUTE_NAME, new javax.mail.internet.AddressException());
+        mockedMail.setAttribute(new Attribute(Mail.MAILET_ERROR, AttributeValue.ofSerializable(new AddressException())));
 
         FakeMatcherConfig matcherConfig = FakeMatcherConfig.builder()
                 .matcherName("HasException")
@@ -61,7 +65,7 @@ public class HasExceptionTest {
 
     @Test
     public void matchShouldReturnAddressesWhenSubclassOfSpecifiedExceptionHasOccurred() throws MessagingException {
-        mockedMail.setAttribute(Mail.MAILET_ERROR_ATTRIBUTE_NAME, new javax.mail.internet.AddressException());
+        mockedMail.setAttribute(new Attribute(Mail.MAILET_ERROR, AttributeValue.ofSerializable(new AddressException())));
 
         FakeMatcherConfig matcherConfig = FakeMatcherConfig.builder()
                 .matcherName("HasException")
@@ -75,7 +79,7 @@ public class HasExceptionTest {
 
     @Test
     public void matchShouldReturnEmptyWhenOtherExceptionHasOccurred() throws MessagingException {
-        mockedMail.setAttribute(Mail.MAILET_ERROR_ATTRIBUTE_NAME, new java.lang.RuntimeException());
+        mockedMail.setAttribute(new Attribute(Mail.MAILET_ERROR, AttributeValue.ofSerializable(new java.lang.RuntimeException())));
 
         testee.init(FakeMatcherConfig.builder()
                 .matcherName("HasException")
@@ -87,7 +91,7 @@ public class HasExceptionTest {
 
     @Test
     public void matchShouldReturnEmptyWhenSuperclassOfSpecifiedExceptionHasOccurred() throws MessagingException {
-        mockedMail.setAttribute(Mail.MAILET_ERROR_ATTRIBUTE_NAME, new javax.mail.MessagingException());
+        mockedMail.setAttribute(new Attribute(Mail.MAILET_ERROR, AttributeValue.ofSerializable(new javax.mail.MessagingException())));
 
         FakeMatcherConfig matcherConfig = FakeMatcherConfig.builder()
                 .matcherName("HasException")
@@ -113,7 +117,7 @@ public class HasExceptionTest {
 
     @Test
     public void matchShouldReturnEmptyWhenNonExceptionIsAttached() throws MessagingException {
-        mockedMail.setAttribute(Mail.MAILET_ERROR_ATTRIBUTE_NAME, new java.lang.String());
+        mockedMail.setAttribute(new Attribute(Mail.MAILET_ERROR, AttributeValue.of(new java.lang.String())));
 
         FakeMatcherConfig matcherConfig = FakeMatcherConfig.builder()
                 .matcherName("HasException")
@@ -147,7 +151,7 @@ public class HasExceptionTest {
     
     @Test
     public void initShouldRaiseMessagingExceptionWhenClassNameIsNotFullyQualified() throws MessagingException {
-        mockedMail.setAttribute(Mail.MAILET_ERROR_ATTRIBUTE_NAME, new javax.mail.MessagingException());
+        mockedMail.setAttribute(new Attribute(Mail.MAILET_ERROR, AttributeValue.ofSerializable(new javax.mail.MessagingException())));
 
         FakeMatcherConfig matcherConfig = FakeMatcherConfig.builder()
                 .matcherName("HasException")
diff --git a/mailet/standard/src/test/java/org/apache/james/transport/matchers/HasMailAttributeTest.java b/mailet/standard/src/test/java/org/apache/james/transport/matchers/HasMailAttributeTest.java
index e3d1c87..82027dd 100644
--- a/mailet/standard/src/test/java/org/apache/james/transport/matchers/HasMailAttributeTest.java
+++ b/mailet/standard/src/test/java/org/apache/james/transport/matchers/HasMailAttributeTest.java
@@ -31,7 +31,7 @@ public class HasMailAttributeTest extends AbstractHasMailAttributeTest {
 
     @Override
     protected String getHasMailAttribute() {
-        return MAIL_ATTRIBUTE_NAME;
+        return MAIL_ATTRIBUTE.getName().asString();
     }
 
     @Override
diff --git a/mailet/standard/src/test/java/org/apache/james/transport/matchers/HasMailAttributeWithValueRegexTest.java b/mailet/standard/src/test/java/org/apache/james/transport/matchers/HasMailAttributeWithValueRegexTest.java
index a42b126..c8fb3c6 100644
--- a/mailet/standard/src/test/java/org/apache/james/transport/matchers/HasMailAttributeWithValueRegexTest.java
+++ b/mailet/standard/src/test/java/org/apache/james/transport/matchers/HasMailAttributeWithValueRegexTest.java
@@ -43,7 +43,7 @@ public class HasMailAttributeWithValueRegexTest extends AbstractHasMailAttribute
 
     @Override
     protected String getHasMailAttribute() {
-        return MAIL_ATTRIBUTE_NAME + ", " + regex;
+        return MAIL_ATTRIBUTE.getName().asString() + ", " + regex;
     }
 
     @Override
diff --git a/mailet/standard/src/test/java/org/apache/james/transport/matchers/HasMailAttributeWithValueTest.java b/mailet/standard/src/test/java/org/apache/james/transport/matchers/HasMailAttributeWithValueTest.java
index 9412d88..af2c7bf 100644
--- a/mailet/standard/src/test/java/org/apache/james/transport/matchers/HasMailAttributeWithValueTest.java
+++ b/mailet/standard/src/test/java/org/apache/james/transport/matchers/HasMailAttributeWithValueTest.java
@@ -27,6 +27,8 @@ import java.util.Collection;
 import javax.mail.MessagingException;
 
 import org.apache.james.core.MailAddress;
+import org.apache.mailet.Attribute;
+import org.apache.mailet.AttributeValue;
 import org.apache.mailet.base.GenericMatcher;
 import org.junit.jupiter.api.Test;
 
@@ -34,7 +36,7 @@ public class HasMailAttributeWithValueTest extends AbstractHasMailAttributeTest
 
     @Override
     protected String getHasMailAttribute() {
-        return MAIL_ATTRIBUTE_NAME + ", " + MAIL_ATTRIBUTE_VALUE;
+        return MAIL_ATTRIBUTE.getName().asString() + ", " + MAIL_ATTRIBUTE.getValue().value();
     }
 
     @Override
@@ -44,7 +46,7 @@ public class HasMailAttributeWithValueTest extends AbstractHasMailAttributeTest
 
     @Test
     void testAttributeIsNotMatchedCauseValue() throws MessagingException {
-        setMailAttributeName(MAIL_ATTRIBUTE_NAME);
+        setMailAttribute(new Attribute(MAIL_ATTRIBUTE.getName(), AttributeValue.of("false")));
         setupMockedMail();
         setupMatcher();
 
diff --git a/mailet/standard/src/test/java/org/apache/james/transport/matchers/SMTPAuthSuccessfulTest.java b/mailet/standard/src/test/java/org/apache/james/transport/matchers/SMTPAuthSuccessfulTest.java
index 7c47bea..7a36347 100644
--- a/mailet/standard/src/test/java/org/apache/james/transport/matchers/SMTPAuthSuccessfulTest.java
+++ b/mailet/standard/src/test/java/org/apache/james/transport/matchers/SMTPAuthSuccessfulTest.java
@@ -24,6 +24,8 @@ import static org.assertj.core.api.Assertions.assertThat;
 import java.util.Collection;
 
 import org.apache.james.core.MailAddress;
+import org.apache.mailet.Attribute;
+import org.apache.mailet.AttributeValue;
 import org.apache.mailet.Mail;
 import org.apache.mailet.base.MailAddressFixture;
 import org.apache.mailet.base.test.FakeMail;
@@ -49,7 +51,7 @@ public class SMTPAuthSuccessfulTest {
         MailAddress recipient = MailAddressFixture.OTHER_AT_JAMES;
         FakeMail fakeMail = FakeMail.builder()
             .recipient(recipient)
-            .attribute(Mail.SMTP_AUTH_USER_ATTRIBUTE_NAME, "other")
+            .attribute(new Attribute(Mail.SMTP_AUTH_USER, AttributeValue.of("other")))
             .build();
 
         Collection<MailAddress> results =  testee.match(fakeMail);
diff --git a/mailet/standard/src/test/java/org/apache/james/transport/matchers/SMTPAuthUserIsTest.java b/mailet/standard/src/test/java/org/apache/james/transport/matchers/SMTPAuthUserIsTest.java
index ef19a41..aff1727 100644
--- a/mailet/standard/src/test/java/org/apache/james/transport/matchers/SMTPAuthUserIsTest.java
+++ b/mailet/standard/src/test/java/org/apache/james/transport/matchers/SMTPAuthUserIsTest.java
@@ -27,6 +27,8 @@ import java.util.Collection;
 import javax.mail.MessagingException;
 
 import org.apache.james.core.MailAddress;
+import org.apache.mailet.Attribute;
+import org.apache.mailet.AttributeValue;
 import org.apache.mailet.Mail;
 import org.apache.mailet.base.GenericMatcher;
 import org.junit.jupiter.api.Test;
@@ -51,8 +53,7 @@ public class SMTPAuthUserIsTest extends AbstractHasMailAttributeTest {
     @Override
     protected void init() {
         super.init();
-        setMailAttributeName(Mail.SMTP_AUTH_USER_ATTRIBUTE_NAME);
-        setMailAttributeValue("test@james.apache.org");
+        setMailAttribute(new Attribute(Mail.SMTP_AUTH_USER, AttributeValue.of("test@james.apache.org")));
     }
     
     
@@ -60,7 +61,7 @@ public class SMTPAuthUserIsTest extends AbstractHasMailAttributeTest {
     @Test
     public void testAttributeIsNotMatched() throws MessagingException {
         setupAll();
-        setMailAttributeValue("notmatched@james.apache.org");
+        setMailAttribute(Attribute.convertToAttribute("notmatched@james.apache.org", ""));
 
         Collection<MailAddress> matchedRecipients = matcher.match(mockedMail);
 
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 aa0cf64..4c144cd 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
@@ -113,8 +113,8 @@ public class SpamAssassinTest {
 
         assertThat(messageReader.readFirstMessageHeaders())
             .contains(
-                SpamAssassinResult.FLAG_MAIL_ATTRIBUTE_NAME,
-                SpamAssassinResult.STATUS_MAIL_ATTRIBUTE_NAME);
+                SpamAssassinResult.FLAG_MAIL.asString(),
+                SpamAssassinResult.STATUS_MAIL.asString());
     }
 
     @Test
@@ -128,8 +128,8 @@ public class SpamAssassinTest {
             .awaitMessage(awaitAtMostOneMinute);
 
         String receivedHeaders = messageReader.readFirstMessageHeaders();
-        assertThat(receivedHeaders).contains(SpamAssassinResult.FLAG_MAIL_ATTRIBUTE_NAME + ": YES");
-        assertThat(receivedHeaders).contains(SpamAssassinResult.STATUS_MAIL_ATTRIBUTE_NAME + ": Yes");
+        assertThat(receivedHeaders).contains(SpamAssassinResult.FLAG_MAIL.asString() + ": YES");
+        assertThat(receivedHeaders).contains(SpamAssassinResult.STATUS_MAIL.asString() + ": Yes");
     }
 
     @Test
@@ -143,8 +143,8 @@ public class SpamAssassinTest {
             .awaitMessage(awaitAtMostOneMinute);
 
         String receivedHeaders = messageReader.readFirstMessageHeaders();
-        assertThat(receivedHeaders).contains(SpamAssassinResult.FLAG_MAIL_ATTRIBUTE_NAME + ": NO");
-        assertThat(receivedHeaders).contains(SpamAssassinResult.STATUS_MAIL_ATTRIBUTE_NAME + ": No");
+        assertThat(receivedHeaders).contains(SpamAssassinResult.FLAG_MAIL.asString() + ": NO");
+        assertThat(receivedHeaders).contains(SpamAssassinResult.STATUS_MAIL.asString() + ": No");
     }
 
     @Test
@@ -159,8 +159,8 @@ public class SpamAssassinTest {
 
         assertThat(messageReader.readFirstMessageHeaders())
             .contains(
-                SpamAssassinResult.FLAG_MAIL_ATTRIBUTE_NAME,
-                SpamAssassinResult.STATUS_MAIL_ATTRIBUTE_NAME);
+                SpamAssassinResult.FLAG_MAIL.asString(),
+                SpamAssassinResult.STATUS_MAIL.asString());
 
         messageReader.disconnect()
             .connect(LOCALHOST_IP, jamesServer.getProbe(ImapGuiceProbe.class).getImapPort())
@@ -170,8 +170,8 @@ public class SpamAssassinTest {
 
         assertThat(messageReader.readFirstMessageHeaders())
             .contains(
-                SpamAssassinResult.FLAG_MAIL_ATTRIBUTE_NAME,
-                SpamAssassinResult.STATUS_MAIL_ATTRIBUTE_NAME);
+                SpamAssassinResult.FLAG_MAIL.asString(),
+                SpamAssassinResult.STATUS_MAIL.asString());
     }
 
     private FakeMail.Builder mailWithContent(String textContent, String... recipients) throws MessagingException {
diff --git a/server/mailet/mailetcontainer-camel/src/main/java/org/apache/james/mailetcontainer/impl/ProcessorUtil.java b/server/mailet/mailetcontainer-camel/src/main/java/org/apache/james/mailetcontainer/impl/ProcessorUtil.java
index 3a88963..7f1786b 100644
--- a/server/mailet/mailetcontainer-camel/src/main/java/org/apache/james/mailetcontainer/impl/ProcessorUtil.java
+++ b/server/mailet/mailetcontainer-camel/src/main/java/org/apache/james/mailetcontainer/impl/ProcessorUtil.java
@@ -26,6 +26,8 @@ import java.util.Collection;
 import javax.mail.MessagingException;
 
 import org.apache.james.core.MailAddress;
+import org.apache.mailet.Attribute;
+import org.apache.mailet.AttributeValue;
 import org.apache.mailet.Mail;
 import org.apache.mailet.MailetException;
 import org.slf4j.Logger;
@@ -63,7 +65,7 @@ public class ProcessorUtil {
         String errorString = sout.toString();
         mail.setErrorMessage(errorString);
         logger.error(errorString);
-        mail.setAttribute(Mail.MAILET_ERROR_ATTRIBUTE_NAME, me);
+        mail.setAttribute(new Attribute(Mail.MAILET_ERROR, AttributeValue.ofSerializable(me)));
     }
 
     /**
diff --git a/server/mailet/mailetcontainer-camel/src/test/java/org/apache/james/mailetcontainer/lib/AbstractStateMailetProcessorTest.java b/server/mailet/mailetcontainer-camel/src/test/java/org/apache/james/mailetcontainer/lib/AbstractStateMailetProcessorTest.java
index fddedaf..b013928 100644
--- a/server/mailet/mailetcontainer-camel/src/test/java/org/apache/james/mailetcontainer/lib/AbstractStateMailetProcessorTest.java
+++ b/server/mailet/mailetcontainer-camel/src/test/java/org/apache/james/mailetcontainer/lib/AbstractStateMailetProcessorTest.java
@@ -233,7 +233,8 @@ public abstract class AbstractStateMailetProcessorTest {
         processor.service(mail);
 
         // the source mail should have captured the exception which was thrown
-        assertThat(mail.getAttribute(Mail.MAILET_ERROR_ATTRIBUTE_NAME).getClass()).isEqualTo(MessagingException.class);
+        assertThat(mail.getAttribute(Mail.MAILET_ERROR)).hasValueSatisfying(attribute ->
+                assertThat(attribute.getValue().value().getClass()).isEqualTo(MessagingException.class));
         latch.await();
         processor.destroy();
     }
diff --git a/server/mailet/mailets/src/main/java/org/apache/james/transport/mailets/RemoteDelivery.java b/server/mailet/mailets/src/main/java/org/apache/james/transport/mailets/RemoteDelivery.java
index 4e5d68f..7192edc 100644
--- a/server/mailet/mailets/src/main/java/org/apache/james/transport/mailets/RemoteDelivery.java
+++ b/server/mailet/mailets/src/main/java/org/apache/james/transport/mailets/RemoteDelivery.java
@@ -198,7 +198,7 @@ public class RemoteDelivery extends GenericMailet {
             LOGGER.debug("Remotely delivering mail {}", mail.getName());
         }
         if (configuration.isUsePriority()) {
-            mail.setAttribute(MailPrioritySupport.MAIL_PRIORITY, MailPrioritySupport.HIGH_PRIORITY);
+            mail.setAttribute(MailPrioritySupport.HIGH_PRIORITY_ATTRIBUTE);
         }
         if (!mail.getRecipients().isEmpty()) {
             if (configuration.getGatewayServer().isEmpty()) {
diff --git a/server/mailet/mailets/src/main/java/org/apache/james/transport/mailets/SpamAssassin.java b/server/mailet/mailets/src/main/java/org/apache/james/transport/mailets/SpamAssassin.java
index adda4b7..c69e4ad 100644
--- a/server/mailet/mailets/src/main/java/org/apache/james/transport/mailets/SpamAssassin.java
+++ b/server/mailet/mailets/src/main/java/org/apache/james/transport/mailets/SpamAssassin.java
@@ -33,6 +33,7 @@ import org.apache.james.spamassassin.SpamAssassinResult;
 import org.apache.james.user.api.UsersRepository;
 import org.apache.james.user.api.UsersRepositoryException;
 import org.apache.james.util.Port;
+import org.apache.mailet.Attribute;
 import org.apache.mailet.Mail;
 import org.apache.mailet.PerRecipientHeaders;
 import org.apache.mailet.base.GenericMailet;
@@ -110,10 +111,10 @@ public class SpamAssassin extends GenericMailet {
         SpamAssassinResult result = sa.scanMail(message, User.fromUsername(usersRepository.getUser(recipient)));
 
         // Add headers per recipient to mail object
-        for (String key : result.getHeadersAsAttribute().keySet()) {
+        for (Attribute attribute : result.getHeadersAsAttributes()) {
             mail.addSpecificHeaderForRecipient(PerRecipientHeaders.Header.builder()
-                    .name(key)
-                    .value(result.getHeadersAsAttribute().get(key))
+                    .name(attribute.getName().asString())
+                    .value((String) attribute.getValue().value())
                     .build(), recipient);
         }
     }
diff --git a/server/mailet/mailets/src/main/java/org/apache/james/transport/mailets/WithPriority.java b/server/mailet/mailets/src/main/java/org/apache/james/transport/mailets/WithPriority.java
index 5e5218c..3138f4b 100644
--- a/server/mailet/mailets/src/main/java/org/apache/james/transport/mailets/WithPriority.java
+++ b/server/mailet/mailets/src/main/java/org/apache/james/transport/mailets/WithPriority.java
@@ -24,6 +24,8 @@ import java.util.Optional;
 import javax.mail.MessagingException;
 
 import org.apache.james.queue.api.MailPrioritySupport;
+import org.apache.mailet.Attribute;
+import org.apache.mailet.AttributeValue;
 import org.apache.mailet.Mail;
 import org.apache.mailet.base.GenericMailet;
 
@@ -38,7 +40,7 @@ import org.apache.mailet.base.GenericMailet;
  */
 public class WithPriority extends GenericMailet {
 
-    private int priority;
+    private Attribute priority;
 
     @Override
     public String getMailetInfo() {
@@ -47,17 +49,18 @@ public class WithPriority extends GenericMailet {
 
     @Override
     public void init() throws MessagingException {
-        priority = Optional.ofNullable(getInitParameter("priority", null))
-                .map(Integer::valueOf)
-                .orElseThrow(() -> new IllegalArgumentException("'priority' init parameter is compulsory"));
+        Integer priorityRaw = Optional.ofNullable(getInitParameter("priority", null))
+            .map(Integer::valueOf)
+            .orElseThrow(() -> new IllegalArgumentException("'priority' init parameter is compulsory"));
 
-        if (priority < 0 || priority > 9) {
+        if (priorityRaw < 0 || priorityRaw > 9) {
             throw new IllegalArgumentException("Invalid priority: Priority should be from 0 to 9");
         }
+        priority = new Attribute(MailPrioritySupport.MAIL_PRIORITY, AttributeValue.of(priorityRaw));
     }
 
     @Override
     public void service(Mail mail) throws MessagingException {
-        mail.setAttribute(MailPrioritySupport.MAIL_PRIORITY, priority);
+        mail.setAttribute(priority);
     }
 }
diff --git a/server/mailet/mailets/src/main/java/org/apache/james/transport/mailets/managesieve/ManageSieveMailet.java b/server/mailet/mailets/src/main/java/org/apache/james/transport/mailets/managesieve/ManageSieveMailet.java
index 6fb60b7..51285b9 100644
--- a/server/mailet/mailets/src/main/java/org/apache/james/transport/mailets/managesieve/ManageSieveMailet.java
+++ b/server/mailet/mailets/src/main/java/org/apache/james/transport/mailets/managesieve/ManageSieveMailet.java
@@ -132,7 +132,7 @@ public class ManageSieveMailet extends GenericMailet implements MessageToCoreToM
 
         // Update the Session for the current mail and execute
         SettableSession session = new SettableSession();
-        if (mail.getAttribute(Mail.SMTP_AUTH_USER_ATTRIBUTE_NAME) != null) {
+        if (mail.getAttribute(Mail.SMTP_AUTH_USER).isPresent()) {
             session.setState(Session.State.AUTHENTICATED);
         } else {
             session.setState(Session.State.UNAUTHENTICATED);
diff --git a/server/mailet/mailets/src/main/java/org/apache/james/transport/mailets/remote/delivery/DeliveryRunnable.java b/server/mailet/mailets/src/main/java/org/apache/james/transport/mailets/remote/delivery/DeliveryRunnable.java
index 53b0420..b5fcebe 100644
--- a/server/mailet/mailets/src/main/java/org/apache/james/transport/mailets/remote/delivery/DeliveryRunnable.java
+++ b/server/mailet/mailets/src/main/java/org/apache/james/transport/mailets/remote/delivery/DeliveryRunnable.java
@@ -167,7 +167,7 @@ public class DeliveryRunnable implements Runnable {
 
         if (configuration.isUsePriority()) {
             // Use lowest priority for retries. See JAMES-1311
-            mail.setAttribute(MailPrioritySupport.MAIL_PRIORITY, MailPrioritySupport.LOW_PRIORITY);
+            mail.setAttribute(MailPrioritySupport.LOW_PRIORITY_ATTRIBUTE);
         }
         queue.enQueue(mail, delay, TimeUnit.MILLISECONDS);
     }
diff --git a/server/mailet/mailets/src/main/java/org/apache/james/transport/matchers/IsMarkedAsSpam.java b/server/mailet/mailets/src/main/java/org/apache/james/transport/matchers/IsMarkedAsSpam.java
index bd516f5..1cace4c 100644
--- a/server/mailet/mailets/src/main/java/org/apache/james/transport/matchers/IsMarkedAsSpam.java
+++ b/server/mailet/mailets/src/main/java/org/apache/james/transport/matchers/IsMarkedAsSpam.java
@@ -73,7 +73,7 @@ public class IsMarkedAsSpam extends GenericMatcher {
     public boolean isMarkedAsSpam(Mail mail, MailAddress recipient) {
         return mail.getPerRecipientSpecificHeaders().getHeadersForRecipient(recipient)
             .stream()
-            .filter(header -> header.getName().equals(SpamAssassinResult.STATUS_MAIL_ATTRIBUTE_NAME))
+            .filter(header -> header.getName().equals(SpamAssassinResult.STATUS_MAIL.asString()))
             .anyMatch(header -> header.getValue().toLowerCase(Locale.US).startsWith(YES));
     }
 
diff --git a/server/mailet/mailets/src/test/java/org/apache/james/transport/mailets/SpamAssassinTest.java b/server/mailet/mailets/src/test/java/org/apache/james/transport/mailets/SpamAssassinTest.java
index 62565ab..29107f4 100644
--- a/server/mailet/mailets/src/test/java/org/apache/james/transport/mailets/SpamAssassinTest.java
+++ b/server/mailet/mailets/src/test/java/org/apache/james/transport/mailets/SpamAssassinTest.java
@@ -170,7 +170,7 @@ public class SpamAssassinTest {
                 .stream()
                 .map(PerRecipientHeaders.Header::getName)
                 .collect(Guavate.toImmutableList()))
-            .contains(SpamAssassinResult.FLAG_MAIL_ATTRIBUTE_NAME, SpamAssassinResult.STATUS_MAIL_ATTRIBUTE_NAME);
+            .contains(SpamAssassinResult.FLAG_MAIL.asString(), SpamAssassinResult.STATUS_MAIL.asString());
     }
 
     @Test
@@ -198,12 +198,12 @@ public class SpamAssassinTest {
             .isEqualTo(new PerRecipientHeaders()
                 .addHeaderForRecipient(
                     PerRecipientHeaders.Header.builder()
-                        .name(SpamAssassinResult.FLAG_MAIL_ATTRIBUTE_NAME)
+                        .name(SpamAssassinResult.FLAG_MAIL.asString())
                         .value("NO"),
                     new MailAddress("user1@exemple.com"))
                 .addHeaderForRecipient(
                     PerRecipientHeaders.Header.builder()
-                        .name(SpamAssassinResult.STATUS_MAIL_ATTRIBUTE_NAME)
+                        .name(SpamAssassinResult.STATUS_MAIL.asString())
                         .value("No, hits=3 required=5"),
                     new MailAddress("user1@exemple.com")));
     }
@@ -233,12 +233,12 @@ public class SpamAssassinTest {
             .isEqualTo(new PerRecipientHeaders()
                 .addHeaderForRecipient(
                     PerRecipientHeaders.Header.builder()
-                        .name(SpamAssassinResult.FLAG_MAIL_ATTRIBUTE_NAME)
+                        .name(SpamAssassinResult.FLAG_MAIL.asString())
                         .value("YES"),
                     new MailAddress("user1@exemple.com"))
                 .addHeaderForRecipient(
                     PerRecipientHeaders.Header.builder()
-                        .name(SpamAssassinResult.STATUS_MAIL_ATTRIBUTE_NAME)
+                        .name(SpamAssassinResult.STATUS_MAIL.asString())
                         .value("Yes, hits=1000 required=5"),
                     new MailAddress("user1@exemple.com")));
     }
diff --git a/server/mailet/mailets/src/test/java/org/apache/james/transport/mailets/WithPriorityTest.java b/server/mailet/mailets/src/test/java/org/apache/james/transport/mailets/WithPriorityTest.java
index 5b414b0..4814a66 100644
--- a/server/mailet/mailets/src/test/java/org/apache/james/transport/mailets/WithPriorityTest.java
+++ b/server/mailet/mailets/src/test/java/org/apache/james/transport/mailets/WithPriorityTest.java
@@ -23,6 +23,8 @@ import static org.assertj.core.api.Assertions.assertThatCode;
 import static org.assertj.core.api.Assertions.assertThatThrownBy;
 
 import org.apache.james.queue.api.MailPrioritySupport;
+import org.apache.mailet.Attribute;
+import org.apache.mailet.AttributeValue;
 import org.apache.mailet.Mail;
 import org.apache.mailet.MailetConfig;
 import org.apache.mailet.base.test.FakeMail;
@@ -33,6 +35,7 @@ import org.junit.Test;
 
 public class WithPriorityTest {
 
+    private static final Attribute PROPERTY_PRIORITY = new Attribute(MailPrioritySupport.MAIL_PRIORITY, AttributeValue.of(7));
     private WithPriority mailet;
 
     @Before
@@ -107,29 +110,29 @@ public class WithPriorityTest {
     public void serviceShouldSetMailPriorityWhenNone() throws Exception {
         MailetConfig mockedMailetConfig = FakeMailetConfig.builder()
             .mailetContext(FakeMailContext.defaultContext())
-            .setProperty("priority", "7")
+            .setProperty("priority", PROPERTY_PRIORITY.getValue().value().toString())
             .build();
 
         mailet.init(mockedMailetConfig);
         Mail mail = FakeMail.builder().build();
         mailet.service(mail);
 
-        assertThat(mail.getAttribute(MailPrioritySupport.MAIL_PRIORITY)).isEqualTo(7);
+        assertThat(mail.getAttribute(MailPrioritySupport.MAIL_PRIORITY)).contains(PROPERTY_PRIORITY);
     }
 
     @Test
     public void serviceShouldSetMailPriorityWhenPriorityExists() throws Exception {
         MailetConfig mockedMailetConfig = FakeMailetConfig.builder()
             .mailetContext(FakeMailContext.defaultContext())
-            .setProperty("priority", "7")
+            .setProperty("priority", PROPERTY_PRIORITY.getValue().value().toString())
             .build();
 
         mailet.init(mockedMailetConfig);
         Mail mail = FakeMail.builder()
-                .attribute(MailPrioritySupport.MAIL_PRIORITY, 5)
+                .attribute(new Attribute(MailPrioritySupport.MAIL_PRIORITY, AttributeValue.of(5)))
                 .build();
         mailet.service(mail);
 
-        assertThat(mail.getAttribute(MailPrioritySupport.MAIL_PRIORITY)).isEqualTo(7);
+        assertThat(mail.getAttribute(MailPrioritySupport.MAIL_PRIORITY)).contains(PROPERTY_PRIORITY);
     }
 }
diff --git a/server/mailet/mailets/src/test/java/org/apache/james/transport/mailets/managesieve/ManageSieveMailetTestCase.java b/server/mailet/mailets/src/test/java/org/apache/james/transport/mailets/managesieve/ManageSieveMailetTestCase.java
index 01bc770..7ee74ac 100644
--- a/server/mailet/mailets/src/test/java/org/apache/james/transport/mailets/managesieve/ManageSieveMailetTestCase.java
+++ b/server/mailet/mailets/src/test/java/org/apache/james/transport/mailets/managesieve/ManageSieveMailetTestCase.java
@@ -49,6 +49,8 @@ import org.apache.james.sieverepository.api.ScriptSummary;
 import org.apache.james.sieverepository.api.SieveRepository;
 import org.apache.james.sieverepository.api.exception.ScriptNotFoundException;
 import org.apache.james.user.api.UsersRepository;
+import org.apache.mailet.Attribute;
+import org.apache.mailet.AttributeValue;
 import org.apache.mailet.Mail;
 import org.apache.mailet.base.test.FakeMail;
 import org.apache.mailet.base.test.FakeMailContext;
@@ -104,7 +106,7 @@ public class ManageSieveMailetTestCase {
         Mail mail = createUnauthenticatedMail(message);
         when(sieveParser.getExtensions()).thenReturn(Lists.newArrayList("a", "b", "c"));
         initializeMailet();
-        mail.setAttribute(Mail.SMTP_AUTH_USER_ATTRIBUTE_NAME, "test");
+        mail.setAttribute(new Attribute(Mail.SMTP_AUTH_USER, AttributeValue.of("test")));
         mailet.service(mail);
         ensureResponseContains("Re: CAPABILITY", "\"SIEVE\" \"a b c\"",
             "\"IMPLEMENTATION\" \"Apache ManageSieve v1.0\"",
@@ -196,7 +198,7 @@ public class ManageSieveMailetTestCase {
         when(sieveRepository.getScript(USER, SCRIPT_NAME)).thenReturn(new ByteArrayInputStream(SCRIPT_CONTENT.getValue().getBytes(StandardCharsets.UTF_8)));
         MimeMessage message = prepareMimeMessage("GETSCRIPT \"" + SCRIPT_NAME.getValue() + "\"");
         Mail mail = createUnauthenticatedMail(message);
-        mail.setAttribute(Mail.SMTP_AUTH_USER_ATTRIBUTE_NAME, USER.asString());
+        mail.setAttribute(new Attribute(Mail.SMTP_AUTH_USER, AttributeValue.of(USER.asString())));
         mailet.service(mail);
         ensureResponse("Re: GETSCRIPT \"" + SCRIPT_NAME.getValue() + "\"", "{13}\r\n" + SCRIPT_CONTENT.getValue() + "\r\nOK");
     }
@@ -214,7 +216,7 @@ public class ManageSieveMailetTestCase {
         doThrow(new ScriptNotFoundException()).when(sieveRepository).getScript(USER, SCRIPT_NAME);
         MimeMessage message = prepareMimeMessage("GETSCRIPT \"" + SCRIPT_NAME.getValue() + "\"");
         Mail mail = createUnauthenticatedMail(message);
-        mail.setAttribute(Mail.SMTP_AUTH_USER_ATTRIBUTE_NAME, USER.asString());
+        mail.setAttribute(new Attribute(Mail.SMTP_AUTH_USER, AttributeValue.of(USER.asString())));
         mailet.service(mail);
         ensureResponse("Re: GETSCRIPT \"" + SCRIPT_NAME.getValue() + "\"", "NO (NONEXISTENT) \"There is no script by that name\"");
     }
@@ -226,7 +228,7 @@ public class ManageSieveMailetTestCase {
         MimeMessage message = prepareMimeMessage("GETSCRIPT");
         Mail mail = createUnauthenticatedMail(message);
 
-        mail.setAttribute(Mail.SMTP_AUTH_USER_ATTRIBUTE_NAME, USER.asString());
+        mail.setAttribute(new Attribute(Mail.SMTP_AUTH_USER, AttributeValue.of(USER.asString())));
         mailet.service(mail);
         ensureResponse("Re: GETSCRIPT", "NO \"Missing argument: script name\"");
     }
@@ -514,7 +516,7 @@ public class ManageSieveMailetTestCase {
 
     private Mail createAuthentificatedMail(MimeMessage message) throws Exception {
         Mail mail = createUnauthenticatedMail(message);
-        mail.setAttribute(Mail.SMTP_AUTH_USER_ATTRIBUTE_NAME, message.getSender().toString());
+        mail.setAttribute(new Attribute(Mail.SMTP_AUTH_USER, AttributeValue.of(message.getSender().toString())));
         return mail;
     }
 
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
index f7b5bd1..00612ae 100644
--- 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
@@ -196,7 +196,7 @@ public class RemoteDeliveryTest {
             .extracting(MailProjection::from)
             .containsOnly(MailProjection.from(FakeMail.builder()
                 .name(MAIL_NAME + RemoteDelivery.NAME_JUNCTION + MailAddressFixture.JAMES_APACHE_ORG)
-                .attribute(MailPrioritySupport.MAIL_PRIORITY, MailPrioritySupport.HIGH_PRIORITY)
+                .attribute(MailPrioritySupport.HIGH_PRIORITY_ATTRIBUTE)
                 .recipient(MailAddressFixture.ANY_AT_JAMES)
                 .build()));
     }
diff --git a/server/mailet/mailets/src/test/java/org/apache/james/transport/matchers/dlp/DlpTest.java b/server/mailet/mailets/src/test/java/org/apache/james/transport/matchers/dlp/DlpTest.java
index 88266d6..0070178 100644
--- a/server/mailet/mailets/src/test/java/org/apache/james/transport/matchers/dlp/DlpTest.java
+++ b/server/mailet/mailets/src/test/java/org/apache/james/transport/matchers/dlp/DlpTest.java
@@ -37,6 +37,9 @@ import org.apache.james.core.Domain;
 import org.apache.james.core.MailAddress;
 import org.apache.james.core.builder.MimeMessageBuilder;
 import org.apache.james.dlp.api.DLPConfigurationItem.Id;
+import org.apache.mailet.Attribute;
+import org.apache.mailet.AttributeName;
+import org.apache.mailet.AttributeValue;
 import org.apache.mailet.base.test.FakeMail;
 import org.junit.jupiter.api.Test;
 
@@ -505,12 +508,13 @@ class DlpTest {
 
     @Test
     void matchShouldAttachMatchingRuleNameToMail() throws Exception {
+        String attributeValue = "should match sender";
         Dlp dlp = new Dlp(
             asRulesLoaderFor(
                 JAMES_APACHE_ORG_DOMAIN,
                 DlpDomainRules.builder()
                     .recipientRule(Id.of("should not match recipient"), Pattern.compile(RECIPIENT3.asString()))
-                    .senderRule(Id.of("should match sender"), Pattern.compile(JAMES_APACHE_ORG))
+                    .senderRule(Id.of(attributeValue), Pattern.compile(JAMES_APACHE_ORG))
                     .build()));
 
         FakeMail mail = FakeMail.builder()
@@ -521,7 +525,8 @@ class DlpTest {
 
         dlp.match(mail);
 
-        assertThat(mail.getAttribute("DlpMatchedRule")).isEqualTo("should match sender");
+        AttributeName name = AttributeName.of("DlpMatchedRule");
+        assertThat(mail.getAttribute(name)).contains(new Attribute(name, AttributeValue.of(attributeValue)));
     }
 
 }
\ No newline at end of file
diff --git a/server/mailrepository/mailrepository-api/src/test/java/org/apache/james/mailrepository/MailRepositoryContract.java b/server/mailrepository/mailrepository-api/src/test/java/org/apache/james/mailrepository/MailRepositoryContract.java
index ee74d10..b94e370 100644
--- a/server/mailrepository/mailrepository-api/src/test/java/org/apache/james/mailrepository/MailRepositoryContract.java
+++ b/server/mailrepository/mailrepository-api/src/test/java/org/apache/james/mailrepository/MailRepositoryContract.java
@@ -42,6 +42,8 @@ import org.apache.james.server.core.MailImpl;
 import org.apache.james.util.concurrency.ConcurrentTestRunner;
 import org.apache.james.utils.DiscreteDistribution;
 import org.apache.james.utils.DiscreteDistribution.DistributionEntry;
+import org.apache.mailet.Attribute;
+import org.apache.mailet.AttributeValue;
 import org.apache.mailet.Mail;
 import org.apache.mailet.PerRecipientHeaders;
 import org.apache.mailet.base.MailAddressFixture;
@@ -58,7 +60,7 @@ import com.google.common.hash.Hashing;
 
 public interface MailRepositoryContract {
 
-    String TEST_ATTRIBUTE = "testAttribute";
+    Attribute TEST_ATTRIBUTE = Attribute.convertToAttribute("testAttribute", "testValue");
     MailKey MAIL_1 = new MailKey("mail1");
     MailKey MAIL_2 = new MailKey("mail2");
     MailKey UNKNOWN_KEY = new MailKey("random");
@@ -74,7 +76,7 @@ public interface MailRepositoryContract {
                 new MailAddress("rec2@domain.com"));
         MailAddress sender = new MailAddress("sender@domain.com");
         MailImpl mail = new MailImpl(key.asString(), sender, recipients, mailContent);
-        mail.setAttribute(TEST_ATTRIBUTE, "testValue");
+        mail.setAttribute(TEST_ATTRIBUTE);
         return mail;
     }
 
@@ -92,7 +94,7 @@ public interface MailRepositoryContract {
             softly.assertThat(actual.getMessageSize()).isEqualTo(expected.getMessageSize());
             softly.assertThat(actual.getName()).isEqualTo(expected.getName());
             softly.assertThat(actual.getState()).isEqualTo(expected.getState());
-            softly.assertThat(actual.getAttribute(TEST_ATTRIBUTE)).isEqualTo(expected.getAttribute(TEST_ATTRIBUTE));
+            softly.assertThat(actual.getAttribute(TEST_ATTRIBUTE.getName())).isEqualTo(expected.getAttribute(TEST_ATTRIBUTE.getName()));
             softly.assertThat(actual.getErrorMessage()).isEqualTo(expected.getErrorMessage());
             softly.assertThat(actual.getRemoteHost()).isEqualTo(expected.getRemoteHost());
             softly.assertThat(actual.getRemoteAddr()).isEqualTo(expected.getRemoteAddr());
@@ -412,7 +414,7 @@ public interface MailRepositoryContract {
         Mail mail = createMail(MAIL_1);
         testee.store(mail);
 
-        mail.setAttribute(TEST_ATTRIBUTE, "newValue");
+        mail.setAttribute(new Attribute(TEST_ATTRIBUTE.getName(), AttributeValue.of("newValue")));
         testee.store(mail);
 
         assertThat(testee.list()).hasSize(1);
diff --git a/server/protocols/jmap/src/main/java/org/apache/james/jmap/mailet/SentByJmap.java b/server/protocols/jmap/src/main/java/org/apache/james/jmap/mailet/SentByJmap.java
index be5ba42..1163c5b 100644
--- a/server/protocols/jmap/src/main/java/org/apache/james/jmap/mailet/SentByJmap.java
+++ b/server/protocols/jmap/src/main/java/org/apache/james/jmap/mailet/SentByJmap.java
@@ -25,6 +25,7 @@ import java.util.Collection;
 
 import org.apache.james.core.MailAddress;
 import org.apache.james.jmap.send.MailMetadata;
+import org.apache.mailet.AttributeUtils;
 import org.apache.mailet.Mail;
 import org.apache.mailet.base.GenericMatcher;
 
@@ -33,11 +34,8 @@ import com.google.common.collect.ImmutableList;
 public class SentByJmap extends GenericMatcher {
     @Override
     public Collection<MailAddress> match(Mail mail) {
-        String authUser = (String) mail.getAttribute(MailMetadata.MAIL_METADATA_USERNAME_ATTRIBUTE);
-        if (authUser != null) {
-            return mail.getRecipients();
-        } else {
-            return ImmutableList.of();
-        }
+        return AttributeUtils.getAttributeValueFromMail(mail, MailMetadata.MAIL_METADATA_USERNAME_ATTRIBUTE)
+            .map(ignored -> mail.getRecipients())
+            .orElse(ImmutableList.of());
     }
 }
diff --git a/server/protocols/jmap/src/main/java/org/apache/james/jmap/send/MailMetadata.java b/server/protocols/jmap/src/main/java/org/apache/james/jmap/send/MailMetadata.java
index 3eebac9..155b58c 100644
--- a/server/protocols/jmap/src/main/java/org/apache/james/jmap/send/MailMetadata.java
+++ b/server/protocols/jmap/src/main/java/org/apache/james/jmap/send/MailMetadata.java
@@ -22,12 +22,13 @@ package org.apache.james.jmap.send;
 import java.util.Objects;
 
 import org.apache.james.mailbox.model.MessageId;
+import org.apache.mailet.AttributeName;
 
 import com.google.common.base.Preconditions;
 
 public class MailMetadata {
-    public static final String MAIL_METADATA_MESSAGE_ID_ATTRIBUTE = "org.apache.james.jmap.send.MailMetaData.messageId";
-    public static final String MAIL_METADATA_USERNAME_ATTRIBUTE = "org.apache.james.jmap.send.MailMetaData.username";
+    public static final AttributeName MAIL_METADATA_MESSAGE_ID_ATTRIBUTE = AttributeName.of("org.apache.james.jmap.send.MailMetaData.messageId");
+    public static final AttributeName MAIL_METADATA_USERNAME_ATTRIBUTE = AttributeName.of("org.apache.james.jmap.send.MailMetaData.username");
 
     private final MessageId messageId;
     private final String username;
diff --git a/server/protocols/jmap/src/main/java/org/apache/james/jmap/send/MailSpool.java b/server/protocols/jmap/src/main/java/org/apache/james/jmap/send/MailSpool.java
index db45b4f..b973cee 100644
--- a/server/protocols/jmap/src/main/java/org/apache/james/jmap/send/MailSpool.java
+++ b/server/protocols/jmap/src/main/java/org/apache/james/jmap/send/MailSpool.java
@@ -24,6 +24,8 @@ import javax.inject.Inject;
 import org.apache.james.queue.api.MailQueue;
 import org.apache.james.queue.api.MailQueue.MailQueueException;
 import org.apache.james.queue.api.MailQueueFactory;
+import org.apache.mailet.Attribute;
+import org.apache.mailet.AttributeValue;
 import org.apache.mailet.Mail;
 
 import com.google.common.annotations.VisibleForTesting;
@@ -38,8 +40,8 @@ public class MailSpool {
     }
 
     public void send(Mail mail, MailMetadata metadata) throws MailQueueException {
-        mail.setAttribute(MailMetadata.MAIL_METADATA_MESSAGE_ID_ATTRIBUTE, metadata.getMessageId().serialize());
-        mail.setAttribute(MailMetadata.MAIL_METADATA_USERNAME_ATTRIBUTE, metadata.getUsername());
+        mail.setAttribute(new Attribute(MailMetadata.MAIL_METADATA_MESSAGE_ID_ATTRIBUTE, AttributeValue.of(metadata.getMessageId().serialize())));
+        mail.setAttribute(new Attribute(MailMetadata.MAIL_METADATA_USERNAME_ATTRIBUTE, AttributeValue.of(metadata.getUsername())));
         queue.enQueue(mail);
     }
 }
diff --git a/server/protocols/jmap/src/main/java/org/apache/james/jmap/send/PostDequeueDecorator.java b/server/protocols/jmap/src/main/java/org/apache/james/jmap/send/PostDequeueDecorator.java
index 4a1df42..44be35b 100644
--- a/server/protocols/jmap/src/main/java/org/apache/james/jmap/send/PostDequeueDecorator.java
+++ b/server/protocols/jmap/src/main/java/org/apache/james/jmap/send/PostDequeueDecorator.java
@@ -18,8 +18,8 @@
  ****************************************************************/
 package org.apache.james.jmap.send;
 
-import java.io.Serializable;
 import java.util.List;
+import java.util.Optional;
 
 import javax.mail.Flags;
 import javax.mail.Flags.Flag;
@@ -41,6 +41,8 @@ import org.apache.james.mailbox.model.MessageResult;
 import org.apache.james.queue.api.MailQueue.MailQueueException;
 import org.apache.james.queue.api.MailQueue.MailQueueItem;
 import org.apache.james.queue.api.MailQueueItemDecoratorFactory.MailQueueItemDecorator;
+import org.apache.mailet.Attribute;
+import org.apache.mailet.AttributeUtils;
 import org.apache.mailet.Mail;
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
@@ -49,7 +51,7 @@ import com.google.common.collect.ImmutableList;
 
 public class PostDequeueDecorator extends MailQueueItemDecorator {
     private static final Logger LOG = LoggerFactory.getLogger(PostDequeueDecorator.class);
-    private static final String IS_DELIVERED = "DELIVERED";
+    private static final Attribute IS_DELIVERED = Attribute.convertToAttribute("DELIVERED", "DELIVERED");
 
     private final MailboxManager mailboxManager;
     private final Factory messageIdFactory;
@@ -77,13 +79,14 @@ public class PostDequeueDecorator extends MailQueueItemDecorator {
     public void done(boolean success) throws MailQueueException {
         mailQueueItem.done(success);
         if (success && mandatoryJmapMetaDataIsPresent()) {
-            MessageId messageId = messageIdFactory.fromString((String) getMail().getAttribute(MailMetadata.MAIL_METADATA_MESSAGE_ID_ATTRIBUTE));
-            String username = (String) getMail().getAttribute(MailMetadata.MAIL_METADATA_USERNAME_ATTRIBUTE);
-            if (getMail().getAttribute(IS_DELIVERED) == null) {
+            Optional<?> optionalRawMessageId = retrieveMessageId();
+            MessageId messageId = messageIdFactory.fromString((String) optionalRawMessageId.get());
+            Optional<String> username = retrieveUsername();
+            if (!getMail().getAttribute(IS_DELIVERED.getName()).isPresent()) {
                 try {
-                    MailboxSession mailboxSession = mailboxManager.createSystemSession(username);
+                    MailboxSession mailboxSession = mailboxManager.createSystemSession(username.get());
                     moveFromOutboxToSentWithSeenFlag(messageId, mailboxSession);
-                    getMail().setAttribute(IS_DELIVERED, IS_DELIVERED);
+                    getMail().setAttribute(IS_DELIVERED);
                 } catch (MailShouldBeInOutboxException e) {
                     LOG.info("Message does not exist on Outbox anymore, it could have already been sent", e);
                 } catch (MailboxException e) {
@@ -93,13 +96,26 @@ public class PostDequeueDecorator extends MailQueueItemDecorator {
         }
     }
 
+    private Optional<?> retrieveMessageId() {
+        return AttributeUtils.getAttributeValueFromMail(getMail(), MailMetadata.MAIL_METADATA_MESSAGE_ID_ATTRIBUTE);
+    }
+
+    private Optional<String> retrieveUsername() {
+        return AttributeUtils.getValueAndCastFromMail(getMail(), MailMetadata.MAIL_METADATA_USERNAME_ATTRIBUTE, String.class);
+    }
+
     private boolean mandatoryJmapMetaDataIsPresent() {
         return checkMessageIdAttribute()
             && checkUsernameAttribute();
     }
 
     private boolean checkMessageIdAttribute() {
-        Serializable messageId = getMail().getAttribute(MailMetadata.MAIL_METADATA_MESSAGE_ID_ATTRIBUTE);
+        return retrieveMessageId()
+            .map(this::validateMessageId)
+            .orElse(false);
+    }
+
+    private boolean validateMessageId(Object messageId) {
         if (messageId instanceof String) {
             try {
                 messageIdFactory.fromString((String) messageId);
@@ -107,15 +123,14 @@ public class PostDequeueDecorator extends MailQueueItemDecorator {
             } catch (Exception e) {
                 LOG.error("Invalid messageId: {}", messageId, e);
             }
-        } else if (messageId != null) {
-            LOG.error("Non-String messageId {} has type {}", messageId, messageId.getClass());
         }
+
+        LOG.error("Non-String messageId {} has type {}", messageId, messageId.getClass());
         return false;
     }
 
     private boolean checkUsernameAttribute() {
-        Serializable username = getMail().getAttribute(MailMetadata.MAIL_METADATA_USERNAME_ATTRIBUTE);
-        return (username instanceof String);
+        return retrieveUsername().isPresent();
     }
 
     private void moveFromOutboxToSentWithSeenFlag(MessageId messageId, MailboxSession mailboxSession) throws MailQueueException, MailboxException {
diff --git a/server/protocols/jmap/src/test/java/org/apache/james/jmap/mailet/SentByJmapTest.java b/server/protocols/jmap/src/test/java/org/apache/james/jmap/mailet/SentByJmapTest.java
index b62702c..11ba63d 100644
--- a/server/protocols/jmap/src/test/java/org/apache/james/jmap/mailet/SentByJmapTest.java
+++ b/server/protocols/jmap/src/test/java/org/apache/james/jmap/mailet/SentByJmapTest.java
@@ -25,6 +25,8 @@ import java.util.Collection;
 
 import org.apache.james.core.MailAddress;
 import org.apache.james.jmap.send.MailMetadata;
+import org.apache.mailet.Attribute;
+import org.apache.mailet.AttributeValue;
 import org.apache.mailet.base.MailAddressFixture;
 import org.apache.mailet.base.test.FakeMail;
 import org.apache.mailet.base.test.FakeMailContext;
@@ -49,7 +51,7 @@ public class SentByJmapTest {
         MailAddress recipient = MailAddressFixture.ANY_AT_JAMES;
         FakeMail fakeMail = FakeMail.builder()
             .recipient(recipient)
-            .attribute(MailMetadata.MAIL_METADATA_USERNAME_ATTRIBUTE, "true")
+            .attribute(new Attribute(MailMetadata.MAIL_METADATA_USERNAME_ATTRIBUTE, AttributeValue.of("true")))
             .build();
 
         Collection<MailAddress> results =  testee.match(fakeMail);
@@ -83,7 +85,7 @@ public class SentByJmapTest {
     public void matchShouldReturnEmptyCollectionWhenUserAttributeIsPresentAndThereIsNoRecipient() throws Exception {
         FakeMail fakeMail = FakeMail.builder()
             .recipients()
-            .attribute(MailMetadata.MAIL_METADATA_USERNAME_ATTRIBUTE, "true")
+            .attribute(new Attribute(MailMetadata.MAIL_METADATA_USERNAME_ATTRIBUTE, AttributeValue.of("true")))
             .build();
 
         Collection<MailAddress> results =  testee.match(fakeMail);
diff --git a/server/protocols/jmap/src/test/java/org/apache/james/jmap/mailet/filter/JMAPFilteringExtension.java b/server/protocols/jmap/src/test/java/org/apache/james/jmap/mailet/filter/JMAPFilteringExtension.java
index 526c94b..11bff54 100644
--- a/server/protocols/jmap/src/test/java/org/apache/james/jmap/mailet/filter/JMAPFilteringExtension.java
+++ b/server/protocols/jmap/src/test/java/org/apache/james/jmap/mailet/filter/JMAPFilteringExtension.java
@@ -68,7 +68,7 @@ public class JMAPFilteringExtension implements BeforeEachCallback, ParameterReso
             this.filteringManagement = filteringManagement;
             this.mailboxManager = mailboxManager;
             try {
-                this.recipient1Mailbox = createMailbox(RECIPIENT_1_USERNAME, RECIPIENT_1_MAILBOX_1);
+                this.recipient1Mailbox = createMailbox(RECIPIENT_1_USERNAME, RECIPIENT_1_MAILBOX_1.value());
             } catch (Exception e) {
                 throw new RuntimeException(e);
             }
diff --git a/server/protocols/jmap/src/test/java/org/apache/james/jmap/mailet/filter/JMAPFilteringFixture.java b/server/protocols/jmap/src/test/java/org/apache/james/jmap/mailet/filter/JMAPFilteringFixture.java
index 1b4792b..ed5da46 100644
--- a/server/protocols/jmap/src/test/java/org/apache/james/jmap/mailet/filter/JMAPFilteringFixture.java
+++ b/server/protocols/jmap/src/test/java/org/apache/james/jmap/mailet/filter/JMAPFilteringFixture.java
@@ -19,6 +19,8 @@
 
 package org.apache.james.jmap.mailet.filter;
 
+import org.apache.mailet.AttributeValue;
+
 public interface JMAPFilteringFixture {
     String GA_BOU_ZO_MEU_FULL_ADDRESS = "GA BOU ZO MEU <GA...@james.org>";
     String BOU = "BOU";
@@ -45,7 +47,7 @@ public interface JMAPFilteringFixture {
 
     String RECIPIENT_1 = "recipient1@james.org";
     String RECIPIENT_1_USERNAME = "recipient1";
-    String RECIPIENT_1_MAILBOX_1 = "recipient1_maibox1";
+    AttributeValue<String> RECIPIENT_1_MAILBOX_1 = AttributeValue.of("recipient1_maibox1");
 
     String FRED_MARTIN_FULLNAME = "Frédéric MARTIN";
     String FRED_MARTIN_FULL_SCRAMBLED_ADDRESS = "=?UTF-8?B?RnLDqWTDqXJpYyBNQVJUSU4=?= <fr...@linagora.com>";
diff --git a/server/protocols/jmap/src/test/java/org/apache/james/jmap/mailet/filter/JMAPFilteringTest.java b/server/protocols/jmap/src/test/java/org/apache/james/jmap/mailet/filter/JMAPFilteringTest.java
index 0aab648..beae898 100644
--- a/server/protocols/jmap/src/test/java/org/apache/james/jmap/mailet/filter/JMAPFilteringTest.java
+++ b/server/protocols/jmap/src/test/java/org/apache/james/jmap/mailet/filter/JMAPFilteringTest.java
@@ -64,6 +64,9 @@ import org.apache.james.jmap.api.filtering.Rule.Condition.Field;
 import org.apache.james.jmap.mailet.filter.JMAPFilteringExtension.JMAPFilteringTestSystem;
 import org.apache.james.mailbox.model.MailboxId;
 import org.apache.james.util.StreamUtils;
+import org.apache.mailet.Attribute;
+import org.apache.mailet.AttributeName;
+import org.apache.mailet.AttributeValue;
 import org.apache.mailet.base.RFC2822Headers;
 import org.apache.mailet.base.test.FakeMail;
 import org.junit.jupiter.api.Nested;
@@ -80,6 +83,9 @@ import com.google.common.collect.ImmutableList;
 @ExtendWith(JMAPFilteringExtension.class)
 class JMAPFilteringTest {
 
+    private static final AttributeName RECIPIENT_1_USERNAME_ATTRIBUTE_NAME = AttributeName.of(DELIVERY_PATH_PREFIX + RECIPIENT_1_USERNAME);
+    private static final Attribute RECIPIENT_1_MAILBOX_1_ATTRIBUTE = new Attribute(RECIPIENT_1_USERNAME_ATTRIBUTE_NAME, RECIPIENT_1_MAILBOX_1);
+
     static class FilteringArgumentBuilder {
         private Optional<String> description;
         private Optional<Rule.Condition.Field> field;
@@ -564,8 +570,8 @@ class JMAPFilteringTest {
         FakeMail mail = testSystem.asMail(mimeMessageBuilder);
         testSystem.getJmapFiltering().service(mail);
 
-        assertThat(mail.getAttribute(DELIVERY_PATH_PREFIX + RECIPIENT_1_USERNAME))
-                .isEqualTo(RECIPIENT_1_MAILBOX_1);
+        assertThat(mail.getAttribute(RECIPIENT_1_USERNAME_ATTRIBUTE_NAME))
+                .contains(RECIPIENT_1_MAILBOX_1_ATTRIBUTE);
     }
 
     @ParameterizedTest(name = "CONTAINS should not match for field {1}: {0}")
@@ -580,8 +586,8 @@ class JMAPFilteringTest {
         FakeMail mail = testSystem.asMail(mimeMessageBuilder);
         testSystem.getJmapFiltering().service(mail);
 
-        assertThat(mail.getAttribute(DELIVERY_PATH_PREFIX + RECIPIENT_1_USERNAME))
-                .isNull();
+        assertThat(mail.getAttribute(RECIPIENT_1_USERNAME_ATTRIBUTE_NAME))
+                .isEmpty();
     }
 
     @ParameterizedTest(name = "NOT-CONTAINS should match for field {1}: {0}")
@@ -595,8 +601,8 @@ class JMAPFilteringTest {
         FakeMail mail = testSystem.asMail(mimeMessageBuilder);
         testSystem.getJmapFiltering().service(mail);
 
-        assertThat(mail.getAttribute(DELIVERY_PATH_PREFIX + RECIPIENT_1_USERNAME))
-            .isEqualTo(RECIPIENT_1_MAILBOX_1);
+        assertThat(mail.getAttribute(RECIPIENT_1_USERNAME_ATTRIBUTE_NAME))
+            .contains(RECIPIENT_1_MAILBOX_1_ATTRIBUTE);
     }
 
 
@@ -612,8 +618,8 @@ class JMAPFilteringTest {
         FakeMail mail = testSystem.asMail(mimeMessageBuilder);
         testSystem.getJmapFiltering().service(mail);
 
-        assertThat(mail.getAttribute(DELIVERY_PATH_PREFIX + RECIPIENT_1_USERNAME))
-            .isNull();
+        assertThat(mail.getAttribute(RECIPIENT_1_USERNAME_ATTRIBUTE_NAME))
+            .isEmpty();
     }
 
     @ParameterizedTest(name = "EXACTLY-EQUALS should match for field {1}: {0}")
@@ -628,8 +634,8 @@ class JMAPFilteringTest {
         FakeMail mail = testSystem.asMail(mimeMessageBuilder);
         testSystem.getJmapFiltering().service(mail);
 
-        assertThat(mail.getAttribute(DELIVERY_PATH_PREFIX + RECIPIENT_1_USERNAME))
-            .isEqualTo(RECIPIENT_1_MAILBOX_1);
+        assertThat(mail.getAttribute(RECIPIENT_1_USERNAME_ATTRIBUTE_NAME))
+            .contains(RECIPIENT_1_MAILBOX_1_ATTRIBUTE);
     }
 
     @ParameterizedTest(name = "EXACTLY-EQUALS should not match for field {1}: {0}")
@@ -643,8 +649,8 @@ class JMAPFilteringTest {
         FakeMail mail = testSystem.asMail(mimeMessageBuilder);
         testSystem.getJmapFiltering().service(mail);
 
-        assertThat(mail.getAttribute(DELIVERY_PATH_PREFIX + RECIPIENT_1_USERNAME))
-            .isNull();
+        assertThat(mail.getAttribute(RECIPIENT_1_USERNAME_ATTRIBUTE_NAME))
+            .isEmpty();
     }
 
     @ParameterizedTest(name = "NOT_EXACTLY_EQUALS should match for field {1}: {0}")
@@ -659,8 +665,8 @@ class JMAPFilteringTest {
         FakeMail mail = testSystem.asMail(mimeMessageBuilder);
         testSystem.getJmapFiltering().service(mail);
 
-        assertThat(mail.getAttribute(DELIVERY_PATH_PREFIX + RECIPIENT_1_USERNAME))
-            .isEqualTo(RECIPIENT_1_MAILBOX_1);
+        assertThat(mail.getAttribute(RECIPIENT_1_USERNAME_ATTRIBUTE_NAME))
+            .contains(RECIPIENT_1_MAILBOX_1_ATTRIBUTE);
     }
 
     @ParameterizedTest(name = "NOT_EXACTLY_EQUALS should not match for field {1}: {0}")
@@ -674,8 +680,8 @@ class JMAPFilteringTest {
         FakeMail mail = testSystem.asMail(mimeMessageBuilder);
         testSystem.getJmapFiltering().service(mail);
 
-        assertThat(mail.getAttribute(DELIVERY_PATH_PREFIX + RECIPIENT_1_USERNAME))
-            .isNull();
+        assertThat(mail.getAttribute(RECIPIENT_1_USERNAME_ATTRIBUTE_NAME))
+            .isEmpty();
     }
 
     @Nested
@@ -713,8 +719,8 @@ class JMAPFilteringTest {
 
             testSystem.getJmapFiltering().service(mail);
 
-            assertThat(mail.getAttribute(DELIVERY_PATH_PREFIX + RECIPIENT_1_USERNAME))
-                .isEqualTo("RECIPIENT_1_MAILBOX_3");
+            assertThat(mail.getAttribute(RECIPIENT_1_USERNAME_ATTRIBUTE_NAME))
+                .contains(new Attribute(RECIPIENT_1_USERNAME_ATTRIBUTE_NAME, AttributeValue.of("RECIPIENT_1_MAILBOX_3")));
         }
 
         @Test
@@ -739,8 +745,8 @@ class JMAPFilteringTest {
 
             testSystem.getJmapFiltering().service(mail);
 
-            assertThat(mail.getAttribute(DELIVERY_PATH_PREFIX + RECIPIENT_1_USERNAME))
-                .isEqualTo("RECIPIENT_1_MAILBOX_1");
+            assertThat(mail.getAttribute(RECIPIENT_1_USERNAME_ATTRIBUTE_NAME))
+                .contains(new Attribute(RECIPIENT_1_USERNAME_ATTRIBUTE_NAME, AttributeValue.of("RECIPIENT_1_MAILBOX_1")));
         }
 
         @Test
@@ -767,8 +773,8 @@ class JMAPFilteringTest {
 
             testSystem.getJmapFiltering().service(mail);
 
-            assertThat(mail.getAttribute(DELIVERY_PATH_PREFIX + RECIPIENT_1_USERNAME))
-                .isEqualTo("RECIPIENT_1_MAILBOX_1");
+            assertThat(mail.getAttribute(RECIPIENT_1_USERNAME_ATTRIBUTE_NAME))
+                .contains(new Attribute(RECIPIENT_1_USERNAME_ATTRIBUTE_NAME, AttributeValue.of("RECIPIENT_1_MAILBOX_1")));
         }
 
         @Test
@@ -788,8 +794,8 @@ class JMAPFilteringTest {
             FakeMail mail = testSystem.asMail(mimeMessageBuilder());
             testSystem.getJmapFiltering().service(mail);
 
-            assertThat(mail.getAttribute(DELIVERY_PATH_PREFIX + RECIPIENT_1_USERNAME))
-                .isNull();
+            assertThat(mail.getAttribute(RECIPIENT_1_USERNAME_ATTRIBUTE_NAME))
+                .isEmpty();
         }
 
         @Test
@@ -806,8 +812,8 @@ class JMAPFilteringTest {
 
             testSystem.getJmapFiltering().service(mail);
 
-            assertThat(mail.getAttribute(DELIVERY_PATH_PREFIX + RECIPIENT_1_USERNAME))
-                .isNull();
+            assertThat(mail.getAttribute(RECIPIENT_1_USERNAME_ATTRIBUTE_NAME))
+                .isEmpty();
         }
     }
 
@@ -847,8 +853,8 @@ class JMAPFilteringTest {
 
             testSystem.getJmapFiltering().service(mail);
 
-            assertThat(mail.getAttribute(DELIVERY_PATH_PREFIX + RECIPIENT_1_USERNAME))
-                .isNull();
+            assertThat(mail.getAttribute(RECIPIENT_1_USERNAME_ATTRIBUTE_NAME))
+                .isEmpty();
         }
 
         @Test
@@ -874,8 +880,8 @@ class JMAPFilteringTest {
 
             testSystem.getJmapFiltering().service(mail);
 
-            assertThat(mail.getAttribute(DELIVERY_PATH_PREFIX + RECIPIENT_1_USERNAME))
-                .isEqualTo(RECIPIENT_1_MAILBOX_1);
+            assertThat(mail.getAttribute(RECIPIENT_1_USERNAME_ATTRIBUTE_NAME))
+                .contains(RECIPIENT_1_MAILBOX_1_ATTRIBUTE);
         }
 
         @Test
@@ -897,8 +903,8 @@ class JMAPFilteringTest {
 
             testSystem.getJmapFiltering().service(mail);
 
-            assertThat(mail.getAttribute(DELIVERY_PATH_PREFIX + RECIPIENT_1_USERNAME))
-                .isEqualTo(RECIPIENT_1_MAILBOX_1);
+            assertThat(mail.getAttribute(RECIPIENT_1_USERNAME_ATTRIBUTE_NAME))
+                .contains(RECIPIENT_1_MAILBOX_1_ATTRIBUTE);
         }
     }
 }
\ No newline at end of file
diff --git a/server/protocols/jmap/src/test/java/org/apache/james/jmap/send/MailSpoolTest.java b/server/protocols/jmap/src/test/java/org/apache/james/jmap/send/MailSpoolTest.java
index abc6291..5984cde 100644
--- a/server/protocols/jmap/src/test/java/org/apache/james/jmap/send/MailSpoolTest.java
+++ b/server/protocols/jmap/src/test/java/org/apache/james/jmap/send/MailSpoolTest.java
@@ -27,6 +27,8 @@ import org.apache.james.queue.api.MailQueue.MailQueueItem;
 import org.apache.james.queue.api.MailQueueFactory;
 import org.apache.james.queue.api.RawMailQueueItemDecoratorFactory;
 import org.apache.james.queue.memory.MemoryMailQueueFactory;
+import org.apache.mailet.Attribute;
+import org.apache.mailet.AttributeValue;
 import org.apache.mailet.base.test.FakeMail;
 import org.junit.Before;
 import org.junit.Test;
@@ -69,9 +71,9 @@ public class MailSpoolTest {
 
         MailQueueItem actual = myQueue.deQueue();
         assertThat(actual.getMail().getAttribute(MailMetadata.MAIL_METADATA_USERNAME_ATTRIBUTE))
-            .isEqualTo(USERNAME);
+            .contains(new Attribute(MailMetadata.MAIL_METADATA_USERNAME_ATTRIBUTE, AttributeValue.of(USERNAME)));
         assertThat(actual.getMail().getAttribute(MailMetadata.MAIL_METADATA_MESSAGE_ID_ATTRIBUTE))
-            .isEqualTo(MESSAGE_ID.serialize());
+            .contains(new Attribute(MailMetadata.MAIL_METADATA_MESSAGE_ID_ATTRIBUTE, AttributeValue.of(MESSAGE_ID.serialize())));
     }
 
 }
diff --git a/server/protocols/jmap/src/test/java/org/apache/james/jmap/send/PostDequeueDecoratorTest.java b/server/protocols/jmap/src/test/java/org/apache/james/jmap/send/PostDequeueDecoratorTest.java
index 80affe6..9cae9ac 100644
--- a/server/protocols/jmap/src/test/java/org/apache/james/jmap/send/PostDequeueDecoratorTest.java
+++ b/server/protocols/jmap/src/test/java/org/apache/james/jmap/send/PostDequeueDecoratorTest.java
@@ -55,6 +55,8 @@ import org.apache.james.mailbox.store.SystemMailboxesProviderImpl;
 import org.apache.james.mime4j.dom.Message;
 import org.apache.james.queue.api.MailQueue;
 import org.apache.james.queue.api.MailQueue.MailQueueItem;
+import org.apache.mailet.Attribute;
+import org.apache.mailet.AttributeValue;
 import org.apache.mailet.Mail;
 import org.apache.mailet.base.test.FakeMail;
 import org.junit.Before;
@@ -69,6 +71,7 @@ public class PostDequeueDecoratorTest {
     private static final MessageUid UID = MessageUid.of(1);
     private static final MailboxPath OUTBOX_MAILBOX_PATH = MailboxPath.forUser(USERNAME, OUTBOX);
     private static final MailboxPath SENT_MAILBOX_PATH = MailboxPath.forUser(USERNAME, SENT);
+    private static final Attribute USERNAME_ATTRIBUTE = new Attribute(MailMetadata.MAIL_METADATA_USERNAME_ATTRIBUTE, AttributeValue.of(USERNAME));
     
     private StoreMailboxManager mailboxManager;
     private MailQueueItem mockedMailQueueItem;
@@ -112,8 +115,8 @@ public class PostDequeueDecoratorTest {
         mailboxManager.createMailbox(SENT_MAILBOX_PATH, mailboxSession);
         MessageManager messageManager = mailboxManager.getMailbox(SENT_MAILBOX_PATH, mailboxSession);
         ComposedMessageId sentMessageId = messageManager.appendMessage(AppendCommand.from(message), mailboxSession);
-        mail.setAttribute(MailMetadata.MAIL_METADATA_MESSAGE_ID_ATTRIBUTE, sentMessageId.getMessageId().serialize());
-        mail.setAttribute(MailMetadata.MAIL_METADATA_USERNAME_ATTRIBUTE, USERNAME);
+        mail.setAttribute(messageIdAttribute(sentMessageId.getMessageId().serialize()));
+        mail.setAttribute(USERNAME_ATTRIBUTE);
         
         testee.done(true);
     }
@@ -124,8 +127,8 @@ public class PostDequeueDecoratorTest {
         mailboxManager.createMailbox(OUTBOX_MAILBOX_PATH, mailboxSession);
         MessageManager messageManager = mailboxManager.getMailbox(OUTBOX_MAILBOX_PATH, mailboxSession);
         ComposedMessageId messageId = messageManager.appendMessage(AppendCommand.from(message), mailboxSession);
-        mail.setAttribute(MailMetadata.MAIL_METADATA_MESSAGE_ID_ATTRIBUTE, messageId.getMessageId().serialize());
-        mail.setAttribute(MailMetadata.MAIL_METADATA_USERNAME_ATTRIBUTE, USERNAME);
+        mail.setAttribute(messageIdAttribute(messageId.getMessageId().serialize()));
+        mail.setAttribute(USERNAME_ATTRIBUTE);
 
         testee.done(true);
     }
@@ -137,8 +140,8 @@ public class PostDequeueDecoratorTest {
         mailboxManager.createMailbox(SENT_MAILBOX_PATH, mailboxSession);
         MessageManager messageManager = mailboxManager.getMailbox(OUTBOX_MAILBOX_PATH, mailboxSession);
         ComposedMessageId messageId = messageManager.appendMessage(AppendCommand.from(message), mailboxSession);
-        mail.setAttribute(MailMetadata.MAIL_METADATA_MESSAGE_ID_ATTRIBUTE, messageId.getMessageId().serialize());
-        mail.setAttribute(MailMetadata.MAIL_METADATA_USERNAME_ATTRIBUTE, USERNAME);
+        mail.setAttribute(messageIdAttribute(messageId.getMessageId().serialize()));
+        mail.setAttribute(USERNAME_ATTRIBUTE);
         
         testee.done(true);
         
@@ -154,8 +157,8 @@ public class PostDequeueDecoratorTest {
         mailboxManager.createMailbox(SENT_MAILBOX_PATH, mailboxSession);
         MessageManager messageManager = mailboxManager.getMailbox(OUTBOX_MAILBOX_PATH, mailboxSession);
         ComposedMessageId messageId = messageManager.appendMessage(AppendCommand.from(message), mailboxSession);
-        mail.setAttribute(MailMetadata.MAIL_METADATA_MESSAGE_ID_ATTRIBUTE, messageId.getMessageId().serialize());
-        mail.setAttribute(MailMetadata.MAIL_METADATA_USERNAME_ATTRIBUTE, USERNAME);
+        mail.setAttribute(messageIdAttribute(messageId.getMessageId().serialize()));
+        mail.setAttribute(USERNAME_ATTRIBUTE);
         
         testee.done(true);
         
@@ -171,8 +174,8 @@ public class PostDequeueDecoratorTest {
         mailboxManager.createMailbox(SENT_MAILBOX_PATH, mailboxSession);
         MessageManager messageManager = mailboxManager.getMailbox(OUTBOX_MAILBOX_PATH, mailboxSession);
         ComposedMessageId messageId = messageManager.appendMessage(AppendCommand.from(message), mailboxSession);
-        mail.setAttribute(MailMetadata.MAIL_METADATA_MESSAGE_ID_ATTRIBUTE, messageId.getMessageId().serialize());
-        mail.setAttribute(MailMetadata.MAIL_METADATA_USERNAME_ATTRIBUTE, USERNAME);
+        mail.setAttribute(messageIdAttribute(messageId.getMessageId().serialize()));
+        mail.setAttribute(USERNAME_ATTRIBUTE);
         
         testee.done(false);
         
@@ -203,7 +206,7 @@ public class PostDequeueDecoratorTest {
         mailboxManager.createMailbox(SENT_MAILBOX_PATH, mailboxSession);
         MessageManager messageManager = mailboxManager.getMailbox(OUTBOX_MAILBOX_PATH, mailboxSession);
         ComposedMessageId messageId = messageManager.appendMessage(AppendCommand.from(message), mailboxSession);
-        mail.setAttribute(MailMetadata.MAIL_METADATA_MESSAGE_ID_ATTRIBUTE, messageId.getMessageId().serialize());
+        mail.setAttribute(messageIdAttribute(messageId.getMessageId().serialize()));
         
         testee.done(true);
         
@@ -219,7 +222,7 @@ public class PostDequeueDecoratorTest {
         mailboxManager.createMailbox(SENT_MAILBOX_PATH, mailboxSession);
         MessageManager messageManager = mailboxManager.getMailbox(OUTBOX_MAILBOX_PATH, mailboxSession);
         messageManager.appendMessage(AppendCommand.from(message), mailboxSession);
-        mail.setAttribute(MailMetadata.MAIL_METADATA_USERNAME_ATTRIBUTE, USERNAME);
+        mail.setAttribute(USERNAME_ATTRIBUTE);
         
         testee.done(true);
         
@@ -235,8 +238,8 @@ public class PostDequeueDecoratorTest {
         mailboxManager.createMailbox(SENT_MAILBOX_PATH, mailboxSession);
         MessageManager messageManager = mailboxManager.getMailbox(OUTBOX_MAILBOX_PATH, mailboxSession);
         messageManager.appendMessage(AppendCommand.from(message), mailboxSession);
-        mail.setAttribute(MailMetadata.MAIL_METADATA_USERNAME_ATTRIBUTE, USERNAME);
-        mail.setAttribute(MailMetadata.MAIL_METADATA_MESSAGE_ID_ATTRIBUTE, "invalid");
+        mail.setAttribute(USERNAME_ATTRIBUTE);
+        mail.setAttribute(messageIdAttribute("invalid"));
         
         testee.done(true);
         
@@ -256,8 +259,8 @@ public class PostDequeueDecoratorTest {
         MailboxId sentMailboxId = mailboxManager.createMailbox(SENT_MAILBOX_PATH, mailboxSession).get();
         MessageManager messageManager = mailboxManager.getMailbox(OUTBOX_MAILBOX_PATH, mailboxSession);
         ComposedMessageId messageId = messageManager.appendMessage(AppendCommand.from(message), mailboxSession);
-        mail.setAttribute(MailMetadata.MAIL_METADATA_MESSAGE_ID_ATTRIBUTE, messageId.getMessageId().serialize());
-        mail.setAttribute(MailMetadata.MAIL_METADATA_USERNAME_ATTRIBUTE, USERNAME);
+        mail.setAttribute(messageIdAttribute(messageId.getMessageId().serialize()));
+        mail.setAttribute(USERNAME_ATTRIBUTE);
 
         ImmutableList<MessageResult> allMessages = ImmutableList.copyOf(messageManager.getMessages(MessageRange.all(), FetchGroupImpl.MINIMAL, mailboxSession));
 
@@ -284,11 +287,15 @@ public class PostDequeueDecoratorTest {
         mailboxManager.createMailbox(SENT_MAILBOX_PATH, mailboxSession).get();
         MessageManager messageManager = mailboxManager.getMailbox(OUTBOX_MAILBOX_PATH, mailboxSession);
         ComposedMessageId messageId = messageManager.appendMessage(AppendCommand.from(message), mailboxSession);
-        mail.setAttribute(MailMetadata.MAIL_METADATA_MESSAGE_ID_ATTRIBUTE, messageId.getMessageId().serialize());
-        mail.setAttribute(MailMetadata.MAIL_METADATA_USERNAME_ATTRIBUTE, USERNAME);
+        mail.setAttribute(messageIdAttribute(messageId.getMessageId().serialize()));
+        mail.setAttribute(USERNAME_ATTRIBUTE);
 
         when(messageIdManager.getMessages(eq(ImmutableList.of(messageId.getMessageId())), eq(FetchGroupImpl.MINIMAL), any(MailboxSession.class))).thenThrow(MailboxException.class);
 
         testee.done(true);
     }
+
+    private Attribute messageIdAttribute(String  value) {
+        return new Attribute(MailMetadata.MAIL_METADATA_MESSAGE_ID_ATTRIBUTE, AttributeValue.of(value));
+    }
 }
diff --git a/server/protocols/protocols-smtp/src/main/java/org/apache/james/smtpserver/AddDefaultAttributesMessageHook.java b/server/protocols/protocols-smtp/src/main/java/org/apache/james/smtpserver/AddDefaultAttributesMessageHook.java
index da701fa..1412cdf 100644
--- a/server/protocols/protocols-smtp/src/main/java/org/apache/james/smtpserver/AddDefaultAttributesMessageHook.java
+++ b/server/protocols/protocols-smtp/src/main/java/org/apache/james/smtpserver/AddDefaultAttributesMessageHook.java
@@ -23,6 +23,8 @@ import org.apache.commons.configuration.ConfigurationException;
 import org.apache.james.protocols.smtp.SMTPSession;
 import org.apache.james.protocols.smtp.hook.HookResult;
 import org.apache.james.server.core.MailImpl;
+import org.apache.mailet.Attribute;
+import org.apache.mailet.AttributeValue;
 import org.apache.mailet.Mail;
 
 /**
@@ -53,7 +55,7 @@ public class AddDefaultAttributesMessageHook implements JamesMessageHook {
             mailImpl.setRemoteHost(session.getRemoteAddress().getHostName());
             mailImpl.setRemoteAddr(session.getRemoteAddress().getAddress().getHostAddress());
             if (session.getUser() != null) {
-                mail.setAttribute(Mail.SMTP_AUTH_USER_ATTRIBUTE_NAME, session.getUser());
+                mail.setAttribute(new Attribute(Mail.SMTP_AUTH_USER, AttributeValue.of(session.getUser())));
             }
 
             if (session.isRelayingAllowed()) {
diff --git a/server/protocols/protocols-smtp/src/main/java/org/apache/james/smtpserver/MailPriorityHandler.java b/server/protocols/protocols-smtp/src/main/java/org/apache/james/smtpserver/MailPriorityHandler.java
index 4959b9e..5230973 100644
--- a/server/protocols/protocols-smtp/src/main/java/org/apache/james/smtpserver/MailPriorityHandler.java
+++ b/server/protocols/protocols-smtp/src/main/java/org/apache/james/smtpserver/MailPriorityHandler.java
@@ -33,6 +33,8 @@ import org.apache.james.protocols.api.handler.ProtocolHandler;
 import org.apache.james.protocols.smtp.SMTPSession;
 import org.apache.james.protocols.smtp.hook.HookResult;
 import org.apache.james.queue.api.MailPrioritySupport;
+import org.apache.mailet.Attribute;
+import org.apache.mailet.AttributeValue;
 import org.apache.mailet.Mail;
 
 /**
@@ -71,7 +73,7 @@ public class MailPriorityHandler implements JamesMessageHook, ProtocolHandler {
 
         // set the priority if one was found
         if (p != null) {
-            mail.setAttribute(MailPrioritySupport.MAIL_PRIORITY, p);
+            mail.setAttribute(new Attribute(MailPrioritySupport.MAIL_PRIORITY, AttributeValue.of(p)));
         }
         return HookResult.DECLINED;
     }
diff --git a/server/protocols/protocols-smtp/src/main/java/org/apache/james/smtpserver/fastfail/SpamAssassinHandler.java b/server/protocols/protocols-smtp/src/main/java/org/apache/james/smtpserver/fastfail/SpamAssassinHandler.java
index ef60371..01718c7 100644
--- a/server/protocols/protocols-smtp/src/main/java/org/apache/james/smtpserver/fastfail/SpamAssassinHandler.java
+++ b/server/protocols/protocols-smtp/src/main/java/org/apache/james/smtpserver/fastfail/SpamAssassinHandler.java
@@ -127,9 +127,7 @@ public class SpamAssassinHandler implements JamesMessageHook, ProtocolHandler {
             SpamAssassinResult result = sa.scanMail(message);
 
             // Add the headers
-            for (String key : result.getHeadersAsAttribute().keySet()) {
-                mail.setAttribute(key, result.getHeadersAsAttribute().get(key));
-            }
+            result.getHeadersAsAttributes().forEach(mail::setAttribute);
 
             // Check if rejectionHits was configured
             if (spamdRejectionHits > 0) {
diff --git a/server/protocols/protocols-smtp/src/test/java/org/apache/james/smtpserver/SpamAssassinHandlerTest.java b/server/protocols/protocols-smtp/src/test/java/org/apache/james/smtpserver/SpamAssassinHandlerTest.java
index db8b783..a257884 100644
--- a/server/protocols/protocols-smtp/src/test/java/org/apache/james/smtpserver/SpamAssassinHandlerTest.java
+++ b/server/protocols/protocols-smtp/src/test/java/org/apache/james/smtpserver/SpamAssassinHandlerTest.java
@@ -18,7 +18,7 @@
  ****************************************************************/
 package org.apache.james.smtpserver;
 
-import static org.apache.james.spamassassin.SpamAssassinResult.STATUS_MAIL_ATTRIBUTE_NAME;
+import static org.apache.james.spamassassin.SpamAssassinResult.STATUS_MAIL;
 import static org.assertj.core.api.Assertions.assertThat;
 
 import java.util.HashMap;
@@ -39,6 +39,8 @@ import org.apache.james.smtpserver.fastfail.SpamAssassinHandler;
 import org.apache.james.spamassassin.SpamAssassinResult;
 import org.apache.james.spamassassin.mock.MockSpamd;
 import org.apache.james.spamassassin.mock.MockSpamdTestRule;
+import org.apache.mailet.Attribute;
+import org.apache.mailet.AttributeValue;
 import org.apache.mailet.Mail;
 import org.apache.mailet.base.test.FakeMail;
 import org.junit.Rule;
@@ -46,8 +48,11 @@ import org.junit.Test;
 
 public class SpamAssassinHandlerTest {
 
+    private static final String SPAMD_HOST = "localhost";
+    private static final Attribute FLAG_MAIL_ATTRIBUTE_NO = new Attribute(SpamAssassinResult.FLAG_MAIL, AttributeValue.of("NO"));
+    private static final Attribute FLAG_MAIL_ATTRIBUTE_YES = new Attribute(SpamAssassinResult.FLAG_MAIL, AttributeValue.of("YES"));
+
     private Mail mockedMail;
-    public static final String SPAMD_HOST = "localhost";
 
     private SMTPSession setupMockedSMTPSession(Mail mail) {
         mockedMail = mail;
@@ -127,8 +132,8 @@ public class SpamAssassinHandlerTest {
         HookResult response = handler.onMessage(session, mockedMail);
 
         assertThat(HookReturnCode.declined()).describedAs("Email was not rejected").isEqualTo(response.getResult());
-        assertThat("NO").describedAs("email was not spam").isEqualTo(mockedMail.getAttribute(SpamAssassinResult.FLAG_MAIL_ATTRIBUTE_NAME));
-        assertThat(mockedMail.getAttribute(STATUS_MAIL_ATTRIBUTE_NAME)).withFailMessage("spam hits").isNotNull();
+        assertThat(mockedMail.getAttribute(SpamAssassinResult.FLAG_MAIL)).describedAs("email was not spam").contains(FLAG_MAIL_ATTRIBUTE_NO);
+        assertThat(mockedMail.getAttribute(STATUS_MAIL)).withFailMessage("spam hits").isPresent();
 
     }
 
@@ -144,8 +149,8 @@ public class SpamAssassinHandlerTest {
         HookResult response = handler.onMessage(session, mockedMail);
 
         assertThat(HookReturnCode.declined()).describedAs("Email was not rejected").isEqualTo(response.getResult());
-        assertThat("YES").describedAs("email was spam").isEqualTo(mockedMail.getAttribute(SpamAssassinResult.FLAG_MAIL_ATTRIBUTE_NAME));
-        assertThat(mockedMail.getAttribute(STATUS_MAIL_ATTRIBUTE_NAME)).withFailMessage("spam hits").isNotNull();
+        assertThat(mockedMail.getAttribute(SpamAssassinResult.FLAG_MAIL)).describedAs("email was spam").contains(FLAG_MAIL_ATTRIBUTE_YES);
+        assertThat(mockedMail.getAttribute(STATUS_MAIL)).withFailMessage("spam hits").isPresent();
     }
 
     @Test
@@ -160,7 +165,7 @@ public class SpamAssassinHandlerTest {
         HookResult response = handler.onMessage(session, mockedMail);
 
         assertThat(HookReturnCode.deny()).describedAs("Email was rejected").isEqualTo(response.getResult());
-        assertThat("YES").describedAs("email was spam").isEqualTo(mockedMail.getAttribute(SpamAssassinResult.FLAG_MAIL_ATTRIBUTE_NAME));
-        assertThat(mockedMail.getAttribute(STATUS_MAIL_ATTRIBUTE_NAME)).withFailMessage("spam hits").isNotNull();
+        assertThat(mockedMail.getAttribute(SpamAssassinResult.FLAG_MAIL)).describedAs("email was spam").contains(FLAG_MAIL_ATTRIBUTE_YES);
+        assertThat(mockedMail.getAttribute(STATUS_MAIL)).withFailMessage("spam hits").isPresent();
     }
 }
diff --git a/server/queue/queue-api/src/main/java/org/apache/james/queue/api/MailPrioritySupport.java b/server/queue/queue-api/src/main/java/org/apache/james/queue/api/MailPrioritySupport.java
index 0c22464..ad3f665 100644
--- a/server/queue/queue-api/src/main/java/org/apache/james/queue/api/MailPrioritySupport.java
+++ b/server/queue/queue-api/src/main/java/org/apache/james/queue/api/MailPrioritySupport.java
@@ -18,25 +18,32 @@
  ****************************************************************/
 package org.apache.james.queue.api;
 
+import org.apache.mailet.Attribute;
+import org.apache.mailet.AttributeName;
+import org.apache.mailet.AttributeValue;
+
 /**
  * Supports Mail Priority handling
  */
 public interface MailPrioritySupport {
 
+    /**
+     * Attribute name for support if priority. If the attribute is set and
+     * priority handling is enabled it will take care of move the Mails with
+     * higher priority to the head of the queue (so the mails are faster
+     * handled).
+     */
+    AttributeName MAIL_PRIORITY = AttributeName.of("MAIL_PRIORITY");
+
     /** Handle mail with lowest priority */
     int LOW_PRIORITY = 0;
+    Attribute LOW_PRIORITY_ATTRIBUTE = new Attribute(MAIL_PRIORITY, AttributeValue.of(LOW_PRIORITY));
 
     /** Handle mail with normal priority (this is the default) */
     int NORMAL_PRIORITY = 5;
+    Attribute NORMAL_PRIORITY_ATTRIBUTE = new Attribute(MAIL_PRIORITY, AttributeValue.of(NORMAL_PRIORITY));
 
     /** Handle mail with highest priority */
     int HIGH_PRIORITY = 9;
-
-    /**
-     * Attribute name for support if priority. If the attribute is set and
-     * priority handling is enabled it will take care of move the Mails with
-     * higher priority to the head of the queue (so the mails are faster
-     * handled).
-     */
-    String MAIL_PRIORITY = "MAIL_PRIORITY";
+    Attribute HIGH_PRIORITY_ATTRIBUTE = new Attribute(MAIL_PRIORITY, AttributeValue.of(HIGH_PRIORITY));
 }
diff --git a/server/queue/queue-api/src/test/java/org/apache/james/queue/api/DelayedPriorityMailQueueContract.java b/server/queue/queue-api/src/test/java/org/apache/james/queue/api/DelayedPriorityMailQueueContract.java
index 895aa88..4ed561c 100644
--- a/server/queue/queue-api/src/test/java/org/apache/james/queue/api/DelayedPriorityMailQueueContract.java
+++ b/server/queue/queue-api/src/test/java/org/apache/james/queue/api/DelayedPriorityMailQueueContract.java
@@ -35,14 +35,14 @@ public interface DelayedPriorityMailQueueContract extends DelayedMailQueueContra
     default void delayedHighPriorityMailShouldBeDeQueuedBeforeLowPriorityNonDelayedMailAfterDelayExpiracy() throws Exception {
         getMailQueue().enQueue(defaultMail()
             .name("name1")
-            .attribute(MailPrioritySupport.MAIL_PRIORITY, MailPrioritySupport.LOW_PRIORITY)
+            .attribute(MailPrioritySupport.LOW_PRIORITY_ATTRIBUTE)
             .build());
 
         int delay = 1;
         TimeUnit unit = TimeUnit.SECONDS;
         getMailQueue().enQueue(defaultMail()
             .name("name2")
-            .attribute(MailPrioritySupport.MAIL_PRIORITY, MailPrioritySupport.HIGH_PRIORITY)
+            .attribute(MailPrioritySupport.HIGH_PRIORITY_ATTRIBUTE)
             .build(),
             delay,
             unit);
@@ -62,14 +62,14 @@ public interface DelayedPriorityMailQueueContract extends DelayedMailQueueContra
     default void delayedHighPriorityMailShouldBeDeQueuedAfterNonDelayedMail() throws Exception {
         getMailQueue().enQueue(defaultMail()
             .name("name1")
-            .attribute(MailPrioritySupport.MAIL_PRIORITY, MailPrioritySupport.LOW_PRIORITY)
+            .attribute(MailPrioritySupport.LOW_PRIORITY_ATTRIBUTE)
             .build());
 
         int delay = 1;
         TimeUnit unit = TimeUnit.SECONDS;
         getMailQueue().enQueue(defaultMail()
             .name("name2")
-            .attribute(MailPrioritySupport.MAIL_PRIORITY, MailPrioritySupport.HIGH_PRIORITY)
+            .attribute(MailPrioritySupport.HIGH_PRIORITY_ATTRIBUTE)
             .build(),
             delay,
             unit);
diff --git a/server/queue/queue-api/src/test/java/org/apache/james/queue/api/MailQueueContract.java b/server/queue/queue-api/src/test/java/org/apache/james/queue/api/MailQueueContract.java
index d6a3ec5..6491502 100644
--- a/server/queue/queue-api/src/test/java/org/apache/james/queue/api/MailQueueContract.java
+++ b/server/queue/queue-api/src/test/java/org/apache/james/queue/api/MailQueueContract.java
@@ -147,15 +147,14 @@ public interface MailQueueContract {
 
     @Test
     default void queueShouldPreserveMailAttribute() throws Exception {
-        String attributeName = "any";
-        String attributeValue = "value";
+        Attribute attribute = Attribute.convertToAttribute("any", "value");
         enQueue(defaultMail()
-            .attribute(attributeName, attributeValue)
+            .attribute(attribute)
             .build());
 
         MailQueue.MailQueueItem mailQueueItem = getMailQueue().deQueue();
-        assertThat(mailQueueItem.getMail().getAttribute(attributeName))
-            .isEqualTo(attributeValue);
+        assertThat(mailQueueItem.getMail().getAttribute(attribute.getName()))
+            .contains(attribute);
     }
 
     @Test
@@ -248,16 +247,19 @@ public interface MailQueueContract {
 
     @Test
     default void queueShouldPreserveNonStringMailAttribute() throws Exception {
-        String attributeName = "any";
-        SerializableAttribute attributeValue = new SerializableAttribute("value");
+        Attribute attribute = Attribute.convertToAttribute("any", new SerializableAttribute("value"));
         enQueue(defaultMail()
-                .attribute(attributeName, attributeValue)
+                .attribute(attribute)
                 .build());
 
         MailQueue.MailQueueItem mailQueueItem = getMailQueue().deQueue();
-        assertThat(mailQueueItem.getMail().getAttribute(attributeName))
-                .isInstanceOf(SerializableAttribute.class)
-                .isEqualTo(attributeValue);
+        assertThat(mailQueueItem.getMail().getAttribute(attribute.getName()))
+            .hasValueSatisfying(item -> {
+                assertThat(item)
+                        .isEqualTo(attribute);
+                assertThat(item.getValue().value())
+                        .isInstanceOf(SerializableAttribute.class);
+            });
     }
 
     @Test
diff --git a/server/queue/queue-api/src/test/java/org/apache/james/queue/api/PriorityMailQueueContract.java b/server/queue/queue-api/src/test/java/org/apache/james/queue/api/PriorityMailQueueContract.java
index ffe8fee..01f50bd 100644
--- a/server/queue/queue-api/src/test/java/org/apache/james/queue/api/PriorityMailQueueContract.java
+++ b/server/queue/queue-api/src/test/java/org/apache/james/queue/api/PriorityMailQueueContract.java
@@ -24,6 +24,8 @@ import static org.assertj.core.api.Assertions.assertThat;
 
 import java.util.stream.IntStream;
 
+import org.apache.mailet.Attribute;
+import org.apache.mailet.AttributeValue;
 import org.apache.mailet.Mail;
 import org.junit.jupiter.api.Test;
 
@@ -39,52 +41,52 @@ public interface PriorityMailQueueContract {
     default void priorityShouldReorderMailsWhenDequeing() throws Exception {
         getMailQueue().enQueue(defaultMail()
             .name("name3")
-            .attribute(MailPrioritySupport.MAIL_PRIORITY, 3)
+            .attribute(mailPriority(3))
             .build());
 
         getMailQueue().enQueue(defaultMail()
             .name("name9")
-            .attribute(MailPrioritySupport.MAIL_PRIORITY, 9)
+            .attribute(mailPriority(9))
             .build());
 
         getMailQueue().enQueue(defaultMail()
             .name("name1")
-            .attribute(MailPrioritySupport.MAIL_PRIORITY, 1)
+            .attribute(mailPriority(1))
             .build());
 
         getMailQueue().enQueue(defaultMail()
             .name("name8")
-            .attribute(MailPrioritySupport.MAIL_PRIORITY, 8)
+            .attribute(mailPriority(8))
             .build());
 
         getMailQueue().enQueue(defaultMail()
             .name("name6")
-            .attribute(MailPrioritySupport.MAIL_PRIORITY, 6)
+            .attribute(mailPriority(6))
             .build());
 
         getMailQueue().enQueue(defaultMail()
             .name("name0")
-            .attribute(MailPrioritySupport.MAIL_PRIORITY, 0)
+            .attribute(mailPriority(0))
             .build());
 
         getMailQueue().enQueue(defaultMail()
             .name("name7")
-            .attribute(MailPrioritySupport.MAIL_PRIORITY, 7)
+            .attribute(mailPriority(7))
             .build());
 
         getMailQueue().enQueue(defaultMail()
             .name("name4")
-            .attribute(MailPrioritySupport.MAIL_PRIORITY, 4)
+            .attribute(mailPriority(4))
             .build());
 
         getMailQueue().enQueue(defaultMail()
             .name("name2")
-            .attribute(MailPrioritySupport.MAIL_PRIORITY, 2)
+            .attribute(mailPriority(2))
             .build());
 
         getMailQueue().enQueue(defaultMail()
             .name("name5")
-            .attribute(MailPrioritySupport.MAIL_PRIORITY, 5)
+            .attribute(mailPriority(5))
             .build());
 
         ImmutableList<MailQueue.MailQueueItem> items = IntStream.range(1, 11).boxed()
@@ -105,11 +107,11 @@ public interface PriorityMailQueueContract {
     default void negativePriorityShouldDefaultToMinimumPriority() throws Exception {
         getMailQueue().enQueue(defaultMail()
             .name("name0")
-            .attribute(MailPrioritySupport.MAIL_PRIORITY, -1)
+            .attribute(mailPriority(-1))
             .build());
         getMailQueue().enQueue(defaultMail()
             .name("name1")
-            .attribute(MailPrioritySupport.MAIL_PRIORITY, 1)
+            .attribute(mailPriority(1))
             .build());
 
         MailQueue.MailQueueItem mailQueueItem1 = getMailQueue().deQueue();
@@ -124,11 +126,11 @@ public interface PriorityMailQueueContract {
     default void tooBigPriorityShouldDefaultToMaximalPriority() throws Exception {
         getMailQueue().enQueue(defaultMail()
             .name("name0")
-            .attribute(MailPrioritySupport.MAIL_PRIORITY, 12)
+            .attribute(mailPriority(12))
             .build());
         getMailQueue().enQueue(defaultMail()
             .name("name1")
-            .attribute(MailPrioritySupport.MAIL_PRIORITY, 8)
+            .attribute(mailPriority(8))
             .build());
 
         MailQueue.MailQueueItem mailQueueItem1 = getMailQueue().deQueue();
@@ -143,15 +145,15 @@ public interface PriorityMailQueueContract {
     default void invalidPriorityShouldDefaultToNormalPriority() throws Exception {
         getMailQueue().enQueue(defaultMail()
             .name("name1")
-            .attribute(MailPrioritySupport.MAIL_PRIORITY, "invalid")
+            .attribute(mailPriority("invalid"))
             .build());
         getMailQueue().enQueue(defaultMail()
             .name("name2")
-            .attribute(MailPrioritySupport.MAIL_PRIORITY, 4)
+            .attribute(mailPriority(4))
             .build());
         getMailQueue().enQueue(defaultMail()
             .name("name3")
-            .attribute(MailPrioritySupport.MAIL_PRIORITY, 6)
+            .attribute(mailPriority(6))
             .build());
 
         MailQueue.MailQueueItem mailQueueItem1 = getMailQueue().deQueue();
@@ -172,11 +174,11 @@ public interface PriorityMailQueueContract {
             .build());
         getMailQueue().enQueue(defaultMail()
             .name("name2")
-            .attribute(MailPrioritySupport.MAIL_PRIORITY, 4)
+            .attribute(mailPriority(4))
             .build());
         getMailQueue().enQueue(defaultMail()
             .name("name3")
-            .attribute(MailPrioritySupport.MAIL_PRIORITY, 6)
+            .attribute(mailPriority(6))
             .build());
 
         MailQueue.MailQueueItem mailQueueItem1 = getMailQueue().deQueue();
@@ -199,4 +201,8 @@ public interface PriorityMailQueueContract {
         MailQueue.MailQueueItem mailQueueItem = getMailQueue().deQueue();
         assertThat(mailQueueItem.getMail().getName()).isEqualTo("name1");
     }
+
+    default Attribute mailPriority(Object priority) {
+        return new Attribute(MailPrioritySupport.MAIL_PRIORITY, AttributeValue.ofAny(priority));
+    }
 }
diff --git a/server/queue/queue-api/src/test/java/org/apache/james/queue/api/PriorityManageableMailQueueContract.java b/server/queue/queue-api/src/test/java/org/apache/james/queue/api/PriorityManageableMailQueueContract.java
index 789bc1d..c9c8c6e 100644
--- a/server/queue/queue-api/src/test/java/org/apache/james/queue/api/PriorityManageableMailQueueContract.java
+++ b/server/queue/queue-api/src/test/java/org/apache/james/queue/api/PriorityManageableMailQueueContract.java
@@ -22,6 +22,8 @@ package org.apache.james.queue.api;
 import static org.apache.james.queue.api.Mails.defaultMail;
 import static org.assertj.core.api.Assertions.assertThat;
 
+import org.apache.mailet.Attribute;
+import org.apache.mailet.AttributeValue;
 import org.apache.mailet.Mail;
 import org.junit.jupiter.api.Test;
 
@@ -34,52 +36,52 @@ public interface PriorityManageableMailQueueContract extends ManageableMailQueue
     default void browseShouldBeOrderedByPriority() throws Exception {
         getManageableMailQueue().enQueue(defaultMail()
             .name("name3")
-            .attribute(MailPrioritySupport.MAIL_PRIORITY, 3)
+            .attribute(mailPriority(3))
             .build());
 
         getManageableMailQueue().enQueue(defaultMail()
             .name("name9")
-            .attribute(MailPrioritySupport.MAIL_PRIORITY, 9)
+            .attribute(mailPriority(9))
             .build());
 
         getManageableMailQueue().enQueue(defaultMail()
             .name("name1")
-            .attribute(MailPrioritySupport.MAIL_PRIORITY, 1)
+            .attribute(mailPriority(1))
             .build());
 
         getManageableMailQueue().enQueue(defaultMail()
             .name("name8")
-            .attribute(MailPrioritySupport.MAIL_PRIORITY, 8)
+            .attribute(mailPriority(8))
             .build());
 
         getManageableMailQueue().enQueue(defaultMail()
             .name("name6")
-            .attribute(MailPrioritySupport.MAIL_PRIORITY, 6)
+            .attribute(mailPriority(6))
             .build());
 
         getManageableMailQueue().enQueue(defaultMail()
             .name("name0")
-            .attribute(MailPrioritySupport.MAIL_PRIORITY, 0)
+            .attribute(mailPriority(0))
             .build());
 
         getManageableMailQueue().enQueue(defaultMail()
             .name("name7")
-            .attribute(MailPrioritySupport.MAIL_PRIORITY, 7)
+            .attribute(mailPriority(7))
             .build());
 
         getManageableMailQueue().enQueue(defaultMail()
             .name("name4")
-            .attribute(MailPrioritySupport.MAIL_PRIORITY, 4)
+            .attribute(mailPriority(4))
             .build());
 
         getManageableMailQueue().enQueue(defaultMail()
             .name("name2")
-            .attribute(MailPrioritySupport.MAIL_PRIORITY, 2)
+            .attribute(mailPriority(2))
             .build());
 
         getManageableMailQueue().enQueue(defaultMail()
             .name("name5")
-            .attribute(MailPrioritySupport.MAIL_PRIORITY, 5)
+            .attribute(mailPriority(5))
             .build());
 
         assertThat(getManageableMailQueue().browse())
@@ -87,4 +89,8 @@ public interface PriorityManageableMailQueueContract extends ManageableMailQueue
             .extracting(Mail::getName)
             .containsExactly("name9", "name8", "name7", "name6", "name5", "name4", "name3", "name2", "name1", "name0");
     }
+
+    default Attribute mailPriority(Integer priority) {
+        return new Attribute(MailPrioritySupport.MAIL_PRIORITY, AttributeValue.of(priority));
+    }
 }
diff --git a/server/queue/queue-jms/src/main/java/org/apache/james/queue/jms/JMSMailQueue.java b/server/queue/queue-jms/src/main/java/org/apache/james/queue/jms/JMSMailQueue.java
index a863479..f35278c 100644
--- a/server/queue/queue-jms/src/main/java/org/apache/james/queue/jms/JMSMailQueue.java
+++ b/server/queue/queue-jms/src/main/java/org/apache/james/queue/jms/JMSMailQueue.java
@@ -67,6 +67,7 @@ import org.apache.james.server.core.MailImpl;
 import org.apache.james.server.core.MimeMessageCopyOnWriteProxy;
 import org.apache.james.util.SerializationUtil;
 import org.apache.mailet.AttributeName;
+import org.apache.mailet.AttributeUtils;
 import org.apache.mailet.Mail;
 import org.apache.mailet.PerRecipientHeaders;
 import org.slf4j.Logger;
@@ -252,11 +253,8 @@ public class JMSMailQueue implements ManageableMailQueue, JMSSupport, MailPriori
 
         try {
 
-            int msgPrio = NORMAL_PRIORITY;
-            Object prio = mail.getAttribute(MAIL_PRIORITY);
-            if (prio instanceof Integer) {
-                msgPrio = (Integer) prio;
-            }
+            int msgPrio = AttributeUtils.getValueAndCastFromMail(mail, MAIL_PRIORITY, Integer.class)
+                .orElse(NORMAL_PRIORITY);
 
             Map<String, Object> props = getJMSProperties(mail, nextDeliveryTimestamp);
             produceMail(props, msgPrio, mail);
diff --git a/third-party/spamassassin/pom.xml b/third-party/spamassassin/pom.xml
index 5bfd2e8..0d70747 100644
--- a/third-party/spamassassin/pom.xml
+++ b/third-party/spamassassin/pom.xml
@@ -31,6 +31,10 @@
     <dependencies>
         <dependency>
             <groupId>${james.groupId}</groupId>
+            <artifactId>apache-mailet-api</artifactId>
+        </dependency>
+        <dependency>
+            <groupId>${james.groupId}</groupId>
             <artifactId>james-core</artifactId>
         </dependency>
         <dependency>
diff --git a/third-party/spamassassin/src/main/java/org/apache/james/spamassassin/SpamAssassinResult.java b/third-party/spamassassin/src/main/java/org/apache/james/spamassassin/SpamAssassinResult.java
index 96f98ea..b246249 100644
--- a/third-party/spamassassin/src/main/java/org/apache/james/spamassassin/SpamAssassinResult.java
+++ b/third-party/spamassassin/src/main/java/org/apache/james/spamassassin/SpamAssassinResult.java
@@ -18,17 +18,21 @@
  ****************************************************************/
 package org.apache.james.spamassassin;
 
-import java.util.Map;
+import java.util.List;
+
+import org.apache.mailet.Attribute;
+import org.apache.mailet.AttributeName;
+import org.apache.mailet.AttributeValue;
 
 import com.google.common.base.Preconditions;
-import com.google.common.collect.ImmutableMap;
+import com.google.common.collect.ImmutableList;
 
 public class SpamAssassinResult {
     /** The mail attribute under which the status get stored */
-    public static final String STATUS_MAIL_ATTRIBUTE_NAME = "org.apache.james.spamassassin.status";
+    public static final AttributeName STATUS_MAIL = AttributeName.of("org.apache.james.spamassassin.status");
 
     /** The mail attribute under which the flag get stored */
-    public static final String FLAG_MAIL_ATTRIBUTE_NAME = "org.apache.james.spamassassin.flag";
+    public static final AttributeName FLAG_MAIL = AttributeName.of("org.apache.james.spamassassin.flag");
 
     public static final String NO_RESULT = "?";
 
@@ -71,27 +75,27 @@ public class SpamAssassinResult {
             Preconditions.checkNotNull(hits);
             Preconditions.checkNotNull(requiredHits);
 
-            ImmutableMap.Builder<String, String> headersAsAttribute = ImmutableMap.builder();
+            ImmutableList.Builder<Attribute> headersAsAttributes = ImmutableList.builder();
             if (isSpam) {
-                headersAsAttribute.put(FLAG_MAIL_ATTRIBUTE_NAME, "YES");
-                headersAsAttribute.put(STATUS_MAIL_ATTRIBUTE_NAME, "Yes, hits=" + hits + " required=" + requiredHits);
+                headersAsAttributes.add(new Attribute(FLAG_MAIL, AttributeValue.of("YES")));
+                headersAsAttributes.add(new Attribute(STATUS_MAIL, AttributeValue.of("Yes, hits=" + hits + " required=" + requiredHits)));
             } else {
-                headersAsAttribute.put(FLAG_MAIL_ATTRIBUTE_NAME, "NO");
-                headersAsAttribute.put(STATUS_MAIL_ATTRIBUTE_NAME, "No, hits=" + hits + " required=" + requiredHits);
+                headersAsAttributes.add(new Attribute(FLAG_MAIL, AttributeValue.of("NO")));
+                headersAsAttributes.add(new Attribute(STATUS_MAIL, AttributeValue.of("No, hits=" + hits + " required=" + requiredHits)));
             }
 
-            return new SpamAssassinResult(hits, requiredHits, headersAsAttribute.build());
+            return new SpamAssassinResult(hits, requiredHits, headersAsAttributes.build());
         }
     }
 
     private final String hits;
     private final String requiredHits;
-    private final Map<String, String> headersAsAttribute;
+    private final List<Attribute> headersAsAttributes;
 
-    private SpamAssassinResult(String hits, String requiredHits, Map<String, String> headersAsAttribute) {
+    private SpamAssassinResult(String hits, String requiredHits, List<Attribute> headersAsAttributes) {
         this.hits = hits;
         this.requiredHits = requiredHits;
-        this.headersAsAttribute = headersAsAttribute;
+        this.headersAsAttributes = headersAsAttributes;
     }
 
     public String getHits() {
@@ -102,8 +106,8 @@ public class SpamAssassinResult {
         return requiredHits;
     }
 
-    public Map<String, String> getHeadersAsAttribute() {
-        return headersAsAttribute;
+    public List<Attribute> getHeadersAsAttributes() {
+        return headersAsAttributes;
     }
 
 }
diff --git a/third-party/spamassassin/src/test/java/org/apache/james/spamassassin/SpamAssassinInvokerTest.java b/third-party/spamassassin/src/test/java/org/apache/james/spamassassin/SpamAssassinInvokerTest.java
index cb3bbdc..26af030 100644
--- a/third-party/spamassassin/src/test/java/org/apache/james/spamassassin/SpamAssassinInvokerTest.java
+++ b/third-party/spamassassin/src/test/java/org/apache/james/spamassassin/SpamAssassinInvokerTest.java
@@ -29,6 +29,8 @@ import org.apache.james.core.User;
 import org.apache.james.metrics.api.NoopMetricFactory;
 import org.apache.james.spamassassin.SpamAssassinExtension.SpamAssassin;
 import org.apache.james.util.MimeMessageUtil;
+import org.apache.mailet.Attribute;
+import org.apache.mailet.AttributeValue;
 import org.junit.jupiter.api.BeforeEach;
 import org.junit.jupiter.api.Disabled;
 import org.junit.jupiter.api.Test;
@@ -71,7 +73,7 @@ public class SpamAssassinInvokerTest {
                 ClassLoader.getSystemResourceAsStream("eml/spam.eml"));
         SpamAssassinResult result = testee.scanMail(mimeMessage, USER);
 
-        assertThat(result.getHeadersAsAttribute()).isNotEmpty();
+        assertThat(result.getHeadersAsAttributes()).isNotEmpty();
     }
 
     @Disabled("MAILBOX-377 This test is not stable, fails on our CI and thus is temporarily disabled")
@@ -84,7 +86,7 @@ public class SpamAssassinInvokerTest {
 
         SpamAssassinResult result = testee.scanMail(mimeMessage, USER);
 
-        assertThat(result.getHeadersAsAttribute().get(SpamAssassinResult.FLAG_MAIL_ATTRIBUTE_NAME)).isEqualTo("YES");
+        assertThat(result.getHeadersAsAttributes()).contains(new Attribute(SpamAssassinResult.FLAG_MAIL, AttributeValue.of("YES")));
     }
 
     @Test
@@ -108,7 +110,7 @@ public class SpamAssassinInvokerTest {
 
         SpamAssassinResult result = testee.scanMail(mimeMessage, USER);
 
-        assertThat(result.getHeadersAsAttribute().get(SpamAssassinResult.FLAG_MAIL_ATTRIBUTE_NAME)).isEqualTo("YES");
+        assertThat(result.getHeadersAsAttributes()).contains(new Attribute(SpamAssassinResult.FLAG_MAIL, AttributeValue.of("YES")));
     }
 
     @Test
@@ -130,7 +132,7 @@ public class SpamAssassinInvokerTest {
 
         SpamAssassinResult result = testee.scanMail(mimeMessage, USER);
 
-        assertThat(result.getHeadersAsAttribute().get(SpamAssassinResult.FLAG_MAIL_ATTRIBUTE_NAME)).isEqualTo("NO");
+        assertThat(result.getHeadersAsAttributes()).contains(new Attribute(SpamAssassinResult.FLAG_MAIL, AttributeValue.of("NO")));
     }
 
     @Test
@@ -145,6 +147,6 @@ public class SpamAssassinInvokerTest {
 
         SpamAssassinResult result = testee.scanMail(mimeMessage, USER);
 
-        assertThat(result.getHeadersAsAttribute().get(SpamAssassinResult.FLAG_MAIL_ATTRIBUTE_NAME)).isEqualTo("NO");
+        assertThat(result.getHeadersAsAttributes()).contains(new Attribute(SpamAssassinResult.FLAG_MAIL, AttributeValue.of("NO")));
     }
 }
diff --git a/third-party/spamassassin/src/test/java/org/apache/james/spamassassin/SpamAssassinResultTest.java b/third-party/spamassassin/src/test/java/org/apache/james/spamassassin/SpamAssassinResultTest.java
index fb75604..470f8c9 100644
--- a/third-party/spamassassin/src/test/java/org/apache/james/spamassassin/SpamAssassinResultTest.java
+++ b/third-party/spamassassin/src/test/java/org/apache/james/spamassassin/SpamAssassinResultTest.java
@@ -21,12 +21,12 @@ package org.apache.james.spamassassin;
 import static org.assertj.core.api.Assertions.assertThat;
 import static org.assertj.core.api.Assertions.assertThatThrownBy;
 
+import org.apache.mailet.Attribute;
+import org.apache.mailet.AttributeValue;
 import org.assertj.core.api.JUnitSoftAssertions;
 import org.junit.Rule;
 import org.junit.Test;
 
-import com.google.common.collect.ImmutableMap;
-
 public class SpamAssassinResultTest {
 
     @Rule
@@ -60,10 +60,10 @@ public class SpamAssassinResultTest {
 
         softly.assertThat(spamAssassinResult.getHits()).isEqualTo(hits);
         softly.assertThat(spamAssassinResult.getRequiredHits()).isEqualTo(requiredHits);
-        softly.assertThat(spamAssassinResult.getHeadersAsAttribute())
-            .containsAllEntriesOf(ImmutableMap.of(
-                SpamAssassinResult.FLAG_MAIL_ATTRIBUTE_NAME, "YES",
-                SpamAssassinResult.STATUS_MAIL_ATTRIBUTE_NAME, "Yes, hits=1.1 required=5.0"));
+        softly.assertThat(spamAssassinResult.getHeadersAsAttributes())
+            .containsOnly(
+                new Attribute(SpamAssassinResult.FLAG_MAIL, AttributeValue.of("YES")),
+                new Attribute(SpamAssassinResult.STATUS_MAIL, AttributeValue.of("Yes, hits=1.1 required=5.0")));
     }
 
     @Test
@@ -76,8 +76,8 @@ public class SpamAssassinResultTest {
             .requiredHits(requiredHits)
             .build();
 
-        assertThat(spamAssassinResult.getHeadersAsAttribute())
-            .containsEntry(SpamAssassinResult.FLAG_MAIL_ATTRIBUTE_NAME, "YES");
+        assertThat(spamAssassinResult.getHeadersAsAttributes())
+            .contains(new Attribute(SpamAssassinResult.FLAG_MAIL, AttributeValue.of("YES")));
     }
 
     @Test
@@ -90,7 +90,7 @@ public class SpamAssassinResultTest {
             .requiredHits(requiredHits)
             .build();
 
-        assertThat(spamAssassinResult.getHeadersAsAttribute())
-            .containsEntry(SpamAssassinResult.FLAG_MAIL_ATTRIBUTE_NAME, "NO");
+        assertThat(spamAssassinResult.getHeadersAsAttributes())
+            .contains(new Attribute(SpamAssassinResult.FLAG_MAIL, AttributeValue.of("NO")));
     }
 }


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


[james-project] 01/07: JAMES-2578 Fix warning using Mailet new API

Posted by ro...@apache.org.
This is an automated email from the ASF dual-hosted git repository.

rouazana pushed a commit to branch master
in repository https://gitbox.apache.org/repos/asf/james-project.git

commit 23e94c4e3300105f12f900ecf070d7cd96961d16
Author: Gautier DI FOLCO <gd...@linagora.com>
AuthorDate: Wed Jan 23 15:40:21 2019 +0100

    JAMES-2578 Fix warning using Mailet new API
---
 .../java/org/apache/mailet/ContractMailTest.java   |   2 +-
 .../transport/mailets/ICALToJsonAttribute.java     |   7 +
 .../transport/mailets/ICALToJsonAttributeTest.java | 312 +++++++++++----------
 .../transport/mailets/ICalendarParserTest.java     |  28 +-
 .../transport/mailets/RemoveMailAttribute.java     |  18 +-
 .../mailets/RemoveAllMailAttributesTest.java       |   7 +-
 .../transport/mailets/SetMailAttributeTest.java    |  19 +-
 .../apache/mailet/base/test/FakeMailContext.java   |  53 ++--
 .../org/apache/james/server/core/MailImpl.java     |   6 -
 .../mailrepository/jdbc/JDBCMailRepository.java    |  25 +-
 .../impl/camel/CamelMailetProcessor.java           |   2 +-
 .../mailetcontainer/impl/camel/MatcherMatch.java   |   2 +-
 .../impl/camel/MatcherSplitter.java                |   9 +-
 .../mailets/AbstractRecipientRewriteTable.java     |   9 +-
 .../mailets/WithStorageDirectiveTest.java          |  18 +-
 .../mailets/delivery/SieveIntegrationTest.java     | 168 +++++------
 .../remote/delivery/RemoteDeliveryTest.java        |  15 +-
 .../cassandra/CassandraMailRepositoryMailDAO.java  |  23 +-
 .../CassandraMailRepositoryMailDAOTest.java        |   8 +-
 .../org/apache/james/webadmin/dto/MailDto.java     |   8 +-
 .../queue/activemq/ActiveMQMailQueueItem.java      |   2 +-
 .../james/queue/activemq/ActiveMQSupport.java      |   3 +-
 .../apache/james/queue/api/MailQueueContract.java  |   1 +
 .../queue/api/ManageableMailQueueContract.java     |  17 +-
 .../org/apache/james/queue/jms/JMSMailQueue.java   |  16 +-
 .../james/queue/library/MailQueueManagement.java   |  19 +-
 26 files changed, 449 insertions(+), 348 deletions(-)

diff --git a/mailet/api/src/test/java/org/apache/mailet/ContractMailTest.java b/mailet/api/src/test/java/org/apache/mailet/ContractMailTest.java
index 8e1f562..3d63f77 100644
--- a/mailet/api/src/test/java/org/apache/mailet/ContractMailTest.java
+++ b/mailet/api/src/test/java/org/apache/mailet/ContractMailTest.java
@@ -152,7 +152,7 @@ public abstract class ContractMailTest {
 
     @SuppressWarnings("deprecation")
     @Nested
-    public class DeprecatedtedAttributes {
+    public class DeprecatedAttributes {
         @Test
         void setAttributeShouldReturnNullWhenNoPreviousValue() {
             Mail mail = newMail();
diff --git a/mailet/icalendar/src/main/java/org/apache/james/transport/mailets/ICALToJsonAttribute.java b/mailet/icalendar/src/main/java/org/apache/james/transport/mailets/ICALToJsonAttribute.java
index f1605bb..630e23c 100644
--- a/mailet/icalendar/src/main/java/org/apache/james/transport/mailets/ICALToJsonAttribute.java
+++ b/mailet/icalendar/src/main/java/org/apache/james/transport/mailets/ICALToJsonAttribute.java
@@ -36,6 +36,7 @@ import org.apache.james.core.MailAddress;
 import org.apache.james.transport.mailets.model.ICAL;
 import org.apache.james.util.OptionalUtils;
 import org.apache.james.util.StreamUtils;
+import org.apache.mailet.AttributeName;
 import org.apache.mailet.Mail;
 import org.apache.mailet.base.GenericMailet;
 import org.slf4j.Logger;
@@ -90,6 +91,12 @@ public class ICALToJsonAttribute extends GenericMailet {
     public static final String DEFAULT_SOURCE_ATTRIBUTE_NAME = "icalendar";
     public static final String DEFAULT_RAW_SOURCE_ATTRIBUTE_NAME = "attachments";
     public static final String DEFAULT_DESTINATION_ATTRIBUTE_NAME = "icalendarJson";
+    public static final AttributeName SOURCE = AttributeName.of(SOURCE_ATTRIBUTE_NAME);
+    public static final AttributeName RAW_SOURCE = AttributeName.of(RAW_SOURCE_ATTRIBUTE_NAME);
+    public static final AttributeName DESTINATION = AttributeName.of(DESTINATION_ATTRIBUTE_NAME);
+    public static final AttributeName DEFAULT_SOURCE = AttributeName.of(DEFAULT_SOURCE_ATTRIBUTE_NAME);
+    public static final AttributeName DEFAULT_RAW_SOURCE = AttributeName.of(DEFAULT_RAW_SOURCE_ATTRIBUTE_NAME);
+    public static final AttributeName DEFAULT_DESTINATION = AttributeName.of(DEFAULT_DESTINATION_ATTRIBUTE_NAME);
 
     static {
         ICal4JConfigurator.configure();
diff --git a/mailet/icalendar/src/test/java/org/apache/james/transport/mailets/ICALToJsonAttributeTest.java b/mailet/icalendar/src/test/java/org/apache/james/transport/mailets/ICALToJsonAttributeTest.java
index 7eb84d2..685497c 100644
--- a/mailet/icalendar/src/test/java/org/apache/james/transport/mailets/ICALToJsonAttributeTest.java
+++ b/mailet/icalendar/src/test/java/org/apache/james/transport/mailets/ICALToJsonAttributeTest.java
@@ -26,6 +26,7 @@ import java.io.ByteArrayInputStream;
 import java.nio.charset.StandardCharsets;
 import java.util.List;
 import java.util.Map;
+import java.util.Optional;
 import java.util.stream.Collectors;
 
 import javax.mail.MessagingException;
@@ -34,6 +35,7 @@ import org.apache.james.core.MailAddress;
 import org.apache.james.core.builder.MimeMessageBuilder;
 import org.apache.james.util.ClassLoaderUtils;
 import org.apache.james.util.MimeMessageUtil;
+import org.apache.mailet.AttributeUtils;
 import org.apache.mailet.Mail;
 import org.apache.mailet.base.MailAddressFixture;
 import org.apache.mailet.base.test.FakeMail;
@@ -50,6 +52,7 @@ import net.fortuna.ical4j.model.Calendar;
 
 public class ICALToJsonAttributeTest {
     public static final MailAddress SENDER = MailAddressFixture.ANY_AT_JAMES;
+    public static final Class<Map<String, byte[]>> MAP_STRING_BYTES_CLASS = (Class<Map<String, byte[]>>) (Object) Map.class;
 
     @Rule
     public ExpectedException expectedException = ExpectedException.none();
@@ -127,8 +130,8 @@ public class ICALToJsonAttributeTest {
             .build();
         testee.service(mail);
 
-        assertThat(mail.getAttribute(ICALToJsonAttribute.DEFAULT_DESTINATION_ATTRIBUTE_NAME))
-            .isNull();
+        assertThat(mail.getAttribute(ICALToJsonAttribute.DEFAULT_DESTINATION))
+            .isEmpty();
     }
 
     @Test
@@ -142,8 +145,8 @@ public class ICALToJsonAttributeTest {
             .build();
         testee.service(mail);
 
-        assertThat(mail.getAttribute(ICALToJsonAttribute.DEFAULT_DESTINATION_ATTRIBUTE_NAME))
-            .isNull();
+        assertThat(mail.getAttribute(ICALToJsonAttribute.DEFAULT_DESTINATION))
+            .isEmpty();
     }
 
     @Test
@@ -157,8 +160,8 @@ public class ICALToJsonAttributeTest {
             .build();
         testee.service(mail);
 
-        assertThat(mail.getAttribute(ICALToJsonAttribute.DEFAULT_DESTINATION_ATTRIBUTE_NAME))
-            .isNull();
+        assertThat(mail.getAttribute(ICALToJsonAttribute.DEFAULT_DESTINATION))
+            .isEmpty();
     }
 
     @Test
@@ -173,8 +176,8 @@ public class ICALToJsonAttributeTest {
             .build();
         testee.service(mail);
 
-        assertThat(mail.getAttribute(ICALToJsonAttribute.DEFAULT_DESTINATION_ATTRIBUTE_NAME))
-            .isNull();
+        assertThat(mail.getAttribute(ICALToJsonAttribute.DEFAULT_DESTINATION))
+            .isEmpty();
     }
 
     @Test
@@ -189,8 +192,8 @@ public class ICALToJsonAttributeTest {
             .build();
         testee.service(mail);
 
-        assertThat(mail.getAttribute(ICALToJsonAttribute.DEFAULT_DESTINATION_ATTRIBUTE_NAME))
-            .isNull();
+        assertThat(mail.getAttribute(ICALToJsonAttribute.DEFAULT_DESTINATION))
+            .isEmpty();
     }
 
     @Test
@@ -207,8 +210,8 @@ public class ICALToJsonAttributeTest {
             .build();
         testee.service(mail);
 
-        assertThat(mail.getAttribute(ICALToJsonAttribute.DEFAULT_DESTINATION_ATTRIBUTE_NAME))
-            .isNull();
+        assertThat(mail.getAttribute(ICALToJsonAttribute.DEFAULT_DESTINATION))
+            .isEmpty();
     }
 
     @Test
@@ -226,8 +229,9 @@ public class ICALToJsonAttributeTest {
             .build();
         testee.service(mail);
 
-        assertThat((Map<?,?>) mail.getAttribute(ICALToJsonAttribute.DEFAULT_DESTINATION_ATTRIBUTE_NAME))
-            .isEmpty();
+        assertThat(AttributeUtils.getValueAndCastFromMail(mail, ICALToJsonAttribute.DEFAULT_DESTINATION, Map.class))
+            .isPresent()
+            .hasValueSatisfying(map -> assertThat(map).isEmpty());
     }
 
     @SuppressWarnings("unchecked")
@@ -248,19 +252,22 @@ public class ICALToJsonAttributeTest {
             .build();
         testee.service(mail);
 
-        Map<String, byte[]> jsons = (Map<String, byte[]>) mail.getAttribute(ICALToJsonAttribute.DEFAULT_DESTINATION_ATTRIBUTE_NAME);
-        assertThat(jsons).hasSize(1);
-        assertThatJson(new String(jsons.values().iterator().next(), StandardCharsets.UTF_8))
-            .isEqualTo("{" +
-                "\"ical\": \"" + toJsonValue(ics) + "\"," +
-                "\"sender\": \"" + SENDER.asString() + "\"," +
-                "\"recipient\": \"" + recipient.asString() + "\"," +
-                "\"uid\": \"f1514f44bf39311568d640727cff54e819573448d09d2e5677987ff29caa01a9e047feb2aab16e43439a608f28671ab7c10e754ce92be513f8e04ae9ff15e65a9819cf285a6962bc\"," +
-                "\"sequence\": \"0\"," +
-                "\"dtstamp\": \"20170106T115036Z\"," +
-                "\"method\": \"REQUEST\"," +
-                "\"recurrence-id\": null" +
-                "}");
+        assertThat(AttributeUtils.getValueAndCastFromMail(mail, ICALToJsonAttribute.DEFAULT_DESTINATION, MAP_STRING_BYTES_CLASS))
+            .isPresent()
+            .hasValueSatisfying(jsons -> {
+                assertThat(jsons).hasSize(1);
+                assertThatJson(new String(jsons.values().iterator().next(), StandardCharsets.UTF_8))
+                    .isEqualTo("{" +
+                        "\"ical\": \"" + toJsonValue(ics) + "\"," +
+                        "\"sender\": \"" + SENDER.asString() + "\"," +
+                        "\"recipient\": \"" + recipient.asString() + "\"," +
+                        "\"uid\": \"f1514f44bf39311568d640727cff54e819573448d09d2e5677987ff29caa01a9e047feb2aab16e43439a608f28671ab7c10e754ce92be513f8e04ae9ff15e65a9819cf285a6962bc\"," +
+                        "\"sequence\": \"0\"," +
+                        "\"dtstamp\": \"20170106T115036Z\"," +
+                        "\"method\": \"REQUEST\"," +
+                        "\"recurrence-id\": null" +
+                        "}");
+            });
     }
 
     private String toJsonValue(byte[] ics) {
@@ -284,30 +291,33 @@ public class ICALToJsonAttributeTest {
             .build();
         testee.service(mail);
 
-        Map<String, byte[]> jsons = (Map<String, byte[]>) mail.getAttribute(ICALToJsonAttribute.DEFAULT_DESTINATION_ATTRIBUTE_NAME);
-        assertThat(jsons).hasSize(2);
-        List<String> actual = toSortedValueList(jsons);
-
-        assertThatJson(actual.get(0)).isEqualTo("{" +
-            "\"ical\": \"" + toJsonValue(ics) + "\"," +
-            "\"sender\": \"" + SENDER.asString() + "\"," +
-            "\"recipient\": \"" + MailAddressFixture.ANY_AT_JAMES2.asString() + "\"," +
-            "\"uid\": \"f1514f44bf39311568d640727cff54e819573448d09d2e5677987ff29caa01a9e047feb2aab16e43439a608f28671ab7c10e754ce92be513f8e04ae9ff15e65a9819cf285a6962bc\"," +
-            "\"sequence\": \"0\"," +
-            "\"dtstamp\": \"20170106T115036Z\"," +
-            "\"method\": \"REQUEST\"," +
-            "\"recurrence-id\": null" +
-            "}");
-        assertThatJson(actual.get(1)).isEqualTo("{" +
-            "\"ical\": \"" + toJsonValue(ics) + "\"," +
-            "\"sender\": \"" + SENDER.asString() + "\"," +
-            "\"recipient\": \"" + MailAddressFixture.OTHER_AT_JAMES.asString() + "\"," +
-            "\"uid\": \"f1514f44bf39311568d640727cff54e819573448d09d2e5677987ff29caa01a9e047feb2aab16e43439a608f28671ab7c10e754ce92be513f8e04ae9ff15e65a9819cf285a6962bc\"," +
-            "\"sequence\": \"0\"," +
-            "\"dtstamp\": \"20170106T115036Z\"," +
-            "\"method\": \"REQUEST\"," +
-            "\"recurrence-id\": null" +
-            "}");
+        assertThat(AttributeUtils.getValueAndCastFromMail(mail, ICALToJsonAttribute.DEFAULT_DESTINATION, MAP_STRING_BYTES_CLASS))
+                .isPresent()
+                .hasValueSatisfying(jsons -> {
+                    assertThat(jsons).hasSize(2);
+                    List<String> actual = toSortedValueList(jsons);
+
+                    assertThatJson(actual.get(0)).isEqualTo("{" +
+                        "\"ical\": \"" + toJsonValue(ics) + "\"," +
+                        "\"sender\": \"" + SENDER.asString() + "\"," +
+                        "\"recipient\": \"" + MailAddressFixture.ANY_AT_JAMES2.asString() + "\"," +
+                        "\"uid\": \"f1514f44bf39311568d640727cff54e819573448d09d2e5677987ff29caa01a9e047feb2aab16e43439a608f28671ab7c10e754ce92be513f8e04ae9ff15e65a9819cf285a6962bc\"," +
+                        "\"sequence\": \"0\"," +
+                        "\"dtstamp\": \"20170106T115036Z\"," +
+                        "\"method\": \"REQUEST\"," +
+                        "\"recurrence-id\": null" +
+                        "}");
+                    assertThatJson(actual.get(1)).isEqualTo("{" +
+                        "\"ical\": \"" + toJsonValue(ics) + "\"," +
+                        "\"sender\": \"" + SENDER.asString() + "\"," +
+                        "\"recipient\": \"" + MailAddressFixture.OTHER_AT_JAMES.asString() + "\"," +
+                        "\"uid\": \"f1514f44bf39311568d640727cff54e819573448d09d2e5677987ff29caa01a9e047feb2aab16e43439a608f28671ab7c10e754ce92be513f8e04ae9ff15e65a9819cf285a6962bc\"," +
+                        "\"sequence\": \"0\"," +
+                        "\"dtstamp\": \"20170106T115036Z\"," +
+                        "\"method\": \"REQUEST\"," +
+                        "\"recurrence-id\": null" +
+                        "}");
+                });
     }
 
     @SuppressWarnings("unchecked")
@@ -330,30 +340,33 @@ public class ICALToJsonAttributeTest {
             .build();
         testee.service(mail);
 
-        Map<String, byte[]> jsons = (Map<String, byte[]>) mail.getAttribute(ICALToJsonAttribute.DEFAULT_DESTINATION_ATTRIBUTE_NAME);
-        assertThat(jsons).hasSize(2);
-        List<String> actual = toSortedValueList(jsons);
-
-        assertThatJson(actual.get(0)).isEqualTo("{" +
-            "\"ical\": \"" + toJsonValue(ics2) + "\"," +
-            "\"sender\": \"" + SENDER.asString() + "\"," +
-            "\"recipient\": \"" + recipient.asString() + "\"," +
-            "\"uid\": \"f1514f44bf39311568d64072ac247c17656ceafde3b4b3eba961c8c5184cdc6ee047feb2aab16e43439a608f28671ab7c10e754c301b1e32001ad51dd20eac2fc7af20abf4093bbe\"," +
-            "\"sequence\": \"0\"," +
-            "\"dtstamp\": \"20170103T103250Z\"," +
-            "\"method\": \"REQUEST\"," +
-            "\"recurrence-id\": null" +
-            "}");
-        assertThatJson(actual.get(1)).isEqualTo("{" +
-            "\"ical\": \"" + toJsonValue(ics) + "\"," +
-            "\"sender\": \"" + SENDER.asString() + "\"," +
-            "\"recipient\": \"" + recipient.asString() + "\"," +
-            "\"uid\": \"f1514f44bf39311568d640727cff54e819573448d09d2e5677987ff29caa01a9e047feb2aab16e43439a608f28671ab7c10e754ce92be513f8e04ae9ff15e65a9819cf285a6962bc\"," +
-            "\"sequence\": \"0\"," +
-            "\"dtstamp\": \"20170106T115036Z\"," +
-            "\"method\": \"REQUEST\"," +
-            "\"recurrence-id\": null" +
-            "}");
+        assertThat(AttributeUtils.getValueAndCastFromMail(mail, ICALToJsonAttribute.DEFAULT_DESTINATION, MAP_STRING_BYTES_CLASS))
+                .isPresent()
+                .hasValueSatisfying(jsons -> {
+                    assertThat(jsons).hasSize(2);
+                    List<String> actual = toSortedValueList(jsons);
+
+                    assertThatJson(actual.get(0)).isEqualTo("{" +
+                        "\"ical\": \"" + toJsonValue(ics2) + "\"," +
+                        "\"sender\": \"" + SENDER.asString() + "\"," +
+                        "\"recipient\": \"" + recipient.asString() + "\"," +
+                        "\"uid\": \"f1514f44bf39311568d64072ac247c17656ceafde3b4b3eba961c8c5184cdc6ee047feb2aab16e43439a608f28671ab7c10e754c301b1e32001ad51dd20eac2fc7af20abf4093bbe\"," +
+                        "\"sequence\": \"0\"," +
+                        "\"dtstamp\": \"20170103T103250Z\"," +
+                        "\"method\": \"REQUEST\"," +
+                        "\"recurrence-id\": null" +
+                        "}");
+                    assertThatJson(actual.get(1)).isEqualTo("{" +
+                        "\"ical\": \"" + toJsonValue(ics) + "\"," +
+                        "\"sender\": \"" + SENDER.asString() + "\"," +
+                        "\"recipient\": \"" + recipient.asString() + "\"," +
+                        "\"uid\": \"f1514f44bf39311568d640727cff54e819573448d09d2e5677987ff29caa01a9e047feb2aab16e43439a608f28671ab7c10e754ce92be513f8e04ae9ff15e65a9819cf285a6962bc\"," +
+                        "\"sequence\": \"0\"," +
+                        "\"dtstamp\": \"20170106T115036Z\"," +
+                        "\"method\": \"REQUEST\"," +
+                        "\"recurrence-id\": null" +
+                        "}");
+                    });
     }
 
     @SuppressWarnings("unchecked")
@@ -376,20 +389,23 @@ public class ICALToJsonAttributeTest {
             .build();
         testee.service(mail);
 
-        Map<String, byte[]> jsons = (Map<String, byte[]>) mail.getAttribute(ICALToJsonAttribute.DEFAULT_DESTINATION_ATTRIBUTE_NAME);
-        assertThat(jsons).hasSize(1);
-        List<String> actual = toSortedValueList(jsons);
-
-        assertThatJson(actual.get(0)).isEqualTo("{" +
-            "\"ical\": \"" + toJsonValue(ics) + "\"," +
-            "\"sender\": \"" + SENDER.asString() + "\"," +
-            "\"recipient\": \"" + recipient.asString() + "\"," +
-            "\"uid\": \"f1514f44bf39311568d640727cff54e819573448d09d2e5677987ff29caa01a9e047feb2aab16e43439a608f28671ab7c10e754ce92be513f8e04ae9ff15e65a9819cf285a6962bc\"," +
-            "\"sequence\": \"0\"," +
-            "\"dtstamp\": \"20170106T115036Z\"," +
-            "\"method\": \"REQUEST\"," +
-            "\"recurrence-id\": null" +
-            "}");
+        assertThat(AttributeUtils.getValueAndCastFromMail(mail, ICALToJsonAttribute.DEFAULT_DESTINATION, MAP_STRING_BYTES_CLASS))
+                .isPresent()
+                .hasValueSatisfying(jsons -> {
+                    assertThat(jsons).hasSize(1);
+                    List<String> actual = toSortedValueList(jsons);
+
+                    assertThatJson(actual.get(0)).isEqualTo("{" +
+                        "\"ical\": \"" + toJsonValue(ics) + "\"," +
+                        "\"sender\": \"" + SENDER.asString() + "\"," +
+                        "\"recipient\": \"" + recipient.asString() + "\"," +
+                        "\"uid\": \"f1514f44bf39311568d640727cff54e819573448d09d2e5677987ff29caa01a9e047feb2aab16e43439a608f28671ab7c10e754ce92be513f8e04ae9ff15e65a9819cf285a6962bc\"," +
+                        "\"sequence\": \"0\"," +
+                        "\"dtstamp\": \"20170106T115036Z\"," +
+                        "\"method\": \"REQUEST\"," +
+                        "\"recurrence-id\": null" +
+                        "}");
+                });
     }
 
     @SuppressWarnings("unchecked")
@@ -412,20 +428,23 @@ public class ICALToJsonAttributeTest {
             .build();
         testee.service(mail);
 
-        Map<String, byte[]> jsons = (Map<String, byte[]>) mail.getAttribute(ICALToJsonAttribute.DEFAULT_DESTINATION_ATTRIBUTE_NAME);
-        assertThat(jsons).hasSize(1);
-        List<String> actual = toSortedValueList(jsons);
-
-        assertThatJson(actual.get(0)).isEqualTo("{" +
-            "\"ical\": \"" + toJsonValue(ics) + "\"," +
-            "\"sender\": \"" + SENDER.asString() + "\"," +
-            "\"recipient\": \"" + recipient.asString() + "\"," +
-            "\"uid\": \"f1514f44bf39311568d640727cff54e819573448d09d2e5677987ff29caa01a9e047feb2aab16e43439a608f28671ab7c10e754ce92be513f8e04ae9ff15e65a9819cf285a6962bc\"," +
-            "\"sequence\": \"0\"," +
-            "\"dtstamp\": \"20170106T115036Z\"," +
-            "\"method\": \"REQUEST\"," +
-            "\"recurrence-id\": null" +
-            "}");
+        assertThat(AttributeUtils.getValueAndCastFromMail(mail, ICALToJsonAttribute.DEFAULT_DESTINATION, MAP_STRING_BYTES_CLASS))
+                .isPresent()
+                .hasValueSatisfying(jsons -> {
+                    assertThat(jsons).hasSize(1);
+                    List<String> actual = toSortedValueList(jsons);
+
+                    assertThatJson(actual.get(0)).isEqualTo("{" +
+                        "\"ical\": \"" + toJsonValue(ics) + "\"," +
+                        "\"sender\": \"" + SENDER.asString() + "\"," +
+                        "\"recipient\": \"" + recipient.asString() + "\"," +
+                        "\"uid\": \"f1514f44bf39311568d640727cff54e819573448d09d2e5677987ff29caa01a9e047feb2aab16e43439a608f28671ab7c10e754ce92be513f8e04ae9ff15e65a9819cf285a6962bc\"," +
+                        "\"sequence\": \"0\"," +
+                        "\"dtstamp\": \"20170106T115036Z\"," +
+                        "\"method\": \"REQUEST\"," +
+                        "\"recurrence-id\": null" +
+                        "}");
+                });
     }
 
     @SuppressWarnings("unchecked")
@@ -449,19 +468,22 @@ public class ICALToJsonAttributeTest {
             .build();
         testee.service(mail);
 
-        Map<String, byte[]> jsons = (Map<String, byte[]>) mail.getAttribute(ICALToJsonAttribute.DEFAULT_DESTINATION_ATTRIBUTE_NAME);
-        assertThat(jsons).hasSize(1);
-        assertThatJson(new String(jsons.values().iterator().next(), StandardCharsets.UTF_8))
-            .isEqualTo("{" +
-                "\"ical\": \"" + toJsonValue(ics) + "\"," +
-                "\"sender\": \"" + from + "\"," +
-                "\"recipient\": \"" + recipient.asString() + "\"," +
-                "\"uid\": \"f1514f44bf39311568d640727cff54e819573448d09d2e5677987ff29caa01a9e047feb2aab16e43439a608f28671ab7c10e754ce92be513f8e04ae9ff15e65a9819cf285a6962bc\"," +
-                "\"sequence\": \"0\"," +
-                "\"dtstamp\": \"20170106T115036Z\"," +
-                "\"method\": \"REQUEST\"," +
-                "\"recurrence-id\": null" +
-                "}");
+        assertThat(AttributeUtils.getValueAndCastFromMail(mail, ICALToJsonAttribute.DEFAULT_DESTINATION, MAP_STRING_BYTES_CLASS))
+                .isPresent()
+                .hasValueSatisfying(jsons -> {
+                    assertThat(jsons).hasSize(1);
+                    assertThatJson(new String(jsons.values().iterator().next(), StandardCharsets.UTF_8))
+                        .isEqualTo("{" +
+                            "\"ical\": \"" + toJsonValue(ics) + "\"," +
+                            "\"sender\": \"" + from + "\"," +
+                            "\"recipient\": \"" + recipient.asString() + "\"," +
+                            "\"uid\": \"f1514f44bf39311568d640727cff54e819573448d09d2e5677987ff29caa01a9e047feb2aab16e43439a608f28671ab7c10e754ce92be513f8e04ae9ff15e65a9819cf285a6962bc\"," +
+                            "\"sequence\": \"0\"," +
+                            "\"dtstamp\": \"20170106T115036Z\"," +
+                            "\"method\": \"REQUEST\"," +
+                            "\"recurrence-id\": null" +
+                            "}");
+                });
     }
 
     @SuppressWarnings("unchecked")
@@ -483,19 +505,22 @@ public class ICALToJsonAttributeTest {
             .build();
         testee.service(mail);
 
-        Map<String, byte[]> jsons = (Map<String, byte[]>) mail.getAttribute(ICALToJsonAttribute.DEFAULT_DESTINATION_ATTRIBUTE_NAME);
-        assertThat(jsons).hasSize(1);
-        assertThatJson(new String(jsons.values().iterator().next(), StandardCharsets.UTF_8))
-            .isEqualTo("{" +
-                "\"ical\": \"" + toJsonValue(ics) + "\"," +
-                "\"sender\": \"" + SENDER.asString() + "\"," +
-                "\"recipient\": \"" + recipient.asString() + "\"," +
-                "\"uid\": \"f1514f44bf39311568d640727cff54e819573448d09d2e5677987ff29caa01a9e047feb2aab16e43439a608f28671ab7c10e754ce92be513f8e04ae9ff15e65a9819cf285a6962bc\"," +
-                "\"sequence\": \"0\"," +
-                "\"dtstamp\": \"20170106T115036Z\"," +
-                "\"method\": \"REQUEST\"," +
-                "\"recurrence-id\": null" +
-                "}");
+        assertThat(AttributeUtils.getValueAndCastFromMail(mail, ICALToJsonAttribute.DEFAULT_DESTINATION, MAP_STRING_BYTES_CLASS))
+                .isPresent()
+                .hasValueSatisfying(jsons -> {
+                    assertThat(jsons).hasSize(1);
+                    assertThatJson(new String(jsons.values().iterator().next(), StandardCharsets.UTF_8))
+                        .isEqualTo("{" +
+                            "\"ical\": \"" + toJsonValue(ics) + "\"," +
+                            "\"sender\": \"" + SENDER.asString() + "\"," +
+                            "\"recipient\": \"" + recipient.asString() + "\"," +
+                            "\"uid\": \"f1514f44bf39311568d640727cff54e819573448d09d2e5677987ff29caa01a9e047feb2aab16e43439a608f28671ab7c10e754ce92be513f8e04ae9ff15e65a9819cf285a6962bc\"," +
+                            "\"sequence\": \"0\"," +
+                            "\"dtstamp\": \"20170106T115036Z\"," +
+                            "\"method\": \"REQUEST\"," +
+                            "\"recurrence-id\": null" +
+                            "}");
+                });
     }
 
     @SuppressWarnings("unchecked")
@@ -518,19 +543,22 @@ public class ICALToJsonAttributeTest {
             .build();
         testee.service(mail);
 
-        Map<String, byte[]> jsons = (Map<String, byte[]>) mail.getAttribute(ICALToJsonAttribute.DEFAULT_DESTINATION_ATTRIBUTE_NAME);
-        assertThat(jsons).hasSize(1);
-        assertThatJson(new String(jsons.values().iterator().next(), StandardCharsets.UTF_8))
-            .isEqualTo("{" +
-                "\"ical\": \"" + toJsonValue(ics) + "\"," +
-                "\"sender\": \"" + from + "\"," +
-                "\"recipient\": \"" + recipient.asString() + "\"," +
-                "\"uid\": \"f1514f44bf39311568d640727cff54e819573448d09d2e5677987ff29caa01a9e047feb2aab16e43439a608f28671ab7c10e754ce92be513f8e04ae9ff15e65a9819cf285a6962bc\"," +
-                "\"sequence\": \"0\"," +
-                "\"dtstamp\": \"20170106T115036Z\"," +
-                "\"method\": \"REQUEST\"," +
-                "\"recurrence-id\": null" +
-                "}");
+        assertThat(AttributeUtils.getValueAndCastFromMail(mail, ICALToJsonAttribute.DEFAULT_DESTINATION, MAP_STRING_BYTES_CLASS))
+                .isPresent()
+                .hasValueSatisfying(jsons -> {
+                    assertThat(jsons).hasSize(1);
+                    assertThatJson(new String(jsons.values().iterator().next(), StandardCharsets.UTF_8))
+                        .isEqualTo("{" +
+                            "\"ical\": \"" + toJsonValue(ics) + "\"," +
+                            "\"sender\": \"" + from + "\"," +
+                            "\"recipient\": \"" + recipient.asString() + "\"," +
+                            "\"uid\": \"f1514f44bf39311568d640727cff54e819573448d09d2e5677987ff29caa01a9e047feb2aab16e43439a608f28671ab7c10e754ce92be513f8e04ae9ff15e65a9819cf285a6962bc\"," +
+                            "\"sequence\": \"0\"," +
+                            "\"dtstamp\": \"20170106T115036Z\"," +
+                            "\"method\": \"REQUEST\"," +
+                            "\"recurrence-id\": null" +
+                            "}");
+                });
     }
 
     private List<String> toSortedValueList(Map<String, byte[]> jsons) {
diff --git a/mailet/icalendar/src/test/java/org/apache/james/transport/mailets/ICalendarParserTest.java b/mailet/icalendar/src/test/java/org/apache/james/transport/mailets/ICalendarParserTest.java
index a61fba9..8f15ddb 100644
--- a/mailet/icalendar/src/test/java/org/apache/james/transport/mailets/ICalendarParserTest.java
+++ b/mailet/icalendar/src/test/java/org/apache/james/transport/mailets/ICalendarParserTest.java
@@ -22,10 +22,15 @@ import static org.assertj.core.api.Assertions.assertThat;
 
 import java.io.Serializable;
 import java.util.Map;
+import java.util.Optional;
 
 import javax.mail.MessagingException;
 
 import org.apache.james.util.ClassLoaderUtils;
+import org.apache.mailet.Attribute;
+import org.apache.mailet.AttributeName;
+import org.apache.mailet.AttributeUtils;
+import org.apache.mailet.AttributeValue;
 import org.apache.mailet.Mail;
 import org.apache.mailet.base.test.FakeMail;
 import org.apache.mailet.base.test.FakeMailetConfig;
@@ -43,7 +48,9 @@ public class ICalendarParserTest {
     private static final String SOURCE_ATTRIBUTE = "sourceAttribute";
 
     private static final String DESTINATION_CUSTOM_ATTRIBUTE = "ics.dest.attribute";
+    private static final AttributeName DESTINATION_CUSTOM_ATTRIBUTE_NAME = AttributeName.of(DESTINATION_CUSTOM_ATTRIBUTE);
     private static final String SOURCE_CUSTOM_ATTRIBUTE = "ics.source.attribute";
+    private static final AttributeName SOURCE_CUSTOM_ATTRIBUTE_NAME = AttributeName.of(SOURCE_CUSTOM_ATTRIBUTE);
 
     private static final String RIGHT_ICAL_VALUE = "BEGIN:VCALENDAR\n" +
         "END:VCALENDAR";
@@ -128,7 +135,7 @@ public class ICalendarParserTest {
 
         mailet.service(mail);
 
-        assertThat(mail.getAttributeNames()).isEmpty();
+        assertThat(mail.attributes()).isEmpty();
     }
 
     @Test
@@ -141,13 +148,14 @@ public class ICalendarParserTest {
         mailet.init(mailetConfiguration);
 
         Mail mail = FakeMail.builder()
-            .attribute(SOURCE_CUSTOM_ATTRIBUTE, ImmutableMap.of())
+            .attribute(new Attribute(SOURCE_CUSTOM_ATTRIBUTE_NAME, AttributeValue.of(ImmutableMap.of())))
             .build();
 
         mailet.service(mail);
 
-        assertThat((Map<?, ?>)mail.getAttribute(DESTINATION_CUSTOM_ATTRIBUTE))
-            .isEmpty();
+        assertThat(mail.getAttribute(DESTINATION_CUSTOM_ATTRIBUTE_NAME))
+            .isPresent()
+            .hasValueSatisfying(attribute -> assertThat((Map) attribute.getValue().value()).isEmpty());
     }
 
     @Test
@@ -160,12 +168,12 @@ public class ICalendarParserTest {
         mailet.init(mailetConfiguration);
 
         Mail mail = FakeMail.builder()
-            .attribute(SOURCE_CUSTOM_ATTRIBUTE, "anyValue")
+            .attribute(new Attribute(SOURCE_CUSTOM_ATTRIBUTE_NAME, AttributeValue.of("anyValue")))
             .build();
 
         mailet.service(mail);
 
-        assertThat(mail.getAttribute(DESTINATION_CUSTOM_ATTRIBUTE)).isNull();
+        assertThat(mail.getAttribute(DESTINATION_CUSTOM_ATTRIBUTE_NAME)).isEmpty();
     }
 
     @Test
@@ -188,8 +196,12 @@ public class ICalendarParserTest {
 
         mailet.service(mail);
 
-        Map<String, Calendar> expectedCalendars = (Map<String, Calendar>)mail.getAttribute(DESTINATION_CUSTOM_ATTRIBUTE);
-        assertThat(expectedCalendars).hasSize(1);
+        Optional<Map<String, Calendar>> expectedCalendars = AttributeUtils.getValueAndCastFromMail(mail, DESTINATION_CUSTOM_ATTRIBUTE_NAME, (Class<Map<String, Calendar>>)(Object) Map.class);
+        assertThat(expectedCalendars)
+            .isPresent()
+            .hasValueSatisfying(calendars ->
+                    assertThat(calendars)
+                        .hasSize(1));
     }
 
     @Test
diff --git a/mailet/standard/src/main/java/org/apache/james/transport/mailets/RemoveMailAttribute.java b/mailet/standard/src/main/java/org/apache/james/transport/mailets/RemoveMailAttribute.java
index 72a39d0..4102908 100644
--- a/mailet/standard/src/main/java/org/apache/james/transport/mailets/RemoveMailAttribute.java
+++ b/mailet/standard/src/main/java/org/apache/james/transport/mailets/RemoveMailAttribute.java
@@ -23,10 +23,13 @@ package org.apache.james.transport.mailets;
 
 import javax.mail.MessagingException;
 
+import org.apache.james.util.streams.Iterators;
+import org.apache.mailet.AttributeName;
 import org.apache.mailet.Mail;
 import org.apache.mailet.MailetException;
 import org.apache.mailet.base.GenericMailet;
 
+import com.github.steveash.guavate.Guavate;
 import com.google.common.base.Preconditions;
 import com.google.common.base.Splitter;
 import com.google.common.base.Strings;
@@ -51,7 +54,7 @@ public class RemoveMailAttribute extends GenericMailet {
     private static final char ATTRIBUTE_SEPARATOR_CHAR = ',';
     protected static final String MAILET_NAME_PARAMETER = "name";
 
-    private ImmutableList<String> attributesToRemove;
+    private ImmutableList<AttributeName> attributesToRemove;
 
     @Override
     public String getMailetInfo() {
@@ -69,17 +72,18 @@ public class RemoveMailAttribute extends GenericMailet {
         attributesToRemove = getAttributes(name);
     }
 
-    private ImmutableList<String> getAttributes(String name) {
-        return ImmutableList.copyOf(Splitter.on(ATTRIBUTE_SEPARATOR_CHAR)
+    private ImmutableList<AttributeName> getAttributes(String name) {
+        return Iterators.toStream(Splitter.on(ATTRIBUTE_SEPARATOR_CHAR)
             .trimResults()
-            .split(name));
+            .split(name)
+            .iterator())
+            .map(AttributeName::of)
+            .collect(Guavate.toImmutableList());
     }
 
     @Override
     public void service(Mail mail) throws MessagingException {
         Preconditions.checkNotNull(mail);
-        for (String attributeToRemove : attributesToRemove) {
-            mail.removeAttribute(attributeToRemove);
-        }
+        attributesToRemove.forEach(mail::removeAttribute);
     }
 }
diff --git a/mailet/standard/src/test/java/org/apache/james/transport/mailets/RemoveAllMailAttributesTest.java b/mailet/standard/src/test/java/org/apache/james/transport/mailets/RemoveAllMailAttributesTest.java
index 0dba54c..def4e6b 100644
--- a/mailet/standard/src/test/java/org/apache/james/transport/mailets/RemoveAllMailAttributesTest.java
+++ b/mailet/standard/src/test/java/org/apache/james/transport/mailets/RemoveAllMailAttributesTest.java
@@ -24,6 +24,7 @@ import static org.assertj.core.api.Assertions.assertThat;
 
 import javax.mail.MessagingException;
 
+import org.apache.mailet.Attribute;
 import org.apache.mailet.Mail;
 import org.apache.mailet.Mailet;
 import org.apache.mailet.base.test.FakeMailetConfig;
@@ -53,11 +54,11 @@ public class RemoveAllMailAttributesTest {
     @Test
     public void serviceShouldRemoveAllMailAttributes() throws MessagingException {
         mail = MailUtil.createMockMail2Recipients();
-        mail.setAttribute("org.apache.james.test.junit", "true");
+        mail.setAttribute(Attribute.convertToAttribute("org.apache.james.test.junit", "true"));
 
         mailet.service(mail);
 
-        assertThat(mail.getAttributeNames()).isEmpty();
+        assertThat(mail.attributes()).isEmpty();
     }
 
     @Test
@@ -66,6 +67,6 @@ public class RemoveAllMailAttributesTest {
 
         mailet.service(mail);
 
-        assertThat(mail.getAttributeNames()).isEmpty();
+        assertThat(mail.attributes()).isEmpty();
     }
 }
diff --git a/mailet/standard/src/test/java/org/apache/james/transport/mailets/SetMailAttributeTest.java b/mailet/standard/src/test/java/org/apache/james/transport/mailets/SetMailAttributeTest.java
index e5614a1..7edd609 100644
--- a/mailet/standard/src/test/java/org/apache/james/transport/mailets/SetMailAttributeTest.java
+++ b/mailet/standard/src/test/java/org/apache/james/transport/mailets/SetMailAttributeTest.java
@@ -25,6 +25,9 @@ import static org.assertj.core.api.Assertions.assertThat;
 import javax.mail.MessagingException;
 
 import org.apache.james.util.MimeMessageUtil;
+import org.apache.mailet.Attribute;
+import org.apache.mailet.AttributeName;
+import org.apache.mailet.AttributeValue;
 import org.apache.mailet.Mail;
 import org.apache.mailet.Mailet;
 import org.apache.mailet.base.test.FakeMailetConfig;
@@ -43,10 +46,16 @@ class SetMailAttributeTest {
 
     @Test
     void shouldAddConfiguredAttributes() throws MessagingException {
+        AttributeName name1 = AttributeName.of("org.apache.james.junit1");
+        AttributeName name2 = AttributeName.of("org.apache.james.junit2");
+        AttributeValue<String> value1 = AttributeValue.of("true");
+        AttributeValue<String> value2 = AttributeValue.of("happy");
+        Attribute attribute1 = new Attribute(name1, value1);
+        Attribute attribute2 = new Attribute(name2, value2);
         FakeMailetConfig mailetConfig = FakeMailetConfig.builder()
                 .mailetName("Test")
-                .setProperty("org.apache.james.junit1", "true")
-                .setProperty("org.apache.james.junit2", "happy")
+                .setProperty(name1.asString(), value1.value())
+                .setProperty(name2.asString(), value2.value())
                 .build();
 
         mailet.init(mailetConfig);
@@ -55,8 +64,8 @@ class SetMailAttributeTest {
         
         mailet.service(mail);
 
-        assertThat(mail.getAttribute("org.apache.james.junit1")).isEqualTo("true");
-        assertThat(mail.getAttribute("org.apache.james.junit2")).isEqualTo("happy");
+        assertThat(mail.getAttribute(name1)).contains(attribute1);
+        assertThat(mail.getAttribute(name2)).contains(attribute2);
     }
     
     @Test
@@ -71,7 +80,7 @@ class SetMailAttributeTest {
         
         mailet.service(mail);
 
-        assertThat(mail.getAttributeNames()).isEmpty();
+        assertThat(mail.attributes()).isEmpty();
     }
     
     @Test
diff --git a/mailet/test/src/main/java/org/apache/mailet/base/test/FakeMailContext.java b/mailet/test/src/main/java/org/apache/mailet/base/test/FakeMailContext.java
index 7fbb014..d34f5d4 100644
--- a/mailet/test/src/main/java/org/apache/mailet/base/test/FakeMailContext.java
+++ b/mailet/test/src/main/java/org/apache/mailet/base/test/FakeMailContext.java
@@ -29,6 +29,7 @@ import java.util.Objects;
 import java.util.Optional;
 import java.util.concurrent.ConcurrentLinkedQueue;
 import java.util.concurrent.TimeUnit;
+import java.util.function.Function;
 
 import javax.mail.MessagingException;
 import javax.mail.internet.AddressException;
@@ -37,6 +38,8 @@ import javax.mail.internet.MimeMessage;
 import org.apache.james.core.Domain;
 import org.apache.james.core.MailAddress;
 import org.apache.james.core.builder.MimeMessageWrapper;
+import org.apache.mailet.Attribute;
+import org.apache.mailet.AttributeName;
 import org.apache.mailet.HostAddress;
 import org.apache.mailet.LookupException;
 import org.apache.mailet.Mail;
@@ -45,11 +48,11 @@ import org.slf4j.Logger;
 
 import com.github.fge.lambdas.Throwing;
 import com.github.fge.lambdas.functions.ThrowingFunction;
+import com.github.steveash.guavate.Guavate;
 import com.google.common.base.MoreObjects;
 import com.google.common.base.Preconditions;
 import com.google.common.collect.ImmutableList;
 import com.google.common.collect.ImmutableMap;
-import com.google.common.collect.Lists;
 
 @SuppressWarnings("deprecation")
 public class FakeMailContext implements MailetContext {
@@ -68,19 +71,10 @@ public class FakeMailContext implements MailetContext {
             .recipients(mail.getRecipients())
             .message(mail.getMessage())
             .state(mail.getState())
-            .attributes(buildAttributesMap(mail))
+            .attributes(mail.attributes().collect(Guavate.toImmutableList()))
             .fromMailet();
     }
 
-    private static ImmutableMap<String, Serializable> buildAttributesMap(Mail mail) {
-        Map<String, Serializable> result = new HashMap<>();
-        List<String> attributesNames = Lists.newArrayList(mail.getAttributeNames());
-        for (String attributeName: attributesNames) {
-            result.put(attributeName, mail.getAttribute(attributeName));
-        }
-        return ImmutableMap.copyOf(result);
-    }
-
     public static FakeMailContext defaultContext() {
         return builder().build();
     }
@@ -123,7 +117,7 @@ public class FakeMailContext implements MailetContext {
             private MailAddress sender;
             private Optional<Collection<MailAddress>> recipients = Optional.empty();
             private MimeMessage msg;
-            private Map<String, Serializable> attributes = new HashMap<>();
+            private Map<AttributeName, Attribute> attributes = new HashMap<>();
             private Optional<String> state = Optional.empty();
             private Optional<Boolean> fromMailet = Optional.empty();
             private Optional<Delay> delay = Optional.empty();
@@ -172,13 +166,23 @@ public class FakeMailContext implements MailetContext {
                 return this;
             }
 
-            public Builder attributes(Map<String, Serializable> attributes) {
-                this.attributes.putAll(attributes);
+            public Builder attributes(List<Attribute> attributes) {
+                this.attributes.putAll(attributes
+                    .stream()
+                    .collect(Guavate.toImmutableMap(
+                            attribute -> attribute.getName(),
+                            Function.identity()
+                    )));
                 return this;
             }
 
+            @Deprecated
             public Builder attribute(String key, Serializable value) {
-                this.attributes.put(key, value);
+                return attribute(Attribute.convertToAttribute(key, value));
+            }
+
+            public Builder attribute(Attribute attribute) {
+                this.attributes.put(attribute.getName(), attribute);
                 return this;
             }
 
@@ -205,11 +209,11 @@ public class FakeMailContext implements MailetContext {
         private final Collection<MailAddress> recipients;
         private final MimeMessage msg;
         private final Optional<String> subject;
-        private final Map<String, Serializable> attributes;
+        private final Map<AttributeName, Attribute> attributes;
         private final String state;
         private final Optional<Delay> delay;
 
-        private SentMail(MailAddress sender, Collection<MailAddress> recipients, MimeMessage msg, Map<String, Serializable> attributes, String state, Optional<Delay> delay) throws MessagingException {
+        private SentMail(MailAddress sender, Collection<MailAddress> recipients, MimeMessage msg, Map<AttributeName, Attribute> attributes, String state, Optional<Delay> delay) throws MessagingException {
             this.sender = sender;
             this.recipients = ImmutableList.copyOf(recipients);
             this.msg = tryCopyMimeMessage(msg);
@@ -369,7 +373,7 @@ public class FakeMailContext implements MailetContext {
         }
     }
 
-    private final HashMap<String, Object> attributes;
+    private final HashMap<AttributeName, Attribute> attributes;
     private final Collection<SentMail> sentMails;
     private final Collection<BouncedMail> bouncedMails;
     private final Optional<Logger> logger;
@@ -413,7 +417,11 @@ public class FakeMailContext implements MailetContext {
 
     @Override
     public Iterator<String> getAttributeNames() {
-        return attributes.keySet().iterator();
+        return attributes
+            .keySet()
+            .stream()
+            .map(AttributeName::asString)
+            .iterator();
     }
 
     @Override
@@ -525,8 +533,13 @@ public class FakeMailContext implements MailetContext {
                 .build());
     }
 
+    @Deprecated
     public void setAttribute(String name, Serializable object) {
-        attributes.put(name,object);
+        setAttribute(Attribute.convertToAttribute(name, object));
+    }
+
+    public void setAttribute(Attribute attribute) {
+        attributes.put(attribute.getName(), attribute);
     }
 
     public void storeMail(MailAddress sender, MailAddress recipient, MimeMessage msg) throws MessagingException {
diff --git a/server/container/core/src/main/java/org/apache/james/server/core/MailImpl.java b/server/container/core/src/main/java/org/apache/james/server/core/MailImpl.java
index 9d97f30..e9b2583 100644
--- a/server/container/core/src/main/java/org/apache/james/server/core/MailImpl.java
+++ b/server/container/core/src/main/java/org/apache/james/server/core/MailImpl.java
@@ -222,12 +222,6 @@ public class MailImpl implements Disposable, Mail {
             return this;
         }
 
-        @Deprecated
-        public Builder attributes(Map<String, Serializable> attributes) {
-            this.attributes(toAttributeMap(attributes).values());
-            return this;
-        }
-
         public Builder attribute(Attribute attribute) {
             this.attributes.put(attribute.getName(), attribute);
             return this;
diff --git a/server/data/data-jdbc/src/main/java/org/apache/james/mailrepository/jdbc/JDBCMailRepository.java b/server/data/data-jdbc/src/main/java/org/apache/james/mailrepository/jdbc/JDBCMailRepository.java
index 4839de7..8c8572b 100644
--- a/server/data/data-jdbc/src/main/java/org/apache/james/mailrepository/jdbc/JDBCMailRepository.java
+++ b/server/data/data-jdbc/src/main/java/org/apache/james/mailrepository/jdbc/JDBCMailRepository.java
@@ -64,9 +64,12 @@ import org.apache.james.server.core.MimeMessageWrapper;
 import org.apache.james.util.sql.JDBCUtil;
 import org.apache.james.util.sql.SqlResources;
 import org.apache.mailet.Mail;
+
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
 
+import com.github.steveash.guavate.Guavate;
+
 /**
  * Implementation of a MailRepository on a database.
  * 
@@ -474,11 +477,12 @@ public class JDBCMailRepository extends AbstractMailRepository {
                             if (mc instanceof MailImpl) {
                                 oos.writeObject(((MailImpl) mc).getAttributesRaw());
                             } else {
-                                HashMap<String, Serializable> temp = new HashMap<>();
-                                for (Iterator<String> i = mc.getAttributeNames(); i.hasNext();) {
-                                    String hashKey = i.next();
-                                    temp.put(hashKey, mc.getAttribute(hashKey));
-                                }
+                                Map<String, Serializable> temp = mc.attributes()
+                                    .collect(Guavate.toImmutableMap(
+                                            attribute -> attribute.getName().asString(),
+                                            attribute -> (Serializable) attribute.getValue().value()
+                                    ));
+
                                 oos.writeObject(temp);
                             }
                             oos.flush();
@@ -562,11 +566,12 @@ public class JDBCMailRepository extends AbstractMailRepository {
                             if (mc instanceof MailImpl) {
                                 oos.writeObject(((MailImpl) mc).getAttributesRaw());
                             } else {
-                                HashMap<String, Serializable> temp = new HashMap<>();
-                                for (Iterator<String> i = mc.getAttributeNames(); i.hasNext();) {
-                                    String hashKey = i.next();
-                                    temp.put(hashKey, mc.getAttribute(hashKey));
-                                }
+                                Map<String, Serializable> temp = mc.attributes()
+                                        .collect(Guavate.toImmutableMap(
+                                                attribute -> attribute.getName().asString(),
+                                                attribute -> (Serializable) attribute.getValue().value()
+                                        ));
+
                                 oos.writeObject(temp);
                             }
                             oos.flush();
diff --git a/server/mailet/mailetcontainer-camel/src/main/java/org/apache/james/mailetcontainer/impl/camel/CamelMailetProcessor.java b/server/mailet/mailetcontainer-camel/src/main/java/org/apache/james/mailetcontainer/impl/camel/CamelMailetProcessor.java
index 1c9a473..16c0dab 100644
--- a/server/mailet/mailetcontainer-camel/src/main/java/org/apache/james/mailetcontainer/impl/camel/CamelMailetProcessor.java
+++ b/server/mailet/mailetcontainer-camel/src/main/java/org/apache/james/mailetcontainer/impl/camel/CamelMailetProcessor.java
@@ -173,7 +173,7 @@ public class CamelMailetProcessor extends AbstractStateMailetProcessor implement
 
         private void handleMailet(Exchange exchange, CamelMailetProcessor container, CamelProcessor mailetProccessor) throws Exception {
             Mail mail = exchange.getIn().getBody(Mail.class);
-            boolean isMatched = mail.removeAttribute(MatcherSplitter.MATCHER_MATCHED_ATTRIBUTE) != null;
+            boolean isMatched = mail.removeAttribute(MatcherSplitter.MATCHER_MATCHED_ATTRIBUTE).isPresent();
             if (isMatched) {
                 mailetProccessor.process(mail);
             }
diff --git a/server/mailet/mailetcontainer-camel/src/main/java/org/apache/james/mailetcontainer/impl/camel/MatcherMatch.java b/server/mailet/mailetcontainer-camel/src/main/java/org/apache/james/mailetcontainer/impl/camel/MatcherMatch.java
index 038f05d..41c61ad 100644
--- a/server/mailet/mailetcontainer-camel/src/main/java/org/apache/james/mailetcontainer/impl/camel/MatcherMatch.java
+++ b/server/mailet/mailetcontainer-camel/src/main/java/org/apache/james/mailetcontainer/impl/camel/MatcherMatch.java
@@ -33,6 +33,6 @@ public class MatcherMatch implements Predicate {
     @Override
     public boolean matches(Exchange arg0) {
         Mail m = arg0.getIn().getBody(Mail.class);
-        return m.removeAttribute(MatcherSplitter.MATCHER_MATCHED_ATTRIBUTE) != null;
+        return m.removeAttribute(MatcherSplitter.MATCHER_MATCHED_ATTRIBUTE).isPresent();
     }
 }
diff --git a/server/mailet/mailetcontainer-camel/src/main/java/org/apache/james/mailetcontainer/impl/camel/MatcherSplitter.java b/server/mailet/mailetcontainer-camel/src/main/java/org/apache/james/mailetcontainer/impl/camel/MatcherSplitter.java
index 7f328fe..03fe79a 100644
--- a/server/mailet/mailetcontainer-camel/src/main/java/org/apache/james/mailetcontainer/impl/camel/MatcherSplitter.java
+++ b/server/mailet/mailetcontainer-camel/src/main/java/org/apache/james/mailetcontainer/impl/camel/MatcherSplitter.java
@@ -39,6 +39,9 @@ import org.apache.james.metrics.api.MetricFactory;
 import org.apache.james.metrics.api.TimeMetric;
 import org.apache.james.server.core.MailImpl;
 import org.apache.james.util.MDCBuilder;
+import org.apache.mailet.Attribute;
+import org.apache.mailet.AttributeName;
+import org.apache.mailet.AttributeValue;
 import org.apache.mailet.Mail;
 import org.apache.mailet.Matcher;
 import org.slf4j.Logger;
@@ -55,7 +58,7 @@ public class MatcherSplitter {
     private static final Logger LOGGER = LoggerFactory.getLogger(MatcherSplitter.class);
 
     /** Headername which is used to indicate that the matcher matched */
-    public static final String MATCHER_MATCHED_ATTRIBUTE = "matched";
+    public static final AttributeName MATCHER_MATCHED_ATTRIBUTE = AttributeName.of("matched");
 
     private final MetricFactory metricFactory;
     private final CamelMailetProcessor container;
@@ -154,7 +157,7 @@ public class MatcherSplitter {
 
                     // Set a header because the matcher matched. This can be
                     // used later when processing the route
-                    newMail.setAttribute(MATCHER_MATCHED_ATTRIBUTE, true);
+                    newMail.setAttribute(new Attribute(MATCHER_MATCHED_ATTRIBUTE, AttributeValue.of(true)));
 
                     // add the new generated mail to the mails list
                     mails.add(newMail);
@@ -164,7 +167,7 @@ public class MatcherSplitter {
             if (fullMatch) {
                 // Set a header because the matcher matched. This can be used
                 // later when processing the route
-                mail.setAttribute(MATCHER_MATCHED_ATTRIBUTE, true);
+                mail.setAttribute(new Attribute(MATCHER_MATCHED_ATTRIBUTE, AttributeValue.of(true)));
             }
 
             // add mailMsg to the mails list
diff --git a/server/mailet/mailets/src/main/java/org/apache/james/transport/mailets/AbstractRecipientRewriteTable.java b/server/mailet/mailets/src/main/java/org/apache/james/transport/mailets/AbstractRecipientRewriteTable.java
index 391da56..a83fc32 100755
--- a/server/mailet/mailets/src/main/java/org/apache/james/transport/mailets/AbstractRecipientRewriteTable.java
+++ b/server/mailet/mailets/src/main/java/org/apache/james/transport/mailets/AbstractRecipientRewriteTable.java
@@ -42,6 +42,9 @@ import org.apache.james.rrt.api.RecipientRewriteTable;
 import org.apache.james.rrt.lib.Mapping;
 import org.apache.james.rrt.lib.UserRewritter;
 import org.apache.james.server.core.MailImpl;
+import org.apache.mailet.Attribute;
+import org.apache.mailet.AttributeName;
+import org.apache.mailet.AttributeValue;
 import org.apache.mailet.Experimental;
 import org.apache.mailet.Mail;
 import org.apache.mailet.base.GenericMailet;
@@ -59,7 +62,7 @@ import org.slf4j.LoggerFactory;
 @Experimental
 public abstract class AbstractRecipientRewriteTable extends GenericMailet {
     private static final Logger LOGGER = LoggerFactory.getLogger(AbstractRecipientRewriteTable.class);
-    private static final String MARKER = "org.apache.james.transport.mailets.AbstractRecipientRewriteTable.mapped";
+    private static final AttributeName MARKER = AttributeName.of("org.apache.james.transport.mailets.AbstractRecipientRewriteTable.mapped");
     private DNSService dns;
     private DomainList domainList;
 
@@ -83,7 +86,7 @@ public abstract class AbstractRecipientRewriteTable extends GenericMailet {
      */
     @Override
     public void service(Mail mail) throws MessagingException {
-        if (mail.getAttribute(MARKER) != null) {
+        if (mail.getAttribute(MARKER).isPresent()) {
             mail.removeAttribute(MARKER);
             return;
         }
@@ -203,7 +206,7 @@ public abstract class AbstractRecipientRewriteTable extends GenericMailet {
                 }
 
                 newMail.setRecipients(recipientsToAddForward);
-                newMail.setAttribute(MARKER, Boolean.TRUE);
+                newMail.setAttribute(new Attribute(MARKER, AttributeValue.of(Boolean.TRUE)));
                 getMailetContext().sendMail(newMail);
             } finally {
                 newMail.dispose();
diff --git a/server/mailet/mailets/src/test/java/org/apache/james/transport/mailets/WithStorageDirectiveTest.java b/server/mailet/mailets/src/test/java/org/apache/james/transport/mailets/WithStorageDirectiveTest.java
index 2f61236..1c26498 100644
--- a/server/mailet/mailets/src/test/java/org/apache/james/transport/mailets/WithStorageDirectiveTest.java
+++ b/server/mailet/mailets/src/test/java/org/apache/james/transport/mailets/WithStorageDirectiveTest.java
@@ -101,22 +101,26 @@ public class WithStorageDirectiveTest {
 
     @Test
     public void serviceShouldOverridePreviousStorageDirectives() throws Exception {
-        String targetFolderName = "Spam";
+        AttributeName name1 = AttributeName.of("DeliveryPath_recipient1@localhost");
+        AttributeName name2 = AttributeName.of("DeliveryPath_recipient2@localhost");
+        AttributeValue<String> targetFolderName = AttributeValue.of("Spam");
+        Attribute attribute1 = new Attribute(name1, targetFolderName);
+        Attribute attribute2 = new Attribute(name2, targetFolderName);
         testee.init(FakeMailetConfig.builder()
-            .setProperty(WithStorageDirective.TARGET_FOLDER_NAME, targetFolderName)
+            .setProperty(WithStorageDirective.TARGET_FOLDER_NAME, targetFolderName.value())
             .build());
 
         FakeMail mail = FakeMail.builder()
             .recipients(MailAddressFixture.RECIPIENT1, MailAddressFixture.RECIPIENT2)
-            .attribute("DeliveryPath_recipient2@localhost", "otherFolder")
+            .attribute(new Attribute(name2, AttributeValue.of("otherFolder")))
             .build();
 
         testee.service(mail);
 
-        softly.assertThat(mail.getAttributeNames())
-            .containsOnly("DeliveryPath_recipient2@localhost", "DeliveryPath_recipient1@localhost");
-        softly.assertThat(mail.getAttribute("DeliveryPath_recipient1@localhost")).isEqualTo(targetFolderName);
-        softly.assertThat(mail.getAttribute("DeliveryPath_recipient2@localhost")).isEqualTo(targetFolderName);
+        softly.assertThat(mail.attributes())
+            .containsExactlyInAnyOrder(attribute1, attribute2);
+        softly.assertThat(mail.getAttribute(name1)).contains(attribute1);
+        softly.assertThat(mail.getAttribute(name2)).contains(attribute2);
     }
 
 }
\ No newline at end of file
diff --git a/server/mailet/mailets/src/test/java/org/apache/james/transport/mailets/delivery/SieveIntegrationTest.java b/server/mailet/mailets/src/test/java/org/apache/james/transport/mailets/delivery/SieveIntegrationTest.java
index 66ac1cb..bfee91b 100644
--- a/server/mailet/mailets/src/test/java/org/apache/james/transport/mailets/delivery/SieveIntegrationTest.java
+++ b/server/mailet/mailets/src/test/java/org/apache/james/transport/mailets/delivery/SieveIntegrationTest.java
@@ -38,6 +38,9 @@ import org.apache.james.transport.mailets.Sieve;
 import org.apache.james.transport.mailets.jsieve.ResourceLocator;
 import org.apache.james.user.api.UsersRepository;
 import org.apache.james.util.MimeMessageUtil;
+import org.apache.mailet.Attribute;
+import org.apache.mailet.AttributeName;
+import org.apache.mailet.AttributeValue;
 import org.apache.mailet.Mail;
 import org.apache.mailet.base.test.FakeMail;
 import org.apache.mailet.base.test.FakeMailContext;
@@ -58,6 +61,15 @@ public class SieveIntegrationTest {
     public static final MailboxPath NOT_SELECTED_MAILBOX = MailboxPath.forUser(LOCAL_PART, "INBOX.not.selected");
     public static final MailboxPath SELECTED_MAILBOX = MailboxPath.forUser(LOCAL_PART, "INBOX.select");
     public static final MailboxPath INBOX = MailboxPath.forUser(LOCAL_PART, "INBOX");
+    public static final MailboxPath INBOX_ANY = MailboxPath.forUser(LOCAL_PART, "INBOX.any");
+
+    public static final AttributeName ATTRIBUTE_NAME = AttributeName.of(MailStore.DELIVERY_PATH_PREFIX + LOCAL_PART);
+    public static final Attribute ATTRIBUTE_INBOX = new Attribute(ATTRIBUTE_NAME, AttributeValue.of(expressMailboxNameWithSlash(INBOX.getName())));
+    public static final Attribute ATTRIBUTE_INBOX_ANY = new Attribute(ATTRIBUTE_NAME, AttributeValue.of(expressMailboxNameWithSlash(INBOX_ANY.getName())));
+    public static final Attribute ATTRIBUTE_SELECTED_MAILBOX = new Attribute(ATTRIBUTE_NAME, AttributeValue.of(expressMailboxNameWithSlash(SELECTED_MAILBOX.getName())));
+    public static final Attribute ATTRIBUTE_NOT_SELECTED_MAILBOX = new Attribute(ATTRIBUTE_NAME, AttributeValue.of(expressMailboxNameWithSlash(NOT_SELECTED_MAILBOX.getName())));
+    public static final AttributeName ATTRIBUTE_NAME_DOMAIN = AttributeName.of(MailStore.DELIVERY_PATH_PREFIX + RECEIVER_DOMAIN_COM);
+    public static final Attribute ATTRIBUTE_INBOX_DOMAIN = new Attribute(ATTRIBUTE_NAME_DOMAIN, AttributeValue.of(expressMailboxNameWithSlash(INBOX.getName())));
 
     private Sieve testee;
     private UsersRepository usersRepository;
@@ -83,7 +95,7 @@ public class SieveIntegrationTest {
         FakeMail mail = createMail();
         testee.service(mail);
 
-        assertThat(mail.getAttribute(MailStore.DELIVERY_PATH_PREFIX + RECEIVER_DOMAIN_COM)).isNull();
+        assertThat(mail.getAttribute(ATTRIBUTE_NAME_DOMAIN)).isEmpty();
         assertThat(mail.getState()).isEqualTo(Mail.DEFAULT);
     }
 
@@ -96,7 +108,7 @@ public class SieveIntegrationTest {
         FakeMail mail = createMail();
         testee.service(mail);
 
-        assertThat(mail.getAttribute(MailStore.DELIVERY_PATH_PREFIX + RECEIVER_DOMAIN_COM)).isEqualTo("/INBOX");
+        assertThat(mail.getAttribute(ATTRIBUTE_NAME_DOMAIN)).contains(ATTRIBUTE_INBOX_DOMAIN);
     }
 
     @Test
@@ -108,7 +120,7 @@ public class SieveIntegrationTest {
         FakeMail mail = createMail();
         testee.service(mail);
 
-        assertThat(mail.getAttribute(MailStore.DELIVERY_PATH_PREFIX + LOCAL_PART)).isEqualTo("/INBOX");
+        assertThat(mail.getAttribute(ATTRIBUTE_NAME)).contains(ATTRIBUTE_INBOX);
     }
 
     @Test
@@ -118,7 +130,7 @@ public class SieveIntegrationTest {
         FakeMail mail = createMail();
         testee.service(mail);
 
-        assertThat(mail.getAttribute(MailStore.DELIVERY_PATH_PREFIX + LOCAL_PART)).isEqualTo("/INBOX");
+        assertThat(mail.getAttribute(ATTRIBUTE_NAME)).contains(ATTRIBUTE_INBOX);
     }
 
     @Test
@@ -138,7 +150,7 @@ public class SieveIntegrationTest {
         FakeMail mail = createMail();
         testee.service(mail);
 
-        assertThat(mail.getAttribute(MailStore.DELIVERY_PATH_PREFIX + LOCAL_PART)).isEqualTo("/INBOX/any");
+        assertThat(mail.getAttribute(ATTRIBUTE_NAME)).contains(ATTRIBUTE_INBOX_ANY);
     }
 
     @Test
@@ -148,7 +160,7 @@ public class SieveIntegrationTest {
         FakeMail mail = createMail();
         testee.service(mail);
 
-        assertThat(mail.getAttribute(MailStore.DELIVERY_PATH_PREFIX + LOCAL_PART)).isEqualTo(expressMailboxNameWithSlash(NOT_SELECTED_MAILBOX.getName()));
+        assertThat(mail.getAttribute(ATTRIBUTE_NAME)).contains(ATTRIBUTE_NOT_SELECTED_MAILBOX);
     }
 
     @Test
@@ -158,7 +170,7 @@ public class SieveIntegrationTest {
         FakeMail mail = createMail();
         testee.service(mail);
 
-        assertThat(mail.getAttribute(MailStore.DELIVERY_PATH_PREFIX + LOCAL_PART)).isEqualTo(expressMailboxNameWithSlash(NOT_SELECTED_MAILBOX.getName()));
+        assertThat(mail.getAttribute(ATTRIBUTE_NAME)).contains(ATTRIBUTE_NOT_SELECTED_MAILBOX);
     }
 
     @Test
@@ -168,7 +180,7 @@ public class SieveIntegrationTest {
         FakeMail mail = createMail();
         testee.service(mail);
 
-        assertThat(mail.getAttribute(MailStore.DELIVERY_PATH_PREFIX + LOCAL_PART)).isEqualTo(expressMailboxNameWithSlash(SELECTED_MAILBOX.getName()));
+        assertThat(mail.getAttribute(ATTRIBUTE_NAME)).contains(ATTRIBUTE_SELECTED_MAILBOX);
     }
 
     @Test
@@ -178,7 +190,7 @@ public class SieveIntegrationTest {
         FakeMail mail = createMail();
         testee.service(mail);
 
-        assertThat(mail.getAttribute(MailStore.DELIVERY_PATH_PREFIX + LOCAL_PART)).isEqualTo(expressMailboxNameWithSlash(NOT_SELECTED_MAILBOX.getName()));
+        assertThat(mail.getAttribute(ATTRIBUTE_NAME)).contains(ATTRIBUTE_NOT_SELECTED_MAILBOX);
     }
 
     @Test
@@ -188,7 +200,7 @@ public class SieveIntegrationTest {
         FakeMail mail = createMail();
         testee.service(mail);
 
-        assertThat(mail.getAttribute(MailStore.DELIVERY_PATH_PREFIX + LOCAL_PART)).isEqualTo(expressMailboxNameWithSlash(NOT_SELECTED_MAILBOX.getName()));
+        assertThat(mail.getAttribute(ATTRIBUTE_NAME)).contains(ATTRIBUTE_NOT_SELECTED_MAILBOX);
     }
 
     @Test
@@ -198,7 +210,7 @@ public class SieveIntegrationTest {
         FakeMail mail = createMail();
         testee.service(mail);
 
-        assertThat(mail.getAttribute(MailStore.DELIVERY_PATH_PREFIX + LOCAL_PART)).isEqualTo(expressMailboxNameWithSlash(SELECTED_MAILBOX.getName()));
+        assertThat(mail.getAttribute(ATTRIBUTE_NAME)).contains(ATTRIBUTE_SELECTED_MAILBOX);
     }
 
     @Test
@@ -208,7 +220,7 @@ public class SieveIntegrationTest {
         FakeMail mail = createMail();
         testee.service(mail);
 
-        assertThat(mail.getAttribute(MailStore.DELIVERY_PATH_PREFIX + LOCAL_PART)).isEqualTo(expressMailboxNameWithSlash(SELECTED_MAILBOX.getName()));
+        assertThat(mail.getAttribute(ATTRIBUTE_NAME)).contains(ATTRIBUTE_SELECTED_MAILBOX);
     }
 
     @Test
@@ -218,7 +230,7 @@ public class SieveIntegrationTest {
         FakeMail mail = createMail();
         testee.service(mail);
 
-        assertThat(mail.getAttribute(MailStore.DELIVERY_PATH_PREFIX + LOCAL_PART)).isEqualTo(expressMailboxNameWithSlash(NOT_SELECTED_MAILBOX.getName()));
+        assertThat(mail.getAttribute(ATTRIBUTE_NAME)).contains(ATTRIBUTE_NOT_SELECTED_MAILBOX);
     }
 
     @Test
@@ -228,7 +240,7 @@ public class SieveIntegrationTest {
         FakeMail mail = createMail();
         testee.service(mail);
 
-        assertThat(mail.getAttribute(MailStore.DELIVERY_PATH_PREFIX + LOCAL_PART)).isEqualTo(expressMailboxNameWithSlash(SELECTED_MAILBOX.getName()));
+        assertThat(mail.getAttribute(ATTRIBUTE_NAME)).contains(ATTRIBUTE_SELECTED_MAILBOX);
     }
 
     @Test
@@ -238,7 +250,7 @@ public class SieveIntegrationTest {
         FakeMail mail = createMail();
         testee.service(mail);
 
-        assertThat(mail.getAttribute(MailStore.DELIVERY_PATH_PREFIX + LOCAL_PART)).isEqualTo(expressMailboxNameWithSlash(SELECTED_MAILBOX.getName()));
+        assertThat(mail.getAttribute(ATTRIBUTE_NAME)).contains(ATTRIBUTE_SELECTED_MAILBOX);
     }
 
     @Test
@@ -248,7 +260,7 @@ public class SieveIntegrationTest {
         FakeMail mail = createMail();
         testee.service(mail);
 
-        assertThat(mail.getAttribute(MailStore.DELIVERY_PATH_PREFIX + LOCAL_PART)).isEqualTo(expressMailboxNameWithSlash(INBOX.getName()));
+        assertThat(mail.getAttribute(ATTRIBUTE_NAME)).contains(ATTRIBUTE_INBOX);
     }
 
     @Test
@@ -258,7 +270,7 @@ public class SieveIntegrationTest {
         FakeMail mail = createMail();
         testee.service(mail);
 
-        assertThat(mail.getAttribute(MailStore.DELIVERY_PATH_PREFIX + LOCAL_PART)).isEqualTo(expressMailboxNameWithSlash(NOT_SELECTED_MAILBOX.getName()));
+        assertThat(mail.getAttribute(ATTRIBUTE_NAME)).contains(ATTRIBUTE_NOT_SELECTED_MAILBOX);
     }
 
     @Test
@@ -274,8 +286,8 @@ public class SieveIntegrationTest {
             .build();
         testee.service(mail);
 
-        assertThat(mail.getAttribute(MailStore.DELIVERY_PATH_PREFIX + LOCAL_PART))
-            .isEqualTo(expressMailboxNameWithSlash(SELECTED_MAILBOX.getName()));
+        assertThat(mail.getAttribute(ATTRIBUTE_NAME))
+            .contains(ATTRIBUTE_SELECTED_MAILBOX);
     }
 
 
@@ -286,7 +298,7 @@ public class SieveIntegrationTest {
         FakeMail mail = createMailWithSubject("JAMES-1620 revolution");
         testee.service(mail);
 
-        assertThat(mail.getAttribute(MailStore.DELIVERY_PATH_PREFIX + LOCAL_PART)).isEqualTo(expressMailboxNameWithSlash(SELECTED_MAILBOX.getName()));
+        assertThat(mail.getAttribute(ATTRIBUTE_NAME)).contains(ATTRIBUTE_SELECTED_MAILBOX);
     }
 
     @Test
@@ -297,7 +309,7 @@ public class SieveIntegrationTest {
         mail.setMessageSize(100);
         testee.service(mail);
 
-        assertThat(mail.getAttribute(MailStore.DELIVERY_PATH_PREFIX + LOCAL_PART)).isEqualTo(expressMailboxNameWithSlash(NOT_SELECTED_MAILBOX.getName()));
+        assertThat(mail.getAttribute(ATTRIBUTE_NAME)).contains(ATTRIBUTE_NOT_SELECTED_MAILBOX);
     }
 
     @Test
@@ -308,7 +320,7 @@ public class SieveIntegrationTest {
         mail.setMessageSize(100);
         testee.service(mail);
 
-        assertThat(mail.getAttribute(MailStore.DELIVERY_PATH_PREFIX + LOCAL_PART)).isEqualTo(expressMailboxNameWithSlash(SELECTED_MAILBOX.getName()));
+        assertThat(mail.getAttribute(ATTRIBUTE_NAME)).contains(ATTRIBUTE_SELECTED_MAILBOX);
     }
 
     @Test
@@ -319,7 +331,7 @@ public class SieveIntegrationTest {
         mail.setMessageSize(1000);
         testee.service(mail);
 
-        assertThat(mail.getAttribute(MailStore.DELIVERY_PATH_PREFIX + LOCAL_PART)).isEqualTo(expressMailboxNameWithSlash(SELECTED_MAILBOX.getName()));
+        assertThat(mail.getAttribute(ATTRIBUTE_NAME)).contains(ATTRIBUTE_SELECTED_MAILBOX);
     }
 
     @Test
@@ -330,7 +342,7 @@ public class SieveIntegrationTest {
         mail.setMessageSize(1000);
         testee.service(mail);
 
-        assertThat(mail.getAttribute(MailStore.DELIVERY_PATH_PREFIX + LOCAL_PART)).isEqualTo(expressMailboxNameWithSlash(NOT_SELECTED_MAILBOX.getName()));
+        assertThat(mail.getAttribute(ATTRIBUTE_NAME)).contains(ATTRIBUTE_NOT_SELECTED_MAILBOX);
     }
 
     @Test
@@ -340,7 +352,7 @@ public class SieveIntegrationTest {
         FakeMail mail = createMailWithSubjectAndHeaders("Default", new Header("Cc", "source@any.com"));
         testee.service(mail);
 
-        assertThat(mail.getAttribute(MailStore.DELIVERY_PATH_PREFIX + LOCAL_PART)).isEqualTo(expressMailboxNameWithSlash(SELECTED_MAILBOX.getName()));
+        assertThat(mail.getAttribute(ATTRIBUTE_NAME)).contains(ATTRIBUTE_SELECTED_MAILBOX);
     }
 
 
@@ -351,7 +363,7 @@ public class SieveIntegrationTest {
         FakeMail mail = createMailWithSubjectAndHeaders("Default", new Header("Cc", "source1@domain.com"));
         testee.service(mail);
 
-        assertThat(mail.getAttribute(MailStore.DELIVERY_PATH_PREFIX + LOCAL_PART)).isEqualTo(expressMailboxNameWithSlash(NOT_SELECTED_MAILBOX.getName()));
+        assertThat(mail.getAttribute(ATTRIBUTE_NAME)).contains(ATTRIBUTE_NOT_SELECTED_MAILBOX);
     }
 
 
@@ -362,7 +374,7 @@ public class SieveIntegrationTest {
         FakeMail mail = createMailWithSubjectAndHeaders("Default", new Header("Cc", "source1@domain.com"));
         testee.service(mail);
 
-        assertThat(mail.getAttribute(MailStore.DELIVERY_PATH_PREFIX + LOCAL_PART)).isEqualTo(expressMailboxNameWithSlash(SELECTED_MAILBOX.getName()));
+        assertThat(mail.getAttribute(ATTRIBUTE_NAME)).contains(ATTRIBUTE_SELECTED_MAILBOX);
     }
 
     @Test
@@ -372,7 +384,7 @@ public class SieveIntegrationTest {
         FakeMail mail = createMailWithSubjectAndHeaders("Default", new Header("Cc", "source@domain.org"));
         testee.service(mail);
 
-        assertThat(mail.getAttribute(MailStore.DELIVERY_PATH_PREFIX + LOCAL_PART)).isEqualTo(expressMailboxNameWithSlash(NOT_SELECTED_MAILBOX.getName()));
+        assertThat(mail.getAttribute(ATTRIBUTE_NAME)).contains(ATTRIBUTE_NOT_SELECTED_MAILBOX);
     }
 
     @Test
@@ -382,7 +394,7 @@ public class SieveIntegrationTest {
         FakeMail mail = createMailWithSubjectAndHeaders("Default", new Header("Cc", "source@domain.com"));
         testee.service(mail);
 
-        assertThat(mail.getAttribute(MailStore.DELIVERY_PATH_PREFIX + LOCAL_PART)).isEqualTo(expressMailboxNameWithSlash(NOT_SELECTED_MAILBOX.getName()));
+        assertThat(mail.getAttribute(ATTRIBUTE_NAME)).contains(ATTRIBUTE_NOT_SELECTED_MAILBOX);
     }
 
     @Test
@@ -392,7 +404,7 @@ public class SieveIntegrationTest {
         FakeMail mail = createMailWithSubjectAndHeaders("Default", new Header("Bcc", "source@domain.com"));
         testee.service(mail);
 
-        assertThat(mail.getAttribute(MailStore.DELIVERY_PATH_PREFIX + LOCAL_PART)).isEqualTo(expressMailboxNameWithSlash(SELECTED_MAILBOX.getName()));
+        assertThat(mail.getAttribute(ATTRIBUTE_NAME)).contains(ATTRIBUTE_SELECTED_MAILBOX);
     }
 
     @Test
@@ -402,7 +414,7 @@ public class SieveIntegrationTest {
         FakeMail mail = createMailWithSubjectAndHeaders("Default", new Header("Bcc", "source2@domain.com"));
         testee.service(mail);
 
-        assertThat(mail.getAttribute(MailStore.DELIVERY_PATH_PREFIX + LOCAL_PART)).isEqualTo(expressMailboxNameWithSlash(NOT_SELECTED_MAILBOX.getName()));
+        assertThat(mail.getAttribute(ATTRIBUTE_NAME)).contains(ATTRIBUTE_NOT_SELECTED_MAILBOX);
     }
 
     @Test
@@ -412,7 +424,7 @@ public class SieveIntegrationTest {
         FakeMail mail = createMailWithSubjectAndHeaders("Default", new Header("Bcc", "source@domain.org"));
         testee.service(mail);
 
-        assertThat(mail.getAttribute(MailStore.DELIVERY_PATH_PREFIX + LOCAL_PART)).isEqualTo(expressMailboxNameWithSlash(NOT_SELECTED_MAILBOX.getName()));
+        assertThat(mail.getAttribute(ATTRIBUTE_NAME)).contains(ATTRIBUTE_NOT_SELECTED_MAILBOX);
     }
 
     @Test
@@ -439,7 +451,7 @@ public class SieveIntegrationTest {
         FakeMail mail = createMailWithSubjectAndHeaders("Default", new Header("Resend-From", "source@domain.com"));
         testee.service(mail);
 
-        assertThat(mail.getAttribute(MailStore.DELIVERY_PATH_PREFIX + LOCAL_PART)).isEqualTo(expressMailboxNameWithSlash(NOT_SELECTED_MAILBOX.getName()));
+        assertThat(mail.getAttribute(ATTRIBUTE_NAME)).contains(ATTRIBUTE_NOT_SELECTED_MAILBOX);
     }
 
     @Test
@@ -449,7 +461,7 @@ public class SieveIntegrationTest {
         FakeMail mail = createMailWithSubjectAndHeaders("Default", new Header("Cc", "source@domain.com"));
         testee.service(mail);
 
-        assertThat(mail.getAttribute(MailStore.DELIVERY_PATH_PREFIX + LOCAL_PART)).isEqualTo(expressMailboxNameWithSlash(SELECTED_MAILBOX.getName()));
+        assertThat(mail.getAttribute(ATTRIBUTE_NAME)).contains(ATTRIBUTE_SELECTED_MAILBOX);
     }
 
     @Test
@@ -459,7 +471,7 @@ public class SieveIntegrationTest {
         FakeMail mail = createMailWithSubjectAndHeaders("Default", new Header("Cc", "source2@domain.com"));
         testee.service(mail);
 
-        assertThat(mail.getAttribute(MailStore.DELIVERY_PATH_PREFIX + LOCAL_PART)).isEqualTo(expressMailboxNameWithSlash(NOT_SELECTED_MAILBOX.getName()));
+        assertThat(mail.getAttribute(ATTRIBUTE_NAME)).contains(ATTRIBUTE_NOT_SELECTED_MAILBOX);
     }
 
     @Test
@@ -469,7 +481,7 @@ public class SieveIntegrationTest {
         FakeMail mail = createMailWithSubjectAndHeaders("Default", new Header("Cc", "source@domain.org"));
         testee.service(mail);
 
-        assertThat(mail.getAttribute(MailStore.DELIVERY_PATH_PREFIX + LOCAL_PART)).isEqualTo(expressMailboxNameWithSlash(NOT_SELECTED_MAILBOX.getName()));
+        assertThat(mail.getAttribute(ATTRIBUTE_NAME)).contains(ATTRIBUTE_NOT_SELECTED_MAILBOX);
     }
 
     @Test
@@ -479,7 +491,7 @@ public class SieveIntegrationTest {
         FakeMail mail = createMailWithSubjectAndHeaders("Default", new Header("Cc", "source@domain.com"));
         testee.service(mail);
 
-        assertThat(mail.getAttribute(MailStore.DELIVERY_PATH_PREFIX + LOCAL_PART)).isEqualTo(expressMailboxNameWithSlash(NOT_SELECTED_MAILBOX.getName()));
+        assertThat(mail.getAttribute(ATTRIBUTE_NAME)).contains(ATTRIBUTE_NOT_SELECTED_MAILBOX);
     }
 
     @Test
@@ -489,7 +501,7 @@ public class SieveIntegrationTest {
         FakeMail mail = createMailWithSubjectAndHeaders("Default", new Header("From", "source@domain.com"));
         testee.service(mail);
 
-        assertThat(mail.getAttribute(MailStore.DELIVERY_PATH_PREFIX + LOCAL_PART)).isEqualTo(expressMailboxNameWithSlash(SELECTED_MAILBOX.getName()));
+        assertThat(mail.getAttribute(ATTRIBUTE_NAME)).contains(ATTRIBUTE_SELECTED_MAILBOX);
     }
 
     @Test
@@ -499,7 +511,7 @@ public class SieveIntegrationTest {
         FakeMail mail = createMailWithSubjectAndHeaders("Default", new Header("From", "source2@domain.com"));
         testee.service(mail);
 
-        assertThat(mail.getAttribute(MailStore.DELIVERY_PATH_PREFIX + LOCAL_PART)).isEqualTo(expressMailboxNameWithSlash(NOT_SELECTED_MAILBOX.getName()));
+        assertThat(mail.getAttribute(ATTRIBUTE_NAME)).contains(ATTRIBUTE_NOT_SELECTED_MAILBOX);
     }
 
     @Test
@@ -509,7 +521,7 @@ public class SieveIntegrationTest {
         FakeMail mail = createMailWithSubjectAndHeaders("Default", new Header("From", "source@domain.org"));
         testee.service(mail);
 
-        assertThat(mail.getAttribute(MailStore.DELIVERY_PATH_PREFIX + LOCAL_PART)).isEqualTo(expressMailboxNameWithSlash(NOT_SELECTED_MAILBOX.getName()));
+        assertThat(mail.getAttribute(ATTRIBUTE_NAME)).contains(ATTRIBUTE_NOT_SELECTED_MAILBOX);
     }
 
     @Test
@@ -519,7 +531,7 @@ public class SieveIntegrationTest {
         FakeMail mail = createMailWithSubjectAndHeaders("Default", new Header("Resent-To", "source@domain.com"));
         testee.service(mail);
 
-        assertThat(mail.getAttribute(MailStore.DELIVERY_PATH_PREFIX + LOCAL_PART)).isEqualTo(expressMailboxNameWithSlash(NOT_SELECTED_MAILBOX.getName()));
+        assertThat(mail.getAttribute(ATTRIBUTE_NAME)).contains(ATTRIBUTE_NOT_SELECTED_MAILBOX);
     }
 
     @Test
@@ -529,7 +541,7 @@ public class SieveIntegrationTest {
         FakeMail mail = createMailWithSubjectAndHeaders("Default", new Header("To", "source@domain.com"));
         testee.service(mail);
 
-        assertThat(mail.getAttribute(MailStore.DELIVERY_PATH_PREFIX + LOCAL_PART)).isEqualTo(expressMailboxNameWithSlash(SELECTED_MAILBOX.getName()));
+        assertThat(mail.getAttribute(ATTRIBUTE_NAME)).contains(ATTRIBUTE_SELECTED_MAILBOX);
     }
 
     @Test
@@ -539,7 +551,7 @@ public class SieveIntegrationTest {
         FakeMail mail = createMailWithSubjectAndHeaders("Default", new Header("To", "source2@domain.com"));
         testee.service(mail);
 
-        assertThat(mail.getAttribute(MailStore.DELIVERY_PATH_PREFIX + LOCAL_PART)).isEqualTo(expressMailboxNameWithSlash(NOT_SELECTED_MAILBOX.getName()));
+        assertThat(mail.getAttribute(ATTRIBUTE_NAME)).contains(ATTRIBUTE_NOT_SELECTED_MAILBOX);
     }
 
     @Test
@@ -549,7 +561,7 @@ public class SieveIntegrationTest {
         FakeMail mail = createMailWithSubjectAndHeaders("Default", new Header("To", "source@domain.org"));
         testee.service(mail);
 
-        assertThat(mail.getAttribute(MailStore.DELIVERY_PATH_PREFIX + LOCAL_PART)).isEqualTo(expressMailboxNameWithSlash(NOT_SELECTED_MAILBOX.getName()));
+        assertThat(mail.getAttribute(ATTRIBUTE_NAME)).contains(ATTRIBUTE_NOT_SELECTED_MAILBOX);
     }
 
     @Test
@@ -559,7 +571,7 @@ public class SieveIntegrationTest {
         FakeMail mail = createMailWithSubjectAndHeaders("Default", new Header("To", "source@domain.com"));
         testee.service(mail);
 
-        assertThat(mail.getAttribute(MailStore.DELIVERY_PATH_PREFIX + LOCAL_PART)).isEqualTo(expressMailboxNameWithSlash(NOT_SELECTED_MAILBOX.getName()));
+        assertThat(mail.getAttribute(ATTRIBUTE_NAME)).contains(ATTRIBUTE_NOT_SELECTED_MAILBOX);
     }
 
     @Test
@@ -569,7 +581,7 @@ public class SieveIntegrationTest {
         FakeMail mail = createMailWithSubjectAndHeaders("Default", new Header("Sender", "source@domain.com"));
         testee.service(mail);
 
-        assertThat(mail.getAttribute(MailStore.DELIVERY_PATH_PREFIX + LOCAL_PART)).isEqualTo(expressMailboxNameWithSlash(SELECTED_MAILBOX.getName()));
+        assertThat(mail.getAttribute(ATTRIBUTE_NAME)).contains(ATTRIBUTE_SELECTED_MAILBOX);
     }
 
     @Test
@@ -579,7 +591,7 @@ public class SieveIntegrationTest {
         FakeMail mail = createMailWithSubjectAndHeaders("Default", new Header("Sender", "source2@domain.com"));
         testee.service(mail);
 
-        assertThat(mail.getAttribute(MailStore.DELIVERY_PATH_PREFIX + LOCAL_PART)).isEqualTo(expressMailboxNameWithSlash(NOT_SELECTED_MAILBOX.getName()));
+        assertThat(mail.getAttribute(ATTRIBUTE_NAME)).contains(ATTRIBUTE_NOT_SELECTED_MAILBOX);
     }
 
     @Test
@@ -589,7 +601,7 @@ public class SieveIntegrationTest {
         FakeMail mail = createMailWithSubjectAndHeaders("Default", new Header("Sender", "source@domain.org"));
         testee.service(mail);
 
-        assertThat(mail.getAttribute(MailStore.DELIVERY_PATH_PREFIX + LOCAL_PART)).isEqualTo(expressMailboxNameWithSlash(NOT_SELECTED_MAILBOX.getName()));
+        assertThat(mail.getAttribute(ATTRIBUTE_NAME)).contains(ATTRIBUTE_NOT_SELECTED_MAILBOX);
     }
 
     @Test
@@ -599,7 +611,7 @@ public class SieveIntegrationTest {
         FakeMail mail = createMailWithSubjectAndHeaders("Default", new Header("From", "source@domain.com"));
         testee.service(mail);
 
-        assertThat(mail.getAttribute(MailStore.DELIVERY_PATH_PREFIX + LOCAL_PART)).isEqualTo(expressMailboxNameWithSlash(NOT_SELECTED_MAILBOX.getName()));
+        assertThat(mail.getAttribute(ATTRIBUTE_NAME)).contains(ATTRIBUTE_NOT_SELECTED_MAILBOX);
     }
 
     @Test
@@ -609,7 +621,7 @@ public class SieveIntegrationTest {
         FakeMail mail = createMailWithSubjectAndHeaders("Default", new Header("Resend-From", "source@domain.com"));
         testee.service(mail);
 
-        assertThat(mail.getAttribute(MailStore.DELIVERY_PATH_PREFIX + LOCAL_PART)).isEqualTo(expressMailboxNameWithSlash(SELECTED_MAILBOX.getName()));
+        assertThat(mail.getAttribute(ATTRIBUTE_NAME)).contains(ATTRIBUTE_SELECTED_MAILBOX);
     }
 
     @Test
@@ -619,7 +631,7 @@ public class SieveIntegrationTest {
         FakeMail mail = createMailWithSubjectAndHeaders("Default", new Header("Resend-From", "source2@domain.com"));
         testee.service(mail);
 
-        assertThat(mail.getAttribute(MailStore.DELIVERY_PATH_PREFIX + LOCAL_PART)).isEqualTo(expressMailboxNameWithSlash(NOT_SELECTED_MAILBOX.getName()));
+        assertThat(mail.getAttribute(ATTRIBUTE_NAME)).contains(ATTRIBUTE_NOT_SELECTED_MAILBOX);
     }
 
     @Test
@@ -629,7 +641,7 @@ public class SieveIntegrationTest {
         FakeMail mail = createMailWithSubjectAndHeaders("Default", new Header("Resend-From", "source@domain.org"));
         testee.service(mail);
 
-        assertThat(mail.getAttribute(MailStore.DELIVERY_PATH_PREFIX + LOCAL_PART)).isEqualTo(expressMailboxNameWithSlash(NOT_SELECTED_MAILBOX.getName()));
+        assertThat(mail.getAttribute(ATTRIBUTE_NAME)).contains(ATTRIBUTE_NOT_SELECTED_MAILBOX);
     }
 
     @Test
@@ -639,7 +651,7 @@ public class SieveIntegrationTest {
         FakeMail mail = createMailWithSubjectAndHeaders("Default", new Header("To", "source@domain.com"));
         testee.service(mail);
 
-        assertThat(mail.getAttribute(MailStore.DELIVERY_PATH_PREFIX + LOCAL_PART)).isEqualTo(expressMailboxNameWithSlash(NOT_SELECTED_MAILBOX.getName()));
+        assertThat(mail.getAttribute(ATTRIBUTE_NAME)).contains(ATTRIBUTE_NOT_SELECTED_MAILBOX);
     }
 
     @Test
@@ -649,7 +661,7 @@ public class SieveIntegrationTest {
         FakeMail mail = createMailWithSubjectAndHeaders("Default", new Header("Resend-To", "source@domain.com"));
         testee.service(mail);
 
-        assertThat(mail.getAttribute(MailStore.DELIVERY_PATH_PREFIX + LOCAL_PART)).isEqualTo(expressMailboxNameWithSlash(SELECTED_MAILBOX.getName()));
+        assertThat(mail.getAttribute(ATTRIBUTE_NAME)).contains(ATTRIBUTE_SELECTED_MAILBOX);
     }
 
     @Test
@@ -659,7 +671,7 @@ public class SieveIntegrationTest {
         FakeMail mail = createMailWithSubjectAndHeaders("Default", new Header("Resend-To", "source2@domain.com"));
         testee.service(mail);
 
-        assertThat(mail.getAttribute(MailStore.DELIVERY_PATH_PREFIX + LOCAL_PART)).isEqualTo(expressMailboxNameWithSlash(NOT_SELECTED_MAILBOX.getName()));
+        assertThat(mail.getAttribute(ATTRIBUTE_NAME)).contains(ATTRIBUTE_NOT_SELECTED_MAILBOX);
     }
 
     @Test
@@ -669,7 +681,7 @@ public class SieveIntegrationTest {
         FakeMail mail = createMailWithSubjectAndHeaders("Default", new Header("Resend-To", "source@domain.org"));
         testee.service(mail);
 
-        assertThat(mail.getAttribute(MailStore.DELIVERY_PATH_PREFIX + LOCAL_PART)).isEqualTo(expressMailboxNameWithSlash(NOT_SELECTED_MAILBOX.getName()));
+        assertThat(mail.getAttribute(ATTRIBUTE_NAME)).contains(ATTRIBUTE_NOT_SELECTED_MAILBOX);
     }
 
     @Test
@@ -679,7 +691,7 @@ public class SieveIntegrationTest {
         FakeMail mail = createMailWithSubjectAndHeaders("Default", new Header("From", "source@domain.com"));
         testee.service(mail);
 
-        assertThat(mail.getAttribute(MailStore.DELIVERY_PATH_PREFIX + LOCAL_PART)).isEqualTo(expressMailboxNameWithSlash(SELECTED_MAILBOX.getName()));
+        assertThat(mail.getAttribute(ATTRIBUTE_NAME)).contains(ATTRIBUTE_SELECTED_MAILBOX);
     }
 
     @Test
@@ -689,7 +701,7 @@ public class SieveIntegrationTest {
         FakeMail mail = createMail();
         testee.service(mail);
 
-        assertThat(mail.getAttribute(MailStore.DELIVERY_PATH_PREFIX + LOCAL_PART)).isEqualTo(expressMailboxNameWithSlash(NOT_SELECTED_MAILBOX.getName()));
+        assertThat(mail.getAttribute(ATTRIBUTE_NAME)).contains(ATTRIBUTE_NOT_SELECTED_MAILBOX);
     }
 
     @Test
@@ -699,7 +711,7 @@ public class SieveIntegrationTest {
         FakeMail mail = createMail();
         testee.service(mail);
 
-        assertThat(mail.getAttribute(MailStore.DELIVERY_PATH_PREFIX + LOCAL_PART)).isEqualTo(expressMailboxNameWithSlash(SELECTED_MAILBOX.getName()));
+        assertThat(mail.getAttribute(ATTRIBUTE_NAME)).contains(ATTRIBUTE_SELECTED_MAILBOX);
     }
 
     @Test
@@ -709,7 +721,7 @@ public class SieveIntegrationTest {
         FakeMail mail = createMail();
         testee.service(mail);
 
-        assertThat(mail.getAttribute(MailStore.DELIVERY_PATH_PREFIX + LOCAL_PART)).isEqualTo(expressMailboxNameWithSlash(NOT_SELECTED_MAILBOX.getName()));
+        assertThat(mail.getAttribute(ATTRIBUTE_NAME)).contains(ATTRIBUTE_NOT_SELECTED_MAILBOX);
     }
 
     @Test
@@ -719,7 +731,7 @@ public class SieveIntegrationTest {
         FakeMail mail = createMail();
         testee.service(mail);
 
-        assertThat(mail.getAttribute(MailStore.DELIVERY_PATH_PREFIX + LOCAL_PART)).isEqualTo(expressMailboxNameWithSlash(NOT_SELECTED_MAILBOX.getName()));
+        assertThat(mail.getAttribute(ATTRIBUTE_NAME)).contains(ATTRIBUTE_NOT_SELECTED_MAILBOX);
     }
 
     @Test
@@ -729,7 +741,7 @@ public class SieveIntegrationTest {
         FakeMail mail = createMail();
         testee.service(mail);
 
-        assertThat(mail.getAttribute(MailStore.DELIVERY_PATH_PREFIX + LOCAL_PART)).isEqualTo(expressMailboxNameWithSlash(SELECTED_MAILBOX.getName()));
+        assertThat(mail.getAttribute(ATTRIBUTE_NAME)).contains(ATTRIBUTE_SELECTED_MAILBOX);
     }
 
     @Test
@@ -739,7 +751,7 @@ public class SieveIntegrationTest {
         FakeMail mail = createMail();
         testee.service(mail);
 
-        assertThat(mail.getAttribute(MailStore.DELIVERY_PATH_PREFIX + LOCAL_PART)).isEqualTo(expressMailboxNameWithSlash(SELECTED_MAILBOX.getName()));
+        assertThat(mail.getAttribute(ATTRIBUTE_NAME)).contains(ATTRIBUTE_SELECTED_MAILBOX);
     }
 
     @Test
@@ -749,7 +761,7 @@ public class SieveIntegrationTest {
         FakeMail mail = createMail();
         testee.service(mail);
 
-        assertThat(mail.getAttribute(MailStore.DELIVERY_PATH_PREFIX + LOCAL_PART)).isEqualTo(expressMailboxNameWithSlash(NOT_SELECTED_MAILBOX.getName()));
+        assertThat(mail.getAttribute(ATTRIBUTE_NAME)).contains(ATTRIBUTE_NOT_SELECTED_MAILBOX);
     }
 
     @Test
@@ -759,7 +771,7 @@ public class SieveIntegrationTest {
         FakeMail mail = createMail();
         testee.service(mail);
 
-        assertThat(mail.getAttribute(MailStore.DELIVERY_PATH_PREFIX + LOCAL_PART)).isEqualTo(expressMailboxNameWithSlash(NOT_SELECTED_MAILBOX.getName()));
+        assertThat(mail.getAttribute(ATTRIBUTE_NAME)).contains(ATTRIBUTE_NOT_SELECTED_MAILBOX);
     }
 
     @Test
@@ -769,7 +781,7 @@ public class SieveIntegrationTest {
         FakeMail mail = createMail();
         testee.service(mail);
 
-        assertThat(mail.getAttribute(MailStore.DELIVERY_PATH_PREFIX + LOCAL_PART)).isEqualTo(expressMailboxNameWithSlash(NOT_SELECTED_MAILBOX.getName()));
+        assertThat(mail.getAttribute(ATTRIBUTE_NAME)).contains(ATTRIBUTE_NOT_SELECTED_MAILBOX);
     }
 
     @Test
@@ -779,7 +791,7 @@ public class SieveIntegrationTest {
         FakeMail mail = createMail();
         testee.service(mail);
 
-        assertThat(mail.getAttribute(MailStore.DELIVERY_PATH_PREFIX + LOCAL_PART)).isEqualTo(expressMailboxNameWithSlash(SELECTED_MAILBOX.getName()));
+        assertThat(mail.getAttribute(ATTRIBUTE_NAME)).contains(ATTRIBUTE_SELECTED_MAILBOX);
     }
 
     @Test
@@ -796,7 +808,7 @@ public class SieveIntegrationTest {
             .fromMailet()
             .build());
         // No action taken
-        assertThat(mail.getAttribute(MailStore.DELIVERY_PATH_PREFIX + LOCAL_PART)).isNull();
+        assertThat(mail.getAttribute(ATTRIBUTE_NAME)).isEmpty();
     }
 
     @Test
@@ -806,7 +818,7 @@ public class SieveIntegrationTest {
         FakeMail mail = createMail();
         testee.service(mail);
 
-        assertThat(mail.getAttribute(MailStore.DELIVERY_PATH_PREFIX + LOCAL_PART)).isEqualTo(expressMailboxNameWithSlash(INBOX.getName()));
+        assertThat(mail.getAttribute(ATTRIBUTE_NAME)).contains(ATTRIBUTE_INBOX);
 
         FakeMailContext.SentMail expectedSentMail = FakeMailContext.sentMailBuilder()
             .sender(new MailAddress(RECEIVER_DOMAIN_COM))
@@ -824,7 +836,7 @@ public class SieveIntegrationTest {
 
         testee.service(mail);
 
-        assertThat(mail.getAttribute(MailStore.DELIVERY_PATH_PREFIX + LOCAL_PART)).isEqualTo(expressMailboxNameWithSlash(INBOX.getName()));
+        assertThat(mail.getAttribute(ATTRIBUTE_NAME)).contains(ATTRIBUTE_INBOX);
         assertThat(fakeMailContext.getSentMails()).isEmpty();
     }
 
@@ -835,7 +847,7 @@ public class SieveIntegrationTest {
         FakeMail mail = createMail();
         testee.service(mail);
 
-        assertThat(mail.getAttribute(MailStore.DELIVERY_PATH_PREFIX + LOCAL_PART)).isEqualTo(expressMailboxNameWithSlash(INBOX.getName()));
+        assertThat(mail.getAttribute(ATTRIBUTE_NAME)).contains(ATTRIBUTE_INBOX);
         assertThat(fakeMailContext.getSentMails()).isEmpty();
     }
 
@@ -846,7 +858,7 @@ public class SieveIntegrationTest {
         FakeMail mail = createMail();
         testee.service(mail);
 
-        assertThat(mail.getAttribute(MailStore.DELIVERY_PATH_PREFIX + LOCAL_PART)).isEqualTo(expressMailboxNameWithSlash(SELECTED_MAILBOX.getName()));
+        assertThat(mail.getAttribute(ATTRIBUTE_NAME)).contains(ATTRIBUTE_SELECTED_MAILBOX);
         assertThat(fakeMailContext.getSentMails()).isEmpty();
     }
 
@@ -857,7 +869,7 @@ public class SieveIntegrationTest {
         FakeMail mail = createMail();
         testee.service(mail);
 
-        assertThat(mail.getAttribute(MailStore.DELIVERY_PATH_PREFIX + LOCAL_PART)).isEqualTo(expressMailboxNameWithSlash(INBOX.getName()));
+        assertThat(mail.getAttribute(ATTRIBUTE_NAME)).contains(ATTRIBUTE_INBOX);
         assertThat(fakeMailContext.getSentMails()).isEmpty();
     }
 
@@ -868,7 +880,7 @@ public class SieveIntegrationTest {
         FakeMail mail = createMail();
         testee.service(mail);
 
-        assertThat(mail.getAttribute(MailStore.DELIVERY_PATH_PREFIX + LOCAL_PART)).isEqualTo(expressMailboxNameWithSlash(INBOX.getName()));
+        assertThat(mail.getAttribute(ATTRIBUTE_NAME)).contains(ATTRIBUTE_INBOX);
         FakeMailContext.SentMail expectedSentMail = FakeMailContext.sentMailBuilder()
             .sender(new MailAddress(RECEIVER_DOMAIN_COM))
             .recipient(new MailAddress("sender@any.com"))
@@ -884,7 +896,7 @@ public class SieveIntegrationTest {
         FakeMail mail = createMail();
         testee.service(mail);
 
-        assertThat(mail.getAttribute(MailStore.DELIVERY_PATH_PREFIX + LOCAL_PART)).isEqualTo(expressMailboxNameWithSlash(SELECTED_MAILBOX.getName()));
+        assertThat(mail.getAttribute(ATTRIBUTE_NAME)).contains(ATTRIBUTE_SELECTED_MAILBOX);
         FakeMailContext.SentMail expectedSentMail = FakeMailContext.sentMailBuilder()
             .sender(new MailAddress(RECEIVER_DOMAIN_COM))
             .recipient(new MailAddress("sender@any.com"))
@@ -900,7 +912,7 @@ public class SieveIntegrationTest {
         FakeMail mail = createMail();
         testee.service(mail);
 
-        assertThat(mail.getAttribute(MailStore.DELIVERY_PATH_PREFIX + LOCAL_PART)).isEqualTo(expressMailboxNameWithSlash(INBOX.getName()));
+        assertThat(mail.getAttribute(ATTRIBUTE_NAME)).contains(ATTRIBUTE_INBOX);
         FakeMailContext.SentMail expectedSentMail = FakeMailContext.sentMailBuilder()
             .sender(new MailAddress("benwa@apache.org"))
             .recipient(new MailAddress("sender@any.com"))
@@ -916,7 +928,7 @@ public class SieveIntegrationTest {
         FakeMail mail = createMail();
         testee.service(mail);
 
-        assertThat(mail.getAttribute(MailStore.DELIVERY_PATH_PREFIX + LOCAL_PART)).isEqualTo(expressMailboxNameWithSlash(INBOX.getName()));
+        assertThat(mail.getAttribute(ATTRIBUTE_NAME)).contains(ATTRIBUTE_INBOX);
         FakeMailContext.SentMail expectedSentMail = FakeMailContext.sentMailBuilder()
             .sender(new MailAddress(RECEIVER_DOMAIN_COM))
             .recipient(new MailAddress("sender@any.com"))
@@ -966,7 +978,7 @@ public class SieveIntegrationTest {
             .build();
     }
 
-    private String expressMailboxNameWithSlash(String name) {
+    private static String expressMailboxNameWithSlash(String name) {
         return '/' + name.replace('.', '/');
     }
 }
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
index d9f84fc..f7b5bd1 100644
--- 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
@@ -22,13 +22,11 @@ package org.apache.james.transport.mailets.remote.delivery;
 import static org.assertj.core.api.Assertions.assertThat;
 import static org.mockito.Mockito.mock;
 
-import java.io.Serializable;
 import java.util.Collection;
 import java.util.List;
 import java.util.Map;
 import java.util.Objects;
 
-import org.apache.commons.lang3.tuple.Pair;
 import org.apache.james.core.MailAddress;
 import org.apache.james.dnsservice.api.DNSService;
 import org.apache.james.domainlist.api.DomainList;
@@ -39,7 +37,8 @@ import org.apache.james.queue.api.ManageableMailQueue;
 import org.apache.james.queue.api.RawMailQueueItemDecoratorFactory;
 import org.apache.james.queue.memory.MemoryMailQueueFactory;
 import org.apache.james.transport.mailets.RemoteDelivery;
-import org.apache.james.util.streams.Iterators;
+import org.apache.mailet.Attribute;
+import org.apache.mailet.AttributeName;
 import org.apache.mailet.Mail;
 import org.apache.mailet.base.MailAddressFixture;
 import org.apache.mailet.base.test.FakeMail;
@@ -47,7 +46,6 @@ import org.apache.mailet.base.test.FakeMailetConfig;
 import org.junit.Before;
 import org.junit.Test;
 
-import com.github.steveash.guavate.Guavate;
 import com.google.common.collect.ImmutableList;
 import com.google.common.collect.ImmutableMap;
 
@@ -55,10 +53,7 @@ public class RemoteDeliveryTest {
 
     public static class MailProjection {
         public static MailProjection from(Mail mail) {
-            return new MailProjection(mail.getName(), mail.getRecipients(),
-                Iterators.toStream(mail.getAttributeNames())
-                    .map(name -> Pair.of(name, mail.getAttribute(name)))
-                    .collect(Guavate.toImmutableMap(Pair::getKey, Pair::getValue)));
+            return new MailProjection(mail.getName(), mail.getRecipients(), mail.attributesMap());
         }
 
         public static MailProjection from(ManageableMailQueue.MailQueueItemView item) {
@@ -67,9 +62,9 @@ public class RemoteDeliveryTest {
 
         private final String name;
         private final List<MailAddress> recipients;
-        private final Map<String, Serializable> attributes;
+        private final ImmutableMap<AttributeName, Attribute> attributes;
 
-        public MailProjection(String name, Collection<MailAddress> recipients, Map<String, Serializable> attributes) {
+        public MailProjection(String name, Collection<MailAddress> recipients, Map<AttributeName, Attribute> attributes) {
             this.name = name;
             this.recipients = ImmutableList.copyOf(recipients);
             this.attributes = ImmutableMap.copyOf(attributes);
diff --git a/server/mailrepository/mailrepository-cassandra/src/main/java/org/apache/james/mailrepository/cassandra/CassandraMailRepositoryMailDAO.java b/server/mailrepository/mailrepository-cassandra/src/main/java/org/apache/james/mailrepository/cassandra/CassandraMailRepositoryMailDAO.java
index 98b3bf8..6e83900 100644
--- a/server/mailrepository/mailrepository-cassandra/src/main/java/org/apache/james/mailrepository/cassandra/CassandraMailRepositoryMailDAO.java
+++ b/server/mailrepository/mailrepository-cassandra/src/main/java/org/apache/james/mailrepository/cassandra/CassandraMailRepositoryMailDAO.java
@@ -69,7 +69,9 @@ import org.apache.james.core.MaybeSender;
 import org.apache.james.mailrepository.api.MailKey;
 import org.apache.james.mailrepository.api.MailRepositoryUrl;
 import org.apache.james.server.core.MailImpl;
-import org.apache.james.util.streams.Iterators;
+import org.apache.mailet.Attribute;
+import org.apache.mailet.AttributeName;
+import org.apache.mailet.AttributeValue;
 import org.apache.mailet.Mail;
 import org.apache.mailet.PerRecipientHeaders;
 
@@ -208,11 +210,11 @@ public class CassandraMailRepositoryMailDAO implements CassandraMailRepositoryMa
             blobIdFactory.from(row.getString(BODY_BLOB_ID)));
     }
 
-    private Map<String, Serializable> toAttributes(Map<String, ByteBuffer> rowAttributes) {
+    private ImmutableList<Attribute> toAttributes(Map<String, ByteBuffer> rowAttributes) {
         return rowAttributes.entrySet()
             .stream()
-            .map(entry -> Pair.of(entry.getKey(), fromByteBuffer(entry.getValue())))
-            .collect(Guavate.toImmutableMap(Pair::getLeft, Pair::getRight));
+            .map(entry -> new Attribute(AttributeName.of(entry.getKey()), fromByteBuffer(entry.getValue())))
+            .collect(Guavate.toImmutableList());
     }
 
     private ImmutableList<String> asStringList(Collection<MailAddress> mailAddresses) {
@@ -220,10 +222,11 @@ public class CassandraMailRepositoryMailDAO implements CassandraMailRepositoryMa
     }
 
     private ImmutableMap<String, ByteBuffer> toRawAttributeMap(Mail mail) {
-        return Iterators.toStream(mail.getAttributeNames())
-            .map(name -> Pair.of(name, mail.getAttribute(name)))
-            .map(pair -> Pair.of(pair.getLeft(), toByteBuffer(pair.getRight())))
-            .collect(Guavate.toImmutableMap(Pair::getLeft, Pair::getRight));
+        return mail.attributes()
+            .map(attribute -> Pair.of(attribute.getName(), attribute.getValue()))
+            .collect(Guavate.toImmutableMap(
+                pair -> pair.getLeft().asString(),
+                pair -> toByteBuffer((Serializable) pair.getRight().value())));
     }
 
     private ImmutableMap<String, UDTValue> toHeaderMap(PerRecipientHeaders perRecipientHeaders) {
@@ -261,12 +264,12 @@ public class CassandraMailRepositoryMailDAO implements CassandraMailRepositoryMa
         }
     }
 
-    private Serializable fromByteBuffer(ByteBuffer byteBuffer) {
+    private AttributeValue<?> fromByteBuffer(ByteBuffer byteBuffer) {
         try {
             byte[] data = new byte[byteBuffer.remaining()];
             byteBuffer.get(data);
             ObjectInputStream objectInputStream = new ObjectInputStream(new ByteArrayInputStream(data));
-            return (Serializable) objectInputStream.readObject();
+            return AttributeValue.ofAny(objectInputStream.readObject());
         } catch (IOException | ClassNotFoundException e) {
             throw new RuntimeException(e);
         }
diff --git a/server/mailrepository/mailrepository-cassandra/src/test/java/org/apache/james/mailrepository/cassandra/CassandraMailRepositoryMailDAOTest.java b/server/mailrepository/mailrepository-cassandra/src/test/java/org/apache/james/mailrepository/cassandra/CassandraMailRepositoryMailDAOTest.java
index 7a48bcb..eebf29a 100644
--- a/server/mailrepository/mailrepository-cassandra/src/test/java/org/apache/james/mailrepository/cassandra/CassandraMailRepositoryMailDAOTest.java
+++ b/server/mailrepository/mailrepository-cassandra/src/test/java/org/apache/james/mailrepository/cassandra/CassandraMailRepositoryMailDAOTest.java
@@ -144,8 +144,8 @@ class CassandraMailRepositoryMailDAOTest {
             String remoteAddr = "remoteAddr";
             String remoteHost = "remoteHost";
             PerRecipientHeaders.Header header = PerRecipientHeaders.Header.builder().name("headerName").value("headerValue").build();
-            String attributeName = "att1";
             ImmutableList<String> attributeValue = ImmutableList.of("value1", "value2");
+            Attribute attribute = Attribute.convertToAttribute("att1", attributeValue);
 
             testee.store(URL,
                 FakeMail.builder()
@@ -157,7 +157,7 @@ class CassandraMailRepositoryMailDAOTest {
                     .remoteAddr(remoteAddr)
                     .remoteHost(remoteHost)
                     .addHeaderForRecipient(header, MailAddressFixture.RECIPIENT1)
-                    .attribute(attributeName, attributeValue)
+                    .attribute(attribute)
                     .build(),
                 blobIdHeader,
                 blobIdBody)
@@ -174,8 +174,8 @@ class CassandraMailRepositoryMailDAOTest {
                 softly.assertThat(partialMail.getState()).isEqualTo(state);
                 softly.assertThat(partialMail.getRemoteAddr()).isEqualTo(remoteAddr);
                 softly.assertThat(partialMail.getRemoteHost()).isEqualTo(remoteHost);
-                softly.assertThat(partialMail.getAttributeNames()).containsOnly(attributeName);
-                softly.assertThat(partialMail.getAttribute(attributeName)).isEqualTo(attributeValue);
+                softly.assertThat(partialMail.attributes()).containsOnly(attribute);
+                softly.assertThat(partialMail.getAttribute(attribute.getName())).contains(attribute);
                 softly.assertThat(partialMail.getPerRecipientSpecificHeaders().getRecipientsWithSpecificHeaders())
                     .containsOnly(MailAddressFixture.RECIPIENT1);
                 softly.assertThat(partialMail.getPerRecipientSpecificHeaders().getHeadersForRecipient(MailAddressFixture.RECIPIENT1))
diff --git a/server/protocols/webadmin/webadmin-mailrepository/src/main/java/org/apache/james/webadmin/dto/MailDto.java b/server/protocols/webadmin/webadmin-mailrepository/src/main/java/org/apache/james/webadmin/dto/MailDto.java
index 053a2bc..210979e 100644
--- a/server/protocols/webadmin/webadmin-mailrepository/src/main/java/org/apache/james/webadmin/dto/MailDto.java
+++ b/server/protocols/webadmin/webadmin-mailrepository/src/main/java/org/apache/james/webadmin/dto/MailDto.java
@@ -29,7 +29,6 @@ import java.util.List;
 import java.util.Objects;
 import java.util.Optional;
 import java.util.Set;
-import java.util.function.Function;
 
 import javax.mail.Header;
 import javax.mail.MessagingException;
@@ -41,7 +40,6 @@ import org.apache.james.mime4j.stream.MimeConfig;
 import org.apache.james.mime4j.util.MimeUtil;
 import org.apache.james.util.mime.MessageContentExtractor;
 import org.apache.james.util.mime.MessageContentExtractor.MessageContent;
-import org.apache.james.util.streams.Iterators;
 import org.apache.mailet.Mail;
 import org.apache.mailet.PerRecipientHeaders;
 
@@ -172,8 +170,10 @@ public class MailDto {
             return Optional.empty();
         }
 
-        return Optional.of(Iterators.toStream(mail.getAttributeNames())
-            .collect(Guavate.toImmutableMap(Function.identity(), attributeName -> mail.getAttribute(attributeName).toString())));
+        return Optional.of(mail.attributes()
+            .collect(Guavate.toImmutableMap(
+                attribute -> attribute.getName().asString(),
+                attribute -> attribute.getValue().value().toString())));
     }
 
     private final String name;
diff --git a/server/queue/queue-activemq/src/main/java/org/apache/james/queue/activemq/ActiveMQMailQueueItem.java b/server/queue/queue-activemq/src/main/java/org/apache/james/queue/activemq/ActiveMQMailQueueItem.java
index e9d0e98..297c613 100644
--- a/server/queue/queue-activemq/src/main/java/org/apache/james/queue/activemq/ActiveMQMailQueueItem.java
+++ b/server/queue/queue-activemq/src/main/java/org/apache/james/queue/activemq/ActiveMQMailQueueItem.java
@@ -52,7 +52,7 @@ public class ActiveMQMailQueueItem extends JMSMailQueueItem implements ActiveMQS
     public void done(boolean success) throws MailQueueException {
         super.done(success);
         if (success) {
-            if (message instanceof ActiveMQBlobMessage && getMail().getAttribute(JAMES_REUSE_BLOB_URL) == null) {
+            if (message instanceof ActiveMQBlobMessage && !getMail().getAttribute(JAMES_REUSE_BLOB_URL).isPresent()) {
 
                 // This should get removed once this jira issue was fixed
                 // https://issues.apache.org/activemq/browse/AMQ-1529
diff --git a/server/queue/queue-activemq/src/main/java/org/apache/james/queue/activemq/ActiveMQSupport.java b/server/queue/queue-activemq/src/main/java/org/apache/james/queue/activemq/ActiveMQSupport.java
index 8b9e4d2..56841fa 100644
--- a/server/queue/queue-activemq/src/main/java/org/apache/james/queue/activemq/ActiveMQSupport.java
+++ b/server/queue/queue-activemq/src/main/java/org/apache/james/queue/activemq/ActiveMQSupport.java
@@ -19,6 +19,7 @@
 package org.apache.james.queue.activemq;
 
 import org.apache.james.queue.jms.JMSSupport;
+import org.apache.mailet.AttributeName;
 
 /**
  * Interface which should get implemented by ActiveMQ depending implementions
@@ -38,6 +39,6 @@ public interface ActiveMQSupport extends JMSSupport {
     /**
      * Indicate that the Blobmessage content is reused for a new message
      */
-    String JAMES_REUSE_BLOB_URL = " JAMES_REUSE_BLOB_URL";
+    AttributeName JAMES_REUSE_BLOB_URL = AttributeName.of(" JAMES_REUSE_BLOB_URL");
 
 }
diff --git a/server/queue/queue-api/src/test/java/org/apache/james/queue/api/MailQueueContract.java b/server/queue/queue-api/src/test/java/org/apache/james/queue/api/MailQueueContract.java
index be3029d..d6a3ec5 100644
--- a/server/queue/queue-api/src/test/java/org/apache/james/queue/api/MailQueueContract.java
+++ b/server/queue/queue-api/src/test/java/org/apache/james/queue/api/MailQueueContract.java
@@ -45,6 +45,7 @@ import org.apache.james.core.MaybeSender;
 import org.apache.james.core.builder.MimeMessageBuilder;
 import org.apache.james.junit.ExecutorExtension;
 import org.apache.james.util.concurrency.ConcurrentTestRunner;
+import org.apache.mailet.Attribute;
 import org.apache.mailet.Mail;
 import org.apache.mailet.PerRecipientHeaders;
 import org.apache.mailet.base.test.FakeMail;
diff --git a/server/queue/queue-api/src/test/java/org/apache/james/queue/api/ManageableMailQueueContract.java b/server/queue/queue-api/src/test/java/org/apache/james/queue/api/ManageableMailQueueContract.java
index 5c76b10..0f7b019 100644
--- a/server/queue/queue-api/src/test/java/org/apache/james/queue/api/ManageableMailQueueContract.java
+++ b/server/queue/queue-api/src/test/java/org/apache/james/queue/api/ManageableMailQueueContract.java
@@ -459,20 +459,21 @@ public interface ManageableMailQueueContract extends MailQueueContract {
 
     @Test
     default void browseShouldReturnMailsWithAttributes() throws Exception {
+        Attribute attribute1 = Attribute.convertToAttribute("Attribute Name 1", "Attribute Value 1");
+        Attribute attribute2 = Attribute.convertToAttribute("Attribute Name 2", "Attribute Value 2");
+
         ManageableMailQueue mailQueue = getManageableMailQueue();
         mailQueue.enQueue(defaultMail()
-            .attributes(ImmutableList.of(
-                Attribute.convertToAttribute("Attribute Name 1", "Attribute Value 1"),
-                Attribute.convertToAttribute("Attribute Name 2", "Attribute Value 2")))
+            .attributes(ImmutableList.of(attribute1, attribute2))
             .name("mail with blob")
             .build());
 
         Mail mail = mailQueue.browse().next().getMail();
-        assertSoftly(softly ->  {
-            softly.assertThat(mail.getAttribute("Attribute Name 1"))
-                .isEqualTo("Attribute Value 1");
-            softly.assertThat(mail.getAttribute("Attribute Name 2"))
-                .isEqualTo("Attribute Value 2");
+        assertSoftly(softly -> {
+            softly.assertThat(mail.getAttribute(attribute1.getName()))
+                .contains(attribute1);
+            softly.assertThat(mail.getAttribute(attribute2.getName()))
+                .contains(attribute2);
         });
     }
 
diff --git a/server/queue/queue-jms/src/main/java/org/apache/james/queue/jms/JMSMailQueue.java b/server/queue/queue-jms/src/main/java/org/apache/james/queue/jms/JMSMailQueue.java
index 07b3128..a863479 100644
--- a/server/queue/queue-jms/src/main/java/org/apache/james/queue/jms/JMSMailQueue.java
+++ b/server/queue/queue-jms/src/main/java/org/apache/james/queue/jms/JMSMailQueue.java
@@ -20,6 +20,7 @@ package org.apache.james.queue.jms;
 
 import java.io.ByteArrayOutputStream;
 import java.io.IOException;
+import java.io.Serializable;
 import java.time.Instant;
 import java.time.ZoneId;
 import java.time.ZonedDateTime;
@@ -65,6 +66,7 @@ import org.apache.james.queue.api.ManageableMailQueue;
 import org.apache.james.server.core.MailImpl;
 import org.apache.james.server.core.MimeMessageCopyOnWriteProxy;
 import org.apache.james.util.SerializationUtil;
+import org.apache.mailet.AttributeName;
 import org.apache.mailet.Mail;
 import org.apache.mailet.PerRecipientHeaders;
 import org.slf4j.Logger;
@@ -72,8 +74,10 @@ import org.slf4j.LoggerFactory;
 import org.threeten.extra.Temporals;
 
 import com.github.fge.lambdas.Throwing;
+import com.github.steveash.guavate.Guavate;
 import com.google.common.base.Joiner;
 import com.google.common.base.Splitter;
+import com.google.common.collect.ImmutableList;
 import com.google.common.collect.Iterators;
 
 /**
@@ -336,10 +340,16 @@ public class JMSMailQueue implements ManageableMailQueue, JMSSupport, MailPriori
 
         String sender = mail.getMaybeSender().asString("");
 
-        org.apache.james.util.streams.Iterators.toStream(mail.getAttributeNames())
-                .forEach(attrName -> props.put(attrName, SerializationUtil.serialize(mail.getAttribute(attrName))));
+        props.putAll(mail.attributes()
+            .collect(Guavate.toImmutableMap(
+                attribute -> attribute.getName().asString(),
+                attribute -> SerializationUtil.serialize((Serializable) attribute.getValue().value()))));
 
-        props.put(JAMES_MAIL_ATTRIBUTE_NAMES, joiner.join(mail.getAttributeNames()));
+        ImmutableList<String> attributeNames = mail.attributeNames()
+            .map(AttributeName::asString)
+            .collect(Guavate.toImmutableList());
+
+        props.put(JAMES_MAIL_ATTRIBUTE_NAMES, joiner.join(attributeNames));
         props.put(JAMES_MAIL_SENDER, sender);
         props.put(JAMES_MAIL_STATE, mail.getState());
 
diff --git a/server/queue/queue-jms/src/main/java/org/apache/james/queue/library/MailQueueManagement.java b/server/queue/queue-jms/src/main/java/org/apache/james/queue/library/MailQueueManagement.java
index 3d32cd6..6b42d6b 100644
--- a/server/queue/queue-jms/src/main/java/org/apache/james/queue/library/MailQueueManagement.java
+++ b/server/queue/queue-jms/src/main/java/org/apache/james/queue/library/MailQueueManagement.java
@@ -18,7 +18,6 @@
  ****************************************************************/
 package org.apache.james.queue.library;
 
-import java.io.Serializable;
 import java.time.ZonedDateTime;
 import java.util.ArrayList;
 import java.util.Collection;
@@ -45,6 +44,8 @@ import org.apache.james.queue.api.ManageableMailQueue.MailQueueIterator;
 import org.apache.james.queue.api.ManageableMailQueue.Type;
 import org.apache.mailet.Mail;
 
+import com.github.steveash.guavate.Guavate;
+
 /**
  * JMX MBean implementation which expose management functions by wrapping a
  * {@link ManageableMailQueue}
@@ -148,17 +149,11 @@ public class MailQueueManagement extends StandardMBean implements MailQueueManag
             map.put(names[6], m.getRemoteAddr());
             map.put(names[7], m.getRemoteHost());
             map.put(names[8], m.getErrorMessage());
-            Map<String, String> attrs = new HashMap<>();
-            Iterator<String> attrNames = m.getAttributeNames();
-            while (attrNames.hasNext()) {
-                String attrName = attrNames.next();
-                String attrValueString = null;
-                Serializable attrValue = m.getAttribute(attrName);
-                if (attrValue != null) {
-                    attrValueString = attrValue.toString();
-                }
-                attrs.put(attrName, attrValueString);
-            }
+            Map<String, String> attrs = m.attributes()
+                .collect(Guavate.toImmutableMap(
+                    attribute -> attribute.getName().asString(),
+                    attribute -> attribute.getValue().value().toString()));
+
             map.put(names[9], attrs.toString());
             map.put(names[10], nextDelivery);
             CompositeDataSupport c = new CompositeDataSupport(new CompositeType(Mail.class.getName(), "Queue Mail", names, descs, types), map);


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


[james-project] 05/07: JAMES-2579 Revise openjpa version in guice jpa doc

Posted by ro...@apache.org.
This is an automated email from the ASF dual-hosted git repository.

rouazana pushed a commit to branch master
in repository https://gitbox.apache.org/repos/asf/james-project.git

commit 27d071fa59651ce886e5f7f93cae27d6433d3921
Author: tran tien duc <dt...@linagora.com>
AuthorDate: Fri Jan 25 11:49:43 2019 +0700

    JAMES-2579 Revise openjpa version in guice jpa doc
---
 src/site/markdown/server/install/guice-jpa.md | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/src/site/markdown/server/install/guice-jpa.md b/src/site/markdown/server/install/guice-jpa.md
index 6e5d71d..836a0d2 100644
--- a/src/site/markdown/server/install/guice-jpa.md
+++ b/src/site/markdown/server/install/guice-jpa.md
@@ -47,7 +47,7 @@ Once everything is set up, you just have to run the jar with:
 
 ```bash
 $ java -classpath 'james-server-jpa-guice.jar:james-server-jpa-guice.lib/*' \
-    -javaagent:james-server-jpa-guice.lib/openjpa-2.4.2.jar \
+    -javaagent:james-server-jpa-guice.lib/openjpa-3.0.0.jar \
     -Dlogback.configurationFile=conf/logback.xml \
     -Dworking.directory=. \
     org.apache.james.JPAJamesServerMain


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


[james-project] 04/07: JAMES-2630 Add CassandraAsyncExecutor.executeRows

Posted by ro...@apache.org.
This is an automated email from the ASF dual-hosted git repository.

rouazana pushed a commit to branch master
in repository https://gitbox.apache.org/repos/asf/james-project.git

commit 04efa195d5bdf3e12feaa4c33e9369e4d8d6621b
Author: Gautier DI FOLCO <gd...@linagora.com>
AuthorDate: Thu Feb 14 13:32:04 2019 +0100

    JAMES-2630 Add CassandraAsyncExecutor.executeRows
---
 .../cassandra/utils/CassandraAsyncExecutor.java    |  6 +++
 .../versions/CassandraSchemaVersionDAO.java        |  4 +-
 .../eventstore/cassandra/EventStoreDao.java        |  4 +-
 .../cassandra/mail/CassandraAttachmentDAO.java     |  3 +-
 .../mail/CassandraAttachmentMessageIdDAO.java      |  3 +-
 .../mail/CassandraAttachmentOwnerDAO.java          |  3 +-
 .../mail/CassandraMailboxPathDAOImpl.java          |  3 +-
 .../cassandra/mail/CassandraMessageDAO.java        |  3 +-
 .../cassandra/mail/CassandraMessageIdDAO.java      | 48 +++++++++++-----------
 .../cassandra/mail/CassandraMessageIdDAOTest.java  |  8 +++-
 .../domainlist/cassandra/CassandraDomainList.java  |  4 +-
 .../james/mailrepository/cassandra/UrlsDao.java    |  3 +-
 .../rrt/cassandra/CassandraMappingsSourcesDAO.java |  3 +-
 .../CassandraRecipientRewriteTableDAO.java         |  3 +-
 .../james/sieve/cassandra/CassandraSieveDAO.java   |  3 +-
 .../user/cassandra/CassandraUsersRepository.java   |  4 +-
 .../view/cassandra/CassandraMailQueueBrowser.java  |  6 +--
 .../rabbitmq/view/cassandra/EnqueuedMailsDAO.java  |  3 +-
 18 files changed, 52 insertions(+), 62 deletions(-)

diff --git a/backends-common/cassandra/src/main/java/org/apache/james/backends/cassandra/utils/CassandraAsyncExecutor.java b/backends-common/cassandra/src/main/java/org/apache/james/backends/cassandra/utils/CassandraAsyncExecutor.java
index c1b86e2..6e19b60 100644
--- a/backends-common/cassandra/src/main/java/org/apache/james/backends/cassandra/utils/CassandraAsyncExecutor.java
+++ b/backends-common/cassandra/src/main/java/org/apache/james/backends/cassandra/utils/CassandraAsyncExecutor.java
@@ -28,6 +28,7 @@ import com.datastax.driver.core.Row;
 import com.datastax.driver.core.Session;
 import com.datastax.driver.core.Statement;
 import net.javacrumbs.futureconverter.java8guava.FutureConverter;
+import reactor.core.publisher.Flux;
 import reactor.core.publisher.Mono;
 import reactor.core.scheduler.Schedulers;
 
@@ -61,6 +62,11 @@ public class CassandraAsyncExecutor {
                 .flatMap(Mono::justOrEmpty);
     }
 
+    public Flux<Row> executeRows(Statement statement) {
+        return execute(statement)
+            .flatMapMany(Flux::fromIterable);
+    }
+
     public Mono<Optional<Row>> executeSingleRowOptional(Statement statement) {
         return execute(statement)
             .map(resultSet -> Optional.ofNullable(resultSet.one()));
diff --git a/backends-common/cassandra/src/main/java/org/apache/james/backends/cassandra/versions/CassandraSchemaVersionDAO.java b/backends-common/cassandra/src/main/java/org/apache/james/backends/cassandra/versions/CassandraSchemaVersionDAO.java
index 6d1ed10..6d958a7 100644
--- a/backends-common/cassandra/src/main/java/org/apache/james/backends/cassandra/versions/CassandraSchemaVersionDAO.java
+++ b/backends-common/cassandra/src/main/java/org/apache/james/backends/cassandra/versions/CassandraSchemaVersionDAO.java
@@ -36,7 +36,6 @@ import org.apache.james.backends.cassandra.versions.table.CassandraSchemaVersion
 import com.datastax.driver.core.PreparedStatement;
 import com.datastax.driver.core.Session;
 import com.datastax.driver.core.utils.UUIDs;
-import reactor.core.publisher.Flux;
 import reactor.core.publisher.Mono;
 
 public class CassandraSchemaVersionDAO {
@@ -65,8 +64,7 @@ public class CassandraSchemaVersionDAO {
     }
 
     public Mono<Optional<SchemaVersion>> getCurrentSchemaVersion() {
-        return cassandraAsyncExecutor.execute(readVersionStatement.bind())
-            .flatMapMany(Flux::fromIterable)
+        return cassandraAsyncExecutor.executeRows(readVersionStatement.bind())
             .map(row -> row.getInt(VALUE))
             .reduce(Math::max)
             .map(SchemaVersion::new)
diff --git a/event-sourcing/event-store-cassandra/src/main/java/org/apache/james/eventsourcing/eventstore/cassandra/EventStoreDao.java b/event-sourcing/event-store-cassandra/src/main/java/org/apache/james/eventsourcing/eventstore/cassandra/EventStoreDao.java
index 226d7b5..d99c15a 100644
--- a/event-sourcing/event-store-cassandra/src/main/java/org/apache/james/eventsourcing/eventstore/cassandra/EventStoreDao.java
+++ b/event-sourcing/event-store-cassandra/src/main/java/org/apache/james/eventsourcing/eventstore/cassandra/EventStoreDao.java
@@ -45,7 +45,6 @@ import com.datastax.driver.core.PreparedStatement;
 import com.datastax.driver.core.Row;
 import com.datastax.driver.core.Session;
 import com.fasterxml.jackson.core.JsonProcessingException;
-import reactor.core.publisher.Flux;
 import reactor.core.publisher.Mono;
 
 public class EventStoreDao {
@@ -97,10 +96,9 @@ public class EventStoreDao {
     }
 
     public History getEventsOfAggregate(AggregateId aggregateId) {
-        return cassandraAsyncExecutor.execute(
+        return cassandraAsyncExecutor.executeRows(
                 select.bind()
                     .setString(AGGREGATE_ID, aggregateId.asAggregateKey()))
-            .flatMapMany(Flux::fromIterable)
             .map(this::toEvent)
             .collectList()
             .map(History::of)
diff --git a/mailbox/cassandra/src/main/java/org/apache/james/mailbox/cassandra/mail/CassandraAttachmentDAO.java b/mailbox/cassandra/src/main/java/org/apache/james/mailbox/cassandra/mail/CassandraAttachmentDAO.java
index b5f8ec7..f7cdcf6 100644
--- a/mailbox/cassandra/src/main/java/org/apache/james/mailbox/cassandra/mail/CassandraAttachmentDAO.java
+++ b/mailbox/cassandra/src/main/java/org/apache/james/mailbox/cassandra/mail/CassandraAttachmentDAO.java
@@ -107,11 +107,10 @@ public class CassandraAttachmentDAO {
     }
 
     public Flux<Attachment> retrieveAll() {
-        return cassandraAsyncExecutor.execute(
+        return cassandraAsyncExecutor.executeRows(
                 selectAllStatement.bind()
                     .setReadTimeoutMillis(configuration.getAttachmentV2MigrationReadTimeout())
                     .setFetchSize(1))
-            .flatMapMany(Flux::fromIterable)
             .map(this::attachment);
     }
 
diff --git a/mailbox/cassandra/src/main/java/org/apache/james/mailbox/cassandra/mail/CassandraAttachmentMessageIdDAO.java b/mailbox/cassandra/src/main/java/org/apache/james/mailbox/cassandra/mail/CassandraAttachmentMessageIdDAO.java
index c10509f..46d664c 100644
--- a/mailbox/cassandra/src/main/java/org/apache/james/mailbox/cassandra/mail/CassandraAttachmentMessageIdDAO.java
+++ b/mailbox/cassandra/src/main/java/org/apache/james/mailbox/cassandra/mail/CassandraAttachmentMessageIdDAO.java
@@ -74,10 +74,9 @@ public class CassandraAttachmentMessageIdDAO {
 
     public Flux<MessageId> getOwnerMessageIds(AttachmentId attachmentId) {
         Preconditions.checkArgument(attachmentId != null);
-        return cassandraAsyncExecutor.execute(
+        return cassandraAsyncExecutor.executeRows(
                 selectStatement.bind()
                     .setUUID(ATTACHMENT_ID_AS_UUID, attachmentId.asUUID()))
-            .flatMapMany(Flux::fromIterable)
             .map(this::rowToMessageId);
     }
 
diff --git a/mailbox/cassandra/src/main/java/org/apache/james/mailbox/cassandra/mail/CassandraAttachmentOwnerDAO.java b/mailbox/cassandra/src/main/java/org/apache/james/mailbox/cassandra/mail/CassandraAttachmentOwnerDAO.java
index d3c6b65..d994881 100644
--- a/mailbox/cassandra/src/main/java/org/apache/james/mailbox/cassandra/mail/CassandraAttachmentOwnerDAO.java
+++ b/mailbox/cassandra/src/main/java/org/apache/james/mailbox/cassandra/mail/CassandraAttachmentOwnerDAO.java
@@ -76,10 +76,9 @@ public class CassandraAttachmentOwnerDAO {
     }
 
     public Flux<Username> retrieveOwners(AttachmentId attachmentId) {
-        return executor.execute(
+        return executor.executeRows(
                 selectStatement.bind()
                     .setUUID(ID, attachmentId.asUUID()))
-            .flatMapMany(Flux::fromIterable)
             .map(this::toOwner);
     }
 
diff --git a/mailbox/cassandra/src/main/java/org/apache/james/mailbox/cassandra/mail/CassandraMailboxPathDAOImpl.java b/mailbox/cassandra/src/main/java/org/apache/james/mailbox/cassandra/mail/CassandraMailboxPathDAOImpl.java
index aae4c7e..99de81b 100644
--- a/mailbox/cassandra/src/main/java/org/apache/james/mailbox/cassandra/mail/CassandraMailboxPathDAOImpl.java
+++ b/mailbox/cassandra/src/main/java/org/apache/james/mailbox/cassandra/mail/CassandraMailboxPathDAOImpl.java
@@ -200,8 +200,7 @@ public class CassandraMailboxPathDAOImpl implements CassandraMailboxPathDAO {
     }
 
     public Flux<CassandraIdAndPath> readAll() {
-        return cassandraAsyncExecutor.execute(selectAll.bind())
-            .flatMapMany(Flux::fromIterable)
+        return cassandraAsyncExecutor.executeRows(selectAll.bind())
             .map(this::fromRowToCassandraIdAndPath);
     }
 
diff --git a/mailbox/cassandra/src/main/java/org/apache/james/mailbox/cassandra/mail/CassandraMessageDAO.java b/mailbox/cassandra/src/main/java/org/apache/james/mailbox/cassandra/mail/CassandraMessageDAO.java
index beab767..6bb6e24 100644
--- a/mailbox/cassandra/src/main/java/org/apache/james/mailbox/cassandra/mail/CassandraMessageDAO.java
+++ b/mailbox/cassandra/src/main/java/org/apache/james/mailbox/cassandra/mail/CassandraMessageDAO.java
@@ -399,10 +399,9 @@ public class CassandraMessageDAO {
     }
 
     public Flux<MessageIdAttachmentIds> retrieveAllMessageIdAttachmentIds() {
-        return cassandraAsyncExecutor.execute(
+        return cassandraAsyncExecutor.executeRows(
             selectAllMessagesWithAttachment.bind()
                 .setReadTimeoutMillis(configuration.getMessageAttachmentIdsReadTimeout()))
-            .flatMapMany(Flux::fromIterable)
             .map(this::fromRow)
             .filter(MessageIdAttachmentIds::hasAttachment);
     }
diff --git a/mailbox/cassandra/src/main/java/org/apache/james/mailbox/cassandra/mail/CassandraMessageIdDAO.java b/mailbox/cassandra/src/main/java/org/apache/james/mailbox/cassandra/mail/CassandraMessageIdDAO.java
index 9bfcd4e..e7cafbe 100644
--- a/mailbox/cassandra/src/main/java/org/apache/james/mailbox/cassandra/mail/CassandraMessageIdDAO.java
+++ b/mailbox/cassandra/src/main/java/org/apache/james/mailbox/cassandra/mail/CassandraMessageIdDAO.java
@@ -59,7 +59,6 @@ import org.apache.james.mailbox.model.ComposedMessageIdWithMetaData;
 import org.apache.james.mailbox.model.MessageRange;
 
 import com.datastax.driver.core.PreparedStatement;
-import com.datastax.driver.core.ResultSet;
 import com.datastax.driver.core.Row;
 import com.datastax.driver.core.Session;
 import com.datastax.driver.core.querybuilder.QueryBuilder;
@@ -211,60 +210,59 @@ public class CassandraMessageIdDAO {
     }
 
     public Mono<Optional<ComposedMessageIdWithMetaData>> retrieve(CassandraId mailboxId, MessageUid uid) {
-        return selectOneRow(mailboxId, uid).map(this::asOptionalOfCassandraMessageId);
+        return asOptionalOfCassandraMessageId(selectOneRow(mailboxId, uid));
     }
 
-    private Optional<ComposedMessageIdWithMetaData> asOptionalOfCassandraMessageId(ResultSet resultSet) {
-        if (resultSet.isExhausted()) {
-            return Optional.empty();
-        }
-        return Optional.of(fromRowToComposedMessageIdWithFlags(resultSet.one()));
+    private Mono<Optional<ComposedMessageIdWithMetaData>> asOptionalOfCassandraMessageId(Mono<Row> row) {
+        return row
+                .map(this::fromRowToComposedMessageIdWithFlags)
+                .map(Optional::of)
+                .switchIfEmpty(Mono.just(Optional.empty()));
     }
 
-    private Mono<ResultSet> selectOneRow(CassandraId mailboxId, MessageUid uid) {
-        return cassandraAsyncExecutor.execute(select.bind()
+    private Mono<Row> selectOneRow(CassandraId mailboxId, MessageUid uid) {
+        return cassandraAsyncExecutor.executeSingleRow(select.bind()
                 .setUUID(MAILBOX_ID, mailboxId.asUuid())
                 .setLong(IMAP_UID, uid.asLong()));
     }
 
     public Flux<ComposedMessageIdWithMetaData> retrieveMessages(CassandraId mailboxId, MessageRange set) {
+        return retrieveRows(mailboxId, set)
+            .map(this::fromRowToComposedMessageIdWithFlags);
+    }
+
+    private Flux<Row> retrieveRows(CassandraId mailboxId, MessageRange set) {
         switch (set.getType()) {
         case ALL:
-            return toMessageIds(selectAll(mailboxId));
+            return selectAll(mailboxId);
         case FROM:
-            return toMessageIds(selectFrom(mailboxId, set.getUidFrom()));
+            return selectFrom(mailboxId, set.getUidFrom());
         case RANGE:
-            return toMessageIds(selectRange(mailboxId, set.getUidFrom(), set.getUidTo()));
+            return selectRange(mailboxId, set.getUidFrom(), set.getUidTo());
         case ONE:
-            return toMessageIds(selectOneRow(mailboxId, set.getUidFrom()));
+            return Flux.concat(selectOneRow(mailboxId, set.getUidFrom()));
         }
         throw new UnsupportedOperationException();
     }
 
-    private Mono<ResultSet> selectAll(CassandraId mailboxId) {
-        return cassandraAsyncExecutor.execute(selectAllUids.bind()
+    private Flux<Row> selectAll(CassandraId mailboxId) {
+        return cassandraAsyncExecutor.executeRows(selectAllUids.bind()
                 .setUUID(MAILBOX_ID, mailboxId.asUuid()));
     }
 
-    private Mono<ResultSet> selectFrom(CassandraId mailboxId, MessageUid uid) {
-        return cassandraAsyncExecutor.execute(selectUidGte.bind()
+    private Flux<Row> selectFrom(CassandraId mailboxId, MessageUid uid) {
+        return cassandraAsyncExecutor.executeRows(selectUidGte.bind()
                 .setUUID(MAILBOX_ID, mailboxId.asUuid())
                 .setLong(IMAP_UID, uid.asLong()));
     }
 
-    private Mono<ResultSet> selectRange(CassandraId mailboxId, MessageUid from, MessageUid to) {
-        return cassandraAsyncExecutor.execute(selectUidRange.bind()
+    private Flux<Row> selectRange(CassandraId mailboxId, MessageUid from, MessageUid to) {
+        return cassandraAsyncExecutor.executeRows(selectUidRange.bind()
                 .setUUID(MAILBOX_ID, mailboxId.asUuid())
                 .setLong(IMAP_UID_GTE, from.asLong())
                 .setLong(IMAP_UID_LTE, to.asLong()));
     }
 
-    private Flux<ComposedMessageIdWithMetaData> toMessageIds(Mono<ResultSet> results) {
-        return results
-            .flatMapMany(Flux::fromIterable)
-            .map(this::fromRowToComposedMessageIdWithFlags);
-    }
-
     private ComposedMessageIdWithMetaData fromRowToComposedMessageIdWithFlags(Row row) {
         return ComposedMessageIdWithMetaData.builder()
                 .composedMessageId(new ComposedMessageId(
diff --git a/mailbox/cassandra/src/test/java/org/apache/james/mailbox/cassandra/mail/CassandraMessageIdDAOTest.java b/mailbox/cassandra/src/test/java/org/apache/james/mailbox/cassandra/mail/CassandraMessageIdDAOTest.java
index 588a634..c81fbf8 100644
--- a/mailbox/cassandra/src/test/java/org/apache/james/mailbox/cassandra/mail/CassandraMessageIdDAOTest.java
+++ b/mailbox/cassandra/src/test/java/org/apache/james/mailbox/cassandra/mail/CassandraMessageIdDAOTest.java
@@ -27,6 +27,8 @@ import javax.mail.Flags.Flag;
 
 import org.apache.james.backends.cassandra.CassandraCluster;
 import org.apache.james.backends.cassandra.CassandraClusterExtension;
+import org.apache.james.backends.cassandra.components.CassandraModule;
+import org.apache.james.backends.cassandra.versions.CassandraSchemaVersionModule;
 import org.apache.james.mailbox.MessageUid;
 import org.apache.james.mailbox.cassandra.ids.CassandraId;
 import org.apache.james.mailbox.cassandra.ids.CassandraMessageId;
@@ -41,8 +43,12 @@ import org.junit.jupiter.api.extension.RegisterExtension;
 import reactor.core.publisher.Flux;
 
 class CassandraMessageIdDAOTest {
+    public static final CassandraModule MODULE = CassandraModule.aggregateModules(
+        CassandraMessageModule.MODULE,
+        CassandraSchemaVersionModule.MODULE);
+
     @RegisterExtension
-    static CassandraClusterExtension cassandraCluster = new CassandraClusterExtension(CassandraMessageModule.MODULE);
+    static CassandraClusterExtension cassandraCluster = new CassandraClusterExtension(MODULE);
 
     private CassandraMessageId.Factory messageIdFactory;
     private CassandraMessageIdDAO testee;
diff --git a/server/data/data-cassandra/src/main/java/org/apache/james/domainlist/cassandra/CassandraDomainList.java b/server/data/data-cassandra/src/main/java/org/apache/james/domainlist/cassandra/CassandraDomainList.java
index 1766aeb..4014e39 100644
--- a/server/data/data-cassandra/src/main/java/org/apache/james/domainlist/cassandra/CassandraDomainList.java
+++ b/server/data/data-cassandra/src/main/java/org/apache/james/domainlist/cassandra/CassandraDomainList.java
@@ -39,7 +39,6 @@ import org.apache.james.domainlist.lib.AbstractDomainList;
 
 import com.datastax.driver.core.PreparedStatement;
 import com.datastax.driver.core.Session;
-import reactor.core.publisher.Flux;
 
 public class CassandraDomainList extends AbstractDomainList {
     private final CassandraAsyncExecutor executor;
@@ -84,8 +83,7 @@ public class CassandraDomainList extends AbstractDomainList {
 
     @Override
     protected List<Domain> getDomainListInternal() throws DomainListException {
-        return executor.execute(readAllStatement.bind())
-            .flatMapMany(Flux::fromIterable)
+        return executor.executeRows(readAllStatement.bind())
             .map(row -> Domain.of(row.getString(DOMAIN)))
             .collectList()
             .block();
diff --git a/server/data/data-cassandra/src/main/java/org/apache/james/mailrepository/cassandra/UrlsDao.java b/server/data/data-cassandra/src/main/java/org/apache/james/mailrepository/cassandra/UrlsDao.java
index 4421e49..ac72216 100644
--- a/server/data/data-cassandra/src/main/java/org/apache/james/mailrepository/cassandra/UrlsDao.java
+++ b/server/data/data-cassandra/src/main/java/org/apache/james/mailrepository/cassandra/UrlsDao.java
@@ -84,8 +84,7 @@ public class UrlsDao {
     }
 
     public Flux<MailRepositoryUrl> retrieveUsedUrls() {
-        return executor.execute(selectAll.bind())
-            .flatMapMany(Flux::fromIterable)
+        return executor.executeRows(selectAll.bind())
             .map(this::toUrl);
     }
 
diff --git a/server/data/data-cassandra/src/main/java/org/apache/james/rrt/cassandra/CassandraMappingsSourcesDAO.java b/server/data/data-cassandra/src/main/java/org/apache/james/rrt/cassandra/CassandraMappingsSourcesDAO.java
index 21a81e3..1002b1f 100644
--- a/server/data/data-cassandra/src/main/java/org/apache/james/rrt/cassandra/CassandraMappingsSourcesDAO.java
+++ b/server/data/data-cassandra/src/main/java/org/apache/james/rrt/cassandra/CassandraMappingsSourcesDAO.java
@@ -99,10 +99,9 @@ public class CassandraMappingsSourcesDAO {
     }
 
     public Flux<MappingSource> retrieveSources(Mapping mapping) {
-        return executor.execute(retrieveSourcesStatement.bind()
+        return executor.executeRows(retrieveSourcesStatement.bind()
             .setString(MAPPING_TYPE, mapping.getType().asPrefix())
             .setString(MAPPING_VALUE, mapping.getMappingValue()))
-            .flatMapMany(Flux::fromIterable)
             .map(row -> MappingSource.parse(row.getString(SOURCE)));
     }
 
diff --git a/server/data/data-cassandra/src/main/java/org/apache/james/rrt/cassandra/CassandraRecipientRewriteTableDAO.java b/server/data/data-cassandra/src/main/java/org/apache/james/rrt/cassandra/CassandraRecipientRewriteTableDAO.java
index 6c1078e..72eaf48 100644
--- a/server/data/data-cassandra/src/main/java/org/apache/james/rrt/cassandra/CassandraRecipientRewriteTableDAO.java
+++ b/server/data/data-cassandra/src/main/java/org/apache/james/rrt/cassandra/CassandraRecipientRewriteTableDAO.java
@@ -116,8 +116,7 @@ public class CassandraRecipientRewriteTableDAO {
     }
 
     public Flux<Pair<MappingSource, Mapping>> getAllMappings() {
-        return executor.execute(retrieveAllMappingsStatement.bind())
-            .flatMapMany(Flux::fromIterable)
+        return executor.executeRows(retrieveAllMappingsStatement.bind())
             .map(row -> Pair.of(
                 MappingSource.fromUser(row.getString(USER), row.getString(DOMAIN)),
                 Mapping.of(row.getString(MAPPING))));
diff --git a/server/data/data-cassandra/src/main/java/org/apache/james/sieve/cassandra/CassandraSieveDAO.java b/server/data/data-cassandra/src/main/java/org/apache/james/sieve/cassandra/CassandraSieveDAO.java
index e4895ad..de1f5ac 100644
--- a/server/data/data-cassandra/src/main/java/org/apache/james/sieve/cassandra/CassandraSieveDAO.java
+++ b/server/data/data-cassandra/src/main/java/org/apache/james/sieve/cassandra/CassandraSieveDAO.java
@@ -106,10 +106,9 @@ public class CassandraSieveDAO {
     }
 
     public Flux<ScriptSummary> listScripts(User user) {
-        return cassandraAsyncExecutor.execute(
+        return cassandraAsyncExecutor.executeRows(
                 selectScriptsStatement.bind()
                     .setString(USER_NAME, user.asString()))
-            .flatMapMany(Flux::fromIterable)
             .map(row -> new ScriptSummary(
                     new ScriptName(row.getString(SCRIPT_NAME)),
                     row.getBool(IS_ACTIVE)));
diff --git a/server/data/data-cassandra/src/main/java/org/apache/james/user/cassandra/CassandraUsersRepository.java b/server/data/data-cassandra/src/main/java/org/apache/james/user/cassandra/CassandraUsersRepository.java
index 1fc36ff..eeaf265 100644
--- a/server/data/data-cassandra/src/main/java/org/apache/james/user/cassandra/CassandraUsersRepository.java
+++ b/server/data/data-cassandra/src/main/java/org/apache/james/user/cassandra/CassandraUsersRepository.java
@@ -52,7 +52,6 @@ import com.datastax.driver.core.PreparedStatement;
 import com.datastax.driver.core.Session;
 import com.google.common.base.Preconditions;
 import com.google.common.primitives.Ints;
-import reactor.core.publisher.Flux;
 
 public class CassandraUsersRepository extends AbstractUsersRepository {
 
@@ -180,8 +179,7 @@ public class CassandraUsersRepository extends AbstractUsersRepository {
 
     @Override
     public Iterator<String> list() throws UsersRepositoryException {
-        return executor.execute(listStatement.bind())
-            .flatMapMany(Flux::fromIterable)
+        return executor.executeRows(listStatement.bind())
             .map(row -> row.getString(REALNAME))
             .toIterable()
             .iterator();
diff --git a/server/queue/queue-rabbitmq/src/main/java/org/apache/james/queue/rabbitmq/view/cassandra/CassandraMailQueueBrowser.java b/server/queue/queue-rabbitmq/src/main/java/org/apache/james/queue/rabbitmq/view/cassandra/CassandraMailQueueBrowser.java
index 29da254..9054e1b 100644
--- a/server/queue/queue-rabbitmq/src/main/java/org/apache/james/queue/rabbitmq/view/cassandra/CassandraMailQueueBrowser.java
+++ b/server/queue/queue-rabbitmq/src/main/java/org/apache/james/queue/rabbitmq/view/cassandra/CassandraMailQueueBrowser.java
@@ -26,7 +26,6 @@ import java.time.Clock;
 import java.time.Instant;
 import java.util.Comparator;
 import java.util.Iterator;
-import java.util.List;
 
 import javax.inject.Inject;
 import javax.mail.MessagingException;
@@ -109,7 +108,6 @@ public class CassandraMailQueueBrowser {
         return browseStartDao.findBrowseStart(queueName)
             .flatMapMany(this::allSlicesStartingAt)
             .flatMapSequential(slice -> browseSlice(queueName, slice))
-            .flatMapSequential(Flux::fromIterable)
             .subscribeOn(Schedulers.parallel());
     }
 
@@ -131,11 +129,11 @@ public class CassandraMailQueueBrowser {
         return mail;
     }
 
-    private Mono<List<EnqueuedItemWithSlicingContext>> browseSlice(MailQueueName queueName, Slice slice) {
+    private Flux<EnqueuedItemWithSlicingContext> browseSlice(MailQueueName queueName, Slice slice) {
         return
             allBucketIds()
                 .flatMap(bucketId -> browseBucket(queueName, slice, bucketId))
-                .collectSortedList(Comparator.comparing(enqueuedMail -> enqueuedMail.getEnqueuedItem().getEnqueuedTime()));
+                .sort(Comparator.comparing(enqueuedMail -> enqueuedMail.getEnqueuedItem().getEnqueuedTime()));
     }
 
     private Flux<EnqueuedItemWithSlicingContext> browseBucket(MailQueueName queueName, Slice slice, BucketId bucketId) {
diff --git a/server/queue/queue-rabbitmq/src/main/java/org/apache/james/queue/rabbitmq/view/cassandra/EnqueuedMailsDAO.java b/server/queue/queue-rabbitmq/src/main/java/org/apache/james/queue/rabbitmq/view/cassandra/EnqueuedMailsDAO.java
index 75101c4..009cfb7 100644
--- a/server/queue/queue-rabbitmq/src/main/java/org/apache/james/queue/rabbitmq/view/cassandra/EnqueuedMailsDAO.java
+++ b/server/queue/queue-rabbitmq/src/main/java/org/apache/james/queue/rabbitmq/view/cassandra/EnqueuedMailsDAO.java
@@ -142,12 +142,11 @@ public class EnqueuedMailsDAO {
     Flux<EnqueuedItemWithSlicingContext> selectEnqueuedMails(
         MailQueueName queueName, Slice slice, BucketId bucketId) {
 
-        return executor.execute(
+        return executor.executeRows(
                 selectFrom.bind()
                     .setString(QUEUE_NAME, queueName.asString())
                     .setTimestamp(TIME_RANGE_START, Date.from(slice.getStartSliceInstant()))
                     .setInt(BUCKET_ID, bucketId.getValue()))
-            .flatMapMany(Flux::fromIterable)
             .map(row -> EnqueuedMailsDaoUtil.toEnqueuedMail(row, blobFactory));
     }
 


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


[james-project] 03/07: DO NOT REVIEW JAMES-2630 Migrate lasts CompletableFutur to Reactor #2156

Posted by ro...@apache.org.
This is an automated email from the ASF dual-hosted git repository.

rouazana pushed a commit to branch master
in repository https://gitbox.apache.org/repos/asf/james-project.git

commit ea3e23192b86c3f28e04357405554cee92859f6a
Author: Matthieu Baechler <ma...@apache.org>
AuthorDate: Mon Jan 28 20:48:16 2019 +0100

    DO NOT REVIEW JAMES-2630 Migrate lasts CompletableFutur to Reactor #2156
---
 .../cassandra/init/CassandraTableManager.java      |   4 +-
 .../init/SessionWithInitializedTablesFactory.java  |   6 +-
 .../migration/CassandraMigrationService.java       |   4 +-
 .../cassandra/utils/CassandraAsyncExecutor.java    |  34 +--
 .../versions/CassandraSchemaVersionDAO.java        |  22 +-
 .../versions/CassandraSchemaVersionManager.java    |   2 +-
 .../SessionWithInitializedTablesFactoryTest.java   |   3 +-
 .../migration/CassandraMigrationServiceTest.java   |  28 +-
 .../backends/cassandra/utils/PaggingTest.java      |  26 +-
 .../versions/CassandraSchemaVersionDAOTest.java    |  15 +-
 .../CassandraSchemaVersionManagerTest.java         |  19 +-
 .../eventstore/cassandra/EventStoreDao.java        |  17 +-
 .../mailbox/cassandra/mail/CassandraACLMapper.java |   2 +-
 .../cassandra/mail/CassandraApplicableFlagDAO.java |   4 +-
 .../cassandra/mail/CassandraAttachmentDAO.java     |  16 +-
 .../cassandra/mail/CassandraAttachmentDAOV2.java   |   4 +-
 .../cassandra/mail/CassandraAttachmentMapper.java  |   7 +-
 .../mail/CassandraAttachmentMessageIdDAO.java      |  23 +-
 .../mail/CassandraAttachmentOwnerDAO.java          |  26 +-
 .../cassandra/mail/CassandraDeletedMessageDAO.java |  12 +-
 .../cassandra/mail/CassandraFirstUnseenDAO.java    |   6 +-
 .../cassandra/mail/CassandraMailboxCounterDAO.java |  14 +-
 .../cassandra/mail/CassandraMailboxDAO.java        |  12 +-
 .../cassandra/mail/CassandraMailboxMapper.java     |   6 +-
 .../mail/CassandraMailboxPathDAOImpl.java          |  21 +-
 .../cassandra/mail/CassandraMailboxPathV2DAO.java  |   6 +-
 .../cassandra/mail/CassandraMailboxRecentsDAO.java |   6 +-
 .../cassandra/mail/CassandraMessageDAO.java        |  15 +-
 .../cassandra/mail/CassandraMessageIdDAO.java      |  31 +-
 .../mail/CassandraMessageIdToImapUidDAO.java       |   8 +-
 .../cassandra/mail/CassandraMessageMapper.java     |  14 +-
 .../cassandra/mail/CassandraModSeqProvider.java    |   2 +-
 .../cassandra/mail/CassandraUidProvider.java       |   2 +-
 .../mail/CassandraUserMailboxRightsDAO.java        |  13 +-
 .../migration/AttachmentMessageIdCreation.java     |  38 ++-
 .../mail/migration/AttachmentV2Migration.java      |  39 ++-
 .../mail/migration/MailboxPathV2Migration.java     |  42 +--
 .../mail/task/MailboxMergingTaskRunner.java        |   4 +-
 .../cassandra/mail/CassandraAttachmentDAOTest.java |  16 +-
 .../mail/CassandraAttachmentFallbackTest.java      |  14 +-
 .../mail/CassandraAttachmentMessageIdDAOTest.java  |  56 ++--
 .../mail/CassandraAttachmentOwnerDAOTest.java      |  13 +-
 .../cassandra/mail/CassandraMailboxDAOTest.java    |   4 +-
 .../mail/CassandraMailboxPathDAOImplTest.java      |  10 +-
 .../cassandra/mail/CassandraMessageDAOTest.java    |  22 +-
 .../cassandra/mail/CassandraMessageIdDAOTest.java  |  54 ++--
 .../mail/CassandraUserMailboxRightsDAOTest.java    |   6 +-
 .../migration/AttachmentMessageIdCreationTest.java |  23 +-
 .../mail/migration/AttachmentV2MigrationTest.java  |  27 +-
 .../mail/migration/MailboxPathV2MigrationTest.java |  11 +-
 .../apache/james/metrics/api/MetricFactory.java    |   5 -
 .../james/blob/cassandra/CassandraBlobsDAO.java    |   8 +-
 .../james/blob/union/UnionBlobStoreTest.java       |   7 +-
 .../apache/james/CassandraVersionCheckingTest.java |  13 +-
 .../apache/james/GuiceLifecycleHeathCheckTest.java |  14 +-
 .../org/apache/james/utils/JmapGuiceProbe.java     |   4 +-
 .../apache/james/util/CompletableFutureUtil.java   | 103 -------
 .../org/apache/james/util/FluentFutureStream.java  | 166 ----------
 .../james/util/CompletableFutureUtilTest.java      | 340 ---------------------
 .../apache/james/util/FluentFutureStreamTest.java  | 293 ------------------
 .../domainlist/cassandra/CassandraDomainList.java  |  25 +-
 .../cassandra/CassandraMailRepositoryUrlStore.java |   6 +-
 .../james/mailrepository/cassandra/UrlsDao.java    |  27 +-
 .../rrt/cassandra/CassandraMappingsSourcesDAO.java |   8 +-
 .../cassandra/CassandraRecipientRewriteTable.java  |   2 +-
 .../CassandraRecipientRewriteTableDAO.java         |   8 +-
 .../sieve/cassandra/CassandraActiveScriptDAO.java  |   6 +-
 .../james/sieve/cassandra/CassandraSieveDAO.java   |  23 +-
 .../sieve/cassandra/CassandraSieveQuotaDAO.java    |  29 +-
 .../sieve/cassandra/CassandraSieveRepository.java  |  99 +++---
 .../user/cassandra/CassandraUsersRepository.java   |  23 +-
 .../CassandraMailRepositoryUrlStoreExtension.java  |   4 +-
 .../CassandraRecipientRewriteTableV6Test.java      |   4 +-
 .../CassandraRecipientRewriteTableV7Test.java      |   4 +-
 .../james/rrt/cassandra/CassandraStepdefs.java     |   2 +-
 .../sieve/cassandra/CassandraSieveDAOTest.java     |  11 +-
 .../cassandra/CassandraSieveQuotaDAOTest.java      |  40 +--
 .../cassandra/access/CassandraAccessTokenDAO.java  |  13 +-
 .../access/CassandraAccessTokenRepository.java     |  12 +-
 .../vacation/CassandraNotificationRegistry.java    |  10 +-
 .../vacation/CassandraNotificationRegistryDAO.java |  12 +-
 .../cassandra/vacation/CassandraVacationDAO.java   |  12 +-
 .../vacation/CassandraVacationRepository.java      |  11 +-
 .../jmap/api/access/AccessTokenRepository.java     |  10 +-
 .../jmap/api/vacation/NotificationRegistry.java    |   9 +-
 .../jmap/api/vacation/VacationRepository.java      |   6 +-
 .../memory/access/MemoryAccessTokenRepository.java |  17 +-
 .../vacation/MemoryNotificationRegistry.java       |  14 +-
 .../memory/vacation/MemoryVacationRepository.java  |  12 +-
 .../jmap/api/access/AccessTokenRepositoryTest.java |  21 +-
 .../vacation/AbstractNotificationRegistryTest.java |  28 +-
 .../vacation/AbstractVacationRepositoryTest.java   |  70 ++---
 .../cassandra/CassandraMailRepository.java         |   2 +-
 .../cassandra/CassandraMailRepositoryCountDAO.java |  11 +-
 .../cassandra/CassandraMailRepositoryKeysDAO.java  |   2 +-
 .../cassandra/CassandraMailRepositoryMailDAO.java  |   6 +-
 .../CassandraMailRepositoryMailDaoV2.java          |   6 +-
 .../CassandraMailRepositoryCountDAOTest.java       |  12 +-
 ...aMailRepositoryWithFakeImplementationsTest.java |   2 +-
 .../james/jmap/crypto/AccessTokenManagerImpl.java  |  16 +-
 .../apache/james/jmap/mailet/VacationMailet.java   |   8 +-
 .../jmap/methods/GetVacationResponseMethod.java    |   2 +-
 .../jmap/methods/SetVacationResponseMethod.java    |   4 +-
 .../james/jmap/AuthenticationFilterTest.java       |   4 +-
 .../jmap/crypto/AccessTokenManagerImplTest.java    |  89 ++++--
 .../james/jmap/mailet/VacationMailetTest.java      |  38 ++-
 .../methods/GetVacationResponseMethodTest.java     |   9 +-
 .../methods/SetVacationResponseMethodTest.java     |   6 +-
 .../routes/CassandraMigrationRoutesTest.java       |  25 +-
 .../rabbitmq/view/cassandra/BrowseStartDAO.java    |  15 +-
 .../cassandra/CassandraMailQueueMailDelete.java    |  10 +-
 .../view/cassandra/CassandraMailQueueView.java     |   2 +-
 .../rabbitmq/view/cassandra/DeletedMailsDAO.java   |   4 +-
 .../rabbitmq/view/cassandra/EnqueuedMailsDAO.java  |  17 +-
 114 files changed, 836 insertions(+), 1794 deletions(-)

diff --git a/backends-common/cassandra/src/main/java/org/apache/james/backends/cassandra/init/CassandraTableManager.java b/backends-common/cassandra/src/main/java/org/apache/james/backends/cassandra/init/CassandraTableManager.java
index 6ad0fdc..30980f3 100644
--- a/backends-common/cassandra/src/main/java/org/apache/james/backends/cassandra/init/CassandraTableManager.java
+++ b/backends-common/cassandra/src/main/java/org/apache/james/backends/cassandra/init/CassandraTableManager.java
@@ -67,12 +67,12 @@ public class CassandraTableManager {
     }
 
     private Mono<Void> truncate(CassandraAsyncExecutor executor, String name) {
-        return executor.executeReactor(
+        return executor.execute(
                 QueryBuilder.select()
                         .from(name)
                         .limit(1)
                         .setFetchSize(1))
                 .filter(resultSet -> !resultSet.isExhausted())
-                .flatMap(ignored -> executor.executeVoidReactor(QueryBuilder.truncate(name)));
+                .flatMap(ignored -> executor.executeVoid(QueryBuilder.truncate(name)));
     }
 }
diff --git a/backends-common/cassandra/src/main/java/org/apache/james/backends/cassandra/init/SessionWithInitializedTablesFactory.java b/backends-common/cassandra/src/main/java/org/apache/james/backends/cassandra/init/SessionWithInitializedTablesFactory.java
index b5213d7..8448a32 100644
--- a/backends-common/cassandra/src/main/java/org/apache/james/backends/cassandra/init/SessionWithInitializedTablesFactory.java
+++ b/backends-common/cassandra/src/main/java/org/apache/james/backends/cassandra/init/SessionWithInitializedTablesFactory.java
@@ -29,7 +29,6 @@ import org.apache.james.backends.cassandra.components.CassandraModule;
 import org.apache.james.backends.cassandra.components.CassandraTable;
 import org.apache.james.backends.cassandra.components.CassandraType;
 import org.apache.james.backends.cassandra.init.configuration.ClusterConfiguration;
-import org.apache.james.backends.cassandra.utils.CassandraUtils;
 import org.apache.james.backends.cassandra.versions.CassandraSchemaVersionDAO;
 import org.apache.james.backends.cassandra.versions.CassandraSchemaVersionManager;
 
@@ -51,8 +50,9 @@ public class SessionWithInitializedTablesFactory implements Provider<Session> {
         Session session = cluster.connect(keyspace);
         try {
             if (allOperationsAreFullyPerformed(session)) {
-                new CassandraSchemaVersionDAO(session, CassandraUtils.WITH_DEFAULT_CONFIGURATION)
-                        .updateVersion(CassandraSchemaVersionManager.MAX_VERSION);
+                new CassandraSchemaVersionDAO(session)
+                    .updateVersion(CassandraSchemaVersionManager.MAX_VERSION)
+                    .block();
             }
             return session;
         } catch (Exception e) {
diff --git a/backends-common/cassandra/src/main/java/org/apache/james/backends/cassandra/migration/CassandraMigrationService.java b/backends-common/cassandra/src/main/java/org/apache/james/backends/cassandra/migration/CassandraMigrationService.java
index 5ee175d..3aec56a 100644
--- a/backends-common/cassandra/src/main/java/org/apache/james/backends/cassandra/migration/CassandraMigrationService.java
+++ b/backends-common/cassandra/src/main/java/org/apache/james/backends/cassandra/migration/CassandraMigrationService.java
@@ -49,7 +49,7 @@ public class CassandraMigrationService {
     }
 
     public Optional<SchemaVersion> getCurrentVersion() {
-        return schemaVersionDAO.getCurrentSchemaVersion().join();
+        return schemaVersionDAO.getCurrentSchemaVersion().block();
     }
 
     public Optional<SchemaVersion> getLatestVersion() {
@@ -91,7 +91,7 @@ public class CassandraMigrationService {
 
             logger.info("Migrating to version {} ", newVersion);
             return allMigrationClazz.get(version).run()
-                .onComplete(() -> schemaVersionDAO.updateVersion(newVersion).join(),
+                .onComplete(() -> schemaVersionDAO.updateVersion(newVersion).block(),
                     () -> logger.info("Migrating to version {} done", newVersion))
                 .onFailure(() -> logger.warn(failureMessage(newVersion)),
                     () -> throwMigrationException(newVersion));
diff --git a/backends-common/cassandra/src/main/java/org/apache/james/backends/cassandra/utils/CassandraAsyncExecutor.java b/backends-common/cassandra/src/main/java/org/apache/james/backends/cassandra/utils/CassandraAsyncExecutor.java
index 361bb93..c1b86e2 100644
--- a/backends-common/cassandra/src/main/java/org/apache/james/backends/cassandra/utils/CassandraAsyncExecutor.java
+++ b/backends-common/cassandra/src/main/java/org/apache/james/backends/cassandra/utils/CassandraAsyncExecutor.java
@@ -20,7 +20,6 @@
 package org.apache.james.backends.cassandra.utils;
 
 import java.util.Optional;
-import java.util.concurrent.CompletableFuture;
 
 import javax.inject.Inject;
 
@@ -28,7 +27,6 @@ import com.datastax.driver.core.ResultSet;
 import com.datastax.driver.core.Row;
 import com.datastax.driver.core.Session;
 import com.datastax.driver.core.Statement;
-
 import net.javacrumbs.futureconverter.java8guava.FutureConverter;
 import reactor.core.publisher.Mono;
 import reactor.core.scheduler.Schedulers;
@@ -42,48 +40,34 @@ public class CassandraAsyncExecutor {
         this.session = session;
     }
 
-    public CompletableFuture<ResultSet> execute(Statement statement) {
-        return executeReactor(statement).toFuture();
-    }
-
-    public CompletableFuture<Void> executeVoid(Statement statement) {
-        return executeVoidReactor(statement).toFuture();
-    }
-
-    public CompletableFuture<Optional<Row>> executeSingleRow(Statement statement) {
-        return executeSingleRowOptionalReactor(statement)
-                .toFuture();
-    }
-
-    public Mono<ResultSet> executeReactor(Statement statement) {
+    public Mono<ResultSet> execute(Statement statement) {
         return Mono.defer(() -> Mono.fromFuture(FutureConverter
                 .toCompletableFuture(session.executeAsync(statement)))
                 .publishOn(Schedulers.elastic()));
     }
 
-
     public Mono<Boolean> executeReturnApplied(Statement statement) {
-        return executeSingleRowReactor(statement)
+        return executeSingleRow(statement)
                 .map(row -> row.getBool(CassandraConstants.LIGHTWEIGHT_TRANSACTION_APPLIED));
     }
 
-    public Mono<Void> executeVoidReactor(Statement statement) {
-        return executeReactor(statement)
+    public Mono<Void> executeVoid(Statement statement) {
+        return execute(statement)
                 .then();
     }
 
-    public Mono<Row> executeSingleRowReactor(Statement statement) {
-        return executeSingleRowOptionalReactor(statement)
+    public Mono<Row> executeSingleRow(Statement statement) {
+        return executeSingleRowOptional(statement)
                 .flatMap(Mono::justOrEmpty);
     }
 
-    public Mono<Optional<Row>> executeSingleRowOptionalReactor(Statement statement) {
-        return executeReactor(statement)
+    public Mono<Optional<Row>> executeSingleRowOptional(Statement statement) {
+        return execute(statement)
             .map(resultSet -> Optional.ofNullable(resultSet.one()));
     }
 
     public Mono<Boolean> executeReturnExists(Statement statement) {
-        return executeSingleRowReactor(statement)
+        return executeSingleRow(statement)
                 .hasElement();
     }
 }
diff --git a/backends-common/cassandra/src/main/java/org/apache/james/backends/cassandra/versions/CassandraSchemaVersionDAO.java b/backends-common/cassandra/src/main/java/org/apache/james/backends/cassandra/versions/CassandraSchemaVersionDAO.java
index 23ca069..6d1ed10 100644
--- a/backends-common/cassandra/src/main/java/org/apache/james/backends/cassandra/versions/CassandraSchemaVersionDAO.java
+++ b/backends-common/cassandra/src/main/java/org/apache/james/backends/cassandra/versions/CassandraSchemaVersionDAO.java
@@ -27,30 +27,28 @@ import static org.apache.james.backends.cassandra.versions.table.CassandraSchema
 import static org.apache.james.backends.cassandra.versions.table.CassandraSchemaVersionTable.VALUE;
 
 import java.util.Optional;
-import java.util.concurrent.CompletableFuture;
 
 import javax.inject.Inject;
 
 import org.apache.james.backends.cassandra.utils.CassandraAsyncExecutor;
-import org.apache.james.backends.cassandra.utils.CassandraUtils;
 import org.apache.james.backends.cassandra.versions.table.CassandraSchemaVersionTable;
 
 import com.datastax.driver.core.PreparedStatement;
 import com.datastax.driver.core.Session;
 import com.datastax.driver.core.utils.UUIDs;
+import reactor.core.publisher.Flux;
+import reactor.core.publisher.Mono;
 
 public class CassandraSchemaVersionDAO {
     private final PreparedStatement readVersionStatement;
     private final PreparedStatement writeVersionStatement;
-    private CassandraUtils cassandraUtils;
     private final CassandraAsyncExecutor cassandraAsyncExecutor;
 
     @Inject
-    public CassandraSchemaVersionDAO(Session session, CassandraUtils cassandraUtils) {
+    public CassandraSchemaVersionDAO(Session session) {
         cassandraAsyncExecutor = new CassandraAsyncExecutor(session);
         readVersionStatement = prepareReadVersionStatement(session);
         writeVersionStatement = prepareWriteVersionStatement(session);
-        this.cassandraUtils = cassandraUtils;
     }
 
     private PreparedStatement prepareReadVersionStatement(Session session) {
@@ -66,15 +64,17 @@ public class CassandraSchemaVersionDAO {
                 .value(VALUE, bindMarker(VALUE)));
     }
 
-    public CompletableFuture<Optional<SchemaVersion>> getCurrentSchemaVersion() {
+    public Mono<Optional<SchemaVersion>> getCurrentSchemaVersion() {
         return cassandraAsyncExecutor.execute(readVersionStatement.bind())
-            .thenApply(resultSet -> cassandraUtils.convertToStream(resultSet)
-                .map(row -> row.getInt(VALUE))
-                .reduce(Math::max))
-            .thenApply(i -> i.map(SchemaVersion::new));
+            .flatMapMany(Flux::fromIterable)
+            .map(row -> row.getInt(VALUE))
+            .reduce(Math::max)
+            .map(SchemaVersion::new)
+            .map(Optional::of)
+            .switchIfEmpty(Mono.just(Optional.empty()));
     }
 
-    public CompletableFuture<Void> updateVersion(SchemaVersion newVersion) {
+    public Mono<Void> updateVersion(SchemaVersion newVersion) {
         return cassandraAsyncExecutor.executeVoid(
             writeVersionStatement.bind()
                 .setUUID(KEY, UUIDs.timeBased())
diff --git a/backends-common/cassandra/src/main/java/org/apache/james/backends/cassandra/versions/CassandraSchemaVersionManager.java b/backends-common/cassandra/src/main/java/org/apache/james/backends/cassandra/versions/CassandraSchemaVersionManager.java
index 172fdb5..37a222d 100644
--- a/backends-common/cassandra/src/main/java/org/apache/james/backends/cassandra/versions/CassandraSchemaVersionManager.java
+++ b/backends-common/cassandra/src/main/java/org/apache/james/backends/cassandra/versions/CassandraSchemaVersionManager.java
@@ -68,7 +68,7 @@ public class CassandraSchemaVersionManager {
     public SchemaVersion computeVersion() {
         return schemaVersionDAO
             .getCurrentSchemaVersion()
-            .join()
+            .block()
             .orElseGet(() -> {
                 LOGGER.warn("No schema version information found on Cassandra, we assume schema is at version {}",
                     CassandraSchemaVersionManager.DEFAULT_VERSION);
diff --git a/backends-common/cassandra/src/test/java/org/apache/james/backends/cassandra/init/SessionWithInitializedTablesFactoryTest.java b/backends-common/cassandra/src/test/java/org/apache/james/backends/cassandra/init/SessionWithInitializedTablesFactoryTest.java
index 631a027..041aaf1 100644
--- a/backends-common/cassandra/src/test/java/org/apache/james/backends/cassandra/init/SessionWithInitializedTablesFactoryTest.java
+++ b/backends-common/cassandra/src/test/java/org/apache/james/backends/cassandra/init/SessionWithInitializedTablesFactoryTest.java
@@ -30,7 +30,6 @@ import java.util.function.Supplier;
 import org.apache.james.backends.cassandra.DockerCassandraExtension;
 import org.apache.james.backends.cassandra.components.CassandraModule;
 import org.apache.james.backends.cassandra.init.configuration.ClusterConfiguration;
-import org.apache.james.backends.cassandra.utils.CassandraUtils;
 import org.apache.james.backends.cassandra.versions.CassandraSchemaVersionDAO;
 import org.apache.james.backends.cassandra.versions.CassandraSchemaVersionManager;
 import org.apache.james.backends.cassandra.versions.CassandraSchemaVersionModule;
@@ -151,6 +150,6 @@ class SessionWithInitializedTablesFactoryTest {
     }
 
     private CassandraSchemaVersionDAO versionManagerDAO(Session session) {
-        return new CassandraSchemaVersionDAO(session, CassandraUtils.WITH_DEFAULT_CONFIGURATION);
+        return new CassandraSchemaVersionDAO(session);
     }
 }
\ No newline at end of file
diff --git a/backends-common/cassandra/src/test/java/org/apache/james/backends/cassandra/migration/CassandraMigrationServiceTest.java b/backends-common/cassandra/src/test/java/org/apache/james/backends/cassandra/migration/CassandraMigrationServiceTest.java
index 7631f4b..e0a849e 100644
--- a/backends-common/cassandra/src/test/java/org/apache/james/backends/cassandra/migration/CassandraMigrationServiceTest.java
+++ b/backends-common/cassandra/src/test/java/org/apache/james/backends/cassandra/migration/CassandraMigrationServiceTest.java
@@ -31,7 +31,6 @@ import static org.mockito.Mockito.when;
 
 import java.util.Map;
 import java.util.Optional;
-import java.util.concurrent.CompletableFuture;
 import java.util.concurrent.ExecutorService;
 import java.util.concurrent.Executors;
 
@@ -48,6 +47,7 @@ import org.junit.rules.ExpectedException;
 
 import com.datastax.driver.core.Session;
 import com.google.common.collect.ImmutableMap;
+import reactor.core.publisher.Mono;
 
 public class CassandraMigrationServiceTest {
     private static final SchemaVersion LATEST_VERSION = new SchemaVersion(3);
@@ -65,7 +65,7 @@ public class CassandraMigrationServiceTest {
     @Before
     public void setUp() throws Exception {
         schemaVersionDAO = mock(CassandraSchemaVersionDAO.class);
-        when(schemaVersionDAO.updateVersion(any())).thenReturn(CompletableFuture.completedFuture(null));
+        when(schemaVersionDAO.updateVersion(any())).thenReturn(Mono.empty());
 
         successfulMigration = mock(Migration.class);
         when(successfulMigration.run()).thenReturn(Migration.Result.COMPLETED);
@@ -86,7 +86,7 @@ public class CassandraMigrationServiceTest {
 
     @Test
     public void getCurrentVersionShouldReturnCurrentVersion() {
-        when(schemaVersionDAO.getCurrentSchemaVersion()).thenReturn(CompletableFuture.completedFuture(Optional.of(CURRENT_VERSION)));
+        when(schemaVersionDAO.getCurrentSchemaVersion()).thenReturn(Mono.just(Optional.of(CURRENT_VERSION)));
 
         assertThat(testee.getCurrentVersion()).contains(CURRENT_VERSION);
     }
@@ -98,7 +98,7 @@ public class CassandraMigrationServiceTest {
 
     @Test
     public void upgradeToVersionShouldNotThrowWhenCurrentVersionIsUpToDate() {
-        when(schemaVersionDAO.getCurrentSchemaVersion()).thenReturn(CompletableFuture.completedFuture(Optional.of(CURRENT_VERSION)));
+        when(schemaVersionDAO.getCurrentSchemaVersion()).thenReturn(Mono.just(Optional.of(CURRENT_VERSION)));
 
         assertThat(testee.upgradeToVersion(OLDER_VERSION).run())
             .isEqualTo(Task.Result.COMPLETED);
@@ -106,7 +106,7 @@ public class CassandraMigrationServiceTest {
 
     @Test
     public void upgradeToVersionShouldUpdateToVersion() {
-        when(schemaVersionDAO.getCurrentSchemaVersion()).thenReturn(CompletableFuture.completedFuture(Optional.of(OLDER_VERSION)));
+        when(schemaVersionDAO.getCurrentSchemaVersion()).thenReturn(Mono.just(Optional.of(OLDER_VERSION)));
 
         testee.upgradeToVersion(CURRENT_VERSION).run();
 
@@ -116,7 +116,7 @@ public class CassandraMigrationServiceTest {
     @Test
     public void upgradeToLastVersionShouldNotThrowWhenVersionIsUpToDate() {
 
-        when(schemaVersionDAO.getCurrentSchemaVersion()).thenReturn(CompletableFuture.completedFuture(Optional.of(LATEST_VERSION)));
+        when(schemaVersionDAO.getCurrentSchemaVersion()).thenReturn(Mono.just(Optional.of(LATEST_VERSION)));
 
         assertThat(testee.upgradeToLastVersion().run())
             .isEqualTo(Task.Result.COMPLETED);
@@ -124,7 +124,7 @@ public class CassandraMigrationServiceTest {
 
     @Test
     public void upgradeToLastVersionShouldUpdateToLatestVersion() {
-        when(schemaVersionDAO.getCurrentSchemaVersion()).thenReturn(CompletableFuture.completedFuture(Optional.of(OLDER_VERSION)));
+        when(schemaVersionDAO.getCurrentSchemaVersion()).thenReturn(Mono.just(Optional.of(OLDER_VERSION)));
 
         testee.upgradeToLastVersion().run();
 
@@ -138,7 +138,7 @@ public class CassandraMigrationServiceTest {
             .put(LATEST_VERSION, successfulMigration)
             .build();
         testee = new CassandraMigrationService(schemaVersionDAO, allMigrationClazz, LATEST_VERSION);
-        when(schemaVersionDAO.getCurrentSchemaVersion()).thenReturn(CompletableFuture.completedFuture(Optional.of(OLDER_VERSION)));
+        when(schemaVersionDAO.getCurrentSchemaVersion()).thenReturn(Mono.just(Optional.of(OLDER_VERSION)));
 
         expectedException.expect(NotImplementedException.class);
 
@@ -154,7 +154,7 @@ public class CassandraMigrationServiceTest {
                 .put(LATEST_VERSION, successfulMigration)
                 .build();
             testee = new CassandraMigrationService(schemaVersionDAO, allMigrationClazz, LATEST_VERSION);
-            when(schemaVersionDAO.getCurrentSchemaVersion()).thenReturn(CompletableFuture.completedFuture(Optional.of(OLDER_VERSION)));
+            when(schemaVersionDAO.getCurrentSchemaVersion()).thenReturn(Mono.just(Optional.of(OLDER_VERSION)));
 
             expectedException.expect(RuntimeException.class);
 
@@ -209,19 +209,19 @@ public class CassandraMigrationServiceTest {
         private SchemaVersion currentVersion;
 
         public InMemorySchemaDAO(SchemaVersion currentVersion) {
-            super(mock(Session.class), null);
+            super(mock(Session.class));
             this.currentVersion = currentVersion;
         }
 
         @Override
-        public CompletableFuture<Optional<SchemaVersion>> getCurrentSchemaVersion() {
-            return CompletableFuture.completedFuture(Optional.of(currentVersion));
+        public Mono<Optional<SchemaVersion>> getCurrentSchemaVersion() {
+            return Mono.just(Optional.of(currentVersion));
         }
 
         @Override
-        public CompletableFuture<Void> updateVersion(SchemaVersion newVersion) {
+        public Mono<Void> updateVersion(SchemaVersion newVersion) {
             currentVersion = newVersion;
-            return CompletableFuture.completedFuture(null);
+            return Mono.empty();
         }
     }
 }
\ No newline at end of file
diff --git a/backends-common/cassandra/src/test/java/org/apache/james/backends/cassandra/utils/PaggingTest.java b/backends-common/cassandra/src/test/java/org/apache/james/backends/cassandra/utils/PaggingTest.java
index 3395e20..4188195 100644
--- a/backends-common/cassandra/src/test/java/org/apache/james/backends/cassandra/utils/PaggingTest.java
+++ b/backends-common/cassandra/src/test/java/org/apache/james/backends/cassandra/utils/PaggingTest.java
@@ -25,18 +25,17 @@ import static com.datastax.driver.core.querybuilder.QueryBuilder.select;
 import static org.assertj.core.api.Assertions.assertThat;
 
 import java.util.UUID;
-import java.util.stream.IntStream;
 
 import org.apache.james.backends.cassandra.CassandraCluster;
 import org.apache.james.backends.cassandra.CassandraClusterExtension;
 import org.apache.james.backends.cassandra.components.CassandraModule;
-import org.apache.james.util.CompletableFutureUtil;
 import org.junit.jupiter.api.BeforeEach;
 import org.junit.jupiter.api.Test;
 import org.junit.jupiter.api.extension.RegisterExtension;
 
 import com.datastax.driver.core.DataType;
 import com.datastax.driver.core.utils.UUIDs;
+import reactor.core.publisher.Flux;
 
 class PaggingTest {
     
@@ -65,22 +64,19 @@ class PaggingTest {
         int fetchSize = 200;
         int size = 2 * fetchSize + 50;
 
-        CompletableFutureUtil.allOf(
-            IntStream.range(0, size)
-                .boxed()
-                .map(i ->
-                    executor
-                        .executeVoid(insertInto(TABLE_NAME)
-                            .value(ID, UUID)
-                            .value(CLUSTERING, i))))
-            .join();
+        Flux.range(0, size)
+            .flatMap(i -> executor
+                .executeVoid(insertInto(TABLE_NAME)
+                    .value(ID, UUID)
+                    .value(CLUSTERING, i)))
+            .blockLast();
 
         assertThat(
             executor.execute(select()
-                .from(TABLE_NAME)
-                .where(eq(ID, UUID))
-                .setFetchSize(fetchSize))
-                .join())
+                    .from(TABLE_NAME)
+                    .where(eq(ID, UUID))
+                    .setFetchSize(fetchSize))
+                .block())
             .hasSize(size);
     }
 
diff --git a/backends-common/cassandra/src/test/java/org/apache/james/backends/cassandra/versions/CassandraSchemaVersionDAOTest.java b/backends-common/cassandra/src/test/java/org/apache/james/backends/cassandra/versions/CassandraSchemaVersionDAOTest.java
index e5a0b8b..edf7206 100644
--- a/backends-common/cassandra/src/test/java/org/apache/james/backends/cassandra/versions/CassandraSchemaVersionDAOTest.java
+++ b/backends-common/cassandra/src/test/java/org/apache/james/backends/cassandra/versions/CassandraSchemaVersionDAOTest.java
@@ -25,7 +25,6 @@ import java.util.Optional;
 
 import org.apache.james.backends.cassandra.CassandraCluster;
 import org.apache.james.backends.cassandra.CassandraClusterExtension;
-import org.apache.james.backends.cassandra.utils.CassandraUtils;
 import org.junit.jupiter.api.BeforeEach;
 import org.junit.jupiter.api.Test;
 import org.junit.jupiter.api.extension.RegisterExtension;
@@ -38,12 +37,12 @@ class CassandraSchemaVersionDAOTest {
 
     @BeforeEach
     void setUp(CassandraCluster cassandra) {
-        testee = new CassandraSchemaVersionDAO(cassandra.getConf(), CassandraUtils.WITH_DEFAULT_CONFIGURATION);
+        testee = new CassandraSchemaVersionDAO(cassandra.getConf());
     }
 
     @Test
     void getCurrentSchemaVersionShouldReturnEmptyWhenTableIsEmpty() {
-        assertThat(testee.getCurrentSchemaVersion().join())
+        assertThat(testee.getCurrentSchemaVersion().block())
             .isEqualTo(Optional.empty());
     }
 
@@ -51,18 +50,18 @@ class CassandraSchemaVersionDAOTest {
     void getCurrentSchemaVersionShouldReturnVersionPresentInTheTable() {
         SchemaVersion version = new SchemaVersion(42);
 
-        testee.updateVersion(version).join();
+        testee.updateVersion(version).block();
 
-        assertThat(testee.getCurrentSchemaVersion().join()).contains(version);
+        assertThat(testee.getCurrentSchemaVersion().block()).contains(version);
     }
 
     @Test
     void getCurrentSchemaVersionShouldBeIdempotent() {
         SchemaVersion version = new SchemaVersion(42);
 
-        testee.updateVersion(version.next()).join();
-        testee.updateVersion(version).join();
+        testee.updateVersion(version.next()).block();
+        testee.updateVersion(version).block();
 
-        assertThat(testee.getCurrentSchemaVersion().join()).contains(version.next());
+        assertThat(testee.getCurrentSchemaVersion().block()).contains(version.next());
     }
 }
\ No newline at end of file
diff --git a/backends-common/cassandra/src/test/java/org/apache/james/backends/cassandra/versions/CassandraSchemaVersionManagerTest.java b/backends-common/cassandra/src/test/java/org/apache/james/backends/cassandra/versions/CassandraSchemaVersionManagerTest.java
index dfffddc..cb395dd 100644
--- a/backends-common/cassandra/src/test/java/org/apache/james/backends/cassandra/versions/CassandraSchemaVersionManagerTest.java
+++ b/backends-common/cassandra/src/test/java/org/apache/james/backends/cassandra/versions/CassandraSchemaVersionManagerTest.java
@@ -28,7 +28,6 @@ import static org.mockito.Mockito.mock;
 import static org.mockito.Mockito.when;
 
 import java.util.Optional;
-import java.util.concurrent.CompletableFuture;
 
 import org.apache.james.backends.cassandra.versions.CassandraSchemaVersionManager.SchemaState;
 import org.junit.Before;
@@ -36,6 +35,8 @@ import org.junit.Rule;
 import org.junit.Test;
 import org.junit.rules.ExpectedException;
 
+import reactor.core.publisher.Mono;
+
 public class CassandraSchemaVersionManagerTest {
 
     private final SchemaVersion minVersion = new SchemaVersion(2);
@@ -55,7 +56,7 @@ public class CassandraSchemaVersionManagerTest {
         SchemaVersion currentVersion = minVersion.previous();
 
         when(schemaVersionDAO.getCurrentSchemaVersion())
-            .thenReturn(CompletableFuture.completedFuture(Optional.of(currentVersion)));
+            .thenReturn(Mono.just(Optional.of(currentVersion)));
 
         CassandraSchemaVersionManager testee = new CassandraSchemaVersionManager(
             schemaVersionDAO,
@@ -70,7 +71,7 @@ public class CassandraSchemaVersionManagerTest {
         SchemaVersion currentVersion = maxVersion.next();
 
         when(schemaVersionDAO.getCurrentSchemaVersion())
-            .thenReturn(CompletableFuture.completedFuture(Optional.of(currentVersion)));
+            .thenReturn(Mono.just(Optional.of(currentVersion)));
 
         CassandraSchemaVersionManager testee = new CassandraSchemaVersionManager(
             schemaVersionDAO,
@@ -85,7 +86,7 @@ public class CassandraSchemaVersionManagerTest {
         SchemaVersion currentVersion = maxVersion;
 
         when(schemaVersionDAO.getCurrentSchemaVersion())
-            .thenReturn(CompletableFuture.completedFuture(Optional.of(currentVersion)));
+            .thenReturn(Mono.just(Optional.of(currentVersion)));
 
         CassandraSchemaVersionManager testee = new CassandraSchemaVersionManager(
             schemaVersionDAO,
@@ -100,7 +101,7 @@ public class CassandraSchemaVersionManagerTest {
         SchemaVersion currentVersion = minVersion.next();
 
         when(schemaVersionDAO.getCurrentSchemaVersion())
-            .thenReturn(CompletableFuture.completedFuture(Optional.of(currentVersion)));
+            .thenReturn(Mono.just(Optional.of(currentVersion)));
 
         CassandraSchemaVersionManager testee = new CassandraSchemaVersionManager(
             schemaVersionDAO,
@@ -128,7 +129,7 @@ public class CassandraSchemaVersionManagerTest {
         SchemaVersion maxVersion = new SchemaVersion(4);
         SchemaVersion currentVersion = new SchemaVersion(4);
         when(schemaVersionDAO.getCurrentSchemaVersion())
-            .thenReturn(CompletableFuture.completedFuture(Optional.of(currentVersion)));
+            .thenReturn(Mono.just(Optional.of(currentVersion)));
 
         CassandraSchemaVersionManager testee = new CassandraSchemaVersionManager(
             schemaVersionDAO,
@@ -141,7 +142,7 @@ public class CassandraSchemaVersionManagerTest {
     @Test
     public void defaultComputedSchemaShouldNotBeTooOldNeitherTooRecent() {
         when(schemaVersionDAO.getCurrentSchemaVersion())
-            .thenReturn(CompletableFuture.completedFuture(Optional.of(CassandraSchemaVersionManager.DEFAULT_VERSION)));
+            .thenReturn(Mono.just(Optional.of(CassandraSchemaVersionManager.DEFAULT_VERSION)));
 
         SchemaState schemaState = new CassandraSchemaVersionManager(schemaVersionDAO).computeSchemaState();
 
@@ -153,7 +154,7 @@ public class CassandraSchemaVersionManagerTest {
     @Test
     public void ensureSchemaDefaultConstructorUseCorrectMinVersion() {
         when(schemaVersionDAO.getCurrentSchemaVersion())
-            .thenReturn(CompletableFuture.completedFuture(Optional.empty()));
+            .thenReturn(Mono.just(Optional.empty()));
 
         CassandraSchemaVersionManager testee = new CassandraSchemaVersionManager(schemaVersionDAO);
 
@@ -163,7 +164,7 @@ public class CassandraSchemaVersionManagerTest {
     @Test
     public void ensureSchemaDefaultConstructorUseCorrectMaxVersion() {
         when(schemaVersionDAO.getCurrentSchemaVersion())
-            .thenReturn(CompletableFuture.completedFuture(Optional.empty()));
+            .thenReturn(Mono.just(Optional.empty()));
 
         CassandraSchemaVersionManager testee = new CassandraSchemaVersionManager(schemaVersionDAO);
 
diff --git a/event-sourcing/event-store-cassandra/src/main/java/org/apache/james/eventsourcing/eventstore/cassandra/EventStoreDao.java b/event-sourcing/event-store-cassandra/src/main/java/org/apache/james/eventsourcing/eventstore/cassandra/EventStoreDao.java
index 8f6a9d1..226d7b5 100644
--- a/event-sourcing/event-store-cassandra/src/main/java/org/apache/james/eventsourcing/eventstore/cassandra/EventStoreDao.java
+++ b/event-sourcing/event-store-cassandra/src/main/java/org/apache/james/eventsourcing/eventstore/cassandra/EventStoreDao.java
@@ -42,11 +42,10 @@ import org.apache.james.eventsourcing.eventstore.History;
 import com.datastax.driver.core.BatchStatement;
 import com.datastax.driver.core.BoundStatement;
 import com.datastax.driver.core.PreparedStatement;
-import com.datastax.driver.core.ResultSet;
 import com.datastax.driver.core.Row;
 import com.datastax.driver.core.Session;
 import com.fasterxml.jackson.core.JsonProcessingException;
-import com.github.steveash.guavate.Guavate;
+import reactor.core.publisher.Flux;
 import reactor.core.publisher.Mono;
 
 public class EventStoreDao {
@@ -98,18 +97,14 @@ public class EventStoreDao {
     }
 
     public History getEventsOfAggregate(AggregateId aggregateId) {
-        return toHistory(
-            cassandraAsyncExecutor.execute(
+        return cassandraAsyncExecutor.execute(
                 select.bind()
                     .setString(AGGREGATE_ID, aggregateId.asAggregateKey()))
-                .join());
-    }
-
-    private History toHistory(ResultSet resultSet) {
-        List<Event> events = cassandraUtils.convertToStream(resultSet)
+            .flatMapMany(Flux::fromIterable)
             .map(this::toEvent)
-            .collect(Guavate.toImmutableList());
-        return History.of(events);
+            .collectList()
+            .map(History::of)
+            .block();
     }
 
     private Event toEvent(Row row) {
diff --git a/mailbox/cassandra/src/main/java/org/apache/james/mailbox/cassandra/mail/CassandraACLMapper.java b/mailbox/cassandra/src/main/java/org/apache/james/mailbox/cassandra/mail/CassandraACLMapper.java
index dd6f6cd..9fb8bbb 100644
--- a/mailbox/cassandra/src/main/java/org/apache/james/mailbox/cassandra/mail/CassandraACLMapper.java
+++ b/mailbox/cassandra/src/main/java/org/apache/james/mailbox/cassandra/mail/CassandraACLMapper.java
@@ -150,7 +150,7 @@ public class CassandraACLMapper {
     }
 
     private Mono<Row> getStoredACLRow(CassandraId cassandraId) {
-        return executor.executeSingleRowReactor(
+        return executor.executeSingleRow(
             readStatement.bind()
                 .setUUID(CassandraACLTable.ID, cassandraId.asUuid()));
     }
diff --git a/mailbox/cassandra/src/main/java/org/apache/james/mailbox/cassandra/mail/CassandraApplicableFlagDAO.java b/mailbox/cassandra/src/main/java/org/apache/james/mailbox/cassandra/mail/CassandraApplicableFlagDAO.java
index 4820e83..952ef7f 100644
--- a/mailbox/cassandra/src/main/java/org/apache/james/mailbox/cassandra/mail/CassandraApplicableFlagDAO.java
+++ b/mailbox/cassandra/src/main/java/org/apache/james/mailbox/cassandra/mail/CassandraApplicableFlagDAO.java
@@ -61,7 +61,7 @@ public class CassandraApplicableFlagDAO {
     }
 
     public Mono<Flags> retrieveApplicableFlag(CassandraId mailboxId) {
-        return cassandraAsyncExecutor.executeSingleRowReactor(
+        return cassandraAsyncExecutor.executeSingleRow(
             select.bind()
                 .setUUID(MAILBOX_ID, mailboxId.asUuid()))
             .map(row -> new FlagsExtractor(row).getApplicableFlags());
@@ -71,7 +71,7 @@ public class CassandraApplicableFlagDAO {
         if (toBeAdded.isEmpty()) {
             return Mono.empty();
         }
-        return cassandraAsyncExecutor.executeVoidReactor(updateQuery(cassandraId, toBeAdded));
+        return cassandraAsyncExecutor.executeVoid(updateQuery(cassandraId, toBeAdded));
     }
 
     private Update.Where updateQuery(CassandraId cassandraId, Set<String> userFlags) {
diff --git a/mailbox/cassandra/src/main/java/org/apache/james/mailbox/cassandra/mail/CassandraAttachmentDAO.java b/mailbox/cassandra/src/main/java/org/apache/james/mailbox/cassandra/mail/CassandraAttachmentDAO.java
index de98abb..b5f8ec7 100644
--- a/mailbox/cassandra/src/main/java/org/apache/james/mailbox/cassandra/mail/CassandraAttachmentDAO.java
+++ b/mailbox/cassandra/src/main/java/org/apache/james/mailbox/cassandra/mail/CassandraAttachmentDAO.java
@@ -33,8 +33,6 @@ import static org.apache.james.mailbox.cassandra.table.CassandraAttachmentTable.
 
 import java.io.IOException;
 import java.nio.ByteBuffer;
-import java.util.concurrent.CompletableFuture;
-import java.util.stream.Stream;
 
 import javax.inject.Inject;
 
@@ -48,6 +46,7 @@ import com.datastax.driver.core.PreparedStatement;
 import com.datastax.driver.core.Row;
 import com.datastax.driver.core.Session;
 import com.google.common.base.Preconditions;
+import reactor.core.publisher.Flux;
 import reactor.core.publisher.Mono;
 
 public class CassandraAttachmentDAO {
@@ -101,23 +100,22 @@ public class CassandraAttachmentDAO {
 
     public Mono<Attachment> getAttachment(AttachmentId attachmentId) {
         Preconditions.checkArgument(attachmentId != null);
-        return cassandraAsyncExecutor.executeSingleRowReactor(
+        return cassandraAsyncExecutor.executeSingleRow(
             selectStatement.bind()
                 .setString(ID, attachmentId.getId()))
             .map(this::attachment);
     }
 
-    public Stream<Attachment> retrieveAll() {
-        return cassandraUtils.convertToStream(
-            cassandraAsyncExecutor.execute(
+    public Flux<Attachment> retrieveAll() {
+        return cassandraAsyncExecutor.execute(
                 selectAllStatement.bind()
                     .setReadTimeoutMillis(configuration.getAttachmentV2MigrationReadTimeout())
                     .setFetchSize(1))
-                .join())
+            .flatMapMany(Flux::fromIterable)
             .map(this::attachment);
     }
 
-    public CompletableFuture<Void> storeAttachment(Attachment attachment) throws IOException {
+    public Mono<Void> storeAttachment(Attachment attachment) throws IOException {
         return cassandraAsyncExecutor.executeVoid(
             insertStatement.bind()
                 .setString(ID, attachment.getAttachmentId().getId())
@@ -127,7 +125,7 @@ public class CassandraAttachmentDAO {
     }
 
     public Mono<Void> deleteAttachment(AttachmentId attachmentId) {
-        return cassandraAsyncExecutor.executeVoidReactor(
+        return cassandraAsyncExecutor.executeVoid(
             deleteStatement
                 .bind()
                 .setString(ID, attachmentId.getId()));
diff --git a/mailbox/cassandra/src/main/java/org/apache/james/mailbox/cassandra/mail/CassandraAttachmentDAOV2.java b/mailbox/cassandra/src/main/java/org/apache/james/mailbox/cassandra/mail/CassandraAttachmentDAOV2.java
index 38b6e21..f0871bf 100644
--- a/mailbox/cassandra/src/main/java/org/apache/james/mailbox/cassandra/mail/CassandraAttachmentDAOV2.java
+++ b/mailbox/cassandra/src/main/java/org/apache/james/mailbox/cassandra/mail/CassandraAttachmentDAOV2.java
@@ -151,14 +151,14 @@ public class CassandraAttachmentDAOV2 {
 
     public Mono<DAOAttachment> getAttachment(AttachmentId attachmentId) {
         Preconditions.checkArgument(attachmentId != null);
-        return cassandraAsyncExecutor.executeSingleRowReactor(
+        return cassandraAsyncExecutor.executeSingleRow(
             selectStatement.bind()
                 .setUUID(ID_AS_UUID, attachmentId.asUUID()))
             .map(row -> CassandraAttachmentDAOV2.fromRow(row, blobIdFactory));
     }
 
     public Mono<Void> storeAttachment(DAOAttachment attachment) {
-        return cassandraAsyncExecutor.executeVoidReactor(
+        return cassandraAsyncExecutor.executeVoid(
             insertStatement.bind()
                 .setUUID(ID_AS_UUID, attachment.getAttachmentId().asUUID())
                 .setString(ID, attachment.getAttachmentId().getId())
diff --git a/mailbox/cassandra/src/main/java/org/apache/james/mailbox/cassandra/mail/CassandraAttachmentMapper.java b/mailbox/cassandra/src/main/java/org/apache/james/mailbox/cassandra/mail/CassandraAttachmentMapper.java
index 71afb7d..c61aeb2 100644
--- a/mailbox/cassandra/src/main/java/org/apache/james/mailbox/cassandra/mail/CassandraAttachmentMapper.java
+++ b/mailbox/cassandra/src/main/java/org/apache/james/mailbox/cassandra/mail/CassandraAttachmentMapper.java
@@ -87,7 +87,7 @@ public class CassandraAttachmentMapper implements AttachmentMapper {
         Preconditions.checkArgument(attachmentIds != null);
         return Flux.fromIterable(attachmentIds)
             .flatMap(this::getAttachmentsAsMono)
-            .collectList()
+            .collect(Guavate.toImmutableList())
             .block();
     }
 
@@ -126,12 +126,13 @@ public class CassandraAttachmentMapper implements AttachmentMapper {
     @Override
     public Collection<MessageId> getRelatedMessageIds(AttachmentId attachmentId) throws MailboxException {
         return attachmentMessageIdDAO.getOwnerMessageIds(attachmentId)
-            .join();
+            .collect(Guavate.toImmutableList())
+            .block();
     }
 
     @Override
     public Collection<Username> getOwners(AttachmentId attachmentId) throws MailboxException {
-        return ownerDAO.retrieveOwners(attachmentId).join().collect(Guavate.toImmutableList());
+        return ownerDAO.retrieveOwners(attachmentId).collect(Guavate.toImmutableList()).block();
     }
 
     public Mono<Void> storeAttachmentAsync(Attachment attachment, MessageId ownerMessageId) {
diff --git a/mailbox/cassandra/src/main/java/org/apache/james/mailbox/cassandra/mail/CassandraAttachmentMessageIdDAO.java b/mailbox/cassandra/src/main/java/org/apache/james/mailbox/cassandra/mail/CassandraAttachmentMessageIdDAO.java
index 3f02c1a..c10509f 100644
--- a/mailbox/cassandra/src/main/java/org/apache/james/mailbox/cassandra/mail/CassandraAttachmentMessageIdDAO.java
+++ b/mailbox/cassandra/src/main/java/org/apache/james/mailbox/cassandra/mail/CassandraAttachmentMessageIdDAO.java
@@ -29,21 +29,17 @@ import static org.apache.james.mailbox.cassandra.table.CassandraAttachmentMessag
 import static org.apache.james.mailbox.cassandra.table.CassandraAttachmentMessageIdTable.MESSAGE_ID;
 import static org.apache.james.mailbox.cassandra.table.CassandraAttachmentMessageIdTable.TABLE_NAME;
 
-import java.util.Collection;
-import java.util.concurrent.CompletableFuture;
-
 import javax.inject.Inject;
 
 import org.apache.james.backends.cassandra.utils.CassandraAsyncExecutor;
-import org.apache.james.backends.cassandra.utils.CassandraUtils;
 import org.apache.james.mailbox.model.AttachmentId;
 import org.apache.james.mailbox.model.MessageId;
 
 import com.datastax.driver.core.PreparedStatement;
 import com.datastax.driver.core.Row;
 import com.datastax.driver.core.Session;
-import com.github.steveash.guavate.Guavate;
 import com.google.common.base.Preconditions;
+import reactor.core.publisher.Flux;
 import reactor.core.publisher.Mono;
 
 public class CassandraAttachmentMessageIdDAO {
@@ -52,12 +48,10 @@ public class CassandraAttachmentMessageIdDAO {
     private final PreparedStatement insertStatement;
     private final PreparedStatement selectStatement;
     private final MessageId.Factory messageIdFactory;
-    private final CassandraUtils cassandraUtils;
 
     @Inject
-    public CassandraAttachmentMessageIdDAO(Session session, MessageId.Factory messageIdFactory, CassandraUtils cassandraUtils) {
+    public CassandraAttachmentMessageIdDAO(Session session, MessageId.Factory messageIdFactory) {
         this.messageIdFactory = messageIdFactory;
-        this.cassandraUtils = cassandraUtils;
         this.cassandraAsyncExecutor = new CassandraAsyncExecutor(session);
 
         this.selectStatement = prepareSelect(session);
@@ -78,14 +72,13 @@ public class CassandraAttachmentMessageIdDAO {
             .where(eq(ATTACHMENT_ID_AS_UUID, bindMarker(ATTACHMENT_ID_AS_UUID))));
     }
 
-    public CompletableFuture<Collection<MessageId>> getOwnerMessageIds(AttachmentId attachmentId) {
+    public Flux<MessageId> getOwnerMessageIds(AttachmentId attachmentId) {
         Preconditions.checkArgument(attachmentId != null);
         return cassandraAsyncExecutor.execute(
-            selectStatement.bind()
-                .setUUID(ATTACHMENT_ID_AS_UUID, attachmentId.asUUID()))
-            .thenApply(resultSet -> cassandraUtils.convertToStream(resultSet)
-                .map(this::rowToMessageId)
-                .collect(Guavate.toImmutableSet()));
+                selectStatement.bind()
+                    .setUUID(ATTACHMENT_ID_AS_UUID, attachmentId.asUUID()))
+            .flatMapMany(Flux::fromIterable)
+            .map(this::rowToMessageId);
     }
 
     private MessageId rowToMessageId(Row row) {
@@ -93,7 +86,7 @@ public class CassandraAttachmentMessageIdDAO {
     }
 
     public Mono<Void> storeAttachmentForMessageId(AttachmentId attachmentId, MessageId ownerMessageId) {
-        return cassandraAsyncExecutor.executeVoidReactor(
+        return cassandraAsyncExecutor.executeVoid(
             insertStatement.bind()
                 .setUUID(ATTACHMENT_ID_AS_UUID, attachmentId.asUUID())
                 .setString(ATTACHMENT_ID, attachmentId.getId())
diff --git a/mailbox/cassandra/src/main/java/org/apache/james/mailbox/cassandra/mail/CassandraAttachmentOwnerDAO.java b/mailbox/cassandra/src/main/java/org/apache/james/mailbox/cassandra/mail/CassandraAttachmentOwnerDAO.java
index fce332d..d3c6b65 100644
--- a/mailbox/cassandra/src/main/java/org/apache/james/mailbox/cassandra/mail/CassandraAttachmentOwnerDAO.java
+++ b/mailbox/cassandra/src/main/java/org/apache/james/mailbox/cassandra/mail/CassandraAttachmentOwnerDAO.java
@@ -28,35 +28,30 @@ import static org.apache.james.mailbox.cassandra.table.CassandraAttachmentOwnerT
 import static org.apache.james.mailbox.cassandra.table.CassandraAttachmentOwnerTable.OWNER;
 import static org.apache.james.mailbox.cassandra.table.CassandraAttachmentOwnerTable.TABLE_NAME;
 
-import java.util.concurrent.CompletableFuture;
-import java.util.stream.Stream;
-
 import javax.inject.Inject;
 
 import org.apache.james.backends.cassandra.utils.CassandraAsyncExecutor;
-import org.apache.james.backends.cassandra.utils.CassandraUtils;
 import org.apache.james.mailbox.model.AttachmentId;
 import org.apache.james.mailbox.store.mail.model.Username;
 
 import com.datastax.driver.core.PreparedStatement;
 import com.datastax.driver.core.Row;
 import com.datastax.driver.core.Session;
+import reactor.core.publisher.Flux;
 import reactor.core.publisher.Mono;
 
 public class CassandraAttachmentOwnerDAO {
 
     private final CassandraAsyncExecutor executor;
     private final PreparedStatement addStatement;
-    private final CassandraUtils cassandraUtils;
     private final PreparedStatement selectStatement;
 
     @Inject
-    public CassandraAttachmentOwnerDAO(Session session, CassandraUtils cassandraUtils) {
+    public CassandraAttachmentOwnerDAO(Session session) {
         this.executor = new CassandraAsyncExecutor(session);
 
         this.selectStatement = prepareSelect(session);
         this.addStatement = prepareAdd(session);
-        this.cassandraUtils = cassandraUtils;
     }
 
     private PreparedStatement prepareAdd(Session session) {
@@ -74,22 +69,21 @@ public class CassandraAttachmentOwnerDAO {
     }
 
     public Mono<Void> addOwner(AttachmentId attachmentId, Username owner) {
-        return executor.executeVoidReactor(
+        return executor.executeVoid(
             addStatement.bind()
                 .setUUID(ID, attachmentId.asUUID())
                 .setString(OWNER, owner.getValue()));
     }
 
-    public CompletableFuture<Stream<Username>> retrieveOwners(AttachmentId attachmentId) {
+    public Flux<Username> retrieveOwners(AttachmentId attachmentId) {
         return executor.execute(
-            selectStatement.bind()
-                .setUUID(ID, attachmentId.asUUID()))
-            .thenApply(cassandraUtils::convertToStream)
-            .thenApply(this::toOwners);
+                selectStatement.bind()
+                    .setUUID(ID, attachmentId.asUUID()))
+            .flatMapMany(Flux::fromIterable)
+            .map(this::toOwner);
     }
 
-    private Stream<Username> toOwners(Stream<Row> stream) {
-        return stream.map(row -> row.getString(OWNER))
-            .map(Username::fromRawValue);
+    private Username toOwner(Row row) {
+        return Username.fromRawValue(row.getString(OWNER));
     }
 }
diff --git a/mailbox/cassandra/src/main/java/org/apache/james/mailbox/cassandra/mail/CassandraDeletedMessageDAO.java b/mailbox/cassandra/src/main/java/org/apache/james/mailbox/cassandra/mail/CassandraDeletedMessageDAO.java
index 4b5da30..0ab4085 100644
--- a/mailbox/cassandra/src/main/java/org/apache/james/mailbox/cassandra/mail/CassandraDeletedMessageDAO.java
+++ b/mailbox/cassandra/src/main/java/org/apache/james/mailbox/cassandra/mail/CassandraDeletedMessageDAO.java
@@ -118,14 +118,14 @@ public class CassandraDeletedMessageDAO {
     }
 
     public Mono<Void> addDeleted(CassandraId cassandraId, MessageUid uid) {
-        return cassandraAsyncExecutor.executeVoidReactor(
+        return cassandraAsyncExecutor.executeVoid(
             addStatement.bind()
                 .setUUID(MAILBOX_ID, cassandraId.asUuid())
                 .setLong(UID, uid.asLong()));
     }
 
     public Mono<Void> removeDeleted(CassandraId cassandraId, MessageUid uid) {
-        return cassandraAsyncExecutor.executeVoidReactor(deleteStatement.bind()
+        return cassandraAsyncExecutor.executeVoid(deleteStatement.bind()
             .setUUID(MAILBOX_ID, cassandraId.asUuid())
             .setLong(UID, uid.asLong()));
     }
@@ -157,20 +157,20 @@ public class CassandraDeletedMessageDAO {
     }
 
     private Mono<ResultSet> retrieveAllDeleted(CassandraId cassandraId) {
-        return cassandraAsyncExecutor.executeReactor(
+        return cassandraAsyncExecutor.execute(
             selectAllUidStatement.bind()
                 .setUUID(MAILBOX_ID, cassandraId.asUuid()));
     }
 
     private Mono<ResultSet> retrieveOneDeleted(CassandraId cassandraId, MessageUid uid) {
-        return cassandraAsyncExecutor.executeReactor(
+        return cassandraAsyncExecutor.execute(
             selectOneUidStatement.bind()
                 .setUUID(MAILBOX_ID, cassandraId.asUuid())
                 .setLong(UID, uid.asLong()));
     }
 
     private Mono<ResultSet> retrieveDeletedBetween(CassandraId cassandraId, MessageUid from, MessageUid to) {
-        return cassandraAsyncExecutor.executeReactor(
+        return cassandraAsyncExecutor.execute(
             selectBetweenUidStatement.bind()
                 .setUUID(MAILBOX_ID, cassandraId.asUuid())
                 .setLong(UID_FROM, from.asLong())
@@ -178,7 +178,7 @@ public class CassandraDeletedMessageDAO {
     }
 
     private Mono<ResultSet> retrieveDeletedAfter(CassandraId cassandraId, MessageUid from) {
-        return cassandraAsyncExecutor.executeReactor(
+        return cassandraAsyncExecutor.execute(
             selectFromUidStatement.bind()
                 .setUUID(MAILBOX_ID, cassandraId.asUuid())
                 .setLong(UID_FROM, from.asLong()));
diff --git a/mailbox/cassandra/src/main/java/org/apache/james/mailbox/cassandra/mail/CassandraFirstUnseenDAO.java b/mailbox/cassandra/src/main/java/org/apache/james/mailbox/cassandra/mail/CassandraFirstUnseenDAO.java
index 50ec510..be0cdc3 100644
--- a/mailbox/cassandra/src/main/java/org/apache/james/mailbox/cassandra/mail/CassandraFirstUnseenDAO.java
+++ b/mailbox/cassandra/src/main/java/org/apache/james/mailbox/cassandra/mail/CassandraFirstUnseenDAO.java
@@ -75,20 +75,20 @@ public class CassandraFirstUnseenDAO {
     }
 
     public Mono<Void> addUnread(CassandraId cassandraId, MessageUid uid) {
-        return cassandraAsyncExecutor.executeVoidReactor(
+        return cassandraAsyncExecutor.executeVoid(
             addStatement.bind()
                 .setUUID(MAILBOX_ID, cassandraId.asUuid())
                 .setLong(UID, uid.asLong()));
     }
 
     public Mono<Void> removeUnread(CassandraId cassandraId, MessageUid uid) {
-        return cassandraAsyncExecutor.executeVoidReactor(deleteStatement.bind()
+        return cassandraAsyncExecutor.executeVoid(deleteStatement.bind()
             .setUUID(MAILBOX_ID, cassandraId.asUuid())
             .setLong(UID, uid.asLong()));
     }
 
     public Mono<MessageUid> retrieveFirstUnread(CassandraId cassandraId) {
-        return cassandraAsyncExecutor.executeSingleRowReactor(
+        return cassandraAsyncExecutor.executeSingleRow(
             readStatement.bind()
                 .setUUID(MAILBOX_ID, cassandraId.asUuid()))
             .map(row -> MessageUid.of(row.getLong(UID)));
diff --git a/mailbox/cassandra/src/main/java/org/apache/james/mailbox/cassandra/mail/CassandraMailboxCounterDAO.java b/mailbox/cassandra/src/main/java/org/apache/james/mailbox/cassandra/mail/CassandraMailboxCounterDAO.java
index 5f2dec0..a9d1a13 100644
--- a/mailbox/cassandra/src/main/java/org/apache/james/mailbox/cassandra/mail/CassandraMailboxCounterDAO.java
+++ b/mailbox/cassandra/src/main/java/org/apache/james/mailbox/cassandra/mail/CassandraMailboxCounterDAO.java
@@ -77,7 +77,7 @@ public class CassandraMailboxCounterDAO {
     public Mono<MailboxCounters> retrieveMailboxCounters(Mailbox mailbox) throws MailboxException {
         CassandraId mailboxId = (CassandraId) mailbox.getMailboxId();
 
-        return cassandraAsyncExecutor.executeSingleRowReactor(bindWithMailbox(mailboxId, readStatement))
+        return cassandraAsyncExecutor.executeSingleRow(bindWithMailbox(mailboxId, readStatement))
             .map(row ->  MailboxCounters.builder()
                 .count(row.getLong(CassandraMailboxCountersTable.COUNT))
                 .unseen(row.getLong(CassandraMailboxCountersTable.UNSEEN))
@@ -91,31 +91,31 @@ public class CassandraMailboxCounterDAO {
     }
 
     public Mono<Long> countMessagesInMailbox(CassandraId cassandraId) {
-        return cassandraAsyncExecutor.executeSingleRowReactor(bindWithMailbox(cassandraId, readStatement))
+        return cassandraAsyncExecutor.executeSingleRow(bindWithMailbox(cassandraId, readStatement))
             .map(row -> row.getLong(CassandraMailboxCountersTable.COUNT));
     }
 
     public Mono<Long> countUnseenMessagesInMailbox(Mailbox mailbox) throws MailboxException {
         CassandraId mailboxId = (CassandraId) mailbox.getMailboxId();
 
-        return cassandraAsyncExecutor.executeSingleRowReactor(bindWithMailbox(mailboxId, readStatement))
+        return cassandraAsyncExecutor.executeSingleRow(bindWithMailbox(mailboxId, readStatement))
             .map(row -> row.getLong(CassandraMailboxCountersTable.UNSEEN));
     }
 
     public Mono<Void> decrementCount(CassandraId mailboxId) {
-        return cassandraAsyncExecutor.executeVoidReactor(bindWithMailbox(mailboxId, decrementMessageCountStatement));
+        return cassandraAsyncExecutor.executeVoid(bindWithMailbox(mailboxId, decrementMessageCountStatement));
     }
 
     public Mono<Void> incrementCount(CassandraId mailboxId) {
-        return cassandraAsyncExecutor.executeVoidReactor(bindWithMailbox(mailboxId, incrementMessageCountStatement));
+        return cassandraAsyncExecutor.executeVoid(bindWithMailbox(mailboxId, incrementMessageCountStatement));
     }
 
     public Mono<Void> decrementUnseen(CassandraId mailboxId) {
-        return cassandraAsyncExecutor.executeVoidReactor(bindWithMailbox(mailboxId, decrementUnseenCountStatement));
+        return cassandraAsyncExecutor.executeVoid(bindWithMailbox(mailboxId, decrementUnseenCountStatement));
     }
 
     public Mono<Void> incrementUnseen(CassandraId mailboxId) {
-        return cassandraAsyncExecutor.executeVoidReactor(bindWithMailbox(mailboxId, incrementUnseenCountStatement));
+        return cassandraAsyncExecutor.executeVoid(bindWithMailbox(mailboxId, incrementUnseenCountStatement));
     }
 
     private BoundStatement bindWithMailbox(CassandraId mailboxId, PreparedStatement statement) {
diff --git a/mailbox/cassandra/src/main/java/org/apache/james/mailbox/cassandra/mail/CassandraMailboxDAO.java b/mailbox/cassandra/src/main/java/org/apache/james/mailbox/cassandra/mail/CassandraMailboxDAO.java
index 7e75099..1be493b 100644
--- a/mailbox/cassandra/src/main/java/org/apache/james/mailbox/cassandra/mail/CassandraMailboxDAO.java
+++ b/mailbox/cassandra/src/main/java/org/apache/james/mailbox/cassandra/mail/CassandraMailboxDAO.java
@@ -32,8 +32,6 @@ import static org.apache.james.mailbox.cassandra.table.CassandraMailboxTable.NAM
 import static org.apache.james.mailbox.cassandra.table.CassandraMailboxTable.TABLE_NAME;
 import static org.apache.james.mailbox.cassandra.table.CassandraMailboxTable.UIDVALIDITY;
 
-import java.util.concurrent.CompletableFuture;
-
 import javax.inject.Inject;
 
 import org.apache.james.backends.cassandra.init.CassandraTypesProvider;
@@ -114,14 +112,14 @@ public class CassandraMailboxDAO {
 
     public Mono<Void> save(Mailbox mailbox) {
         CassandraId cassandraId = (CassandraId) mailbox.getMailboxId();
-        return executor.executeVoidReactor(insertStatement.bind()
+        return executor.executeVoid(insertStatement.bind()
             .setUUID(ID, cassandraId.asUuid())
             .setString(NAME, mailbox.getName())
             .setLong(UIDVALIDITY, mailbox.getUidValidity())
             .setUDTValue(MAILBOX_BASE, mailboxBaseTupleUtil.createMailboxBaseUDT(mailbox.getNamespace(), mailbox.getUser())));
     }
 
-    public CompletableFuture<Void> updatePath(CassandraId mailboxId, MailboxPath mailboxPath) {
+    public Mono<Void> updatePath(CassandraId mailboxId, MailboxPath mailboxPath) {
         return executor.executeVoid(updateStatement.bind()
             .setUUID(ID, mailboxId.asUuid())
             .setString(NAME, mailboxPath.getName())
@@ -129,12 +127,12 @@ public class CassandraMailboxDAO {
     }
 
     public Mono<Void> delete(CassandraId mailboxId) {
-        return executor.executeVoidReactor(deleteStatement.bind()
+        return executor.executeVoid(deleteStatement.bind()
             .setUUID(ID, mailboxId.asUuid()));
     }
 
     public Mono<SimpleMailbox> retrieveMailbox(CassandraId mailboxId) {
-        return executor.executeSingleRowReactor(readStatement.bind()
+        return executor.executeSingleRow(readStatement.bind()
             .setUUID(ID, mailboxId.asUuid()))
             .map(this::mailboxFromRow)
             .map(mailbox -> addMailboxId(mailboxId, mailbox));
@@ -155,7 +153,7 @@ public class CassandraMailboxDAO {
     }
 
     public Flux<SimpleMailbox> retrieveAllMailboxes() {
-        return executor.executeReactor(listStatement.bind())
+        return executor.execute(listStatement.bind())
             .flatMapMany(cassandraUtils::convertToFlux)
             .map(this::toMailboxWithId);
     }
diff --git a/mailbox/cassandra/src/main/java/org/apache/james/mailbox/cassandra/mail/CassandraMailboxMapper.java b/mailbox/cassandra/src/main/java/org/apache/james/mailbox/cassandra/mail/CassandraMailboxMapper.java
index 058d6fe..484d95b 100644
--- a/mailbox/cassandra/src/main/java/org/apache/james/mailbox/cassandra/mail/CassandraMailboxMapper.java
+++ b/mailbox/cassandra/src/main/java/org/apache/james/mailbox/cassandra/mail/CassandraMailboxMapper.java
@@ -123,10 +123,10 @@ public class CassandraMailboxMapper implements MailboxMapper {
     }
 
     private Mono<SimpleMailbox> retrieveMailbox(CassandraId mailboxId) {
-        Mono<MailboxACL> aclCompletableFuture = cassandraACLMapper.getACL(mailboxId);
-        Mono<SimpleMailbox> simpleMailboxFuture = mailboxDAO.retrieveMailbox(mailboxId);
+        Mono<MailboxACL> acl = cassandraACLMapper.getACL(mailboxId);
+        Mono<SimpleMailbox> simpleMailbox = mailboxDAO.retrieveMailbox(mailboxId);
 
-        return aclCompletableFuture.zipWith(simpleMailboxFuture, this::addAcl);
+        return acl.zipWith(simpleMailbox, this::addAcl);
     }
 
     private SimpleMailbox addAcl(MailboxACL acl, SimpleMailbox mailbox) {
diff --git a/mailbox/cassandra/src/main/java/org/apache/james/mailbox/cassandra/mail/CassandraMailboxPathDAOImpl.java b/mailbox/cassandra/src/main/java/org/apache/james/mailbox/cassandra/mail/CassandraMailboxPathDAOImpl.java
index 46975a0..aae4c7e 100644
--- a/mailbox/cassandra/src/main/java/org/apache/james/mailbox/cassandra/mail/CassandraMailboxPathDAOImpl.java
+++ b/mailbox/cassandra/src/main/java/org/apache/james/mailbox/cassandra/mail/CassandraMailboxPathDAOImpl.java
@@ -31,9 +31,6 @@ import static org.apache.james.mailbox.cassandra.table.CassandraMailboxPathTable
 import static org.apache.james.mailbox.cassandra.table.CassandraMailboxPathTable.NAMESPACE_AND_USER;
 import static org.apache.james.mailbox.cassandra.table.CassandraMailboxPathTable.TABLE_NAME;
 
-import java.util.concurrent.CompletableFuture;
-import java.util.stream.Stream;
-
 import javax.inject.Inject;
 
 import org.apache.james.backends.cassandra.init.CassandraTypesProvider;
@@ -126,7 +123,7 @@ public class CassandraMailboxPathDAOImpl implements CassandraMailboxPathDAO {
     }
 
     public Mono<CassandraIdAndPath> retrieveId(MailboxPath mailboxPath) {
-        return cassandraAsyncExecutor.executeSingleRowReactor(
+        return cassandraAsyncExecutor.executeSingleRow(
             select.bind()
                 .setUDTValue(NAMESPACE_AND_USER, mailboxBaseTupleUtil.createMailboxBaseUDT(mailboxPath.getNamespace(), mailboxPath.getUser()))
                 .setString(MAILBOX_NAME, mailboxPath.getName()))
@@ -137,7 +134,7 @@ public class CassandraMailboxPathDAOImpl implements CassandraMailboxPathDAO {
 
     @Override
     public Flux<CassandraIdAndPath> listUserMailboxes(String namespace, String user) {
-        return cassandraAsyncExecutor.executeReactor(
+        return cassandraAsyncExecutor.execute(
             selectAllForUser.bind()
                 .setUDTValue(NAMESPACE_AND_USER, mailboxBaseTupleUtil.createMailboxBaseUDT(namespace, user)))
             .flatMapMany(resultSet -> cassandraUtils.convertToFlux(resultSet)
@@ -197,20 +194,20 @@ public class CassandraMailboxPathDAOImpl implements CassandraMailboxPathDAO {
 
     @Override
     public Mono<Void> delete(MailboxPath mailboxPath) {
-        return cassandraAsyncExecutor.executeVoidReactor(delete.bind()
+        return cassandraAsyncExecutor.executeVoid(delete.bind()
             .setUDTValue(NAMESPACE_AND_USER, mailboxBaseTupleUtil.createMailboxBaseUDT(mailboxPath.getNamespace(), mailboxPath.getUser()))
             .setString(MAILBOX_NAME, mailboxPath.getName()));
     }
 
-    public CompletableFuture<Stream<CassandraIdAndPath>> readAll() {
+    public Flux<CassandraIdAndPath> readAll() {
         return cassandraAsyncExecutor.execute(selectAll.bind())
-            .thenApply(cassandraUtils::convertToStream)
-            .thenApply(stream -> stream.map(this::fromRowToCassandraIdAndPath));
+            .flatMapMany(Flux::fromIterable)
+            .map(this::fromRowToCassandraIdAndPath);
     }
 
-    public CompletableFuture<Long> countAll() {
-        return cassandraAsyncExecutor.executeSingleRow(countAll.bind())
-            .thenApply(optional -> optional.map(row -> row.getLong(FIRST_CELL)).orElse(0L));
+    public Mono<Long> countAll() {
+        return cassandraAsyncExecutor.executeSingleRowOptional(countAll.bind())
+            .map(optional -> optional.map(row -> row.getLong(FIRST_CELL)).orElse(0L));
     }
 
 }
diff --git a/mailbox/cassandra/src/main/java/org/apache/james/mailbox/cassandra/mail/CassandraMailboxPathV2DAO.java b/mailbox/cassandra/src/main/java/org/apache/james/mailbox/cassandra/mail/CassandraMailboxPathV2DAO.java
index 2247c66..1e5653c 100644
--- a/mailbox/cassandra/src/main/java/org/apache/james/mailbox/cassandra/mail/CassandraMailboxPathV2DAO.java
+++ b/mailbox/cassandra/src/main/java/org/apache/james/mailbox/cassandra/mail/CassandraMailboxPathV2DAO.java
@@ -102,7 +102,7 @@ public class CassandraMailboxPathV2DAO implements CassandraMailboxPathDAO {
 
     @Override
     public Mono<CassandraIdAndPath> retrieveId(MailboxPath mailboxPath) {
-        return cassandraAsyncExecutor.executeSingleRowReactor(
+        return cassandraAsyncExecutor.executeSingleRow(
             select.bind()
                 .setString(NAMESPACE, mailboxPath.getNamespace())
                 .setString(USER, sanitizeUser(mailboxPath.getUser()))
@@ -114,7 +114,7 @@ public class CassandraMailboxPathV2DAO implements CassandraMailboxPathDAO {
 
     @Override
     public Flux<CassandraIdAndPath> listUserMailboxes(String namespace, String user) {
-        return cassandraAsyncExecutor.executeReactor(
+        return cassandraAsyncExecutor.execute(
             selectAll.bind()
                 .setString(NAMESPACE, namespace)
                 .setString(USER, sanitizeUser(user)))
@@ -175,7 +175,7 @@ public class CassandraMailboxPathV2DAO implements CassandraMailboxPathDAO {
 
     @Override
     public Mono<Void> delete(MailboxPath mailboxPath) {
-        return cassandraAsyncExecutor.executeVoidReactor(delete.bind()
+        return cassandraAsyncExecutor.executeVoid(delete.bind()
             .setString(NAMESPACE, mailboxPath.getNamespace())
             .setString(USER, sanitizeUser(mailboxPath.getUser()))
             .setString(MAILBOX_NAME, mailboxPath.getName()));
diff --git a/mailbox/cassandra/src/main/java/org/apache/james/mailbox/cassandra/mail/CassandraMailboxRecentsDAO.java b/mailbox/cassandra/src/main/java/org/apache/james/mailbox/cassandra/mail/CassandraMailboxRecentsDAO.java
index 9a521d0..802e423 100644
--- a/mailbox/cassandra/src/main/java/org/apache/james/mailbox/cassandra/mail/CassandraMailboxRecentsDAO.java
+++ b/mailbox/cassandra/src/main/java/org/apache/james/mailbox/cassandra/mail/CassandraMailboxRecentsDAO.java
@@ -85,7 +85,7 @@ public class CassandraMailboxRecentsDAO {
     }
 
     public Flux<MessageUid> getRecentMessageUidsInMailbox(CassandraId mailboxId) {
-        return cassandraAsyncExecutor.executeReactor(bindWithMailbox(mailboxId, readStatement))
+        return cassandraAsyncExecutor.execute(bindWithMailbox(mailboxId, readStatement))
             .flatMapMany(cassandraUtils::convertToFlux)
             .map(row -> row.getLong(CassandraMailboxRecentsTable.RECENT_MESSAGE_UID))
             .map(MessageUid::of);
@@ -97,13 +97,13 @@ public class CassandraMailboxRecentsDAO {
     }
 
     public Mono<Void> removeFromRecent(CassandraId mailboxId, MessageUid messageUid) {
-        return cassandraAsyncExecutor.executeVoidReactor(deleteStatement.bind()
+        return cassandraAsyncExecutor.executeVoid(deleteStatement.bind()
             .setUUID(CassandraMailboxRecentsTable.MAILBOX_ID, mailboxId.asUuid())
             .setLong(CassandraMailboxRecentsTable.RECENT_MESSAGE_UID, messageUid.asLong()));
     }
 
     public Mono<Void> addToRecent(CassandraId mailboxId, MessageUid messageUid) {
-        return cassandraAsyncExecutor.executeVoidReactor(addStatement.bind()
+        return cassandraAsyncExecutor.executeVoid(addStatement.bind()
             .setUUID(CassandraMailboxRecentsTable.MAILBOX_ID, mailboxId.asUuid())
             .setLong(CassandraMailboxRecentsTable.RECENT_MESSAGE_UID, messageUid.asLong()));
     }
diff --git a/mailbox/cassandra/src/main/java/org/apache/james/mailbox/cassandra/mail/CassandraMessageDAO.java b/mailbox/cassandra/src/main/java/org/apache/james/mailbox/cassandra/mail/CassandraMessageDAO.java
index 2a277d3..beab767 100644
--- a/mailbox/cassandra/src/main/java/org/apache/james/mailbox/cassandra/mail/CassandraMessageDAO.java
+++ b/mailbox/cassandra/src/main/java/org/apache/james/mailbox/cassandra/mail/CassandraMessageDAO.java
@@ -45,7 +45,6 @@ import java.util.List;
 import java.util.Objects;
 import java.util.Optional;
 import java.util.Set;
-import java.util.concurrent.CompletableFuture;
 import java.util.stream.Collectors;
 import java.util.stream.Stream;
 
@@ -177,7 +176,7 @@ public class CassandraMessageDAO {
 
     public Mono<Void> save(MailboxMessage message) throws MailboxException {
         return saveContent(message)
-            .flatMap(pair -> cassandraAsyncExecutor.executeVoidReactor(boundWriteStatement(message, pair)))
+            .flatMap(pair -> cassandraAsyncExecutor.executeVoid(boundWriteStatement(message, pair)))
             .then();
     }
 
@@ -250,7 +249,7 @@ public class CassandraMessageDAO {
     private Mono<ResultSet> retrieveRow(ComposedMessageIdWithMetaData messageId, FetchType fetchType) {
         CassandraMessageId cassandraMessageId = (CassandraMessageId) messageId.getComposedMessageId().getMessageId();
 
-        return cassandraAsyncExecutor.executeReactor(retrieveSelect(fetchType)
+        return cassandraAsyncExecutor.execute(retrieveSelect(fetchType)
             .bind()
             .setUUID(MESSAGE_ID, cassandraMessageId.get()));
     }
@@ -331,7 +330,7 @@ public class CassandraMessageDAO {
         }
     }
 
-    public CompletableFuture<Void> delete(CassandraMessageId messageId) {
+    public Mono<Void> delete(CassandraMessageId messageId) {
         return cassandraAsyncExecutor.executeVoid(delete.bind()
             .setUUID(MESSAGE_ID, messageId.get()));
     }
@@ -399,13 +398,13 @@ public class CassandraMessageDAO {
         }
     }
 
-    public CompletableFuture<Stream<MessageIdAttachmentIds>> retrieveAllMessageIdAttachmentIds() {
+    public Flux<MessageIdAttachmentIds> retrieveAllMessageIdAttachmentIds() {
         return cassandraAsyncExecutor.execute(
             selectAllMessagesWithAttachment.bind()
                 .setReadTimeoutMillis(configuration.getMessageAttachmentIdsReadTimeout()))
-            .thenApply(resultSet -> cassandraUtils.convertToStream(resultSet)
-                .map(this::fromRow)
-                .filter(MessageIdAttachmentIds::hasAttachment));
+            .flatMapMany(Flux::fromIterable)
+            .map(this::fromRow)
+            .filter(MessageIdAttachmentIds::hasAttachment);
     }
 
     private MessageIdAttachmentIds fromRow(Row row) {
diff --git a/mailbox/cassandra/src/main/java/org/apache/james/mailbox/cassandra/mail/CassandraMessageIdDAO.java b/mailbox/cassandra/src/main/java/org/apache/james/mailbox/cassandra/mail/CassandraMessageIdDAO.java
index 9f8b4ad..9bfcd4e 100644
--- a/mailbox/cassandra/src/main/java/org/apache/james/mailbox/cassandra/mail/CassandraMessageIdDAO.java
+++ b/mailbox/cassandra/src/main/java/org/apache/james/mailbox/cassandra/mail/CassandraMessageIdDAO.java
@@ -43,8 +43,6 @@ import static org.apache.james.mailbox.cassandra.table.Flag.USER_FLAGS;
 import static org.apache.james.mailbox.cassandra.table.MessageIdToImapUid.MOD_SEQ;
 
 import java.util.Optional;
-import java.util.concurrent.CompletableFuture;
-import java.util.stream.Stream;
 
 import javax.inject.Inject;
 import javax.mail.Flags;
@@ -67,6 +65,7 @@ import com.datastax.driver.core.Session;
 import com.datastax.driver.core.querybuilder.QueryBuilder;
 import com.google.common.annotations.VisibleForTesting;
 import com.google.common.collect.ImmutableSet;
+import reactor.core.publisher.Flux;
 import reactor.core.publisher.Mono;
 
 public class CassandraMessageIdDAO {
@@ -171,7 +170,7 @@ public class CassandraMessageIdDAO {
     }
 
     public Mono<Void> delete(CassandraId mailboxId, MessageUid uid) {
-        return cassandraAsyncExecutor.executeVoidReactor(delete.bind()
+        return cassandraAsyncExecutor.executeVoid(delete.bind()
                 .setUUID(MAILBOX_ID, mailboxId.asUuid())
                 .setLong(IMAP_UID, uid.asLong()));
     }
@@ -179,7 +178,7 @@ public class CassandraMessageIdDAO {
     public Mono<Void> insert(ComposedMessageIdWithMetaData composedMessageIdWithMetaData) {
         ComposedMessageId composedMessageId = composedMessageIdWithMetaData.getComposedMessageId();
         Flags flags = composedMessageIdWithMetaData.getFlags();
-        return cassandraAsyncExecutor.executeVoidReactor(insert.bind()
+        return cassandraAsyncExecutor.executeVoid(insert.bind()
                 .setUUID(MAILBOX_ID, ((CassandraId) composedMessageId.getMailboxId()).asUuid())
                 .setLong(IMAP_UID, composedMessageId.getUid().asLong())
                 .setUUID(MESSAGE_ID, ((CassandraMessageId) composedMessageId.getMessageId()).get())
@@ -197,7 +196,7 @@ public class CassandraMessageIdDAO {
     public Mono<Void> updateMetadata(ComposedMessageIdWithMetaData composedMessageIdWithMetaData) {
         ComposedMessageId composedMessageId = composedMessageIdWithMetaData.getComposedMessageId();
         Flags flags = composedMessageIdWithMetaData.getFlags();
-        return cassandraAsyncExecutor.executeVoidReactor(update.bind()
+        return cassandraAsyncExecutor.executeVoid(update.bind()
                 .setLong(MOD_SEQ, composedMessageIdWithMetaData.getModSeq())
                 .setBool(ANSWERED, flags.contains(Flag.ANSWERED))
                 .setBool(DELETED, flags.contains(Flag.DELETED))
@@ -211,8 +210,8 @@ public class CassandraMessageIdDAO {
                 .setLong(IMAP_UID, composedMessageId.getUid().asLong()));
     }
 
-    public CompletableFuture<Optional<ComposedMessageIdWithMetaData>> retrieve(CassandraId mailboxId, MessageUid uid) {
-        return selectOneRow(mailboxId, uid).thenApply(this::asOptionalOfCassandraMessageId);
+    public Mono<Optional<ComposedMessageIdWithMetaData>> retrieve(CassandraId mailboxId, MessageUid uid) {
+        return selectOneRow(mailboxId, uid).map(this::asOptionalOfCassandraMessageId);
     }
 
     private Optional<ComposedMessageIdWithMetaData> asOptionalOfCassandraMessageId(ResultSet resultSet) {
@@ -222,13 +221,13 @@ public class CassandraMessageIdDAO {
         return Optional.of(fromRowToComposedMessageIdWithFlags(resultSet.one()));
     }
 
-    private CompletableFuture<ResultSet> selectOneRow(CassandraId mailboxId, MessageUid uid) {
+    private Mono<ResultSet> selectOneRow(CassandraId mailboxId, MessageUid uid) {
         return cassandraAsyncExecutor.execute(select.bind()
                 .setUUID(MAILBOX_ID, mailboxId.asUuid())
                 .setLong(IMAP_UID, uid.asLong()));
     }
 
-    public CompletableFuture<Stream<ComposedMessageIdWithMetaData>> retrieveMessages(CassandraId mailboxId, MessageRange set) {
+    public Flux<ComposedMessageIdWithMetaData> retrieveMessages(CassandraId mailboxId, MessageRange set) {
         switch (set.getType()) {
         case ALL:
             return toMessageIds(selectAll(mailboxId));
@@ -242,28 +241,28 @@ public class CassandraMessageIdDAO {
         throw new UnsupportedOperationException();
     }
 
-    private CompletableFuture<ResultSet> selectAll(CassandraId mailboxId) {
+    private Mono<ResultSet> selectAll(CassandraId mailboxId) {
         return cassandraAsyncExecutor.execute(selectAllUids.bind()
                 .setUUID(MAILBOX_ID, mailboxId.asUuid()));
     }
 
-    private CompletableFuture<ResultSet> selectFrom(CassandraId mailboxId, MessageUid uid) {
+    private Mono<ResultSet> selectFrom(CassandraId mailboxId, MessageUid uid) {
         return cassandraAsyncExecutor.execute(selectUidGte.bind()
                 .setUUID(MAILBOX_ID, mailboxId.asUuid())
                 .setLong(IMAP_UID, uid.asLong()));
     }
 
-    private CompletableFuture<ResultSet> selectRange(CassandraId mailboxId, MessageUid from, MessageUid to) {
+    private Mono<ResultSet> selectRange(CassandraId mailboxId, MessageUid from, MessageUid to) {
         return cassandraAsyncExecutor.execute(selectUidRange.bind()
                 .setUUID(MAILBOX_ID, mailboxId.asUuid())
                 .setLong(IMAP_UID_GTE, from.asLong())
                 .setLong(IMAP_UID_LTE, to.asLong()));
     }
 
-    private CompletableFuture<Stream<ComposedMessageIdWithMetaData>> toMessageIds(CompletableFuture<ResultSet> completableFuture) {
-        return completableFuture
-            .thenApply(resultSet -> cassandraUtils.convertToStream(resultSet)
-                .map(this::fromRowToComposedMessageIdWithFlags));
+    private Flux<ComposedMessageIdWithMetaData> toMessageIds(Mono<ResultSet> results) {
+        return results
+            .flatMapMany(Flux::fromIterable)
+            .map(this::fromRowToComposedMessageIdWithFlags);
     }
 
     private ComposedMessageIdWithMetaData fromRowToComposedMessageIdWithFlags(Row row) {
diff --git a/mailbox/cassandra/src/main/java/org/apache/james/mailbox/cassandra/mail/CassandraMessageIdToImapUidDAO.java b/mailbox/cassandra/src/main/java/org/apache/james/mailbox/cassandra/mail/CassandraMessageIdToImapUidDAO.java
index 4018a8c..95bf82c 100644
--- a/mailbox/cassandra/src/main/java/org/apache/james/mailbox/cassandra/mail/CassandraMessageIdToImapUidDAO.java
+++ b/mailbox/cassandra/src/main/java/org/apache/james/mailbox/cassandra/mail/CassandraMessageIdToImapUidDAO.java
@@ -149,7 +149,7 @@ public class CassandraMessageIdToImapUidDAO {
     }
 
     public Mono<Void> delete(CassandraMessageId messageId, CassandraId mailboxId) {
-        return cassandraAsyncExecutor.executeVoidReactor(delete.bind()
+        return cassandraAsyncExecutor.executeVoid(delete.bind()
                 .setUUID(MESSAGE_ID, messageId.get())
                 .setUUID(MAILBOX_ID, mailboxId.asUuid()));
     }
@@ -157,7 +157,7 @@ public class CassandraMessageIdToImapUidDAO {
     public Mono<Void> insert(ComposedMessageIdWithMetaData composedMessageIdWithMetaData) {
         ComposedMessageId composedMessageId = composedMessageIdWithMetaData.getComposedMessageId();
         Flags flags = composedMessageIdWithMetaData.getFlags();
-        return cassandraAsyncExecutor.executeVoidReactor(insert.bind()
+        return cassandraAsyncExecutor.executeVoid(insert.bind()
                 .setUUID(MESSAGE_ID, ((CassandraMessageId) composedMessageId.getMessageId()).get())
                 .setUUID(MAILBOX_ID, ((CassandraId) composedMessageId.getMailboxId()).asUuid())
                 .setLong(IMAP_UID, composedMessageId.getUid().asLong())
@@ -210,10 +210,10 @@ public class CassandraMessageIdToImapUidDAO {
 
     private Mono<ResultSet> selectStatement(CassandraMessageId messageId, Optional<CassandraId> mailboxId) {
         return mailboxId
-            .map(cassandraId -> cassandraAsyncExecutor.executeReactor(select.bind()
+            .map(cassandraId -> cassandraAsyncExecutor.execute(select.bind()
                 .setUUID(MESSAGE_ID, messageId.get())
                 .setUUID(MAILBOX_ID, cassandraId.asUuid())))
-            .orElseGet(() -> cassandraAsyncExecutor.executeReactor(selectAll.bind()
+            .orElseGet(() -> cassandraAsyncExecutor.execute(selectAll.bind()
                 .setUUID(MESSAGE_ID, messageId.get())));
     }
 }
diff --git a/mailbox/cassandra/src/main/java/org/apache/james/mailbox/cassandra/mail/CassandraMessageMapper.java b/mailbox/cassandra/src/main/java/org/apache/james/mailbox/cassandra/mail/CassandraMessageMapper.java
index aa1b869..ba66061 100644
--- a/mailbox/cassandra/src/main/java/org/apache/james/mailbox/cassandra/mail/CassandraMessageMapper.java
+++ b/mailbox/cassandra/src/main/java/org/apache/james/mailbox/cassandra/mail/CassandraMessageMapper.java
@@ -109,8 +109,8 @@ public class CassandraMessageMapper implements MessageMapper {
     public Iterator<MessageUid> listAllMessageUids(Mailbox mailbox) throws MailboxException {
         CassandraId cassandraId = (CassandraId) mailbox.getMailboxId();
         return messageIdDAO.retrieveMessages(cassandraId, MessageRange.all())
-            .join()
             .map(metaData -> metaData.getComposedMessageId().getUid())
+            .toIterable()
             .iterator();
     }
 
@@ -170,8 +170,8 @@ public class CassandraMessageMapper implements MessageMapper {
 
     private List<ComposedMessageIdWithMetaData> retrieveMessageIds(CassandraId mailboxId, MessageRange messageRange) {
         return messageIdDAO.retrieveMessages(mailboxId, messageRange)
-            .join()
-            .collect(Guavate.toImmutableList());
+            .collect(Guavate.toImmutableList())
+            .block();
     }
 
     private Flux<SimpleMailboxMessage> retrieveMessages(List<ComposedMessageIdWithMetaData> messageIds, FetchType fetchType, Limit limit) {
@@ -219,7 +219,7 @@ public class CassandraMessageMapper implements MessageMapper {
     }
 
     private Mono<ComposedMessageIdWithMetaData> retrieveComposedId(CassandraId mailboxId, MessageUid uid) {
-        return Mono.fromCompletionStage(messageIdDAO.retrieve(mailboxId, uid))
+        return messageIdDAO.retrieve(mailboxId, uid)
             .doOnNext(optional -> OptionalUtils.executeIfEmpty(optional,
                 () -> LOGGER.warn("Could not retrieve message {} {}", mailboxId, uid)))
             .flatMap(Mono::justOrEmpty);
@@ -272,8 +272,7 @@ public class CassandraMessageMapper implements MessageMapper {
     public Iterator<UpdatedFlags> updateFlags(Mailbox mailbox, FlagsUpdateCalculator flagUpdateCalculator, MessageRange range) throws MailboxException {
         CassandraId mailboxId = (CassandraId) mailbox.getMailboxId();
 
-        Flux<ComposedMessageIdWithMetaData> toBeUpdated = Mono.fromCompletionStage(messageIdDAO.retrieveMessages(mailboxId, range))
-            .flatMapMany(Flux::fromStream);
+        Flux<ComposedMessageIdWithMetaData> toBeUpdated = messageIdDAO.retrieveMessages(mailboxId, range);
 
         FlagsUpdateStageResult firstResult = runUpdateStage(mailboxId, toBeUpdated, flagUpdateCalculator).block();
         FlagsUpdateStageResult finalResult = handleUpdatesStagedRetry(mailboxId, flagUpdateCalculator, firstResult);
@@ -297,8 +296,7 @@ public class CassandraMessageMapper implements MessageMapper {
     private Mono<FlagsUpdateStageResult> retryUpdatesStage(CassandraId mailboxId, FlagsUpdateCalculator flagsUpdateCalculator, List<MessageUid> failed) {
         if (!failed.isEmpty()) {
             Flux<ComposedMessageIdWithMetaData> toUpdate = Flux.fromIterable(failed)
-                .flatMap(uid ->
-                    Mono.fromCompletionStage(messageIdDAO.retrieve(mailboxId, uid))
+                .flatMap(uid -> messageIdDAO.retrieve(mailboxId, uid)
                         .flatMap(Mono::justOrEmpty)
                 );
             return runUpdateStage(mailboxId, toUpdate, flagsUpdateCalculator);
diff --git a/mailbox/cassandra/src/main/java/org/apache/james/mailbox/cassandra/mail/CassandraModSeqProvider.java b/mailbox/cassandra/src/main/java/org/apache/james/mailbox/cassandra/mail/CassandraModSeqProvider.java
index 6f798c5..25347bb 100644
--- a/mailbox/cassandra/src/main/java/org/apache/james/mailbox/cassandra/mail/CassandraModSeqProvider.java
+++ b/mailbox/cassandra/src/main/java/org/apache/james/mailbox/cassandra/mail/CassandraModSeqProvider.java
@@ -145,7 +145,7 @@ public class CassandraModSeqProvider implements ModSeqProvider {
     }
 
     private Mono<Optional<ModSeq>> findHighestModSeq(CassandraId mailboxId) {
-        return cassandraAsyncExecutor.executeSingleRowOptionalReactor(
+        return cassandraAsyncExecutor.executeSingleRowOptional(
             select.bind()
                 .setUUID(MAILBOX_ID, mailboxId.asUuid()))
             .map(maybeRow -> maybeRow.map(row -> new ModSeq(row.getLong(NEXT_MODSEQ))));
diff --git a/mailbox/cassandra/src/main/java/org/apache/james/mailbox/cassandra/mail/CassandraUidProvider.java b/mailbox/cassandra/src/main/java/org/apache/james/mailbox/cassandra/mail/CassandraUidProvider.java
index bd3baac..6451619 100644
--- a/mailbox/cassandra/src/main/java/org/apache/james/mailbox/cassandra/mail/CassandraUidProvider.java
+++ b/mailbox/cassandra/src/main/java/org/apache/james/mailbox/cassandra/mail/CassandraUidProvider.java
@@ -116,7 +116,7 @@ public class CassandraUidProvider implements UidProvider {
     }
 
     private Mono<MessageUid> findHighestUid(CassandraId mailboxId) {
-        return Mono.defer(() -> executor.executeSingleRowReactor(
+        return Mono.defer(() -> executor.executeSingleRow(
             selectStatement.bind()
                 .setUUID(MAILBOX_ID, mailboxId.asUuid()))
             .map(row -> MessageUid.of(row.getLong(NEXT_UID))));
diff --git a/mailbox/cassandra/src/main/java/org/apache/james/mailbox/cassandra/mail/CassandraUserMailboxRightsDAO.java b/mailbox/cassandra/src/main/java/org/apache/james/mailbox/cassandra/mail/CassandraUserMailboxRightsDAO.java
index 4bfeafb..ff54813 100644
--- a/mailbox/cassandra/src/main/java/org/apache/james/mailbox/cassandra/mail/CassandraUserMailboxRightsDAO.java
+++ b/mailbox/cassandra/src/main/java/org/apache/james/mailbox/cassandra/mail/CassandraUserMailboxRightsDAO.java
@@ -28,7 +28,6 @@ import static org.apache.james.mailbox.cassandra.table.CassandraUserMailboxRight
 import static org.apache.james.mailbox.cassandra.table.CassandraUserMailboxRightsTable.USER_NAME;
 
 import java.util.Optional;
-import java.util.concurrent.CompletableFuture;
 import java.util.stream.Stream;
 
 import javax.inject.Inject;
@@ -108,7 +107,7 @@ public class CassandraUserMailboxRightsDAO {
 
     private Mono<Void> removeAll(CassandraId cassandraId, Stream<MailboxACL.Entry> removedEntries) {
         return Flux.fromStream(removedEntries)
-            .flatMap(entry -> cassandraAsyncExecutor.executeVoidReactor(
+            .flatMap(entry -> cassandraAsyncExecutor.executeVoid(
                 delete.bind()
                     .setString(USER_NAME, entry.getKey().getName())
                     .setUUID(MAILBOX_ID, cassandraId.asUuid())))
@@ -117,7 +116,7 @@ public class CassandraUserMailboxRightsDAO {
 
     private Mono<Void> addAll(CassandraId cassandraId, Stream<MailboxACL.Entry> addedEntries) {
         return Flux.fromStream(addedEntries)
-            .flatMap(entry -> cassandraAsyncExecutor.executeVoidReactor(
+            .flatMap(entry -> cassandraAsyncExecutor.executeVoid(
                 insert.bind()
                     .setString(USER_NAME, entry.getKey().getName())
                     .setUUID(MAILBOX_ID, cassandraId.asUuid())
@@ -125,17 +124,17 @@ public class CassandraUserMailboxRightsDAO {
             .then();
     }
 
-    public CompletableFuture<Optional<Rfc4314Rights>> retrieve(String userName, CassandraId mailboxId) {
-        return cassandraAsyncExecutor.executeSingleRow(
+    public Mono<Optional<Rfc4314Rights>> retrieve(String userName, CassandraId mailboxId) {
+        return cassandraAsyncExecutor.executeSingleRowOptional(
             select.bind()
                 .setString(USER_NAME, userName)
                 .setUUID(MAILBOX_ID, mailboxId.asUuid()))
-            .thenApply(rowOptional ->
+            .map(rowOptional ->
                 rowOptional.map(Throwing.function(row -> Rfc4314Rights.fromSerializedRfc4314Rights(row.getString(RIGHTS)))));
     }
 
     public Flux<Pair<CassandraId, Rfc4314Rights>> listRightsForUser(String userName) {
-        return cassandraAsyncExecutor.executeReactor(
+        return cassandraAsyncExecutor.execute(
             selectUser.bind()
                 .setString(USER_NAME, userName))
             .flatMapMany(cassandraUtils::convertToFlux)
diff --git a/mailbox/cassandra/src/main/java/org/apache/james/mailbox/cassandra/mail/migration/AttachmentMessageIdCreation.java b/mailbox/cassandra/src/main/java/org/apache/james/mailbox/cassandra/mail/migration/AttachmentMessageIdCreation.java
index 2ab5e56..bb65783 100644
--- a/mailbox/cassandra/src/main/java/org/apache/james/mailbox/cassandra/mail/migration/AttachmentMessageIdCreation.java
+++ b/mailbox/cassandra/src/main/java/org/apache/james/mailbox/cassandra/mail/migration/AttachmentMessageIdCreation.java
@@ -31,6 +31,7 @@ import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
 
 import reactor.core.publisher.Flux;
+import reactor.core.publisher.Mono;
 
 public class AttachmentMessageIdCreation implements Migration {
     private static final Logger LOGGER = LoggerFactory.getLogger(AttachmentMessageIdCreation.class);
@@ -46,28 +47,23 @@ public class AttachmentMessageIdCreation implements Migration {
 
     @Override
     public Result run() {
-        try {
-            return cassandraMessageDAO.retrieveAllMessageIdAttachmentIds()
-                .join()
-                .map(this::createIndex)
-                .reduce(Result.COMPLETED, Task::combine);
-        } catch (Exception e) {
-            LOGGER.error("Error while creation attachmentId -> messageIds index", e);
-            return Result.PARTIAL;
-        }
+        return cassandraMessageDAO.retrieveAllMessageIdAttachmentIds()
+            .flatMap(this::createIndex)
+            .reduce(Result.COMPLETED, Task::combine)
+            .onErrorResume(this::errorHandling)
+            .block();
     }
 
-    private Result createIndex(MessageIdAttachmentIds message) {
-        try {
-            MessageId messageId = message.getMessageId();
-            Flux.fromIterable(message.getAttachmentId())
-                .flatMap(attachmentId -> attachmentMessageIdDAO.storeAttachmentForMessageId(attachmentId, messageId))
-                .then()
-                .block();
-            return Result.COMPLETED;
-        } catch (Exception e) {
-            LOGGER.error("Error while creation attachmentId -> messageIds index", e);
-            return Result.PARTIAL;
-        }
+    private Mono<Result> createIndex(MessageIdAttachmentIds message) {
+        MessageId messageId = message.getMessageId();
+        return Flux.fromIterable(message.getAttachmentId())
+            .flatMap(attachmentId -> attachmentMessageIdDAO.storeAttachmentForMessageId(attachmentId, messageId))
+            .then()
+            .thenReturn(Result.COMPLETED);
+    }
+
+    private Mono<Result> errorHandling(Throwable e) {
+        LOGGER.error("Error while creation attachmentId -> messageIds index", e);
+        return Mono.just(Result.PARTIAL);
     }
 }
diff --git a/mailbox/cassandra/src/main/java/org/apache/james/mailbox/cassandra/mail/migration/AttachmentV2Migration.java b/mailbox/cassandra/src/main/java/org/apache/james/mailbox/cassandra/mail/migration/AttachmentV2Migration.java
index ed836ff..1a0ce08 100644
--- a/mailbox/cassandra/src/main/java/org/apache/james/mailbox/cassandra/mail/migration/AttachmentV2Migration.java
+++ b/mailbox/cassandra/src/main/java/org/apache/james/mailbox/cassandra/mail/migration/AttachmentV2Migration.java
@@ -27,9 +27,12 @@ import org.apache.james.mailbox.cassandra.mail.CassandraAttachmentDAO;
 import org.apache.james.mailbox.cassandra.mail.CassandraAttachmentDAOV2;
 import org.apache.james.mailbox.model.Attachment;
 import org.apache.james.task.Task;
+
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
 
+import reactor.core.publisher.Mono;
+
 public class AttachmentV2Migration implements Migration {
     private static final Logger LOGGER = LoggerFactory.getLogger(AttachmentV2Migration.class);
     private final CassandraAttachmentDAO attachmentDAOV1;
@@ -47,27 +50,23 @@ public class AttachmentV2Migration implements Migration {
 
     @Override
     public Result run() {
-        try {
-            return attachmentDAOV1.retrieveAll()
-                .map(this::migrateAttachment)
-                .reduce(Result.COMPLETED, Task::combine);
-        } catch (Exception e) {
-            LOGGER.error("Error while performing attachmentDAO V2 migration", e);
-            return Result.PARTIAL;
-        }
+        return attachmentDAOV1.retrieveAll()
+            .flatMap(this::migrateAttachment)
+            .reduce(Result.COMPLETED, Task::combine)
+            .onErrorResume(this::handlError)
+            .block();
+    }
+
+    private Mono<Result> handlError(Throwable throwable) {
+        LOGGER.error("Error while performing attachmentDAO V2 migration", throwable);
+        return Mono.just(Result.PARTIAL);
     }
 
-    private Result migrateAttachment(Attachment attachment) {
-        try {
-            return blobStore.save(attachment.getBytes())
-                .map(blobId -> CassandraAttachmentDAOV2.from(attachment, blobId))
-                .flatMap(attachmentDAOV2::storeAttachment)
-                .then(attachmentDAOV1.deleteAttachment(attachment.getAttachmentId()))
-                .thenReturn(Result.COMPLETED)
-                .block();
-        } catch (Exception e) {
-            LOGGER.error("Error while performing attachmentDAO V2 migration", e);
-            return Result.PARTIAL;
-        }
+    private Mono<Result> migrateAttachment(Attachment attachment) {
+        return blobStore.save(attachment.getBytes())
+            .map(blobId -> CassandraAttachmentDAOV2.from(attachment, blobId))
+            .flatMap(attachmentDAOV2::storeAttachment)
+            .then(attachmentDAOV1.deleteAttachment(attachment.getAttachmentId()))
+            .thenReturn(Result.COMPLETED);
     }
 }
diff --git a/mailbox/cassandra/src/main/java/org/apache/james/mailbox/cassandra/mail/migration/MailboxPathV2Migration.java b/mailbox/cassandra/src/main/java/org/apache/james/mailbox/cassandra/mail/migration/MailboxPathV2Migration.java
index c4f3fd2..cfa5f60 100644
--- a/mailbox/cassandra/src/main/java/org/apache/james/mailbox/cassandra/mail/migration/MailboxPathV2Migration.java
+++ b/mailbox/cassandra/src/main/java/org/apache/james/mailbox/cassandra/mail/migration/MailboxPathV2Migration.java
@@ -30,9 +30,12 @@ import org.apache.james.mailbox.cassandra.mail.CassandraMailboxPathDAOImpl;
 import org.apache.james.mailbox.cassandra.mail.CassandraMailboxPathV2DAO;
 import org.apache.james.task.Task;
 import org.apache.james.task.TaskExecutionDetails;
+
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
 
+import reactor.core.publisher.Mono;
+
 public class MailboxPathV2Migration implements Migration {
 
     public static class AdditionalInformation implements TaskExecutionDetails.AdditionalInformation {
@@ -62,32 +65,33 @@ public class MailboxPathV2Migration implements Migration {
     public MailboxPathV2Migration(CassandraMailboxPathDAOImpl daoV1, CassandraMailboxPathV2DAO daoV2) {
         this.daoV1 = daoV1;
         this.daoV2 = daoV2;
-        this.additionalInformation = new AdditionalInformation(() -> daoV1.countAll().join());
+        this.additionalInformation = new AdditionalInformation(() -> daoV1.countAll().block());
     }
 
     @Override
     public Result run() {
-        try {
-            return daoV1.readAll()
-                .join()
-                .map(this::migrate)
-                .reduce(Result.COMPLETED, Task::combine);
-        } catch (Exception e) {
-            LOGGER.error("Error while performing migration", e);
-            return Result.PARTIAL;
-        }
+        return daoV1.readAll()
+            .flatMap(this::migrate)
+            .reduce(Result.COMPLETED, Task::combine)
+            .onErrorResume(this::handleErrorRun)
+            .block();
     }
 
-    public Result migrate(CassandraIdAndPath idAndPath) {
-        try {
-            daoV2.save(idAndPath.getMailboxPath(), idAndPath.getCassandraId()).block();
+    private Mono<Result> handleErrorRun(Throwable throwable) {
+            LOGGER.error("Error while performing migration", throwable);
+            return Mono.just(Result.PARTIAL);
+    }
 
-            daoV1.delete(idAndPath.getMailboxPath()).block();
-            return Result.COMPLETED;
-        } catch (Exception e) {
-            LOGGER.error("Error while performing migration for path {}", idAndPath.getMailboxPath(), e);
-            return Result.PARTIAL;
-        }
+    public Mono<Result> migrate(CassandraIdAndPath idAndPath) {
+        return daoV2.save(idAndPath.getMailboxPath(), idAndPath.getCassandraId())
+            .then(daoV1.delete(idAndPath.getMailboxPath()))
+            .thenReturn(Result.COMPLETED)
+            .onErrorResume(error -> handleErrorMigrate(idAndPath, error));
+    }
+
+    private Mono<Result> handleErrorMigrate(CassandraIdAndPath idAndPath, Throwable throwable) {
+        LOGGER.error("Error while performing migration for path {}", idAndPath.getMailboxPath(), throwable);
+        return Mono.just(Result.PARTIAL);
     }
 
     @Override
diff --git a/mailbox/cassandra/src/main/java/org/apache/james/mailbox/cassandra/mail/task/MailboxMergingTaskRunner.java b/mailbox/cassandra/src/main/java/org/apache/james/mailbox/cassandra/mail/task/MailboxMergingTaskRunner.java
index 0032ef6..4ce86ea 100644
--- a/mailbox/cassandra/src/main/java/org/apache/james/mailbox/cassandra/mail/task/MailboxMergingTaskRunner.java
+++ b/mailbox/cassandra/src/main/java/org/apache/james/mailbox/cassandra/mail/task/MailboxMergingTaskRunner.java
@@ -68,10 +68,10 @@ public class MailboxMergingTaskRunner {
 
     private Task.Result moveMessages(CassandraId oldMailboxId, CassandraId newMailboxId, MailboxSession session, MailboxMergingTask.Context context) {
         return cassandraMessageIdDAO.retrieveMessages(oldMailboxId, MessageRange.all())
-            .join()
             .map(ComposedMessageIdWithMetaData::getComposedMessageId)
             .map(messageId -> moveMessage(newMailboxId, messageId, session, context))
-            .reduce(Task.Result.COMPLETED, Task::combine);
+            .reduce(Task.Result.COMPLETED, Task::combine)
+            .block();
     }
 
     private Task.Result moveMessage(CassandraId newMailboxId, ComposedMessageId composedMessageId, MailboxSession session, MailboxMergingTask.Context context) {
diff --git a/mailbox/cassandra/src/test/java/org/apache/james/mailbox/cassandra/mail/CassandraAttachmentDAOTest.java b/mailbox/cassandra/src/test/java/org/apache/james/mailbox/cassandra/mail/CassandraAttachmentDAOTest.java
index 2aa9601..5cb927e 100644
--- a/mailbox/cassandra/src/test/java/org/apache/james/mailbox/cassandra/mail/CassandraAttachmentDAOTest.java
+++ b/mailbox/cassandra/src/test/java/org/apache/james/mailbox/cassandra/mail/CassandraAttachmentDAOTest.java
@@ -35,8 +35,6 @@ import org.junit.jupiter.api.BeforeEach;
 import org.junit.jupiter.api.Test;
 import org.junit.jupiter.api.extension.RegisterExtension;
 
-import com.github.steveash.guavate.Guavate;
-
 class CassandraAttachmentDAOTest {
     private static final AttachmentId ATTACHMENT_ID = AttachmentId.from("id1");
     private static final AttachmentId ATTACHMENT_ID_2 = AttachmentId.from("id2");
@@ -64,7 +62,8 @@ class CassandraAttachmentDAOTest {
     void retrieveAllShouldReturnEmptyByDefault() {
         assertThat(
             testee.retrieveAll()
-                .collect(Guavate.toImmutableList()))
+                .collectList()
+                .block())
             .isEmpty();
     }
 
@@ -80,12 +79,13 @@ class CassandraAttachmentDAOTest {
             .type("application/json")
             .bytes("{\"property\":`\"value2\"}".getBytes(StandardCharsets.UTF_8))
             .build();
-        testee.storeAttachment(attachment1).join();
-        testee.storeAttachment(attachment2).join();
+        testee.storeAttachment(attachment1).block();
+        testee.storeAttachment(attachment2).block();
 
         assertThat(
             testee.retrieveAll()
-                .collect(Guavate.toImmutableList()))
+                .collectList()
+                .block())
             .containsOnly(attachment1, attachment2);
     }
 
@@ -96,7 +96,7 @@ class CassandraAttachmentDAOTest {
             .type("application/json")
             .bytes("{\"property\":`\"value\"}".getBytes(StandardCharsets.UTF_8))
             .build();
-        testee.storeAttachment(attachment).join();
+        testee.storeAttachment(attachment).block();
 
         Optional<Attachment> actual = testee.getAttachment(ATTACHMENT_ID).blockOptional();
 
@@ -110,7 +110,7 @@ class CassandraAttachmentDAOTest {
             .type("application/json")
             .bytes("{\"property\":`\"value\"}".getBytes(StandardCharsets.UTF_8))
             .build();
-        testee.storeAttachment(attachment).join();
+        testee.storeAttachment(attachment).block();
 
         testee.deleteAttachment(attachment.getAttachmentId()).block();
 
diff --git a/mailbox/cassandra/src/test/java/org/apache/james/mailbox/cassandra/mail/CassandraAttachmentFallbackTest.java b/mailbox/cassandra/src/test/java/org/apache/james/mailbox/cassandra/mail/CassandraAttachmentFallbackTest.java
index 1b98b9c..7d2b475 100644
--- a/mailbox/cassandra/src/test/java/org/apache/james/mailbox/cassandra/mail/CassandraAttachmentFallbackTest.java
+++ b/mailbox/cassandra/src/test/java/org/apache/james/mailbox/cassandra/mail/CassandraAttachmentFallbackTest.java
@@ -70,8 +70,8 @@ class CassandraAttachmentFallbackTest {
             CassandraUtils.WITH_DEFAULT_CONFIGURATION,
             CassandraConfiguration.DEFAULT_CONFIGURATION);
         blobsDAO = new CassandraBlobsDAO(cassandra.getConf());
-        attachmentMessageIdDAO = new CassandraAttachmentMessageIdDAO(cassandra.getConf(), new CassandraMessageId.Factory(), CassandraUtils.WITH_DEFAULT_CONFIGURATION);
-        CassandraAttachmentOwnerDAO ownerDAO = new CassandraAttachmentOwnerDAO(cassandra.getConf(), CassandraUtils.WITH_DEFAULT_CONFIGURATION);
+        attachmentMessageIdDAO = new CassandraAttachmentMessageIdDAO(cassandra.getConf(), new CassandraMessageId.Factory());
+        CassandraAttachmentOwnerDAO ownerDAO = new CassandraAttachmentOwnerDAO(cassandra.getConf());
         attachmentMapper = new CassandraAttachmentMapper(attachmentDAO, attachmentDAOV2, blobsDAO, attachmentMessageIdDAO, ownerDAO);
     }
 
@@ -102,7 +102,7 @@ class CassandraAttachmentFallbackTest {
 
         BlobId blobId = blobsDAO.save(attachment.getBytes()).block();
         attachmentDAOV2.storeAttachment(CassandraAttachmentDAOV2.from(attachment, blobId)).block();
-        attachmentDAO.storeAttachment(otherAttachment).join();
+        attachmentDAO.storeAttachment(otherAttachment).block();
 
         assertThat(attachmentMapper.getAttachment(ATTACHMENT_ID_1))
             .isEqualTo(attachment);
@@ -116,7 +116,7 @@ class CassandraAttachmentFallbackTest {
             .bytes("{\"property\":`\"value\"}".getBytes(StandardCharsets.UTF_8))
             .build();
 
-        attachmentDAO.storeAttachment(attachment).join();
+        attachmentDAO.storeAttachment(attachment).block();
 
         assertThat(attachmentMapper.getAttachment(ATTACHMENT_ID_1))
             .isEqualTo(attachment);
@@ -137,7 +137,7 @@ class CassandraAttachmentFallbackTest {
 
         BlobId blobId = blobsDAO.save(attachment.getBytes()).block();
         attachmentDAOV2.storeAttachment(CassandraAttachmentDAOV2.from(attachment, blobId)).block();
-        attachmentDAO.storeAttachment(otherAttachment).join();
+        attachmentDAO.storeAttachment(otherAttachment).block();
 
         assertThat(attachmentMapper.getAttachments(ImmutableList.of(ATTACHMENT_ID_1)))
             .containsExactly(attachment);
@@ -151,7 +151,7 @@ class CassandraAttachmentFallbackTest {
             .bytes("{\"property\":`\"value\"}".getBytes(StandardCharsets.UTF_8))
             .build();
 
-        attachmentDAO.storeAttachment(attachment).join();
+        attachmentDAO.storeAttachment(attachment).block();
 
         assertThat(attachmentMapper.getAttachments(ImmutableList.of(ATTACHMENT_ID_1)))
             .containsExactly(attachment);
@@ -172,7 +172,7 @@ class CassandraAttachmentFallbackTest {
 
         BlobId blobId = blobsDAO.save(attachment.getBytes()).block();
         attachmentDAOV2.storeAttachment(CassandraAttachmentDAOV2.from(attachment, blobId)).block();
-        attachmentDAO.storeAttachment(otherAttachment).join();
+        attachmentDAO.storeAttachment(otherAttachment).block();
 
         List<Attachment> attachments = attachmentMapper.getAttachments(ImmutableList.of(ATTACHMENT_ID_1, ATTACHMENT_ID_2));
         assertThat(attachments)
diff --git a/backends-common/cassandra/src/test/java/org/apache/james/backends/cassandra/versions/CassandraSchemaVersionDAOTest.java b/mailbox/cassandra/src/test/java/org/apache/james/mailbox/cassandra/mail/CassandraAttachmentMessageIdDAOTest.java
similarity index 52%
copy from backends-common/cassandra/src/test/java/org/apache/james/backends/cassandra/versions/CassandraSchemaVersionDAOTest.java
copy to mailbox/cassandra/src/test/java/org/apache/james/mailbox/cassandra/mail/CassandraAttachmentMessageIdDAOTest.java
index e5a0b8b..3b42458 100644
--- a/backends-common/cassandra/src/test/java/org/apache/james/backends/cassandra/versions/CassandraSchemaVersionDAOTest.java
+++ b/mailbox/cassandra/src/test/java/org/apache/james/mailbox/cassandra/mail/CassandraAttachmentMessageIdDAOTest.java
@@ -17,52 +17,52 @@
  * under the License.                                           *
  ****************************************************************/
 
-package org.apache.james.backends.cassandra.versions;
+package org.apache.james.mailbox.cassandra.mail;
 
 import static org.assertj.core.api.Assertions.assertThat;
 
-import java.util.Optional;
-
 import org.apache.james.backends.cassandra.CassandraCluster;
 import org.apache.james.backends.cassandra.CassandraClusterExtension;
-import org.apache.james.backends.cassandra.utils.CassandraUtils;
+import org.apache.james.backends.cassandra.components.CassandraModule;
+
+import org.apache.james.backends.cassandra.versions.CassandraSchemaVersionModule;
+import org.apache.james.mailbox.cassandra.ids.CassandraMessageId;
+import org.apache.james.mailbox.cassandra.modules.CassandraAttachmentModule;
+import org.apache.james.mailbox.model.AttachmentId;
+
 import org.junit.jupiter.api.BeforeEach;
 import org.junit.jupiter.api.Test;
 import org.junit.jupiter.api.extension.RegisterExtension;
 
-class CassandraSchemaVersionDAOTest {
+class CassandraAttachmentMessageIdDAOTest {
+
+    private static final CassandraModule MODULE = CassandraModule.aggregateModules(
+            CassandraAttachmentModule.MODULE,
+            CassandraSchemaVersionModule.MODULE
+    );
+
     @RegisterExtension
-    static CassandraClusterExtension cassandraCluster = new CassandraClusterExtension(CassandraSchemaVersionModule.MODULE);
+    static CassandraClusterExtension cassandraCluster = new CassandraClusterExtension(MODULE);
 
-    private CassandraSchemaVersionDAO testee;
+    private CassandraAttachmentMessageIdDAO testee;
 
     @BeforeEach
     void setUp(CassandraCluster cassandra) {
-        testee = new CassandraSchemaVersionDAO(cassandra.getConf(), CassandraUtils.WITH_DEFAULT_CONFIGURATION);
-    }
-
-    @Test
-    void getCurrentSchemaVersionShouldReturnEmptyWhenTableIsEmpty() {
-        assertThat(testee.getCurrentSchemaVersion().join())
-            .isEqualTo(Optional.empty());
-    }
-
-    @Test
-    void getCurrentSchemaVersionShouldReturnVersionPresentInTheTable() {
-        SchemaVersion version = new SchemaVersion(42);
-
-        testee.updateVersion(version).join();
-
-        assertThat(testee.getCurrentSchemaVersion().join()).contains(version);
+        testee = new CassandraAttachmentMessageIdDAO(cassandra.getConf(), new CassandraMessageId.Factory());
     }
 
     @Test
-    void getCurrentSchemaVersionShouldBeIdempotent() {
-        SchemaVersion version = new SchemaVersion(42);
+    void getOwnerMessageIdsShouldReturnDistinctValues() {
+        CassandraMessageId messageId1 = new CassandraMessageId.Factory().generate();
+        CassandraMessageId messageId2 = new CassandraMessageId.Factory().generate();
+        AttachmentId attachmentId = AttachmentId.random();
 
-        testee.updateVersion(version.next()).join();
-        testee.updateVersion(version).join();
+        testee.storeAttachmentForMessageId(attachmentId, messageId1).block();
+        testee.storeAttachmentForMessageId(attachmentId, messageId2).block();
+        testee.storeAttachmentForMessageId(attachmentId, messageId1).block();
 
-        assertThat(testee.getCurrentSchemaVersion().join()).contains(version.next());
+        assertThat(testee.getOwnerMessageIds(attachmentId).collectList().block())
+            .containsExactlyInAnyOrder(messageId1, messageId2)
+            .hasSize(2);
     }
 }
\ No newline at end of file
diff --git a/mailbox/cassandra/src/test/java/org/apache/james/mailbox/cassandra/mail/CassandraAttachmentOwnerDAOTest.java b/mailbox/cassandra/src/test/java/org/apache/james/mailbox/cassandra/mail/CassandraAttachmentOwnerDAOTest.java
index 0b87025..bf325af 100644
--- a/mailbox/cassandra/src/test/java/org/apache/james/mailbox/cassandra/mail/CassandraAttachmentOwnerDAOTest.java
+++ b/mailbox/cassandra/src/test/java/org/apache/james/mailbox/cassandra/mail/CassandraAttachmentOwnerDAOTest.java
@@ -25,7 +25,6 @@ import java.util.stream.IntStream;
 
 import org.apache.james.backends.cassandra.CassandraCluster;
 import org.apache.james.backends.cassandra.CassandraClusterExtension;
-import org.apache.james.backends.cassandra.utils.CassandraUtils;
 import org.apache.james.mailbox.cassandra.modules.CassandraAttachmentModule;
 import org.apache.james.mailbox.model.AttachmentId;
 import org.apache.james.mailbox.store.mail.model.Username;
@@ -48,13 +47,13 @@ class CassandraAttachmentOwnerDAOTest {
 
     @BeforeEach
     void setUp(CassandraCluster cassandra) {
-        testee = new CassandraAttachmentOwnerDAO(cassandra.getConf(),
-            CassandraUtils.WITH_DEFAULT_CONFIGURATION);
+        testee = new CassandraAttachmentOwnerDAO(cassandra.getConf()
+        );
     }
 
     @Test
     void retrieveOwnersShouldReturnEmptyByDefault() {
-        assertThat(testee.retrieveOwners(ATTACHMENT_ID).join())
+        assertThat(testee.retrieveOwners(ATTACHMENT_ID).toIterable())
             .isEmpty();
     }
 
@@ -62,7 +61,7 @@ class CassandraAttachmentOwnerDAOTest {
     void retrieveOwnersShouldReturnAddedOwner() {
         testee.addOwner(ATTACHMENT_ID, OWNER_1).block();
 
-        assertThat(testee.retrieveOwners(ATTACHMENT_ID).join())
+        assertThat(testee.retrieveOwners(ATTACHMENT_ID).toIterable())
             .containsOnly(OWNER_1);
     }
 
@@ -71,7 +70,7 @@ class CassandraAttachmentOwnerDAOTest {
         testee.addOwner(ATTACHMENT_ID, OWNER_1).block();
         testee.addOwner(ATTACHMENT_ID, OWNER_2).block();
 
-        assertThat(testee.retrieveOwners(ATTACHMENT_ID).join())
+        assertThat(testee.retrieveOwners(ATTACHMENT_ID).toIterable())
             .containsOnly(OWNER_1, OWNER_2);
     }
 
@@ -87,7 +86,7 @@ class CassandraAttachmentOwnerDAOTest {
                     .then()
                     .block());
 
-        assertThat(testee.retrieveOwners(ATTACHMENT_ID).join())
+        assertThat(testee.retrieveOwners(ATTACHMENT_ID).toIterable())
             .hasSize(referenceCountExceedingPaging);
     }
 }
\ No newline at end of file
diff --git a/mailbox/cassandra/src/test/java/org/apache/james/mailbox/cassandra/mail/CassandraMailboxDAOTest.java b/mailbox/cassandra/src/test/java/org/apache/james/mailbox/cassandra/mail/CassandraMailboxDAOTest.java
index 4af1bdc..ad4c36b 100644
--- a/mailbox/cassandra/src/test/java/org/apache/james/mailbox/cassandra/mail/CassandraMailboxDAOTest.java
+++ b/mailbox/cassandra/src/test/java/org/apache/james/mailbox/cassandra/mail/CassandraMailboxDAOTest.java
@@ -145,14 +145,14 @@ class CassandraMailboxDAOTest {
 
     @Test
     void updateShouldNotFailWhenMailboxIsAbsent() {
-        testee.updatePath(CASSANDRA_ID_1, NEW_MAILBOX_PATH).join();
+        testee.updatePath(CASSANDRA_ID_1, NEW_MAILBOX_PATH).block();
     }
 
     @Test
     void updateShouldChangeMailboxPath() {
         testee.save(mailbox1).block();
 
-        testee.updatePath(CASSANDRA_ID_1, NEW_MAILBOX_PATH).join();
+        testee.updatePath(CASSANDRA_ID_1, NEW_MAILBOX_PATH).block();
 
         mailbox1.setNamespace(NEW_MAILBOX_PATH.getNamespace());
         mailbox1.setUser(NEW_MAILBOX_PATH.getUser());
diff --git a/mailbox/cassandra/src/test/java/org/apache/james/mailbox/cassandra/mail/CassandraMailboxPathDAOImplTest.java b/mailbox/cassandra/src/test/java/org/apache/james/mailbox/cassandra/mail/CassandraMailboxPathDAOImplTest.java
index dbf64f2..3a40381 100644
--- a/mailbox/cassandra/src/test/java/org/apache/james/mailbox/cassandra/mail/CassandraMailboxPathDAOImplTest.java
+++ b/mailbox/cassandra/src/test/java/org/apache/james/mailbox/cassandra/mail/CassandraMailboxPathDAOImplTest.java
@@ -24,8 +24,6 @@ import static org.assertj.core.api.Assertions.assertThat;
 import org.apache.james.backends.cassandra.CassandraCluster;
 import org.junit.jupiter.api.Test;
 
-import com.github.steveash.guavate.Guavate;
-
 class CassandraMailboxPathDAOImplTest extends CassandraMailboxPathDAOTest {
 
     @Override
@@ -41,7 +39,7 @@ class CassandraMailboxPathDAOImplTest extends CassandraMailboxPathDAOTest {
 
         CassandraMailboxPathDAOImpl daoV1 = (CassandraMailboxPathDAOImpl) testee;
 
-        assertThat(daoV1.countAll().join())
+        assertThat(daoV1.countAll().block())
             .isEqualTo(3);
     }
 
@@ -49,7 +47,7 @@ class CassandraMailboxPathDAOImplTest extends CassandraMailboxPathDAOTest {
     void countAllShouldReturnZeroByDefault() {
         CassandraMailboxPathDAOImpl daoV1 = (CassandraMailboxPathDAOImpl) testee;
 
-        assertThat(daoV1.countAll().join())
+        assertThat(daoV1.countAll().block())
             .isEqualTo(0);
     }
 
@@ -61,7 +59,7 @@ class CassandraMailboxPathDAOImplTest extends CassandraMailboxPathDAOTest {
 
         CassandraMailboxPathDAOImpl daoV1 = (CassandraMailboxPathDAOImpl) testee;
 
-        assertThat(daoV1.readAll().join().collect(Guavate.toImmutableList()))
+        assertThat(daoV1.readAll().toIterable())
             .containsOnly(
                 new CassandraIdAndPath(INBOX_ID, USER_INBOX_MAILBOXPATH),
                 new CassandraIdAndPath(OUTBOX_ID, USER_OUTBOX_MAILBOXPATH),
@@ -72,7 +70,7 @@ class CassandraMailboxPathDAOImplTest extends CassandraMailboxPathDAOTest {
     void readAllShouldReturnEmptyByDefault() {
         CassandraMailboxPathDAOImpl daoV1 = (CassandraMailboxPathDAOImpl) testee;
 
-        assertThat(daoV1.readAll().join().collect(Guavate.toImmutableList()))
+        assertThat(daoV1.readAll().toIterable())
             .isEmpty();
     }
 }
\ No newline at end of file
diff --git a/mailbox/cassandra/src/test/java/org/apache/james/mailbox/cassandra/mail/CassandraMessageDAOTest.java b/mailbox/cassandra/src/test/java/org/apache/james/mailbox/cassandra/mail/CassandraMessageDAOTest.java
index c6c953e..4bb120c 100644
--- a/mailbox/cassandra/src/test/java/org/apache/james/mailbox/cassandra/mail/CassandraMessageDAOTest.java
+++ b/mailbox/cassandra/src/test/java/org/apache/james/mailbox/cassandra/mail/CassandraMessageDAOTest.java
@@ -37,6 +37,7 @@ import org.apache.james.backends.cassandra.CassandraCluster;
 import org.apache.james.backends.cassandra.CassandraClusterExtension;
 import org.apache.james.backends.cassandra.components.CassandraModule;
 import org.apache.james.backends.cassandra.utils.CassandraUtils;
+import org.apache.james.backends.cassandra.versions.CassandraSchemaVersionModule;
 import org.apache.james.blob.api.HashBlobId;
 import org.apache.james.blob.cassandra.CassandraBlobModule;
 import org.apache.james.blob.cassandra.CassandraBlobsDAO;
@@ -71,11 +72,14 @@ class CassandraMessageDAOTest {
     private static final MessageUid messageUid = MessageUid.of(1);
     private static final List<MessageAttachment> NO_ATTACHMENT = ImmutableList.of();
 
+    public static final CassandraModule MODULES = CassandraModule.aggregateModules(
+            CassandraMessageModule.MODULE,
+            CassandraBlobModule.MODULE,
+            CassandraSchemaVersionModule.MODULE);
+
     @RegisterExtension
     static CassandraClusterExtension cassandraCluster = new CassandraClusterExtension(
-        CassandraModule.aggregateModules(
-            CassandraMessageModule.MODULE,
-            CassandraBlobModule.MODULE));
+            MODULES);
 
     private CassandraMessageDAO testee;
     private CassandraMessageId.Factory messageIdFactory;
@@ -195,7 +199,7 @@ class CassandraMessageDAOTest {
 
     @Test
     void retrieveAllMessageIdAttachmentIdsShouldReturnEmptyWhenNone() {
-        Stream<MessageIdAttachmentIds> actual = testee.retrieveAllMessageIdAttachmentIds().join();
+        Stream<MessageIdAttachmentIds> actual = testee.retrieveAllMessageIdAttachmentIds().toStream();
         
         assertThat(actual).isEmpty();
     }
@@ -214,7 +218,7 @@ class CassandraMessageDAOTest {
         MessageIdAttachmentIds expected = new MessageIdAttachmentIds(messageId, ImmutableSet.of(attachment.getAttachmentId()));
         
         //When
-        Stream<MessageIdAttachmentIds> actual = testee.retrieveAllMessageIdAttachmentIds().join();
+        Stream<MessageIdAttachmentIds> actual = testee.retrieveAllMessageIdAttachmentIds().toStream();
         
         //Then
         assertThat(actual).containsOnly(expected);
@@ -240,7 +244,7 @@ class CassandraMessageDAOTest {
         MessageIdAttachmentIds expected = new MessageIdAttachmentIds(messageId, ImmutableSet.of(attachment1.getAttachmentId(), attachment2.getAttachmentId()));
         
         //When
-        Stream<MessageIdAttachmentIds> actual = testee.retrieveAllMessageIdAttachmentIds().join();
+        Stream<MessageIdAttachmentIds> actual = testee.retrieveAllMessageIdAttachmentIds().toStream();
         
         //Then
         assertThat(actual).containsOnly(expected);
@@ -271,7 +275,7 @@ class CassandraMessageDAOTest {
         MessageIdAttachmentIds expected2 = new MessageIdAttachmentIds(messageId2, ImmutableSet.of(attachment2.getAttachmentId()));
         
         //When
-        Stream<MessageIdAttachmentIds> actual = testee.retrieveAllMessageIdAttachmentIds().join();
+        Stream<MessageIdAttachmentIds> actual = testee.retrieveAllMessageIdAttachmentIds().toStream();
         
         //Then
         assertThat(actual).containsOnly(expected1, expected2);
@@ -284,7 +288,7 @@ class CassandraMessageDAOTest {
         testee.save(message1).block();
         
         //When
-        Stream<MessageIdAttachmentIds> actual = testee.retrieveAllMessageIdAttachmentIds().join();
+        Stream<MessageIdAttachmentIds> actual = testee.retrieveAllMessageIdAttachmentIds().toStream();
         
         //Then
         assertThat(actual).isEmpty();
@@ -316,7 +320,7 @@ class CassandraMessageDAOTest {
         testee.save(message3).block();
         
         //When
-        Stream<MessageIdAttachmentIds> actual = testee.retrieveAllMessageIdAttachmentIds().join();
+        Stream<MessageIdAttachmentIds> actual = testee.retrieveAllMessageIdAttachmentIds().toStream();
         
         //Then
         assertThat(actual).extracting(MessageIdAttachmentIds::getMessageId)
diff --git a/mailbox/cassandra/src/test/java/org/apache/james/mailbox/cassandra/mail/CassandraMessageIdDAOTest.java b/mailbox/cassandra/src/test/java/org/apache/james/mailbox/cassandra/mail/CassandraMessageIdDAOTest.java
index 1ebc42b..588a634 100644
--- a/mailbox/cassandra/src/test/java/org/apache/james/mailbox/cassandra/mail/CassandraMessageIdDAOTest.java
+++ b/mailbox/cassandra/src/test/java/org/apache/james/mailbox/cassandra/mail/CassandraMessageIdDAOTest.java
@@ -20,9 +20,7 @@ package org.apache.james.mailbox.cassandra.mail;
 
 import static org.assertj.core.api.Assertions.assertThat;
 
-import java.util.List;
 import java.util.Optional;
-import java.util.stream.Collectors;
 
 import javax.mail.Flags;
 import javax.mail.Flags.Flag;
@@ -75,7 +73,7 @@ class CassandraMessageIdDAOTest {
 
         testee.delete(mailboxId, messageUid).block();
 
-        Optional<ComposedMessageIdWithMetaData> message = testee.retrieve(mailboxId, messageUid).join();
+        Optional<ComposedMessageIdWithMetaData> message = testee.retrieve(mailboxId, messageUid).block();
         assertThat(message.isPresent()).isFalse();
     }
 
@@ -101,9 +99,9 @@ class CassandraMessageIdDAOTest {
 
         testee.delete(mailboxId, messageUid).block();
 
-        Optional<ComposedMessageIdWithMetaData> message = testee.retrieve(mailboxId, messageUid).join();
+        Optional<ComposedMessageIdWithMetaData> message = testee.retrieve(mailboxId, messageUid).block();
         assertThat(message.isPresent()).isFalse();
-        Optional<ComposedMessageIdWithMetaData> messageNotDeleted = testee.retrieve(mailboxId, messageUid2).join();
+        Optional<ComposedMessageIdWithMetaData> messageNotDeleted = testee.retrieve(mailboxId, messageUid2).block();
         assertThat(messageNotDeleted.isPresent()).isTrue();
     }
 
@@ -120,7 +118,7 @@ class CassandraMessageIdDAOTest {
                 .build();
         testee.insert(composedMessageIdWithMetaData).block();
 
-        Optional<ComposedMessageIdWithMetaData> message = testee.retrieve(mailboxId, messageUid).join();
+        Optional<ComposedMessageIdWithMetaData> message = testee.retrieve(mailboxId, messageUid).block();
         assertThat(message.get()).isEqualTo(composedMessageIdWithMetaData);
     }
 
@@ -145,7 +143,7 @@ class CassandraMessageIdDAOTest {
                 .build();
         testee.updateMetadata(expectedComposedMessageId).block();
 
-        Optional<ComposedMessageIdWithMetaData> message = testee.retrieve(mailboxId, messageUid).join();
+        Optional<ComposedMessageIdWithMetaData> message = testee.retrieve(mailboxId, messageUid).block();
         assertThat(message.get()).isEqualTo(expectedComposedMessageId);
     }
 
@@ -170,7 +168,7 @@ class CassandraMessageIdDAOTest {
                 .build();
         testee.updateMetadata(expectedComposedMessageId).block();
 
-        Optional<ComposedMessageIdWithMetaData> message = testee.retrieve(mailboxId, messageUid).join();
+        Optional<ComposedMessageIdWithMetaData> message = testee.retrieve(mailboxId, messageUid).block();
         assertThat(message.get()).isEqualTo(expectedComposedMessageId);
     }
 
@@ -195,7 +193,7 @@ class CassandraMessageIdDAOTest {
                 .build();
         testee.updateMetadata(expectedComposedMessageId).block();
 
-        Optional<ComposedMessageIdWithMetaData> message = testee.retrieve(mailboxId, messageUid).join();
+        Optional<ComposedMessageIdWithMetaData> message = testee.retrieve(mailboxId, messageUid).block();
         assertThat(message.get()).isEqualTo(expectedComposedMessageId);
     }
 
@@ -220,7 +218,7 @@ class CassandraMessageIdDAOTest {
                 .build();
         testee.updateMetadata(expectedComposedMessageId).block();
 
-        Optional<ComposedMessageIdWithMetaData> message = testee.retrieve(mailboxId, messageUid).join();
+        Optional<ComposedMessageIdWithMetaData> message = testee.retrieve(mailboxId, messageUid).block();
         assertThat(message.get()).isEqualTo(expectedComposedMessageId);
     }
 
@@ -245,7 +243,7 @@ class CassandraMessageIdDAOTest {
                 .build();
         testee.updateMetadata(expectedComposedMessageId).block();
 
-        Optional<ComposedMessageIdWithMetaData> message = testee.retrieve(mailboxId, messageUid).join();
+        Optional<ComposedMessageIdWithMetaData> message = testee.retrieve(mailboxId, messageUid).block();
         assertThat(message.get()).isEqualTo(expectedComposedMessageId);
     }
 
@@ -270,7 +268,7 @@ class CassandraMessageIdDAOTest {
                 .build();
         testee.updateMetadata(expectedComposedMessageId).block();
 
-        Optional<ComposedMessageIdWithMetaData> message = testee.retrieve(mailboxId, messageUid).join();
+        Optional<ComposedMessageIdWithMetaData> message = testee.retrieve(mailboxId, messageUid).block();
         assertThat(message.get()).isEqualTo(expectedComposedMessageId);
     }
 
@@ -295,7 +293,7 @@ class CassandraMessageIdDAOTest {
                 .build();
         testee.updateMetadata(expectedComposedMessageId).block();
 
-        Optional<ComposedMessageIdWithMetaData> message = testee.retrieve(mailboxId, messageUid).join();
+        Optional<ComposedMessageIdWithMetaData> message = testee.retrieve(mailboxId, messageUid).block();
         assertThat(message.get()).isEqualTo(expectedComposedMessageId);
     }
 
@@ -320,7 +318,7 @@ class CassandraMessageIdDAOTest {
                 .build();
         testee.updateMetadata(expectedComposedMessageId).block();
 
-        Optional<ComposedMessageIdWithMetaData> message = testee.retrieve(mailboxId, messageUid).join();
+        Optional<ComposedMessageIdWithMetaData> message = testee.retrieve(mailboxId, messageUid).block();
         assertThat(message.get()).isEqualTo(expectedComposedMessageId);
     }
 
@@ -347,7 +345,7 @@ class CassandraMessageIdDAOTest {
                 .build();
         testee.updateMetadata(expectedComposedMessageId).block();
 
-        Optional<ComposedMessageIdWithMetaData> message = testee.retrieve(mailboxId, messageUid).join();
+        Optional<ComposedMessageIdWithMetaData> message = testee.retrieve(mailboxId, messageUid).block();
         assertThat(message.get()).isEqualTo(expectedComposedMessageId);
     }
 
@@ -363,7 +361,7 @@ class CassandraMessageIdDAOTest {
                 .build();
         testee.insert(composedMessageIdWithMetaData).block();
 
-        Optional<ComposedMessageIdWithMetaData> message = testee.retrieve(mailboxId, messageUid).join();
+        Optional<ComposedMessageIdWithMetaData> message = testee.retrieve(mailboxId, messageUid).block();
 
         assertThat(message.get()).isEqualTo(composedMessageIdWithMetaData);
     }
@@ -390,10 +388,8 @@ class CassandraMessageIdDAOTest {
                 testee.insert(composedMessageIdWithMetaData2))
         .blockLast();
 
-        List<ComposedMessageIdWithMetaData> messages = testee.retrieveMessages(mailboxId, MessageRange.all()).join()
-                .collect(Collectors.toList());
-
-        assertThat(messages).containsOnly(composedMessageIdWithMetaData, composedMessageIdWithMetaData2);
+        assertThat(testee.retrieveMessages(mailboxId, MessageRange.all()).toIterable())
+            .containsOnly(composedMessageIdWithMetaData, composedMessageIdWithMetaData2);
     }
 
     @Test
@@ -426,10 +422,8 @@ class CassandraMessageIdDAOTest {
                 testee.insert(composedMessageIdWithMetaData2))
         .blockLast();
 
-        List<ComposedMessageIdWithMetaData> messages = testee.retrieveMessages(mailboxId, MessageRange.from(messageUid2)).join()
-                .collect(Collectors.toList());
-
-        assertThat(messages).containsOnly(composedMessageIdWithMetaData, composedMessageIdWithMetaData2);
+        assertThat(testee.retrieveMessages(mailboxId, MessageRange.from(messageUid2)).toIterable())
+            .containsOnly(composedMessageIdWithMetaData, composedMessageIdWithMetaData2);
     }
 
     @Test
@@ -471,10 +465,8 @@ class CassandraMessageIdDAOTest {
                     .build()))
         .blockLast();
 
-        List<ComposedMessageIdWithMetaData> messages = testee.retrieveMessages(mailboxId, MessageRange.range(messageUid2, messageUid3)).join()
-                .collect(Collectors.toList());
-
-        assertThat(messages).containsOnly(composedMessageIdWithMetaData, composedMessageIdWithMetaData2);
+        assertThat(testee.retrieveMessages(mailboxId, MessageRange.range(messageUid2, messageUid3)).toIterable())
+            .containsOnly(composedMessageIdWithMetaData, composedMessageIdWithMetaData2);
     }
 
     @Test
@@ -506,9 +498,7 @@ class CassandraMessageIdDAOTest {
                     .build()))
         .blockLast();
 
-        List<ComposedMessageIdWithMetaData> messages = testee.retrieveMessages(mailboxId, MessageRange.one(messageUid2)).join()
-                .collect(Collectors.toList());
-
-        assertThat(messages).containsOnly(composedMessageIdWithMetaData);
+        assertThat(testee.retrieveMessages(mailboxId, MessageRange.one(messageUid2)).toIterable())
+            .containsOnly(composedMessageIdWithMetaData);
     }
 }
diff --git a/mailbox/cassandra/src/test/java/org/apache/james/mailbox/cassandra/mail/CassandraUserMailboxRightsDAOTest.java b/mailbox/cassandra/src/test/java/org/apache/james/mailbox/cassandra/mail/CassandraUserMailboxRightsDAOTest.java
index 1596e1c..ce52234 100644
--- a/mailbox/cassandra/src/test/java/org/apache/james/mailbox/cassandra/mail/CassandraUserMailboxRightsDAOTest.java
+++ b/mailbox/cassandra/src/test/java/org/apache/james/mailbox/cassandra/mail/CassandraUserMailboxRightsDAOTest.java
@@ -59,7 +59,7 @@ class CassandraUserMailboxRightsDAOTest {
             new MailboxACL(new Entry(ENTRY_KEY, RIGHTS))))
             .block();
 
-        assertThat(testee.retrieve(USER_NAME, MAILBOX_ID).join())
+        assertThat(testee.retrieve(USER_NAME, MAILBOX_ID).block())
             .contains(RIGHTS);
     }
 
@@ -75,7 +75,7 @@ class CassandraUserMailboxRightsDAOTest {
             new MailboxACL(new Entry(ENTRY_KEY, OTHER_RIGHTS))))
             .block();
 
-        assertThat(testee.retrieve(USER_NAME, MAILBOX_ID).join())
+        assertThat(testee.retrieve(USER_NAME, MAILBOX_ID).block())
             .contains(OTHER_RIGHTS);
     }
 
@@ -98,7 +98,7 @@ class CassandraUserMailboxRightsDAOTest {
             MailboxACL.EMPTY))
             .block();
 
-        assertThat(testee.retrieve(USER_NAME, MAILBOX_ID).join())
+        assertThat(testee.retrieve(USER_NAME, MAILBOX_ID).block())
             .isEmpty();
     }
 }
diff --git a/mailbox/cassandra/src/test/java/org/apache/james/mailbox/cassandra/mail/migration/AttachmentMessageIdCreationTest.java b/mailbox/cassandra/src/test/java/org/apache/james/mailbox/cassandra/mail/migration/AttachmentMessageIdCreationTest.java
index 499cf54..27d28ca 100644
--- a/mailbox/cassandra/src/test/java/org/apache/james/mailbox/cassandra/mail/migration/AttachmentMessageIdCreationTest.java
+++ b/mailbox/cassandra/src/test/java/org/apache/james/mailbox/cassandra/mail/migration/AttachmentMessageIdCreationTest.java
@@ -28,8 +28,6 @@ import java.nio.charset.StandardCharsets;
 import java.util.Collection;
 import java.util.Date;
 import java.util.List;
-import java.util.concurrent.CompletableFuture;
-import java.util.stream.Stream;
 
 import javax.mail.Flags;
 import javax.mail.util.SharedByteArrayInputStream;
@@ -39,6 +37,7 @@ import org.apache.james.backends.cassandra.CassandraClusterExtension;
 import org.apache.james.backends.cassandra.components.CassandraModule;
 import org.apache.james.backends.cassandra.migration.Migration;
 import org.apache.james.backends.cassandra.utils.CassandraUtils;
+import org.apache.james.backends.cassandra.versions.CassandraSchemaVersionModule;
 import org.apache.james.blob.api.HashBlobId;
 import org.apache.james.blob.cassandra.CassandraBlobModule;
 import org.apache.james.blob.cassandra.CassandraBlobsDAO;
@@ -61,14 +60,18 @@ import org.junit.jupiter.api.extension.RegisterExtension;
 
 import com.google.common.collect.ImmutableList;
 import com.google.common.collect.ImmutableSet;
+import reactor.core.publisher.Flux;
 
 class AttachmentMessageIdCreationTest {
-    @RegisterExtension
-    static CassandraClusterExtension cassandraCluster = new CassandraClusterExtension(
-        CassandraModule.aggregateModules(
+    public static final CassandraModule MODULES = CassandraModule.aggregateModules(
             CassandraMessageModule.MODULE,
             CassandraAttachmentModule.MODULE,
-            CassandraBlobModule.MODULE));
+            CassandraBlobModule.MODULE,
+            CassandraSchemaVersionModule.MODULE);
+
+    @RegisterExtension
+    static CassandraClusterExtension cassandraCluster = new CassandraClusterExtension(
+            MODULES);
 
     private CassandraBlobsDAO blobsDAO;
     private CassandraMessageDAO cassandraMessageDAO;
@@ -88,7 +91,7 @@ class AttachmentMessageIdCreationTest {
             blobsDAO, new HashBlobId.Factory(), CassandraUtils.WITH_DEFAULT_CONFIGURATION, messageIdFactory);
 
         attachmentMessageIdDAO = new CassandraAttachmentMessageIdDAO(cassandra.getConf(),
-            new CassandraMessageId.Factory(), CassandraUtils.WITH_DEFAULT_CONFIGURATION);
+            new CassandraMessageId.Factory());
 
         migration = new AttachmentMessageIdCreation(cassandraMessageDAO, attachmentMessageIdDAO);
 
@@ -132,7 +135,7 @@ class AttachmentMessageIdCreationTest {
 
         migration.run();
 
-        assertThat(attachmentMessageIdDAO.getOwnerMessageIds(attachment.getAttachmentId()).join())
+        assertThat(attachmentMessageIdDAO.getOwnerMessageIds(attachment.getAttachmentId()).toIterable())
             .containsExactly(messageId);
     }
 
@@ -142,7 +145,7 @@ class AttachmentMessageIdCreationTest {
         CassandraAttachmentMessageIdDAO attachmentMessageIdDAO = mock(CassandraAttachmentMessageIdDAO.class);
         migration = new AttachmentMessageIdCreation(cassandraMessageDAO, attachmentMessageIdDAO);
 
-        when(cassandraMessageDAO.retrieveAllMessageIdAttachmentIds()).thenThrow(new RuntimeException());
+        when(cassandraMessageDAO.retrieveAllMessageIdAttachmentIds()).thenReturn(Flux.error(new RuntimeException("Mocked exception")));
 
         assertThat(migration.run()).isEqualTo(Migration.Result.PARTIAL);
     }
@@ -157,7 +160,7 @@ class AttachmentMessageIdCreationTest {
 
         when(messageIdAttachmentIds.getAttachmentId()).thenReturn(ImmutableSet.of(AttachmentId.from("any")));
         when(cassandraMessageDAO.retrieveAllMessageIdAttachmentIds())
-            .thenReturn(CompletableFuture.completedFuture(Stream.of(messageIdAttachmentIds)));
+            .thenReturn(Flux.just(messageIdAttachmentIds));
         when(attachmentMessageIdDAO.storeAttachmentForMessageId(any(AttachmentId.class), any(MessageId.class)))
             .thenThrow(new RuntimeException());
 
diff --git a/mailbox/cassandra/src/test/java/org/apache/james/mailbox/cassandra/mail/migration/AttachmentV2MigrationTest.java b/mailbox/cassandra/src/test/java/org/apache/james/mailbox/cassandra/mail/migration/AttachmentV2MigrationTest.java
index 1c8ec6c..f11c800 100644
--- a/mailbox/cassandra/src/test/java/org/apache/james/mailbox/cassandra/mail/migration/AttachmentV2MigrationTest.java
+++ b/mailbox/cassandra/src/test/java/org/apache/james/mailbox/cassandra/mail/migration/AttachmentV2MigrationTest.java
@@ -25,8 +25,6 @@ import static org.mockito.Mockito.mock;
 import static org.mockito.Mockito.when;
 
 import java.nio.charset.StandardCharsets;
-import java.util.concurrent.CompletableFuture;
-import java.util.stream.Stream;
 
 import org.apache.james.backends.cassandra.CassandraCluster;
 import org.apache.james.backends.cassandra.CassandraClusterExtension;
@@ -46,6 +44,7 @@ import org.junit.jupiter.api.BeforeEach;
 import org.junit.jupiter.api.Test;
 import org.junit.jupiter.api.extension.RegisterExtension;
 
+import reactor.core.publisher.Flux;
 import reactor.core.publisher.Mono;
 
 class AttachmentV2MigrationTest {
@@ -95,8 +94,8 @@ class AttachmentV2MigrationTest {
 
     @Test
     void migrationShouldSucceed() throws Exception {
-        attachmentDAO.storeAttachment(attachment1).join();
-        attachmentDAO.storeAttachment(attachment2).join();
+        attachmentDAO.storeAttachment(attachment1).block();
+        attachmentDAO.storeAttachment(attachment2).block();
 
         assertThat(migration.run())
             .isEqualTo(Migration.Result.COMPLETED);
@@ -104,8 +103,8 @@ class AttachmentV2MigrationTest {
 
     @Test
     void migrationShouldMoveAttachmentsToV2() throws Exception {
-        attachmentDAO.storeAttachment(attachment1).join();
-        attachmentDAO.storeAttachment(attachment2).join();
+        attachmentDAO.storeAttachment(attachment1).block();
+        attachmentDAO.storeAttachment(attachment2).block();
 
         migration.run();
 
@@ -121,8 +120,8 @@ class AttachmentV2MigrationTest {
 
     @Test
     void migrationShouldRemoveAttachmentsFromV1() throws Exception {
-        attachmentDAO.storeAttachment(attachment1).join();
-        attachmentDAO.storeAttachment(attachment2).join();
+        attachmentDAO.storeAttachment(attachment1).block();
+        attachmentDAO.storeAttachment(attachment2).block();
 
         migration.run();
 
@@ -139,7 +138,7 @@ class AttachmentV2MigrationTest {
         CassandraBlobsDAO blobsDAO = mock(CassandraBlobsDAO.class);
         migration = new AttachmentV2Migration(attachmentDAO, attachmentDAOV2, blobsDAO);
 
-        when(attachmentDAO.retrieveAll()).thenThrow(new RuntimeException());
+        when(attachmentDAO.retrieveAll()).thenReturn(Flux.error(new RuntimeException()));
 
         assertThat(migration.run()).isEqualTo(Migration.Result.PARTIAL);
     }
@@ -151,7 +150,7 @@ class AttachmentV2MigrationTest {
         CassandraBlobsDAO blobsDAO = mock(CassandraBlobsDAO.class);
         migration = new AttachmentV2Migration(attachmentDAO, attachmentDAOV2, blobsDAO);
 
-        when(attachmentDAO.retrieveAll()).thenReturn(Stream.of(
+        when(attachmentDAO.retrieveAll()).thenReturn(Flux.just(
             attachment1,
             attachment2));
         when(blobsDAO.save(any(byte[].class))).thenThrow(new RuntimeException());
@@ -166,7 +165,7 @@ class AttachmentV2MigrationTest {
         CassandraBlobsDAO blobsDAO = mock(CassandraBlobsDAO.class);
         migration = new AttachmentV2Migration(attachmentDAO, attachmentDAOV2, blobsDAO);
 
-        when(attachmentDAO.retrieveAll()).thenReturn(Stream.of(
+        when(attachmentDAO.retrieveAll()).thenReturn(Flux.just(
             attachment1,
             attachment2));
         when(blobsDAO.save(attachment1.getBytes()))
@@ -185,7 +184,7 @@ class AttachmentV2MigrationTest {
         CassandraBlobsDAO blobsDAO = mock(CassandraBlobsDAO.class);
         migration = new AttachmentV2Migration(attachmentDAO, attachmentDAOV2, blobsDAO);
 
-        when(attachmentDAO.retrieveAll()).thenReturn(Stream.of(
+        when(attachmentDAO.retrieveAll()).thenReturn(Flux.just(
             attachment1,
             attachment2));
         when(blobsDAO.save(attachment1.getBytes()))
@@ -205,7 +204,7 @@ class AttachmentV2MigrationTest {
         CassandraBlobsDAO blobsDAO = mock(CassandraBlobsDAO.class);
         migration = new AttachmentV2Migration(attachmentDAO, attachmentDAOV2, blobsDAO);
 
-        when(attachmentDAO.retrieveAll()).thenReturn(Stream.of(
+        when(attachmentDAO.retrieveAll()).thenReturn(Flux.just(
             attachment1,
             attachment2));
         when(blobsDAO.save(attachment1.getBytes()))
@@ -218,4 +217,4 @@ class AttachmentV2MigrationTest {
         assertThat(migration.run()).isEqualTo(Migration.Result.PARTIAL);
     }
 
-}
\ No newline at end of file
+}
diff --git a/mailbox/cassandra/src/test/java/org/apache/james/mailbox/cassandra/mail/migration/MailboxPathV2MigrationTest.java b/mailbox/cassandra/src/test/java/org/apache/james/mailbox/cassandra/mail/migration/MailboxPathV2MigrationTest.java
index f17ab80..0c59918 100644
--- a/mailbox/cassandra/src/test/java/org/apache/james/mailbox/cassandra/mail/migration/MailboxPathV2MigrationTest.java
+++ b/mailbox/cassandra/src/test/java/org/apache/james/mailbox/cassandra/mail/migration/MailboxPathV2MigrationTest.java
@@ -26,6 +26,7 @@ import org.apache.james.backends.cassandra.CassandraClusterExtension;
 import org.apache.james.backends.cassandra.components.CassandraModule;
 import org.apache.james.backends.cassandra.init.configuration.CassandraConfiguration;
 import org.apache.james.backends.cassandra.utils.CassandraUtils;
+import org.apache.james.backends.cassandra.versions.CassandraSchemaVersionModule;
 import org.apache.james.mailbox.cassandra.ids.CassandraId;
 import org.apache.james.mailbox.cassandra.mail.CassandraACLMapper;
 import org.apache.james.mailbox.cassandra.mail.CassandraIdAndPath;
@@ -51,11 +52,13 @@ class MailboxPathV2MigrationTest {
     private static final SimpleMailbox MAILBOX_1 = new SimpleMailbox(MAILBOX_PATH_1, UID_VALIDITY_1);
     private static final CassandraId MAILBOX_ID_1 = CassandraId.timeBased();
 
-    @RegisterExtension
-    static CassandraClusterExtension cassandraCluster = new CassandraClusterExtension(
-        CassandraModule.aggregateModules(
+    public static final CassandraModule MODULES = CassandraModule.aggregateModules(
             CassandraMailboxModule.MODULE,
-            CassandraAclModule.MODULE));
+            CassandraAclModule.MODULE,
+            CassandraSchemaVersionModule.MODULE);
+
+    @RegisterExtension
+    static CassandraClusterExtension cassandraCluster = new CassandraClusterExtension(MODULES);
 
     private CassandraMailboxPathDAOImpl daoV1;
     private CassandraMailboxPathV2DAO daoV2;
diff --git a/metrics/metrics-api/src/main/java/org/apache/james/metrics/api/MetricFactory.java b/metrics/metrics-api/src/main/java/org/apache/james/metrics/api/MetricFactory.java
index 0b02371..d476cf4 100644
--- a/metrics/metrics-api/src/main/java/org/apache/james/metrics/api/MetricFactory.java
+++ b/metrics/metrics-api/src/main/java/org/apache/james/metrics/api/MetricFactory.java
@@ -19,7 +19,6 @@
 
 package org.apache.james.metrics.api;
 
-import java.util.concurrent.CompletableFuture;
 import java.util.function.Supplier;
 
 import reactor.core.publisher.Mono;
@@ -51,8 +50,4 @@ public interface MetricFactory {
         });
     }
 
-    default <T> CompletableFuture<T> runPublishingTimerMetric(String name, CompletableFuture<T> future) {
-        TimeMetric timer = timer(name);
-        return future.whenComplete((result, throwable) -> timer.stopAndPublish());
-    }
 }
diff --git a/server/blob/blob-cassandra/src/main/java/org/apache/james/blob/cassandra/CassandraBlobsDAO.java b/server/blob/blob-cassandra/src/main/java/org/apache/james/blob/cassandra/CassandraBlobsDAO.java
index 2dfc808..cd77a88 100644
--- a/server/blob/blob-cassandra/src/main/java/org/apache/james/blob/cassandra/CassandraBlobsDAO.java
+++ b/server/blob/blob-cassandra/src/main/java/org/apache/james/blob/cassandra/CassandraBlobsDAO.java
@@ -145,7 +145,7 @@ public class CassandraBlobsDAO implements BlobStore {
     }
 
     private Mono<Integer> writePart(ByteBuffer data, BlobId blobId, int position) {
-        return cassandraAsyncExecutor.executeVoidReactor(
+        return cassandraAsyncExecutor.executeVoid(
             insertPart.bind()
                 .setString(BlobTable.ID, blobId.asString())
                 .setInt(BlobParts.CHUNK_NUMBER, position)
@@ -154,7 +154,7 @@ public class CassandraBlobsDAO implements BlobStore {
     }
 
     private Mono<BlobId> saveBlobPartsReferences(BlobId blobId, int numberOfChunk) {
-        return cassandraAsyncExecutor.executeVoidReactor(
+        return cassandraAsyncExecutor.executeVoid(
             insert.bind()
                 .setString(BlobTable.ID, blobId.asString())
                 .setInt(BlobTable.NUMBER_OF_CHUNK, numberOfChunk))
@@ -169,7 +169,7 @@ public class CassandraBlobsDAO implements BlobStore {
     }
 
     private Mono<Integer> selectRowCount(BlobId blobId) {
-        return cassandraAsyncExecutor.executeSingleRowReactor(
+        return cassandraAsyncExecutor.executeSingleRow(
                 select.bind()
                     .setString(BlobTable.ID, blobId.asString()))
             .map(row -> row.getInt(BlobTable.NUMBER_OF_CHUNK));
@@ -182,7 +182,7 @@ public class CassandraBlobsDAO implements BlobStore {
     }
 
     private Mono<byte[]> readPart(BlobId blobId, int position) {
-        return cassandraAsyncExecutor.executeSingleRowReactor(
+        return cassandraAsyncExecutor.executeSingleRow(
             selectPart.bind()
                 .setString(BlobTable.ID, blobId.asString())
                 .setInt(BlobParts.CHUNK_NUMBER, position))
diff --git a/server/blob/blob-union/src/test/java/org/apache/james/blob/union/UnionBlobStoreTest.java b/server/blob/blob-union/src/test/java/org/apache/james/blob/union/UnionBlobStoreTest.java
index db1a5b5..2bed094 100644
--- a/server/blob/blob-union/src/test/java/org/apache/james/blob/union/UnionBlobStoreTest.java
+++ b/server/blob/blob-union/src/test/java/org/apache/james/blob/union/UnionBlobStoreTest.java
@@ -27,7 +27,6 @@ import java.io.ByteArrayInputStream;
 import java.io.InputStream;
 import java.io.PushbackInputStream;
 import java.util.List;
-import java.util.concurrent.CompletableFuture;
 import java.util.function.Function;
 import java.util.stream.Stream;
 
@@ -331,8 +330,8 @@ class UnionBlobStoreTest implements BlobStoreContract {
         @ParameterizedTest
         @MethodSource("blobStoresCauseThrowExceptions")
         void operationShouldThrow(UnionBlobStore blobStoreThrowsException,
-                                  Function<UnionBlobStore, CompletableFuture<?>> blobStoreOperation) {
-            assertThatThrownBy(() -> blobStoreOperation.apply(blobStoreThrowsException))
+                                  Function<UnionBlobStore, Mono<?>> blobStoreOperation) {
+            assertThatThrownBy(() -> blobStoreOperation.apply(blobStoreThrowsException).block())
                 .isInstanceOf(RuntimeException.class);
         }
 
@@ -450,4 +449,4 @@ class UnionBlobStoreTest implements BlobStoreContract {
         assertThat(pushBackIS)
             .hasSameContentAs(new ByteArrayInputStream(new byte[0]));
     }
-}
\ No newline at end of file
+}
diff --git a/server/container/guice/cassandra-guice/src/test/java/org/apache/james/CassandraVersionCheckingTest.java b/server/container/guice/cassandra-guice/src/test/java/org/apache/james/CassandraVersionCheckingTest.java
index 45e79fc..0b0e335 100644
--- a/server/container/guice/cassandra-guice/src/test/java/org/apache/james/CassandraVersionCheckingTest.java
+++ b/server/container/guice/cassandra-guice/src/test/java/org/apache/james/CassandraVersionCheckingTest.java
@@ -30,7 +30,6 @@ import java.nio.ByteBuffer;
 import java.nio.channels.SocketChannel;
 import java.nio.charset.Charset;
 import java.util.Optional;
-import java.util.concurrent.CompletableFuture;
 
 import org.apache.james.backends.cassandra.versions.CassandraSchemaVersionDAO;
 import org.apache.james.backends.cassandra.versions.CassandraSchemaVersionManager;
@@ -44,6 +43,8 @@ import org.junit.jupiter.api.BeforeEach;
 import org.junit.jupiter.api.Test;
 import org.junit.jupiter.api.extension.RegisterExtension;
 
+import reactor.core.publisher.Mono;
+
 class CassandraVersionCheckingTest {
     private static final int LIMIT_TO_10_MESSAGES = 10;
     private static final String LOCAL_HOST = "127.0.0.1";
@@ -82,7 +83,7 @@ class CassandraVersionCheckingTest {
     @Test
     void serverShouldStartSuccessfullyWhenMaxVersion(GuiceJamesServer server) throws Exception {
         when(versionDAO.getCurrentSchemaVersion())
-            .thenReturn(CompletableFuture.completedFuture(Optional.of(MAX_VERSION)));
+            .thenReturn(Mono.just(Optional.of(MAX_VERSION)));
 
         assertThatServerStartCorrectly(server);
     }
@@ -90,7 +91,7 @@ class CassandraVersionCheckingTest {
     @Test
     void serverShouldStartSuccessfullyWhenBetweenMinAndMaxVersion(GuiceJamesServer server) throws Exception {
         when(versionDAO.getCurrentSchemaVersion())
-            .thenReturn(CompletableFuture.completedFuture(Optional.of(MIN_VERSION.next())));
+            .thenReturn(Mono.just(Optional.of(MIN_VERSION.next())));
 
         assertThatServerStartCorrectly(server);
     }
@@ -98,7 +99,7 @@ class CassandraVersionCheckingTest {
     @Test
     void serverShouldStartSuccessfullyWhenMinVersion(GuiceJamesServer server) throws Exception {
         when(versionDAO.getCurrentSchemaVersion())
-            .thenReturn(CompletableFuture.completedFuture(Optional.of(MIN_VERSION)));
+            .thenReturn(Mono.just(Optional.of(MIN_VERSION)));
 
         assertThatServerStartCorrectly(server);
     }
@@ -106,7 +107,7 @@ class CassandraVersionCheckingTest {
     @Test
     void serverShouldNotStartWhenUnderMinVersion(GuiceJamesServer server) {
         when(versionDAO.getCurrentSchemaVersion())
-            .thenReturn(CompletableFuture.completedFuture(Optional.of(MIN_VERSION.previous())));
+            .thenReturn(Mono.just(Optional.of(MIN_VERSION.previous())));
 
         assertThatThrownBy(server::start).isInstanceOf(IllegalStateException.class);
     }
@@ -114,7 +115,7 @@ class CassandraVersionCheckingTest {
     @Test
     void serverShouldNotStartWhenAboveMaxVersion(GuiceJamesServer server) {
         when(versionDAO.getCurrentSchemaVersion())
-            .thenReturn(CompletableFuture.completedFuture(Optional.of(MAX_VERSION.next())));
+            .thenReturn(Mono.just(Optional.of(MAX_VERSION.next())));
 
         assertThatThrownBy(server::start).isInstanceOf(IllegalStateException.class);
     }
diff --git a/server/container/guice/memory-guice/src/test/java/org/apache/james/GuiceLifecycleHeathCheckTest.java b/server/container/guice/memory-guice/src/test/java/org/apache/james/GuiceLifecycleHeathCheckTest.java
index 24c854c..86576bd 100644
--- a/server/container/guice/memory-guice/src/test/java/org/apache/james/GuiceLifecycleHeathCheckTest.java
+++ b/server/container/guice/memory-guice/src/test/java/org/apache/james/GuiceLifecycleHeathCheckTest.java
@@ -24,7 +24,6 @@ import static io.restassured.config.EncoderConfig.encoderConfig;
 import static io.restassured.config.RestAssuredConfig.newConfig;
 
 import java.nio.charset.StandardCharsets;
-import java.util.concurrent.CompletableFuture;
 import java.util.concurrent.CountDownLatch;
 
 import javax.annotation.PreDestroy;
@@ -44,6 +43,9 @@ import org.junit.jupiter.api.extension.RegisterExtension;
 import io.restassured.RestAssured;
 import io.restassured.builder.RequestSpecBuilder;
 import io.restassured.http.ContentType;
+import reactor.core.publisher.Mono;
+import reactor.core.publisher.MonoProcessor;
+import reactor.core.scheduler.Schedulers;
 
 class GuiceLifecycleHeathCheckTest {
     private static final int LIMIT_TO_10_MESSAGES = 10;
@@ -118,12 +120,14 @@ class GuiceLifecycleHeathCheckTest {
 
         @Test
         void stoppingJamesServerShouldBeUnhealthy(GuiceJamesServer server) {
-            CompletableFuture<Void> stopCompletedFuture = CompletableFuture.completedFuture(null);
-
+            Mono<Void> stopMono = Mono.fromRunnable(() -> { });
             try {
                 configureRequestSpecification(server);
 
-                stopCompletedFuture = CompletableFuture.runAsync(server::stop);
+                stopMono = Mono.fromRunnable(server::stop);
+                stopMono
+                    .publishOn(Schedulers.elastic())
+                    .subscribeWith(MonoProcessor.create());
 
                 when()
                     .get("/healthcheck")
@@ -131,7 +135,7 @@ class GuiceLifecycleHeathCheckTest {
                     .statusCode(HttpStatus.INTERNAL_SERVER_ERROR_500);
             } finally {
                 latch.countDown();
-                stopCompletedFuture.join();
+                stopMono.block();
             }
         }
     }
diff --git a/server/container/guice/protocols/jmap/src/main/java/org/apache/james/utils/JmapGuiceProbe.java b/server/container/guice/protocols/jmap/src/main/java/org/apache/james/utils/JmapGuiceProbe.java
index 3c97d25..76840ce 100644
--- a/server/container/guice/protocols/jmap/src/main/java/org/apache/james/utils/JmapGuiceProbe.java
+++ b/server/container/guice/protocols/jmap/src/main/java/org/apache/james/utils/JmapGuiceProbe.java
@@ -63,11 +63,11 @@ public class JmapGuiceProbe implements GuiceProbe {
     }
 
     public void modifyVacation(AccountId accountId, VacationPatch vacationPatch) {
-        vacationRepository.modifyVacation(accountId, vacationPatch).join();
+        vacationRepository.modifyVacation(accountId, vacationPatch).block();
     }
 
     public Vacation retrieveVacation(AccountId accountId) {
-        return vacationRepository.retrieveVacation(accountId).join();
+        return vacationRepository.retrieveVacation(accountId).block();
     }
 
     public void setInMailboxes(MessageId messageId, String username, MailboxId... mailboxIds) throws MailboxException {
diff --git a/server/container/util/src/main/java/org/apache/james/util/CompletableFutureUtil.java b/server/container/util/src/main/java/org/apache/james/util/CompletableFutureUtil.java
deleted file mode 100644
index c9e0fd8..0000000
--- a/server/container/util/src/main/java/org/apache/james/util/CompletableFutureUtil.java
+++ /dev/null
@@ -1,103 +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.util;
-
-import java.util.ArrayList;
-import java.util.Arrays;
-import java.util.Comparator;
-import java.util.Optional;
-import java.util.concurrent.CompletableFuture;
-import java.util.function.BiFunction;
-import java.util.function.BinaryOperator;
-import java.util.function.Function;
-import java.util.function.Supplier;
-import java.util.stream.Stream;
-
-import com.google.common.collect.ImmutableList;
-
-public class CompletableFutureUtil {
-
-    public static <T> CompletableFuture<Optional<T>> unwrap(CompletableFuture<Optional<CompletableFuture<T>>> base) {
-        return base.thenCompose(
-            optional -> optional.map(future -> future.thenApply(Optional::of))
-                .orElse(CompletableFuture.completedFuture(Optional.empty())));
-    }
-
-    @SuppressWarnings("unchecked")
-    public static <T> CompletableFuture<Stream<T>> allOf(Stream<CompletableFuture<T>> futureStream) {
-        CompletableFuture<T>[] arrayOfFutures = futureStream.toArray(CompletableFuture[]::new);
-
-        return CompletableFuture.allOf(arrayOfFutures)
-            .thenApply(any -> Arrays.stream(arrayOfFutures)
-                .map(CompletableFuture::join));
-    }
-
-    public static <R, T> CompletableFuture<Stream<R>> chainAll(Stream<T> futureStream, Function<T, CompletableFuture<R>> transformationToChain) {
-        ImmutableList<T> elements = futureStream.collect(ImmutableList.toImmutableList());
-        ArrayList<R> results = new ArrayList<>(elements.size());
-
-        CompletableFuture<Void> futureEmptyStream = CompletableFuture.completedFuture(null);
-
-        BiFunction<CompletableFuture<?>, Supplier<CompletableFuture<R>>, CompletableFuture<?>> accumulator =
-            (future, supplier) -> future.thenCompose(any -> supplier.get().thenAccept(results::add));
-
-        BinaryOperator<CompletableFuture<?>> combiner = (f1, f2) -> f1.thenCompose(any -> f2);
-
-        return elements.stream()
-            .map(t -> (Supplier<CompletableFuture<R>>) (() -> transformationToChain.apply(t)))
-            .reduce(futureEmptyStream, accumulator, combiner)
-            .thenApply(any -> results.stream());
-    }
-
-    public static <T, U> CompletableFuture<Stream<U>> map(CompletableFuture<Stream<T>> futurStream, Function<T, U> action) {
-        return futurStream
-            .thenApply(stream ->
-                stream.map(action));
-    }
-
-    public static <T> CompletableFuture<Optional<T>> reduce(BinaryOperator<T> binaryOperator, CompletableFuture<Stream<T>> futureStream) {
-        return futureStream.thenApply(stream -> stream.reduce(binaryOperator));
-    }
-
-    public static <T> CompletableFuture<T> reduce(BinaryOperator<T> binaryOperator, CompletableFuture<Stream<T>> futureStream, T emptyAccumulator) {
-        return futureStream.thenApply(stream -> stream.reduce(binaryOperator).orElse(emptyAccumulator));
-    }
-
-    public static <T> Function<Boolean, CompletableFuture<Boolean>> composeIfTrue(Supplier<CompletableFuture<T>> composeOperation) {
-        return b -> {
-            if (b) {
-                return composeOperation.get().thenApply(any -> b);
-            }
-            return CompletableFuture.completedFuture(b);
-        };
-    }
-
-    public static <T> CompletableFuture<Stream<T>> sorted(CompletableFuture<Stream<T>> futureStream, Comparator<T> comparator) {
-        return futureStream
-            .thenApply(stream ->
-                stream.sorted(comparator));
-    }
-
-    public static <T> CompletableFuture<T> exceptionallyFuture(Throwable throwable) {
-        CompletableFuture<T> failedFuture = new CompletableFuture<>();
-        failedFuture.completeExceptionally(throwable);
-        return failedFuture;
-    }
-}
diff --git a/server/container/util/src/main/java/org/apache/james/util/FluentFutureStream.java b/server/container/util/src/main/java/org/apache/james/util/FluentFutureStream.java
deleted file mode 100644
index 0b0b86e..0000000
--- a/server/container/util/src/main/java/org/apache/james/util/FluentFutureStream.java
+++ /dev/null
@@ -1,166 +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.util;
-
-import java.util.Arrays;
-import java.util.Comparator;
-import java.util.Optional;
-import java.util.concurrent.CompletableFuture;
-import java.util.function.BinaryOperator;
-import java.util.function.Function;
-import java.util.function.Predicate;
-import java.util.stream.Collector;
-import java.util.stream.Stream;
-
-public class FluentFutureStream<T> {
-
-    public static <T> FluentFutureStream<T> unboxStream(FluentFutureStream<Stream<T>> streams) {
-        return FluentFutureStream.of(
-            streams.completableFuture()
-                .thenApply(StreamUtils::flatten));
-    }
-
-    public static <T> FluentFutureStream<T> unboxOptional(FluentFutureStream<Optional<T>> optionals) {
-        return unboxStream(optionals.map(OptionalUtils::toStream));
-    }
-
-    public static <T> FluentFutureStream<T> unboxFuture(FluentFutureStream<CompletableFuture<T>> futures) {
-        return FluentFutureStream.of(futures.completableFuture()
-            .thenCompose(CompletableFutureUtil::allOf));
-    }
-
-    public static <T> FluentFutureStream<T> unboxFluentFuture(FluentFutureStream<FluentFutureStream<T>> futures) {
-        return unboxStream(
-            unboxFuture(
-                futures.map(FluentFutureStream::completableFuture)));
-    }
-
-    public static <T> FluentFutureStream<T> unboxFutureOptional(FluentFutureStream<CompletableFuture<Optional<T>>> futures) {
-        return unboxOptional(unboxFuture(futures));
-    }
-
-    private final CompletableFuture<Stream<T>> completableFuture;
-
-    /**
-     * Constructs a FluentFutureStream from a future of Stream.
-     */
-    public static <T> FluentFutureStream<T> of(CompletableFuture<Stream<T>> completableFuture) {
-        return new FluentFutureStream<>(completableFuture);
-    }
-
-    public static <T, U> FluentFutureStream<U> of(Stream<CompletableFuture<T>> completableFuture,
-                                               Function<FluentFutureStream<T>, FluentFutureStream<U>> unboxer) {
-        return unboxer.apply(of(completableFuture));
-    }
-
-    /**
-     * Constructs a FluentFutureStream from a Stream of Future
-     */
-    public static <T> FluentFutureStream<T> of(Stream<CompletableFuture<T>> completableFutureStream) {
-        return new FluentFutureStream<>(CompletableFutureUtil.allOf(completableFutureStream));
-    }
-
-    @SafeVarargs
-    public static <T> FluentFutureStream<T> ofFutures(CompletableFuture<T>... completableFutures) {
-        return of(Arrays.stream(completableFutures));
-    }
-
-    private FluentFutureStream(CompletableFuture<Stream<T>> completableFuture) {
-        this.completableFuture = completableFuture;
-    }
-
-    /**
-     * For all values of the underlying stream, an action will be performed.
-     */
-    public FluentFutureStream<T> performOnAll(Function<T, CompletableFuture<Void>> action) {
-        return map(t -> action.apply(t).thenApply(any -> t),
-            FluentFutureStream::unboxFuture);
-    }
-
-    /**
-     * Apply a transformation to all values of the underlying stream.
-     */
-    public <U> FluentFutureStream<U> map(Function<T, U> function) {
-        return FluentFutureStream.of(
-            CompletableFutureUtil.map(completableFuture(), function));
-    }
-
-    public <U, V> FluentFutureStream<V> map(Function<T, U> function, Function<FluentFutureStream<U>, FluentFutureStream<V>> unboxer) {
-        return unboxer.apply(map(function));
-    }
-
-    /**
-     * Filter the values of the underlying stream.
-     */
-    public FluentFutureStream<T> filter(Predicate<T> predicate) {
-        return FluentFutureStream.of(completableFuture
-            .thenApply(stream -> stream.filter(predicate)));
-    }
-
-    public FluentFutureStream<T> thenFilter(Function<T, CompletableFuture<Boolean>> futurePredicate) {
-        return map(t -> futurePredicate.apply(t)
-            .thenApply(isKept -> Optional.of(t).filter(any -> isKept)),
-            FluentFutureStream::unboxFutureOptional);
-    }
-
-    /**
-     * Reduces the underlying stream. Reduced value is supplied as a Future of optional, as no empty value is supplied.
-     */
-    public CompletableFuture<Optional<T>> reduce(BinaryOperator<T> combiner) {
-        return CompletableFutureUtil.reduce(combiner, completableFuture);
-    }
-
-    /**
-     * educes the underlying stream. Reduced value is supplied as a Future, as an empty value is specified.
-     */
-    public CompletableFuture<T> reduce(T emptyAccumulator, BinaryOperator<T> combiner) {
-        return CompletableFutureUtil.reduce(combiner, completableFuture, emptyAccumulator);
-    }
-
-    /**
-     * sort all elements of the stream by the provided {@code Comparator}.
-     */
-    public FluentFutureStream<T> sorted(Comparator<T> comparator) {
-        return FluentFutureStream.of(
-            CompletableFutureUtil.sorted(completableFuture(), comparator));
-    }
-
-    /**
-     * Returns a future of the underlying stream.
-     */
-    public CompletableFuture<Stream<T>> completableFuture() {
-        return this.completableFuture;
-    }
-
-    /**
-     * Returns the future of the underlying collected stream.
-     */
-    public <C> CompletableFuture<C> collect(Collector<T, ?, C> collector) {
-        return this.completableFuture
-            .thenApply(stream -> stream.collect(collector));
-    }
-
-    /**
-     * Join and returns the underlying stream.
-     */
-    public Stream<T> join() {
-        return completableFuture().join();
-    }
-}
diff --git a/server/container/util/src/test/java/org/apache/james/util/CompletableFutureUtilTest.java b/server/container/util/src/test/java/org/apache/james/util/CompletableFutureUtilTest.java
deleted file mode 100644
index 3b544e9..0000000
--- a/server/container/util/src/test/java/org/apache/james/util/CompletableFutureUtilTest.java
+++ /dev/null
@@ -1,340 +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.util;
-
-import static org.assertj.core.api.Assertions.assertThat;
-import static org.assertj.core.api.Assertions.assertThatCode;
-
-import java.util.Optional;
-import java.util.concurrent.CompletableFuture;
-import java.util.concurrent.ConcurrentLinkedDeque;
-import java.util.concurrent.ExecutorService;
-import java.util.concurrent.Executors;
-import java.util.concurrent.ThreadFactory;
-import java.util.concurrent.atomic.AtomicInteger;
-import java.util.stream.Collectors;
-import java.util.stream.IntStream;
-import java.util.stream.Stream;
-
-import org.apache.james.util.concurrent.NamedThreadFactory;
-import org.junit.jupiter.api.AfterAll;
-import org.junit.jupiter.api.BeforeAll;
-import org.junit.jupiter.api.Test;
-
-import com.github.steveash.guavate.Guavate;
-import com.google.common.collect.ImmutableList;
-
-public class CompletableFutureUtilTest {
-    private static ExecutorService executorService;
-
-    @BeforeAll
-    static void setUp() {
-        ThreadFactory threadFactory = NamedThreadFactory.withClassName(CompletableFutureUtilTest.class);
-        executorService = Executors.newFixedThreadPool(4, threadFactory);
-    }
-
-    @AfterAll
-    static void tearDown() {
-        executorService.shutdownNow();
-    }
-
-    @Test
-    void allOfShouldUnboxEmptyStream() {
-        assertThat(
-            CompletableFutureUtil.allOf(Stream.empty())
-                .join()
-                .collect(Guavate.toImmutableList()))
-            .isEmpty();
-    }
-
-    @Test
-    void chainAllShouldPreserveExecutionOrder() {
-        int itemCount = 10;
-        ImmutableList<Integer> ints = IntStream.range(0, itemCount)
-            .boxed()
-            .collect(Guavate.toImmutableList());
-
-        ConcurrentLinkedDeque<Integer> queue = new ConcurrentLinkedDeque<>();
-
-        CompletableFutureUtil.chainAll(ints.stream(),
-            i -> CompletableFuture.supplyAsync(() -> {
-                try {
-                    Thread.sleep(itemCount - i);
-                } catch (InterruptedException e) {
-                    throw new RuntimeException(e);
-                }
-                queue.add(i);
-                return i;
-            }, executorService))
-            .join();
-
-        assertThat(queue)
-            .containsExactlyElementsOf(ints);
-    }
-
-    @Test
-    void chainAllShouldNotThrowOnEmptyStream() {
-        Stream<Integer> result = CompletableFutureUtil.chainAll(Stream.<Integer>of(),
-            i -> CompletableFuture.supplyAsync(() -> i, executorService))
-            .join();
-
-        assertThat(result.collect(Guavate.toImmutableList()))
-            .isEmpty();
-    }
-
-    @Test
-    void chainAllShouldPreserveOrder() {
-        int itemCount = 10;
-        ImmutableList<Integer> ints = IntStream.range(0, itemCount)
-            .boxed()
-            .collect(Guavate.toImmutableList());
-
-        Stream<Integer> result = CompletableFutureUtil.chainAll(ints.stream(),
-            i -> CompletableFuture.supplyAsync(() -> i, executorService))
-            .join();
-
-        assertThat(result.collect(Guavate.toImmutableList()))
-            .containsExactlyElementsOf(ints);
-    }
-
-    @Test
-    void allOfShouldUnboxStream() {
-        long value1 = 18L;
-        long value2 = 19L;
-        long value3 = 20L;
-        assertThat(
-            CompletableFutureUtil.allOf(
-                Stream.of(
-                    CompletableFuture.completedFuture(value1),
-                    CompletableFuture.completedFuture(value2),
-                    CompletableFuture.completedFuture(value3)))
-                .join()
-                .collect(Guavate.toImmutableList()))
-            .containsOnly(value1, value2, value3);
-    }
-
-    @Test
-    void allOfShouldSupportNullValue() {
-        assertThatCode(() ->
-            CompletableFutureUtil.allOf(
-                Stream.of(
-                    CompletableFuture.completedFuture(null),
-                    CompletableFuture.completedFuture(null),
-                    CompletableFuture.completedFuture(null)))
-                .join()
-                .collect(Collectors.toList()))
-            .doesNotThrowAnyException();
-    }
-
-    @Test
-    void allOfShouldPreserveOrder() {
-        long value1 = 18L;
-        long value2 = 19L;
-        long value3 = 20L;
-        long value4 = 21L;
-        long value5 = 22L;
-        long value6 = 23L;
-        long value7 = 24L;
-        long value8 = 25L;
-        long value9 = 26L;
-        long value10 = 27L;
-        assertThat(
-            CompletableFutureUtil.allOf(
-                Stream.of(
-                    CompletableFuture.completedFuture(value1),
-                    CompletableFuture.completedFuture(value2),
-                    CompletableFuture.completedFuture(value3),
-                    CompletableFuture.completedFuture(value4),
-                    CompletableFuture.completedFuture(value5),
-                    CompletableFuture.completedFuture(value6),
-                    CompletableFuture.completedFuture(value7),
-                    CompletableFuture.completedFuture(value8),
-                    CompletableFuture.completedFuture(value9),
-                    CompletableFuture.completedFuture(value10)))
-                .join()
-                .collect(Guavate.toImmutableList()))
-            .containsExactly(value1, value2, value3, value4, value5, value6, value7, value8, value9, value10);
-    }
-
-    @Test
-    void allOfShouldWorkOnVeryLargeStream() {
-        CompletableFutureUtil.allOf(
-            IntStream.range(0, 100000)
-                .boxed()
-                .map(CompletableFuture::completedFuture))
-            .join();
-    }
-
-    @Test
-    void mapShouldMapOnStreamInsideACompletableFuturOfStream() {
-        CompletableFuture<Stream<Integer>> futurOfInteger = CompletableFuture.completedFuture(Stream.of(1, 2, 3));
-
-        assertThat(
-            CompletableFutureUtil.map(futurOfInteger, integer ->
-                integer * 2)
-                .join()
-                .collect(Guavate.toImmutableList()))
-            .containsExactly(2, 4, 6);
-    }
-
-    @Test
-    void mapShouldReturnEmptyStreamWhenGivenAnEmptyStream() {
-        CompletableFuture<Stream<Integer>> futurOfInteger = CompletableFuture.completedFuture(Stream.of());
-
-        assertThat(
-            CompletableFutureUtil.map(futurOfInteger, integer ->
-                integer * 2)
-                .join()
-                .collect(Guavate.toImmutableList()))
-            .isEmpty();
-    }
-
-    @Test
-    void composeIfTrueShouldReturnTrueWhenTrue() {
-        assertThat(
-            CompletableFutureUtil.composeIfTrue(() -> CompletableFuture.completedFuture(null))
-                .apply(true)
-                .join())
-            .isTrue();
-    }
-
-    @Test
-    void composeIfTrueShouldReturnFalseWhenFalse() {
-        assertThat(
-            CompletableFutureUtil.composeIfTrue(() -> CompletableFuture.completedFuture(null))
-                .apply(false)
-                .join())
-            .isFalse();
-    }
-
-    @Test
-    void composeIfTrueShouldComposeWhenTrue() {
-        AtomicInteger atomicInteger = new AtomicInteger(0);
-        CompletableFutureUtil.composeIfTrue(() -> {
-            atomicInteger.incrementAndGet();
-            return CompletableFuture.completedFuture(null);
-        })
-            .apply(true)
-            .join();
-
-        assertThat(atomicInteger.get()).isEqualTo(1);
-    }
-
-    @Test
-    void composeIfTrueShouldNotComposeWhenFalse() {
-        AtomicInteger atomicInteger = new AtomicInteger(0);
-        CompletableFutureUtil.composeIfTrue(() -> {
-            atomicInteger.incrementAndGet();
-            return CompletableFuture.completedFuture(null);
-        })
-            .apply(false)
-            .join();
-
-        assertThat(atomicInteger.get()).isEqualTo(0);
-    }
-
-    @Test
-    void reduceShouldReturnEmptyWhenNoValue() {
-        assertThat(
-            CompletableFutureUtil.reduce(
-                (i, j) -> i + j,
-                CompletableFuture.completedFuture(Stream.<Long>of()))
-                .join())
-            .isEmpty();
-    }
-
-    @Test
-    void reduceShouldWork() {
-        assertThat(
-            CompletableFutureUtil.reduce(
-                (i, j) -> i + j,
-                CompletableFuture.completedFuture(Stream.of(
-                    1L, 2L, 3L)))
-                .join())
-            .contains(6L);
-    }
-
-    @Test
-    void reduceShouldReturnIdentityAccumulatorWhenNoValue() {
-        long identityAccumulator = 0L;
-        assertThat(
-            CompletableFutureUtil.reduce(
-                (i, j) -> i + j,
-                CompletableFuture.completedFuture(Stream.of()),
-                identityAccumulator)
-                .join())
-            .isEqualTo(identityAccumulator);
-    }
-
-    @Test
-    void reduceShouldWorkWithIdentityAccumulator() {
-        assertThat(
-            CompletableFutureUtil.reduce(
-                (i, j) -> i + j,
-                CompletableFuture.completedFuture(Stream.of(1L, 2L,3L)),
-                0L)
-                .join())
-            .isEqualTo(6L);
-    }
-
-    @Test
-    void unwrapShouldUnwrapWhenValue() {
-        assertThat(
-            CompletableFutureUtil.unwrap(
-                    CompletableFuture.completedFuture(Optional.of(CompletableFuture.completedFuture(1L))))
-                .join())
-            .isEqualTo(Optional.of(1L));
-    }
-
-    @Test
-    void unwrapShouldUnwrapWhenEmpty() {
-        assertThat(
-            CompletableFutureUtil.unwrap(
-                    CompletableFuture.completedFuture(Optional.empty()))
-                .join())
-            .isEmpty();
-    }
-
-    @Test
-    void sortShouldReturnEmptyWhenEmptyStream() {
-        FluentFutureStream<Long> futureStream = FluentFutureStream.ofFutures();
-        assertThat(futureStream.sorted(Long::compareTo).join())
-            .isEmpty();
-    }
-
-    @Test
-    void sortShouldReturnTheSortedStream() {
-        FluentFutureStream<Long> futureStream = FluentFutureStream.ofFutures(
-            CompletableFuture.completedFuture(4L),
-            CompletableFuture.completedFuture(3L),
-            CompletableFuture.completedFuture(2L),
-            CompletableFuture.completedFuture(1L));
-
-        assertThat(futureStream.sorted(Long::compareTo).join())
-            .containsExactly(1L, 2L, 3L, 4L);
-    }
-
-    @Test
-    void exceptionallyFutureShouldReturnACompletedExceptionallyFuture() {
-        CompletableFuture<Object> failedFuture = CompletableFutureUtil.exceptionallyFuture(new Exception("failure"));
-        assertThat(failedFuture)
-            .isCompletedExceptionally();
-    }
-}
diff --git a/server/container/util/src/test/java/org/apache/james/util/FluentFutureStreamTest.java b/server/container/util/src/test/java/org/apache/james/util/FluentFutureStreamTest.java
deleted file mode 100644
index 2745280..0000000
--- a/server/container/util/src/test/java/org/apache/james/util/FluentFutureStreamTest.java
+++ /dev/null
@@ -1,293 +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.util;
-
-import static org.assertj.core.api.Assertions.assertThat;
-
-import java.util.Optional;
-import java.util.concurrent.CompletableFuture;
-import java.util.concurrent.ConcurrentLinkedDeque;
-import java.util.stream.Stream;
-
-import org.junit.jupiter.api.Test;
-
-import com.github.steveash.guavate.Guavate;
-
-public class FluentFutureStreamTest {
-
-    @Test
-    void ofFutureShouldConstructAFluentFutureStream() {
-        assertThat(
-            FluentFutureStream.ofFutures(
-                CompletableFuture.completedFuture(1),
-                CompletableFuture.completedFuture(2),
-                CompletableFuture.completedFuture(3))
-                .join()
-                .collect(Guavate.toImmutableList()))
-            .containsExactly(1, 2, 3);
-    }
-
-    @Test
-    void ofShouldConstructAFluentFutureStreamWhenProvidedAFutureOfStream() {
-        assertThat(
-            FluentFutureStream.of(
-                CompletableFuture.completedFuture(
-                    Stream.of(1, 2, 3)))
-                .join()
-                .collect(Guavate.toImmutableList()))
-            .containsExactly(1, 2, 3);
-    }
-
-    @Test
-    void ofShouldConstructAFluentFutureStreamWhenProvidedAStreamOfFuture() {
-        assertThat(
-            FluentFutureStream.of(
-                Stream.of(
-                    CompletableFuture.completedFuture(1),
-                    CompletableFuture.completedFuture(2),
-                    CompletableFuture.completedFuture(3)))
-                .join()
-                .collect(Guavate.toImmutableList()))
-            .containsExactly(1, 2, 3);
-    }
-
-    @Test
-    void ofNestedStreamsShouldConstructAFluentFutureStreamWhenProvidedAStreamOfFutureOfStream() {
-        assertThat(
-            FluentFutureStream.<Stream<Integer>, Integer>of(
-                Stream.of(
-                    CompletableFuture.completedFuture(Stream.of(1, 2)),
-                    CompletableFuture.completedFuture(Stream.of()),
-                    CompletableFuture.completedFuture(Stream.of(3))),
-                    FluentFutureStream::unboxStream)
-                .join()
-                .collect(Guavate.toImmutableList()))
-            .containsExactly(1, 2, 3);
-    }
-
-
-    @Test
-    void ofOptionalsShouldConstructAFluentFutureStreamWhenProvidedAStreamOfFutureOfOptionals() {
-        assertThat(
-            FluentFutureStream.<Optional<Integer>, Integer>of(
-                Stream.of(
-                    CompletableFuture.completedFuture(Optional.of(1)),
-                    CompletableFuture.completedFuture(Optional.of(2)),
-                    CompletableFuture.completedFuture(Optional.empty()),
-                    CompletableFuture.completedFuture(Optional.of(3))),
-                    FluentFutureStream::unboxOptional)
-                .join()
-                .collect(Guavate.toImmutableList()))
-            .containsExactly(1, 2, 3);
-    }
-
-    @Test
-    void completableFutureShouldReturnAFutureOfTheUnderLayingStream() {
-        assertThat(
-            FluentFutureStream.of(
-                CompletableFuture.completedFuture(
-                    Stream.of(1, 2, 3)))
-                .completableFuture()
-                .join()
-                .collect(Guavate.toImmutableList()))
-            .containsExactly(1, 2, 3);
-    }
-
-    @Test
-    void mapShouldTransformUnderlyingValues() {
-        assertThat(
-            FluentFutureStream.of(
-                CompletableFuture.completedFuture(
-                    Stream.of(1, 2, 3)))
-                .map(i -> i + 1)
-                .join()
-                .collect(Guavate.toImmutableList()))
-            .containsExactly(2, 3, 4);
-    }
-
-    @Test
-    void flatMapShouldTransformUnderlyingValuesAndFlatMapResult() {
-        assertThat(
-            FluentFutureStream.of(
-                CompletableFuture.completedFuture(
-                    Stream.of(1, 2, 3)))
-                .map(i -> Stream.of(i, i + 1), FluentFutureStream::unboxStream)
-                .join()
-                .collect(Guavate.toImmutableList()))
-            .containsExactly(1, 2, 2, 3, 3, 4);
-    }
-
-    @Test
-    void flatMapOptionalShouldTransformUnderlyingValuesAndUnboxResult() {
-        assertThat(
-            FluentFutureStream.of(
-                CompletableFuture.completedFuture(
-                    Stream.of(1, 2, 3)))
-                .map(i -> Optional.of(i + 1)
-                    .filter(j -> j % 2 == 0),
-                    FluentFutureStream::unboxOptional)
-                .join()
-                .collect(Guavate.toImmutableList()))
-            .containsExactly(2, 4);
-    }
-
-    @Test
-    void reduceShouldGatherAllValuesOfTheUnderlyingStream() {
-        assertThat(
-            FluentFutureStream.of(
-                CompletableFuture.completedFuture(
-                    Stream.of(1, 2, 3)))
-                .reduce((a, b) -> a + b)
-                .join())
-            .contains(6);
-    }
-
-    @Test
-    void reduceShouldGatherAllValuesOfTheUnderlyingStreamWithAnEmptyValue() {
-        assertThat(
-            FluentFutureStream.of(
-                CompletableFuture.completedFuture(
-                    Stream.of(1, 2, 3)))
-                .reduce(0, (a, b) -> a + b)
-                .join())
-            .isEqualTo(6);
-    }
-
-    @Test
-    void filterShouldBeAppliedOnTheUnderlyingStream() {
-        assertThat(
-            FluentFutureStream.of(
-                CompletableFuture.completedFuture(
-                    Stream.of(1, 2, 3)))
-                .filter(i -> i % 2 == 1)
-                .join()
-                .collect(Guavate.toImmutableList()))
-            .containsExactly(1, 3);
-    }
-
-    @Test
-    void thenFilterShouldBeAppliedOnTheUnderlyingStream() {
-        assertThat(
-            FluentFutureStream.of(
-                CompletableFuture.completedFuture(
-                    Stream.of(1, 2, 3)))
-                .thenFilter(i -> CompletableFuture.completedFuture(i % 2 == 1))
-                .join()
-                .collect(Guavate.toImmutableList()))
-            .containsExactly(1, 3);
-    }
-
-    @Test
-    void thenComposeOnAllShouldTransformUnderlyingValuesAndComposeFutures() {
-        assertThat(
-            FluentFutureStream.of(
-                CompletableFuture.completedFuture(
-                    Stream.of(1, 2, 3)))
-                .map(i -> CompletableFuture.completedFuture(i + 1), FluentFutureStream::unboxFuture)
-                .join()
-                .collect(Guavate.toImmutableList()))
-            .containsExactly(2, 3, 4);
-    }
-
-    @Test
-    void thenFlatComposeShouldTransformUnderlyingValuesAndComposeFuturesWithStreamUnboxing() {
-        assertThat(
-            FluentFutureStream.of(
-                CompletableFuture.completedFuture(
-                    Stream.of(1, 2, 3)))
-                .map(i -> FluentFutureStream.of(CompletableFuture.completedFuture(Stream.of(i, i + 1))), FluentFutureStream::unboxFluentFuture)
-                .join()
-                .collect(Guavate.toImmutableList()))
-            .containsExactly(1, 2, 2, 3, 3, 4);
-    }
-
-    @Test
-    void thenFlatComposeOnOptionalShouldTransformUnderlyingValuesAndComposeFuturesWithOptionalUnboxing() {
-        assertThat(
-            FluentFutureStream.of(
-                CompletableFuture.completedFuture(
-                    Stream.of(1, 2, 3)))
-                .map(i -> CompletableFuture.completedFuture(
-                    Optional.of(i + 1).filter(j -> j % 2 == 0)),
-                    FluentFutureStream::unboxFutureOptional)
-                .join()
-                .collect(Guavate.toImmutableList()))
-            .containsExactly(2, 4);
-    }
-
-    @Test
-    void thenPerformOnAllShouldGenerateASynchronousSideEffectForAllElementsOfTheUnderlyingStream() {
-        ConcurrentLinkedDeque<Integer> sideEffects = new ConcurrentLinkedDeque<>();
-
-        FluentFutureStream.of(
-            CompletableFuture.completedFuture(
-                Stream.of(1, 2, 3)))
-            .performOnAll(i -> {
-                sideEffects.addLast(i);
-                return CompletableFuture.completedFuture(null);
-            })
-            .join()
-            .collect(Guavate.toImmutableList());
-
-        assertThat(sideEffects).containsOnly(1, 2, 3);
-    }
-
-    @Test
-    void collectShouldReturnTheCollectionOfData() {
-        assertThat(
-            FluentFutureStream.of(
-                Stream.of(
-                    CompletableFuture.completedFuture(1),
-                    CompletableFuture.completedFuture(2),
-                    CompletableFuture.completedFuture(3)))
-                .collect(Guavate.toImmutableList())
-                .join())
-            .containsExactly(1, 2, 3);
-    }
-
-    @Test
-    void collectShouldReturnEmptyWhenStreamIsEmpty() {
-        assertThat(
-            FluentFutureStream.ofFutures()
-                .collect(Guavate.toImmutableList())
-                .join())
-            .isEmpty();
-    }
-
-    @Test
-    void sortedShouldReturnInOrderElements() {
-        assertThat(
-            FluentFutureStream.of(
-                CompletableFuture.completedFuture(Stream.of(4L, 3L, 2L, 1L)))
-                .sorted(Long::compareTo)
-                .join())
-            .containsExactly(1L, 2L, 3L, 4L);
-    }
-
-    @Test
-    void sortedShouldReturnEmptyWhenEmpty() {
-        CompletableFuture<Stream<Long>> completableFutureStream = CompletableFuture.completedFuture(Stream.of());
-        assertThat(
-            FluentFutureStream.of(completableFutureStream)
-                .sorted(Long::compareTo)
-                .join())
-            .isEmpty();
-    }
-}
diff --git a/server/data/data-cassandra/src/main/java/org/apache/james/domainlist/cassandra/CassandraDomainList.java b/server/data/data-cassandra/src/main/java/org/apache/james/domainlist/cassandra/CassandraDomainList.java
index 830b01c..1766aeb 100644
--- a/server/data/data-cassandra/src/main/java/org/apache/james/domainlist/cassandra/CassandraDomainList.java
+++ b/server/data/data-cassandra/src/main/java/org/apache/james/domainlist/cassandra/CassandraDomainList.java
@@ -32,7 +32,6 @@ import java.util.List;
 import javax.inject.Inject;
 
 import org.apache.james.backends.cassandra.utils.CassandraAsyncExecutor;
-import org.apache.james.backends.cassandra.utils.CassandraUtils;
 import org.apache.james.core.Domain;
 import org.apache.james.dnsservice.api.DNSService;
 import org.apache.james.domainlist.api.DomainListException;
@@ -40,22 +39,19 @@ import org.apache.james.domainlist.lib.AbstractDomainList;
 
 import com.datastax.driver.core.PreparedStatement;
 import com.datastax.driver.core.Session;
-import com.github.steveash.guavate.Guavate;
-import com.google.common.annotations.VisibleForTesting;
+import reactor.core.publisher.Flux;
 
 public class CassandraDomainList extends AbstractDomainList {
     private final CassandraAsyncExecutor executor;
-    private final CassandraUtils cassandraUtils;
     private final PreparedStatement readAllStatement;
     private final PreparedStatement readStatement;
     private final PreparedStatement insertStatement;
     private final PreparedStatement removeStatement;
 
     @Inject
-    public CassandraDomainList(DNSService dnsService, Session session, CassandraUtils cassandraUtils) {
+    public CassandraDomainList(DNSService dnsService, Session session) {
         super(dnsService);
         this.executor = new CassandraAsyncExecutor(session);
-        this.cassandraUtils = cassandraUtils;
         this.readAllStatement = prepareReadAllStatement(session);
         this.readStatement = prepareReadStatement(session);
         this.insertStatement = prepareInsertStatement(session);
@@ -86,25 +82,20 @@ public class CassandraDomainList extends AbstractDomainList {
             .from(TABLE_NAME));
     }
 
-    @VisibleForTesting
-    CassandraDomainList(DNSService dnsService, Session session) {
-        this(dnsService, session, CassandraUtils.WITH_DEFAULT_CONFIGURATION);
-    }
-
     @Override
     protected List<Domain> getDomainListInternal() throws DomainListException {
         return executor.execute(readAllStatement.bind())
-            .thenApply(resultSet -> cassandraUtils.convertToStream(resultSet)
-                .map(row -> Domain.of(row.getString(DOMAIN)))
-                .collect(Guavate.toImmutableList()))
-            .join();
+            .flatMapMany(Flux::fromIterable)
+            .map(row -> Domain.of(row.getString(DOMAIN)))
+            .collectList()
+            .block();
     }
 
     @Override
     protected boolean containsDomainInternal(Domain domain) throws DomainListException {
-        return executor.executeSingleRow(readStatement.bind()
+        return executor.executeSingleRowOptional(readStatement.bind()
                 .setString(DOMAIN, domain.asString()))
-            .join()
+            .block()
             .isPresent();
     }
 
diff --git a/server/data/data-cassandra/src/main/java/org/apache/james/mailrepository/cassandra/CassandraMailRepositoryUrlStore.java b/server/data/data-cassandra/src/main/java/org/apache/james/mailrepository/cassandra/CassandraMailRepositoryUrlStore.java
index b4c482a..c304283 100644
--- a/server/data/data-cassandra/src/main/java/org/apache/james/mailrepository/cassandra/CassandraMailRepositoryUrlStore.java
+++ b/server/data/data-cassandra/src/main/java/org/apache/james/mailrepository/cassandra/CassandraMailRepositoryUrlStore.java
@@ -37,19 +37,19 @@ public class CassandraMailRepositoryUrlStore implements MailRepositoryUrlStore {
 
     @Override
     public void add(MailRepositoryUrl url) {
-        urlsDao.addUrl(url).join();
+        urlsDao.addUrl(url).block();
     }
 
     @Override
     public Stream<MailRepositoryUrl> listDistinct() {
         return urlsDao.retrieveUsedUrls()
-            .join();
+            .toStream();
     }
 
     @Override
     public boolean contains(MailRepositoryUrl url) {
         return urlsDao.retrieve(url)
-            .join()
+            .block()
             .isPresent();
     }
 }
diff --git a/server/data/data-cassandra/src/main/java/org/apache/james/mailrepository/cassandra/UrlsDao.java b/server/data/data-cassandra/src/main/java/org/apache/james/mailrepository/cassandra/UrlsDao.java
index 0a05b6e..4421e49 100644
--- a/server/data/data-cassandra/src/main/java/org/apache/james/mailrepository/cassandra/UrlsDao.java
+++ b/server/data/data-cassandra/src/main/java/org/apache/james/mailrepository/cassandra/UrlsDao.java
@@ -27,30 +27,27 @@ import static org.apache.james.mailrepository.cassandra.UrlsTable.TABLE_NAME;
 import static org.apache.james.mailrepository.cassandra.UrlsTable.URL;
 
 import java.util.Optional;
-import java.util.concurrent.CompletableFuture;
-import java.util.stream.Stream;
 
 import javax.inject.Inject;
 
 import org.apache.james.backends.cassandra.utils.CassandraAsyncExecutor;
-import org.apache.james.backends.cassandra.utils.CassandraUtils;
 import org.apache.james.mailrepository.api.MailRepositoryUrl;
 
 import com.datastax.driver.core.PreparedStatement;
 import com.datastax.driver.core.Row;
 import com.datastax.driver.core.Session;
+import reactor.core.publisher.Flux;
+import reactor.core.publisher.Mono;
 
 public class UrlsDao {
     private final CassandraAsyncExecutor executor;
     private final PreparedStatement insert;
     private final PreparedStatement selectAll;
     private final PreparedStatement select;
-    private final CassandraUtils cassandraUtils;
 
     @Inject
-    public UrlsDao(Session session, CassandraUtils cassandraUtils) {
+    public UrlsDao(Session session) {
         this.executor = new CassandraAsyncExecutor(session);
-        this.cassandraUtils = cassandraUtils;
 
         this.insert = prepareInsert(session);
         this.selectAll = prepareSelectAll(session);
@@ -73,23 +70,23 @@ public class UrlsDao {
             .value(URL, bindMarker(URL)));
     }
 
-    public CompletableFuture<Void> addUrl(MailRepositoryUrl url) {
+    public Mono<Void> addUrl(MailRepositoryUrl url) {
         return executor.executeVoid(
             insert.bind()
                 .setString(URL, url.asString()));
     }
 
-    public CompletableFuture<Optional<MailRepositoryUrl>> retrieve(MailRepositoryUrl url) {
-        return executor.executeSingleRow(
-            select.bind()
-                .setString(URL, url.asString()))
-            .thenApply(optional -> optional.map(this::toUrl));
+    public Mono<Optional<MailRepositoryUrl>> retrieve(MailRepositoryUrl url) {
+        return executor.executeSingleRowOptional(
+                select.bind()
+                    .setString(URL, url.asString()))
+            .map(optional -> optional.map(this::toUrl));
     }
 
-    public CompletableFuture<Stream<MailRepositoryUrl>> retrieveUsedUrls() {
+    public Flux<MailRepositoryUrl> retrieveUsedUrls() {
         return executor.execute(selectAll.bind())
-            .thenApply(resultSet -> cassandraUtils.convertToStream(resultSet)
-                .map(this::toUrl));
+            .flatMapMany(Flux::fromIterable)
+            .map(this::toUrl);
     }
 
     private MailRepositoryUrl toUrl(Row row) {
diff --git a/server/data/data-cassandra/src/main/java/org/apache/james/rrt/cassandra/CassandraMappingsSourcesDAO.java b/server/data/data-cassandra/src/main/java/org/apache/james/rrt/cassandra/CassandraMappingsSourcesDAO.java
index d7d5fb3..21a81e3 100644
--- a/server/data/data-cassandra/src/main/java/org/apache/james/rrt/cassandra/CassandraMappingsSourcesDAO.java
+++ b/server/data/data-cassandra/src/main/java/org/apache/james/rrt/cassandra/CassandraMappingsSourcesDAO.java
@@ -85,21 +85,21 @@ public class CassandraMappingsSourcesDAO {
     }
 
     public Mono<Void> addMapping(Mapping mapping, MappingSource source) {
-        return executor.executeVoidReactor(insertStatement.bind()
+        return executor.executeVoid(insertStatement.bind()
             .setString(MAPPING_TYPE, mapping.getType().asPrefix())
             .setString(MAPPING_VALUE, mapping.getMappingValue())
             .setString(SOURCE, source.asMailAddressString()));
     }
 
     Mono<Void> removeMapping(Mapping mapping, MappingSource source) {
-        return executor.executeVoidReactor(deleteStatement.bind()
+        return executor.executeVoid(deleteStatement.bind()
             .setString(MAPPING_TYPE, mapping.getType().asPrefix())
             .setString(MAPPING_VALUE, mapping.getMappingValue())
             .setString(SOURCE, source.asMailAddressString()));
     }
 
     public Flux<MappingSource> retrieveSources(Mapping mapping) {
-        return executor.executeReactor(retrieveSourcesStatement.bind()
+        return executor.execute(retrieveSourcesStatement.bind()
             .setString(MAPPING_TYPE, mapping.getType().asPrefix())
             .setString(MAPPING_VALUE, mapping.getMappingValue()))
             .flatMapMany(Flux::fromIterable)
@@ -107,6 +107,6 @@ public class CassandraMappingsSourcesDAO {
     }
 
     public Mono<Void> removeAllData() {
-        return executor.executeVoidReactor(truncateStatement.bind());
+        return executor.executeVoid(truncateStatement.bind());
     }
 }
diff --git a/server/data/data-cassandra/src/main/java/org/apache/james/rrt/cassandra/CassandraRecipientRewriteTable.java b/server/data/data-cassandra/src/main/java/org/apache/james/rrt/cassandra/CassandraRecipientRewriteTable.java
index bcd7283..d554b13 100644
--- a/server/data/data-cassandra/src/main/java/org/apache/james/rrt/cassandra/CassandraRecipientRewriteTable.java
+++ b/server/data/data-cassandra/src/main/java/org/apache/james/rrt/cassandra/CassandraRecipientRewriteTable.java
@@ -99,7 +99,7 @@ public class CassandraRecipientRewriteTable extends AbstractRecipientRewriteTabl
             String.format("Not supported mapping of type %s", mapping.getType()));
 
         SchemaVersion schemaVersion = cassandraSchemaVersionDAO.getCurrentSchemaVersion()
-            .join()
+            .block()
             .orElse(CassandraSchemaVersionManager.MIN_VERSION);
 
         if (schemaVersion.isBefore(MAPPINGS_SOURCES_SUPPORTED_VERSION)) {
diff --git a/server/data/data-cassandra/src/main/java/org/apache/james/rrt/cassandra/CassandraRecipientRewriteTableDAO.java b/server/data/data-cassandra/src/main/java/org/apache/james/rrt/cassandra/CassandraRecipientRewriteTableDAO.java
index fe31f1f..6c1078e 100644
--- a/server/data/data-cassandra/src/main/java/org/apache/james/rrt/cassandra/CassandraRecipientRewriteTableDAO.java
+++ b/server/data/data-cassandra/src/main/java/org/apache/james/rrt/cassandra/CassandraRecipientRewriteTableDAO.java
@@ -91,21 +91,21 @@ public class CassandraRecipientRewriteTableDAO {
     }
 
     public Mono<Void> addMapping(MappingSource source, Mapping mapping) {
-        return executor.executeVoidReactor(insertStatement.bind()
+        return executor.executeVoid(insertStatement.bind()
             .setString(USER, source.getFixedUser())
             .setString(DOMAIN, source.getFixedDomain())
             .setString(MAPPING, mapping.asString()));
     }
 
     Mono<Void> removeMapping(MappingSource source, Mapping mapping) {
-        return executor.executeVoidReactor(deleteStatement.bind()
+        return executor.executeVoid(deleteStatement.bind()
             .setString(USER, source.getFixedUser())
             .setString(DOMAIN, source.getFixedDomain())
             .setString(MAPPING, mapping.asString()));
     }
 
     Mono<MappingsImpl> retrieveMappings(MappingSource source) {
-        return executor.executeReactor(retrieveMappingStatement.bind()
+        return executor.execute(retrieveMappingStatement.bind()
             .setString(USER, source.getFixedUser())
             .setString(DOMAIN, source.getFixedDomain()))
             .map(resultSet -> cassandraUtils.convertToStream(resultSet)
@@ -116,7 +116,7 @@ public class CassandraRecipientRewriteTableDAO {
     }
 
     public Flux<Pair<MappingSource, Mapping>> getAllMappings() {
-        return executor.executeReactor(retrieveAllMappingsStatement.bind())
+        return executor.execute(retrieveAllMappingsStatement.bind())
             .flatMapMany(Flux::fromIterable)
             .map(row -> Pair.of(
                 MappingSource.fromUser(row.getString(USER), row.getString(DOMAIN)),
diff --git a/server/data/data-cassandra/src/main/java/org/apache/james/sieve/cassandra/CassandraActiveScriptDAO.java b/server/data/data-cassandra/src/main/java/org/apache/james/sieve/cassandra/CassandraActiveScriptDAO.java
index 10049e1..26bf3c3 100644
--- a/server/data/data-cassandra/src/main/java/org/apache/james/sieve/cassandra/CassandraActiveScriptDAO.java
+++ b/server/data/data-cassandra/src/main/java/org/apache/james/sieve/cassandra/CassandraActiveScriptDAO.java
@@ -66,7 +66,7 @@ public class CassandraActiveScriptDAO {
     }
 
     public Mono<ActiveScriptInfo> getActiveSctiptInfo(User user) {
-        return cassandraAsyncExecutor.executeSingleRowReactor(
+        return cassandraAsyncExecutor.executeSingleRow(
             selectActiveName.bind()
                 .setString(USER_NAME, user.asString()))
             .map(row -> new ActiveScriptInfo(
@@ -75,13 +75,13 @@ public class CassandraActiveScriptDAO {
     }
 
     public Mono<Void> unactivate(User user) {
-        return cassandraAsyncExecutor.executeVoidReactor(
+        return cassandraAsyncExecutor.executeVoid(
             deleteActive.bind()
                 .setString(USER_NAME, user.asString()));
     }
 
     public Mono<Void> activate(User user, ScriptName scriptName) {
-        return cassandraAsyncExecutor.executeVoidReactor(
+        return cassandraAsyncExecutor.executeVoid(
             insertActive.bind()
                 .setString(USER_NAME, user.asString())
                 .setString(SCRIPT_NAME, scriptName.getValue())
diff --git a/server/data/data-cassandra/src/main/java/org/apache/james/sieve/cassandra/CassandraSieveDAO.java b/server/data/data-cassandra/src/main/java/org/apache/james/sieve/cassandra/CassandraSieveDAO.java
index d3cf741..e4895ad 100644
--- a/server/data/data-cassandra/src/main/java/org/apache/james/sieve/cassandra/CassandraSieveDAO.java
+++ b/server/data/data-cassandra/src/main/java/org/apache/james/sieve/cassandra/CassandraSieveDAO.java
@@ -33,9 +33,6 @@ import static org.apache.james.sieve.cassandra.tables.CassandraSieveTable.SIZE;
 import static org.apache.james.sieve.cassandra.tables.CassandraSieveTable.TABLE_NAME;
 import static org.apache.james.sieve.cassandra.tables.CassandraSieveTable.USER_NAME;
 
-import java.util.List;
-import java.util.concurrent.CompletableFuture;
-
 import javax.inject.Inject;
 
 import org.apache.james.backends.cassandra.utils.CassandraAsyncExecutor;
@@ -48,7 +45,7 @@ import com.datastax.driver.core.PreparedStatement;
 import com.datastax.driver.core.Row;
 import com.datastax.driver.core.Session;
 import com.datastax.driver.core.querybuilder.Select;
-import com.github.steveash.guavate.Guavate;
+import reactor.core.publisher.Flux;
 import reactor.core.publisher.Mono;
 
 public class CassandraSieveDAO {
@@ -99,7 +96,7 @@ public class CassandraSieveDAO {
     }
 
     public Mono<Void> insertScript(User user, Script script) {
-        return cassandraAsyncExecutor.executeVoidReactor(
+        return cassandraAsyncExecutor.executeVoid(
             insertScriptStatement.bind()
                 .setString(USER_NAME, user.asString())
                 .setString(SCRIPT_NAME, script.getName().getValue())
@@ -108,16 +105,14 @@ public class CassandraSieveDAO {
                 .setLong(SIZE, script.getSize()));
     }
 
-    public CompletableFuture<List<ScriptSummary>> listScripts(User user) {
+    public Flux<ScriptSummary> listScripts(User user) {
         return cassandraAsyncExecutor.execute(
-            selectScriptsStatement.bind()
-                .setString(USER_NAME, user.asString()))
-            .thenApply(resultSet -> resultSet.all()
-                .stream()
-                .map(row -> new ScriptSummary(
+                selectScriptsStatement.bind()
+                    .setString(USER_NAME, user.asString()))
+            .flatMapMany(Flux::fromIterable)
+            .map(row -> new ScriptSummary(
                     new ScriptName(row.getString(SCRIPT_NAME)),
-                    row.getBool(IS_ACTIVE)))
-                .collect(Guavate.toImmutableList()));
+                    row.getBool(IS_ACTIVE)));
     }
 
     public Mono<Boolean> updateScriptActivation(User user, ScriptName scriptName, boolean active) {
@@ -145,7 +140,7 @@ public class CassandraSieveDAO {
     }
 
     private Mono<Row> getScriptRow(User user, ScriptName name) {
-        return cassandraAsyncExecutor.executeSingleRowReactor(
+        return cassandraAsyncExecutor.executeSingleRow(
             selectScriptStatement.bind()
                 .setString(USER_NAME, user.asString())
                 .setString(SCRIPT_NAME, name.getValue()));
diff --git a/server/data/data-cassandra/src/main/java/org/apache/james/sieve/cassandra/CassandraSieveQuotaDAO.java b/server/data/data-cassandra/src/main/java/org/apache/james/sieve/cassandra/CassandraSieveQuotaDAO.java
index 1e99f1a..c24f032 100644
--- a/server/data/data-cassandra/src/main/java/org/apache/james/sieve/cassandra/CassandraSieveQuotaDAO.java
+++ b/server/data/data-cassandra/src/main/java/org/apache/james/sieve/cassandra/CassandraSieveQuotaDAO.java
@@ -28,7 +28,6 @@ import static com.datastax.driver.core.querybuilder.QueryBuilder.set;
 import static com.datastax.driver.core.querybuilder.QueryBuilder.update;
 
 import java.util.Optional;
-import java.util.concurrent.CompletableFuture;
 
 import javax.inject.Inject;
 
@@ -100,58 +99,58 @@ public class CassandraSieveQuotaDAO {
                 .where(eq(CassandraSieveQuotaTable.USER_NAME, bindMarker(CassandraSieveQuotaTable.USER_NAME))));
     }
 
-    public CompletableFuture<Long> spaceUsedBy(User user) {
-        return cassandraAsyncExecutor.executeSingleRow(
+    public Mono<Long> spaceUsedBy(User user) {
+        return cassandraAsyncExecutor.executeSingleRowOptional(
             selectSpaceUsedByUserStatement.bind()
                 .setString(CassandraSieveSpaceTable.USER_NAME, user.asString()))
-            .thenApply(optional -> optional.map(row -> row.getLong(CassandraSieveSpaceTable.SPACE_USED))
+            .map(optional -> optional.map(row -> row.getLong(CassandraSieveSpaceTable.SPACE_USED))
                 .orElse(0L));
     }
 
     public Mono<Void> updateSpaceUsed(User user, long spaceUsed) {
-        return cassandraAsyncExecutor.executeVoidReactor(
+        return cassandraAsyncExecutor.executeVoid(
             updateSpaceUsedStatement.bind()
                 .setLong(CassandraSieveSpaceTable.SPACE_USED, spaceUsed)
                 .setString(CassandraSieveSpaceTable.USER_NAME, user.asString()));
     }
 
-    public CompletableFuture<Optional<QuotaSize>> getQuota() {
-        return cassandraAsyncExecutor.executeSingleRow(
+    public Mono<Optional<QuotaSize>> getQuota() {
+        return cassandraAsyncExecutor.executeSingleRowOptional(
             selectClusterQuotaStatement.bind()
                 .setString(CassandraSieveClusterQuotaTable.NAME, CassandraSieveClusterQuotaTable.DEFAULT_NAME))
-            .thenApply(optional -> optional.map(row ->
+            .map(optional -> optional.map(row ->
                 QuotaSize.size(row.getLong(CassandraSieveClusterQuotaTable.VALUE))));
     }
 
-    public CompletableFuture<Void> setQuota(QuotaSize quota) {
+    public Mono<Void> setQuota(QuotaSize quota) {
         return cassandraAsyncExecutor.executeVoid(
             updateClusterQuotaStatement.bind()
                 .setLong(CassandraSieveClusterQuotaTable.VALUE, quota.asLong())
                 .setString(CassandraSieveClusterQuotaTable.NAME, CassandraSieveClusterQuotaTable.DEFAULT_NAME));
     }
 
-    public CompletableFuture<Void> removeQuota() {
+    public Mono<Void> removeQuota() {
         return cassandraAsyncExecutor.executeVoid(
             deleteClusterQuotaStatement.bind()
                 .setString(CassandraSieveClusterQuotaTable.NAME, CassandraSieveClusterQuotaTable.DEFAULT_NAME));
     }
 
-    public CompletableFuture<Optional<QuotaSize>> getQuota(User user) {
-        return cassandraAsyncExecutor.executeSingleRow(
+    public Mono<Optional<QuotaSize>> getQuota(User user) {
+        return cassandraAsyncExecutor.executeSingleRowOptional(
             selectUserQuotaStatement.bind()
                 .setString(CassandraSieveQuotaTable.USER_NAME, user.asString()))
-            .thenApply(optional -> optional.map(row ->
+            .map(optional -> optional.map(row ->
                 QuotaSize.size(row.getLong(CassandraSieveQuotaTable.QUOTA))));
     }
 
-    public CompletableFuture<Void> setQuota(User user, QuotaSize quota) {
+    public Mono<Void> setQuota(User user, QuotaSize quota) {
         return cassandraAsyncExecutor.executeVoid(
             updateUserQuotaStatement.bind()
                 .setLong(CassandraSieveQuotaTable.QUOTA, quota.asLong())
                 .setString(CassandraSieveQuotaTable.USER_NAME, user.asString()));
     }
 
-    public CompletableFuture<Void> removeQuota(User user)  {
+    public Mono<Void> removeQuota(User user)  {
         return cassandraAsyncExecutor.executeVoid(
             deleteUserQuotaStatement.bind()
                 .setString(CassandraSieveQuotaTable.USER_NAME, user.asString()));
diff --git a/server/data/data-cassandra/src/main/java/org/apache/james/sieve/cassandra/CassandraSieveRepository.java b/server/data/data-cassandra/src/main/java/org/apache/james/sieve/cassandra/CassandraSieveRepository.java
index 7f4b559..c01f9d3 100644
--- a/server/data/data-cassandra/src/main/java/org/apache/james/sieve/cassandra/CassandraSieveRepository.java
+++ b/server/data/data-cassandra/src/main/java/org/apache/james/sieve/cassandra/CassandraSieveRepository.java
@@ -24,7 +24,6 @@ import java.nio.charset.StandardCharsets;
 import java.time.ZonedDateTime;
 import java.util.List;
 import java.util.Optional;
-import java.util.concurrent.CompletableFuture;
 import java.util.function.Function;
 
 import javax.inject.Inject;
@@ -44,9 +43,9 @@ import org.apache.james.sieverepository.api.exception.IsActiveException;
 import org.apache.james.sieverepository.api.exception.QuotaExceededException;
 import org.apache.james.sieverepository.api.exception.QuotaNotFoundException;
 import org.apache.james.sieverepository.api.exception.ScriptNotFoundException;
-
 import org.apache.james.util.FunctionalUtils;
 
+import com.github.steveash.guavate.Guavate;
 import reactor.core.publisher.Flux;
 import reactor.core.publisher.Mono;
 
@@ -73,16 +72,29 @@ public class CassandraSieveRepository implements SieveRepository {
 
     @Override
     public void haveSpace(User user, ScriptName name, long newSize) throws QuotaExceededException {
-        throwOnOverQuota(user, spaceThatWillBeUsedByNewScript(user, name, newSize));
+        reThrowQuotaExceededException(() ->
+            spaceThatWillBeUsedByNewScript(user, name, newSize)
+                .flatMap(sizeDifference -> throwOnOverQuota(user, sizeDifference))
+                .block());
     }
 
-    private void throwOnOverQuota(User user, Mono<Long> sizeDifference) throws QuotaExceededException {
-        CompletableFuture<Optional<QuotaSize>> userQuotaFuture = cassandraSieveQuotaDAO.getQuota(user);
-        CompletableFuture<Optional<QuotaSize>> globalQuotaFuture = cassandraSieveQuotaDAO.getQuota();
-        CompletableFuture<Long> spaceUsedFuture = cassandraSieveQuotaDAO.spaceUsedBy(user);
+    private Mono<Void> throwOnOverQuota(User user, Long sizeDifference) {
+        Mono<Optional<QuotaSize>> userQuotaMono = cassandraSieveQuotaDAO.getQuota(user);
+        Mono<Optional<QuotaSize>> globalQuotaMono = cassandraSieveQuotaDAO.getQuota();
+        Mono<Long> spaceUsedMono = cassandraSieveQuotaDAO.spaceUsedBy(user);
 
-        new SieveQuota(spaceUsedFuture.join(), limitToUse(userQuotaFuture, globalQuotaFuture))
-            .checkOverQuotaUponModification(sizeDifference.block());
+        return limitToUse(userQuotaMono, globalQuotaMono).zipWith(spaceUsedMono)
+            .flatMap(pair -> checkOverQuotaUponModification(sizeDifference, pair.getT2(), pair.getT1()));
+    }
+
+    private Mono<Void> checkOverQuotaUponModification(Long sizeDifference, Long spaceUsed, Optional<QuotaSize> limit) {
+        try {
+            new SieveQuota(spaceUsed, limit)
+                .checkOverQuotaUponModification(sizeDifference);
+            return Mono.empty();
+        } catch (QuotaExceededException e) {
+            return Mono.error(new RuntimeException(e));
+        }
     }
 
     private Mono<Long> spaceThatWillBeUsedByNewScript(User user, ScriptName name, long scriptSize) {
@@ -92,28 +104,39 @@ public class CassandraSieveRepository implements SieveRepository {
             .map(sizeOfStoredScript -> scriptSize - sizeOfStoredScript);
     }
 
-    private Optional<QuotaSize> limitToUse(CompletableFuture<Optional<QuotaSize>> userQuota, CompletableFuture<Optional<QuotaSize>> globalQuota) {
-        if (userQuota.join().isPresent()) {
-            return userQuota.join();
-        }
-        return globalQuota.join();
+    private Mono<Optional<QuotaSize>> limitToUse(Mono<Optional<QuotaSize>> userQuota, Mono<Optional<QuotaSize>> globalQuota) {
+        return userQuota
+            .filter(Optional::isPresent)
+            .switchIfEmpty(globalQuota);
     }
 
     @Override
     public void putScript(User user, ScriptName name, ScriptContent content) throws QuotaExceededException {
-        Mono<Long> spaceUsed = spaceThatWillBeUsedByNewScript(user, name, content.length());
-        throwOnOverQuota(user, spaceUsed);
+        Function<Long, Mono<Void>> updateAndInsert = spaceUsed -> Flux.merge(
+                updateSpaceUsed(user, spaceUsed),
+                cassandraSieveDAO.insertScript(user,
+                        Script.builder()
+                                .name(name)
+                                .content(content)
+                                .isActive(false)
+                                .build()))
+                .then();
+
+        reThrowQuotaExceededException(() ->
+            spaceThatWillBeUsedByNewScript(user, name, content.length())
+                .flatMap(spaceUsed -> throwOnOverQuota(user, spaceUsed)
+                        .thenEmpty(updateAndInsert.apply(spaceUsed)))
+                .block());
+    }
 
-        Flux.merge(
-            updateSpaceUsed(user, spaceUsed.block()),
-            cassandraSieveDAO.insertScript(user,
-                Script.builder()
-                    .name(name)
-                    .content(content)
-                    .isActive(false)
-                    .build()))
-            .then()
-            .block();
+    private void reThrowQuotaExceededException(Runnable runnable) throws QuotaExceededException {
+       try {
+           runnable.run();
+       } catch (RuntimeException e) {
+           if (e.getCause() instanceof QuotaExceededException) {
+               throw (QuotaExceededException) e.getCause();
+           }
+       }
     }
 
     private Mono<Void> updateSpaceUsed(User user, long spaceUsed) {
@@ -125,7 +148,7 @@ public class CassandraSieveRepository implements SieveRepository {
 
     @Override
     public List<ScriptSummary> listScripts(User user) {
-        return cassandraSieveDAO.listScripts(user).join();
+        return cassandraSieveDAO.listScripts(user).collect(Guavate.toImmutableList()).block();
     }
 
     @Override
@@ -224,51 +247,51 @@ public class CassandraSieveRepository implements SieveRepository {
     @Override
     public boolean hasDefaultQuota() {
         return cassandraSieveQuotaDAO.getQuota()
-            .join()
+            .block()
             .isPresent();
     }
 
     @Override
     public QuotaSize getDefaultQuota() throws QuotaNotFoundException {
         return cassandraSieveQuotaDAO.getQuota()
-            .join()
+            .block()
             .orElseThrow(QuotaNotFoundException::new);
     }
 
     @Override
     public void setDefaultQuota(QuotaSize quota) {
-        cassandraSieveQuotaDAO.setQuota(quota).join();
+        cassandraSieveQuotaDAO.setQuota(quota).block();
     }
 
     @Override
     public void removeQuota() {
-        cassandraSieveQuotaDAO.removeQuota().join();
+        cassandraSieveQuotaDAO.removeQuota().block();
     }
 
     @Override
     public boolean hasQuota(User user) {
-        CompletableFuture<Boolean> hasUserQuota = cassandraSieveQuotaDAO.getQuota(user).thenApply(Optional::isPresent);
-        CompletableFuture<Boolean> hasGlobalQuota = cassandraSieveQuotaDAO.getQuota().thenApply(Optional::isPresent);
+        Mono<Boolean> hasUserQuota = cassandraSieveQuotaDAO.getQuota(user).map(Optional::isPresent);
+        Mono<Boolean> hasGlobalQuota = cassandraSieveQuotaDAO.getQuota().map(Optional::isPresent);
 
-        return hasUserQuota.thenCombine(hasGlobalQuota, (a, b) -> a || b)
-            .join();
+        return hasUserQuota.zipWith(hasGlobalQuota, (a, b) -> a || b)
+            .block();
     }
 
     @Override
     public QuotaSize getQuota(User user) throws QuotaNotFoundException {
         return cassandraSieveQuotaDAO.getQuota(user)
-            .join()
+            .block()
             .orElseThrow(QuotaNotFoundException::new);
     }
 
     @Override
     public void setQuota(User user, QuotaSize quota) {
-        cassandraSieveQuotaDAO.setQuota(user, quota).join();
+        cassandraSieveQuotaDAO.setQuota(user, quota).block();
     }
 
     @Override
     public void removeQuota(User user) {
-        cassandraSieveQuotaDAO.removeQuota(user).join();
+        cassandraSieveQuotaDAO.removeQuota(user).block();
     }
 
 }
diff --git a/server/data/data-cassandra/src/main/java/org/apache/james/user/cassandra/CassandraUsersRepository.java b/server/data/data-cassandra/src/main/java/org/apache/james/user/cassandra/CassandraUsersRepository.java
index 0d6eee8..1fc36ff 100644
--- a/server/data/data-cassandra/src/main/java/org/apache/james/user/cassandra/CassandraUsersRepository.java
+++ b/server/data/data-cassandra/src/main/java/org/apache/james/user/cassandra/CassandraUsersRepository.java
@@ -49,10 +49,10 @@ import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
 
 import com.datastax.driver.core.PreparedStatement;
-import com.datastax.driver.core.ResultSet;
 import com.datastax.driver.core.Session;
 import com.google.common.base.Preconditions;
 import com.google.common.primitives.Ints;
+import reactor.core.publisher.Flux;
 
 public class CassandraUsersRepository extends AbstractUsersRepository {
 
@@ -118,12 +118,12 @@ public class CassandraUsersRepository extends AbstractUsersRepository {
 
     @Override
     public User getUserByName(String name) {
-        ResultSet result = executor.execute(getUserStatement.bind()
-            .setString(NAME, name.toLowerCase(Locale.US)))
-            .join();
-        return Optional.ofNullable(result.one())
+        return executor.executeSingleRow(
+                getUserStatement.bind()
+                    .setString(NAME, name.toLowerCase(Locale.US)))
             .map(row -> new DefaultUser(row.getString(REALNAME), row.getString(PASSWORD), row.getString(ALGORITHM)))
             .filter(user -> user.hasUsername(name))
+            .blockOptional()
             .orElse(null);
     }
 
@@ -172,17 +172,18 @@ public class CassandraUsersRepository extends AbstractUsersRepository {
     }
 
     @Override
-    public int countUsers() throws UsersRepositoryException {
-        ResultSet result = executor.execute(countUserStatement.bind()).join();
-        return Ints.checkedCast(result.one().getLong(0));
+    public int countUsers() {
+        return executor.executeSingleRow(countUserStatement.bind())
+            .map(row -> Ints.checkedCast(row.getLong(0)))
+            .block();
     }
 
     @Override
     public Iterator<String> list() throws UsersRepositoryException {
-        ResultSet result = executor.execute(listStatement.bind())
-            .join();
-        return cassandraUtils.convertToStream(result)
+        return executor.execute(listStatement.bind())
+            .flatMapMany(Flux::fromIterable)
             .map(row -> row.getString(REALNAME))
+            .toIterable()
             .iterator();
     }
 
diff --git a/server/data/data-cassandra/src/test/java/org/apache/james/mailrepository/cassandra/CassandraMailRepositoryUrlStoreExtension.java b/server/data/data-cassandra/src/test/java/org/apache/james/mailrepository/cassandra/CassandraMailRepositoryUrlStoreExtension.java
index 30df692..de51737 100644
--- a/server/data/data-cassandra/src/test/java/org/apache/james/mailrepository/cassandra/CassandraMailRepositoryUrlStoreExtension.java
+++ b/server/data/data-cassandra/src/test/java/org/apache/james/mailrepository/cassandra/CassandraMailRepositoryUrlStoreExtension.java
@@ -20,7 +20,6 @@
 package org.apache.james.mailrepository.cassandra;
 
 import org.apache.james.backends.cassandra.CassandraClusterExtension;
-import org.apache.james.backends.cassandra.utils.CassandraUtils;
 import org.apache.james.mailrepository.api.MailRepositoryUrlStore;
 import org.junit.jupiter.api.extension.AfterAllCallback;
 import org.junit.jupiter.api.extension.AfterEachCallback;
@@ -61,7 +60,6 @@ public class CassandraMailRepositoryUrlStoreExtension implements ParameterResolv
     public Object resolveParameter(ParameterContext parameterContext, ExtensionContext extensionContext) throws ParameterResolutionException {
         return new CassandraMailRepositoryUrlStore(
             new UrlsDao(
-                cassandraCluster.getCassandraCluster().getConf(),
-                CassandraUtils.WITH_DEFAULT_CONFIGURATION));
+                cassandraCluster.getCassandraCluster().getConf()));
     }
 }
diff --git a/server/data/data-cassandra/src/test/java/org/apache/james/rrt/cassandra/CassandraRecipientRewriteTableV6Test.java b/server/data/data-cassandra/src/test/java/org/apache/james/rrt/cassandra/CassandraRecipientRewriteTableV6Test.java
index 31a32e8..54a1658 100644
--- a/server/data/data-cassandra/src/test/java/org/apache/james/rrt/cassandra/CassandraRecipientRewriteTableV6Test.java
+++ b/server/data/data-cassandra/src/test/java/org/apache/james/rrt/cassandra/CassandraRecipientRewriteTableV6Test.java
@@ -73,8 +73,8 @@ public class CassandraRecipientRewriteTableV6Test extends AbstractRecipientRewri
     @Override
     protected AbstractRecipientRewriteTable getRecipientRewriteTable() throws Exception {
         CassandraSchemaVersionDAO cassandraSchemaVersionDAO = new CassandraSchemaVersionDAO(
-            cassandra.getConf(),
-            CassandraUtils.WITH_DEFAULT_CONFIGURATION);
+            cassandra.getConf()
+        );
 
         CassandraRecipientRewriteTable rrt = new CassandraRecipientRewriteTable(
             new CassandraRecipientRewriteTableDAO(cassandra.getConf(), CassandraUtils.WITH_DEFAULT_CONFIGURATION),
diff --git a/server/data/data-cassandra/src/test/java/org/apache/james/rrt/cassandra/CassandraRecipientRewriteTableV7Test.java b/server/data/data-cassandra/src/test/java/org/apache/james/rrt/cassandra/CassandraRecipientRewriteTableV7Test.java
index c7711b1..c504f0c 100644
--- a/server/data/data-cassandra/src/test/java/org/apache/james/rrt/cassandra/CassandraRecipientRewriteTableV7Test.java
+++ b/server/data/data-cassandra/src/test/java/org/apache/james/rrt/cassandra/CassandraRecipientRewriteTableV7Test.java
@@ -73,8 +73,8 @@ public class CassandraRecipientRewriteTableV7Test extends AbstractRecipientRewri
     @Override
     protected AbstractRecipientRewriteTable getRecipientRewriteTable() throws Exception {
         CassandraSchemaVersionDAO cassandraSchemaVersionDAO = new CassandraSchemaVersionDAO(
-            cassandra.getConf(),
-            CassandraUtils.WITH_DEFAULT_CONFIGURATION);
+            cassandra.getConf()
+        );
 
         CassandraRecipientRewriteTable rrt = new CassandraRecipientRewriteTable(
             new CassandraRecipientRewriteTableDAO(cassandra.getConf(), CassandraUtils.WITH_DEFAULT_CONFIGURATION),
diff --git a/server/data/data-cassandra/src/test/java/org/apache/james/rrt/cassandra/CassandraStepdefs.java b/server/data/data-cassandra/src/test/java/org/apache/james/rrt/cassandra/CassandraStepdefs.java
index c609267..e6eb0fd 100644
--- a/server/data/data-cassandra/src/test/java/org/apache/james/rrt/cassandra/CassandraStepdefs.java
+++ b/server/data/data-cassandra/src/test/java/org/apache/james/rrt/cassandra/CassandraStepdefs.java
@@ -57,7 +57,7 @@ public class CassandraStepdefs {
         CassandraRecipientRewriteTable rrt = new CassandraRecipientRewriteTable(
             new CassandraRecipientRewriteTableDAO(cassandra.getConf(), CassandraUtils.WITH_DEFAULT_CONFIGURATION),
             new CassandraMappingsSourcesDAO(cassandra.getConf()),
-            new CassandraSchemaVersionDAO(cassandra.getConf(), CassandraUtils.WITH_DEFAULT_CONFIGURATION));
+            new CassandraSchemaVersionDAO(cassandra.getConf()));
         rrt.configure(new DefaultConfigurationBuilder());
         return rrt;
     }
diff --git a/server/data/data-cassandra/src/test/java/org/apache/james/sieve/cassandra/CassandraSieveDAOTest.java b/server/data/data-cassandra/src/test/java/org/apache/james/sieve/cassandra/CassandraSieveDAOTest.java
index 5e3150d..b7c216c 100644
--- a/server/data/data-cassandra/src/test/java/org/apache/james/sieve/cassandra/CassandraSieveDAOTest.java
+++ b/server/data/data-cassandra/src/test/java/org/apache/james/sieve/cassandra/CassandraSieveDAOTest.java
@@ -21,7 +21,6 @@ package org.apache.james.sieve.cassandra;
 
 import static org.assertj.core.api.Assertions.assertThat;
 
-import java.util.List;
 import java.util.Optional;
 
 import org.apache.james.backends.cassandra.CassandraCluster;
@@ -29,7 +28,6 @@ import org.apache.james.backends.cassandra.CassandraClusterExtension;
 import org.apache.james.core.User;
 import org.apache.james.sieve.cassandra.model.Script;
 import org.apache.james.sieverepository.api.ScriptName;
-import org.apache.james.sieverepository.api.ScriptSummary;
 import org.junit.jupiter.api.BeforeEach;
 import org.junit.jupiter.api.Test;
 import org.junit.jupiter.api.extension.RegisterExtension;
@@ -123,9 +121,7 @@ class CassandraSieveDAOTest {
 
     @Test
     void listScriptsShouldReturnEmpty() {
-        List<ScriptSummary> scriptSummaryList = sieveDAO.listScripts(USER).join();
-
-        assertThat(scriptSummaryList).isEmpty();
+        assertThat(sieveDAO.listScripts(USER).toIterable()).isEmpty();
     }
 
     @Test
@@ -133,8 +129,7 @@ class CassandraSieveDAOTest {
         sieveDAO.insertScript(USER, SCRIPT).block();
         sieveDAO.insertScript(USER, SCRIPT2).block();
 
-        List<ScriptSummary> scriptSummaryList = sieveDAO.listScripts(USER).join();
-
-        assertThat(scriptSummaryList).containsOnly(SCRIPT.toSummary(), SCRIPT2.toSummary());
+        assertThat(sieveDAO.listScripts(USER).toIterable())
+            .containsOnly(SCRIPT.toSummary(), SCRIPT2.toSummary());
     }
 }
diff --git a/server/data/data-cassandra/src/test/java/org/apache/james/sieve/cassandra/CassandraSieveQuotaDAOTest.java b/server/data/data-cassandra/src/test/java/org/apache/james/sieve/cassandra/CassandraSieveQuotaDAOTest.java
index 7cacb55..845cc9e 100644
--- a/server/data/data-cassandra/src/test/java/org/apache/james/sieve/cassandra/CassandraSieveQuotaDAOTest.java
+++ b/server/data/data-cassandra/src/test/java/org/apache/james/sieve/cassandra/CassandraSieveQuotaDAOTest.java
@@ -45,71 +45,71 @@ class CassandraSieveQuotaDAOTest {
 
     @Test
     void getQuotaShouldReturnEmptyByDefault() {
-        assertThat(sieveQuotaDAO.getQuota().join())
+        assertThat(sieveQuotaDAO.getQuota().block())
             .isEmpty();
     }
 
     @Test
     void getQuotaUserShouldReturnEmptyByDefault() {
-        assertThat(sieveQuotaDAO.getQuota(USER).join())
+        assertThat(sieveQuotaDAO.getQuota(USER).block())
             .isEmpty();
     }
 
     @Test
     void getQuotaShouldReturnStoredValue() {
-        sieveQuotaDAO.setQuota(QUOTA_SIZE).join();
+        sieveQuotaDAO.setQuota(QUOTA_SIZE).block();
 
-        assertThat(sieveQuotaDAO.getQuota().join())
+        assertThat(sieveQuotaDAO.getQuota().block())
             .contains(QUOTA_SIZE);
     }
 
     @Test
     void getQuotaUserShouldReturnStoredValue() {
-        sieveQuotaDAO.setQuota(USER, QUOTA_SIZE).join();
+        sieveQuotaDAO.setQuota(USER, QUOTA_SIZE).block();
 
-        assertThat(sieveQuotaDAO.getQuota(USER).join())
+        assertThat(sieveQuotaDAO.getQuota(USER).block())
             .contains(QUOTA_SIZE);
     }
 
     @Test
     void removeQuotaShouldDeleteQuota() {
-        sieveQuotaDAO.setQuota(QUOTA_SIZE).join();
+        sieveQuotaDAO.setQuota(QUOTA_SIZE).block();
 
-        sieveQuotaDAO.removeQuota().join();
+        sieveQuotaDAO.removeQuota().block();
 
-        assertThat(sieveQuotaDAO.getQuota().join())
+        assertThat(sieveQuotaDAO.getQuota().block())
             .isEmpty();
     }
 
     @Test
     void removeQuotaUserShouldDeleteQuotaUser() {
-        sieveQuotaDAO.setQuota(USER, QUOTA_SIZE).join();
+        sieveQuotaDAO.setQuota(USER, QUOTA_SIZE).block();
 
-        sieveQuotaDAO.removeQuota(USER).join();
+        sieveQuotaDAO.removeQuota(USER).block();
 
-        assertThat(sieveQuotaDAO.getQuota(USER).join())
+        assertThat(sieveQuotaDAO.getQuota(USER).block())
             .isEmpty();
     }
 
     @Test
     void removeQuotaShouldWorkWhenNoneStore() {
-        sieveQuotaDAO.removeQuota().join();
+        sieveQuotaDAO.removeQuota().block();
 
-        assertThat(sieveQuotaDAO.getQuota().join())
+        assertThat(sieveQuotaDAO.getQuota().block())
             .isEmpty();
     }
 
     @Test
     void removeQuotaUserShouldWorkWhenNoneStore() {
-        sieveQuotaDAO.removeQuota(USER).join();
+        sieveQuotaDAO.removeQuota(USER).block();
 
-        assertThat(sieveQuotaDAO.getQuota(USER).join())
+        assertThat(sieveQuotaDAO.getQuota(USER).block())
             .isEmpty();
     }
 
     @Test
     void spaceUsedByShouldReturnZeroByDefault() {
-        assertThat(sieveQuotaDAO.spaceUsedBy(USER).join()).isEqualTo(0);
+        assertThat(sieveQuotaDAO.spaceUsedBy(USER).block()).isEqualTo(0);
     }
 
     @Test
@@ -118,7 +118,7 @@ class CassandraSieveQuotaDAOTest {
 
         sieveQuotaDAO.updateSpaceUsed(USER, spaceUsed).block();
 
-        assertThat(sieveQuotaDAO.spaceUsedBy(USER).join()).isEqualTo(spaceUsed);
+        assertThat(sieveQuotaDAO.spaceUsedBy(USER).block()).isEqualTo(spaceUsed);
     }
 
     @Test
@@ -128,7 +128,7 @@ class CassandraSieveQuotaDAOTest {
         sieveQuotaDAO.updateSpaceUsed(USER, spaceUsed).block();
         sieveQuotaDAO.updateSpaceUsed(USER, spaceUsed).block();
 
-        assertThat(sieveQuotaDAO.spaceUsedBy(USER).join()).isEqualTo(2 * spaceUsed);
+        assertThat(sieveQuotaDAO.spaceUsedBy(USER).block()).isEqualTo(2 * spaceUsed);
     }
 
     @Test
@@ -138,6 +138,6 @@ class CassandraSieveQuotaDAOTest {
         sieveQuotaDAO.updateSpaceUsed(USER, spaceUsed).block();
         sieveQuotaDAO.updateSpaceUsed(USER, -1 * spaceUsed).block();
 
-        assertThat(sieveQuotaDAO.spaceUsedBy(USER).join()).isEqualTo(0L);
+        assertThat(sieveQuotaDAO.spaceUsedBy(USER).block()).isEqualTo(0L);
     }
 }
diff --git a/server/data/data-jmap-cassandra/src/main/java/org/apache/james/jmap/cassandra/access/CassandraAccessTokenDAO.java b/server/data/data-jmap-cassandra/src/main/java/org/apache/james/jmap/cassandra/access/CassandraAccessTokenDAO.java
index 5bdd9be..23e761a 100644
--- a/server/data/data-jmap-cassandra/src/main/java/org/apache/james/jmap/cassandra/access/CassandraAccessTokenDAO.java
+++ b/server/data/data-jmap-cassandra/src/main/java/org/apache/james/jmap/cassandra/access/CassandraAccessTokenDAO.java
@@ -27,8 +27,6 @@ import static com.datastax.driver.core.querybuilder.QueryBuilder.select;
 import static com.datastax.driver.core.querybuilder.QueryBuilder.ttl;
 import static org.apache.james.jmap.api.access.AccessTokenRepository.TOKEN_EXPIRATION_IN_MS;
 
-import java.util.Optional;
-import java.util.concurrent.CompletableFuture;
 import java.util.concurrent.TimeUnit;
 
 import javax.inject.Inject;
@@ -41,6 +39,7 @@ import org.apache.james.jmap.cassandra.access.table.CassandraAccessTokenTable;
 import com.datastax.driver.core.PreparedStatement;
 import com.datastax.driver.core.Session;
 import com.google.common.primitives.Ints;
+import reactor.core.publisher.Mono;
 
 public class CassandraAccessTokenDAO {
 
@@ -71,21 +70,21 @@ public class CassandraAccessTokenDAO {
             .where(eq(CassandraAccessTokenTable.TOKEN, bindMarker(CassandraAccessTokenTable.TOKEN))));
     }
 
-    public CompletableFuture<Void> addToken(String username, AccessToken accessToken) {
+    public Mono<Void> addToken(String username, AccessToken accessToken) {
         return cassandraAsyncExecutor.executeVoid(insertStatement.bind()
             .setUUID(CassandraAccessTokenTable.TOKEN, accessToken.asUUID())
             .setString(CassandraAccessTokenTable.USERNAME, username)
             .setInt(TTL, durationInSeconds));
     }
 
-    public CompletableFuture<Void> removeToken(AccessToken accessToken) {
+    public Mono<Void> removeToken(AccessToken accessToken) {
         return cassandraAsyncExecutor.executeVoid(removeStatement.bind()
             .setUUID(CassandraAccessTokenTable.TOKEN, accessToken.asUUID()));
     }
 
-    public CompletableFuture<Optional<String>> getUsernameFromToken(AccessToken accessToken) {
+    public Mono<String> getUsernameFromToken(AccessToken accessToken) {
         return cassandraAsyncExecutor.executeSingleRow(selectStatement.bind()
-            .setUUID(CassandraAccessTokenTable.TOKEN, accessToken.asUUID()))
-            .thenApply(optional -> optional.map(row -> row.getString(CassandraAccessTokenTable.USERNAME)));
+                .setUUID(CassandraAccessTokenTable.TOKEN, accessToken.asUUID()))
+            .map(row -> row.getString(CassandraAccessTokenTable.USERNAME));
     }
 }
diff --git a/server/data/data-jmap-cassandra/src/main/java/org/apache/james/jmap/cassandra/access/CassandraAccessTokenRepository.java b/server/data/data-jmap-cassandra/src/main/java/org/apache/james/jmap/cassandra/access/CassandraAccessTokenRepository.java
index 1dac5e7..9b0a928 100644
--- a/server/data/data-jmap-cassandra/src/main/java/org/apache/james/jmap/cassandra/access/CassandraAccessTokenRepository.java
+++ b/server/data/data-jmap-cassandra/src/main/java/org/apache/james/jmap/cassandra/access/CassandraAccessTokenRepository.java
@@ -19,8 +19,6 @@
 
 package org.apache.james.jmap.cassandra.access;
 
-import java.util.concurrent.CompletableFuture;
-
 import javax.inject.Inject;
 
 import org.apache.james.jmap.api.access.AccessToken;
@@ -28,6 +26,7 @@ import org.apache.james.jmap.api.access.AccessTokenRepository;
 import org.apache.james.jmap.api.access.exceptions.InvalidAccessToken;
 
 import com.google.common.base.Preconditions;
+import reactor.core.publisher.Mono;
 
 public class CassandraAccessTokenRepository implements AccessTokenRepository {
 
@@ -39,7 +38,7 @@ public class CassandraAccessTokenRepository implements AccessTokenRepository {
     }
 
     @Override
-    public CompletableFuture<Void> addToken(String username, AccessToken accessToken) {
+    public Mono<Void> addToken(String username, AccessToken accessToken) {
         Preconditions.checkNotNull(username);
         Preconditions.checkArgument(! username.isEmpty(), "Username should not be empty");
         Preconditions.checkNotNull(accessToken);
@@ -48,18 +47,17 @@ public class CassandraAccessTokenRepository implements AccessTokenRepository {
     }
 
     @Override
-    public CompletableFuture<Void> removeToken(AccessToken accessToken) {
+    public Mono<Void> removeToken(AccessToken accessToken) {
         Preconditions.checkNotNull(accessToken);
 
         return cassandraAccessTokenDAO.removeToken(accessToken);
     }
 
     @Override
-    public CompletableFuture<String> getUsernameFromToken(AccessToken accessToken) throws InvalidAccessToken {
+    public Mono<String> getUsernameFromToken(AccessToken accessToken) throws InvalidAccessToken {
         Preconditions.checkNotNull(accessToken);
 
         return cassandraAccessTokenDAO.getUsernameFromToken(accessToken)
-            .thenApply(
-                optional -> optional.<InvalidAccessToken>orElseThrow(() -> new InvalidAccessToken(accessToken)));
+            .switchIfEmpty(Mono.error(new InvalidAccessToken(accessToken)));
     }
 }
diff --git a/server/data/data-jmap-cassandra/src/main/java/org/apache/james/jmap/cassandra/vacation/CassandraNotificationRegistry.java b/server/data/data-jmap-cassandra/src/main/java/org/apache/james/jmap/cassandra/vacation/CassandraNotificationRegistry.java
index e253e33..218f0ad 100644
--- a/server/data/data-jmap-cassandra/src/main/java/org/apache/james/jmap/cassandra/vacation/CassandraNotificationRegistry.java
+++ b/server/data/data-jmap-cassandra/src/main/java/org/apache/james/jmap/cassandra/vacation/CassandraNotificationRegistry.java
@@ -22,7 +22,6 @@ package org.apache.james.jmap.cassandra.vacation;
 import java.time.ZonedDateTime;
 import java.time.temporal.ChronoUnit;
 import java.util.Optional;
-import java.util.concurrent.CompletableFuture;
 
 import javax.inject.Inject;
 
@@ -34,6 +33,7 @@ import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
 
 import com.google.common.primitives.Ints;
+import reactor.core.publisher.Mono;
 
 public class CassandraNotificationRegistry implements NotificationRegistry {
 
@@ -49,23 +49,23 @@ public class CassandraNotificationRegistry implements NotificationRegistry {
     }
 
     @Override
-    public CompletableFuture<Void> register(AccountId accountId, RecipientId recipientId, Optional<ZonedDateTime> expiryDate) {
+    public Mono<Void> register(AccountId accountId, RecipientId recipientId, Optional<ZonedDateTime> expiryDate) {
         Optional<Integer> waitDelay = expiryDate.map(expiry -> Ints.checkedCast(zonedDateTimeProvider.get().until(expiry, ChronoUnit.SECONDS)));
         if (isValid(waitDelay)) {
             return cassandraNotificationRegistryDAO.register(accountId, recipientId, waitDelay);
         } else {
             LOGGER.warn("Invalid wait delay for {} {} : {}", accountId, recipientId, waitDelay);
-            return CompletableFuture.completedFuture(null);
+            return Mono.empty();
         }
     }
 
     @Override
-    public CompletableFuture<Boolean> isRegistered(AccountId accountId, RecipientId recipientId) {
+    public Mono<Boolean> isRegistered(AccountId accountId, RecipientId recipientId) {
         return cassandraNotificationRegistryDAO.isRegistered(accountId, recipientId);
     }
 
     @Override
-    public CompletableFuture<Void> flush(AccountId accountId) {
+    public Mono<Void> flush(AccountId accountId) {
         return cassandraNotificationRegistryDAO.flush(accountId);
     }
 
diff --git a/server/data/data-jmap-cassandra/src/main/java/org/apache/james/jmap/cassandra/vacation/CassandraNotificationRegistryDAO.java b/server/data/data-jmap-cassandra/src/main/java/org/apache/james/jmap/cassandra/vacation/CassandraNotificationRegistryDAO.java
index 555713e..ea31e35 100644
--- a/server/data/data-jmap-cassandra/src/main/java/org/apache/james/jmap/cassandra/vacation/CassandraNotificationRegistryDAO.java
+++ b/server/data/data-jmap-cassandra/src/main/java/org/apache/james/jmap/cassandra/vacation/CassandraNotificationRegistryDAO.java
@@ -27,7 +27,6 @@ import static com.datastax.driver.core.querybuilder.QueryBuilder.select;
 import static com.datastax.driver.core.querybuilder.QueryBuilder.ttl;
 
 import java.util.Optional;
-import java.util.concurrent.CompletableFuture;
 
 import javax.inject.Inject;
 
@@ -39,6 +38,7 @@ import org.apache.james.jmap.cassandra.vacation.tables.CassandraNotificationTabl
 import com.datastax.driver.core.PreparedStatement;
 import com.datastax.driver.core.Session;
 import com.datastax.driver.core.querybuilder.Insert;
+import reactor.core.publisher.Mono;
 
 public class CassandraNotificationRegistryDAO {
 
@@ -73,7 +73,7 @@ public class CassandraNotificationRegistryDAO {
             .value(CassandraNotificationTable.RECIPIENT_ID, bindMarker(CassandraNotificationTable.RECIPIENT_ID));
     }
 
-    public CompletableFuture<Void> register(AccountId accountId, RecipientId recipientId, Optional<Integer> ttl) {
+    public Mono<Void> register(AccountId accountId, RecipientId recipientId, Optional<Integer> ttl) {
         return cassandraAsyncExecutor.executeVoid(
             ttl.map(value -> registerWithTTLStatement.bind().setInt(TTL, value))
                 .orElse(registerStatement.bind())
@@ -81,15 +81,15 @@ public class CassandraNotificationRegistryDAO {
                 .setString(CassandraNotificationTable.RECIPIENT_ID, recipientId.getAsString()));
     }
 
-    public CompletableFuture<Boolean> isRegistered(AccountId accountId, RecipientId recipientId) {
-        return cassandraAsyncExecutor.executeSingleRow(
+    public Mono<Boolean> isRegistered(AccountId accountId, RecipientId recipientId) {
+        return cassandraAsyncExecutor.executeSingleRowOptional(
             isRegisteredStatement.bind()
                 .setString(CassandraNotificationTable.ACCOUNT_ID, accountId.getIdentifier())
                 .setString(CassandraNotificationTable.RECIPIENT_ID, recipientId.getAsString()))
-            .thenApply(Optional::isPresent);
+            .map(Optional::isPresent);
     }
 
-    public CompletableFuture<Void> flush(AccountId accountId) {
+    public Mono<Void> flush(AccountId accountId) {
         return cassandraAsyncExecutor.executeVoid(
             flushStatement.bind()
                 .setString(CassandraNotificationTable.ACCOUNT_ID, accountId.getIdentifier()));
diff --git a/server/data/data-jmap-cassandra/src/main/java/org/apache/james/jmap/cassandra/vacation/CassandraVacationDAO.java b/server/data/data-jmap-cassandra/src/main/java/org/apache/james/jmap/cassandra/vacation/CassandraVacationDAO.java
index d2ac082..aacdf8e 100644
--- a/server/data/data-jmap-cassandra/src/main/java/org/apache/james/jmap/cassandra/vacation/CassandraVacationDAO.java
+++ b/server/data/data-jmap-cassandra/src/main/java/org/apache/james/jmap/cassandra/vacation/CassandraVacationDAO.java
@@ -26,7 +26,6 @@ import static com.datastax.driver.core.querybuilder.QueryBuilder.select;
 
 import java.time.ZonedDateTime;
 import java.util.Optional;
-import java.util.concurrent.CompletableFuture;
 import java.util.function.BiFunction;
 import java.util.function.Function;
 
@@ -49,6 +48,7 @@ import com.datastax.driver.core.UDTValue;
 import com.datastax.driver.core.UserType;
 import com.datastax.driver.core.querybuilder.Insert;
 import com.google.common.collect.ImmutableList;
+import reactor.core.publisher.Mono;
 
 public class CassandraVacationDAO {
 
@@ -79,17 +79,17 @@ public class CassandraVacationDAO {
                     (a, b) -> (vacation, insert) -> b.apply(vacation, a.apply(vacation, insert)));
     }
 
-    public CompletableFuture<Void> modifyVacation(AccountId accountId, VacationPatch vacationPatch) {
+    public Mono<Void> modifyVacation(AccountId accountId, VacationPatch vacationPatch) {
         return cassandraAsyncExecutor.executeVoid(
             createSpecificUpdate(vacationPatch,
                 insertInto(CassandraVacationTable.TABLE_NAME)
                     .value(CassandraVacationTable.ACCOUNT_ID, accountId.getIdentifier())));
     }
 
-    public CompletableFuture<Optional<Vacation>> retrieveVacation(AccountId accountId) {
-        return cassandraAsyncExecutor.executeSingleRow(readStatement.bind()
-            .setString(CassandraVacationTable.ACCOUNT_ID, accountId.getIdentifier()))
-            .thenApply(optional -> optional.map(row -> Vacation.builder()
+    public Mono<Optional<Vacation>> retrieveVacation(AccountId accountId) {
+        return cassandraAsyncExecutor.executeSingleRowOptional(readStatement.bind()
+                .setString(CassandraVacationTable.ACCOUNT_ID, accountId.getIdentifier()))
+            .map(optional -> optional.map(row -> Vacation.builder()
                 .enabled(row.getBool(CassandraVacationTable.IS_ENABLED))
                 .fromDate(retrieveDate(row, CassandraVacationTable.FROM_DATE))
                 .toDate(retrieveDate(row, CassandraVacationTable.TO_DATE))
diff --git a/server/data/data-jmap-cassandra/src/main/java/org/apache/james/jmap/cassandra/vacation/CassandraVacationRepository.java b/server/data/data-jmap-cassandra/src/main/java/org/apache/james/jmap/cassandra/vacation/CassandraVacationRepository.java
index aa2a1f4..b0448b3 100644
--- a/server/data/data-jmap-cassandra/src/main/java/org/apache/james/jmap/cassandra/vacation/CassandraVacationRepository.java
+++ b/server/data/data-jmap-cassandra/src/main/java/org/apache/james/jmap/cassandra/vacation/CassandraVacationRepository.java
@@ -19,8 +19,6 @@
 
 package org.apache.james.jmap.cassandra.vacation;
 
-import java.util.concurrent.CompletableFuture;
-
 import javax.inject.Inject;
 
 import org.apache.james.jmap.api.vacation.AccountId;
@@ -29,6 +27,7 @@ import org.apache.james.jmap.api.vacation.VacationPatch;
 import org.apache.james.jmap.api.vacation.VacationRepository;
 
 import com.google.common.base.Preconditions;
+import reactor.core.publisher.Mono;
 
 public class CassandraVacationRepository implements VacationRepository {
 
@@ -40,18 +39,18 @@ public class CassandraVacationRepository implements VacationRepository {
     }
 
     @Override
-    public CompletableFuture<Void> modifyVacation(AccountId accountId, VacationPatch vacationPatch) {
+    public Mono<Void> modifyVacation(AccountId accountId, VacationPatch vacationPatch) {
         Preconditions.checkNotNull(accountId);
         Preconditions.checkNotNull(vacationPatch);
         if (vacationPatch.isIdentity()) {
-            return CompletableFuture.completedFuture(null);
+            return Mono.empty();
         } else {
             return cassandraVacationDAO.modifyVacation(accountId, vacationPatch);
         }
     }
 
     @Override
-    public CompletableFuture<Vacation> retrieveVacation(AccountId accountId) {
-        return cassandraVacationDAO.retrieveVacation(accountId).thenApply(optional -> optional.orElse(DEFAULT_VACATION));
+    public Mono<Vacation> retrieveVacation(AccountId accountId) {
+        return cassandraVacationDAO.retrieveVacation(accountId).map(optional -> optional.orElse(DEFAULT_VACATION));
     }
 }
diff --git a/server/data/data-jmap/src/main/java/org/apache/james/jmap/api/access/AccessTokenRepository.java b/server/data/data-jmap/src/main/java/org/apache/james/jmap/api/access/AccessTokenRepository.java
index 525fea9..06e97dc 100644
--- a/server/data/data-jmap/src/main/java/org/apache/james/jmap/api/access/AccessTokenRepository.java
+++ b/server/data/data-jmap/src/main/java/org/apache/james/jmap/api/access/AccessTokenRepository.java
@@ -19,18 +19,18 @@
 
 package org.apache.james.jmap.api.access;
 
-import java.util.concurrent.CompletableFuture;
-
 import org.apache.james.jmap.api.access.exceptions.InvalidAccessToken;
 
+import reactor.core.publisher.Mono;
+
 public interface AccessTokenRepository {
 
     String TOKEN_EXPIRATION_IN_MS = "tokenExpirationInMs";
     
-    CompletableFuture<Void> addToken(String username, AccessToken accessToken);
+    Mono<Void> addToken(String username, AccessToken accessToken);
 
-    CompletableFuture<Void> removeToken(AccessToken accessToken);
+    Mono<Void> removeToken(AccessToken accessToken);
 
-    CompletableFuture<String> getUsernameFromToken(AccessToken accessToken) throws InvalidAccessToken;
+    Mono<String> getUsernameFromToken(AccessToken accessToken) throws InvalidAccessToken;
 
 }
diff --git a/server/data/data-jmap/src/main/java/org/apache/james/jmap/api/vacation/NotificationRegistry.java b/server/data/data-jmap/src/main/java/org/apache/james/jmap/api/vacation/NotificationRegistry.java
index 6d4889e..1526ca4 100644
--- a/server/data/data-jmap/src/main/java/org/apache/james/jmap/api/vacation/NotificationRegistry.java
+++ b/server/data/data-jmap/src/main/java/org/apache/james/jmap/api/vacation/NotificationRegistry.java
@@ -21,14 +21,15 @@ package org.apache.james.jmap.api.vacation;
 
 import java.time.ZonedDateTime;
 import java.util.Optional;
-import java.util.concurrent.CompletableFuture;
+
+import reactor.core.publisher.Mono;
 
 public interface NotificationRegistry {
 
-    CompletableFuture<Void> register(AccountId accountId, RecipientId recipientId, Optional<ZonedDateTime> expiryDate);
+    Mono<Void> register(AccountId accountId, RecipientId recipientId, Optional<ZonedDateTime> expiryDate);
 
-    CompletableFuture<Boolean> isRegistered(AccountId accountId, RecipientId recipientId);
+    Mono<Boolean> isRegistered(AccountId accountId, RecipientId recipientId);
 
-    CompletableFuture<Void> flush(AccountId accountId);
+    Mono<Void> flush(AccountId accountId);
 
 }
diff --git a/server/data/data-jmap/src/main/java/org/apache/james/jmap/api/vacation/VacationRepository.java b/server/data/data-jmap/src/main/java/org/apache/james/jmap/api/vacation/VacationRepository.java
index 8267249..fe58e49 100644
--- a/server/data/data-jmap/src/main/java/org/apache/james/jmap/api/vacation/VacationRepository.java
+++ b/server/data/data-jmap/src/main/java/org/apache/james/jmap/api/vacation/VacationRepository.java
@@ -19,14 +19,14 @@
 
 package org.apache.james.jmap.api.vacation;
 
-import java.util.concurrent.CompletableFuture;
+import reactor.core.publisher.Mono;
 
 public interface VacationRepository {
 
     Vacation DEFAULT_VACATION = Vacation.builder().enabled(false).build();
 
-    CompletableFuture<Void> modifyVacation(AccountId accountId, VacationPatch vacationPatch);
+    Mono<Void> modifyVacation(AccountId accountId, VacationPatch vacationPatch);
 
-    CompletableFuture<Vacation> retrieveVacation(AccountId accountId);
+    Mono<Vacation> retrieveVacation(AccountId accountId);
 
 }
diff --git a/server/data/data-jmap/src/main/java/org/apache/james/jmap/memory/access/MemoryAccessTokenRepository.java b/server/data/data-jmap/src/main/java/org/apache/james/jmap/memory/access/MemoryAccessTokenRepository.java
index 18f3645..6c33983 100644
--- a/server/data/data-jmap/src/main/java/org/apache/james/jmap/memory/access/MemoryAccessTokenRepository.java
+++ b/server/data/data-jmap/src/main/java/org/apache/james/jmap/memory/access/MemoryAccessTokenRepository.java
@@ -20,8 +20,6 @@
 package org.apache.james.jmap.memory.access;
 
 import java.util.Optional;
-import java.util.concurrent.CompletableFuture;
-import java.util.concurrent.CompletionException;
 
 import javax.inject.Inject;
 import javax.inject.Named;
@@ -32,6 +30,7 @@ import org.apache.james.jmap.api.access.AccessTokenRepository;
 import org.apache.james.jmap.api.access.exceptions.InvalidAccessToken;
 
 import com.google.common.base.Preconditions;
+import reactor.core.publisher.Mono;
 
 public class MemoryAccessTokenRepository implements AccessTokenRepository {
 
@@ -43,32 +42,32 @@ public class MemoryAccessTokenRepository implements AccessTokenRepository {
     }
 
     @Override
-    public CompletableFuture<Void> addToken(String username, AccessToken accessToken) {
+    public Mono<Void> addToken(String username, AccessToken accessToken) {
         Preconditions.checkNotNull(username);
         Preconditions.checkArgument(! username.isEmpty(), "Username should not be empty");
         Preconditions.checkNotNull(accessToken);
         synchronized (tokensExpirationDates) {
             tokensExpirationDates.put(accessToken, username);
         }
-        return CompletableFuture.completedFuture(null);
+        return Mono.empty();
     }
 
     @Override
-    public CompletableFuture<Void> removeToken(AccessToken accessToken) {
+    public Mono<Void> removeToken(AccessToken accessToken) {
         Preconditions.checkNotNull(accessToken);
         synchronized (tokensExpirationDates) {
             tokensExpirationDates.remove(accessToken);
         }
-        return CompletableFuture.completedFuture(null);
+        return Mono.empty();
     }
 
     @Override
-    public CompletableFuture<String> getUsernameFromToken(AccessToken accessToken) throws InvalidAccessToken {
+    public Mono<String> getUsernameFromToken(AccessToken accessToken) throws InvalidAccessToken {
         Preconditions.checkNotNull(accessToken);
         synchronized (tokensExpirationDates) {
-            return CompletableFuture.completedFuture(
+            return Mono.just(
                 Optional.ofNullable(tokensExpirationDates.get(accessToken))
-                    .<CompletionException>orElseThrow(() -> new CompletionException(new InvalidAccessToken(accessToken))));
+                    .orElseThrow(() -> new InvalidAccessToken(accessToken)));
         }
     }
 
diff --git a/server/data/data-jmap/src/main/java/org/apache/james/jmap/memory/vacation/MemoryNotificationRegistry.java b/server/data/data-jmap/src/main/java/org/apache/james/jmap/memory/vacation/MemoryNotificationRegistry.java
index f9e6733..33e8c0d 100644
--- a/server/data/data-jmap/src/main/java/org/apache/james/jmap/memory/vacation/MemoryNotificationRegistry.java
+++ b/server/data/data-jmap/src/main/java/org/apache/james/jmap/memory/vacation/MemoryNotificationRegistry.java
@@ -21,7 +21,6 @@ package org.apache.james.jmap.memory.vacation;
 
 import java.time.ZonedDateTime;
 import java.util.Optional;
-import java.util.concurrent.CompletableFuture;
 
 import javax.inject.Inject;
 
@@ -33,6 +32,7 @@ import org.apache.james.util.date.ZonedDateTimeProvider;
 import com.google.common.collect.HashMultimap;
 import com.google.common.collect.Multimap;
 import com.google.common.collect.Multimaps;
+import reactor.core.publisher.Mono;
 
 public class MemoryNotificationRegistry implements NotificationRegistry {
 
@@ -64,15 +64,15 @@ public class MemoryNotificationRegistry implements NotificationRegistry {
 }
 
     @Override
-    public CompletableFuture<Void> register(AccountId accountId, RecipientId recipientId, Optional<ZonedDateTime> expiryDate) {
+    public Mono<Void> register(AccountId accountId, RecipientId recipientId, Optional<ZonedDateTime> expiryDate) {
         registrations.put(accountId, new Entry(recipientId, expiryDate));
-        return CompletableFuture.completedFuture(null);
+        return Mono.empty();
     }
 
     @Override
-    public CompletableFuture<Boolean> isRegistered(AccountId accountId, RecipientId recipientId) {
+    public Mono<Boolean> isRegistered(AccountId accountId, RecipientId recipientId) {
         ZonedDateTime currentTime = zonedDateTimeProvider.get();
-        return CompletableFuture.completedFuture(
+        return Mono.just(
             registrations.get(accountId)
                 .stream()
                 .filter(entry -> entry.getRecipientId().equals(recipientId))
@@ -87,8 +87,8 @@ public class MemoryNotificationRegistry implements NotificationRegistry {
     }
 
     @Override
-    public CompletableFuture<Void> flush(AccountId accountId) {
+    public Mono<Void> flush(AccountId accountId) {
         registrations.removeAll(accountId);
-        return CompletableFuture.completedFuture(null);
+        return Mono.empty();
     }
 }
diff --git a/server/data/data-jmap/src/main/java/org/apache/james/jmap/memory/vacation/MemoryVacationRepository.java b/server/data/data-jmap/src/main/java/org/apache/james/jmap/memory/vacation/MemoryVacationRepository.java
index 44cc538..5e3b085 100644
--- a/server/data/data-jmap/src/main/java/org/apache/james/jmap/memory/vacation/MemoryVacationRepository.java
+++ b/server/data/data-jmap/src/main/java/org/apache/james/jmap/memory/vacation/MemoryVacationRepository.java
@@ -21,7 +21,6 @@ package org.apache.james.jmap.memory.vacation;
 
 import java.util.HashMap;
 import java.util.Map;
-import java.util.concurrent.CompletableFuture;
 
 import org.apache.james.jmap.api.vacation.AccountId;
 import org.apache.james.jmap.api.vacation.Vacation;
@@ -29,6 +28,7 @@ import org.apache.james.jmap.api.vacation.VacationPatch;
 import org.apache.james.jmap.api.vacation.VacationRepository;
 
 import com.google.common.base.Preconditions;
+import reactor.core.publisher.Mono;
 
 public class MemoryVacationRepository implements VacationRepository {
 
@@ -39,18 +39,18 @@ public class MemoryVacationRepository implements VacationRepository {
     }
 
     @Override
-    public CompletableFuture<Vacation> retrieveVacation(AccountId accountId) {
+    public Mono<Vacation> retrieveVacation(AccountId accountId) {
         Preconditions.checkNotNull(accountId);
-        return CompletableFuture.completedFuture(vacationMap.getOrDefault(accountId, DEFAULT_VACATION));
+        return Mono.just(vacationMap.getOrDefault(accountId, DEFAULT_VACATION));
     }
 
     @Override
-    public CompletableFuture<Void> modifyVacation(AccountId accountId, VacationPatch vacationPatch) {
+    public Mono<Void> modifyVacation(AccountId accountId, VacationPatch vacationPatch) {
         Preconditions.checkNotNull(accountId);
         Preconditions.checkNotNull(vacationPatch);
-        Vacation oldVacation = retrieveVacation(accountId).join();
+        Vacation oldVacation = retrieveVacation(accountId).block();
         vacationMap.put(accountId, vacationPatch.patch(oldVacation));
-        return CompletableFuture.completedFuture(null);
+        return Mono.empty();
     }
 
 
diff --git a/server/data/data-jmap/src/test/java/org/apache/james/jmap/api/access/AccessTokenRepositoryTest.java b/server/data/data-jmap/src/test/java/org/apache/james/jmap/api/access/AccessTokenRepositoryTest.java
index d8fa18d..d5c49e5 100644
--- a/server/data/data-jmap/src/test/java/org/apache/james/jmap/api/access/AccessTokenRepositoryTest.java
+++ b/server/data/data-jmap/src/test/java/org/apache/james/jmap/api/access/AccessTokenRepositoryTest.java
@@ -22,8 +22,6 @@ package org.apache.james.jmap.api.access;
 import static org.assertj.core.api.Assertions.assertThat;
 import static org.assertj.core.api.Assertions.assertThatThrownBy;
 
-import java.util.concurrent.CompletionException;
-
 import org.apache.james.jmap.api.access.exceptions.InvalidAccessToken;
 import org.junit.Test;
 
@@ -43,30 +41,27 @@ public abstract class AccessTokenRepositoryTest {
 
     @Test
     public void validTokenMustBeRetrieved() throws Throwable {
-        accessTokenRepository.addToken(USERNAME, TOKEN).join();
-        assertThat(accessTokenRepository.getUsernameFromToken(TOKEN).join()).isEqualTo(USERNAME);
+        accessTokenRepository.addToken(USERNAME, TOKEN).block();
+        assertThat(accessTokenRepository.getUsernameFromToken(TOKEN).block()).isEqualTo(USERNAME);
     }
 
     @Test
     public void absentTokensMustBeInvalid() throws Exception {
-        assertThatThrownBy(() -> accessTokenRepository.getUsernameFromToken(TOKEN).join()).isInstanceOf(CompletionException.class);
-        assertThatThrownBy(() -> accessTokenRepository.getUsernameFromToken(TOKEN).join()).hasCauseInstanceOf(InvalidAccessToken.class);
+        assertThatThrownBy(() -> accessTokenRepository.getUsernameFromToken(TOKEN).block()).isExactlyInstanceOf(InvalidAccessToken.class);
     }
 
     @Test
     public void removedTokensMustBeInvalid() throws Exception {
-        accessTokenRepository.addToken(USERNAME, TOKEN).join();
-        accessTokenRepository.removeToken(TOKEN).join();
-        assertThatThrownBy(() -> accessTokenRepository.getUsernameFromToken(TOKEN).join()).isInstanceOf(CompletionException.class);
-        assertThatThrownBy(() -> accessTokenRepository.getUsernameFromToken(TOKEN).join()).hasCauseInstanceOf(InvalidAccessToken.class);
+        accessTokenRepository.addToken(USERNAME, TOKEN).block();
+        accessTokenRepository.removeToken(TOKEN).block();
+        assertThatThrownBy(() -> accessTokenRepository.getUsernameFromToken(TOKEN).block()).isExactlyInstanceOf(InvalidAccessToken.class);
     }
 
     @Test
     public void outDatedTokenMustBeInvalid() throws Exception {
-        accessTokenRepository.addToken(USERNAME, TOKEN).join();
+        accessTokenRepository.addToken(USERNAME, TOKEN).block();
         Thread.sleep(2 * TTL_IN_MS);
-        assertThatThrownBy(() -> accessTokenRepository.getUsernameFromToken(TOKEN).join()).isInstanceOf(CompletionException.class);
-        assertThatThrownBy(() -> accessTokenRepository.getUsernameFromToken(TOKEN).join()).hasCauseInstanceOf(InvalidAccessToken.class);
+        assertThatThrownBy(() -> accessTokenRepository.getUsernameFromToken(TOKEN).block()).isExactlyInstanceOf(InvalidAccessToken.class);
     }
 
     @Test
diff --git a/server/data/data-jmap/src/test/java/org/apache/james/jmap/api/vacation/AbstractNotificationRegistryTest.java b/server/data/data-jmap/src/test/java/org/apache/james/jmap/api/vacation/AbstractNotificationRegistryTest.java
index 029405e..c1c27bb 100644
--- a/server/data/data-jmap/src/test/java/org/apache/james/jmap/api/vacation/AbstractNotificationRegistryTest.java
+++ b/server/data/data-jmap/src/test/java/org/apache/james/jmap/api/vacation/AbstractNotificationRegistryTest.java
@@ -55,60 +55,60 @@ public abstract class AbstractNotificationRegistryTest {
 
     @Test
     public void isRegisterShouldReturnFalseByDefault() {
-        assertThat(notificationRegistry.isRegistered(ACCOUNT_ID, recipientId).join()).isFalse();
+        assertThat(notificationRegistry.isRegistered(ACCOUNT_ID, recipientId).block()).isFalse();
     }
 
     @Test
     public void registerShouldWork() {
-        notificationRegistry.register(ACCOUNT_ID, recipientId, Optional.empty()).join();
+        notificationRegistry.register(ACCOUNT_ID, recipientId, Optional.empty()).block();
 
-        assertThat(notificationRegistry.isRegistered(ACCOUNT_ID, recipientId).join()).isTrue();
+        assertThat(notificationRegistry.isRegistered(ACCOUNT_ID, recipientId).block()).isTrue();
     }
 
     @Test
     public void registerShouldWorkWithExpiracyDate() {
         when(zonedDateTimeProvider.get()).thenReturn(ZONED_DATE_TIME);
-        notificationRegistry.register(ACCOUNT_ID, recipientId, Optional.of(ZONED_DATE_TIME_PLUS_4_SECONDS)).join();
+        notificationRegistry.register(ACCOUNT_ID, recipientId, Optional.of(ZONED_DATE_TIME_PLUS_4_SECONDS)).block();
 
-        assertThat(notificationRegistry.isRegistered(ACCOUNT_ID, recipientId).join()).isTrue();
+        assertThat(notificationRegistry.isRegistered(ACCOUNT_ID, recipientId).block()).isTrue();
     }
 
     @Test
     public void registerShouldExpireAfterExpiracyDate() {
         when(zonedDateTimeProvider.get()).thenReturn(ZONED_DATE_TIME);
 
-        notificationRegistry.register(ACCOUNT_ID, recipientId, Optional.of(ZONED_DATE_TIME_PLUS_4_SECONDS)).join();
+        notificationRegistry.register(ACCOUNT_ID, recipientId, Optional.of(ZONED_DATE_TIME_PLUS_4_SECONDS)).block();
 
         when(zonedDateTimeProvider.get()).thenReturn(ZONED_DATE_TIME_PLUS_8_SECONDS);
 
-        await().atMost(20, TimeUnit.SECONDS).until(() -> !notificationRegistry.isRegistered(ACCOUNT_ID, recipientId).join());
+        await().atMost(20, TimeUnit.SECONDS).until(() -> !notificationRegistry.isRegistered(ACCOUNT_ID, recipientId).block());
     }
 
     @Test
     public void flushShouldWork() {
         when(zonedDateTimeProvider.get()).thenReturn(ZONED_DATE_TIME);
-        notificationRegistry.register(ACCOUNT_ID, recipientId, Optional.empty()).join();
+        notificationRegistry.register(ACCOUNT_ID, recipientId, Optional.empty()).block();
 
-        notificationRegistry.flush(ACCOUNT_ID).join();
+        notificationRegistry.flush(ACCOUNT_ID).block();
 
-        assertThat(notificationRegistry.isRegistered(ACCOUNT_ID, recipientId).join()).isFalse();
+        assertThat(notificationRegistry.isRegistered(ACCOUNT_ID, recipientId).block()).isFalse();
     }
 
     @Test
     public void registerShouldNotPersistWhenExpiryDateIsPast() {
         when(zonedDateTimeProvider.get()).thenReturn(ZONED_DATE_TIME_PLUS_4_SECONDS);
 
-        notificationRegistry.register(ACCOUNT_ID, recipientId, Optional.of(ZONED_DATE_TIME)).join();
+        notificationRegistry.register(ACCOUNT_ID, recipientId, Optional.of(ZONED_DATE_TIME)).block();
 
-        assertThat(notificationRegistry.isRegistered(ACCOUNT_ID, recipientId).join()).isFalse();
+        assertThat(notificationRegistry.isRegistered(ACCOUNT_ID, recipientId).block()).isFalse();
     }
 
     @Test
     public void registerShouldNotPersistWhenExpiryDateIsPresent() {
         when(zonedDateTimeProvider.get()).thenReturn(ZONED_DATE_TIME);
 
-        notificationRegistry.register(ACCOUNT_ID, recipientId, Optional.of(ZONED_DATE_TIME)).join();
+        notificationRegistry.register(ACCOUNT_ID, recipientId, Optional.of(ZONED_DATE_TIME)).block();
 
-        assertThat(notificationRegistry.isRegistered(ACCOUNT_ID, recipientId).join()).isTrue();
+        assertThat(notificationRegistry.isRegistered(ACCOUNT_ID, recipientId).block()).isTrue();
     }
 }
diff --git a/server/data/data-jmap/src/test/java/org/apache/james/jmap/api/vacation/AbstractVacationRepositoryTest.java b/server/data/data-jmap/src/test/java/org/apache/james/jmap/api/vacation/AbstractVacationRepositoryTest.java
index 71340ff..133143e 100644
--- a/server/data/data-jmap/src/test/java/org/apache/james/jmap/api/vacation/AbstractVacationRepositoryTest.java
+++ b/server/data/data-jmap/src/test/java/org/apache/james/jmap/api/vacation/AbstractVacationRepositoryTest.java
@@ -56,7 +56,7 @@ public abstract class AbstractVacationRepositoryTest {
 
     @Test
     public void retrieveVacationShouldReturnDefaultValueByDefault() {
-        assertThat(vacationRepository.retrieveVacation(ACCOUNT_ID).join()).isEqualTo(VacationRepository.DEFAULT_VACATION);
+        assertThat(vacationRepository.retrieveVacation(ACCOUNT_ID).block()).isEqualTo(VacationRepository.DEFAULT_VACATION);
     }
 
     @Test
@@ -65,9 +65,9 @@ public abstract class AbstractVacationRepositoryTest {
             .isEnabled(true)
             .build();
 
-        vacationRepository.modifyVacation(ACCOUNT_ID, vacationPatch).join();
+        vacationRepository.modifyVacation(ACCOUNT_ID, vacationPatch).block();
 
-        assertThat(vacationRepository.retrieveVacation(ACCOUNT_ID).join())
+        assertThat(vacationRepository.retrieveVacation(ACCOUNT_ID).block())
             .isEqualTo(Vacation.builder()
                 .enabled(true)
                 .build());
@@ -79,9 +79,9 @@ public abstract class AbstractVacationRepositoryTest {
             .fromDate(DATE_2014)
             .build();
 
-        vacationRepository.modifyVacation(ACCOUNT_ID, vacationPatch).join();
+        vacationRepository.modifyVacation(ACCOUNT_ID, vacationPatch).block();
 
-        assertThat(vacationRepository.retrieveVacation(ACCOUNT_ID).join())
+        assertThat(vacationRepository.retrieveVacation(ACCOUNT_ID).block())
             .isEqualTo(Vacation.builder()
                 .fromDate(Optional.of(DATE_2014))
                 .enabled(false)
@@ -94,9 +94,9 @@ public abstract class AbstractVacationRepositoryTest {
             .toDate(DATE_2017)
             .build();
 
-        vacationRepository.modifyVacation(ACCOUNT_ID, vacationPatch).join();
+        vacationRepository.modifyVacation(ACCOUNT_ID, vacationPatch).block();
 
-        assertThat(vacationRepository.retrieveVacation(ACCOUNT_ID).join())
+        assertThat(vacationRepository.retrieveVacation(ACCOUNT_ID).block())
             .isEqualTo(Vacation.builder()
                 .toDate(Optional.of(DATE_2017))
                 .enabled(false)
@@ -110,9 +110,9 @@ public abstract class AbstractVacationRepositoryTest {
             .subject(newSubject)
             .build();
 
-        vacationRepository.modifyVacation(ACCOUNT_ID, vacationPatch).join();
+        vacationRepository.modifyVacation(ACCOUNT_ID, vacationPatch).block();
 
-        assertThat(vacationRepository.retrieveVacation(ACCOUNT_ID).join())
+        assertThat(vacationRepository.retrieveVacation(ACCOUNT_ID).block())
             .isEqualTo(Vacation.builder()
                 .subject(Optional.of(newSubject))
                 .enabled(false)
@@ -126,9 +126,9 @@ public abstract class AbstractVacationRepositoryTest {
             .textBody(newTextBody)
             .build();
 
-        vacationRepository.modifyVacation(ACCOUNT_ID, vacationPatch).join();
+        vacationRepository.modifyVacation(ACCOUNT_ID, vacationPatch).block();
 
-        assertThat(vacationRepository.retrieveVacation(ACCOUNT_ID).join())
+        assertThat(vacationRepository.retrieveVacation(ACCOUNT_ID).block())
             .isEqualTo(Vacation.builder()
                 .textBody(newTextBody)
                 .enabled(false)
@@ -142,9 +142,9 @@ public abstract class AbstractVacationRepositoryTest {
             .htmlBody(newHtmlBody)
             .build();
 
-        vacationRepository.modifyVacation(ACCOUNT_ID, vacationPatch).join();
+        vacationRepository.modifyVacation(ACCOUNT_ID, vacationPatch).block();
 
-        assertThat(vacationRepository.retrieveVacation(ACCOUNT_ID).join())
+        assertThat(vacationRepository.retrieveVacation(ACCOUNT_ID).block())
             .isEqualTo(Vacation.builder()
                 .enabled(false)
                 .htmlBody(newHtmlBody)
@@ -156,9 +156,9 @@ public abstract class AbstractVacationRepositoryTest {
         VacationPatch vacationPatch = VacationPatch.builderFrom(VACATION)
             .build();
 
-        vacationRepository.modifyVacation(ACCOUNT_ID, vacationPatch).join();
+        vacationRepository.modifyVacation(ACCOUNT_ID, vacationPatch).block();
 
-        assertThat(vacationRepository.retrieveVacation(ACCOUNT_ID).join())
+        assertThat(vacationRepository.retrieveVacation(ACCOUNT_ID).block())
             .isEqualTo(VACATION);
     }
 
@@ -167,9 +167,9 @@ public abstract class AbstractVacationRepositoryTest {
         VacationPatch vacationPatch = VacationPatch.builder()
             .build();
 
-        vacationRepository.modifyVacation(ACCOUNT_ID, vacationPatch).join();
+        vacationRepository.modifyVacation(ACCOUNT_ID, vacationPatch).block();
 
-        assertThat(vacationRepository.retrieveVacation(ACCOUNT_ID).join())
+        assertThat(vacationRepository.retrieveVacation(ACCOUNT_ID).block())
             .isEqualTo(VacationRepository.DEFAULT_VACATION);
     }
 
@@ -179,15 +179,15 @@ public abstract class AbstractVacationRepositoryTest {
         vacationRepository.modifyVacation(ACCOUNT_ID,
             VacationPatch.builderFrom(VACATION)
                 .build())
-            .join();
+            .block();
 
         // When
         vacationRepository.modifyVacation(ACCOUNT_ID, VacationPatch.builder()
             .build())
-            .join();
+            .block();
 
         // Then
-        assertThat(vacationRepository.retrieveVacation(ACCOUNT_ID).join())
+        assertThat(vacationRepository.retrieveVacation(ACCOUNT_ID).block())
             .isEqualTo(VACATION);
     }
 
@@ -197,16 +197,16 @@ public abstract class AbstractVacationRepositoryTest {
         vacationRepository.modifyVacation(ACCOUNT_ID,
             VacationPatch.builderFrom(VACATION)
                 .build())
-            .join();
+            .block();
 
         // When
         vacationRepository.modifyVacation(ACCOUNT_ID, VacationPatch.builder()
             .subject(ValuePatch.remove())
             .build())
-            .join();
+            .block();
 
         // Then
-        Vacation vacation = vacationRepository.retrieveVacation(ACCOUNT_ID).join();
+        Vacation vacation = vacationRepository.retrieveVacation(ACCOUNT_ID).block();
         assertThat(vacation.getSubject()).isEmpty();
         assertThat(vacation)
             .isEqualTo(Vacation.builder()
@@ -224,16 +224,16 @@ public abstract class AbstractVacationRepositoryTest {
         vacationRepository.modifyVacation(ACCOUNT_ID,
             VacationPatch.builderFrom(VACATION)
                 .build())
-            .join();
+            .block();
 
         // When
         vacationRepository.modifyVacation(ACCOUNT_ID, VacationPatch.builder()
             .textBody(ValuePatch.remove())
             .build())
-            .join();
+            .block();
 
         // Then
-        Vacation vacation = vacationRepository.retrieveVacation(ACCOUNT_ID).join();
+        Vacation vacation = vacationRepository.retrieveVacation(ACCOUNT_ID).block();
         assertThat(vacation.getTextBody()).isEmpty();
         assertThat(vacation)
             .isEqualTo(Vacation.builder()
@@ -251,16 +251,16 @@ public abstract class AbstractVacationRepositoryTest {
         vacationRepository.modifyVacation(ACCOUNT_ID,
             VacationPatch.builderFrom(VACATION)
                 .build())
-            .join();
+            .block();
 
         // When
         vacationRepository.modifyVacation(ACCOUNT_ID, VacationPatch.builder()
             .htmlBody(ValuePatch.remove())
             .build())
-            .join();
+            .block();
 
         // Then
-        Vacation vacation = vacationRepository.retrieveVacation(ACCOUNT_ID).join();
+        Vacation vacation = vacationRepository.retrieveVacation(ACCOUNT_ID).block();
         assertThat(vacation.getHtmlBody()).isEmpty();
         assertThat(vacation)
             .isEqualTo(Vacation.builder()
@@ -278,16 +278,16 @@ public abstract class AbstractVacationRepositoryTest {
         vacationRepository.modifyVacation(ACCOUNT_ID,
             VacationPatch.builderFrom(VACATION)
                 .build())
-            .join();
+            .block();
 
         // When
         vacationRepository.modifyVacation(ACCOUNT_ID, VacationPatch.builder()
             .toDate(ValuePatch.remove())
             .build())
-            .join();
+            .block();
 
         // Then
-        Vacation vacation = vacationRepository.retrieveVacation(ACCOUNT_ID).join();
+        Vacation vacation = vacationRepository.retrieveVacation(ACCOUNT_ID).block();
         assertThat(vacation.getToDate()).isEmpty();
         assertThat(vacation)
             .isEqualTo(Vacation.builder()
@@ -305,16 +305,16 @@ public abstract class AbstractVacationRepositoryTest {
         vacationRepository.modifyVacation(ACCOUNT_ID,
             VacationPatch.builderFrom(VACATION)
                 .build())
-            .join();
+            .block();
 
         // When
         vacationRepository.modifyVacation(ACCOUNT_ID, VacationPatch.builder()
             .fromDate(ValuePatch.remove())
             .build())
-            .join();
+            .block();
 
         // Then
-        Vacation vacation = vacationRepository.retrieveVacation(ACCOUNT_ID).join();
+        Vacation vacation = vacationRepository.retrieveVacation(ACCOUNT_ID).block();
         assertThat(vacation.getFromDate()).isEmpty();
         assertThat(vacation)
             .isEqualTo(Vacation.builder()
diff --git a/server/mailrepository/mailrepository-cassandra/src/main/java/org/apache/james/mailrepository/cassandra/CassandraMailRepository.java b/server/mailrepository/mailrepository-cassandra/src/main/java/org/apache/james/mailrepository/cassandra/CassandraMailRepository.java
index a433ac6..08f4f99 100644
--- a/server/mailrepository/mailrepository-cassandra/src/main/java/org/apache/james/mailrepository/cassandra/CassandraMailRepository.java
+++ b/server/mailrepository/mailrepository-cassandra/src/main/java/org/apache/james/mailrepository/cassandra/CassandraMailRepository.java
@@ -136,7 +136,7 @@ public class CassandraMailRepository implements MailRepository {
 
     @Override
     public long size() {
-        return countDAO.getCount(url).join();
+        return countDAO.getCount(url).block();
     }
 
     @Override
diff --git a/server/mailrepository/mailrepository-cassandra/src/main/java/org/apache/james/mailrepository/cassandra/CassandraMailRepositoryCountDAO.java b/server/mailrepository/mailrepository-cassandra/src/main/java/org/apache/james/mailrepository/cassandra/CassandraMailRepositoryCountDAO.java
index 540aa1a..444a2cf 100644
--- a/server/mailrepository/mailrepository-cassandra/src/main/java/org/apache/james/mailrepository/cassandra/CassandraMailRepositoryCountDAO.java
+++ b/server/mailrepository/mailrepository-cassandra/src/main/java/org/apache/james/mailrepository/cassandra/CassandraMailRepositoryCountDAO.java
@@ -30,7 +30,6 @@ import static org.apache.james.mailrepository.cassandra.MailRepositoryTable.COUN
 import static org.apache.james.mailrepository.cassandra.MailRepositoryTable.REPOSITORY_NAME;
 
 import java.util.Optional;
-import java.util.concurrent.CompletableFuture;
 
 import javax.inject.Inject;
 
@@ -77,19 +76,19 @@ public class CassandraMailRepositoryCountDAO {
     }
 
     public Mono<Void> increment(MailRepositoryUrl url) {
-        return executor.executeVoidReactor(increment.bind()
+        return executor.executeVoid(increment.bind()
             .setString(REPOSITORY_NAME, url.asString()));
     }
 
     public Mono<Void> decrement(MailRepositoryUrl url) {
-        return executor.executeVoidReactor(decrement.bind()
+        return executor.executeVoid(decrement.bind()
             .setString(REPOSITORY_NAME, url.asString()));
     }
 
-    public CompletableFuture<Long> getCount(MailRepositoryUrl url) {
-        return executor.executeSingleRow(select.bind()
+    public Mono<Long> getCount(MailRepositoryUrl url) {
+        return executor.executeSingleRowOptional(select.bind()
                 .setString(REPOSITORY_NAME, url.asString()))
-            .thenApply(this::toCount);
+            .map(this::toCount);
     }
 
     private Long toCount(Optional<Row> rowOptional) {
diff --git a/server/mailrepository/mailrepository-cassandra/src/main/java/org/apache/james/mailrepository/cassandra/CassandraMailRepositoryKeysDAO.java b/server/mailrepository/mailrepository-cassandra/src/main/java/org/apache/james/mailrepository/cassandra/CassandraMailRepositoryKeysDAO.java
index 8bd5902..503a8ae 100644
--- a/server/mailrepository/mailrepository-cassandra/src/main/java/org/apache/james/mailrepository/cassandra/CassandraMailRepositoryKeysDAO.java
+++ b/server/mailrepository/mailrepository-cassandra/src/main/java/org/apache/james/mailrepository/cassandra/CassandraMailRepositoryKeysDAO.java
@@ -86,7 +86,7 @@ public class CassandraMailRepositoryKeysDAO {
     }
 
     public Flux<MailKey> list(MailRepositoryUrl url) {
-        return executor.executeReactor(listKeys.bind()
+        return executor.execute(listKeys.bind()
             .setString(REPOSITORY_NAME, url.asString()))
             .flatMapMany(cassandraUtils::convertToFlux)
             .map(row -> new MailKey(row.getString(MAIL_KEY)));
diff --git a/server/mailrepository/mailrepository-cassandra/src/main/java/org/apache/james/mailrepository/cassandra/CassandraMailRepositoryMailDAO.java b/server/mailrepository/mailrepository-cassandra/src/main/java/org/apache/james/mailrepository/cassandra/CassandraMailRepositoryMailDAO.java
index 6e83900..f50d567 100644
--- a/server/mailrepository/mailrepository-cassandra/src/main/java/org/apache/james/mailrepository/cassandra/CassandraMailRepositoryMailDAO.java
+++ b/server/mailrepository/mailrepository-cassandra/src/main/java/org/apache/james/mailrepository/cassandra/CassandraMailRepositoryMailDAO.java
@@ -158,19 +158,19 @@ public class CassandraMailRepositoryMailDAO implements CassandraMailRepositoryMa
                 .setTimestamp(LAST_UPDATED, mail.getLastUpdated())
                 .setMap(ATTRIBUTES, toRawAttributeMap(mail))
                 .setMap(PER_RECIPIENT_SPECIFIC_HEADERS, toHeaderMap(mail.getPerRecipientSpecificHeaders())))
-            .flatMap(executor::executeVoidReactor);
+            .flatMap(executor::executeVoid);
     }
 
     @Override
     public Mono<Void> remove(MailRepositoryUrl url, MailKey key) {
-        return executor.executeVoidReactor(deleteMail.bind()
+        return executor.executeVoid(deleteMail.bind()
             .setString(REPOSITORY_NAME, url.asString())
             .setString(MAIL_KEY, key.asString()));
     }
 
     @Override
     public Mono<Optional<MailDTO>> read(MailRepositoryUrl url, MailKey key) {
-        return executor.executeSingleRowOptionalReactor(selectMail.bind()
+        return executor.executeSingleRowOptional(selectMail.bind()
                 .setString(REPOSITORY_NAME, url.asString())
                 .setString(MAIL_KEY, key.asString()))
             .map(rowOptional -> rowOptional.map(this::toMail));
diff --git a/server/mailrepository/mailrepository-cassandra/src/main/java/org/apache/james/mailrepository/cassandra/CassandraMailRepositoryMailDaoV2.java b/server/mailrepository/mailrepository-cassandra/src/main/java/org/apache/james/mailrepository/cassandra/CassandraMailRepositoryMailDaoV2.java
index 70471c8..a5662f1 100644
--- a/server/mailrepository/mailrepository-cassandra/src/main/java/org/apache/james/mailrepository/cassandra/CassandraMailRepositoryMailDaoV2.java
+++ b/server/mailrepository/mailrepository-cassandra/src/main/java/org/apache/james/mailrepository/cassandra/CassandraMailRepositoryMailDaoV2.java
@@ -148,18 +148,18 @@ public class CassandraMailRepositoryMailDaoV2 implements CassandraMailRepository
                 .setTimestamp(LAST_UPDATED, mail.getLastUpdated())
                 .setMap(ATTRIBUTES, toRawAttributeMap(mail))
                 .setList(PER_RECIPIENT_SPECIFIC_HEADERS, toTupleList(mail.getPerRecipientSpecificHeaders())))
-            .flatMap(executor::executeVoidReactor);
+            .flatMap(executor::executeVoid);
     }
 
     @Override
     public Mono<Void> remove(MailRepositoryUrl url, MailKey key) {
-        return executor.executeVoidReactor(deleteMail.bind()
+        return executor.executeVoid(deleteMail.bind()
             .setString(REPOSITORY_NAME, url.asString())
             .setString(MAIL_KEY, key.asString()));
     }
 
     public Mono<Optional<MailDTO>> read(MailRepositoryUrl url, MailKey key) {
-        return executor.executeSingleRowOptionalReactor(selectMail.bind()
+        return executor.executeSingleRowOptional(selectMail.bind()
                 .setString(REPOSITORY_NAME, url.asString())
                 .setString(MAIL_KEY, key.asString()))
             .map(rowOptional -> rowOptional.map(this::toMail));
diff --git a/server/mailrepository/mailrepository-cassandra/src/test/java/org/apache/james/mailrepository/cassandra/CassandraMailRepositoryCountDAOTest.java b/server/mailrepository/mailrepository-cassandra/src/test/java/org/apache/james/mailrepository/cassandra/CassandraMailRepositoryCountDAOTest.java
index 32eb13d..6e651f3 100644
--- a/server/mailrepository/mailrepository-cassandra/src/test/java/org/apache/james/mailrepository/cassandra/CassandraMailRepositoryCountDAOTest.java
+++ b/server/mailrepository/mailrepository-cassandra/src/test/java/org/apache/james/mailrepository/cassandra/CassandraMailRepositoryCountDAOTest.java
@@ -44,7 +44,7 @@ class CassandraMailRepositoryCountDAOTest {
 
     @Test
     void getCountShouldReturnZeroWhenEmpty() {
-        assertThat(testee.getCount(URL).join())
+        assertThat(testee.getCount(URL).block())
             .isEqualTo(0L);
     }
 
@@ -52,7 +52,7 @@ class CassandraMailRepositoryCountDAOTest {
     void getCountShouldReturnOneWhenIncrementedOneTime() {
         testee.increment(URL).block();
 
-        assertThat(testee.getCount(URL).join())
+        assertThat(testee.getCount(URL).block())
             .isEqualTo(1L);
     }
 
@@ -60,7 +60,7 @@ class CassandraMailRepositoryCountDAOTest {
     void incrementShouldNotAffectOtherUrls() {
         testee.increment(URL).block();
 
-        assertThat(testee.getCount(URL2).join())
+        assertThat(testee.getCount(URL2).block())
             .isEqualTo(0L);
     }
 
@@ -69,7 +69,7 @@ class CassandraMailRepositoryCountDAOTest {
         testee.increment(URL).block();
         testee.increment(URL).block();
 
-        assertThat(testee.getCount(URL).join())
+        assertThat(testee.getCount(URL).block())
             .isEqualTo(2L);
     }
 
@@ -81,7 +81,7 @@ class CassandraMailRepositoryCountDAOTest {
 
         testee.decrement(URL).block();
 
-        assertThat(testee.getCount(URL).join())
+        assertThat(testee.getCount(URL).block())
             .isEqualTo(2L);
     }
 
@@ -89,7 +89,7 @@ class CassandraMailRepositoryCountDAOTest {
     void decrementCanLeadToNegativeCount() {
         testee.decrement(URL).block();
 
-        assertThat(testee.getCount(URL).join())
+        assertThat(testee.getCount(URL).block())
             .isEqualTo(-1L);
     }
 }
\ No newline at end of file
diff --git a/server/mailrepository/mailrepository-cassandra/src/test/java/org/apache/james/mailrepository/cassandra/CassandraMailRepositoryWithFakeImplementationsTest.java b/server/mailrepository/mailrepository-cassandra/src/test/java/org/apache/james/mailrepository/cassandra/CassandraMailRepositoryWithFakeImplementationsTest.java
index 4e03ec6..bf74e46 100644
--- a/server/mailrepository/mailrepository-cassandra/src/test/java/org/apache/james/mailrepository/cassandra/CassandraMailRepositoryWithFakeImplementationsTest.java
+++ b/server/mailrepository/mailrepository-cassandra/src/test/java/org/apache/james/mailrepository/cassandra/CassandraMailRepositoryWithFakeImplementationsTest.java
@@ -251,7 +251,7 @@ class CassandraMailRepositoryWithFakeImplementationsTest {
                     .isInstanceOf(RuntimeException.class)
                     .hasMessage("Expected failure while storing keys");
 
-            assertThat(countDAO.getCount(URL).join()).isEqualTo(0);
+            assertThat(countDAO.getCount(URL).block()).isEqualTo(0);
         }
 
         @Test
diff --git a/server/protocols/jmap/src/main/java/org/apache/james/jmap/crypto/AccessTokenManagerImpl.java b/server/protocols/jmap/src/main/java/org/apache/james/jmap/crypto/AccessTokenManagerImpl.java
index e90b912..22b785a 100644
--- a/server/protocols/jmap/src/main/java/org/apache/james/jmap/crypto/AccessTokenManagerImpl.java
+++ b/server/protocols/jmap/src/main/java/org/apache/james/jmap/crypto/AccessTokenManagerImpl.java
@@ -19,8 +19,6 @@
 
 package org.apache.james.jmap.crypto;
 
-import java.util.concurrent.CompletionException;
-
 import javax.inject.Inject;
 
 import org.apache.james.jmap.api.AccessTokenManager;
@@ -43,21 +41,13 @@ public class AccessTokenManagerImpl implements AccessTokenManager {
     public AccessToken grantAccessToken(String username) {
         Preconditions.checkNotNull(username);
         AccessToken accessToken = AccessToken.generate();
-        accessTokenRepository.addToken(username, accessToken).join();
+        accessTokenRepository.addToken(username, accessToken).block();
         return accessToken;
     }
 
     @Override
     public String getUsernameFromToken(AccessToken token) throws InvalidAccessToken {
-        try {
-            return accessTokenRepository.getUsernameFromToken(token).join();
-        } catch (CompletionException completionException) {
-            if (completionException.getCause() instanceof InvalidAccessToken) {
-                throw (InvalidAccessToken) completionException.getCause();
-            } else {
-                throw new RuntimeException(completionException);
-            }
-        }
+        return accessTokenRepository.getUsernameFromToken(token).block();
     }
     
     @Override
@@ -72,7 +62,7 @@ public class AccessTokenManagerImpl implements AccessTokenManager {
 
     @Override
     public void revoke(AccessToken token) {
-        accessTokenRepository.removeToken(token).join();
+        accessTokenRepository.removeToken(token).block();
     }
 
 }
diff --git a/server/protocols/jmap/src/main/java/org/apache/james/jmap/mailet/VacationMailet.java b/server/protocols/jmap/src/main/java/org/apache/james/jmap/mailet/VacationMailet.java
index ac50d14..cbb159e 100644
--- a/server/protocols/jmap/src/main/java/org/apache/james/jmap/mailet/VacationMailet.java
+++ b/server/protocols/jmap/src/main/java/org/apache/james/jmap/mailet/VacationMailet.java
@@ -82,10 +82,10 @@ public class VacationMailet extends GenericMailet {
     private void manageVacation(MailAddress recipient, Mail processedMail, ZonedDateTime processingDate) {
         AccountId accountId = AccountId.fromString(recipient.toString());
 
-        Mono<Vacation> vacation = Mono.fromCompletionStage(vacationRepository.retrieveVacation(accountId));
-        Mono<Boolean> alreadySent = Mono.fromCompletionStage(notificationRegistry.isRegistered(
+        Mono<Vacation> vacation = vacationRepository.retrieveVacation(accountId);
+        Mono<Boolean> alreadySent = notificationRegistry.isRegistered(
                 AccountId.fromString(recipient.toString()),
-                RecipientId.fromMailAddress(processedMail.getMaybeSender().get())));
+                RecipientId.fromMailAddress(processedMail.getMaybeSender().get()));
         Pair<Vacation, Boolean> pair = Flux.combineLatest(vacation, alreadySent, Pair::of)
             .blockFirst();
 
@@ -115,7 +115,7 @@ public class VacationMailet extends GenericMailet {
             notificationRegistry.register(AccountId.fromString(recipient.toString()),
                 RecipientId.fromMailAddress(processedMail.getMaybeSender().get()),
                 vacation.getToDate())
-                .join();
+                .block();
         } catch (MessagingException e) {
             LOGGER.warn("Failed to send JMAP vacation notification from {} to {}", recipient, processedMail.getMaybeSender(), e);
         }
diff --git a/server/protocols/jmap/src/main/java/org/apache/james/jmap/methods/GetVacationResponseMethod.java b/server/protocols/jmap/src/main/java/org/apache/james/jmap/methods/GetVacationResponseMethod.java
index 445c760..6e722b5 100644
--- a/server/protocols/jmap/src/main/java/org/apache/james/jmap/methods/GetVacationResponseMethod.java
+++ b/server/protocols/jmap/src/main/java/org/apache/james/jmap/methods/GetVacationResponseMethod.java
@@ -82,7 +82,7 @@ public class GetVacationResponseMethod implements Method {
     }
 
     private GetVacationResponse process(MailboxSession mailboxSession) {
-        Vacation vacation = vacationRepository.retrieveVacation(AccountId.fromString(mailboxSession.getUser().asString())).join();
+        Vacation vacation = vacationRepository.retrieveVacation(AccountId.fromString(mailboxSession.getUser().asString())).block();
         return GetVacationResponse.builder()
             .accountId(mailboxSession.getUser().asString())
             .vacationResponse(VacationResponse.builder()
diff --git a/server/protocols/jmap/src/main/java/org/apache/james/jmap/methods/SetVacationResponseMethod.java b/server/protocols/jmap/src/main/java/org/apache/james/jmap/methods/SetVacationResponseMethod.java
index 3cc6266..7164db8 100644
--- a/server/protocols/jmap/src/main/java/org/apache/james/jmap/methods/SetVacationResponseMethod.java
+++ b/server/protocols/jmap/src/main/java/org/apache/james/jmap/methods/SetVacationResponseMethod.java
@@ -104,8 +104,8 @@ public class SetVacationResponseMethod implements Method {
 
     private Stream<JmapResponse> process(ClientId clientId, AccountId accountId, VacationResponse vacationResponse) {
         if (vacationResponse.isValid()) {
-            vacationRepository.modifyVacation(accountId, vacationResponse.getPatch()).join();
-            notificationRegistry.flush(accountId).join();
+            vacationRepository.modifyVacation(accountId, vacationResponse.getPatch()).block();
+            notificationRegistry.flush(accountId).block();
             return Stream.of(JmapResponse.builder()
                 .clientId(clientId)
                 .responseName(RESPONSE_NAME)
diff --git a/server/protocols/jmap/src/test/java/org/apache/james/jmap/AuthenticationFilterTest.java b/server/protocols/jmap/src/test/java/org/apache/james/jmap/AuthenticationFilterTest.java
index c090cc7..c6e9250 100644
--- a/server/protocols/jmap/src/test/java/org/apache/james/jmap/AuthenticationFilterTest.java
+++ b/server/protocols/jmap/src/test/java/org/apache/james/jmap/AuthenticationFilterTest.java
@@ -92,7 +92,7 @@ public class AuthenticationFilterTest {
         when(mockedRequest.getHeader("Authorization"))
             .thenReturn(TOKEN);
 
-        accessTokenRepository.addToken("user@domain.tld", token).join();
+        accessTokenRepository.addToken("user@domain.tld", token).block();
 
         AuthenticationFilter sut = new AuthenticationFilter(ImmutableList.of(new FakeAuthenticationStrategy(true)), new NoopMetricFactory());
         sut.doFilter(mockedRequest, mockedResponse, filterChain);
@@ -106,7 +106,7 @@ public class AuthenticationFilterTest {
         when(mockedRequest.getHeader("Authorization"))
             .thenReturn(TOKEN);
 
-        accessTokenRepository.addToken("user@domain.tld", token).join();
+        accessTokenRepository.addToken("user@domain.tld", token).block();
 
         AuthenticationFilter sut = new AuthenticationFilter(ImmutableList.of(new FakeAuthenticationStrategy(false), new FakeAuthenticationStrategy(true)), new NoopMetricFactory());
         sut.doFilter(mockedRequest, mockedResponse, filterChain);
diff --git a/server/protocols/jmap/src/test/java/org/apache/james/jmap/crypto/AccessTokenManagerImplTest.java b/server/protocols/jmap/src/test/java/org/apache/james/jmap/crypto/AccessTokenManagerImplTest.java
index 5b80677..8c1d26d 100644
--- a/server/protocols/jmap/src/test/java/org/apache/james/jmap/crypto/AccessTokenManagerImplTest.java
+++ b/server/protocols/jmap/src/test/java/org/apache/james/jmap/crypto/AccessTokenManagerImplTest.java
@@ -19,107 +19,132 @@
 package org.apache.james.jmap.crypto;
 
 import static org.assertj.core.api.Assertions.assertThat;
+import static org.assertj.core.api.Assertions.assertThatNullPointerException;
+import static org.assertj.core.api.Assertions.assertThatThrownBy;
+import static org.mockito.Mockito.mock;
+import static org.mockito.Mockito.when;
 
 import org.apache.james.jmap.api.AccessTokenManager;
 import org.apache.james.jmap.api.access.AccessToken;
 import org.apache.james.jmap.api.access.AccessTokenRepository;
 import org.apache.james.jmap.api.access.exceptions.InvalidAccessToken;
 import org.apache.james.jmap.memory.access.MemoryAccessTokenRepository;
-import org.junit.Before;
-import org.junit.Test;
+
+import org.junit.jupiter.api.BeforeEach;
+import org.junit.jupiter.api.Test;
+
+import reactor.core.publisher.Mono;
 
 public class AccessTokenManagerImplTest {
     
     private AccessTokenManager accessTokenManager;
     private AccessTokenRepository accessTokenRepository;
     
-    @Before
-    public void setUp() throws Exception {
+    @BeforeEach
+    void setUp() {
         accessTokenRepository = new MemoryAccessTokenRepository(100);
         accessTokenManager = new AccessTokenManagerImpl(accessTokenRepository);
     }
 
-    @Test(expected = NullPointerException.class)
-    public void grantShouldThrowOnNullUsername() throws Exception {
-        accessTokenManager.grantAccessToken(null);
+    @Test
+    void grantShouldThrowOnNullUsername() {
+        assertThatNullPointerException()
+            .isThrownBy(() -> accessTokenManager.grantAccessToken(null));
     }
     
     @Test
-    public void grantShouldGenerateATokenOnUsername() throws Exception {
+    void grantShouldGenerateATokenOnUsername() {
         assertThat(accessTokenManager.grantAccessToken("username")).isNotNull();
     }
 
     @Test
-    public void grantShouldStoreATokenOnUsername() throws Exception {
+    void grantShouldStoreATokenOnUsername() {
         AccessToken token = accessTokenManager.grantAccessToken("username");
-        assertThat(accessTokenRepository.getUsernameFromToken(token).join()).isEqualTo("username");
+        assertThat(accessTokenRepository.getUsernameFromToken(token).block()).isEqualTo("username");
     }
     
-    @Test(expected = NullPointerException.class)
-    public void getUsernameShouldThrowWhenNullToken() throws Exception {
-        accessTokenManager.getUsernameFromToken(null);
+    @Test
+    void getUsernameShouldThrowWhenNullToken() {
+        assertThatNullPointerException()
+            .isThrownBy(() -> accessTokenManager.getUsernameFromToken(null));
     }
 
-    @Test(expected = InvalidAccessToken.class)
-    public void getUsernameShouldThrowWhenUnknownToken() throws Exception {
-        accessTokenManager.getUsernameFromToken(AccessToken.generate());
+    @Test
+    void getUsernameShouldThrowWhenUnknownToken() {
+        assertThatThrownBy(() -> accessTokenManager.getUsernameFromToken(AccessToken.generate()))
+            .isExactlyInstanceOf(InvalidAccessToken.class);
     }
 
-    @Test(expected = InvalidAccessToken.class)
-    public void getUsernameShouldThrowWhenOtherToken() throws Exception {
+    @Test
+    void getUsernameShouldThrowWhenOtherToken() {
         accessTokenManager.grantAccessToken("username");
-        accessTokenManager.getUsernameFromToken(AccessToken.generate());
+        assertThatThrownBy(() -> accessTokenManager.getUsernameFromToken(AccessToken.generate()))
+            .isExactlyInstanceOf(InvalidAccessToken.class);
     }
 
     @Test
-    public void getUsernameShouldReturnUsernameWhenExistingUsername() throws Exception {
+    void getUsernameShouldReturnUsernameWhenExistingUsername() {
         AccessToken token = accessTokenManager.grantAccessToken("username");
         assertThat(accessTokenManager.getUsernameFromToken(token)).isEqualTo("username");
     }
     
-    @Test(expected = NullPointerException.class)
-    public void isValidShouldThrowOnNullToken() throws Exception {
-        accessTokenManager.isValid(null);
+    @Test
+    void isValidShouldThrowOnNullToken() {
+        assertThatNullPointerException()
+            .isThrownBy(() -> accessTokenManager.isValid(null));
     }
     
     @Test
-    public void isValidShouldReturnFalseOnUnknownToken() throws Exception {
+    void isValidShouldReturnFalseOnUnknownToken() {
         assertThat(accessTokenManager.isValid(AccessToken.generate())).isFalse();
     }
     
     @Test
-    public void isValidShouldReturnFalseWhenOtherToken() throws Exception {
+    void isValidShouldReturnFalseWhenOtherToken() {
         accessTokenManager.grantAccessToken("username");
         assertThat(accessTokenManager.isValid(AccessToken.generate())).isFalse();
     }
     
     @Test
-    public void isValidShouldReturnTrueWhenValidToken() throws Exception {
+    void isValidShouldReturnTrueWhenValidToken() {
         AccessToken accessToken = accessTokenManager.grantAccessToken("username");
         assertThat(accessTokenManager.isValid(accessToken)).isTrue();
     }
     
-    @Test(expected = NullPointerException.class)
-    public void revokeShouldThrowWhenNullToken() throws Exception {
-        accessTokenManager.revoke(null);
+    @Test
+    void revokeShouldThrowWhenNullToken() {
+        assertThatNullPointerException()
+            .isThrownBy(() -> accessTokenManager.revoke(null));
     }
     
     @Test
-    public void revokeShouldNoopOnUnknownToken() throws Exception {
+    void revokeShouldNoopOnUnknownToken() {
         accessTokenManager.revoke(AccessToken.generate());
     }
     
     @Test
-    public void revokeShouldNoopOnRevokingTwice() throws Exception {
+    void revokeShouldNoopOnRevokingTwice() {
         AccessToken token = AccessToken.generate();
         accessTokenManager.revoke(token);
         accessTokenManager.revoke(token);
     }
     
     @Test
-    public void revokeShouldInvalidExistingToken() throws Exception {
+    void revokeShouldInvalidExistingToken() {
         AccessToken token = accessTokenManager.grantAccessToken("username");
         accessTokenManager.revoke(token);
         assertThat(accessTokenManager.isValid(token)).isFalse();
     }
+
+    @Test
+    void getUsernameShouldThrowWhenRepositoryThrows() {
+        accessTokenRepository = mock(AccessTokenRepository.class);
+        accessTokenManager = new AccessTokenManagerImpl(accessTokenRepository);
+
+        AccessToken accessToken = AccessToken.generate();
+        when(accessTokenRepository.getUsernameFromToken(accessToken)).thenReturn(Mono.error(new InvalidAccessToken(accessToken)));
+
+        assertThatThrownBy(() -> accessTokenManager.getUsernameFromToken(accessToken))
+            .isExactlyInstanceOf(InvalidAccessToken.class);
+    }
 }
diff --git a/server/protocols/jmap/src/test/java/org/apache/james/jmap/mailet/VacationMailetTest.java b/server/protocols/jmap/src/test/java/org/apache/james/jmap/mailet/VacationMailetTest.java
index 8680ee2..fed071e 100644
--- a/server/protocols/jmap/src/test/java/org/apache/james/jmap/mailet/VacationMailetTest.java
+++ b/server/protocols/jmap/src/test/java/org/apache/james/jmap/mailet/VacationMailetTest.java
@@ -29,7 +29,6 @@ import static org.mockito.Mockito.when;
 
 import java.time.ZonedDateTime;
 import java.util.Optional;
-import java.util.concurrent.CompletableFuture;
 
 import javax.mail.MessagingException;
 
@@ -49,6 +48,7 @@ import org.junit.Before;
 import org.junit.Test;
 
 import com.google.common.collect.ImmutableList;
+import reactor.core.publisher.Mono;
 
 public class VacationMailetTest {
 
@@ -104,7 +104,7 @@ public class VacationMailetTest {
     public void unactivatedVacationShouldNotSendNotification() throws Exception {
         when(zonedDateTimeProvider.get()).thenReturn(DATE_TIME_2017);
         when(vacationRepository.retrieveVacation(AccountId.fromString(USERNAME)))
-            .thenReturn(CompletableFuture.completedFuture(VacationRepository.DEFAULT_VACATION));
+            .thenReturn(Mono.just(VacationRepository.DEFAULT_VACATION));
         when(automaticallySentMailDetector.isAutomaticallySent(mail)).thenReturn(false);
 
         testee.service(mail);
@@ -115,11 +115,11 @@ public class VacationMailetTest {
     @Test
     public void activateVacationShouldSendNotification() throws Exception {
         when(vacationRepository.retrieveVacation(AccountId.fromString(USERNAME)))
-            .thenReturn(CompletableFuture.completedFuture(VACATION));
+            .thenReturn(Mono.just(VACATION));
         when(zonedDateTimeProvider.get()).thenReturn(DATE_TIME_2017);
         when(automaticallySentMailDetector.isAutomaticallySent(mail)).thenReturn(false);
         when(notificationRegistry.isRegistered(ACCOUNT_ID, recipientId))
-            .thenReturn(CompletableFuture.completedFuture(false));
+            .thenReturn(Mono.just(false));
 
         testee.service(mail);
 
@@ -132,10 +132,10 @@ public class VacationMailetTest {
     @Test
     public void activateVacationShouldNotSendNotificationIfAlreadySent() throws Exception {
         when(vacationRepository.retrieveVacation(AccountId.fromString(USERNAME)))
-            .thenReturn(CompletableFuture.completedFuture(VACATION));
+            .thenReturn(Mono.just(VACATION));
         when(zonedDateTimeProvider.get()).thenReturn(DATE_TIME_2017);
         when(notificationRegistry.isRegistered(ACCOUNT_ID, recipientId))
-            .thenReturn(CompletableFuture.completedFuture(true));
+            .thenReturn(Mono.just(true));
 
         testee.service(mail);
 
@@ -145,11 +145,11 @@ public class VacationMailetTest {
     @Test
     public void activateVacationShouldSendNotificationIfErrorUpdatingNotificationRepository() throws Exception {
         when(vacationRepository.retrieveVacation(AccountId.fromString(USERNAME)))
-            .thenReturn(CompletableFuture.completedFuture(VACATION));
+            .thenReturn(Mono.just(VACATION));
         when(zonedDateTimeProvider.get()).thenReturn(DATE_TIME_2017);
         RecipientId recipientId = RecipientId.fromMailAddress(originalSender);
         when(notificationRegistry.isRegistered(ACCOUNT_ID, recipientId))
-            .thenReturn(CompletableFuture.completedFuture(false));
+            .thenReturn(Mono.just(false));
         when(notificationRegistry.register(ACCOUNT_ID, recipientId, Optional.of(DATE_TIME_2018))).thenThrow(new RuntimeException());
 
         testee.service(mail);
@@ -161,7 +161,7 @@ public class VacationMailetTest {
     @Test
     public void activateVacationShouldSendNotificationIfErrorRetrievingNotificationRepository() throws Exception {
         when(vacationRepository.retrieveVacation(AccountId.fromString(USERNAME)))
-            .thenReturn(CompletableFuture.completedFuture(VACATION));
+            .thenReturn(Mono.just(VACATION));
         when(zonedDateTimeProvider.get()).thenReturn(DATE_TIME_2017);
         RecipientId recipientId = RecipientId.fromMailAddress(originalSender);
         when(notificationRegistry.isRegistered(ACCOUNT_ID, recipientId))
@@ -194,17 +194,17 @@ public class VacationMailetTest {
             .sender(originalSender)
             .build();
         when(vacationRepository.retrieveVacation(AccountId.fromString(USERNAME)))
-            .thenReturn(CompletableFuture.completedFuture(VACATION));
+            .thenReturn(Mono.just(VACATION));
         when(vacationRepository.retrieveVacation(secondAccountId))
-            .thenReturn(CompletableFuture.completedFuture(VACATION));
+            .thenReturn(Mono.just(VACATION));
         when(zonedDateTimeProvider.get()).thenReturn(DATE_TIME_2017);
         when(automaticallySentMailDetector.isAutomaticallySent(mail)).thenReturn(false);
         when(notificationRegistry.isRegistered(ACCOUNT_ID, RecipientId.fromMailAddress(originalSender)))
-            .thenReturn(CompletableFuture.completedFuture(false));
+            .thenReturn(Mono.just(false));
         when(notificationRegistry.isRegistered(secondAccountId, RecipientId.fromMailAddress(originalSender)))
-            .thenReturn(CompletableFuture.completedFuture(false));
+            .thenReturn(Mono.just(false));
         when(notificationRegistry.register(any(), any(), any()))
-            .thenReturn(CompletableFuture.completedFuture(null));
+            .thenReturn(Mono.empty());
 
         testee.service(mail);
 
@@ -216,9 +216,7 @@ public class VacationMailetTest {
     @Test
     public void serviceShouldNotSendNotificationUponErrorsRetrievingVacationObject() throws Exception {
         when(vacationRepository.retrieveVacation(AccountId.fromString(USERNAME)))
-            .thenReturn(CompletableFuture.supplyAsync(() -> {
-                throw new RuntimeException();
-            }));
+            .thenReturn(Mono.error(new RuntimeException()));
         when(zonedDateTimeProvider.get()).thenReturn(DATE_TIME_2017);
         when(automaticallySentMailDetector.isAutomaticallySent(mail)).thenReturn(false);
 
@@ -230,7 +228,7 @@ public class VacationMailetTest {
     @Test
     public void serviceShouldNotSendNotificationUponErrorsDetectingAutomaticallySentMails() throws Exception {
         when(vacationRepository.retrieveVacation(AccountId.fromString(USERNAME)))
-            .thenReturn(CompletableFuture.completedFuture(VACATION));
+            .thenReturn(Mono.just(VACATION));
         when(zonedDateTimeProvider.get()).thenReturn(DATE_TIME_2017);
         when(automaticallySentMailDetector.isAutomaticallySent(mail)).thenThrow(new MessagingException());
 
@@ -242,11 +240,11 @@ public class VacationMailetTest {
     @Test
     public void serviceShouldNotPropagateExceptionIfSendFails() throws Exception {
         when(vacationRepository.retrieveVacation(AccountId.fromString(USERNAME)))
-            .thenReturn(CompletableFuture.completedFuture(VACATION));
+            .thenReturn(Mono.just(VACATION));
         when(zonedDateTimeProvider.get()).thenReturn(DATE_TIME_2017);
         when(automaticallySentMailDetector.isAutomaticallySent(mail)).thenReturn(false);
         when(notificationRegistry.isRegistered(ACCOUNT_ID, RecipientId.fromMailAddress(originalSender)))
-            .thenReturn(CompletableFuture.completedFuture(false));
+            .thenReturn(Mono.just(false));
 
         doThrow(new MessagingException()).when(mailetContext).sendMail(eq(originalSender), eq(ImmutableList.of(originalRecipient)), any());
 
diff --git a/server/protocols/jmap/src/test/java/org/apache/james/jmap/methods/GetVacationResponseMethodTest.java b/server/protocols/jmap/src/test/java/org/apache/james/jmap/methods/GetVacationResponseMethodTest.java
index e3b4752..95b9c56 100644
--- a/server/protocols/jmap/src/test/java/org/apache/james/jmap/methods/GetVacationResponseMethodTest.java
+++ b/server/protocols/jmap/src/test/java/org/apache/james/jmap/methods/GetVacationResponseMethodTest.java
@@ -25,7 +25,6 @@ import static org.mockito.Mockito.when;
 
 import java.time.ZonedDateTime;
 import java.util.Optional;
-import java.util.concurrent.CompletableFuture;
 import java.util.stream.Stream;
 
 import org.apache.james.core.User;
@@ -44,6 +43,8 @@ import org.apache.james.util.date.ZonedDateTimeProvider;
 import org.junit.Before;
 import org.junit.Test;
 
+import reactor.core.publisher.Mono;
+
 public class GetVacationResponseMethodTest {
 
     private static final ZonedDateTime DATE_2014 = ZonedDateTime.parse("2014-09-30T14:10:00Z");
@@ -98,7 +99,7 @@ public class GetVacationResponseMethodTest {
             .fromDate(Optional.of(DATE_2014))
             .toDate(Optional.of(DATE_2016))
             .build();
-        when(vacationRepository.retrieveVacation(AccountId.fromString(USERNAME))).thenReturn(CompletableFuture.completedFuture(vacation));
+        when(vacationRepository.retrieveVacation(AccountId.fromString(USERNAME))).thenReturn(Mono.just(vacation));
         when(mailboxSession.getUser()).thenReturn(user);
         when(zonedDateTimeProvider.get()).thenReturn(DATE_2015);
 
@@ -130,7 +131,7 @@ public class GetVacationResponseMethodTest {
             .fromDate(Optional.of(DATE_2015))
             .toDate(Optional.of(DATE_2016))
             .build();
-        when(vacationRepository.retrieveVacation(AccountId.fromString(USERNAME))).thenReturn(CompletableFuture.completedFuture(vacation));
+        when(vacationRepository.retrieveVacation(AccountId.fromString(USERNAME))).thenReturn(Mono.just(vacation));
         when(mailboxSession.getUser()).thenReturn(user);
         when(zonedDateTimeProvider.get()).thenReturn(DATE_2014);
 
@@ -164,7 +165,7 @@ public class GetVacationResponseMethodTest {
             .fromDate(Optional.of(DATE_2014))
             .toDate(Optional.of(DATE_2015))
             .build();
-        when(vacationRepository.retrieveVacation(AccountId.fromString(USERNAME))).thenReturn(CompletableFuture.completedFuture(vacation));
+        when(vacationRepository.retrieveVacation(AccountId.fromString(USERNAME))).thenReturn(Mono.just(vacation));
         when(mailboxSession.getUser()).thenReturn(user);
         when(zonedDateTimeProvider.get()).thenReturn(DATE_2016);
 
diff --git a/server/protocols/jmap/src/test/java/org/apache/james/jmap/methods/SetVacationResponseMethodTest.java b/server/protocols/jmap/src/test/java/org/apache/james/jmap/methods/SetVacationResponseMethodTest.java
index beb249f..712fc80 100644
--- a/server/protocols/jmap/src/test/java/org/apache/james/jmap/methods/SetVacationResponseMethodTest.java
+++ b/server/protocols/jmap/src/test/java/org/apache/james/jmap/methods/SetVacationResponseMethodTest.java
@@ -28,7 +28,6 @@ import static org.mockito.Mockito.verifyNoMoreInteractions;
 import static org.mockito.Mockito.when;
 
 import java.util.Optional;
-import java.util.concurrent.CompletableFuture;
 import java.util.stream.Stream;
 
 import org.apache.james.core.User;
@@ -49,6 +48,7 @@ import org.junit.Before;
 import org.junit.Test;
 
 import com.google.common.collect.ImmutableMap;
+import reactor.core.publisher.Mono;
 
 public class SetVacationResponseMethodTest {
     private static final String WRONG_ID = "WrongId";
@@ -175,9 +175,9 @@ public class SetVacationResponseMethodTest {
         AccountId accountId = AccountId.fromString(USERNAME);
 
         when(mailboxSession.getUser()).thenReturn(USER);
-        when(vacationRepository.modifyVacation(eq(accountId), any())).thenReturn(CompletableFuture.completedFuture(null));
+        when(vacationRepository.modifyVacation(eq(accountId), any())).thenReturn(Mono.empty());
         when(notificationRegistry.flush(any()))
-            .thenReturn(CompletableFuture.completedFuture(null));
+            .thenReturn(Mono.empty());
 
         Stream<JmapResponse> result = testee.process(setVacationRequest, clientId, mailboxSession);
 
diff --git a/server/protocols/webadmin/webadmin-cassandra/src/test/java/org/apache/james/webadmin/routes/CassandraMigrationRoutesTest.java b/server/protocols/webadmin/webadmin-cassandra/src/test/java/org/apache/james/webadmin/routes/CassandraMigrationRoutesTest.java
index 50cc86b..8307081 100644
--- a/server/protocols/webadmin/webadmin-cassandra/src/test/java/org/apache/james/webadmin/routes/CassandraMigrationRoutesTest.java
+++ b/server/protocols/webadmin/webadmin-cassandra/src/test/java/org/apache/james/webadmin/routes/CassandraMigrationRoutesTest.java
@@ -37,7 +37,6 @@ import static org.mockito.Mockito.when;
 
 import java.util.Map;
 import java.util.Optional;
-import java.util.concurrent.CompletableFuture;
 
 import org.apache.james.backends.cassandra.migration.CassandraMigrationService;
 import org.apache.james.backends.cassandra.migration.Migration;
@@ -56,9 +55,9 @@ import org.junit.Ignore;
 import org.junit.Test;
 
 import com.google.common.collect.ImmutableMap;
-
 import io.restassured.RestAssured;
 import io.restassured.http.ContentType;
+import reactor.core.publisher.Mono;
 
 public class CassandraMigrationRoutesTest {
     private static final SchemaVersion LATEST_VERSION = new SchemaVersion(3);
@@ -78,7 +77,7 @@ public class CassandraMigrationRoutesTest {
             .put(LATEST_VERSION, successfulMigration)
             .build();
         schemaVersionDAO = mock(CassandraSchemaVersionDAO.class);
-        when(schemaVersionDAO.updateVersion(any())).thenReturn(CompletableFuture.completedFuture(null));
+        when(schemaVersionDAO.updateVersion(any())).thenReturn(Mono.empty());
 
         taskManager = new MemoryTaskManager();
         JsonTransformer jsonTransformer = new JsonTransformer();
@@ -110,7 +109,7 @@ public class CassandraMigrationRoutesTest {
 
     @Test
     public void getShouldReturnTheCurrentVersion() throws Exception {
-        when(schemaVersionDAO.getCurrentSchemaVersion()).thenReturn(CompletableFuture.completedFuture(Optional.of(CURRENT_VERSION)));
+        when(schemaVersionDAO.getCurrentSchemaVersion()).thenReturn(Mono.just(Optional.of(CURRENT_VERSION)));
 
         Integer version =
             when()
@@ -152,7 +151,7 @@ public class CassandraMigrationRoutesTest {
 
     @Test
     public void postShouldReturnErrorCodeWhenInvalidVersion() throws Exception {
-        when(schemaVersionDAO.getCurrentSchemaVersion()).thenReturn(CompletableFuture.completedFuture(Optional.of(OLDER_VERSION)));
+        when(schemaVersionDAO.getCurrentSchemaVersion()).thenReturn(Mono.just(Optional.of(OLDER_VERSION)));
 
         Map<String, Object> errors = given()
             .body("NonInt")
@@ -177,7 +176,7 @@ public class CassandraMigrationRoutesTest {
 
     @Test
     public void postShouldDoMigrationToNewVersion() throws Exception {
-        when(schemaVersionDAO.getCurrentSchemaVersion()).thenReturn(CompletableFuture.completedFuture(Optional.of(OLDER_VERSION)));
+        when(schemaVersionDAO.getCurrentSchemaVersion()).thenReturn(Mono.just(Optional.of(OLDER_VERSION)));
 
         String taskId = with()
             .body(String.valueOf(CURRENT_VERSION.getValue()))
@@ -199,7 +198,7 @@ public class CassandraMigrationRoutesTest {
 
     @Test
     public void postShouldCreateTaskWhenCurrentVersionIsNewerThan() throws Exception {
-        when(schemaVersionDAO.getCurrentSchemaVersion()).thenReturn(CompletableFuture.completedFuture(Optional.of(CURRENT_VERSION)));
+        when(schemaVersionDAO.getCurrentSchemaVersion()).thenReturn(Mono.just(Optional.of(CURRENT_VERSION)));
 
         String taskId =  given()
             .body(String.valueOf(OLDER_VERSION.getValue()))
@@ -218,7 +217,7 @@ public class CassandraMigrationRoutesTest {
 
     @Test
     public void postShouldNotUpdateVersionWhenCurrentVersionIsNewerThan() throws Exception {
-        when(schemaVersionDAO.getCurrentSchemaVersion()).thenReturn(CompletableFuture.completedFuture(Optional.of(CURRENT_VERSION)));
+        when(schemaVersionDAO.getCurrentSchemaVersion()).thenReturn(Mono.just(Optional.of(CURRENT_VERSION)));
 
         String taskId =  given()
             .body(String.valueOf(OLDER_VERSION.getValue()))
@@ -237,7 +236,7 @@ public class CassandraMigrationRoutesTest {
 
     @Test
     public void postShouldDoMigrationToLatestVersion() throws Exception {
-        when(schemaVersionDAO.getCurrentSchemaVersion()).thenReturn(CompletableFuture.completedFuture(Optional.of(OLDER_VERSION)));
+        when(schemaVersionDAO.getCurrentSchemaVersion()).thenReturn(Mono.just(Optional.of(OLDER_VERSION)));
 
         String taskId = with()
             .post("/upgrade/latest")
@@ -256,7 +255,7 @@ public class CassandraMigrationRoutesTest {
 
     @Test
     public void postShouldReturnTaskIdAndLocation() throws Exception {
-        when(schemaVersionDAO.getCurrentSchemaVersion()).thenReturn(CompletableFuture.completedFuture(Optional.of(OLDER_VERSION)));
+        when(schemaVersionDAO.getCurrentSchemaVersion()).thenReturn(Mono.just(Optional.of(OLDER_VERSION)));
 
         when()
             .post("/upgrade/latest")
@@ -267,7 +266,7 @@ public class CassandraMigrationRoutesTest {
 
     @Test
     public void createdTaskShouldHaveDetails() throws Exception {
-        when(schemaVersionDAO.getCurrentSchemaVersion()).thenReturn(CompletableFuture.completedFuture(Optional.of(OLDER_VERSION)));
+        when(schemaVersionDAO.getCurrentSchemaVersion()).thenReturn(Mono.just(Optional.of(OLDER_VERSION)));
 
         String taskId = with()
             .post("/upgrade/latest")
@@ -290,7 +289,7 @@ public class CassandraMigrationRoutesTest {
 
     @Test
     public void postShouldCreateTaskWhenItIsUpToDate() throws Exception {
-        when(schemaVersionDAO.getCurrentSchemaVersion()).thenReturn(CompletableFuture.completedFuture(Optional.of(LATEST_VERSION)));
+        when(schemaVersionDAO.getCurrentSchemaVersion()).thenReturn(Mono.just(Optional.of(LATEST_VERSION)));
 
         String taskId = with()
             .post("/upgrade/latest")
@@ -307,7 +306,7 @@ public class CassandraMigrationRoutesTest {
 
     @Test
     public void postShouldNotUpdateVersionWhenItIsUpToDate() throws Exception {
-        when(schemaVersionDAO.getCurrentSchemaVersion()).thenReturn(CompletableFuture.completedFuture(Optional.of(LATEST_VERSION)));
+        when(schemaVersionDAO.getCurrentSchemaVersion()).thenReturn(Mono.just(Optional.of(LATEST_VERSION)));
 
         String taskId = with()
             .post("/upgrade/latest")
diff --git a/server/queue/queue-rabbitmq/src/main/java/org/apache/james/queue/rabbitmq/view/cassandra/BrowseStartDAO.java b/server/queue/queue-rabbitmq/src/main/java/org/apache/james/queue/rabbitmq/view/cassandra/BrowseStartDAO.java
index 9552f5c..28b19b8 100644
--- a/server/queue/queue-rabbitmq/src/main/java/org/apache/james/queue/rabbitmq/view/cassandra/BrowseStartDAO.java
+++ b/server/queue/queue-rabbitmq/src/main/java/org/apache/james/queue/rabbitmq/view/cassandra/BrowseStartDAO.java
@@ -84,23 +84,22 @@ public class BrowseStartDAO {
     }
 
     Mono<Void> updateBrowseStart(MailQueueName mailQueueName, Instant sliceStart) {
-        return Mono.fromCompletionStage(executor.executeVoid(updateOne.bind()
+        return executor.executeVoid(updateOne.bind()
             .setTimestamp(BROWSE_START, Date.from(sliceStart))
-            .setString(QUEUE_NAME, mailQueueName.asString())));
+            .setString(QUEUE_NAME, mailQueueName.asString()));
     }
 
     Mono<Void> insertInitialBrowseStart(MailQueueName mailQueueName, Instant sliceStart) {
-        return Mono.fromCompletionStage(executor.executeVoid(insertOne.bind()
+        return executor.executeVoid(insertOne.bind()
             .setTimestamp(BROWSE_START, Date.from(sliceStart))
-            .setString(QUEUE_NAME, mailQueueName.asString())));
+            .setString(QUEUE_NAME, mailQueueName.asString()));
     }
 
     @VisibleForTesting
     Mono<Row> selectOne(MailQueueName queueName) {
-        return Mono.fromCompletionStage(executor.executeSingleRow(
-            selectOne.bind()
-                .setString(QUEUE_NAME, queueName.asString())))
-            .flatMap(Mono::justOrEmpty);
+        return executor.executeSingleRow(
+                selectOne.bind()
+                    .setString(QUEUE_NAME, queueName.asString()));
     }
 
     private Instant getBrowseStart(Row row) {
diff --git a/server/queue/queue-rabbitmq/src/main/java/org/apache/james/queue/rabbitmq/view/cassandra/CassandraMailQueueMailDelete.java b/server/queue/queue-rabbitmq/src/main/java/org/apache/james/queue/rabbitmq/view/cassandra/CassandraMailQueueMailDelete.java
index a97999a..723f702 100644
--- a/server/queue/queue-rabbitmq/src/main/java/org/apache/james/queue/rabbitmq/view/cassandra/CassandraMailQueueMailDelete.java
+++ b/server/queue/queue-rabbitmq/src/main/java/org/apache/james/queue/rabbitmq/view/cassandra/CassandraMailQueueMailDelete.java
@@ -67,8 +67,9 @@ public class CassandraMailQueueMailDelete {
     }
 
     void updateBrowseStart(MailQueueName mailQueueName) {
-        Mono<Instant> newBrowseStart = findNewBrowseStart(mailQueueName);
-        updateNewBrowseStart(mailQueueName, newBrowseStart);
+        findNewBrowseStart(mailQueueName)
+            .flatMap(newBrowseStart -> updateNewBrowseStart(mailQueueName, newBrowseStart))
+            .block();
     }
 
     private void maybeUpdateBrowseStart(MailQueueName mailQueueName) {
@@ -83,9 +84,8 @@ public class CassandraMailQueueMailDelete {
             .next();
     }
 
-    private Mono<Void> updateNewBrowseStart(MailQueueName mailQueueName, Mono<Instant> maybeNewBrowseStart) {
-        return maybeNewBrowseStart
-            .flatMap(newBrowseStartInstant -> browseStartDao.updateBrowseStart(mailQueueName, newBrowseStartInstant));
+    private Mono<Void> updateNewBrowseStart(MailQueueName mailQueueName, Instant newBrowseStartInstant) {
+        return browseStartDao.updateBrowseStart(mailQueueName, newBrowseStartInstant);
     }
 
     private boolean shouldUpdateBrowseStart() {
diff --git a/server/queue/queue-rabbitmq/src/main/java/org/apache/james/queue/rabbitmq/view/cassandra/CassandraMailQueueView.java b/server/queue/queue-rabbitmq/src/main/java/org/apache/james/queue/rabbitmq/view/cassandra/CassandraMailQueueView.java
index fd9d327..85ae197 100644
--- a/server/queue/queue-rabbitmq/src/main/java/org/apache/james/queue/rabbitmq/view/cassandra/CassandraMailQueueView.java
+++ b/server/queue/queue-rabbitmq/src/main/java/org/apache/james/queue/rabbitmq/view/cassandra/CassandraMailQueueView.java
@@ -113,7 +113,7 @@ public class CassandraMailQueueView implements MailQueueView {
         return cassandraMailQueueBrowser.browseReferences(mailQueueName)
             .map(EnqueuedItemWithSlicingContext::getEnqueuedItem)
             .filter(mailReference -> deleteCondition.shouldBeDeleted(mailReference.getMail()))
-            .map(mailReference -> cassandraMailQueueMailDelete.considerDeleted(mailReference.getMail(), mailQueueName))
+            .flatMap(mailReference -> cassandraMailQueueMailDelete.considerDeleted(mailReference.getMail(), mailQueueName))
             .count()
             .doOnNext(ignored -> cassandraMailQueueMailDelete.updateBrowseStart(mailQueueName))
             .block();
diff --git a/server/queue/queue-rabbitmq/src/main/java/org/apache/james/queue/rabbitmq/view/cassandra/DeletedMailsDAO.java b/server/queue/queue-rabbitmq/src/main/java/org/apache/james/queue/rabbitmq/view/cassandra/DeletedMailsDAO.java
index 6d65172..eb64990 100644
--- a/server/queue/queue-rabbitmq/src/main/java/org/apache/james/queue/rabbitmq/view/cassandra/DeletedMailsDAO.java
+++ b/server/queue/queue-rabbitmq/src/main/java/org/apache/james/queue/rabbitmq/view/cassandra/DeletedMailsDAO.java
@@ -64,9 +64,9 @@ public class DeletedMailsDAO {
     }
 
     Mono<Void> markAsDeleted(MailQueueName mailQueueName, MailKey mailKey) {
-        return Mono.fromCompletionStage(executor.executeVoid(insertOne.bind()
+        return executor.executeVoid(insertOne.bind()
             .setString(QUEUE_NAME, mailQueueName.asString())
-            .setString(MAIL_KEY, mailKey.getMailKey())));
+            .setString(MAIL_KEY, mailKey.getMailKey()));
     }
 
     Mono<Boolean> isDeleted(MailQueueName mailQueueName, MailKey mailKey) {
diff --git a/server/queue/queue-rabbitmq/src/main/java/org/apache/james/queue/rabbitmq/view/cassandra/EnqueuedMailsDAO.java b/server/queue/queue-rabbitmq/src/main/java/org/apache/james/queue/rabbitmq/view/cassandra/EnqueuedMailsDAO.java
index 8562310..75101c4 100644
--- a/server/queue/queue-rabbitmq/src/main/java/org/apache/james/queue/rabbitmq/view/cassandra/EnqueuedMailsDAO.java
+++ b/server/queue/queue-rabbitmq/src/main/java/org/apache/james/queue/rabbitmq/view/cassandra/EnqueuedMailsDAO.java
@@ -120,7 +120,7 @@ public class EnqueuedMailsDAO {
         Mail mail = enqueuedItem.getMail();
         MimeMessagePartsId mimeMessagePartsId = enqueuedItem.getPartsId();
 
-        return Mono.fromCompletionStage(executor.executeVoid(insert.bind()
+        return executor.executeVoid(insert.bind()
             .setString(QUEUE_NAME, enqueuedItem.getMailQueueName().asString())
             .setTimestamp(TIME_RANGE_START, Date.from(slicingContext.getTimeRangeStart()))
             .setInt(BUCKET_ID, slicingContext.getBucketId().getValue())
@@ -136,19 +136,18 @@ public class EnqueuedMailsDAO {
             .setString(REMOTE_HOST, mail.getRemoteHost())
             .setTimestamp(LAST_UPDATED, mail.getLastUpdated())
             .setMap(ATTRIBUTES, toRawAttributeMap(mail))
-            .setMap(PER_RECIPIENT_SPECIFIC_HEADERS, toHeaderMap(cassandraTypesProvider, mail.getPerRecipientSpecificHeaders()))));
+            .setMap(PER_RECIPIENT_SPECIFIC_HEADERS, toHeaderMap(cassandraTypesProvider, mail.getPerRecipientSpecificHeaders())));
     }
 
     Flux<EnqueuedItemWithSlicingContext> selectEnqueuedMails(
         MailQueueName queueName, Slice slice, BucketId bucketId) {
 
-        return Mono.fromCompletionStage(executor.execute(
-            selectFrom.bind()
-                .setString(QUEUE_NAME, queueName.asString())
-                .setTimestamp(TIME_RANGE_START, Date.from(slice.getStartSliceInstant()))
-                .setInt(BUCKET_ID, bucketId.getValue())))
-            .map(cassandraUtils::convertToStream)
-            .flatMapMany(Flux::fromStream)
+        return executor.execute(
+                selectFrom.bind()
+                    .setString(QUEUE_NAME, queueName.asString())
+                    .setTimestamp(TIME_RANGE_START, Date.from(slice.getStartSliceInstant()))
+                    .setInt(BUCKET_ID, bucketId.getValue()))
+            .flatMapMany(Flux::fromIterable)
             .map(row -> EnqueuedMailsDaoUtil.toEnqueuedMail(row, blobFactory));
     }
 


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


[james-project] 06/07: JAMES-2651 JPAEntityManagerModule supports username password

Posted by ro...@apache.org.
This is an automated email from the ASF dual-hosted git repository.

rouazana pushed a commit to branch master
in repository https://gitbox.apache.org/repos/asf/james-project.git

commit 3a4fe51d0a716e004974790c8a5ae59de958b49c
Author: tran tien duc <dt...@linagora.com>
AuthorDate: Fri Jan 25 15:32:32 2019 +0700

    JAMES-2651 JPAEntityManagerModule supports username password
---
 server/container/guice/jpa-common-guice/pom.xml    |  10 ++
 .../james/modules/data/JPAConfiguration.java       | 142 ++++++++++++++----
 .../james/modules/data/JPAEntityManagerModule.java |  21 ++-
 ...estJPAConfigurationModuleWithSqlValidation.java |  80 ++++++++--
 .../james/modules/data/JPAConfigurationTest.java   | 163 +++++++++++++++++++++
 ...ithAuthenticatedDatabaseSqlValidationTest.java} |  10 +-
 ...tabaseAuthenticaticationSqlValidationTest.java} |  10 +-
 .../james/JPAJamesServerWithSqlValidationTest.java |  10 +-
 8 files changed, 370 insertions(+), 76 deletions(-)

diff --git a/server/container/guice/jpa-common-guice/pom.xml b/server/container/guice/jpa-common-guice/pom.xml
index ab82416..5372b1e 100644
--- a/server/container/guice/jpa-common-guice/pom.xml
+++ b/server/container/guice/jpa-common-guice/pom.xml
@@ -51,6 +51,16 @@
             <artifactId>derby</artifactId>
             <scope>test</scope>
         </dependency>
+        <dependency>
+            <groupId>org.assertj</groupId>
+            <artifactId>assertj-core</artifactId>
+            <scope>test</scope>
+        </dependency>
+        <dependency>
+            <groupId>org.junit.jupiter</groupId>
+            <artifactId>junit-jupiter-engine</artifactId>
+            <scope>test</scope>
+        </dependency>
     </dependencies>
 
     <build>
diff --git a/server/container/guice/jpa-common-guice/src/main/java/org/apache/james/modules/data/JPAConfiguration.java b/server/container/guice/jpa-common-guice/src/main/java/org/apache/james/modules/data/JPAConfiguration.java
index 89e07fd..46f7309 100644
--- a/server/container/guice/jpa-common-guice/src/main/java/org/apache/james/modules/data/JPAConfiguration.java
+++ b/server/container/guice/jpa-common-guice/src/main/java/org/apache/james/modules/data/JPAConfiguration.java
@@ -18,67 +18,142 @@
  ****************************************************************/
 package org.apache.james.modules.data;
 
-import org.apache.james.backends.jpa.JPAConstants;
+import static org.apache.james.modules.data.JPAConfiguration.Credential.NO_CREDENTIAL;
+import static org.apache.james.modules.data.JPAConfiguration.ReadyToBuild.NO_TEST_ON_BORROW;
+import static org.apache.james.modules.data.JPAConfiguration.ReadyToBuild.NO_VALIDATION_QUERY;
+import static org.apache.james.modules.data.JPAConfiguration.ReadyToBuild.NO_VALIDATION_QUERY_TIMEOUT_SEC;
+
+import java.util.Optional;
+
+import org.apache.commons.lang3.StringUtils;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
 
 import com.google.common.annotations.VisibleForTesting;
 import com.google.common.base.Preconditions;
 
 public class JPAConfiguration {
 
-    public static Builder builder() {
-        return new Builder();
+    public static class Credential {
+        private static final Logger LOGGER = LoggerFactory.getLogger(Credential.class);
+        static final Optional<Credential> NO_CREDENTIAL = Optional.empty();
+
+        public static Optional<Credential> of(String username, String password) {
+            if (StringUtils.isBlank(username) && StringUtils.isBlank(password)) {
+                LOGGER.debug("username and password are blank, returns no credential by default");
+                return NO_CREDENTIAL;
+            }
+
+            return Optional.of(new Credential(username, password));
+        }
+
+        private final String username;
+        private final String password;
+
+        private Credential(String username, String password) {
+            Preconditions.checkArgument(StringUtils.isNotBlank(username) && StringUtils.isNotBlank(password),
+                "username and password for connecting to database can't be blank");
+            this.username = username;
+            this.password = password;
+        }
+
+        public String getUsername() {
+            return username;
+        }
+
+        public String getPassword() {
+            return password;
+        }
     }
 
-    public static class Builder {
-        private String driverName;
-        private String driverURL;
-        private boolean testOnBorrow;
-        private int validationQueryTimeoutSec = JPAConstants.VALIDATION_NO_TIMEOUT;
-        private String validationQuery;
+    @FunctionalInterface
+    public interface RequireDriverName {
+        RequireDriverURL driverName(String driverName);
+    }
+
+    @FunctionalInterface
+    public interface RequireDriverURL {
+        ReadyToBuild driverURL(String driverUrl);
+    }
 
+    public static class ReadyToBuild {
+        static final Optional<Boolean> NO_TEST_ON_BORROW = Optional.empty();
+        static final Optional<Integer> NO_VALIDATION_QUERY_TIMEOUT_SEC = Optional.empty();
+        static final Optional<String> NO_VALIDATION_QUERY = Optional.empty();
 
-        public Builder driverName(String driverName) {
+        private final String driverName;
+        private final String driverURL;
+
+        private Optional<Credential> credential;
+        private Optional<Boolean> testOnBorrow;
+        private Optional<Integer> validationQueryTimeoutSec;
+        private Optional<String> validationQuery;
+
+
+        private ReadyToBuild(String driverName, String driverURL, Optional<Credential> credential,
+                            Optional<Boolean> testOnBorrow, Optional<Integer> validationQueryTimeoutSec,
+                            Optional<String> validationQuery) {
             this.driverName = driverName;
-            return this;
+            this.driverURL = driverURL;
+            this.credential = credential;
+            this.testOnBorrow = testOnBorrow;
+            this.validationQueryTimeoutSec = validationQueryTimeoutSec;
+            this.validationQuery = validationQuery;
         }
 
-        public Builder driverURL(String driverURL) {
-            this.driverURL = driverURL;
-            return this;
+        public JPAConfiguration build() {
+            return new JPAConfiguration(driverName, driverURL, credential, testOnBorrow, validationQueryTimeoutSec, validationQuery);
         }
 
-        public Builder testOnBorrow(boolean testOnBorrow) {
-            this.testOnBorrow = testOnBorrow;
-            return this;
+        public RequirePassword username(String username) {
+            return password -> new ReadyToBuild(driverName, driverURL, Credential.of(username, password),
+                testOnBorrow, validationQueryTimeoutSec, validationQuery);
         }
 
-        public Builder validationQueryTimeoutSec(int validationQueryTimeoutSec) {
-            this.validationQueryTimeoutSec = validationQueryTimeoutSec;
+        public ReadyToBuild testOnBorrow(Boolean testOnBorrow) {
+            this.testOnBorrow = Optional.ofNullable(testOnBorrow);
             return this;
         }
 
-        public Builder validationQuery(String validationQuery) {
-            this.validationQuery = validationQuery;
+        public ReadyToBuild validationQueryTimeoutSec(Integer validationQueryTimeoutSec) {
+            this.validationQueryTimeoutSec = Optional.ofNullable(validationQueryTimeoutSec);
             return this;
         }
 
-        public JPAConfiguration build() {
-            Preconditions.checkNotNull(driverName);
-            Preconditions.checkNotNull(driverURL);
-            return new JPAConfiguration(driverName, driverURL, testOnBorrow, validationQueryTimeoutSec, validationQuery);
+        public ReadyToBuild validationQuery(String validationQuery) {
+            this.validationQuery = Optional.ofNullable(validationQuery);
+            return this;
         }
     }
 
+    @FunctionalInterface
+    public interface RequirePassword {
+        ReadyToBuild password(String password);
+    }
+
+    public static RequireDriverName builder() {
+        return driverName -> driverURL -> new ReadyToBuild(driverName, driverURL, NO_CREDENTIAL, NO_TEST_ON_BORROW,
+            NO_VALIDATION_QUERY_TIMEOUT_SEC, NO_VALIDATION_QUERY);
+    }
+
     private final String driverName;
     private final String driverURL;
-    private final boolean testOnBorrow;
-    private final int validationQueryTimeoutSec;
-    private final String validationQuery;
+    private final Optional<Boolean> testOnBorrow;
+    private final Optional<Integer> validationQueryTimeoutSec;
+    private final Optional<Credential> credential;
+    private final Optional<String> validationQuery;
 
     @VisibleForTesting
-    JPAConfiguration(String driverName, String driverURL, boolean testOnBorrow, int validationQueryTimeoutSec, String validationQuery) {
+    JPAConfiguration(String driverName, String driverURL, Optional<Credential> credential, Optional<Boolean> testOnBorrow,
+                     Optional<Integer> validationQueryTimeoutSec, Optional<String> validationQuery) {
+        Preconditions.checkNotNull(driverName, "driverName cannot be null");
+        Preconditions.checkNotNull(driverURL, "driverURL cannot be null");
+        validationQueryTimeoutSec.ifPresent(timeoutInSec ->
+            Preconditions.checkArgument(timeoutInSec > 0, "validationQueryTimeoutSec is required to be greater than 0"));
+
         this.driverName = driverName;
         this.driverURL = driverURL;
+        this.credential = credential;
         this.testOnBorrow = testOnBorrow;
         this.validationQueryTimeoutSec = validationQueryTimeoutSec;
         this.validationQuery = validationQuery;
@@ -92,16 +167,19 @@ public class JPAConfiguration {
         return driverURL;
     }
 
-    public boolean isTestOnBorrow() {
+    public Optional<Boolean> isTestOnBorrow() {
         return testOnBorrow;
     }
 
-    public int getValidationQueryTimeoutSec() {
+    public Optional<Integer> getValidationQueryTimeoutSec() {
         return validationQueryTimeoutSec;
     }
 
-    public String getValidationQuery() {
+    public Optional<String> getValidationQuery() {
         return validationQuery;
     }
 
+    public Optional<Credential> getCredential() {
+        return credential;
+    }
 }
diff --git a/server/container/guice/jpa-common-guice/src/main/java/org/apache/james/modules/data/JPAEntityManagerModule.java b/server/container/guice/jpa-common-guice/src/main/java/org/apache/james/modules/data/JPAEntityManagerModule.java
index c9fb943..eda24ef 100644
--- a/server/container/guice/jpa-common-guice/src/main/java/org/apache/james/modules/data/JPAEntityManagerModule.java
+++ b/server/container/guice/jpa-common-guice/src/main/java/org/apache/james/modules/data/JPAEntityManagerModule.java
@@ -29,7 +29,6 @@ import javax.persistence.Persistence;
 
 import org.apache.commons.configuration.Configuration;
 import org.apache.commons.configuration.ConfigurationException;
-import org.apache.james.backends.jpa.JPAConstants;
 import org.apache.james.utils.PropertiesProvider;
 
 import com.google.common.base.Joiner;
@@ -49,15 +48,19 @@ public class JPAEntityManagerModule extends AbstractModule {
         
         properties.put("openjpa.ConnectionDriverName", jpaConfiguration.getDriverName());
         properties.put("openjpa.ConnectionURL", jpaConfiguration.getDriverURL());
+        jpaConfiguration.getCredential()
+            .ifPresent(credential -> {
+                properties.put("openjpa.ConnectionUserName", credential.getUsername());
+                properties.put("openjpa.ConnectionPassword", credential.getPassword());
+            });
 
         List<String> connectionFactoryProperties = new ArrayList<>();
         connectionFactoryProperties.add("TestOnBorrow=" + jpaConfiguration.isTestOnBorrow());
-        if (jpaConfiguration.getValidationQueryTimeoutSec() > 0) {
-            connectionFactoryProperties.add("ValidationTimeout=" + jpaConfiguration.getValidationQueryTimeoutSec() * 1000);
-        }
-        if (jpaConfiguration.getValidationQuery() != null) {
-            connectionFactoryProperties.add("ValidationSQL='" + jpaConfiguration.getValidationQuery() + "'");
-        }
+        jpaConfiguration.getValidationQueryTimeoutSec()
+            .ifPresent(timeoutSecond -> connectionFactoryProperties.add("ValidationTimeout=" + timeoutSecond * 1000));
+        jpaConfiguration.getValidationQuery()
+            .ifPresent(validationQuery -> connectionFactoryProperties.add("ValidationSQL='" + validationQuery + "'"));
+
         properties.put("openjpa.ConnectionFactoryProperties", Joiner.on(", ").join(connectionFactoryProperties));
 
         return Persistence.createEntityManagerFactory("Global", properties);
@@ -71,8 +74,10 @@ public class JPAEntityManagerModule extends AbstractModule {
                 .driverName(dataSource.getString("database.driverClassName"))
                 .driverURL(dataSource.getString("database.url"))
                 .testOnBorrow(dataSource.getBoolean("datasource.testOnBorrow", false))
-                .validationQueryTimeoutSec(dataSource.getInt("datasource.validationQueryTimeoutSec", JPAConstants.VALIDATION_NO_TIMEOUT))
+                .validationQueryTimeoutSec(dataSource.getInteger("datasource.validationQueryTimeoutSec", null))
                 .validationQuery(dataSource.getString("datasource.validationQuery", null))
+                .username(dataSource.getString("database.username"))
+                .password(dataSource.getString("database.password"))
                 .build();
     }
 }
diff --git a/server/container/guice/jpa-common-guice/src/test/java/org/apache/james/TestJPAConfigurationModuleWithSqlValidation.java b/server/container/guice/jpa-common-guice/src/test/java/org/apache/james/TestJPAConfigurationModuleWithSqlValidation.java
index 4fdb623..9013fef 100644
--- a/server/container/guice/jpa-common-guice/src/test/java/org/apache/james/TestJPAConfigurationModuleWithSqlValidation.java
+++ b/server/container/guice/jpa-common-guice/src/test/java/org/apache/james/TestJPAConfigurationModuleWithSqlValidation.java
@@ -19,6 +19,11 @@
 
 package org.apache.james;
 
+import java.sql.CallableStatement;
+import java.sql.Connection;
+import java.sql.DriverManager;
+import java.sql.SQLException;
+
 import javax.inject.Singleton;
 
 import org.apache.james.modules.data.JPAConfiguration;
@@ -26,25 +31,78 @@ import org.apache.james.modules.data.JPAConfiguration;
 import com.google.inject.AbstractModule;
 import com.google.inject.Provides;
 
-public class TestJPAConfigurationModuleWithSqlValidation extends AbstractModule {
+public interface TestJPAConfigurationModuleWithSqlValidation {
+
+    class NoDatabaseAuthentication extends AbstractModule {
+        @Override
+        protected void configure() {
+        }
+
+        @Provides
+        @Singleton
+        JPAConfiguration provideConfiguration() {
+            return jpaConfigurationBuilder().build();
+        }
+    }
+
+    class WithDatabaseAuthentication extends AbstractModule {
+
+        @Override
+        protected void configure() {
+            setupAuthenticationOnDerby();
+        }
 
-    private static final String JDBC_EMBEDDED_URL = "jdbc:derby:memory:mailboxintegration;create=true";
-    private static final String JDBC_EMBEDDED_DRIVER = org.apache.derby.jdbc.EmbeddedDriver.class.getName();
-    private static final String VALIDATION_SQL_QUERY = "VALUES 1";
+        @Provides
+        @Singleton
+        JPAConfiguration provideConfiguration() {
+            return jpaConfigurationBuilder()
+                .username(DATABASE_USERNAME)
+                .password(DATABASE_PASSWORD)
+                .build();
+        }
+
+        private void setupAuthenticationOnDerby() {
+            try (Connection conn = DriverManager.getConnection(JDBC_EMBEDDED_URL, DATABASE_USERNAME, DATABASE_PASSWORD)) {
+                // Setting and Confirming requireAuthentication
+                setDerbyProperty(conn, "derby.connection.requireAuthentication", "true");
+
+                // Setting authentication scheme and username password to Derby
+                setDerbyProperty(conn, "derby.authentication.provider", "BUILTIN");
+                setDerbyProperty(conn, "derby.user." + DATABASE_USERNAME + "", DATABASE_PASSWORD);
+                setDerbyProperty(conn, "derby.database.propertiesOnly", "true");
 
-    @Override
-    protected void configure() {
+                // Setting default connection mode to no access to restrict accesses without authentication information
+                setDerbyProperty(conn, "derby.database.defaultConnectionMode", "noAccess");
+                setDerbyProperty(conn, "derby.database.fullAccessUsers", DATABASE_USERNAME);
+                setDerbyProperty(conn, "derby.database.propertiesOnly", "false");
+            } catch (SQLException e) {
+                throw new RuntimeException(e);
+            }
+        }
+
+        private void setDerbyProperty(Connection conn, String key, String value) {
+            try (CallableStatement call = conn.prepareCall("CALL SYSCS_UTIL.SYSCS_SET_DATABASE_PROPERTY(?, ?)")) {
+                call.setString(1, key);
+                call.setString(2, value);
+                call.execute();
+            } catch (SQLException e) {
+                throw new RuntimeException(e);
+            }
+        }
     }
 
-    @Provides
-    @Singleton
-    JPAConfiguration provideConfiguration() {
+    String DATABASE_USERNAME = "james";
+    String DATABASE_PASSWORD = "james-secret";
+    String JDBC_EMBEDDED_URL = "jdbc:derby:memory:mailboxintegration;create=true";
+    String JDBC_EMBEDDED_DRIVER = org.apache.derby.jdbc.EmbeddedDriver.class.getName();
+    String VALIDATION_SQL_QUERY = "VALUES 1";
+
+    static JPAConfiguration.ReadyToBuild jpaConfigurationBuilder() {
         return JPAConfiguration.builder()
                 .driverName(JDBC_EMBEDDED_DRIVER)
                 .driverURL(JDBC_EMBEDDED_URL)
                 .testOnBorrow(true)
                 .validationQueryTimeoutSec(2)
-                .validationQuery(VALIDATION_SQL_QUERY)
-                .build();
+                .validationQuery(VALIDATION_SQL_QUERY);
     }
 }
diff --git a/server/container/guice/jpa-common-guice/src/test/java/org/apache/james/modules/data/JPAConfigurationTest.java b/server/container/guice/jpa-common-guice/src/test/java/org/apache/james/modules/data/JPAConfigurationTest.java
new file mode 100644
index 0000000..967d252
--- /dev/null
+++ b/server/container/guice/jpa-common-guice/src/test/java/org/apache/james/modules/data/JPAConfigurationTest.java
@@ -0,0 +1,163 @@
+/****************************************************************
+ * 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.modules.data;
+
+import static org.assertj.core.api.Assertions.assertThat;
+import static org.assertj.core.api.Assertions.assertThatThrownBy;
+
+import org.assertj.core.api.SoftAssertions;
+import org.junit.jupiter.api.Test;
+
+class JPAConfigurationTest {
+
+    private static final String DRIVER_NAME = "driverName";
+    private static final String DRIVER_URL = "driverUrl";
+    private static final boolean TEST_ON_BORROW = true;
+    private static final String VALIDATION_QUERY = "validationQuery";
+    private static final int VALIDATION_TIMEOUT_SEC = 1;
+    private static final String USER_NAME = "username";
+    private static final String PASSWORD = "password";
+    private static final String EMPTY_STRING = "";
+
+    @Test
+    void buildShouldReturnCorrespondingProperties() {
+        JPAConfiguration configuration = JPAConfiguration.builder()
+            .driverName(DRIVER_NAME)
+            .driverURL(DRIVER_URL)
+            .testOnBorrow(TEST_ON_BORROW)
+            .validationQuery(VALIDATION_QUERY)
+            .validationQueryTimeoutSec(VALIDATION_TIMEOUT_SEC)
+            .username(USER_NAME)
+            .password(PASSWORD)
+            .build();
+
+        SoftAssertions.assertSoftly(softly -> {
+            softly.assertThat(configuration.getDriverName()).isEqualTo(DRIVER_NAME);
+            softly.assertThat(configuration.getDriverURL()).isEqualTo(DRIVER_URL);
+            softly.assertThat(configuration.isTestOnBorrow()).contains(TEST_ON_BORROW);
+            softly.assertThat(configuration.getValidationQuery()).contains(VALIDATION_QUERY);
+            softly.assertThat(configuration.getValidationQueryTimeoutSec()).contains(VALIDATION_TIMEOUT_SEC);
+            softly.assertThat(configuration.getCredential()).hasValueSatisfying(credential -> {
+                    softly.assertThat(credential.getPassword()).isEqualTo(PASSWORD);
+                    softly.assertThat(credential.getUsername()).isEqualTo(USER_NAME);
+                });
+        });
+    }
+
+    @Test
+    void buildShouldReturnEmptyOptionalPropertiesWhenNotSpecified() {
+        JPAConfiguration configuration = JPAConfiguration.builder()
+            .driverName(DRIVER_NAME)
+            .driverURL(DRIVER_URL)
+            .build();
+
+        SoftAssertions.assertSoftly(softly -> {
+            softly.assertThat(configuration.getDriverName()).isEqualTo(DRIVER_NAME);
+            softly.assertThat(configuration.getDriverURL()).isEqualTo(DRIVER_URL);
+
+            softly.assertThat(configuration.isTestOnBorrow()).isEmpty();
+            softly.assertThat(configuration.getValidationQuery()).isEmpty();
+            softly.assertThat(configuration.getValidationQueryTimeoutSec()).isEmpty();
+            softly.assertThat(configuration.getCredential()).isEmpty();
+        });
+    }
+
+    @Test
+    void buildShouldThrowWhenValidationQueryTimeoutSecIsZero() {
+        assertThatThrownBy(() -> JPAConfiguration.builder()
+                .driverName(DRIVER_NAME)
+                .driverURL(DRIVER_URL)
+                .validationQueryTimeoutSec(0)
+                .build())
+            .isInstanceOf(IllegalArgumentException.class)
+            .hasMessage("validationQueryTimeoutSec is required to be greater than 0");
+    }
+
+    @Test
+    void buildShouldThrowWhenValidationQueryTimeoutSecIsNegative() {
+        assertThatThrownBy(() -> JPAConfiguration.builder()
+                .driverName(DRIVER_NAME)
+                .driverURL(DRIVER_URL)
+                .validationQueryTimeoutSec(-1)
+                .build())
+            .isInstanceOf(IllegalArgumentException.class)
+            .hasMessage("validationQueryTimeoutSec is required to be greater than 0");
+    }
+
+    @Test
+    void buildShouldThrowWhenPasswordIsNull() {
+        assertThatThrownBy(() -> JPAConfiguration.builder()
+                .driverName(DRIVER_NAME)
+                .driverURL(DRIVER_URL)
+                .username(USER_NAME)
+                .password(null)
+                .build())
+            .isInstanceOf(IllegalArgumentException.class)
+            .hasMessage("username and password for connecting to database can't be blank");
+    }
+
+    @Test
+    void buildShouldThrowWhenPasswordIsEmpty() {
+        assertThatThrownBy(() -> JPAConfiguration.builder()
+                .driverName(DRIVER_NAME)
+                .driverURL(DRIVER_URL)
+                .username(USER_NAME)
+                .password(EMPTY_STRING)
+                .build())
+            .isInstanceOf(IllegalArgumentException.class)
+            .hasMessage("username and password for connecting to database can't be blank");
+    }
+
+    @Test
+    void buildShouldThrowWhenUsernameIsNull() {
+        assertThatThrownBy(() -> JPAConfiguration.builder()
+                .driverName(DRIVER_NAME)
+                .driverURL(DRIVER_URL)
+                .username(null)
+                .password(PASSWORD)
+                .build())
+            .isInstanceOf(IllegalArgumentException.class)
+            .hasMessage("username and password for connecting to database can't be blank");
+    }
+
+    @Test
+    void buildShouldThrowWhenUsernameIsEmpty() {
+        assertThatThrownBy(() -> JPAConfiguration.builder()
+                .driverName(DRIVER_NAME)
+                .driverURL(DRIVER_URL)
+                .username(EMPTY_STRING)
+                .password(PASSWORD)
+                .build())
+            .isInstanceOf(IllegalArgumentException.class)
+            .hasMessage("username and password for connecting to database can't be blank");
+    }
+
+    @Test
+    void buildShouldReturnEmptyOptionalCredentialWhenPassingNullValues() {
+        JPAConfiguration configuration = JPAConfiguration.builder()
+            .driverName(DRIVER_NAME)
+            .driverURL(DRIVER_URL)
+            .username(null)
+            .password(null)
+            .build();
+
+        assertThat(configuration.getCredential()).isEmpty();
+    }
+}
\ No newline at end of file
diff --git a/server/container/guice/jpa-guice/src/test/java/org/apache/james/JPAJamesServerWithSqlValidationTest.java b/server/container/guice/jpa-guice/src/test/java/org/apache/james/JPAJamesServerWithAuthenticatedDatabaseSqlValidationTest.java
similarity index 82%
copy from server/container/guice/jpa-guice/src/test/java/org/apache/james/JPAJamesServerWithSqlValidationTest.java
copy to server/container/guice/jpa-guice/src/test/java/org/apache/james/JPAJamesServerWithAuthenticatedDatabaseSqlValidationTest.java
index 85132d5..863d22d 100644
--- a/server/container/guice/jpa-guice/src/test/java/org/apache/james/JPAJamesServerWithSqlValidationTest.java
+++ b/server/container/guice/jpa-guice/src/test/java/org/apache/james/JPAJamesServerWithAuthenticatedDatabaseSqlValidationTest.java
@@ -19,20 +19,14 @@
 
 package org.apache.james;
 
-import org.junit.jupiter.api.Disabled;
 import org.junit.jupiter.api.extension.RegisterExtension;
 
-class JPAJamesServerWithSqlValidationTest extends JPAJamesServerTest {
+class JPAJamesServerWithAuthenticatedDatabaseSqlValidationTest extends JPAJamesServerWithSqlValidationTest {
 
     @RegisterExtension
     static JamesServerExtension jamesServerExtension = new JamesServerExtensionBuilder()
         .server(configuration -> GuiceJamesServer.forConfiguration(configuration)
             .combineWith(JPAJamesServerMain.JPA_MODULE_AGGREGATE)
-            .overrideWith(new TestJPAConfigurationModuleWithSqlValidation(), DOMAIN_LIST_CONFIGURATION_MODULE))
+            .overrideWith(new TestJPAConfigurationModuleWithSqlValidation.WithDatabaseAuthentication(), DOMAIN_LIST_CONFIGURATION_MODULE))
         .build();
-
-    @Override
-    @Disabled("Failing to create the domain: duplicate with test in JPAJamesServerTest")
-    void jpaGuiceServerShouldUpdateQuota(GuiceJamesServer jamesServer) {
-    }
 }
diff --git a/server/container/guice/jpa-guice/src/test/java/org/apache/james/JPAJamesServerWithSqlValidationTest.java b/server/container/guice/jpa-guice/src/test/java/org/apache/james/JPAJamesServerWithNoDatabaseAuthenticaticationSqlValidationTest.java
similarity index 82%
copy from server/container/guice/jpa-guice/src/test/java/org/apache/james/JPAJamesServerWithSqlValidationTest.java
copy to server/container/guice/jpa-guice/src/test/java/org/apache/james/JPAJamesServerWithNoDatabaseAuthenticaticationSqlValidationTest.java
index 85132d5..4f1b4c1 100644
--- a/server/container/guice/jpa-guice/src/test/java/org/apache/james/JPAJamesServerWithSqlValidationTest.java
+++ b/server/container/guice/jpa-guice/src/test/java/org/apache/james/JPAJamesServerWithNoDatabaseAuthenticaticationSqlValidationTest.java
@@ -19,20 +19,14 @@
 
 package org.apache.james;
 
-import org.junit.jupiter.api.Disabled;
 import org.junit.jupiter.api.extension.RegisterExtension;
 
-class JPAJamesServerWithSqlValidationTest extends JPAJamesServerTest {
+class JPAJamesServerWithNoDatabaseAuthenticaticationSqlValidationTest extends JPAJamesServerWithSqlValidationTest {
 
     @RegisterExtension
     static JamesServerExtension jamesServerExtension = new JamesServerExtensionBuilder()
         .server(configuration -> GuiceJamesServer.forConfiguration(configuration)
             .combineWith(JPAJamesServerMain.JPA_MODULE_AGGREGATE)
-            .overrideWith(new TestJPAConfigurationModuleWithSqlValidation(), DOMAIN_LIST_CONFIGURATION_MODULE))
+            .overrideWith(new TestJPAConfigurationModuleWithSqlValidation.NoDatabaseAuthentication(), DOMAIN_LIST_CONFIGURATION_MODULE))
         .build();
-
-    @Override
-    @Disabled("Failing to create the domain: duplicate with test in JPAJamesServerTest")
-    void jpaGuiceServerShouldUpdateQuota(GuiceJamesServer jamesServer) {
-    }
 }
diff --git a/server/container/guice/jpa-guice/src/test/java/org/apache/james/JPAJamesServerWithSqlValidationTest.java b/server/container/guice/jpa-guice/src/test/java/org/apache/james/JPAJamesServerWithSqlValidationTest.java
index 85132d5..4a0e1f5 100644
--- a/server/container/guice/jpa-guice/src/test/java/org/apache/james/JPAJamesServerWithSqlValidationTest.java
+++ b/server/container/guice/jpa-guice/src/test/java/org/apache/james/JPAJamesServerWithSqlValidationTest.java
@@ -20,16 +20,8 @@
 package org.apache.james;
 
 import org.junit.jupiter.api.Disabled;
-import org.junit.jupiter.api.extension.RegisterExtension;
 
-class JPAJamesServerWithSqlValidationTest extends JPAJamesServerTest {
-
-    @RegisterExtension
-    static JamesServerExtension jamesServerExtension = new JamesServerExtensionBuilder()
-        .server(configuration -> GuiceJamesServer.forConfiguration(configuration)
-            .combineWith(JPAJamesServerMain.JPA_MODULE_AGGREGATE)
-            .overrideWith(new TestJPAConfigurationModuleWithSqlValidation(), DOMAIN_LIST_CONFIGURATION_MODULE))
-        .build();
+abstract class JPAJamesServerWithSqlValidationTest extends JPAJamesServerTest {
 
     @Override
     @Disabled("Failing to create the domain: duplicate with test in JPAJamesServerTest")


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