You are viewing a plain text version of this content. The canonical link for it is here.
Posted to notifications@james.apache.org by bt...@apache.org on 2021/02/04 05:02:28 UTC

[james-project] 02/18: JAMES-3498 Move as is the In VM implementation

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

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

commit c4f6a0d82af3560f07aba5889a8c8d3d5dd48d99
Author: Benoit Tellier <bt...@linagora.com>
AuthorDate: Mon Jan 25 13:47:59 2021 +0700

    JAMES-3498 Move as is the In VM implementation
---
 event-bus/in-vm/pom.xml                            |  44 +
 .../listeners/SetCustomFlagOnBigMessages.java      |   6 +-
 .../apache/james/mailbox/events/MailboxEvents.java | 582 ------------
 .../mailbox/events/MailboxIdRegistrationKey.java   |  78 --
 .../james/mailbox/events/MessageMoveEvent.java     | 154 ----
 .../mailbox/events/RetryBackoffConfiguration.java  | 125 ---
 .../java/org/apache/james/mailbox/EventTest.java   |   2 +-
 .../apache/james/mailbox/MailboxListenerTest.java  |  16 +-
 .../mailbox/MailboxManagerStressContract.java      |   4 +-
 .../apache/james/mailbox/MailboxManagerTest.java   |  16 +-
 .../apache/james/mailbox/MessageMoveEventTest.java |   2 +-
 .../mailbox/events/ErrorHandlingContract.java      | 367 --------
 .../events/EventBusConcurrentTestContract.java     | 240 -----
 .../james/mailbox/events/EventBusContract.java     |  73 --
 .../james/mailbox/events/EventBusTestFixture.java  | 145 ---
 .../mailbox/events/EventDeadLettersContract.java   | 493 -----------
 .../EventDeadLettersHealthCheckContract.java       | 134 ---
 .../apache/james/mailbox/events/GroupContract.java | 504 -----------
 .../org/apache/james/mailbox/events/GroupTest.java | 135 ---
 .../james/mailbox/events/InsertionIdTest.java      |  57 --
 .../apache/james/mailbox/events/KeyContract.java   | 458 ----------
 .../events/MailboxIdRegistrationKeyTest.java       |  60 --
 .../events/RetryBackoffConfigurationTest.java      | 141 ---
 .../james/mailbox/model/MessageMovesTest.java      |   2 +-
 mailbox/cassandra/pom.xml                          |  10 +-
 .../mailbox/cassandra/DeleteMessageListener.java   |   4 +-
 .../cassandra/MailboxOperationLoggingListener.java |   6 +-
 .../cassandra/CassandraCombinationManagerTest.java |   8 +-
 .../cassandra/CassandraMailboxManagerProvider.java |   8 +-
 .../CassandraMessageIdManagerStorageTest.java      |   8 +-
 .../cassandra/CassandraTestSystemFixture.java      |   8 +-
 .../CassandraMailboxManagerAttachmentTest.java     |   8 +-
 mailbox/elasticsearch/pom.xml                      |  10 +-
 .../mailbox/events/CassandraEventDeadLetters.java  |  89 --
 .../events/CassandraEventDeadLettersDAO.java       | 132 ---
 .../events/CassandraEventDeadLettersGroupDAO.java  |  71 --
 .../events/CassandraEventDeadLettersModule.java    |  46 -
 .../CassandraEventDeadLettersGroupTable.java       |  27 -
 .../tables/CassandraEventDeadLettersTable.java     |  29 -
 .../events/CassandraEventDeadLettersDAOTest.java   | 145 ---
 .../CassandraEventDeadLettersGroupDAOTest.java     |  60 --
 .../CassandraEventDeadLettersHealthCheckTest.java  |  70 --
 .../events/CassandraEventDeadLettersTest.java      |  50 --
 mailbox/event/event-memory/pom.xml                 |  79 --
 .../apache/james/mailbox/events/InVMEventBus.java  | 134 ---
 .../mailbox/events/MemoryEventDeadLetters.java     |  95 --
 .../mailbox/events/delivery/EventDelivery.java     | 134 ---
 .../mailbox/events/delivery/InVmEventDelivery.java | 104 ---
 .../james/mailbox/events/InVMEventBusTest.java     |  55 --
 .../MemoryEventDeadLettersHealthCheckTest.java     |  59 --
 .../mailbox/events/MemoryEventDeadLettersTest.java |  38 -
 .../events/delivery/InVmEventDeliveryTest.java     | 253 ------
 mailbox/event/event-rabbitmq/pom.xml               |  10 +-
 .../apache/james/mailbox/events/EventBusId.java    |  72 --
 .../james/mailbox/events/EventDispatcher.java      | 201 -----
 .../james/mailbox/events/GroupConsumerRetry.java   | 145 ---
 .../james/mailbox/events/GroupRegistration.java    | 198 -----
 .../mailbox/events/GroupRegistrationHandler.java   |  93 --
 .../mailbox/events/KeyReconnectionHandler.java     |  60 --
 .../james/mailbox/events/KeyRegistration.java      |  35 -
 .../mailbox/events/KeyRegistrationHandler.java     | 204 -----
 .../mailbox/events/LocalListenerRegistry.java      | 112 ---
 .../mailbox/events/MailboxListenerExecutor.java    |  56 --
 .../james/mailbox/events/RabbitMQEventBus.java     | 177 ----
 .../james/mailbox/events/RegistrationBinder.java   |  56 --
 .../mailbox/events/RegistrationQueueName.java      |  32 -
 .../james/mailbox/events/RoutingKeyConverter.java  |  92 --
 .../james/mailbox/events/WaitDelayGenerator.java   |  83 --
 .../james/mailbox/events/EventBusIdTest.java       |  50 --
 .../mailbox/events/LocalListenerRegistryTest.java  | 256 ------
 .../james/mailbox/events/NetworkErrorTest.java     |  89 --
 ...RabbitMQEventBusDeadLetterQueueUpgradeTest.java |  88 --
 .../james/mailbox/events/RabbitMQEventBusTest.java | 980 ---------------------
 .../mailbox/events/RoutingKeyConverterTest.java    | 144 ---
 .../mailbox/events/WaitDelayGeneratorTest.java     | 103 ---
 .../apache/james/event/json/EventSerializer.scala  |   8 +-
 .../james/event/json/AddedSerializationTest.java   |   2 +-
 .../event/json/ExpungedSerializationTest.java      |   2 +-
 .../event/json/FlagsUpdatedSerializationTest.java  |   2 +-
 .../MailboxACLUpdatedEventSerializationTest.java   |   2 +-
 .../event/json/MailboxAddedSerializationTest.java  |   2 +-
 .../json/MailboxDeletionSerializationTest.java     |   2 +-
 .../json/MailboxRenamedSerializationTest.java      |   2 +-
 .../json/MessageMoveEventSerializationTest.java    |   2 +-
 .../QuotaUsageUpdatedEventSerializationTest.java   |   2 +-
 mailbox/jpa/pom.xml                                |  10 +-
 .../mailbox/jpa/JpaMailboxManagerProvider.java     |   8 +-
 mailbox/lucene/pom.xml                             |  10 +-
 mailbox/maildir/pom.xml                            |   6 +-
 .../maildir/MaildirMailboxManagerProvider.java     |   8 +-
 .../manager/InMemoryIntegrationResources.java      |   8 +-
 mailbox/plugin/quota-mailing/pom.xml               |  10 +-
 .../listeners/QuotaThresholdCrossingListener.java  |   2 +-
 .../QuotaThresholdListenersTestSystem.java         |   8 +-
 .../events/ElasticSearchQuotaMailboxListener.java  |   2 +-
 .../json/QuotaRatioToElasticSearchJson.java        |   2 +-
 .../json/QuotaRatioToElasticSearchJsonTest.java    |   2 +-
 .../mailbox/spamassassin/SpamAssassinListener.java |   4 +-
 .../spamassassin/SpamAssassinListenerTest.java     |   4 +-
 mailbox/pom.xml                                    |   1 -
 mailbox/spring/pom.xml                             |   8 +-
 .../resources/META-INF/spring/event-system.xml     |   8 +-
 mailbox/store/pom.xml                              |   2 +-
 .../james/mailbox/store/StoreMailboxManager.java   |   2 +-
 .../james/mailbox/store/StoreMessageIdManager.java |   2 +-
 .../james/mailbox/store/StoreMessageManager.java   |   2 +-
 .../james/mailbox/store/StoreRightManager.java     |   2 +-
 .../james/mailbox/store/event/EventFactory.java    |  18 +-
 .../store/event/MailboxAnnotationListener.java     |   2 +-
 .../store/quota/ListeningCurrentQuotaUpdater.java  |   8 +-
 .../store/search/ListeningMessageSearchIndex.java  |  10 +-
 .../AbstractMessageIdManagerSideEffectTest.java    |  18 +-
 .../mailbox/store/MessageIdManagerTestSystem.java  |   2 +-
 .../mailbox/store/StoreMailboxManagerTest.java     |   8 +-
 .../store/event/MailboxAnnotationListenerTest.java |   4 +-
 .../quota/ListeningCurrentQuotaUpdaterTest.java    |   6 +-
 mpt/impl/imap-mailbox/cassandra/pom.xml            |   8 +-
 .../cassandra/host/CassandraHostSystem.java        |   8 +-
 mpt/impl/imap-mailbox/elasticsearch/pom.xml        |  10 +-
 mpt/impl/imap-mailbox/jpa/pom.xml                  |   2 +-
 .../mpt/imapmailbox/jpa/host/JPAHostSystem.java    |   8 +-
 mpt/impl/imap-mailbox/lucenesearch/pom.xml         |   2 +-
 mpt/impl/imap-mailbox/maildir/pom.xml              |   8 +-
 .../maildir/host/MaildirHostSystem.java            |   8 +-
 .../rabbitmq/host/RabbitMQEventBusHostSystem.java  |  12 +-
 pom.xml                                            |  10 +-
 .../apache/james/imap/processor/IdleProcessor.java |   8 +-
 .../imap/processor/base/SelectedMailboxImpl.java   |  14 +-
 .../processor/base/MailboxEventAnalyserTest.java   |  18 +-
 .../processor/base/SelectedMailboxImplTest.java    |  10 +-
 .../james/app/spring/JamesSpringContextTest.java   |   2 +-
 .../modules/mailbox/CassandraDeadLetterModule.java |   8 +-
 .../modules/event/RabbitMQEventBusModule.java      |  10 +-
 server/container/guice/mailbox/pom.xml             |   6 +-
 .../james/modules/mailbox/DefaultEventModule.java  |   8 +-
 .../modules/mailbox/FastRetryBackoffModule.java    |   2 +-
 .../modules/mailbox/MemoryDeadLetterModule.java    |   2 +-
 .../mailbox/MailboxListenersLoaderImplTest.java    |   9 +-
 .../apache/james/jmap/api/change/EmailChange.java  |   6 +-
 .../james/jmap/api/change/MailboxChange.java       |  14 +-
 .../methods/integration/SetMessagesMethodTest.java |   4 +-
 .../ComputeMessageFastViewProjectionListener.java  |   2 +-
 .../jmap/event/PopulateEmailQueryViewListener.java |   6 +-
 .../jmap/event/PropagateLookupRightListener.java   |   4 +-
 ...mputeMessageFastViewProjectionListenerTest.java |   8 +-
 .../event/PopulateEmailQueryViewListenerTest.java  |   8 +-
 .../james/jmap/change/MailboxChangeListener.scala  |   7 +-
 .../jmap/change/MailboxChangeListenerTest.scala    |   7 +-
 .../rabbitmq/ConsistencyTasksIntegrationTest.java  |   2 +-
 .../RabbitMQEventDeadLettersIntegrationTest.java   |   4 +-
 ...RabbitMQReindexingWithEventDeadLettersTest.java |   2 +-
 ...dminServerTaskSerializationIntegrationTest.java |   2 +-
 server/protocols/webadmin/webadmin-mailbox/pom.xml |   2 +-
 .../routes/EventDeadLettersRoutesTest.java         |  12 +-
 154 files changed, 346 insertions(+), 9044 deletions(-)

diff --git a/event-bus/in-vm/pom.xml b/event-bus/in-vm/pom.xml
index 99fc5c2..a0a178c 100644
--- a/event-bus/in-vm/pom.xml
+++ b/event-bus/in-vm/pom.xml
@@ -31,4 +31,48 @@
     <name>Apache James :: Event Bus :: In VM</name>
     <description>In VM (non distributed) implementation for the eventBus</description>
 
+    <dependencies>
+        <dependency>
+            <groupId>${james.groupId}</groupId>
+            <artifactId>metrics-tests</artifactId>
+            <scope>test</scope>
+        </dependency>
+        <dependency>
+            <groupId>${james.groupId}</groupId>
+            <artifactId>testing-base</artifactId>
+            <scope>test</scope>
+        </dependency>
+        <dependency>
+            <groupId>${project.groupId}</groupId>
+            <artifactId>apache-james-mailbox-api</artifactId>
+        </dependency>
+        <dependency>
+            <groupId>${project.groupId}</groupId>
+            <artifactId>apache-james-mailbox-api</artifactId>
+            <type>test-jar</type>
+            <scope>test</scope>
+        </dependency>
+        <dependency>
+            <groupId>${project.groupId}</groupId>
+            <artifactId>james-server-util</artifactId>
+        </dependency>
+        <dependency>
+            <groupId>${project.groupId}</groupId>
+            <artifactId>metrics-api</artifactId>
+        </dependency>
+        <dependency>
+            <groupId>io.projectreactor</groupId>
+            <artifactId>reactor-core</artifactId>
+        </dependency>
+        <dependency>
+            <groupId>org.awaitility</groupId>
+            <artifactId>awaitility</artifactId>
+            <scope>test</scope>
+        </dependency>
+        <dependency>
+            <groupId>org.mockito</groupId>
+            <artifactId>mockito-core</artifactId>
+            <scope>test</scope>
+        </dependency>
+    </dependencies>
 </project>
\ No newline at end of file
diff --git a/examples/custom-listeners/src/main/java/org/apache/james/examples/custom/listeners/SetCustomFlagOnBigMessages.java b/examples/custom-listeners/src/main/java/org/apache/james/examples/custom/listeners/SetCustomFlagOnBigMessages.java
index d541029..6c942ce 100644
--- a/examples/custom-listeners/src/main/java/org/apache/james/examples/custom/listeners/SetCustomFlagOnBigMessages.java
+++ b/examples/custom-listeners/src/main/java/org/apache/james/examples/custom/listeners/SetCustomFlagOnBigMessages.java
@@ -22,15 +22,15 @@ package org.apache.james.examples.custom.listeners;
 import javax.inject.Inject;
 import javax.mail.Flags;
 
+import org.apache.james.events.Event;
 import org.apache.james.events.EventListener;
+import org.apache.james.events.Group;
+import org.apache.james.events.MailboxEvents.Added;
 import org.apache.james.mailbox.MailboxManager;
 import org.apache.james.mailbox.MailboxSession;
 import org.apache.james.mailbox.MessageManager;
 import org.apache.james.mailbox.MessageManager.FlagsUpdateMode;
 import org.apache.james.mailbox.MessageUid;
-import org.apache.james.events.Event;
-import org.apache.james.events.Group;
-import org.apache.james.mailbox.events.MailboxEvents.Added;
 import org.apache.james.mailbox.exception.MailboxException;
 import org.apache.james.mailbox.model.MessageRange;
 import org.slf4j.Logger;
diff --git a/mailbox/api/src/main/java/org/apache/james/mailbox/events/MailboxEvents.java b/mailbox/api/src/main/java/org/apache/james/mailbox/events/MailboxEvents.java
deleted file mode 100644
index d544e35..0000000
--- a/mailbox/api/src/main/java/org/apache/james/mailbox/events/MailboxEvents.java
+++ /dev/null
@@ -1,582 +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.mailbox.events;
-
-import java.time.Instant;
-import java.util.Collection;
-import java.util.List;
-import java.util.Map;
-import java.util.Objects;
-import java.util.Optional;
-import java.util.SortedMap;
-
-import org.apache.james.core.Username;
-import org.apache.james.core.quota.QuotaCountLimit;
-import org.apache.james.core.quota.QuotaCountUsage;
-import org.apache.james.core.quota.QuotaSizeLimit;
-import org.apache.james.core.quota.QuotaSizeUsage;
-import org.apache.james.events.Event;
-import org.apache.james.mailbox.MailboxSession;
-import org.apache.james.mailbox.MessageUid;
-import org.apache.james.mailbox.acl.ACLDiff;
-import org.apache.james.mailbox.model.MailboxACL;
-import org.apache.james.mailbox.model.MailboxId;
-import org.apache.james.mailbox.model.MailboxPath;
-import org.apache.james.mailbox.model.MessageId;
-import org.apache.james.mailbox.model.MessageMetaData;
-import org.apache.james.mailbox.model.Quota;
-import org.apache.james.mailbox.model.QuotaRoot;
-import org.apache.james.mailbox.model.UpdatedFlags;
-
-import com.github.steveash.guavate.Guavate;
-import com.google.common.collect.ImmutableList;
-import com.google.common.collect.ImmutableMap;
-import com.google.common.collect.ImmutableSet;
-
-public interface MailboxEvents {
-
-    interface QuotaEvent extends Event {
-        QuotaRoot getQuotaRoot();
-    }
-
-    class QuotaUsageUpdatedEvent implements QuotaEvent {
-        private final EventId eventId;
-        private final Username username;
-        private final QuotaRoot quotaRoot;
-        private final Quota<QuotaCountLimit, QuotaCountUsage> countQuota;
-        private final Quota<QuotaSizeLimit, QuotaSizeUsage> sizeQuota;
-        private final Instant instant;
-
-        public QuotaUsageUpdatedEvent(EventId eventId, Username username, QuotaRoot quotaRoot, Quota<QuotaCountLimit, QuotaCountUsage> countQuota, Quota<QuotaSizeLimit, QuotaSizeUsage> sizeQuota, Instant instant) {
-            this.eventId = eventId;
-            this.username = username;
-            this.quotaRoot = quotaRoot;
-            this.countQuota = countQuota;
-            this.sizeQuota = sizeQuota;
-            this.instant = instant;
-        }
-
-        @Override
-        public boolean isNoop() {
-            return false;
-        }
-
-        @Override
-        public Username getUsername() {
-            return username;
-        }
-
-        public Quota<QuotaCountLimit, QuotaCountUsage> getCountQuota() {
-            return countQuota;
-        }
-
-        public Quota<QuotaSizeLimit, QuotaSizeUsage> getSizeQuota() {
-            return sizeQuota;
-        }
-
-        @Override
-        public QuotaRoot getQuotaRoot() {
-            return quotaRoot;
-        }
-
-        public Instant getInstant() {
-            return instant;
-        }
-
-        @Override
-        public EventId getEventId() {
-            return eventId;
-        }
-
-        @Override
-        public final boolean equals(Object o) {
-            if (o instanceof QuotaUsageUpdatedEvent) {
-                QuotaUsageUpdatedEvent that = (QuotaUsageUpdatedEvent) o;
-
-                return Objects.equals(this.eventId, that.eventId)
-                    && Objects.equals(this.username, that.username)
-                    && Objects.equals(this.quotaRoot, that.quotaRoot)
-                    && Objects.equals(this.countQuota, that.countQuota)
-                    && Objects.equals(this.sizeQuota, that.sizeQuota)
-                    && Objects.equals(this.instant, that.instant);
-            }
-            return false;
-        }
-
-        @Override
-        public final int hashCode() {
-            return Objects.hash(eventId, username, quotaRoot, countQuota, sizeQuota, instant);
-        }
-
-    }
-
-    /**
-     * A mailbox event.
-     */
-    abstract class MailboxEvent implements Event {
-        protected final MailboxPath path;
-        protected final MailboxId mailboxId;
-        protected final Username username;
-        protected final MailboxSession.SessionId sessionId;
-        protected final EventId eventId;
-
-        public MailboxEvent(MailboxSession.SessionId sessionId, Username username, MailboxPath path, MailboxId mailboxId, EventId eventId) {
-            this.username = username;
-            this.path = path;
-            this.mailboxId = mailboxId;
-            this.sessionId = sessionId;
-            this.eventId = eventId;
-        }
-
-        /**
-         * Gets the {@link Username} in which's context the {@link MailboxEvent}
-         * happened
-         *
-         * @return user
-         */
-        @Override
-        public Username getUsername() {
-            return username;
-        }
-
-        @Override
-        public EventId getEventId() {
-            return eventId;
-        }
-
-        /**
-         * Gets the sessionId in which's context the {@link MailboxEvent}
-         * happened
-         *
-         * @return sessionId
-         */
-        public MailboxSession.SessionId getSessionId() {
-            return sessionId;
-        }
-
-        /**
-         * Return the path of the Mailbox this event belongs to.
-         *
-         * @return path
-         */
-        public MailboxPath getMailboxPath() {
-            return path;
-        }
-
-        /**
-         * Return the id of the Mailbox this event belongs to.
-         *
-         * @return mailboxId
-         */
-        public MailboxId getMailboxId() {
-            return mailboxId;
-        }
-    }
-
-    /**
-     * Indicates that mailbox has been deleted.
-     */
-    class MailboxDeletion extends MailboxEvent {
-        private final MailboxACL mailboxACL;
-        private final QuotaRoot quotaRoot;
-        private final QuotaCountUsage deletedMessageCount;
-        private final QuotaSizeUsage totalDeletedSize;
-
-        public MailboxDeletion(MailboxSession.SessionId sessionId, Username username, MailboxPath path, MailboxACL mailboxACL, QuotaRoot quotaRoot, QuotaCountUsage deletedMessageCount, QuotaSizeUsage totalDeletedSize,
-                               MailboxId mailboxId, EventId eventId) {
-            super(sessionId, username, path, mailboxId, eventId);
-            this.mailboxACL = mailboxACL;
-            this.quotaRoot = quotaRoot;
-            this.deletedMessageCount = deletedMessageCount;
-            this.totalDeletedSize = totalDeletedSize;
-        }
-
-        @Override
-        public boolean isNoop() {
-            return false;
-        }
-
-        public MailboxACL getMailboxACL() {
-            return mailboxACL;
-        }
-
-        public QuotaRoot getQuotaRoot() {
-            return quotaRoot;
-        }
-
-        public QuotaCountUsage getDeletedMessageCount() {
-            return deletedMessageCount;
-        }
-
-        public QuotaSizeUsage getTotalDeletedSize() {
-            return totalDeletedSize;
-        }
-
-        @Override
-        public final boolean equals(Object o) {
-            if (o instanceof MailboxDeletion) {
-                MailboxDeletion that = (MailboxDeletion) o;
-
-                return Objects.equals(this.eventId, that.eventId)
-                    && Objects.equals(this.sessionId, that.sessionId)
-                    && Objects.equals(this.username, that.username)
-                    && Objects.equals(this.path, that.path)
-                    && Objects.equals(this.mailboxACL, that.mailboxACL)
-                    && Objects.equals(this.mailboxId, that.mailboxId)
-                    && Objects.equals(this.quotaRoot, that.quotaRoot)
-                    && Objects.equals(this.deletedMessageCount, that.deletedMessageCount)
-                    && Objects.equals(this.totalDeletedSize, that.totalDeletedSize);
-            }
-            return false;
-        }
-
-        @Override
-        public final int hashCode() {
-            return Objects.hash(eventId, sessionId, username, path, mailboxACL, mailboxId, quotaRoot, deletedMessageCount, totalDeletedSize);
-        }
-    }
-
-    /**
-     * Indicates that a mailbox has been Added.
-     */
-    class MailboxAdded extends MailboxEvent {
-
-        public MailboxAdded(MailboxSession.SessionId sessionId, Username username, MailboxPath path, MailboxId mailboxId, EventId eventId) {
-            super(sessionId, username, path, mailboxId, eventId);
-        }
-
-        @Override
-        public boolean isNoop() {
-            return false;
-        }
-
-        @Override
-        public final boolean equals(Object o) {
-            if (o instanceof MailboxAdded) {
-                MailboxAdded that = (MailboxAdded) o;
-
-                return Objects.equals(this.eventId, that.eventId)
-                    && Objects.equals(this.sessionId, that.sessionId)
-                    && Objects.equals(this.username, that.username)
-                    && Objects.equals(this.path, that.path)
-                    && Objects.equals(this.mailboxId, that.mailboxId);
-            }
-            return false;
-        }
-
-        @Override
-        public final int hashCode() {
-            return Objects.hash(eventId, sessionId, username, path, mailboxId);
-        }
-    }
-
-    /**
-     * Indicates that a mailbox has been renamed.
-     */
-    class MailboxRenamed extends MailboxEvent {
-        private final MailboxPath newPath;
-
-        public MailboxRenamed(MailboxSession.SessionId sessionId, Username username, MailboxPath path, MailboxId mailboxId, MailboxPath newPath, EventId eventId) {
-            super(sessionId, username, path, mailboxId, eventId);
-            this.newPath = newPath;
-        }
-
-        @Override
-        public boolean isNoop() {
-            return newPath.equals(path);
-        }
-
-        /**
-         * Gets the new name for this mailbox.
-         *
-         * @return name, not null
-         */
-        public MailboxPath getNewPath() {
-            return newPath;
-        }
-
-        @Override
-        public final boolean equals(Object o) {
-            if (o instanceof MailboxRenamed) {
-                MailboxRenamed that = (MailboxRenamed) o;
-
-                return Objects.equals(this.eventId, that.eventId)
-                    && Objects.equals(this.sessionId, that.sessionId)
-                    && Objects.equals(this.username, that.username)
-                    && Objects.equals(this.path, that.path)
-                    && Objects.equals(this.mailboxId, that.mailboxId)
-                    && Objects.equals(this.newPath, that.newPath);
-            }
-            return false;
-        }
-
-        @Override
-        public final int hashCode() {
-            return Objects.hash(eventId, sessionId, username, path, mailboxId, newPath);
-        }
-    }
-
-
-    /**
-     * A mailbox event related to updated ACL
-     */
-    class MailboxACLUpdated extends MailboxEvent {
-        private final ACLDiff aclDiff;
-
-        public MailboxACLUpdated(MailboxSession.SessionId sessionId, Username username, MailboxPath path, ACLDiff aclDiff, MailboxId mailboxId, EventId eventId) {
-            super(sessionId, username, path, mailboxId, eventId);
-            this.aclDiff = aclDiff;
-        }
-
-        public ACLDiff getAclDiff() {
-            return aclDiff;
-        }
-
-        @Override
-        public boolean isNoop() {
-            return aclDiff.getNewACL().equals(aclDiff.getOldACL());
-        }
-
-        @Override
-        public final boolean equals(Object o) {
-            if (o instanceof MailboxACLUpdated) {
-                MailboxACLUpdated that = (MailboxACLUpdated) o;
-
-                return Objects.equals(this.eventId, that.eventId)
-                    && Objects.equals(this.sessionId, that.sessionId)
-                    && Objects.equals(this.username, that.username)
-                    && Objects.equals(this.path, that.path)
-                    && Objects.equals(this.aclDiff, that.aclDiff)
-                    && Objects.equals(this.mailboxId, that.mailboxId);
-            }
-            return false;
-        }
-
-        @Override
-        public final int hashCode() {
-            return Objects.hash(eventId, sessionId, username, path, aclDiff, mailboxId);
-        }
-
-    }
-
-    /**
-     * A mailbox event related to a message.
-     */
-    abstract class MessageEvent extends MailboxEvent {
-
-        public MessageEvent(MailboxSession.SessionId sessionId, Username username, MailboxPath path, MailboxId mailboxId, EventId eventId) {
-            super(sessionId, username, path, mailboxId, eventId);
-        }
-
-        /**
-         * Gets the message UIDs for the subject of this event.
-         *
-         * @return message uids
-         */
-        public abstract Collection<MessageUid> getUids();
-    }
-
-    abstract class MetaDataHoldingEvent extends MessageEvent {
-
-        public MetaDataHoldingEvent(MailboxSession.SessionId sessionId, Username username, MailboxPath path, MailboxId mailboxId, EventId eventId) {
-            super(sessionId, username, path, mailboxId, eventId);
-        }
-
-        /**
-         * Return the flags which were set for the affected message
-         *
-         * @return flags
-         */
-        public abstract MessageMetaData getMetaData(MessageUid uid);
-
-        public ImmutableSet<MessageId> getMessageIds() {
-            return getUids()
-                .stream()
-                .map(uid -> getMetaData(uid).getMessageId())
-                .collect(Guavate.toImmutableSet());
-        }
-    }
-
-    class Expunged extends MetaDataHoldingEvent {
-        private final Map<MessageUid, MessageMetaData> expunged;
-
-        public Expunged(MailboxSession.SessionId sessionId, Username username, MailboxPath path, MailboxId mailboxId, Map<MessageUid, MessageMetaData> uids, EventId eventId) {
-            super(sessionId, username, path, mailboxId, eventId);
-            this.expunged = ImmutableMap.copyOf(uids);
-        }
-
-        @Override
-        public Collection<MessageUid> getUids() {
-            return expunged.keySet();
-        }
-
-        /**
-         * Return the flags which were set for the added message
-         *
-         * @return flags
-         */
-        @Override
-        public MessageMetaData getMetaData(MessageUid uid) {
-            return expunged.get(uid);
-        }
-
-        public Map<MessageUid, MessageMetaData> getExpunged() {
-            return expunged;
-        }
-
-        @Override
-        public boolean isNoop() {
-            return expunged.isEmpty();
-        }
-
-        @Override
-        public final boolean equals(Object o) {
-            if (o instanceof Expunged) {
-                Expunged that = (Expunged) o;
-
-                return Objects.equals(this.eventId, that.eventId)
-                    && Objects.equals(this.sessionId, that.sessionId)
-                    && Objects.equals(this.username, that.username)
-                    && Objects.equals(this.path, that.path)
-                    && Objects.equals(this.mailboxId, that.mailboxId)
-                    && Objects.equals(this.expunged, that.expunged);
-            }
-            return false;
-        }
-
-        @Override
-        public final int hashCode() {
-            return Objects.hash(eventId, sessionId, username, path, mailboxId, expunged);
-        }
-    }
-
-    /**
-     * A mailbox event related to updated flags
-     */
-    class FlagsUpdated extends MessageEvent {
-        private final List<UpdatedFlags> updatedFlags;
-
-        public FlagsUpdated(MailboxSession.SessionId sessionId, Username username, MailboxPath path,
-                            MailboxId mailboxId, List<UpdatedFlags> updatedFlags, EventId eventId) {
-            super(sessionId, username, path, mailboxId, eventId);
-            this.updatedFlags = ImmutableList.copyOf(updatedFlags);
-        }
-
-        @Override
-        public Collection<MessageUid> getUids() {
-            return updatedFlags.stream()
-                .map(UpdatedFlags::getUid)
-                .collect(Guavate.toImmutableList());
-        }
-
-        public Collection<MessageId> getMessageIds() {
-            return updatedFlags.stream()
-                .map(UpdatedFlags::getMessageId)
-                .flatMap(Optional::stream)
-                .collect(Guavate.toImmutableList());
-        }
-
-        public List<UpdatedFlags> getUpdatedFlags() {
-            return updatedFlags;
-        }
-
-        @Override
-        public boolean isNoop() {
-            return updatedFlags.isEmpty();
-        }
-
-        @Override
-        public final boolean equals(Object o) {
-            if (o instanceof FlagsUpdated) {
-                FlagsUpdated that = (FlagsUpdated) o;
-
-                return Objects.equals(this.eventId, that.eventId)
-                    && Objects.equals(this.sessionId, that.sessionId)
-                    && Objects.equals(this.username, that.username)
-                    && Objects.equals(this.path, that.path)
-                    && Objects.equals(this.mailboxId, that.mailboxId)
-                    && Objects.equals(this.updatedFlags, that.updatedFlags);
-            }
-            return false;
-        }
-
-        @Override
-        public final int hashCode() {
-            return Objects.hash(eventId, sessionId, username, path, mailboxId, updatedFlags);
-        }
-    }
-
-    /**
-     * A mailbox event related to added message
-     */
-    class Added extends MetaDataHoldingEvent {
-        private final Map<MessageUid, MessageMetaData> added;
-
-        public Added(MailboxSession.SessionId sessionId, Username username, MailboxPath path, MailboxId mailboxId,
-                     SortedMap<MessageUid, MessageMetaData> uids, EventId eventId) {
-            super(sessionId, username, path, mailboxId, eventId);
-            this.added = ImmutableMap.copyOf(uids);
-        }
-
-        /**
-         * Return the flags which were set for the added message
-         *
-         * @return flags
-         */
-        public MessageMetaData getMetaData(MessageUid uid) {
-            return added.get(uid);
-        }
-
-        @Override
-        public Collection<MessageUid> getUids() {
-            return added.keySet();
-        }
-
-        public Map<MessageUid, MessageMetaData> getAdded() {
-            return added;
-        }
-
-        @Override
-        public boolean isNoop() {
-            return added.isEmpty();
-        }
-
-        @Override
-        public final boolean equals(Object o) {
-            if (o instanceof Added) {
-                Added that = (Added) o;
-
-                return Objects.equals(this.eventId, that.eventId)
-                    && Objects.equals(this.sessionId, that.sessionId)
-                    && Objects.equals(this.username, that.username)
-                    && Objects.equals(this.path, that.path)
-                    && Objects.equals(this.mailboxId, that.mailboxId)
-                    && Objects.equals(this.added, that.added);
-            }
-            return false;
-        }
-
-        @Override
-        public final int hashCode() {
-            return Objects.hash(eventId, sessionId, username, path, mailboxId, added);
-        }
-    }
-
-}
diff --git a/mailbox/api/src/main/java/org/apache/james/mailbox/events/MailboxIdRegistrationKey.java b/mailbox/api/src/main/java/org/apache/james/mailbox/events/MailboxIdRegistrationKey.java
deleted file mode 100644
index cbbd20b..0000000
--- a/mailbox/api/src/main/java/org/apache/james/mailbox/events/MailboxIdRegistrationKey.java
+++ /dev/null
@@ -1,78 +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.mailbox.events;
-
-import java.util.Objects;
-
-import javax.inject.Inject;
-
-import org.apache.james.events.RegistrationKey;
-import org.apache.james.mailbox.model.MailboxId;
-
-public class MailboxIdRegistrationKey implements RegistrationKey {
-    public static class Factory implements RegistrationKey.Factory {
-        private final MailboxId.Factory mailboxIdFactory;
-
-        @Inject
-        public Factory(MailboxId.Factory mailboxIdFactory) {
-            this.mailboxIdFactory = mailboxIdFactory;
-        }
-
-        @Override
-        public Class<? extends RegistrationKey> forClass() {
-            return MailboxIdRegistrationKey.class;
-        }
-
-        @Override
-        public RegistrationKey fromString(String asString) {
-            return new MailboxIdRegistrationKey(mailboxIdFactory.fromString(asString));
-        }
-    }
-
-    private final MailboxId mailboxId;
-
-    public MailboxIdRegistrationKey(MailboxId mailboxId) {
-        this.mailboxId = mailboxId;
-    }
-
-    public MailboxId getMailboxId() {
-        return mailboxId;
-    }
-
-    @Override
-    public String asString() {
-        return mailboxId.serialize();
-    }
-
-    @Override
-    public final boolean equals(Object o) {
-        if (o instanceof MailboxIdRegistrationKey) {
-            MailboxIdRegistrationKey that = (MailboxIdRegistrationKey) o;
-
-            return Objects.equals(this.mailboxId, that.mailboxId);
-        }
-        return false;
-    }
-
-    @Override
-    public final int hashCode() {
-        return Objects.hash(mailboxId);
-    }
-}
diff --git a/mailbox/api/src/main/java/org/apache/james/mailbox/events/MessageMoveEvent.java b/mailbox/api/src/main/java/org/apache/james/mailbox/events/MessageMoveEvent.java
deleted file mode 100644
index 69173d2..0000000
--- a/mailbox/api/src/main/java/org/apache/james/mailbox/events/MessageMoveEvent.java
+++ /dev/null
@@ -1,154 +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.mailbox.events;
-
-import java.util.Collection;
-import java.util.Objects;
-import java.util.Optional;
-
-import org.apache.james.core.Username;
-import org.apache.james.events.Event;
-import org.apache.james.mailbox.MailboxSession;
-import org.apache.james.mailbox.model.MailboxId;
-import org.apache.james.mailbox.model.MessageId;
-import org.apache.james.mailbox.model.MessageMoves;
-
-import com.google.common.annotations.VisibleForTesting;
-import com.google.common.base.Preconditions;
-import com.google.common.collect.ImmutableList;
-
-public class MessageMoveEvent implements Event {
-
-    public static Builder builder() {
-        return new Builder();
-    }
-
-    public static class Builder {
-        private ImmutableList.Builder<MessageId> messageIds;
-        private Username username;
-        private MessageMoves messageMoves;
-        private Optional<EventId> eventId;
-
-        private Builder() {
-            messageIds = ImmutableList.builder();
-            eventId = Optional.empty();
-        }
-
-        public Builder session(MailboxSession session) {
-            this.username = session.getUser();
-            return this;
-        }
-
-        public Builder user(Username username) {
-            this.username = username;
-            return this;
-        }
-
-        public Builder messageMoves(MessageMoves messageMoves) {
-            this.messageMoves = messageMoves;
-            return this;
-        }
-
-        public Builder messageId(MessageId messageId) {
-            this.messageIds.add(messageId);
-            return this;
-        }
-
-        public Builder eventId(EventId eventId) {
-            this.eventId = Optional.of(eventId);
-            return this;
-        }
-
-        public Builder messageId(Iterable<MessageId> messageIds) {
-            this.messageIds.addAll(messageIds);
-            return this;
-        }
-
-        public MessageMoveEvent build() {
-            Preconditions.checkNotNull(username, "'user' is mandatory");
-            Preconditions.checkNotNull(messageMoves, "'messageMoves' is mandatory");
-
-            return new MessageMoveEvent(eventId.orElse(EventId.random()), username, messageMoves, messageIds.build());
-        }
-    }
-
-    private final EventId eventId;
-    private final Username username;
-    private final MessageMoves messageMoves;
-    private final Collection<MessageId> messageIds;
-
-    @VisibleForTesting
-    MessageMoveEvent(EventId eventId, Username username, MessageMoves messageMoves, Collection<MessageId> messageIds) {
-        this.eventId = eventId;
-        this.username = username;
-        this.messageMoves = messageMoves;
-        this.messageIds = messageIds;
-    }
-
-    @Override
-    public boolean isNoop() {
-        return messageIds.isEmpty();
-    }
-
-    public Collection<MessageId> getMessageIds() {
-        return messageIds;
-    }
-
-    @Override
-    public EventId getEventId() {
-        return eventId;
-    }
-
-    @Override
-    public Username getUsername() {
-        return username;
-    }
-
-    public MessageMoves getMessageMoves() {
-        return messageMoves;
-    }
-
-    public boolean isMoveTo(MailboxId mailboxId) {
-        return messageMoves.addedMailboxIds()
-                .contains(mailboxId);
-    }
-
-    public boolean isMoveFrom(MailboxId mailboxId) {
-        return messageMoves.removedMailboxIds()
-                .contains(mailboxId);
-    }
-
-    @Override
-    public final boolean equals(Object o) {
-        if (o instanceof MessageMoveEvent) {
-            MessageMoveEvent that = (MessageMoveEvent) o;
-
-            return Objects.equals(this.eventId, that.eventId)
-                && Objects.equals(this.username, that.username)
-                && Objects.equals(this.messageMoves, that.messageMoves)
-                && Objects.equals(this.messageIds, that.messageIds);
-        }
-        return false;
-    }
-
-    @Override
-    public final int hashCode() {
-        return Objects.hash(eventId, username, messageMoves, messageIds);
-    }
-}
diff --git a/mailbox/api/src/main/java/org/apache/james/mailbox/events/RetryBackoffConfiguration.java b/mailbox/api/src/main/java/org/apache/james/mailbox/events/RetryBackoffConfiguration.java
deleted file mode 100644
index f90a4d4..0000000
--- a/mailbox/api/src/main/java/org/apache/james/mailbox/events/RetryBackoffConfiguration.java
+++ /dev/null
@@ -1,125 +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.mailbox.events;
-
-import java.time.Duration;
-import java.util.Objects;
-
-import com.google.common.base.MoreObjects;
-import com.google.common.base.Preconditions;
-
-public class RetryBackoffConfiguration {
-
-    @FunctionalInterface
-    public interface RequireMaxRetries {
-        RequireFirstBackoff maxRetries(int maxRetries);
-    }
-
-    @FunctionalInterface
-    public interface RequireFirstBackoff {
-        RequireJitterFactor firstBackoff(Duration firstBackoff);
-    }
-
-    @FunctionalInterface
-    public interface RequireJitterFactor {
-        ReadyToBuild jitterFactor(double jitterFactor);
-    }
-
-    public static class ReadyToBuild {
-        private final int maxRetries;
-        private final Duration firstBackoff;
-        private final double jitterFactor;
-
-        private ReadyToBuild(int maxRetries, Duration firstBackoff, double jitterFactor) {
-            this.maxRetries = maxRetries;
-            this.firstBackoff = firstBackoff;
-            this.jitterFactor = jitterFactor;
-        }
-
-        public RetryBackoffConfiguration build() {
-            return new RetryBackoffConfiguration(maxRetries, firstBackoff, jitterFactor);
-        }
-    }
-
-    public static RequireMaxRetries builder() {
-        return maxRetries -> firstBackoff -> jitterFactor -> new ReadyToBuild(maxRetries, firstBackoff, jitterFactor);
-    }
-
-    static final double DEFAULT_JITTER_FACTOR = 0.5;
-    static final int DEFAULT_MAX_RETRIES = 8;
-    static final Duration DEFAULT_FIRST_BACKOFF = Duration.ofMillis(100);
-    public static final RetryBackoffConfiguration DEFAULT = new RetryBackoffConfiguration(
-        DEFAULT_MAX_RETRIES,
-        DEFAULT_FIRST_BACKOFF,
-        DEFAULT_JITTER_FACTOR);
-
-    private final int maxRetries;
-    private final Duration firstBackoff;
-    private final double jitterFactor;
-
-    private RetryBackoffConfiguration(int maxRetries, Duration firstBackoff, double jitterFactor) {
-        Preconditions.checkArgument(!firstBackoff.isNegative(), "firstBackoff is not allowed to be negative");
-        Preconditions.checkArgument(maxRetries >= 0, "maxRetries is not allowed to be negative");
-        Preconditions.checkArgument(jitterFactor >= 0 && jitterFactor <= 1.0, "jitterFactor is not " +
-            "allowed to be negative or greater than 1");
-
-        this.maxRetries = maxRetries;
-        this.firstBackoff = firstBackoff;
-        this.jitterFactor = jitterFactor;
-    }
-
-    public int getMaxRetries() {
-        return maxRetries;
-    }
-
-    public Duration getFirstBackoff() {
-        return firstBackoff;
-    }
-
-    public double getJitterFactor() {
-        return jitterFactor;
-    }
-
-    @Override
-    public final boolean equals(Object o) {
-        if (o instanceof RetryBackoffConfiguration) {
-            RetryBackoffConfiguration that = (RetryBackoffConfiguration) o;
-
-            return Objects.equals(this.maxRetries, that.maxRetries)
-                && Objects.equals(this.jitterFactor, that.jitterFactor)
-                && Objects.equals(this.firstBackoff, that.firstBackoff);
-        }
-        return false;
-    }
-
-    @Override
-    public final int hashCode() {
-        return Objects.hash(maxRetries, firstBackoff, jitterFactor);
-    }
-
-    @Override
-    public String toString() {
-        return MoreObjects.toStringHelper(this)
-            .add("maxRetries", maxRetries)
-            .add("firstBackoff", firstBackoff)
-            .add("jitterFactor", jitterFactor)
-            .toString();
-    }
-}
diff --git a/mailbox/api/src/test/java/org/apache/james/mailbox/EventTest.java b/mailbox/api/src/test/java/org/apache/james/mailbox/EventTest.java
index c25f7df..1d36cd7 100644
--- a/mailbox/api/src/test/java/org/apache/james/mailbox/EventTest.java
+++ b/mailbox/api/src/test/java/org/apache/james/mailbox/EventTest.java
@@ -28,7 +28,7 @@ import javax.mail.Flags;
 
 import org.apache.james.core.Username;
 import org.apache.james.events.Event;
-import org.apache.james.mailbox.events.MailboxEvents.Added;
+import org.apache.james.events.MailboxEvents.Added;
 import org.apache.james.mailbox.model.MailboxPath;
 import org.apache.james.mailbox.model.MessageMetaData;
 import org.apache.james.mailbox.model.TestId;
diff --git a/mailbox/api/src/test/java/org/apache/james/mailbox/MailboxListenerTest.java b/mailbox/api/src/test/java/org/apache/james/mailbox/MailboxListenerTest.java
index 13fa417..5ff940d 100644
--- a/mailbox/api/src/test/java/org/apache/james/mailbox/MailboxListenerTest.java
+++ b/mailbox/api/src/test/java/org/apache/james/mailbox/MailboxListenerTest.java
@@ -34,15 +34,15 @@ import org.apache.james.core.quota.QuotaCountUsage;
 import org.apache.james.core.quota.QuotaSizeLimit;
 import org.apache.james.core.quota.QuotaSizeUsage;
 import org.apache.james.events.Event;
+import org.apache.james.events.MailboxEvents.Added;
+import org.apache.james.events.MailboxEvents.Expunged;
+import org.apache.james.events.MailboxEvents.FlagsUpdated;
+import org.apache.james.events.MailboxEvents.MailboxACLUpdated;
+import org.apache.james.events.MailboxEvents.MailboxAdded;
+import org.apache.james.events.MailboxEvents.MailboxDeletion;
+import org.apache.james.events.MailboxEvents.MailboxRenamed;
+import org.apache.james.events.MailboxEvents.QuotaUsageUpdatedEvent;
 import org.apache.james.mailbox.acl.ACLDiff;
-import org.apache.james.mailbox.events.MailboxEvents.Added;
-import org.apache.james.mailbox.events.MailboxEvents.Expunged;
-import org.apache.james.mailbox.events.MailboxEvents.FlagsUpdated;
-import org.apache.james.mailbox.events.MailboxEvents.MailboxACLUpdated;
-import org.apache.james.mailbox.events.MailboxEvents.MailboxAdded;
-import org.apache.james.mailbox.events.MailboxEvents.MailboxDeletion;
-import org.apache.james.mailbox.events.MailboxEvents.MailboxRenamed;
-import org.apache.james.mailbox.events.MailboxEvents.QuotaUsageUpdatedEvent;
 import org.apache.james.mailbox.model.MailboxACL;
 import org.apache.james.mailbox.model.MailboxPath;
 import org.apache.james.mailbox.model.MessageMetaData;
diff --git a/mailbox/api/src/test/java/org/apache/james/mailbox/MailboxManagerStressContract.java b/mailbox/api/src/test/java/org/apache/james/mailbox/MailboxManagerStressContract.java
index d8667e2..bd95fd3 100644
--- a/mailbox/api/src/test/java/org/apache/james/mailbox/MailboxManagerStressContract.java
+++ b/mailbox/api/src/test/java/org/apache/james/mailbox/MailboxManagerStressContract.java
@@ -33,8 +33,8 @@ import java.util.concurrent.atomic.AtomicBoolean;
 
 import org.apache.james.core.Username;
 import org.apache.james.events.EventBus;
-import org.apache.james.mailbox.events.MailboxEvents.Added;
-import org.apache.james.mailbox.events.MailboxIdRegistrationKey;
+import org.apache.james.events.MailboxEvents.Added;
+import org.apache.james.events.MailboxIdRegistrationKey;
 import org.apache.james.mailbox.exception.MailboxException;
 import org.apache.james.mailbox.model.ComposedMessageId;
 import org.apache.james.mailbox.model.MailboxId;
diff --git a/mailbox/api/src/test/java/org/apache/james/mailbox/MailboxManagerTest.java b/mailbox/api/src/test/java/org/apache/james/mailbox/MailboxManagerTest.java
index 7a23c69..03c5a46 100644
--- a/mailbox/api/src/test/java/org/apache/james/mailbox/MailboxManagerTest.java
+++ b/mailbox/api/src/test/java/org/apache/james/mailbox/MailboxManagerTest.java
@@ -47,17 +47,17 @@ import org.apache.james.core.quota.QuotaCountUsage;
 import org.apache.james.core.quota.QuotaSizeLimit;
 import org.apache.james.core.quota.QuotaSizeUsage;
 import org.apache.james.events.EventBus;
+import org.apache.james.events.MailboxEvents.Added;
+import org.apache.james.events.MailboxEvents.Expunged;
+import org.apache.james.events.MailboxEvents.FlagsUpdated;
+import org.apache.james.events.MailboxEvents.MailboxAdded;
+import org.apache.james.events.MailboxEvents.MailboxDeletion;
+import org.apache.james.events.MailboxEvents.QuotaUsageUpdatedEvent;
+import org.apache.james.events.MailboxIdRegistrationKey;
+import org.apache.james.events.MessageMoveEvent;
 import org.apache.james.mailbox.MailboxManager.MailboxCapabilities;
 import org.apache.james.mailbox.MailboxManager.MailboxRenamedResult;
 import org.apache.james.mailbox.MessageManager.AppendCommand;
-import org.apache.james.mailbox.events.MailboxEvents.Added;
-import org.apache.james.mailbox.events.MailboxEvents.Expunged;
-import org.apache.james.mailbox.events.MailboxEvents.FlagsUpdated;
-import org.apache.james.mailbox.events.MailboxEvents.MailboxAdded;
-import org.apache.james.mailbox.events.MailboxEvents.MailboxDeletion;
-import org.apache.james.mailbox.events.MailboxEvents.QuotaUsageUpdatedEvent;
-import org.apache.james.mailbox.events.MailboxIdRegistrationKey;
-import org.apache.james.mailbox.events.MessageMoveEvent;
 import org.apache.james.mailbox.exception.AnnotationException;
 import org.apache.james.mailbox.exception.HasEmptyMailboxNameInHierarchyException;
 import org.apache.james.mailbox.exception.InboxAlreadyCreated;
diff --git a/mailbox/api/src/test/java/org/apache/james/mailbox/MessageMoveEventTest.java b/mailbox/api/src/test/java/org/apache/james/mailbox/MessageMoveEventTest.java
index 0069e62..73859f4 100644
--- a/mailbox/api/src/test/java/org/apache/james/mailbox/MessageMoveEventTest.java
+++ b/mailbox/api/src/test/java/org/apache/james/mailbox/MessageMoveEventTest.java
@@ -22,7 +22,7 @@ import static org.assertj.core.api.Assertions.assertThat;
 import static org.assertj.core.api.Assertions.assertThatThrownBy;
 
 import org.apache.james.core.Username;
-import org.apache.james.mailbox.events.MessageMoveEvent;
+import org.apache.james.events.MessageMoveEvent;
 import org.apache.james.mailbox.model.MessageMoves;
 import org.apache.james.mailbox.model.TestId;
 import org.apache.james.mailbox.model.TestMessageId;
diff --git a/mailbox/api/src/test/java/org/apache/james/mailbox/events/ErrorHandlingContract.java b/mailbox/api/src/test/java/org/apache/james/mailbox/events/ErrorHandlingContract.java
deleted file mode 100644
index 226f1bb..0000000
--- a/mailbox/api/src/test/java/org/apache/james/mailbox/events/ErrorHandlingContract.java
+++ /dev/null
@@ -1,367 +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.mailbox.events;
-
-import static org.apache.james.mailbox.events.EventBusTestFixture.DEFAULT_FIRST_BACKOFF;
-import static org.apache.james.mailbox.events.EventBusTestFixture.EVENT;
-import static org.apache.james.mailbox.events.EventBusTestFixture.EVENT_2;
-import static org.apache.james.mailbox.events.EventBusTestFixture.EVENT_ID;
-import static org.apache.james.mailbox.events.EventBusTestFixture.GROUP_A;
-import static org.apache.james.mailbox.events.EventBusTestFixture.KEY_1;
-import static org.apache.james.mailbox.events.EventBusTestFixture.NO_KEYS;
-import static org.apache.james.mailbox.events.EventBusTestFixture.RETRY_BACKOFF_CONFIGURATION;
-import static org.assertj.core.api.Assertions.assertThat;
-import static org.mockito.Mockito.doThrow;
-import static org.mockito.Mockito.spy;
-
-import java.time.Instant;
-import java.util.ArrayList;
-import java.util.List;
-import java.util.concurrent.TimeUnit;
-import java.util.concurrent.atomic.AtomicBoolean;
-
-import org.apache.james.events.Event;
-import org.apache.james.events.EventDeadLetters;
-import org.apache.james.events.EventListener;
-import org.apache.james.mailbox.util.EventCollector;
-import org.assertj.core.api.SoftAssertions;
-import org.junit.jupiter.api.Disabled;
-import org.junit.jupiter.api.Test;
-
-import com.google.common.collect.ImmutableSet;
-
-import reactor.core.publisher.Mono;
-
-interface ErrorHandlingContract extends EventBusContract {
-
-    class ThrowingListener implements EventListener {
-        private final List<Instant> timeElapsed;
-
-        private ThrowingListener() {
-            timeElapsed = new ArrayList<>();
-        }
-
-        @Override
-        public boolean isHandling(Event event) {
-            return true;
-        }
-
-        @Override
-        public void event(Event event) {
-            timeElapsed.add(Instant.now());
-            throw new RuntimeException("throw to trigger reactor retry");
-        }
-
-        public int executionCount() {
-            return timeElapsed.size();
-        }
-    }
-
-    EventDeadLetters deadLetter();
-
-    default EventCollector eventCollector() {
-        return spy(new EventCollector());
-    }
-
-    default ThrowingListener throwingListener() {
-        return new ThrowingListener();
-    }
-
-    @Test
-    default void retryingIsNotAppliedForKeyRegistrations() {
-        EventCollector eventCollector = eventCollector();
-
-        doThrow(new RuntimeException())
-            .when(eventCollector).event(EVENT);
-
-        Mono.from(eventBus().register(eventCollector, KEY_1)).block();
-        eventBus().dispatch(EVENT, ImmutableSet.of(KEY_1)).block();
-
-        assertThat(eventCollector.getEvents())
-            .isEmpty();
-    }
-
-    @Test
-    default void listenerShouldReceiveWhenFailsLessThanMaxRetries() {
-        EventCollector eventCollector = eventCollector();
-
-        doThrow(new RuntimeException())
-            .doThrow(new RuntimeException())
-            .doCallRealMethod()
-            .when(eventCollector).event(EVENT);
-
-        eventBus().register(eventCollector, GROUP_A);
-        eventBus().dispatch(EVENT, NO_KEYS).block();
-
-        getSpeedProfile().shortWaitCondition()
-            .untilAsserted(() -> assertThat(eventCollector.getEvents()).hasSize(1));
-    }
-
-    @Test
-    default void listenerShouldReceiveWhenFailsEqualsMaxRetries() {
-        EventCollector eventCollector = eventCollector();
-        //do throw  RetryBackoffConfiguration.DEFAULT.DEFAULT_MAX_RETRIES
-        doThrow(new RuntimeException())
-            .doThrow(new RuntimeException())
-            .doThrow(new RuntimeException())
-            .doCallRealMethod()
-            .when(eventCollector).event(EVENT);
-
-        eventBus().register(eventCollector, GROUP_A);
-        eventBus().dispatch(EVENT, NO_KEYS).block();
-
-        getSpeedProfile().longWaitCondition()
-            .untilAsserted(() -> assertThat(eventCollector.getEvents()).hasSize(1));
-    }
-
-    @Test
-    default void listenerShouldNotReceiveWhenFailsGreaterThanMaxRetries() throws Exception {
-        EventCollector eventCollector = eventCollector();
-
-        //do throw  RetryBackoffConfiguration.DEFAULT.DEFAULT_MAX_RETRIES + 1 times
-        doThrow(new RuntimeException())
-            .doThrow(new RuntimeException())
-            .doThrow(new RuntimeException())
-            .doThrow(new RuntimeException())
-            .doThrow(new RuntimeException())
-            .doThrow(new RuntimeException())
-            .doThrow(new RuntimeException())
-            .doThrow(new RuntimeException())
-            .doThrow(new RuntimeException())
-            .doCallRealMethod()
-            .when(eventCollector).event(EVENT);
-
-        eventBus().register(eventCollector, GROUP_A);
-        eventBus().dispatch(EVENT, NO_KEYS).block();
-
-        TimeUnit.SECONDS.sleep(1);
-        assertThat(eventCollector.getEvents())
-            .isEmpty();
-    }
-
-    @Test
-    default void exceedingMaxRetriesShouldStopConsumingFailedEvent() throws Exception {
-        ThrowingListener throwingListener = throwingListener();
-
-        eventBus().register(throwingListener, GROUP_A);
-        eventBus().dispatch(EVENT, NO_KEYS).block();
-
-        getSpeedProfile().shortWaitCondition()
-            .untilAsserted(() -> assertThat(throwingListener.executionCount()).isEqualTo(4));
-        Thread.sleep(getSpeedProfile().getShortWaitTime().toMillis());
-
-        assertThat(throwingListener.executionCount())
-            .isEqualTo(4);
-    }
-
-    @Test
-    default void retriesBackOffShouldDelayByExponentialGrowth() {
-        ThrowingListener throwingListener = throwingListener();
-
-        eventBus().register(throwingListener, GROUP_A);
-        eventBus().dispatch(EVENT, NO_KEYS).block();
-
-        getSpeedProfile().shortWaitCondition()
-            .untilAsserted(() -> assertThat(throwingListener.executionCount()).isEqualTo(4));
-        SoftAssertions.assertSoftly(softly -> {
-            List<Instant> timeElapsed = throwingListener.timeElapsed;
-            softly.assertThat(timeElapsed).hasSize(RETRY_BACKOFF_CONFIGURATION.getMaxRetries() + 1);
-
-            long minFirstDelayAfter = DEFAULT_FIRST_BACKOFF.toMillis(); // first backOff
-            long minSecondDelayAfter = DEFAULT_FIRST_BACKOFF.toMillis() / 2; // first_backOff * jitter factor (first_backOff * 0.5)
-            long minThirdDelayAfter = DEFAULT_FIRST_BACKOFF.toMillis(); // first_backOff * jitter factor (first_backOff * 1)
-
-            softly.assertThat(timeElapsed.get(1))
-                .isAfterOrEqualTo(timeElapsed.get(0).plusMillis(minFirstDelayAfter));
-
-            softly.assertThat(timeElapsed.get(2))
-                .isAfterOrEqualTo(timeElapsed.get(1).plusMillis(minSecondDelayAfter));
-
-            softly.assertThat(timeElapsed.get(3))
-                .isAfterOrEqualTo(timeElapsed.get(2).plusMillis(minThirdDelayAfter));
-        });
-    }
-
-    @Test
-    default void retryingListenerCallingDispatchShouldNotFail() {
-        AtomicBoolean firstExecution = new AtomicBoolean(true);
-        AtomicBoolean successfulRetry = new AtomicBoolean(false);
-        EventListener listener = event -> {
-            if (event.getEventId().equals(EVENT_ID)) {
-                if (firstExecution.get()) {
-                    firstExecution.set(false);
-                    throw new RuntimeException();
-                }
-                eventBus().dispatch(EVENT_2, NO_KEYS).block();
-                successfulRetry.set(true);
-            }
-        };
-
-        eventBus().register(listener, GROUP_A);
-        eventBus().dispatch(EVENT, NO_KEYS).block();
-
-        getSpeedProfile().shortWaitCondition().until(successfulRetry::get);
-    }
-
-    @Test
-    default void deadLettersIsNotAppliedForKeyRegistrations() throws Exception {
-        EventCollector eventCollector = eventCollector();
-
-        //do throw  RetryBackoffConfiguration.DEFAULT.DEFAULT_MAX_RETRIES + 1 times
-        doThrow(new RuntimeException())
-            .doThrow(new RuntimeException())
-            .doThrow(new RuntimeException())
-            .doThrow(new RuntimeException())
-            .doThrow(new RuntimeException())
-            .doThrow(new RuntimeException())
-            .doThrow(new RuntimeException())
-            .doThrow(new RuntimeException())
-            .doThrow(new RuntimeException())
-            .doCallRealMethod()
-            .when(eventCollector).event(EVENT);
-
-        Mono.from(eventBus().register(eventCollector, KEY_1)).block();
-        eventBus().dispatch(EVENT, ImmutableSet.of(KEY_1)).block();
-
-        TimeUnit.SECONDS.sleep(1);
-        SoftAssertions.assertSoftly(softly -> {
-            softly.assertThat(eventCollector.getEvents()).isEmpty();
-            softly.assertThat(deadLetter().groupsWithFailedEvents().toIterable())
-                .isEmpty();
-        });
-    }
-
-    @Test
-    default void deadLetterShouldNotStoreWhenFailsLessThanMaxRetries() {
-        EventCollector eventCollector = eventCollector();
-
-        doThrow(new RuntimeException())
-            .doThrow(new RuntimeException())
-            .doCallRealMethod()
-            .when(eventCollector).event(EVENT);
-
-        eventBus().register(eventCollector, new EventBusTestFixture.GroupA());
-        eventBus().dispatch(EVENT, NO_KEYS).block();
-
-        getSpeedProfile().shortWaitCondition()
-            .untilAsserted(() -> assertThat(eventCollector.getEvents()).hasSize(1));
-
-        assertThat(deadLetter().groupsWithFailedEvents().toIterable())
-            .isEmpty();
-    }
-
-    @Test
-    default void deadLetterShouldStoreWhenDispatchFailsGreaterThanMaxRetries() {
-        EventCollector eventCollector = eventCollector();
-        //do throw  RetryBackoffConfiguration.DEFAULT.DEFAULT_MAX_RETRIES + 1 times
-        doThrow(new RuntimeException())
-            .doThrow(new RuntimeException())
-            .doThrow(new RuntimeException())
-            .doThrow(new RuntimeException())
-            .doThrow(new RuntimeException())
-            .doThrow(new RuntimeException())
-            .doThrow(new RuntimeException())
-            .doThrow(new RuntimeException())
-            .doThrow(new RuntimeException())
-            .doCallRealMethod()
-            .when(eventCollector).event(EVENT);
-
-        eventBus().register(eventCollector, GROUP_A);
-        eventBus().dispatch(EVENT, NO_KEYS).block();
-
-        getSpeedProfile().longWaitCondition()
-            .untilAsserted(() -> assertThat(deadLetter().failedIds(GROUP_A)
-                .flatMap(insertionId -> deadLetter().failedEvent(GROUP_A, insertionId))
-                .toIterable())
-            .containsOnly(EVENT));
-        assertThat(eventCollector.getEvents())
-            .isEmpty();
-    }
-
-    @Test
-    default void deadLetterShouldStoreWhenRedeliverFailsGreaterThanMaxRetries() {
-        EventCollector eventCollector = eventCollector();
-
-        //do throw  RetryBackoffConfiguration.DEFAULT.DEFAULT_MAX_RETRIES + 1 times
-        doThrow(new RuntimeException())
-            .doThrow(new RuntimeException())
-            .doThrow(new RuntimeException())
-            .doThrow(new RuntimeException())
-            .doThrow(new RuntimeException())
-            .doThrow(new RuntimeException())
-            .doThrow(new RuntimeException())
-            .doThrow(new RuntimeException())
-            .doThrow(new RuntimeException())
-            .doCallRealMethod()
-            .when(eventCollector).event(EVENT);
-
-        eventBus().register(eventCollector, GROUP_A);
-        eventBus().reDeliver(GROUP_A, EVENT).block();
-
-        getSpeedProfile().longWaitCondition()
-            .untilAsserted(() ->
-                assertThat(
-                        deadLetter()
-                            .failedIds(GROUP_A)
-                            .flatMap(insertionId -> deadLetter().failedEvent(GROUP_A, insertionId))
-                            .toIterable())
-                .containsOnly(EVENT));
-        assertThat(eventCollector.getEvents()).isEmpty();
-    }
-
-    @Disabled("JAMES-2907 redeliver should work as initial dispatch")
-    @Test
-    default void retryShouldDeliverAsManyTimesAsInitialDeliveryAttempt() {
-        EventCollector eventCollector = eventCollector();
-
-        //do throw  RetryBackoffConfiguration.DEFAULT.DEFAULT_MAX_RETRIES + 1 times
-        doThrow(new RuntimeException())
-            .doThrow(new RuntimeException())
-            .doThrow(new RuntimeException())
-            .doThrow(new RuntimeException())
-            .doThrow(new RuntimeException())
-            .doThrow(new RuntimeException())
-            .doThrow(new RuntimeException())
-            .doThrow(new RuntimeException())
-            .doThrow(new RuntimeException())
-            .doCallRealMethod()
-            .when(eventCollector).event(EVENT);
-
-        eventBus().register(eventCollector, GROUP_A);
-        eventBus().reDeliver(GROUP_A, EVENT).block();
-
-        getSpeedProfile().longWaitCondition()
-            .untilAsserted(() -> assertThat(eventCollector.getEvents()).isNotEmpty());
-    }
-
-    @Test
-    default void redeliverShouldNotSendEventsToKeyListeners() {
-        EventCollector eventCollector = eventCollector();
-        EventCollector eventCollector2 = eventCollector();
-
-        eventBus().register(eventCollector, GROUP_A);
-        Mono.from(eventBus().register(eventCollector2, KEY_1)).block();
-        eventBus().reDeliver(GROUP_A, EVENT).block();
-
-        getSpeedProfile().longWaitCondition()
-            .untilAsserted(() -> assertThat(eventCollector.getEvents()).hasSize(1));
-        assertThat(eventCollector2.getEvents()).isEmpty();
-    }
-}
diff --git a/mailbox/api/src/test/java/org/apache/james/mailbox/events/EventBusConcurrentTestContract.java b/mailbox/api/src/test/java/org/apache/james/mailbox/events/EventBusConcurrentTestContract.java
deleted file mode 100644
index 8b73023..0000000
--- a/mailbox/api/src/test/java/org/apache/james/mailbox/events/EventBusConcurrentTestContract.java
+++ /dev/null
@@ -1,240 +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.mailbox.events;
-
-import static org.apache.james.mailbox.events.EventBusTestFixture.EVENT;
-import static org.apache.james.mailbox.events.EventBusTestFixture.KEY_1;
-import static org.apache.james.mailbox.events.EventBusTestFixture.KEY_2;
-import static org.apache.james.mailbox.events.EventBusTestFixture.KEY_3;
-import static org.apache.james.mailbox.events.EventBusTestFixture.NO_KEYS;
-import static org.apache.james.mailbox.events.EventDeadLettersContract.GROUP_A;
-import static org.assertj.core.api.Assertions.assertThat;
-import static org.awaitility.Awaitility.await;
-
-import java.time.Duration;
-import java.util.Set;
-import java.util.concurrent.TimeUnit;
-
-import org.apache.james.events.EventBus;
-import org.apache.james.events.RegistrationKey;
-import org.apache.james.util.concurrency.ConcurrentTestRunner;
-import org.awaitility.core.ConditionFactory;
-import org.junit.jupiter.api.Test;
-
-import com.google.common.collect.ImmutableList;
-import com.google.common.collect.ImmutableSet;
-
-import reactor.core.publisher.Mono;
-
-public interface EventBusConcurrentTestContract {
-
-    Duration FIVE_SECONDS = Duration.ofSeconds(5);
-    ConditionFactory AWAIT_CONDITION = await().timeout(new org.awaitility.Duration(5, TimeUnit.SECONDS));
-
-    int THREAD_COUNT = 10;
-    int OPERATION_COUNT = 30;
-    int TOTAL_DISPATCH_OPERATIONS = THREAD_COUNT * OPERATION_COUNT;
-
-    Set<RegistrationKey> ALL_KEYS = ImmutableSet.of(KEY_1, KEY_2, KEY_3);
-
-    static EventBusTestFixture.EventListenerCountingSuccessfulExecution newCountingListener() {
-        return new EventBusTestFixture.EventListenerCountingSuccessfulExecution();
-    }
-
-    static int totalEventsReceived(ImmutableList<EventBusTestFixture.EventListenerCountingSuccessfulExecution> allListeners) {
-        return allListeners.stream()
-            .mapToInt(EventBusTestFixture.EventListenerCountingSuccessfulExecution::numberOfEventCalls)
-            .sum();
-    }
-
-    interface SingleEventBusConcurrentContract extends EventBusContract {
-
-        @Test
-        default void concurrentDispatchGroupShouldDeliverAllEventsToListenersWithSingleEventBus() throws Exception {
-            EventBusTestFixture.EventListenerCountingSuccessfulExecution countingListener1 = newCountingListener();
-            EventBusTestFixture.EventListenerCountingSuccessfulExecution countingListener2 = newCountingListener();
-            EventBusTestFixture.EventListenerCountingSuccessfulExecution countingListener3 = newCountingListener();
-
-            eventBus().register(countingListener1, new EventBusTestFixture.GroupA());
-            eventBus().register(countingListener2, new EventBusTestFixture.GroupB());
-            eventBus().register(countingListener3, new EventBusTestFixture.GroupC());
-            int totalGlobalRegistrations = 3; // GroupA + GroupB + GroupC
-
-            ConcurrentTestRunner.builder()
-                .operation((threadNumber, operationNumber) -> eventBus().dispatch(EVENT, NO_KEYS).block())
-                .threadCount(THREAD_COUNT)
-                .operationCount(OPERATION_COUNT)
-                .runSuccessfullyWithin(FIVE_SECONDS);
-
-            AWAIT_CONDITION.untilAsserted(() ->
-                assertThat(totalEventsReceived(ImmutableList.of(countingListener1, countingListener2, countingListener3)))
-                    .isEqualTo(totalGlobalRegistrations * TOTAL_DISPATCH_OPERATIONS));
-        }
-
-        @Test
-        default void concurrentDispatchKeyShouldDeliverAllEventsToListenersWithSingleEventBus() throws Exception {
-            EventBusTestFixture.EventListenerCountingSuccessfulExecution countingListener1 = newCountingListener();
-            EventBusTestFixture.EventListenerCountingSuccessfulExecution countingListener2 = newCountingListener();
-            EventBusTestFixture.EventListenerCountingSuccessfulExecution countingListener3 = newCountingListener();
-            Mono.from(eventBus().register(countingListener1, KEY_1)).block();
-            Mono.from(eventBus().register(countingListener2, KEY_2)).block();
-            Mono.from(eventBus().register(countingListener3, KEY_3)).block();
-
-            int totalKeyListenerRegistrations = 3; // KEY1 + KEY2 + KEY3
-            int totalEventBus = 1;
-
-            ConcurrentTestRunner.builder()
-                .operation((threadNumber, operationNumber) -> eventBus().dispatch(EVENT, ALL_KEYS).block())
-                .threadCount(THREAD_COUNT)
-                .operationCount(OPERATION_COUNT)
-                .runSuccessfullyWithin(FIVE_SECONDS);
-
-            AWAIT_CONDITION.untilAsserted(() ->
-                assertThat(totalEventsReceived(ImmutableList.of(countingListener1, countingListener2, countingListener3)))
-                    .isEqualTo(totalKeyListenerRegistrations * totalEventBus * TOTAL_DISPATCH_OPERATIONS));
-        }
-
-        @Test
-        default void concurrentDispatchShouldDeliverAllEventsToListenersWithSingleEventBus() throws Exception {
-            EventBusTestFixture.EventListenerCountingSuccessfulExecution countingListener1 = newCountingListener();
-            EventBusTestFixture.EventListenerCountingSuccessfulExecution countingListener2 = newCountingListener();
-            EventBusTestFixture.EventListenerCountingSuccessfulExecution countingListener3 = newCountingListener();
-
-            eventBus().register(countingListener1, new EventBusTestFixture.GroupA());
-            eventBus().register(countingListener2, new EventBusTestFixture.GroupB());
-            eventBus().register(countingListener3, new EventBusTestFixture.GroupC());
-
-            int totalGlobalRegistrations = 3; // GroupA + GroupB + GroupC
-            int totalEventDeliveredGlobally = totalGlobalRegistrations * TOTAL_DISPATCH_OPERATIONS;
-
-            Mono.from(eventBus().register(countingListener1, KEY_1)).block();
-            Mono.from(eventBus().register(countingListener2, KEY_2)).block();
-            Mono.from(eventBus().register(countingListener3, KEY_3)).block();
-            int totalKeyListenerRegistrations = 3; // KEY1 + KEY2 + KEY3
-            int totalEventDeliveredByKeys = totalKeyListenerRegistrations * TOTAL_DISPATCH_OPERATIONS;
-
-            ConcurrentTestRunner.builder()
-                .operation((threadNumber, operationNumber) -> eventBus().dispatch(EVENT, ALL_KEYS).block())
-                .threadCount(THREAD_COUNT)
-                .operationCount(OPERATION_COUNT)
-                .runSuccessfullyWithin(FIVE_SECONDS);
-
-            AWAIT_CONDITION.untilAsserted(() ->
-                assertThat(totalEventsReceived(ImmutableList.of(countingListener1, countingListener2, countingListener3)))
-                    .isEqualTo(totalEventDeliveredGlobally + totalEventDeliveredByKeys));
-        }
-    }
-
-    interface MultiEventBusConcurrentContract extends EventBusContract.MultipleEventBusContract {
-
-        EventBus eventBus3();
-
-        @Test
-        default void concurrentDispatchGroupShouldDeliverAllEventsToListenersWithMultipleEventBus() throws Exception {
-            EventBusTestFixture.EventListenerCountingSuccessfulExecution countingListener1 = newCountingListener();
-            EventBusTestFixture.EventListenerCountingSuccessfulExecution countingListener2 = newCountingListener();
-            EventBusTestFixture.EventListenerCountingSuccessfulExecution countingListener3 = newCountingListener();
-
-            eventBus().register(countingListener1, new EventBusTestFixture.GroupA());
-            eventBus().register(countingListener2, new EventBusTestFixture.GroupB());
-            eventBus().register(countingListener3, new EventBusTestFixture.GroupC());
-
-            eventBus2().register(countingListener1, new EventBusTestFixture.GroupA());
-            eventBus2().register(countingListener2, new EventBusTestFixture.GroupB());
-            eventBus2().register(countingListener3, new EventBusTestFixture.GroupC());
-
-            int totalGlobalRegistrations = 3; // GroupA + GroupB + GroupC
-
-            ConcurrentTestRunner.builder()
-                .operation((threadNumber, operationNumber) -> eventBus().dispatch(EVENT, NO_KEYS).block())
-                .threadCount(THREAD_COUNT)
-                .operationCount(OPERATION_COUNT)
-                .runSuccessfullyWithin(FIVE_SECONDS);
-
-            AWAIT_CONDITION.untilAsserted(() ->
-                assertThat(totalEventsReceived(ImmutableList.of(countingListener1, countingListener2, countingListener3)))
-                    .isEqualTo(totalGlobalRegistrations * TOTAL_DISPATCH_OPERATIONS));
-        }
-
-        @Test
-        default void concurrentDispatchKeyShouldDeliverAllEventsToListenersWithMultipleEventBus() throws Exception {
-            EventBusTestFixture.EventListenerCountingSuccessfulExecution countingListener1 = newCountingListener();
-            EventBusTestFixture.EventListenerCountingSuccessfulExecution countingListener2 = newCountingListener();
-            EventBusTestFixture.EventListenerCountingSuccessfulExecution countingListener3 = newCountingListener();
-
-            Mono.from(eventBus().register(countingListener1, KEY_1)).block();
-            Mono.from(eventBus().register(countingListener2, KEY_2)).block();
-            Mono.from(eventBus().register(countingListener3, KEY_3)).block();
-
-            Mono.from(eventBus2().register(countingListener1, KEY_1)).block();
-            Mono.from(eventBus2().register(countingListener2, KEY_2)).block();
-            Mono.from(eventBus2().register(countingListener3, KEY_3)).block();
-
-            int totalKeyListenerRegistrations = 3; // KEY1 + KEY2 + KEY3
-            int totalEventBus = 2; // eventBus1 + eventBus2
-
-            ConcurrentTestRunner.builder()
-                .operation((threadNumber, operationNumber) -> eventBus().dispatch(EVENT, ALL_KEYS).block())
-                .threadCount(THREAD_COUNT)
-                .operationCount(OPERATION_COUNT)
-                .runSuccessfullyWithin(FIVE_SECONDS);
-
-            AWAIT_CONDITION.untilAsserted(() ->
-                assertThat(totalEventsReceived(ImmutableList.of(countingListener1, countingListener2, countingListener3)))
-                    .isEqualTo(totalKeyListenerRegistrations * totalEventBus * TOTAL_DISPATCH_OPERATIONS));
-        }
-
-        @Test
-        default void concurrentDispatchShouldDeliverAllEventsToListenersWithMultipleEventBus() throws Exception {
-            EventBusTestFixture.EventListenerCountingSuccessfulExecution countingListener1 = newCountingListener();
-            EventBusTestFixture.EventListenerCountingSuccessfulExecution countingListener2 = newCountingListener();
-            EventBusTestFixture.EventListenerCountingSuccessfulExecution countingListener3 = newCountingListener();
-
-            eventBus2().register(countingListener1, GROUP_A);
-            eventBus2().register(countingListener2, new EventBusTestFixture.GroupB());
-            eventBus2().register(countingListener3, new EventBusTestFixture.GroupC());
-            int totalGlobalRegistrations = 3; // GroupA + GroupB + GroupC
-            int totalEventDeliveredGlobally = totalGlobalRegistrations * TOTAL_DISPATCH_OPERATIONS;
-
-            Mono.from(eventBus().register(countingListener1, KEY_1)).block();
-            Mono.from(eventBus().register(countingListener2, KEY_2)).block();
-
-            Mono.from(eventBus2().register(countingListener1, KEY_1)).block();
-            Mono.from(eventBus2().register(countingListener2, KEY_2)).block();
-
-            Mono.from(eventBus3().register(countingListener3, KEY_1)).block();
-            Mono.from(eventBus3().register(countingListener3, KEY_2)).block();
-
-            int totalKeyListenerRegistrations = 2; // KEY1 + KEY2
-            int totalEventBus = 3; // eventBus1 + eventBus2 + eventBus3
-            int totalEventDeliveredByKeys = totalKeyListenerRegistrations * totalEventBus * TOTAL_DISPATCH_OPERATIONS;
-
-            ConcurrentTestRunner.builder()
-                .operation((threadNumber, operationNumber) -> eventBus().dispatch(EVENT, ALL_KEYS).block())
-                .threadCount(THREAD_COUNT)
-                .operationCount(OPERATION_COUNT)
-                .runSuccessfullyWithin(FIVE_SECONDS);
-
-            AWAIT_CONDITION.untilAsserted(() ->
-                assertThat(totalEventsReceived(ImmutableList.of(countingListener1, countingListener2, countingListener3)))
-                    .isEqualTo(totalEventDeliveredGlobally + totalEventDeliveredByKeys));
-        }
-    }
-}
diff --git a/mailbox/api/src/test/java/org/apache/james/mailbox/events/EventBusContract.java b/mailbox/api/src/test/java/org/apache/james/mailbox/events/EventBusContract.java
deleted file mode 100644
index c94c5a3..0000000
--- a/mailbox/api/src/test/java/org/apache/james/mailbox/events/EventBusContract.java
+++ /dev/null
@@ -1,73 +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.mailbox.events;
-
-import static org.awaitility.Awaitility.await;
-
-import java.time.Duration;
-import java.util.concurrent.TimeUnit;
-
-import org.apache.james.events.EventBus;
-import org.awaitility.core.ConditionFactory;
-
-public interface EventBusContract {
-
-    enum EnvironmentSpeedProfile {
-        SLOW(Duration.ofSeconds(2), Duration.ofSeconds(10)),
-        FAST(Duration.ofMillis(200), Duration.ofSeconds(5));
-
-        private final Duration shortWaitTime;
-        private final Duration longWaitTime;
-
-        EnvironmentSpeedProfile(Duration shortWaitTime, Duration longWaitTime) {
-            this.shortWaitTime = shortWaitTime;
-            this.longWaitTime = longWaitTime;
-        }
-
-        public Duration getShortWaitTime() {
-            return shortWaitTime;
-        }
-
-        public Duration getLongWaitTime() {
-            return longWaitTime;
-        }
-
-        public ConditionFactory shortWaitCondition() {
-            return await().pollDelay(org.awaitility.Duration.ZERO)
-                .pollInterval(org.awaitility.Duration.ONE_HUNDRED_MILLISECONDS)
-                .timeout(new org.awaitility.Duration(this.getShortWaitTime().toMillis(), TimeUnit.MILLISECONDS));
-        }
-
-        public ConditionFactory longWaitCondition() {
-            return await().pollDelay(org.awaitility.Duration.ZERO)
-                .pollInterval(org.awaitility.Duration.ONE_HUNDRED_MILLISECONDS)
-                .timeout(new org.awaitility.Duration(this.getLongWaitTime().toMillis(), TimeUnit.MILLISECONDS));
-        }
-    }
-
-    EnvironmentSpeedProfile getSpeedProfile();
-
-    interface MultipleEventBusContract extends EventBusContract {
-
-        EventBus eventBus2();
-    }
-
-    EventBus eventBus();
-}
\ No newline at end of file
diff --git a/mailbox/api/src/test/java/org/apache/james/mailbox/events/EventBusTestFixture.java b/mailbox/api/src/test/java/org/apache/james/mailbox/events/EventBusTestFixture.java
deleted file mode 100644
index dccec61..0000000
--- a/mailbox/api/src/test/java/org/apache/james/mailbox/events/EventBusTestFixture.java
+++ /dev/null
@@ -1,145 +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.mailbox.events;
-
-import static org.apache.james.mailbox.events.RetryBackoffConfiguration.DEFAULT_JITTER_FACTOR;
-import static org.mockito.ArgumentMatchers.any;
-import static org.mockito.Mockito.mock;
-import static org.mockito.Mockito.when;
-
-import java.util.List;
-import java.util.concurrent.atomic.AtomicInteger;
-
-import org.apache.james.core.Username;
-import org.apache.james.events.Event;
-import org.apache.james.events.EventListener;
-import org.apache.james.events.Group;
-import org.apache.james.events.RegistrationKey;
-import org.apache.james.mailbox.MailboxSession;
-import org.apache.james.mailbox.events.MailboxEvents.MailboxAdded;
-import org.apache.james.mailbox.events.MailboxEvents.MailboxEvent;
-import org.apache.james.mailbox.events.MailboxEvents.MailboxRenamed;
-import org.apache.james.mailbox.model.MailboxConstants;
-import org.apache.james.mailbox.model.MailboxId;
-import org.apache.james.mailbox.model.MailboxPath;
-import org.apache.james.mailbox.model.TestId;
-
-import com.google.common.collect.ImmutableList;
-import com.google.common.collect.ImmutableSet;
-
-public interface EventBusTestFixture {
-
-    class EventListenerCountingSuccessfulExecution implements EventListener {
-        private final AtomicInteger calls = new AtomicInteger(0);
-
-        @Override
-        public boolean isHandling(Event event) {
-            return true;
-        }
-
-        @Override
-        public void event(Event event) {
-            calls.incrementAndGet();
-        }
-
-        public int numberOfEventCalls() {
-            return calls.get();
-        }
-    }
-
-    class EventMatcherThrowingListener extends EventListenerCountingSuccessfulExecution {
-        private final ImmutableSet<Event> eventsCauseThrowing;
-
-        EventMatcherThrowingListener(ImmutableSet<Event> eventsCauseThrowing) {
-            this.eventsCauseThrowing = eventsCauseThrowing;
-        }
-
-        @Override
-        public boolean isHandling(Event event) {
-            return true;
-        }
-
-        @Override
-        public void event(Event event) {
-            if (eventsCauseThrowing.contains(event)) {
-                throw new RuntimeException("event triggers throwing");
-            }
-            super.event(event);
-        }
-    }
-
-    class GroupA extends Group {
-
-    }
-
-    class GroupB extends Group {
-
-    }
-
-    class GroupC extends Group {
-
-    }
-
-    MailboxSession.SessionId SESSION_ID = MailboxSession.SessionId.of(42);
-    Username USERNAME = Username.of("user");
-    MailboxPath MAILBOX_PATH = new MailboxPath(MailboxConstants.USER_NAMESPACE, USERNAME, "mailboxName");
-    TestId TEST_ID = TestId.of(18);
-    Event.EventId EVENT_ID = Event.EventId.of("6e0dd59d-660e-4d9b-b22f-0354479f47b4");
-    Event.EventId EVENT_ID_2 = Event.EventId.of("5a7a9f3f-5f03-44be-b457-a51e93760645");
-    MailboxEvent EVENT = new MailboxAdded(SESSION_ID, USERNAME, MAILBOX_PATH, TEST_ID, EVENT_ID);
-    MailboxEvent EVENT_2 = new MailboxAdded(SESSION_ID, USERNAME, MAILBOX_PATH, TEST_ID, EVENT_ID_2);
-    MailboxRenamed EVENT_UNSUPPORTED_BY_LISTENER = new MailboxRenamed(SESSION_ID, USERNAME, MAILBOX_PATH, TEST_ID, MAILBOX_PATH, EVENT_ID_2);
-
-    java.time.Duration ONE_SECOND = java.time.Duration.ofSeconds(1);
-    java.time.Duration FIVE_HUNDRED_MS = java.time.Duration.ofMillis(500);
-    MailboxId ID_1 = TEST_ID;
-    MailboxId ID_2 = TestId.of(24);
-    MailboxId ID_3 = TestId.of(36);
-    ImmutableSet<RegistrationKey> NO_KEYS = ImmutableSet.of();
-    MailboxIdRegistrationKey KEY_1 = new MailboxIdRegistrationKey(ID_1);
-    MailboxIdRegistrationKey KEY_2 = new MailboxIdRegistrationKey(ID_2);
-    MailboxIdRegistrationKey KEY_3 = new MailboxIdRegistrationKey(ID_3);
-    GroupA GROUP_A = new GroupA();
-    GroupB GROUP_B = new GroupB();
-    GroupC GROUP_C = new GroupC();
-    List<Group> ALL_GROUPS = ImmutableList.of(GROUP_A, GROUP_B, GROUP_C);
-
-    java.time.Duration DEFAULT_FIRST_BACKOFF = java.time.Duration.ofMillis(5);
-    //Retry backoff configuration for testing with a shorter first backoff to accommodate the shorter retry interval in tests
-    RetryBackoffConfiguration RETRY_BACKOFF_CONFIGURATION = RetryBackoffConfiguration.builder()
-        .maxRetries(3)
-        .firstBackoff(DEFAULT_FIRST_BACKOFF)
-        .jitterFactor(DEFAULT_JITTER_FACTOR)
-        .build();
-
-    static EventListener newListener() {
-        EventListener listener = mock(EventListener.class);
-        when(listener.getExecutionMode()).thenReturn(EventListener.ExecutionMode.SYNCHRONOUS);
-        when(listener.isHandling(any(MailboxAdded.class))).thenReturn(true);
-        return listener;
-    }
-
-    static EventListener newAsyncListener() {
-        EventListener listener = mock(EventListener.class);
-        when(listener.getExecutionMode()).thenReturn(EventListener.ExecutionMode.ASYNCHRONOUS);
-        when(listener.isHandling(any(MailboxAdded.class))).thenReturn(true);
-        return listener;
-    }
-}
diff --git a/mailbox/api/src/test/java/org/apache/james/mailbox/events/EventDeadLettersContract.java b/mailbox/api/src/test/java/org/apache/james/mailbox/events/EventDeadLettersContract.java
deleted file mode 100644
index 1e8f003..0000000
--- a/mailbox/api/src/test/java/org/apache/james/mailbox/events/EventDeadLettersContract.java
+++ /dev/null
@@ -1,493 +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.mailbox.events;
-
-import static org.assertj.core.api.Assertions.assertThat;
-import static org.assertj.core.api.Assertions.assertThatCode;
-import static org.assertj.core.api.Assertions.assertThatThrownBy;
-
-import java.time.Duration;
-import java.util.List;
-import java.util.concurrent.ConcurrentHashMap;
-import java.util.function.Function;
-import java.util.stream.IntStream;
-import java.util.stream.Stream;
-
-import org.apache.james.core.Username;
-import org.apache.james.events.Event;
-import org.apache.james.events.EventDeadLetters;
-import org.apache.james.events.Group;
-import org.apache.james.mailbox.MailboxSession;
-import org.apache.james.mailbox.events.MailboxEvents.MailboxAdded;
-import org.apache.james.mailbox.model.MailboxConstants;
-import org.apache.james.mailbox.model.MailboxPath;
-import org.apache.james.mailbox.model.TestId;
-import org.apache.james.util.concurrency.ConcurrentTestRunner;
-import org.junit.jupiter.api.Test;
-
-import com.github.steveash.guavate.Guavate;
-import com.google.common.collect.HashMultimap;
-import com.google.common.collect.ImmutableList;
-import com.google.common.collect.ImmutableMap;
-import com.google.common.collect.Multimap;
-import com.google.common.collect.Multimaps;
-
-interface EventDeadLettersContract {
-
-    class Group0 extends Group {
-
-    }
-
-    class Group1 extends Group {
-
-    }
-
-    class Group2 extends Group {
-
-    }
-
-    class Group3 extends Group {
-
-    }
-
-    class Group4 extends Group {
-
-    }
-
-    class Group5 extends Group {
-
-    }
-
-    class Group6 extends Group {
-
-    }
-
-    class Group7 extends Group {
-
-    }
-
-    class Group8 extends Group {
-
-    }
-
-    class Group9 extends Group {
-
-    }
-
-    static ImmutableMap<Integer, Group> concurrentGroups() {
-        return IntStream.range(0, CONCURRENT_GROUPS.size()).boxed()
-            .collect(Guavate.toImmutableMap(Function.identity(), CONCURRENT_GROUPS::get));
-    }
-
-    static Event event(Event.EventId eventId) {
-        return new MailboxAdded(SESSION_ID, USERNAME, MAILBOX_PATH, MAILBOX_ID, eventId);
-    }
-
-    List<Group> CONCURRENT_GROUPS = ImmutableList.of(new Group0(), new Group1(), new Group2(), new Group3(), new Group4(), new Group5(),
-        new Group6(), new Group7(), new Group8(), new Group9());
-    Duration RUN_SUCCESSFULLY_IN = Duration.ofSeconds(5);
-    int THREAD_COUNT = 10;
-    int OPERATION_COUNT = 50;
-
-    Username USERNAME = Username.of("user");
-    MailboxPath MAILBOX_PATH = new MailboxPath(MailboxConstants.USER_NAMESPACE, USERNAME, "mailboxName");
-    MailboxSession.SessionId SESSION_ID = MailboxSession.SessionId.of(235);
-    TestId MAILBOX_ID = TestId.of(563);
-    Event.EventId EVENT_ID_1 = Event.EventId.of("6e0dd59d-660e-4d9b-b22f-0354479f47b4");
-    Event.EventId EVENT_ID_2 = Event.EventId.of("6e0dd59d-660e-4d9b-b22f-0354479f47b5");
-    Event.EventId EVENT_ID_3 = Event.EventId.of("6e0dd59d-660e-4d9b-b22f-0354479f47b6");
-    MailboxAdded EVENT_1 = new MailboxAdded(SESSION_ID, USERNAME, MAILBOX_PATH, MAILBOX_ID, EVENT_ID_1);
-    MailboxAdded EVENT_2 = new MailboxAdded(SESSION_ID, USERNAME, MAILBOX_PATH, MAILBOX_ID, EVENT_ID_2);
-    MailboxAdded EVENT_3 = new MailboxAdded(SESSION_ID, USERNAME, MAILBOX_PATH, MAILBOX_ID, EVENT_ID_3);
-    EventDeadLetters.InsertionId INSERTION_ID_1 = EventDeadLetters.InsertionId.of("6e0dd59d-660e-4d9b-b22f-0354479f47b7");
-    EventDeadLetters.InsertionId INSERTION_ID_2 = EventDeadLetters.InsertionId.of("6e0dd59d-660e-4d9b-b22f-0354479f47b8");
-    EventDeadLetters.InsertionId INSERTION_ID_3 = EventDeadLetters.InsertionId.of("6e0dd59d-660e-4d9b-b22f-0354479f47b9");
-
-    Group GROUP_A = new EventBusTestFixture.GroupA();
-    Group GROUP_B = new EventBusTestFixture.GroupB();
-    Group NULL_GROUP = null;
-    Event NULL_EVENT = null;
-    EventDeadLetters.InsertionId NULL_INSERTION_ID = null;
-
-    EventDeadLetters eventDeadLetters();
-
-    default Stream<EventDeadLetters.InsertionId> allInsertionIds() {
-        EventDeadLetters eventDeadLetters = eventDeadLetters();
-
-        return eventDeadLetters.groupsWithFailedEvents()
-            .flatMap(eventDeadLetters::failedIds)
-            .toStream();
-    }
-
-    interface StoreContract extends EventDeadLettersContract {
-
-        @Test
-        default void storeShouldThrowWhenNullGroup() {
-            EventDeadLetters eventDeadLetters = eventDeadLetters();
-
-            assertThatThrownBy(() -> eventDeadLetters.store(NULL_GROUP, EVENT_1))
-                .isInstanceOf(IllegalArgumentException.class);
-        }
-
-        @Test
-        default void storeShouldThrowWhenNullEvent() {
-            EventDeadLetters eventDeadLetters = eventDeadLetters();
-
-            assertThatThrownBy(() -> eventDeadLetters.store(GROUP_A, NULL_EVENT))
-                .isInstanceOf(IllegalArgumentException.class);
-        }
-
-        @Test
-        default void storeShouldThrowWhenBothGroupAndEventAndInsertionIdAreNull() {
-            EventDeadLetters eventDeadLetters = eventDeadLetters();
-
-            assertThatThrownBy(() -> eventDeadLetters.store(NULL_GROUP, NULL_EVENT))
-                .isInstanceOf(IllegalArgumentException.class);
-        }
-
-        @Test
-        default void storeShouldStoreGroupWithCorrespondingEvent() {
-            EventDeadLetters eventDeadLetters = eventDeadLetters();
-
-            EventDeadLetters.InsertionId insertionId = eventDeadLetters.store(GROUP_A, EVENT_1).block();
-            assertThat(eventDeadLetters.failedEvent(GROUP_A, insertionId).block())
-                .isEqualTo(EVENT_1);
-        }
-
-        @Test
-        default void storeShouldKeepConsistencyWhenConcurrentStore() throws Exception {
-            EventDeadLetters eventDeadLetters = eventDeadLetters();
-
-            ImmutableMap<Integer, Group> groups = concurrentGroups();
-            Multimap<Integer, EventDeadLetters.InsertionId> storedInsertionIds = Multimaps.synchronizedSetMultimap(HashMultimap.create());
-
-            ConcurrentTestRunner.builder()
-                .operation((threadNumber, step) -> {
-                    Event.EventId eventId = Event.EventId.random();
-                    EventDeadLetters.InsertionId insertionId = eventDeadLetters.store(groups.get(threadNumber), event(eventId)).block();
-                    storedInsertionIds.put(threadNumber, insertionId);
-                })
-                .threadCount(THREAD_COUNT)
-                .operationCount(OPERATION_COUNT)
-                .runSuccessfullyWithin(RUN_SUCCESSFULLY_IN);
-
-            groups.forEach((groupId, group) -> {
-                Group storedGroup = groups.get(groupId);
-                assertThat(eventDeadLetters.failedIds(storedGroup).collectList().block())
-                    .hasSameElementsAs(storedInsertionIds.get(groupId));
-            });
-        }
-    }
-
-    interface RemoveContract extends EventDeadLettersContract {
-
-        @Test
-        default void removeShouldThrowWhenGroupIsNull() {
-            EventDeadLetters eventDeadLetters = eventDeadLetters();
-
-            assertThatThrownBy(() -> eventDeadLetters.remove(NULL_GROUP, INSERTION_ID_1))
-                .isInstanceOf(IllegalArgumentException.class);
-        }
-
-        @Test
-        default void removeShouldThrowWhenInsertionIdIsNull() {
-            EventDeadLetters eventDeadLetters = eventDeadLetters();
-
-            assertThatThrownBy(() -> eventDeadLetters.remove(GROUP_A, NULL_INSERTION_ID))
-                .isInstanceOf(IllegalArgumentException.class);
-        }
-
-        @Test
-        default void removeShouldThrowWhenBothGroupAndInsertionIdAreNull() {
-            EventDeadLetters eventDeadLetters = eventDeadLetters();
-
-            assertThatThrownBy(() -> eventDeadLetters.remove(NULL_GROUP, NULL_INSERTION_ID))
-                .isInstanceOf(IllegalArgumentException.class);
-        }
-
-        @Test
-        default void removeShouldRemoveMatched() {
-            EventDeadLetters eventDeadLetters = eventDeadLetters();
-
-            eventDeadLetters.store(GROUP_A, EVENT_1).block();
-            eventDeadLetters.store(GROUP_A, EVENT_2).block();
-
-            eventDeadLetters.remove(GROUP_A, INSERTION_ID_1).block();
-
-            assertThat(eventDeadLetters.failedEvent(GROUP_A, INSERTION_ID_1).block())
-                .isNull();
-        }
-
-        @Test
-        default void removeShouldKeepNonMatched() {
-            EventDeadLetters eventDeadLetters = eventDeadLetters();
-
-            EventDeadLetters.InsertionId insertionId1 = eventDeadLetters.store(GROUP_A, EVENT_1).block();
-            EventDeadLetters.InsertionId insertionId2 = eventDeadLetters.store(GROUP_A, EVENT_2).block();
-            EventDeadLetters.InsertionId insertionId3 = eventDeadLetters.store(GROUP_A, EVENT_3).block();
-
-            eventDeadLetters.remove(GROUP_A, insertionId1).block();
-
-            assertThat(eventDeadLetters.failedIds(GROUP_A).toStream())
-                .containsOnly(insertionId2, insertionId3);
-        }
-
-        @Test
-        default void removeShouldNotThrowWhenNoInsertionIdMatched() {
-            EventDeadLetters eventDeadLetters = eventDeadLetters();
-
-            eventDeadLetters.store(GROUP_A, EVENT_1).block();
-
-            assertThatCode(() -> eventDeadLetters.remove(GROUP_A, INSERTION_ID_2).block())
-                .doesNotThrowAnyException();
-        }
-
-        @Test
-        default void removeShouldNotThrowWhenNoGroupMatched() {
-            EventDeadLetters eventDeadLetters = eventDeadLetters();
-
-            eventDeadLetters.store(GROUP_A, EVENT_1).block();
-
-            assertThatCode(() -> eventDeadLetters.remove(GROUP_B, INSERTION_ID_1).block())
-                .doesNotThrowAnyException();
-        }
-
-        @Test
-        default void removeShouldKeepConsistencyWhenConcurrentRemove() throws Exception {
-            EventDeadLetters eventDeadLetters = eventDeadLetters();
-
-            ImmutableMap<Integer, Group> groups = concurrentGroups();
-            ConcurrentHashMap<Integer, EventDeadLetters.InsertionId> storedInsertionIds = new ConcurrentHashMap<>();
-
-            ConcurrentTestRunner.builder()
-                .operation((threadNumber, step) -> {
-                    int operationIndex = threadNumber * OPERATION_COUNT + step;
-                    Event.EventId eventId = Event.EventId.random();
-                    EventDeadLetters.InsertionId insertionId = eventDeadLetters.store(groups.get(threadNumber), event(eventId)).block();
-                    storedInsertionIds.put(operationIndex, insertionId);
-                })
-                .threadCount(THREAD_COUNT)
-                .operationCount(OPERATION_COUNT)
-                .runSuccessfullyWithin(RUN_SUCCESSFULLY_IN);
-
-            ConcurrentTestRunner.builder()
-                .operation((threadNumber, step) -> {
-                    int operationIndex = threadNumber * OPERATION_COUNT + step;
-                    eventDeadLetters.remove(groups.get(threadNumber), storedInsertionIds.get(operationIndex))
-                        .block();
-                })
-                .threadCount(THREAD_COUNT)
-                .operationCount(OPERATION_COUNT)
-                .runSuccessfullyWithin(RUN_SUCCESSFULLY_IN);
-
-            assertThat(allInsertionIds())
-                .isEmpty();
-        }
-    }
-
-    interface FailedEventContract extends EventDeadLettersContract {
-
-        @Test
-        default void failedEventShouldThrowWhenGroupIsNull() {
-            EventDeadLetters eventDeadLetters = eventDeadLetters();
-
-            assertThatThrownBy(() -> eventDeadLetters.failedEvent(NULL_GROUP, INSERTION_ID_1))
-                .isInstanceOf(IllegalArgumentException.class);
-        }
-
-        @Test
-        default void failedEventShouldThrowWhenInsertionIdIsNull() {
-            EventDeadLetters eventDeadLetters = eventDeadLetters();
-
-            assertThatThrownBy(() -> eventDeadLetters.failedEvent(GROUP_A, NULL_INSERTION_ID))
-                .isInstanceOf(IllegalArgumentException.class);
-        }
-
-        @Test
-        default void failedEventShouldThrowWhenBothGroupAndInsertionIdAreNull() {
-            EventDeadLetters eventDeadLetters = eventDeadLetters();
-
-            assertThatThrownBy(() -> eventDeadLetters.failedEvent(NULL_GROUP, NULL_INSERTION_ID))
-                .isInstanceOf(IllegalArgumentException.class);
-        }
-
-        @Test
-        default void failedEventShouldReturnEmptyWhenNotFound() {
-            EventDeadLetters eventDeadLetters = eventDeadLetters();
-
-            eventDeadLetters.store(GROUP_A, EVENT_1).block();
-            eventDeadLetters.store(GROUP_A, EVENT_2).block();
-
-            assertThat(eventDeadLetters.failedEvent(GROUP_A, INSERTION_ID_3).block())
-                .isNull();
-        }
-
-        @Test
-        default void failedEventShouldReturnEventWhenContains() {
-            EventDeadLetters eventDeadLetters = eventDeadLetters();
-
-            EventDeadLetters.InsertionId insertionId = eventDeadLetters.store(GROUP_A, EVENT_1).block();
-            eventDeadLetters.store(GROUP_A, EVENT_2).block();
-
-            assertThat(eventDeadLetters.failedEvent(GROUP_A, insertionId).block())
-                .isEqualTo(EVENT_1);
-        }
-
-        @Test
-        default void failedEventShouldNotRemoveEvent() {
-            EventDeadLetters eventDeadLetters = eventDeadLetters();
-
-            EventDeadLetters.InsertionId insertionId1 = eventDeadLetters.store(GROUP_A, EVENT_1).block();
-            EventDeadLetters.InsertionId insertionId2 = eventDeadLetters.store(GROUP_A, EVENT_2).block();
-            EventDeadLetters.InsertionId insertionId3 = eventDeadLetters.store(GROUP_A, EVENT_3).block();
-
-            eventDeadLetters.failedEvent(GROUP_A, insertionId1).block();
-
-            assertThat(allInsertionIds())
-                .containsOnly(insertionId1, insertionId2, insertionId3);
-        }
-
-        @Test
-        default void failedEventShouldNotThrowWhenNoGroupMatched() {
-            EventDeadLetters eventDeadLetters = eventDeadLetters();
-
-            EventDeadLetters.InsertionId insertionId = eventDeadLetters.store(GROUP_A, EVENT_1).block();
-
-            assertThatCode(() -> eventDeadLetters.failedEvent(GROUP_B, insertionId).block())
-                .doesNotThrowAnyException();
-        }
-    }
-
-    interface FailedEventsContract extends EventDeadLettersContract {
-
-        @Test
-        default void failedEventsShouldThrowWhenGroupIsNull() {
-            EventDeadLetters eventDeadLetters = eventDeadLetters();
-
-            assertThatThrownBy(() -> eventDeadLetters.failedIds(NULL_GROUP))
-                .isInstanceOf(IllegalArgumentException.class);
-        }
-
-        @Test
-        default void failedEventsByGroupShouldReturnEmptyWhenNonMatch() {
-            EventDeadLetters eventDeadLetters = eventDeadLetters();
-
-            eventDeadLetters.store(GROUP_A, EVENT_1).block();
-            eventDeadLetters.store(GROUP_A, EVENT_2).block();
-            eventDeadLetters.store(GROUP_A, EVENT_3).block();
-
-            assertThat(eventDeadLetters.failedIds(GROUP_B).toStream())
-                .isEmpty();
-        }
-
-        @Test
-        default void failedEventsByGroupShouldReturnAllEventsCorrespondingToGivenGroup() {
-            EventDeadLetters eventDeadLetters = eventDeadLetters();
-
-            EventDeadLetters.InsertionId insertionId = eventDeadLetters.store(GROUP_A, EVENT_1).block();
-            eventDeadLetters.store(GROUP_B, EVENT_2).block();
-            eventDeadLetters.store(GROUP_B, EVENT_3).block();
-
-            assertThat(eventDeadLetters.failedIds(GROUP_A).toStream())
-                .containsOnly(insertionId);
-        }
-
-        @Test
-        default void failedEventsByGroupShouldNotRemoveEvents() {
-            EventDeadLetters eventDeadLetters = eventDeadLetters();
-
-            EventDeadLetters.InsertionId insertionId1 = eventDeadLetters.store(GROUP_A, EVENT_1).block();
-            EventDeadLetters.InsertionId insertionId2 = eventDeadLetters.store(GROUP_A, EVENT_2).block();
-            EventDeadLetters.InsertionId insertionId3 = eventDeadLetters.store(GROUP_B, EVENT_3).block();
-
-            eventDeadLetters.failedIds(GROUP_A).toStream();
-
-            assertThat(allInsertionIds())
-                .containsOnly(insertionId1, insertionId2, insertionId3);
-        }
-    }
-
-    interface GroupsWithFailedEventsContract extends EventDeadLettersContract {
-        @Test
-        default void groupsWithFailedEventsShouldReturnAllStoredGroups() {
-            EventDeadLetters eventDeadLetters = eventDeadLetters();
-            eventDeadLetters.store(GROUP_A, EVENT_1).block();
-            eventDeadLetters.store(GROUP_B, EVENT_1).block();
-
-            assertThat(eventDeadLetters.groupsWithFailedEvents().collectList().block())
-                .containsOnly(GROUP_A, GROUP_B);
-        }
-
-        @Test
-        default void groupsWithFailedEventsShouldReturnEmptyWhenNoStored() {
-            EventDeadLetters eventDeadLetters = eventDeadLetters();
-
-            assertThat(eventDeadLetters.groupsWithFailedEvents().toStream()).isEmpty();
-        }
-    }
-
-    interface ContainEventsContract extends EventDeadLettersContract {
-        @Test
-        default void containEventsShouldReturnFalseOnNothingStored() {
-            EventDeadLetters eventDeadLetters = eventDeadLetters();
-
-            assertThat(eventDeadLetters.containEvents().block()).isFalse();
-        }
-
-        @Test
-        default void containEventsShouldReturnTrueOnStoredEvents() {
-            EventDeadLetters eventDeadLetters = eventDeadLetters();
-            eventDeadLetters.store(GROUP_A, EVENT_1).block();
-
-            assertThat(eventDeadLetters.containEvents().block()).isTrue();
-        }
-
-        @Test
-        default void containEventsShouldReturnFalseWhenRemoveAllStoredEvents() {
-            EventDeadLetters eventDeadLetters = eventDeadLetters();
-            EventDeadLetters.InsertionId insertionId1 = eventDeadLetters().store(GROUP_A, EVENT_1).block();
-            EventDeadLetters.InsertionId insertionId2 = eventDeadLetters().store(GROUP_A, EVENT_2).block();
-
-            assertThat(eventDeadLetters.containEvents().block()).isTrue();
-
-            eventDeadLetters.remove(GROUP_A, insertionId1).block();
-            eventDeadLetters.remove(GROUP_A, insertionId2).block();
-
-            assertThat(eventDeadLetters.containEvents().block()).isFalse();
-        }
-
-        @Test
-        default void containEventsShouldReturnTrueWhenRemoveSomeStoredEvents() {
-            EventDeadLetters eventDeadLetters = eventDeadLetters();
-            EventDeadLetters.InsertionId insertionId1 = eventDeadLetters().store(GROUP_A, EVENT_1).block();
-            eventDeadLetters().store(GROUP_B, EVENT_2).block();
-
-            assertThat(eventDeadLetters.containEvents().block()).isTrue();
-
-            eventDeadLetters.remove(GROUP_A, insertionId1).block();
-
-            assertThat(eventDeadLetters.containEvents().block()).isTrue();
-        }
-    }
-
-    interface AllContracts extends StoreContract, RemoveContract, FailedEventContract, FailedEventsContract, GroupsWithFailedEventsContract, ContainEventsContract {
-
-    }
-}
\ No newline at end of file
diff --git a/mailbox/api/src/test/java/org/apache/james/mailbox/events/EventDeadLettersHealthCheckContract.java b/mailbox/api/src/test/java/org/apache/james/mailbox/events/EventDeadLettersHealthCheckContract.java
deleted file mode 100644
index 4479714..0000000
--- a/mailbox/api/src/test/java/org/apache/james/mailbox/events/EventDeadLettersHealthCheckContract.java
+++ /dev/null
@@ -1,134 +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.mailbox.events;
-
-import static org.assertj.core.api.Assertions.assertThat;
-
-import org.apache.james.core.Username;
-import org.apache.james.core.healthcheck.ComponentName;
-import org.apache.james.core.healthcheck.Result;
-import org.apache.james.events.Event;
-import org.apache.james.events.EventDeadLetters;
-import org.apache.james.events.EventDeadLettersHealthCheck;
-import org.apache.james.events.Group;
-import org.apache.james.mailbox.MailboxSession;
-import org.apache.james.mailbox.events.MailboxEvents.MailboxAdded;
-import org.apache.james.mailbox.model.MailboxConstants;
-import org.apache.james.mailbox.model.MailboxPath;
-import org.apache.james.mailbox.model.TestId;
-import org.junit.jupiter.api.Test;
-
-interface EventDeadLettersHealthCheckContract {
-
-    ComponentName COMPONENT_NAME = new ComponentName("EventDeadLettersHealthCheck");
-    String EXPECTED_DEGRADED_MESSAGE = "EventDeadLetters contain events. This might indicate transient failure on mailbox event processing.";
-
-    Username USERNAME = Username.of("user");
-    MailboxPath MAILBOX_PATH = new MailboxPath(MailboxConstants.USER_NAMESPACE, USERNAME, "mailboxName");
-    MailboxSession.SessionId SESSION_ID = MailboxSession.SessionId.of(235);
-    TestId MAILBOX_ID = TestId.of(563);
-    Event.EventId EVENT_ID_1 = Event.EventId.of("6e0dd59d-660e-4d9b-b22f-0354479f47b4");
-    Event.EventId EVENT_ID_2 = Event.EventId.of("6e0dd59d-660e-4d9b-b22f-0354479f47b5");
-    MailboxAdded EVENT_1 = new MailboxAdded(SESSION_ID, USERNAME, MAILBOX_PATH, MAILBOX_ID, EVENT_ID_1);
-    MailboxAdded EVENT_2 = new MailboxAdded(SESSION_ID, USERNAME, MAILBOX_PATH, MAILBOX_ID, EVENT_ID_2);
-
-    Group GROUP_A = new EventBusTestFixture.GroupA();
-    Group GROUP_B = new EventBusTestFixture.GroupB();
-
-    EventDeadLettersHealthCheck testee();
-
-    EventDeadLetters eventDeadLetters();
-
-    void createErrorWhenDoingHealthCheck();
-
-    void resolveErrorWhenDoingHealthCheck();
-
-    @Test
-    default void checkShouldReturnHealthyWhenEventDeadLetterEmpty() {
-        assertThat(testee().check().block().isHealthy()).isTrue();
-        assertThat(testee().check().block())
-            .isEqualTo(Result.healthy(COMPONENT_NAME));
-    }
-
-    @Test
-    default void checkShouldReturnDegradedWhenEventDeadLetterContainEvent() {
-        eventDeadLetters().store(GROUP_A, EVENT_1).block();
-
-        assertThat(testee().check().block().isDegraded()).isTrue();
-        assertThat(testee().check().block())
-            .isEqualTo(Result.degraded(COMPONENT_NAME, EXPECTED_DEGRADED_MESSAGE));
-    }
-
-    @Test
-    default void checkShouldReturnDegradedWhenEventDeadLetterContainEvents() {
-        eventDeadLetters().store(GROUP_A, EVENT_1).block();
-        eventDeadLetters().store(GROUP_B, EVENT_2).block();
-
-        assertThat(testee().check().block().isDegraded()).isTrue();
-        assertThat(testee().check().block())
-            .isEqualTo(Result.degraded(COMPONENT_NAME, EXPECTED_DEGRADED_MESSAGE));
-    }
-
-    @Test
-    default void checkShouldReturnHealthyWhenRemovedAllEventDeadLetters() {
-        EventDeadLetters.InsertionId insertionId1 = eventDeadLetters().store(GROUP_A, EVENT_1).block();
-        EventDeadLetters.InsertionId insertionId2 = eventDeadLetters().store(GROUP_B, EVENT_2).block();
-
-        assertThat(testee().check().block().isDegraded()).isTrue();
-        assertThat(testee().check().block())
-            .isEqualTo(Result.degraded(COMPONENT_NAME, EXPECTED_DEGRADED_MESSAGE));
-
-        eventDeadLetters().remove(GROUP_A, insertionId1).block();
-        eventDeadLetters().remove(GROUP_B, insertionId2).block();
-
-        assertThat(testee().check().block().isHealthy()).isTrue();
-        assertThat(testee().check().block())
-            .isEqualTo(Result.healthy(COMPONENT_NAME));
-    }
-
-    @Test
-    default void checkShouldReturnDegradedWhenRemovedSomeEventDeadLetters() {
-        EventDeadLetters.InsertionId insertionId1 = eventDeadLetters().store(GROUP_A, EVENT_1).block();
-        eventDeadLetters().store(GROUP_B, EVENT_2).block();
-
-        assertThat(testee().check().block().isDegraded()).isTrue();
-        assertThat(testee().check().block())
-            .isEqualTo(Result.degraded(COMPONENT_NAME, EXPECTED_DEGRADED_MESSAGE));
-
-        eventDeadLetters().remove(GROUP_A, insertionId1).block();
-
-        assertThat(testee().check().block().isDegraded()).isTrue();
-        assertThat(testee().check().block())
-            .isEqualTo(Result.degraded(COMPONENT_NAME, EXPECTED_DEGRADED_MESSAGE));
-    }
-
-    @Test
-    default void checkShouldReturnUnHealthyWhenEventDeadLetterError() {
-        Result actualResult;
-        try {
-            createErrorWhenDoingHealthCheck();
-            actualResult = testee().check().block();
-        } finally {
-            resolveErrorWhenDoingHealthCheck();
-        }
-
-        assertThat(actualResult.isUnHealthy()).isTrue();
-    }
-}
diff --git a/mailbox/api/src/test/java/org/apache/james/mailbox/events/GroupContract.java b/mailbox/api/src/test/java/org/apache/james/mailbox/events/GroupContract.java
deleted file mode 100644
index fb5131d..0000000
--- a/mailbox/api/src/test/java/org/apache/james/mailbox/events/GroupContract.java
+++ /dev/null
@@ -1,504 +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.mailbox.events;
-
-import static org.apache.james.mailbox.events.EventBusTestFixture.EVENT;
-import static org.apache.james.mailbox.events.EventBusTestFixture.EVENT_2;
-import static org.apache.james.mailbox.events.EventBusTestFixture.EVENT_ID;
-import static org.apache.james.mailbox.events.EventBusTestFixture.EVENT_UNSUPPORTED_BY_LISTENER;
-import static org.apache.james.mailbox.events.EventBusTestFixture.FIVE_HUNDRED_MS;
-import static org.apache.james.mailbox.events.EventBusTestFixture.GROUP_A;
-import static org.apache.james.mailbox.events.EventBusTestFixture.GROUP_B;
-import static org.apache.james.mailbox.events.EventBusTestFixture.GROUP_C;
-import static org.apache.james.mailbox.events.EventBusTestFixture.NO_KEYS;
-import static org.apache.james.mailbox.events.EventBusTestFixture.ONE_SECOND;
-import static org.apache.james.mailbox.events.EventBusTestFixture.newListener;
-import static org.assertj.core.api.Assertions.assertThat;
-import static org.assertj.core.api.Assertions.assertThatCode;
-import static org.assertj.core.api.Assertions.assertThatThrownBy;
-import static org.mockito.ArgumentMatchers.any;
-import static org.mockito.Mockito.after;
-import static org.mockito.Mockito.doThrow;
-import static org.mockito.Mockito.mock;
-import static org.mockito.Mockito.timeout;
-import static org.mockito.Mockito.verify;
-import static org.mockito.Mockito.when;
-
-import java.time.Duration;
-import java.util.concurrent.ConcurrentLinkedQueue;
-import java.util.concurrent.CountDownLatch;
-import java.util.concurrent.atomic.AtomicBoolean;
-import java.util.concurrent.atomic.AtomicInteger;
-import java.util.stream.IntStream;
-
-import org.apache.james.core.Username;
-import org.apache.james.events.Event;
-import org.apache.james.events.EventBus;
-import org.apache.james.events.EventListener;
-import org.apache.james.events.GenericGroup;
-import org.apache.james.events.Group;
-import org.apache.james.events.GroupAlreadyRegistered;
-import org.apache.james.events.GroupRegistrationNotFound;
-import org.apache.james.events.Registration;
-import org.apache.james.mailbox.MailboxSession;
-import org.apache.james.mailbox.events.MailboxEvents.Added;
-import org.apache.james.mailbox.model.MailboxPath;
-import org.apache.james.mailbox.model.TestId;
-import org.junit.jupiter.api.Test;
-
-import com.google.common.collect.ImmutableSet;
-import com.google.common.collect.ImmutableSortedMap;
-
-import reactor.core.scheduler.Schedulers;
-
-public interface GroupContract {
-
-    interface SingleEventBusGroupContract extends EventBusContract {
-
-        @Test
-        default void groupDeliveryShouldNotExceedRate() {
-            int eventCount = 50;
-            AtomicInteger nbCalls = new AtomicInteger(0);
-            AtomicInteger finishedExecutions = new AtomicInteger(0);
-            AtomicBoolean rateExceeded = new AtomicBoolean(false);
-
-            eventBus().register(new EventListener.GroupEventListener() {
-                @Override
-                public Group getDefaultGroup() {
-                    return new GenericGroup("group");
-                }
-
-                @Override
-                public boolean isHandling(Event event) {
-                    return true;
-                }
-
-                @Override
-                public void event(Event event) throws Exception {
-                    if (nbCalls.get() - finishedExecutions.get() > EventBus.EXECUTION_RATE) {
-                        rateExceeded.set(true);
-                    }
-                    nbCalls.incrementAndGet();
-                    Thread.sleep(Duration.ofMillis(20).toMillis());
-                    finishedExecutions.incrementAndGet();
-
-                }
-            }, GROUP_A);
-
-            IntStream.range(0, eventCount)
-                .forEach(i -> eventBus().dispatch(EVENT, NO_KEYS).block());
-
-            getSpeedProfile().shortWaitCondition().atMost(org.awaitility.Duration.TEN_MINUTES)
-                .untilAsserted(() -> assertThat(finishedExecutions.get()).isEqualTo(eventCount));
-            assertThat(rateExceeded).isFalse();
-        }
-
-        @Test
-        default void groupNotificationShouldDeliverASingleEventToAllListenersAtTheSameTime() {
-            CountDownLatch countDownLatch = new CountDownLatch(1);
-            try {
-                ConcurrentLinkedQueue<String> threads = new ConcurrentLinkedQueue<>();
-                eventBus().register(new EventListener.GroupEventListener() {
-                    @Override
-                    public Group getDefaultGroup() {
-                        return new GenericGroup("groupA");
-                    }
-
-                    @Override
-                    public void event(Event event) throws Exception {
-                        threads.add(Thread.currentThread().getName());
-                        countDownLatch.await();
-                    }
-                }, GROUP_A);
-                eventBus().register(new EventListener.GroupEventListener() {
-                    @Override
-                    public Group getDefaultGroup() {
-                        return new GenericGroup("groupB");
-                    }
-
-                    @Override
-                    public void event(Event event) throws Exception {
-                        threads.add(Thread.currentThread().getName());
-                        countDownLatch.await();
-                    }
-                }, GROUP_B);
-                eventBus().register(new EventListener.GroupEventListener() {
-                    @Override
-                    public Group getDefaultGroup() {
-                        return new GenericGroup("groupC");
-                    }
-
-                    @Override
-                    public void event(Event event) throws Exception {
-                        threads.add(Thread.currentThread().getName());
-                        countDownLatch.await();
-                    }
-                }, GROUP_C);
-
-                eventBus().dispatch(EVENT, NO_KEYS).subscribeOn(Schedulers.elastic()).subscribe();
-
-
-                getSpeedProfile().shortWaitCondition().atMost(org.awaitility.Duration.TEN_SECONDS)
-                    .untilAsserted(() -> assertThat(threads).hasSize(3));
-                assertThat(threads).doesNotHaveDuplicates();
-            } finally {
-                countDownLatch.countDown();
-            }
-        }
-
-        @Test
-        default void listenersShouldBeAbleToDispatch() {
-            AtomicBoolean successfulRetry = new AtomicBoolean(false);
-            EventListener listener = event -> {
-                if (event.getEventId().equals(EVENT_ID)) {
-                    eventBus().dispatch(EVENT_2, NO_KEYS)
-                        .subscribeOn(Schedulers.elastic())
-                        .block();
-                    successfulRetry.set(true);
-                }
-            };
-
-            eventBus().register(listener, GROUP_A);
-            eventBus().dispatch(EVENT, NO_KEYS).block();
-
-            getSpeedProfile().shortWaitCondition().until(successfulRetry::get);
-        }
-
-        @Test
-        default void registerShouldNotDispatchPastEventsForGroups() throws Exception {
-            EventListener listener = newListener();
-
-            eventBus().dispatch(EVENT, NO_KEYS).block();
-
-            eventBus().register(listener, GROUP_A);
-
-            verify(listener, after(FIVE_HUNDRED_MS.toMillis()).never())
-                .event(any());
-        }
-
-        @Test
-        default void listenerGroupShouldReceiveEvents() throws Exception {
-            EventListener listener = newListener();
-
-            eventBus().register(listener, GROUP_A);
-
-            eventBus().dispatch(EVENT, NO_KEYS).block();
-
-            verify(listener, timeout(ONE_SECOND.toMillis()).times(1)).event(any());
-        }
-
-        @Test
-        default void groupListenersShouldNotReceiveNoopEvents() throws Exception {
-            EventListener listener = newListener();
-
-            eventBus().register(listener, GROUP_A);
-
-            Username bob = Username.of("bob");
-            Added noopEvent = new Added(MailboxSession.SessionId.of(18), bob, MailboxPath.forUser(bob, "mailbox"), TestId.of(58), ImmutableSortedMap.of(), Event.EventId.random());
-            eventBus().dispatch(noopEvent, NO_KEYS).block();
-
-            verify(listener, after(FIVE_HUNDRED_MS.toMillis()).never())
-                .event(any());
-        }
-
-        @Test
-        default void groupListenersShouldReceiveOnlyHandledEvents() throws Exception {
-            EventListener listener = newListener();
-
-            eventBus().register(listener, GROUP_A);
-
-            eventBus().dispatch(EVENT_UNSUPPORTED_BY_LISTENER, NO_KEYS).block();
-
-            verify(listener, after(FIVE_HUNDRED_MS.toMillis()).never())
-                .event(any());
-        }
-
-        @Test
-        default void dispatchShouldNotThrowWhenAGroupListenerFails() throws Exception {
-            EventListener listener = newListener();
-            doThrow(new RuntimeException()).when(listener).event(any());
-
-            eventBus().register(listener, GROUP_A);
-
-            assertThatCode(() -> eventBus().dispatch(EVENT, NO_KEYS).block())
-                .doesNotThrowAnyException();
-        }
-
-        @Test
-        default void eachListenerGroupShouldReceiveEvents() throws Exception {
-            EventListener listener = newListener();
-            EventListener listener2 = newListener();
-            eventBus().register(listener, GROUP_A);
-            eventBus().register(listener2, GROUP_B);
-
-            eventBus().dispatch(EVENT, NO_KEYS).block();
-
-            verify(listener, timeout(ONE_SECOND.toMillis()).times(1)).event(any());
-            verify(listener2, timeout(ONE_SECOND.toMillis()).times(1)).event(any());
-        }
-
-        @Test
-        default void unregisteredGroupListenerShouldNotReceiveEvents() throws Exception {
-            EventListener listener = newListener();
-            Registration registration = eventBus().register(listener, GROUP_A);
-
-            registration.unregister();
-
-            eventBus().dispatch(EVENT, NO_KEYS).block();
-            verify(listener, after(FIVE_HUNDRED_MS.toMillis()).never())
-                .event(any());
-        }
-
-        @Test
-        default void registerShouldThrowWhenAGroupIsAlreadyUsed() {
-            EventListener listener = newListener();
-            EventListener listener2 = newListener();
-
-            eventBus().register(listener, GROUP_A);
-
-            assertThatThrownBy(() -> eventBus().register(listener2, GROUP_A))
-                .isInstanceOf(GroupAlreadyRegistered.class);
-        }
-
-        @Test
-        default void registerShouldNotThrowOnAnUnregisteredGroup() {
-            EventListener listener = newListener();
-            EventListener listener2 = newListener();
-
-            eventBus().register(listener, GROUP_A).unregister();
-
-            assertThatCode(() -> eventBus().register(listener2, GROUP_A))
-                .doesNotThrowAnyException();
-        }
-
-        @Test
-        default void unregisterShouldBeIdempotentForGroups() {
-            EventListener listener = newListener();
-
-            Registration registration = eventBus().register(listener, GROUP_A);
-            registration.unregister();
-
-            assertThatCode(registration::unregister)
-                .doesNotThrowAnyException();
-        }
-
-        @Test
-        default void registerShouldAcceptAlreadyUnregisteredGroups() throws Exception {
-            EventListener listener = newListener();
-
-            eventBus().register(listener, GROUP_A).unregister();
-            eventBus().register(listener, GROUP_A);
-
-            eventBus().dispatch(EVENT, NO_KEYS).block();
-
-            verify(listener, timeout(ONE_SECOND.toMillis()).times(1)).event(any());
-        }
-
-        @Test
-        default void dispatchShouldCallSynchronousListener() throws Exception {
-            EventListener listener = newListener();
-
-            eventBus().register(listener, GROUP_A);
-
-            eventBus().dispatch(EVENT, NO_KEYS).block();
-
-            verify(listener, timeout(ONE_SECOND.toMillis()).times(1)).event(any());
-        }
-
-        @Test
-        default void failingGroupListenersShouldNotAbortGroupDelivery() {
-            EventBusTestFixture.EventListenerCountingSuccessfulExecution listener = new EventBusTestFixture.EventMatcherThrowingListener(ImmutableSet.of(EVENT));
-            eventBus().register(listener, GROUP_A);
-
-            eventBus().dispatch(EVENT, NO_KEYS).block();
-            eventBus().dispatch(EVENT_2, NO_KEYS).block();
-
-            getSpeedProfile().shortWaitCondition()
-                .untilAsserted(() -> assertThat(listener.numberOfEventCalls()).isEqualTo(1));
-        }
-
-        @Test
-        default void allGroupListenersShouldBeExecutedWhenAGroupListenerFails() throws Exception {
-            EventListener listener = newListener();
-
-            EventListener failingListener = mock(EventListener.class);
-            when(failingListener.getExecutionMode()).thenReturn(EventListener.ExecutionMode.SYNCHRONOUS);
-            doThrow(new RuntimeException()).when(failingListener).event(any());
-
-            eventBus().register(failingListener, GROUP_A);
-            eventBus().register(listener, GROUP_B);
-
-            eventBus().dispatch(EVENT, NO_KEYS).block();
-
-            verify(listener, timeout(ONE_SECOND.toMillis()).times(1)).event(any());
-        }
-
-        @Test
-        default void allGroupListenersShouldBeExecutedWhenGenericGroups() throws Exception {
-            EventListener listener1 = newListener();
-            EventListener listener2 = newListener();
-
-            eventBus().register(listener1, new GenericGroup("a"));
-            eventBus().register(listener2, new GenericGroup("b"));
-
-            eventBus().dispatch(EVENT, NO_KEYS).block();
-
-            verify(listener1, timeout(ONE_SECOND.toMillis()).times(1)).event(any());
-            verify(listener2, timeout(ONE_SECOND.toMillis()).times(1)).event(any());
-        }
-
-        @Test
-        default void groupListenerShouldReceiveEventWhenRedeliver() throws Exception {
-            EventListener listener = newListener();
-
-            eventBus().register(listener, GROUP_A);
-
-            eventBus().reDeliver(GROUP_A, EVENT).block();
-
-            verify(listener, timeout(ONE_SECOND.toMillis()).times(1)).event(any());
-        }
-
-        @Test
-        default void redeliverShouldNotThrowWhenAGroupListenerFails() throws Exception {
-            EventListener listener = newListener();
-            doThrow(new RuntimeException()).when(listener).event(any());
-
-            eventBus().register(listener, GROUP_A);
-
-            assertThatCode(() -> eventBus().reDeliver(GROUP_A, EVENT).block())
-                .doesNotThrowAnyException();
-        }
-
-        @Test
-        default void redeliverShouldThrowWhenGroupNotRegistered() {
-            assertThatThrownBy(() -> eventBus().reDeliver(GROUP_A, EVENT).block())
-                .isInstanceOf(GroupRegistrationNotFound.class);
-        }
-
-        @Test
-        default void redeliverShouldThrowAfterGroupIsUnregistered() {
-            EventListener listener = newListener();
-
-            eventBus().register(listener, GROUP_A).unregister();
-
-            assertThatThrownBy(() -> eventBus().reDeliver(GROUP_A, EVENT).block())
-                .isInstanceOf(GroupRegistrationNotFound.class);
-        }
-
-        @Test
-        default void redeliverShouldOnlySendEventToDefinedGroup() throws Exception {
-            EventListener listener = newListener();
-            EventListener listener2 = newListener();
-            eventBus().register(listener, GROUP_A);
-            eventBus().register(listener2, GROUP_B);
-
-            eventBus().reDeliver(GROUP_A, EVENT).block();
-
-            verify(listener, timeout(ONE_SECOND.toMillis()).times(1)).event(any());
-            verify(listener2, after(FIVE_HUNDRED_MS.toMillis()).never()).event(any());
-        }
-
-        @Test
-        default void groupListenersShouldNotReceiveNoopRedeliveredEvents() throws Exception {
-            EventListener listener = newListener();
-
-            eventBus().register(listener, GROUP_A);
-
-            Username bob = Username.of("bob");
-            Added noopEvent = new Added(MailboxSession.SessionId.of(18), bob, MailboxPath.forUser(bob, "mailbox"), TestId.of(58), ImmutableSortedMap.of(), Event.EventId.random());
-            eventBus().reDeliver(GROUP_A, noopEvent).block();
-
-            verify(listener, after(FIVE_HUNDRED_MS.toMillis()).never()).event(any());
-        }
-    }
-
-    interface MultipleEventBusGroupContract extends EventBusContract.MultipleEventBusContract {
-
-        @Test
-        default void groupsDefinedOnlyOnSomeNodesShouldBeNotifiedWhenDispatch() throws Exception {
-            EventListener mailboxListener = newListener();
-
-            eventBus().register(mailboxListener, GROUP_A);
-
-            eventBus2().dispatch(EVENT, NO_KEYS).block();
-
-            verify(mailboxListener, timeout(ONE_SECOND.toMillis()).times(1)).event(any());
-        }
-
-        @Test
-        default void groupsDefinedOnlyOnSomeNodesShouldNotBeNotifiedWhenRedeliver() {
-            EventListener mailboxListener = newListener();
-
-            eventBus().register(mailboxListener, GROUP_A);
-
-            assertThatThrownBy(() -> eventBus2().reDeliver(GROUP_A, EVENT).block())
-                .isInstanceOf(GroupRegistrationNotFound.class);
-        }
-
-        @Test
-        default void groupListenersShouldBeExecutedOnceWhenRedeliverInADistributedEnvironment() throws Exception {
-            EventListener mailboxListener = newListener();
-
-            eventBus().register(mailboxListener, GROUP_A);
-            eventBus2().register(mailboxListener, GROUP_A);
-
-            eventBus2().reDeliver(GROUP_A, EVENT).block();
-
-            verify(mailboxListener, timeout(ONE_SECOND.toMillis()).times(1)).event(any());
-        }
-
-        @Test
-        default void groupListenersShouldBeExecutedOnceInAControlledEnvironment() throws Exception {
-            EventListener mailboxListener = newListener();
-
-            eventBus().register(mailboxListener, GROUP_A);
-            eventBus2().register(mailboxListener, GROUP_A);
-
-            eventBus2().dispatch(EVENT, NO_KEYS).block();
-
-            verify(mailboxListener, timeout(ONE_SECOND.toMillis()).times(1)).event(any());
-        }
-
-        @Test
-        default void unregisterShouldStopNotificationForDistantGroups() throws Exception {
-            EventListener mailboxListener = newListener();
-
-            eventBus().register(mailboxListener, GROUP_A).unregister();
-
-            eventBus2().dispatch(EVENT, NO_KEYS).block();
-
-
-            verify(mailboxListener, after(FIVE_HUNDRED_MS.toMillis()).never())
-                .event(any());
-        }
-
-        @Test
-        default void registerShouldNotDispatchPastEventsForGroupsInADistributedContext() throws Exception {
-            EventListener listener = newListener();
-
-            eventBus().dispatch(EVENT, NO_KEYS).block();
-
-            eventBus2().register(listener, GROUP_A);
-
-            verify(listener, after(FIVE_HUNDRED_MS.toMillis()).never())
-                .event(any());
-        }
-    }
-}
diff --git a/mailbox/api/src/test/java/org/apache/james/mailbox/events/GroupTest.java b/mailbox/api/src/test/java/org/apache/james/mailbox/events/GroupTest.java
deleted file mode 100644
index 53176df..0000000
--- a/mailbox/api/src/test/java/org/apache/james/mailbox/events/GroupTest.java
+++ /dev/null
@@ -1,135 +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.mailbox.events;
-
-import static org.assertj.core.api.Assertions.assertThat;
-import static org.assertj.core.api.Assertions.assertThatThrownBy;
-
-import org.apache.james.events.GenericGroup;
-import org.apache.james.events.Group;
-import org.junit.jupiter.api.Test;
-
-import nl.jqno.equalsverifier.EqualsVerifier;
-
-class GroupTest {
-    static class GroupA extends Group {
-
-    }
-
-    static class GroupB extends Group {
-
-    }
-
-    static class GroupC extends GroupA {
-
-    }
-
-    @Test
-    void shouldMatchBeanContract() {
-        EqualsVerifier.forClass(Group.class)
-            .usingGetClass()
-            .verify();
-    }
-
-    @Test
-    void equalsShouldReturnTrueOnSameClass() {
-        assertThat(new GroupA()).isEqualTo(new GroupA());
-    }
-
-    @Test
-    void equalsShouldReturnFalseOnDifferentClass() {
-        assertThat(new GroupA()).isNotEqualTo(new GroupB());
-    }
-
-    @Test
-    void equalsShouldReturnFalseOnSubClass() {
-        assertThat(new GroupA()).isNotEqualTo(new GroupC());
-    }
-
-    @Test
-    void equalsShouldReturnFalseOnParentClass() {
-        assertThat(new GroupC()).isNotEqualTo(new GroupA());
-    }
-
-    @Test
-    void genericGroupShouldMatchBeanContract() {
-        EqualsVerifier.forClass(GenericGroup.class)
-            .withRedefinedSuperclass()
-            .verify();
-    }
-
-    @Test
-    void asStringShouldReturnFqdnByDefault() {
-        assertThat(new EventBusTestFixture.GroupA().asString()).isEqualTo("org.apache.james.mailbox.events.EventBusTestFixture$GroupA");
-    }
-
-    @Test
-    void asStringShouldReturnNameWhenGenericGroup() {
-        assertThat(new GenericGroup("abc").asString()).isEqualTo("org.apache.james.events.GenericGroup-abc");
-    }
-
-    @Test
-    void deserializeShouldReturnGroupWhenGenericGroup() throws Exception {
-        assertThat(Group.deserialize("org.apache.james.events.GenericGroup-abc"))
-            .isEqualTo(new GenericGroup("abc"));
-    }
-
-    @Test
-    void deserializeShouldReturnGroupWhenEmptyGenericGroup() throws Exception {
-        assertThat(Group.deserialize("org.apache.james.events.GenericGroup-"))
-            .isEqualTo(new GenericGroup(""));
-    }
-
-    @Test
-    void deserializeShouldReturnGroupWhenExtendsGroup() throws Exception {
-        assertThat(Group.deserialize("org.apache.james.mailbox.events.EventBusTestFixture$GroupA"))
-            .isEqualTo(new EventBusTestFixture.GroupA());
-    }
-
-    @Test
-    void deserializeShouldThrowWhenClassNotFound() {
-        assertThatThrownBy(() -> Group.deserialize("org.apache.james.mailbox.events.Noone"))
-            .isInstanceOf(Group.GroupDeserializationException.class);
-    }
-
-    @Test
-    void deserializeShouldThrowWhenNotAGroup() {
-        assertThatThrownBy(() -> Group.deserialize("java.lang.String"))
-            .isInstanceOf(Group.GroupDeserializationException.class);
-    }
-
-    @Test
-    void deserializeShouldThrowWhenConstructorArgumentsRequired() {
-        assertThatThrownBy(() -> Group.deserialize("org.apache.james.events.GenericGroup"))
-            .isInstanceOf(Group.GroupDeserializationException.class);
-    }
-
-    @Test
-    void deserializeShouldThrowWhenNull() {
-        assertThatThrownBy(() -> Group.deserialize(null))
-            .isInstanceOf(Group.GroupDeserializationException.class);
-    }
-
-    @Test
-    void deserializeShouldThrowWhenEmpty() {
-        assertThatThrownBy(() -> Group.deserialize(""))
-            .isInstanceOf(Group.GroupDeserializationException.class);
-    }
-}
\ No newline at end of file
diff --git a/mailbox/api/src/test/java/org/apache/james/mailbox/events/InsertionIdTest.java b/mailbox/api/src/test/java/org/apache/james/mailbox/events/InsertionIdTest.java
deleted file mode 100644
index c951edd..0000000
--- a/mailbox/api/src/test/java/org/apache/james/mailbox/events/InsertionIdTest.java
+++ /dev/null
@@ -1,57 +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.mailbox.events;
-
-import static org.assertj.core.api.Assertions.assertThat;
-import static org.assertj.core.api.Assertions.assertThatThrownBy;
-
-import java.util.UUID;
-
-import org.apache.james.events.EventDeadLetters;
-import org.junit.jupiter.api.Test;
-
-import nl.jqno.equalsverifier.EqualsVerifier;
-
-class InsertionIdTest {
-    private static final UUID UUID_1 = UUID.fromString("6e0dd59d-660e-4d9b-b22f-0354479f47b4");
-
-    @Test
-    void eventIdShouldMatchBeanContract() {
-        EqualsVerifier.forClass(EventDeadLetters.InsertionId.class).verify();
-    }
-
-    @Test
-    void ofShouldDeserializeUUIDs() {
-        assertThat(EventDeadLetters.InsertionId.of(UUID_1.toString()))
-            .isEqualTo(EventDeadLetters.InsertionId.of(UUID_1));
-    }
-
-    @Test
-    void ofStringShouldThrowOnNullValue() {
-        assertThatThrownBy(() -> EventDeadLetters.InsertionId.of((String) null))
-            .isInstanceOf(NullPointerException.class);
-    }
-
-    @Test
-    void ofUuidShouldThrowOnNullValue() {
-        assertThatThrownBy(() -> EventDeadLetters.InsertionId.of((UUID) null))
-            .isInstanceOf(NullPointerException.class);
-    }
-}
diff --git a/mailbox/api/src/test/java/org/apache/james/mailbox/events/KeyContract.java b/mailbox/api/src/test/java/org/apache/james/mailbox/events/KeyContract.java
deleted file mode 100644
index 4c22d4b..0000000
--- a/mailbox/api/src/test/java/org/apache/james/mailbox/events/KeyContract.java
+++ /dev/null
@@ -1,458 +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.mailbox.events;
-
-import static org.apache.james.mailbox.events.EventBusTestFixture.EVENT;
-import static org.apache.james.mailbox.events.EventBusTestFixture.EVENT_2;
-import static org.apache.james.mailbox.events.EventBusTestFixture.EVENT_UNSUPPORTED_BY_LISTENER;
-import static org.apache.james.mailbox.events.EventBusTestFixture.FIVE_HUNDRED_MS;
-import static org.apache.james.mailbox.events.EventBusTestFixture.KEY_1;
-import static org.apache.james.mailbox.events.EventBusTestFixture.KEY_2;
-import static org.apache.james.mailbox.events.EventBusTestFixture.NO_KEYS;
-import static org.apache.james.mailbox.events.EventBusTestFixture.ONE_SECOND;
-import static org.apache.james.mailbox.events.EventBusTestFixture.newListener;
-import static org.assertj.core.api.Assertions.assertThat;
-import static org.assertj.core.api.Assertions.assertThatCode;
-import static org.junit.jupiter.api.Assertions.assertTimeout;
-import static org.mockito.ArgumentMatchers.any;
-import static org.mockito.Mockito.after;
-import static org.mockito.Mockito.doAnswer;
-import static org.mockito.Mockito.doThrow;
-import static org.mockito.Mockito.mock;
-import static org.mockito.Mockito.timeout;
-import static org.mockito.Mockito.times;
-import static org.mockito.Mockito.verify;
-import static org.mockito.Mockito.when;
-
-import java.time.Duration;
-import java.util.concurrent.ConcurrentLinkedQueue;
-import java.util.concurrent.CountDownLatch;
-import java.util.concurrent.atomic.AtomicBoolean;
-import java.util.concurrent.atomic.AtomicInteger;
-import java.util.stream.IntStream;
-
-import org.apache.james.core.Username;
-import org.apache.james.events.Event;
-import org.apache.james.events.EventBus;
-import org.apache.james.events.EventListener;
-import org.apache.james.events.Registration;
-import org.apache.james.mailbox.MailboxSession;
-import org.apache.james.mailbox.events.MailboxEvents.Added;
-import org.apache.james.mailbox.model.MailboxPath;
-import org.apache.james.mailbox.model.TestId;
-import org.junit.jupiter.api.Test;
-
-import com.google.common.collect.ImmutableSet;
-import com.google.common.collect.ImmutableSortedMap;
-
-import reactor.core.publisher.Mono;
-import reactor.core.scheduler.Schedulers;
-
-public interface KeyContract extends EventBusContract {
-
-    interface SingleEventBusKeyContract extends EventBusContract {
-        @Test
-        default void notificationShouldNotExceedRate() {
-            int eventCount = 50;
-            AtomicInteger nbCalls = new AtomicInteger(0);
-            AtomicInteger finishedExecutions = new AtomicInteger(0);
-            AtomicBoolean rateExceeded = new AtomicBoolean(false);
-
-            Mono.from(eventBus().register(event -> {
-                if (nbCalls.get() - finishedExecutions.get() > EventBus.EXECUTION_RATE) {
-                    rateExceeded.set(true);
-                }
-                nbCalls.incrementAndGet();
-                Thread.sleep(Duration.ofMillis(20).toMillis());
-                finishedExecutions.incrementAndGet();
-
-            }, KEY_1)).block();
-
-            IntStream.range(0, eventCount)
-                .forEach(i -> eventBus().dispatch(EVENT, KEY_1).block());
-
-            getSpeedProfile().shortWaitCondition().atMost(org.awaitility.Duration.TEN_MINUTES)
-                .untilAsserted(() -> assertThat(finishedExecutions.get()).isEqualTo(eventCount));
-            assertThat(rateExceeded).isFalse();
-        }
-
-        @Test
-        default void notificationShouldDeliverASingleEventToAllListenersAtTheSameTime() {
-            CountDownLatch countDownLatch = new CountDownLatch(1);
-            try {
-                ConcurrentLinkedQueue<String> threads = new ConcurrentLinkedQueue<>();
-                Mono.from(eventBus().register(event -> {
-                    threads.add(Thread.currentThread().getName());
-                    countDownLatch.await();
-                }, KEY_1)).block();
-                Mono.from(eventBus().register(event -> {
-                    threads.add(Thread.currentThread().getName());
-                    countDownLatch.await();
-                }, KEY_1)).block();
-                Mono.from(eventBus().register(event -> {
-                    threads.add(Thread.currentThread().getName());
-                    countDownLatch.await();
-                }, KEY_1)).block();
-
-                eventBus().dispatch(EVENT, KEY_1).subscribeOn(Schedulers.elastic()).subscribe();
-
-
-                getSpeedProfile().shortWaitCondition().atMost(org.awaitility.Duration.TEN_SECONDS)
-                    .untilAsserted(() -> assertThat(threads).hasSize(3));
-                assertThat(threads).doesNotHaveDuplicates();
-            } finally {
-                countDownLatch.countDown();
-            }
-        }
-
-
-        @Test
-        default void registeredListenersShouldNotReceiveNoopEvents() throws Exception {
-            EventListener listener = newListener();
-
-            Mono.from(eventBus().register(listener, KEY_1)).block();
-
-            Username bob = Username.of("bob");
-            Added noopEvent = new Added(MailboxSession.SessionId.of(18), bob, MailboxPath.forUser(bob, "mailbox"), TestId.of(58), ImmutableSortedMap.of(), Event.EventId.random());
-            eventBus().dispatch(noopEvent, KEY_1).block();
-
-            verify(listener, after(FIVE_HUNDRED_MS.toMillis()).never())
-                .event(any());
-        }
-
-       @Test
-        default void registeredListenersShouldReceiveOnlyHandledEvents() throws Exception {
-            EventListener listener = newListener();
-
-            Mono.from(eventBus().register(listener, KEY_1)).block();
-
-            eventBus().dispatch(EVENT_UNSUPPORTED_BY_LISTENER, KEY_1).block();
-
-            verify(listener, after(FIVE_HUNDRED_MS.toMillis()).never())
-                .event(any());
-        }
-
-        @Test
-        default void dispatchShouldNotThrowWhenARegisteredListenerFails() throws Exception {
-            EventListener listener = newListener();
-            doThrow(new RuntimeException()).when(listener).event(any());
-
-            Mono.from(eventBus().register(listener, KEY_1)).block();
-
-            assertThatCode(() -> eventBus().dispatch(EVENT, NO_KEYS).block())
-                .doesNotThrowAnyException();
-        }
-
-        @Test
-        default void dispatchShouldNotNotifyRegisteredListenerWhenEmptyKeySet() throws Exception {
-            EventListener listener = newListener();
-            Mono.from(eventBus().register(listener, KEY_1)).block();
-
-            eventBus().dispatch(EVENT, NO_KEYS).block();
-
-            verify(listener, after(FIVE_HUNDRED_MS.toMillis()).never())
-                .event(any());
-        }
-
-        @Test
-        default void dispatchShouldNotNotifyListenerRegisteredOnOtherKeys() throws Exception {
-            EventListener listener = newListener();
-            Mono.from(eventBus().register(listener, KEY_1)).block();
-
-            eventBus().dispatch(EVENT, ImmutableSet.of(KEY_2)).block();
-
-            verify(listener, after(FIVE_HUNDRED_MS.toMillis()).never())
-                .event(any());
-        }
-
-        @Test
-        default void dispatchShouldNotifyRegisteredListeners() throws Exception {
-            EventListener listener = newListener();
-            Mono.from(eventBus().register(listener, KEY_1)).block();
-
-            eventBus().dispatch(EVENT, ImmutableSet.of(KEY_1)).block();
-
-            verify(listener, timeout(ONE_SECOND.toMillis()).times(1)).event(any());
-        }
-
-        @Test
-        default void dispatchShouldNotifyLocalRegisteredListenerWithoutDelay() throws Exception {
-            EventListener listener = newListener();
-            Mono.from(eventBus().register(listener, KEY_1)).block();
-
-            eventBus().dispatch(EVENT, ImmutableSet.of(KEY_1)).block();
-
-            verify(listener, times(1)).event(any());
-        }
-
-        @Test
-        default void dispatchShouldNotifyOnlyRegisteredListener() throws Exception {
-            EventListener listener = newListener();
-            EventListener listener2 = newListener();
-            Mono.from(eventBus().register(listener, KEY_1)).block();
-            Mono.from(eventBus().register(listener2, KEY_2)).block();
-
-            eventBus().dispatch(EVENT, ImmutableSet.of(KEY_1)).block();
-
-            verify(listener, timeout(ONE_SECOND.toMillis()).times(1)).event(any());
-            verify(listener2, after(FIVE_HUNDRED_MS.toMillis()).never())
-                .event(any());
-        }
-
-        @Test
-        default void dispatchShouldNotifyAllListenersRegisteredOnAKey() throws Exception {
-            EventListener listener = newListener();
-            EventListener listener2 = newListener();
-            Mono.from(eventBus().register(listener, KEY_1)).block();
-            Mono.from(eventBus().register(listener2, KEY_1)).block();
-
-            eventBus().dispatch(EVENT, ImmutableSet.of(KEY_1)).block();
-
-            verify(listener, timeout(ONE_SECOND.toMillis()).times(1)).event(any());
-            verify(listener2, timeout(ONE_SECOND.toMillis()).times(1)).event(any());
-        }
-
-        @Test
-        default void registerShouldAllowDuplicatedRegistration() throws Exception {
-            EventListener listener = newListener();
-            Mono.from(eventBus().register(listener, KEY_1)).block();
-            Mono.from(eventBus().register(listener, KEY_1)).block();
-
-            eventBus().dispatch(EVENT, ImmutableSet.of(KEY_1)).block();
-
-            verify(listener, timeout(ONE_SECOND.toMillis()).times(1)).event(any());
-        }
-
-        @Test
-        default void unregisterShouldRemoveDoubleRegisteredListener() throws Exception {
-            EventListener listener = newListener();
-            Mono.from(eventBus().register(listener, KEY_1)).block();
-            Mono.from(eventBus().register(listener, KEY_1)).block().unregister();
-
-            eventBus().dispatch(EVENT, ImmutableSet.of(KEY_1)).block();
-
-            verify(listener, after(FIVE_HUNDRED_MS.toMillis()).never())
-                .event(any());
-        }
-
-        @Test
-        default void registerShouldNotDispatchPastEvents() throws Exception {
-            EventListener listener = newListener();
-
-            eventBus().dispatch(EVENT, ImmutableSet.of(KEY_1)).block();
-
-            Mono.from(eventBus().register(listener, KEY_1)).block();
-
-            verify(listener, after(FIVE_HUNDRED_MS.toMillis()).never())
-                .event(any());
-        }
-
-        @Test
-        default void callingAllUnregisterMethodShouldUnregisterTheListener() throws Exception {
-            EventListener listener = newListener();
-            Registration registration = Mono.from(eventBus().register(listener, KEY_1)).block();
-            Mono.from(eventBus().register(listener, KEY_1)).block().unregister();
-            registration.unregister();
-
-            eventBus().dispatch(EVENT, ImmutableSet.of(KEY_1)).block();
-
-            verify(listener, after(FIVE_HUNDRED_MS.toMillis()).never())
-                .event(any());
-        }
-
-        @Test
-        default void unregisterShouldHaveNotNotifyWhenCalledOnDifferentKeys() throws Exception {
-            EventListener listener = newListener();
-            Mono.from(eventBus().register(listener, KEY_1)).block();
-            Mono.from(eventBus().register(listener, KEY_2)).block().unregister();
-
-            eventBus().dispatch(EVENT, ImmutableSet.of(KEY_1)).block();
-
-            verify(listener, timeout(ONE_SECOND.toMillis()).times(1)).event(any());
-        }
-
-        @Test
-        default void unregisterShouldBeIdempotentForKeyRegistrations() {
-            EventListener listener = newListener();
-
-            Registration registration = Mono.from(eventBus().register(listener, KEY_1)).block();
-            registration.unregister();
-
-            assertThatCode(registration::unregister)
-                .doesNotThrowAnyException();
-        }
-
-        @Test
-        default void dispatchShouldAcceptSeveralKeys() throws Exception {
-            EventListener listener = newListener();
-            Mono.from(eventBus().register(listener, KEY_1)).block();
-
-            eventBus().dispatch(EVENT, ImmutableSet.of(KEY_1, KEY_2)).block();
-
-            verify(listener, timeout(ONE_SECOND.toMillis()).times(1)).event(any());
-        }
-
-        @Test
-        default void dispatchShouldCallListenerOnceWhenSeveralKeysMatching() throws Exception {
-            EventListener listener = newListener();
-            Mono.from(eventBus().register(listener, KEY_1)).block();
-            Mono.from(eventBus().register(listener, KEY_2)).block();
-
-            eventBus().dispatch(EVENT, ImmutableSet.of(KEY_1, KEY_2)).block();
-
-            verify(listener, timeout(ONE_SECOND.toMillis()).times(1)).event(any());
-        }
-
-        @Test
-        default void dispatchShouldNotNotifyUnregisteredListener() throws Exception {
-            EventListener listener = newListener();
-            Mono.from(eventBus().register(listener, KEY_1)).block().unregister();
-
-            eventBus().dispatch(EVENT, ImmutableSet.of(KEY_1)).block();
-
-            verify(listener, after(FIVE_HUNDRED_MS.toMillis()).never())
-                .event(any());
-        }
-
-
-        @Test
-        default void dispatchShouldNotifyAsynchronousListener() throws Exception {
-            EventListener listener = newListener();
-            when(listener.getExecutionMode()).thenReturn(EventListener.ExecutionMode.ASYNCHRONOUS);
-            Mono.from(eventBus().register(listener, KEY_1)).block();
-
-            eventBus().dispatch(EVENT, KEY_1).block();
-
-            verify(listener, after(FIVE_HUNDRED_MS.toMillis())).event(EVENT);
-        }
-
-        @Test
-        default void dispatchShouldNotBlockAsynchronousListener() throws Exception {
-            EventListener listener = newListener();
-            when(listener.getExecutionMode()).thenReturn(EventListener.ExecutionMode.ASYNCHRONOUS);
-            CountDownLatch latch = new CountDownLatch(1);
-            doAnswer(invocation -> {
-                latch.await();
-                return null;
-            }).when(listener).event(EVENT);
-
-            assertTimeout(Duration.ofSeconds(2),
-                () -> {
-                    eventBus().dispatch(EVENT, NO_KEYS).block();
-                    latch.countDown();
-                });
-        }
-
-        @Test
-        default void failingRegisteredListenersShouldNotAbortRegisteredDelivery() {
-            EventBusTestFixture.EventListenerCountingSuccessfulExecution listener = new EventBusTestFixture.EventMatcherThrowingListener(ImmutableSet.of(EVENT));
-            Mono.from(eventBus().register(listener, KEY_1)).block();
-
-            eventBus().dispatch(EVENT, KEY_1).block();
-            eventBus().dispatch(EVENT_2, KEY_1).block();
-
-            getSpeedProfile().shortWaitCondition()
-                .untilAsserted(() -> assertThat(listener.numberOfEventCalls()).isEqualTo(1));
-        }
-
-        @Test
-        default void allRegisteredListenersShouldBeExecutedWhenARegisteredListenerFails() throws Exception {
-            EventListener listener = newListener();
-
-            EventListener failingListener = mock(EventListener.class);
-            when(failingListener.getExecutionMode()).thenReturn(EventListener.ExecutionMode.SYNCHRONOUS);
-            doThrow(new RuntimeException()).when(failingListener).event(any());
-
-            Mono.from(eventBus().register(failingListener, KEY_1)).block();
-            Mono.from(eventBus().register(listener, KEY_1)).block();
-
-            eventBus().dispatch(EVENT, ImmutableSet.of(KEY_1)).block();
-
-            verify(listener, timeout(ONE_SECOND.toMillis()).times(1)).event(any());
-        }
-    }
-
-    interface MultipleEventBusKeyContract extends MultipleEventBusContract {
-
-        @Test
-        default void crossEventBusRegistrationShouldBeAllowed() throws Exception {
-            EventListener mailboxListener = newListener();
-
-            Mono.from(eventBus().register(mailboxListener, KEY_1)).block();
-
-            eventBus2().dispatch(EVENT, KEY_1).block();
-
-            verify(mailboxListener, timeout(ONE_SECOND.toMillis()).times(1)).event(any());
-        }
-
-        @Test
-        default void unregisteredDistantListenersShouldNotBeNotified() throws Exception {
-            EventListener eventListener = newListener();
-
-            Mono.from(eventBus().register(eventListener, KEY_1)).block().unregister();
-
-            eventBus2().dispatch(EVENT, ImmutableSet.of(KEY_1)).block();
-
-            verify(eventListener, after(FIVE_HUNDRED_MS.toMillis()).never())
-                .event(any());
-        }
-
-        @Test
-        default void allRegisteredListenersShouldBeDispatched() throws Exception {
-            EventListener mailboxListener1 = newListener();
-            EventListener mailboxListener2 = newListener();
-
-            Mono.from(eventBus().register(mailboxListener1, KEY_1)).block();
-            Mono.from(eventBus2().register(mailboxListener2, KEY_1)).block();
-
-            eventBus2().dispatch(EVENT, KEY_1).block();
-
-            verify(mailboxListener1, timeout(ONE_SECOND.toMillis()).times(1)).event(any());
-            verify(mailboxListener2, timeout(ONE_SECOND.toMillis()).times(1)).event(any());
-        }
-
-        @Test
-        default void registerShouldNotDispatchPastEventsInDistributedContext() throws Exception {
-            EventListener listener = newListener();
-
-            eventBus2().dispatch(EVENT, ImmutableSet.of(KEY_1)).block();
-
-            Mono.from(eventBus().register(listener, KEY_1)).block();
-
-            verify(listener, after(FIVE_HUNDRED_MS.toMillis()).never())
-                .event(any());
-        }
-
-        @Test
-        default void localDispatchedListenersShouldBeDispatchedWithoutDelay() throws Exception {
-            EventListener mailboxListener1 = newListener();
-            EventListener mailboxListener2 = newListener();
-
-            Mono.from(eventBus().register(mailboxListener1, KEY_1)).block();
-            Mono.from(eventBus2().register(mailboxListener2, KEY_1)).block();
-
-            eventBus2().dispatch(EVENT, KEY_1).block();
-
-            verify(mailboxListener2, times(1)).event(any());
-            verify(mailboxListener1, timeout(ONE_SECOND.toMillis()).times(1)).event(any());
-        }
-
-    }
-}
diff --git a/mailbox/api/src/test/java/org/apache/james/mailbox/events/MailboxIdRegistrationKeyTest.java b/mailbox/api/src/test/java/org/apache/james/mailbox/events/MailboxIdRegistrationKeyTest.java
deleted file mode 100644
index 0a361b6..0000000
--- a/mailbox/api/src/test/java/org/apache/james/mailbox/events/MailboxIdRegistrationKeyTest.java
+++ /dev/null
@@ -1,60 +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.mailbox.events;
-
-import static org.assertj.core.api.Assertions.assertThat;
-import static org.assertj.core.api.Assertions.assertThatThrownBy;
-
-import org.apache.james.mailbox.model.TestId;
-import org.junit.jupiter.api.Test;
-
-import nl.jqno.equalsverifier.EqualsVerifier;
-
-class MailboxIdRegistrationKeyTest {
-    private static final String ID = "42";
-
-    private static final MailboxIdRegistrationKey.Factory FACTORY = new MailboxIdRegistrationKey.Factory(new TestId.Factory());
-
-    private static final MailboxIdRegistrationKey MAILBOX_ID_REGISTRATION_KEY = new MailboxIdRegistrationKey((TestId.of(42)));
-
-    @Test
-    void shouldRespectBeanContract() {
-        EqualsVerifier.forClass(MailboxIdRegistrationKey.class)
-            .verify();
-    }
-
-    @Test
-    void asStringShouldReturnSerializedMailboxId() {
-        assertThat(MAILBOX_ID_REGISTRATION_KEY.asString())
-            .isEqualTo(ID);
-    }
-
-    @Test
-    void fromStringShouldReturnCorrespondingRegistrationKey() {
-        assertThat(FACTORY.fromString(ID))
-            .isEqualTo(MAILBOX_ID_REGISTRATION_KEY);
-    }
-
-    @Test
-    void fromStringShouldThrowOnInvalidValues() {
-        assertThatThrownBy(() -> FACTORY.fromString("invalid"))
-            .isInstanceOf(IllegalArgumentException.class);
-    }
-}
\ No newline at end of file
diff --git a/mailbox/api/src/test/java/org/apache/james/mailbox/events/RetryBackoffConfigurationTest.java b/mailbox/api/src/test/java/org/apache/james/mailbox/events/RetryBackoffConfigurationTest.java
deleted file mode 100644
index 0788da9..0000000
--- a/mailbox/api/src/test/java/org/apache/james/mailbox/events/RetryBackoffConfigurationTest.java
+++ /dev/null
@@ -1,141 +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.mailbox.events;
-
-import static org.apache.james.mailbox.events.RetryBackoffConfiguration.DEFAULT_FIRST_BACKOFF;
-import static org.apache.james.mailbox.events.RetryBackoffConfiguration.DEFAULT_JITTER_FACTOR;
-import static org.apache.james.mailbox.events.RetryBackoffConfiguration.DEFAULT_MAX_RETRIES;
-import static org.assertj.core.api.Assertions.assertThat;
-import static org.assertj.core.api.Assertions.assertThatThrownBy;
-
-import java.time.Duration;
-
-import org.assertj.core.api.SoftAssertions;
-import org.junit.jupiter.api.Test;
-
-import nl.jqno.equalsverifier.EqualsVerifier;
-
-class RetryBackoffConfigurationTest {
-
-    @Test
-    void shouldMatchBeanContract() {
-        EqualsVerifier.forClass(RetryBackoffConfiguration.class)
-            .verify();
-    }
-
-    @Test
-    void buildShouldThrowWhenNegativeFirstBackoff() {
-        assertThatThrownBy(() -> RetryBackoffConfiguration.builder()
-            .maxRetries(DEFAULT_MAX_RETRIES)
-            .firstBackoff(Duration.ofMillis(-1000L))
-            .jitterFactor(DEFAULT_JITTER_FACTOR)
-            .build())
-        .isInstanceOf(IllegalArgumentException.class)
-        .hasMessage("firstBackoff is not allowed to be negative");
-    }
-
-    @Test
-    void buildShouldThrowWhenNegativeMaxRetries() {
-        assertThatThrownBy(() -> RetryBackoffConfiguration.builder()
-            .maxRetries(-6)
-            .firstBackoff(DEFAULT_FIRST_BACKOFF)
-            .jitterFactor(DEFAULT_JITTER_FACTOR)
-            .build())
-        .isInstanceOf(IllegalArgumentException.class)
-        .hasMessage("maxRetries is not allowed to be negative");
-    }
-
-    @Test
-    void buildShouldThrowWhenNegativeJitterFactor() {
-        assertThatThrownBy(() -> RetryBackoffConfiguration.builder()
-            .maxRetries(DEFAULT_MAX_RETRIES)
-            .firstBackoff(DEFAULT_FIRST_BACKOFF)
-            .jitterFactor(-2.5)
-            .build())
-        .isInstanceOf(IllegalArgumentException.class)
-        .hasMessage("jitterFactor is not allowed to be negative or greater than 1");
-    }
-
-    @Test
-    void buildShouldThrowWhenGreaterThanOneJitterFactor() {
-        assertThatThrownBy(() -> RetryBackoffConfiguration.builder()
-            .maxRetries(DEFAULT_MAX_RETRIES)
-            .firstBackoff(DEFAULT_FIRST_BACKOFF)
-            .jitterFactor(1.000001)
-            .build())
-        .isInstanceOf(IllegalArgumentException.class)
-        .hasMessage("jitterFactor is not allowed to be negative or greater than 1");
-    }
-
-    @Test
-    void buildShouldSuccessWhenZeroFirstBackoff() {
-        RetryBackoffConfiguration retryBackoff = RetryBackoffConfiguration.builder()
-            .maxRetries(DEFAULT_MAX_RETRIES)
-            .firstBackoff(Duration.ZERO)
-            .jitterFactor(DEFAULT_JITTER_FACTOR)
-            .build();
-
-        assertThat(retryBackoff.getFirstBackoff().toMillis())
-            .isEqualTo(0L);
-    }
-
-    @Test
-    void buildShouldSuccessWhenZeroMaxRetries() {
-        RetryBackoffConfiguration retryBackoff = RetryBackoffConfiguration.builder()
-            .maxRetries(0)
-            .firstBackoff(DEFAULT_FIRST_BACKOFF)
-            .jitterFactor(DEFAULT_JITTER_FACTOR)
-            .build();
-
-        assertThat(retryBackoff.getMaxRetries())
-            .isEqualTo(0L);
-    }
-
-    @Test
-    void buildShouldSuccessWhenZeroJitterFactor() {
-        RetryBackoffConfiguration retryBackoff = RetryBackoffConfiguration.builder()
-            .maxRetries(DEFAULT_MAX_RETRIES)
-            .firstBackoff(DEFAULT_FIRST_BACKOFF)
-            .jitterFactor(0)
-            .build();
-
-        assertThat(retryBackoff.getJitterFactor())
-            .isEqualTo(0);
-    }
-
-    @Test
-    void buildShouldReturnCorrespondingValues() {
-        RetryBackoffConfiguration retryBackoff = RetryBackoffConfiguration.builder()
-            .maxRetries(5)
-            .firstBackoff(Duration.ofMillis(200))
-            .jitterFactor(0.6)
-            .build();
-
-        SoftAssertions.assertSoftly(softly -> {
-            softly.assertThat(retryBackoff.getJitterFactor())
-                .isEqualTo(0.6);
-            softly.assertThat(retryBackoff.getMaxRetries())
-                .isEqualTo(5);
-            softly.assertThat(retryBackoff.getFirstBackoff())
-                .isEqualTo(Duration.ofMillis(200));
-        });
-    }
-
-}
\ No newline at end of file
diff --git a/mailbox/api/src/test/java/org/apache/james/mailbox/model/MessageMovesTest.java b/mailbox/api/src/test/java/org/apache/james/mailbox/model/MessageMovesTest.java
index 8787db5..1710ceb 100644
--- a/mailbox/api/src/test/java/org/apache/james/mailbox/model/MessageMovesTest.java
+++ b/mailbox/api/src/test/java/org/apache/james/mailbox/model/MessageMovesTest.java
@@ -19,7 +19,7 @@
 
 package org.apache.james.mailbox.model;
 
-import org.apache.james.mailbox.events.MessageMoveEvent;
+import org.apache.james.events.MessageMoveEvent;
 import org.junit.jupiter.api.Test;
 
 import nl.jqno.equalsverifier.EqualsVerifier;
diff --git a/mailbox/cassandra/pom.xml b/mailbox/cassandra/pom.xml
index 385f0b6..f596178 100644
--- a/mailbox/cassandra/pom.xml
+++ b/mailbox/cassandra/pom.xml
@@ -54,11 +54,6 @@
         </dependency>
         <dependency>
             <groupId>${james.groupId}</groupId>
-            <artifactId>apache-james-mailbox-event-memory</artifactId>
-            <scope>test</scope>
-        </dependency>
-        <dependency>
-            <groupId>${james.groupId}</groupId>
             <artifactId>apache-james-mailbox-store</artifactId>
         </dependency>
         <dependency>
@@ -89,6 +84,11 @@
         </dependency>
         <dependency>
             <groupId>${james.groupId}</groupId>
+            <artifactId>event-bus-in-vm</artifactId>
+            <scope>test</scope>
+        </dependency>
+        <dependency>
+            <groupId>${james.groupId}</groupId>
             <artifactId>event-sourcing-core</artifactId>
         </dependency>
         <dependency>
diff --git a/mailbox/cassandra/src/main/java/org/apache/james/mailbox/cassandra/DeleteMessageListener.java b/mailbox/cassandra/src/main/java/org/apache/james/mailbox/cassandra/DeleteMessageListener.java
index 728bd81..4b2f084 100644
--- a/mailbox/cassandra/src/main/java/org/apache/james/mailbox/cassandra/DeleteMessageListener.java
+++ b/mailbox/cassandra/src/main/java/org/apache/james/mailbox/cassandra/DeleteMessageListener.java
@@ -31,6 +31,8 @@ import org.apache.james.blob.api.BlobStore;
 import org.apache.james.events.Event;
 import org.apache.james.events.EventListener;
 import org.apache.james.events.Group;
+import org.apache.james.events.MailboxEvents.Expunged;
+import org.apache.james.events.MailboxEvents.MailboxDeletion;
 import org.apache.james.mailbox.acl.ACLDiff;
 import org.apache.james.mailbox.cassandra.ids.CassandraId;
 import org.apache.james.mailbox.cassandra.ids.CassandraMessageId;
@@ -50,8 +52,6 @@ import org.apache.james.mailbox.cassandra.mail.CassandraMessageIdToImapUidDAO;
 import org.apache.james.mailbox.cassandra.mail.CassandraUserMailboxRightsDAO;
 import org.apache.james.mailbox.cassandra.mail.MessageAttachmentRepresentation;
 import org.apache.james.mailbox.cassandra.mail.MessageRepresentation;
-import org.apache.james.mailbox.events.MailboxEvents.Expunged;
-import org.apache.james.mailbox.events.MailboxEvents.MailboxDeletion;
 import org.apache.james.mailbox.model.ComposedMessageIdWithMetaData;
 import org.apache.james.mailbox.model.MailboxACL;
 import org.apache.james.mailbox.model.MessageMetaData;
diff --git a/mailbox/cassandra/src/main/java/org/apache/james/mailbox/cassandra/MailboxOperationLoggingListener.java b/mailbox/cassandra/src/main/java/org/apache/james/mailbox/cassandra/MailboxOperationLoggingListener.java
index dcfd070..b48508f 100644
--- a/mailbox/cassandra/src/main/java/org/apache/james/mailbox/cassandra/MailboxOperationLoggingListener.java
+++ b/mailbox/cassandra/src/main/java/org/apache/james/mailbox/cassandra/MailboxOperationLoggingListener.java
@@ -26,9 +26,9 @@ import static org.apache.james.mailbox.cassandra.GhostMailbox.TYPE;
 import org.apache.james.events.Event;
 import org.apache.james.events.EventListener;
 import org.apache.james.events.Group;
-import org.apache.james.mailbox.events.MailboxEvents.MailboxAdded;
-import org.apache.james.mailbox.events.MailboxEvents.MailboxDeletion;
-import org.apache.james.mailbox.events.MailboxEvents.MailboxRenamed;
+import org.apache.james.events.MailboxEvents.MailboxAdded;
+import org.apache.james.events.MailboxEvents.MailboxDeletion;
+import org.apache.james.events.MailboxEvents.MailboxRenamed;
 
 /**
  * See https://issues.apache.org/jira/browse/MAILBOX-322 for reading about the Ghost mailbox bug.
diff --git a/mailbox/cassandra/src/test/java/org/apache/james/mailbox/cassandra/CassandraCombinationManagerTest.java b/mailbox/cassandra/src/test/java/org/apache/james/mailbox/cassandra/CassandraCombinationManagerTest.java
index 88ef7a5..dfd49c7 100644
--- a/mailbox/cassandra/src/test/java/org/apache/james/mailbox/cassandra/CassandraCombinationManagerTest.java
+++ b/mailbox/cassandra/src/test/java/org/apache/james/mailbox/cassandra/CassandraCombinationManagerTest.java
@@ -20,11 +20,11 @@
 package org.apache.james.mailbox.cassandra;
 
 import org.apache.james.backends.cassandra.CassandraClusterExtension;
+import org.apache.james.events.EventBusTestFixture;
+import org.apache.james.events.InVMEventBus;
+import org.apache.james.events.MemoryEventDeadLetters;
+import org.apache.james.events.delivery.InVmEventDelivery;
 import org.apache.james.mailbox.cassandra.mail.MailboxAggregateModule;
-import org.apache.james.mailbox.events.EventBusTestFixture;
-import org.apache.james.mailbox.events.InVMEventBus;
-import org.apache.james.mailbox.events.MemoryEventDeadLetters;
-import org.apache.james.mailbox.events.delivery.InVmEventDelivery;
 import org.apache.james.mailbox.store.AbstractCombinationManagerTest;
 import org.apache.james.mailbox.store.CombinationManagerTestSystem;
 import org.apache.james.mailbox.store.quota.NoQuotaManager;
diff --git a/mailbox/cassandra/src/test/java/org/apache/james/mailbox/cassandra/CassandraMailboxManagerProvider.java b/mailbox/cassandra/src/test/java/org/apache/james/mailbox/cassandra/CassandraMailboxManagerProvider.java
index e497c3f..3d2226c 100644
--- a/mailbox/cassandra/src/test/java/org/apache/james/mailbox/cassandra/CassandraMailboxManagerProvider.java
+++ b/mailbox/cassandra/src/test/java/org/apache/james/mailbox/cassandra/CassandraMailboxManagerProvider.java
@@ -21,6 +21,10 @@ package org.apache.james.mailbox.cassandra;
 
 import org.apache.james.backends.cassandra.CassandraCluster;
 import org.apache.james.backends.cassandra.init.configuration.CassandraConfiguration;
+import org.apache.james.events.EventBusTestFixture;
+import org.apache.james.events.InVMEventBus;
+import org.apache.james.events.MemoryEventDeadLetters;
+import org.apache.james.events.delivery.InVmEventDelivery;
 import org.apache.james.mailbox.AttachmentContentLoader;
 import org.apache.james.mailbox.Authenticator;
 import org.apache.james.mailbox.Authorizator;
@@ -34,10 +38,6 @@ import org.apache.james.mailbox.cassandra.quota.CassandraGlobalMaxQuotaDao;
 import org.apache.james.mailbox.cassandra.quota.CassandraPerDomainMaxQuotaDao;
 import org.apache.james.mailbox.cassandra.quota.CassandraPerUserMaxQuotaDao;
 import org.apache.james.mailbox.cassandra.quota.CassandraPerUserMaxQuotaManager;
-import org.apache.james.mailbox.events.EventBusTestFixture;
-import org.apache.james.mailbox.events.InVMEventBus;
-import org.apache.james.mailbox.events.MemoryEventDeadLetters;
-import org.apache.james.mailbox.events.delivery.InVmEventDelivery;
 import org.apache.james.mailbox.model.MessageId;
 import org.apache.james.mailbox.quota.QuotaRootResolver;
 import org.apache.james.mailbox.store.MailboxManagerConfiguration;
diff --git a/mailbox/cassandra/src/test/java/org/apache/james/mailbox/cassandra/CassandraMessageIdManagerStorageTest.java b/mailbox/cassandra/src/test/java/org/apache/james/mailbox/cassandra/CassandraMessageIdManagerStorageTest.java
index d536fd4..2d9179c 100644
--- a/mailbox/cassandra/src/test/java/org/apache/james/mailbox/cassandra/CassandraMessageIdManagerStorageTest.java
+++ b/mailbox/cassandra/src/test/java/org/apache/james/mailbox/cassandra/CassandraMessageIdManagerStorageTest.java
@@ -20,11 +20,11 @@
 package org.apache.james.mailbox.cassandra;
 
 import org.apache.james.backends.cassandra.CassandraClusterExtension;
+import org.apache.james.events.EventBusTestFixture;
+import org.apache.james.events.InVMEventBus;
+import org.apache.james.events.MemoryEventDeadLetters;
+import org.apache.james.events.delivery.InVmEventDelivery;
 import org.apache.james.mailbox.cassandra.mail.MailboxAggregateModule;
-import org.apache.james.mailbox.events.EventBusTestFixture;
-import org.apache.james.mailbox.events.InVMEventBus;
-import org.apache.james.mailbox.events.MemoryEventDeadLetters;
-import org.apache.james.mailbox.events.delivery.InVmEventDelivery;
 import org.apache.james.mailbox.extension.PreDeletionHook;
 import org.apache.james.mailbox.store.AbstractMessageIdManagerStorageTest;
 import org.apache.james.mailbox.store.MessageIdManagerTestSystem;
diff --git a/mailbox/cassandra/src/test/java/org/apache/james/mailbox/cassandra/CassandraTestSystemFixture.java b/mailbox/cassandra/src/test/java/org/apache/james/mailbox/cassandra/CassandraTestSystemFixture.java
index 1b4f270..12c1553 100644
--- a/mailbox/cassandra/src/test/java/org/apache/james/mailbox/cassandra/CassandraTestSystemFixture.java
+++ b/mailbox/cassandra/src/test/java/org/apache/james/mailbox/cassandra/CassandraTestSystemFixture.java
@@ -23,6 +23,10 @@ import static org.mockito.Mockito.mock;
 
 import org.apache.james.backends.cassandra.CassandraCluster;
 import org.apache.james.events.EventBus;
+import org.apache.james.events.EventBusTestFixture;
+import org.apache.james.events.InVMEventBus;
+import org.apache.james.events.MemoryEventDeadLetters;
+import org.apache.james.events.delivery.InVmEventDelivery;
 import org.apache.james.mailbox.AttachmentContentLoader;
 import org.apache.james.mailbox.Authenticator;
 import org.apache.james.mailbox.Authorizator;
@@ -34,10 +38,6 @@ import org.apache.james.mailbox.cassandra.quota.CassandraGlobalMaxQuotaDao;
 import org.apache.james.mailbox.cassandra.quota.CassandraPerDomainMaxQuotaDao;
 import org.apache.james.mailbox.cassandra.quota.CassandraPerUserMaxQuotaDao;
 import org.apache.james.mailbox.cassandra.quota.CassandraPerUserMaxQuotaManager;
-import org.apache.james.mailbox.events.EventBusTestFixture;
-import org.apache.james.mailbox.events.InVMEventBus;
-import org.apache.james.mailbox.events.MemoryEventDeadLetters;
-import org.apache.james.mailbox.events.delivery.InVmEventDelivery;
 import org.apache.james.mailbox.quota.CurrentQuotaManager;
 import org.apache.james.mailbox.quota.MaxQuotaManager;
 import org.apache.james.mailbox.quota.QuotaManager;
diff --git a/mailbox/cassandra/src/test/java/org/apache/james/mailbox/cassandra/mail/CassandraMailboxManagerAttachmentTest.java b/mailbox/cassandra/src/test/java/org/apache/james/mailbox/cassandra/mail/CassandraMailboxManagerAttachmentTest.java
index d0e2910..05624f3 100644
--- a/mailbox/cassandra/src/test/java/org/apache/james/mailbox/cassandra/mail/CassandraMailboxManagerAttachmentTest.java
+++ b/mailbox/cassandra/src/test/java/org/apache/james/mailbox/cassandra/mail/CassandraMailboxManagerAttachmentTest.java
@@ -23,6 +23,10 @@ import static org.mockito.Mockito.mock;
 import static org.mockito.Mockito.when;
 
 import org.apache.james.backends.cassandra.CassandraClusterExtension;
+import org.apache.james.events.EventBusTestFixture;
+import org.apache.james.events.InVMEventBus;
+import org.apache.james.events.MemoryEventDeadLetters;
+import org.apache.james.events.delivery.InVmEventDelivery;
 import org.apache.james.mailbox.AttachmentContentLoader;
 import org.apache.james.mailbox.Authenticator;
 import org.apache.james.mailbox.Authorizator;
@@ -33,10 +37,6 @@ import org.apache.james.mailbox.cassandra.CassandraMailboxManager;
 import org.apache.james.mailbox.cassandra.CassandraMailboxSessionMapperFactory;
 import org.apache.james.mailbox.cassandra.TestCassandraMailboxSessionMapperFactory;
 import org.apache.james.mailbox.cassandra.ids.CassandraMessageId;
-import org.apache.james.mailbox.events.EventBusTestFixture;
-import org.apache.james.mailbox.events.InVMEventBus;
-import org.apache.james.mailbox.events.MemoryEventDeadLetters;
-import org.apache.james.mailbox.events.delivery.InVmEventDelivery;
 import org.apache.james.mailbox.store.AbstractMailboxManagerAttachmentTest;
 import org.apache.james.mailbox.store.MailboxManagerConfiguration;
 import org.apache.james.mailbox.store.MailboxSessionMapperFactory;
diff --git a/mailbox/elasticsearch/pom.xml b/mailbox/elasticsearch/pom.xml
index 607e814..f4b06b7 100644
--- a/mailbox/elasticsearch/pom.xml
+++ b/mailbox/elasticsearch/pom.xml
@@ -54,11 +54,6 @@
         </dependency>
         <dependency>
             <groupId>${james.groupId}</groupId>
-            <artifactId>apache-james-mailbox-event-memory</artifactId>
-            <scope>test</scope>
-        </dependency>
-        <dependency>
-            <groupId>${james.groupId}</groupId>
             <artifactId>apache-james-mailbox-memory</artifactId>
             <scope>test</scope>
         </dependency>
@@ -91,6 +86,11 @@
         </dependency>
         <dependency>
             <groupId>${james.groupId}</groupId>
+            <artifactId>event-bus-in-vm</artifactId>
+            <scope>test</scope>
+        </dependency>
+        <dependency>
+            <groupId>${james.groupId}</groupId>
             <artifactId>james-server-testing</artifactId>
             <scope>test</scope>
         </dependency>
diff --git a/mailbox/event/event-cassandra/src/main/java/org/apache/james/mailbox/events/CassandraEventDeadLetters.java b/mailbox/event/event-cassandra/src/main/java/org/apache/james/mailbox/events/CassandraEventDeadLetters.java
deleted file mode 100644
index 77a1c5e..0000000
--- a/mailbox/event/event-cassandra/src/main/java/org/apache/james/mailbox/events/CassandraEventDeadLetters.java
+++ /dev/null
@@ -1,89 +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.mailbox.events;
-
-import javax.inject.Inject;
-
-import org.apache.james.events.Event;
-import org.apache.james.events.EventDeadLetters;
-import org.apache.james.events.Group;
-
-import com.google.common.base.Preconditions;
-
-import reactor.core.publisher.Flux;
-import reactor.core.publisher.Mono;
-
-public class CassandraEventDeadLetters implements EventDeadLetters {
-
-    private final CassandraEventDeadLettersDAO cassandraEventDeadLettersDAO;
-    private final CassandraEventDeadLettersGroupDAO cassandraEventDeadLettersGroupDAO;
-
-
-    @Inject
-    CassandraEventDeadLetters(CassandraEventDeadLettersDAO cassandraEventDeadLettersDAO,
-                              CassandraEventDeadLettersGroupDAO cassandraEventDeadLettersGroupDAO) {
-        this.cassandraEventDeadLettersDAO = cassandraEventDeadLettersDAO;
-        this.cassandraEventDeadLettersGroupDAO = cassandraEventDeadLettersGroupDAO;
-    }
-
-    @Override
-    public Mono<InsertionId> store(Group registeredGroup, Event failDeliveredEvent) {
-        Preconditions.checkArgument(registeredGroup != null, REGISTERED_GROUP_CANNOT_BE_NULL);
-        Preconditions.checkArgument(failDeliveredEvent != null, FAIL_DELIVERED_EVENT_CANNOT_BE_NULL);
-
-        InsertionId insertionId = InsertionId.random();
-        return cassandraEventDeadLettersDAO.store(registeredGroup, failDeliveredEvent, insertionId)
-            .then(cassandraEventDeadLettersGroupDAO.storeGroup(registeredGroup))
-            .thenReturn(insertionId);
-    }
-
-    @Override
-    public Mono<Void> remove(Group registeredGroup, InsertionId failDeliveredInsertionId) {
-        Preconditions.checkArgument(registeredGroup != null, REGISTERED_GROUP_CANNOT_BE_NULL);
-        Preconditions.checkArgument(failDeliveredInsertionId != null, FAIL_DELIVERED_ID_INSERTION_CANNOT_BE_NULL);
-
-        return cassandraEventDeadLettersDAO.removeEvent(registeredGroup, failDeliveredInsertionId);
-    }
-
-    @Override
-    public Mono<Event> failedEvent(Group registeredGroup, InsertionId failDeliveredInsertionId) {
-        Preconditions.checkArgument(registeredGroup != null, REGISTERED_GROUP_CANNOT_BE_NULL);
-        Preconditions.checkArgument(failDeliveredInsertionId != null, FAIL_DELIVERED_ID_INSERTION_CANNOT_BE_NULL);
-
-        return cassandraEventDeadLettersDAO.retrieveFailedEvent(registeredGroup, failDeliveredInsertionId);
-    }
-
-    @Override
-    public Flux<InsertionId> failedIds(Group registeredGroup) {
-        Preconditions.checkArgument(registeredGroup != null, REGISTERED_GROUP_CANNOT_BE_NULL);
-
-        return cassandraEventDeadLettersDAO.retrieveInsertionIdsWithGroup(registeredGroup);
-    }
-
-    @Override
-    public Flux<Group> groupsWithFailedEvents() {
-        return cassandraEventDeadLettersGroupDAO.retrieveAllGroups();
-    }
-
-    @Override
-    public Mono<Boolean> containEvents() {
-        return cassandraEventDeadLettersDAO.containEvents();
-    }
-}
diff --git a/mailbox/event/event-cassandra/src/main/java/org/apache/james/mailbox/events/CassandraEventDeadLettersDAO.java b/mailbox/event/event-cassandra/src/main/java/org/apache/james/mailbox/events/CassandraEventDeadLettersDAO.java
deleted file mode 100644
index 0d20d43..0000000
--- a/mailbox/event/event-cassandra/src/main/java/org/apache/james/mailbox/events/CassandraEventDeadLettersDAO.java
+++ /dev/null
@@ -1,132 +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.mailbox.events;
-
-import static com.datastax.driver.core.querybuilder.QueryBuilder.bindMarker;
-import static com.datastax.driver.core.querybuilder.QueryBuilder.delete;
-import static com.datastax.driver.core.querybuilder.QueryBuilder.eq;
-import static com.datastax.driver.core.querybuilder.QueryBuilder.insertInto;
-import static com.datastax.driver.core.querybuilder.QueryBuilder.select;
-import static org.apache.james.mailbox.events.tables.CassandraEventDeadLettersTable.EVENT;
-import static org.apache.james.mailbox.events.tables.CassandraEventDeadLettersTable.GROUP;
-import static org.apache.james.mailbox.events.tables.CassandraEventDeadLettersTable.INSERTION_ID;
-import static org.apache.james.mailbox.events.tables.CassandraEventDeadLettersTable.TABLE_NAME;
-
-import javax.inject.Inject;
-
-import org.apache.james.backends.cassandra.utils.CassandraAsyncExecutor;
-import org.apache.james.event.json.EventSerializer;
-import org.apache.james.events.Event;
-import org.apache.james.events.EventDeadLetters;
-import org.apache.james.events.Group;
-
-import com.datastax.driver.core.PreparedStatement;
-import com.datastax.driver.core.Session;
-
-import reactor.core.publisher.Flux;
-import reactor.core.publisher.Mono;
-
-public class CassandraEventDeadLettersDAO {
-    private final CassandraAsyncExecutor executor;
-    private final EventSerializer eventSerializer;
-    private final PreparedStatement insertStatement;
-    private final PreparedStatement deleteStatement;
-    private final PreparedStatement selectEventStatement;
-    private final PreparedStatement selectEventIdsWithGroupStatement;
-    private final PreparedStatement containEventsStatement;
-
-    @Inject
-    CassandraEventDeadLettersDAO(Session session, EventSerializer eventSerializer) {
-        this.executor = new CassandraAsyncExecutor(session);
-        this.eventSerializer = eventSerializer;
-        this.insertStatement = prepareInsertStatement(session);
-        this.deleteStatement = prepareDeleteStatement(session);
-        this.selectEventStatement = prepareSelectEventStatement(session);
-        this.selectEventIdsWithGroupStatement = prepareSelectInsertionIdsWithGroupStatement(session);
-        this.containEventsStatement = prepareContainEventStatement(session);
-    }
-
-    private PreparedStatement prepareInsertStatement(Session session) {
-        return session.prepare(insertInto(TABLE_NAME)
-            .value(GROUP, bindMarker(GROUP))
-            .value(INSERTION_ID, bindMarker(INSERTION_ID))
-            .value(EVENT, bindMarker(EVENT)));
-    }
-
-    private PreparedStatement prepareDeleteStatement(Session session) {
-        return session.prepare(delete()
-            .from(TABLE_NAME)
-            .where(eq(GROUP, bindMarker(GROUP)))
-            .and(eq(INSERTION_ID, bindMarker(INSERTION_ID))));
-    }
-
-    private PreparedStatement prepareSelectEventStatement(Session session) {
-        return session.prepare(select(EVENT)
-            .from(TABLE_NAME)
-            .where(eq(GROUP, bindMarker(GROUP)))
-            .and(eq(INSERTION_ID, bindMarker(INSERTION_ID))));
-    }
-
-    private PreparedStatement prepareSelectInsertionIdsWithGroupStatement(Session session) {
-        return session.prepare(select(INSERTION_ID)
-            .from(TABLE_NAME)
-            .where(eq(GROUP, bindMarker(GROUP))));
-    }
-
-    private PreparedStatement prepareContainEventStatement(Session session) {
-        return session.prepare(select(EVENT)
-            .from(TABLE_NAME)
-            .limit(1));
-    }
-
-    Mono<Void> store(Group group, Event failedEvent, EventDeadLetters.InsertionId insertionId) {
-        return executor.executeVoid(insertStatement.bind()
-                .setString(GROUP, group.asString())
-                .setUUID(INSERTION_ID, insertionId.getId())
-                .setString(EVENT, eventSerializer.toJson(failedEvent)));
-    }
-
-    Mono<Void> removeEvent(Group group, EventDeadLetters.InsertionId failedInsertionId) {
-        return executor.executeVoid(deleteStatement.bind()
-                .setString(GROUP, group.asString())
-                .setUUID(INSERTION_ID, failedInsertionId.getId()));
-    }
-
-    Mono<Event> retrieveFailedEvent(Group group, EventDeadLetters.InsertionId insertionId) {
-        return executor.executeSingleRow(selectEventStatement.bind()
-                .setString(GROUP, group.asString())
-                .setUUID(INSERTION_ID, insertionId.getId()))
-            .map(row -> deserializeEvent(row.getString(EVENT)));
-    }
-
-    Flux<EventDeadLetters.InsertionId> retrieveInsertionIdsWithGroup(Group group) {
-        return executor.executeRows(selectEventIdsWithGroupStatement.bind()
-                .setString(GROUP, group.asString()))
-            .map(row -> EventDeadLetters.InsertionId.of(row.getUUID(INSERTION_ID)));
-    }
-
-    Mono<Boolean> containEvents() {
-        return executor.executeReturnExists(containEventsStatement.bind());
-    }
-
-    private Event deserializeEvent(String serializedEvent) {
-        return eventSerializer.fromJson(serializedEvent).get();
-    }
-}
diff --git a/mailbox/event/event-cassandra/src/main/java/org/apache/james/mailbox/events/CassandraEventDeadLettersGroupDAO.java b/mailbox/event/event-cassandra/src/main/java/org/apache/james/mailbox/events/CassandraEventDeadLettersGroupDAO.java
deleted file mode 100644
index 20b283e..0000000
--- a/mailbox/event/event-cassandra/src/main/java/org/apache/james/mailbox/events/CassandraEventDeadLettersGroupDAO.java
+++ /dev/null
@@ -1,71 +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.mailbox.events;
-
-import static com.datastax.driver.core.querybuilder.QueryBuilder.bindMarker;
-import static com.datastax.driver.core.querybuilder.QueryBuilder.insertInto;
-import static com.datastax.driver.core.querybuilder.QueryBuilder.select;
-import static org.apache.james.mailbox.events.tables.CassandraEventDeadLettersGroupTable.GROUP;
-import static org.apache.james.mailbox.events.tables.CassandraEventDeadLettersGroupTable.TABLE_NAME;
-
-import javax.inject.Inject;
-
-import org.apache.james.backends.cassandra.utils.CassandraAsyncExecutor;
-import org.apache.james.events.Group;
-
-import com.datastax.driver.core.PreparedStatement;
-import com.datastax.driver.core.Session;
-import com.github.fge.lambdas.Throwing;
-
-import reactor.core.publisher.Flux;
-import reactor.core.publisher.Mono;
-
-public class CassandraEventDeadLettersGroupDAO {
-    private final CassandraAsyncExecutor executor;
-    private final PreparedStatement insertStatement;
-    private final PreparedStatement selectAllStatement;
-
-    @Inject
-    CassandraEventDeadLettersGroupDAO(Session session) {
-        this.executor = new CassandraAsyncExecutor(session);
-        this.insertStatement = prepareInsertStatement(session);
-        this.selectAllStatement = prepareSelectStatement(session);
-    }
-
-    private PreparedStatement prepareInsertStatement(Session session) {
-        return session.prepare(insertInto(TABLE_NAME)
-            .value(GROUP, bindMarker(GROUP)));
-    }
-
-    private PreparedStatement prepareSelectStatement(Session session) {
-        return session.prepare(select(GROUP)
-            .from(TABLE_NAME));
-    }
-
-    Mono<Void> storeGroup(Group group) {
-        return executor.executeVoid(insertStatement.bind()
-                .setString(GROUP, group.asString()));
-    }
-
-    Flux<Group> retrieveAllGroups() {
-        return executor.executeRows(selectAllStatement.bind())
-            .map(Throwing.function(row -> Group.deserialize(row.getString(GROUP))));
-    }
-}
diff --git a/mailbox/event/event-cassandra/src/main/java/org/apache/james/mailbox/events/CassandraEventDeadLettersModule.java b/mailbox/event/event-cassandra/src/main/java/org/apache/james/mailbox/events/CassandraEventDeadLettersModule.java
deleted file mode 100644
index 6c4095c..0000000
--- a/mailbox/event/event-cassandra/src/main/java/org/apache/james/mailbox/events/CassandraEventDeadLettersModule.java
+++ /dev/null
@@ -1,46 +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.mailbox.events;
-
-import org.apache.james.backends.cassandra.components.CassandraModule;
-import org.apache.james.backends.cassandra.utils.CassandraConstants;
-import org.apache.james.mailbox.events.tables.CassandraEventDeadLettersGroupTable;
-import org.apache.james.mailbox.events.tables.CassandraEventDeadLettersTable;
-
-import com.datastax.driver.core.DataType;
-import com.datastax.driver.core.schemabuilder.SchemaBuilder;
-
-public interface CassandraEventDeadLettersModule {
-    CassandraModule MODULE = CassandraModule.builder()
-        .table(CassandraEventDeadLettersTable.TABLE_NAME)
-        .comment("Holds event dead letter")
-        .options(options -> options
-            .caching(SchemaBuilder.KeyCaching.ALL,
-                SchemaBuilder.rows(CassandraConstants.DEFAULT_CACHED_ROW_PER_PARTITION)))
-        .statement(statement -> statement
-            .addPartitionKey(CassandraEventDeadLettersTable.GROUP, DataType.text())
-            .addClusteringColumn(CassandraEventDeadLettersTable.INSERTION_ID, DataType.uuid())
-            .addColumn(CassandraEventDeadLettersTable.EVENT, DataType.text()))
-        .table(CassandraEventDeadLettersGroupTable.TABLE_NAME)
-        .comment("Projection table for retrieving groups for all failed events")
-        .statement(statement -> statement
-            .addPartitionKey(CassandraEventDeadLettersGroupTable.GROUP, DataType.text()))
-        .build();
-}
diff --git a/mailbox/event/event-cassandra/src/main/java/org/apache/james/mailbox/events/tables/CassandraEventDeadLettersGroupTable.java b/mailbox/event/event-cassandra/src/main/java/org/apache/james/mailbox/events/tables/CassandraEventDeadLettersGroupTable.java
deleted file mode 100644
index b1d6219..0000000
--- a/mailbox/event/event-cassandra/src/main/java/org/apache/james/mailbox/events/tables/CassandraEventDeadLettersGroupTable.java
+++ /dev/null
@@ -1,27 +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.mailbox.events.tables;
-
-public interface CassandraEventDeadLettersGroupTable {
-
-    String TABLE_NAME = "group_table";
-
-    String GROUP = "group";
-}
diff --git a/mailbox/event/event-cassandra/src/main/java/org/apache/james/mailbox/events/tables/CassandraEventDeadLettersTable.java b/mailbox/event/event-cassandra/src/main/java/org/apache/james/mailbox/events/tables/CassandraEventDeadLettersTable.java
deleted file mode 100644
index cbf272c..0000000
--- a/mailbox/event/event-cassandra/src/main/java/org/apache/james/mailbox/events/tables/CassandraEventDeadLettersTable.java
+++ /dev/null
@@ -1,29 +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.mailbox.events.tables;
-
-public interface CassandraEventDeadLettersTable {
-
-    String TABLE_NAME = "event_dead_letters";
-
-    String GROUP = "group";
-    String INSERTION_ID = "insertionId";
-    String EVENT = "event";
-}
diff --git a/mailbox/event/event-cassandra/src/test/java/org/apache/james/mailbox/events/CassandraEventDeadLettersDAOTest.java b/mailbox/event/event-cassandra/src/test/java/org/apache/james/mailbox/events/CassandraEventDeadLettersDAOTest.java
deleted file mode 100644
index 35ab39f..0000000
--- a/mailbox/event/event-cassandra/src/test/java/org/apache/james/mailbox/events/CassandraEventDeadLettersDAOTest.java
+++ /dev/null
@@ -1,145 +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.mailbox.events;
-
-import static org.apache.james.mailbox.events.EventDeadLettersContract.EVENT_1;
-import static org.apache.james.mailbox.events.EventDeadLettersContract.EVENT_2;
-import static org.apache.james.mailbox.events.EventDeadLettersContract.EVENT_3;
-import static org.apache.james.mailbox.events.EventDeadLettersContract.GROUP_A;
-import static org.apache.james.mailbox.events.EventDeadLettersContract.GROUP_B;
-import static org.apache.james.mailbox.events.EventDeadLettersContract.INSERTION_ID_1;
-import static org.apache.james.mailbox.events.EventDeadLettersContract.INSERTION_ID_2;
-import static org.apache.james.mailbox.events.EventDeadLettersContract.INSERTION_ID_3;
-import static org.assertj.core.api.Assertions.assertThat;
-
-import org.apache.james.backends.cassandra.CassandraCluster;
-import org.apache.james.backends.cassandra.CassandraClusterExtension;
-import org.apache.james.event.json.EventSerializer;
-import org.apache.james.mailbox.model.TestId;
-import org.apache.james.mailbox.model.TestMessageId;
-import org.apache.james.mailbox.store.quota.DefaultUserQuotaRootResolver;
-import org.junit.jupiter.api.BeforeEach;
-import org.junit.jupiter.api.Test;
-import org.junit.jupiter.api.extension.RegisterExtension;
-
-class CassandraEventDeadLettersDAOTest {
-
-    @RegisterExtension
-    static CassandraClusterExtension cassandraClusterExtension = new CassandraClusterExtension(CassandraEventDeadLettersModule.MODULE);
-
-    private CassandraEventDeadLettersDAO cassandraEventDeadLettersDAO;
-
-    @BeforeEach
-    void setUp(CassandraCluster cassandraCluster) {
-        EventSerializer eventSerializer = new EventSerializer(new TestId.Factory(), new TestMessageId.Factory(), new DefaultUserQuotaRootResolver.DefaultQuotaRootDeserializer());
-        cassandraEventDeadLettersDAO = new CassandraEventDeadLettersDAO(cassandraCluster.getConf(), eventSerializer);
-    }
-
-    @Test
-    void removeEventShouldSucceededWhenRemoveStoredEvent() {
-        cassandraEventDeadLettersDAO.store(GROUP_A, EVENT_1, INSERTION_ID_1).block();
-
-        cassandraEventDeadLettersDAO.removeEvent(GROUP_A, INSERTION_ID_1).block();
-
-        assertThat(cassandraEventDeadLettersDAO
-                .retrieveInsertionIdsWithGroup(GROUP_A)
-                .collectList().block())
-            .isEmpty();
-    }
-
-    @Test
-    void retrieveFailedEventShouldReturnEmptyWhenDefault() {
-        assertThat(cassandraEventDeadLettersDAO
-                .retrieveFailedEvent(GROUP_A, INSERTION_ID_1)
-                .blockOptional().isPresent())
-            .isFalse();
-    }
-
-    @Test
-    void retrieveFailedEventShouldReturnStoredEvent() {
-        cassandraEventDeadLettersDAO.store(GROUP_A, EVENT_1, INSERTION_ID_1).block();
-        cassandraEventDeadLettersDAO.store(GROUP_B, EVENT_2, INSERTION_ID_2).block();
-
-        assertThat(cassandraEventDeadLettersDAO
-                .retrieveFailedEvent(GROUP_B, INSERTION_ID_2)
-                .blockOptional().get())
-            .isEqualTo(EVENT_2);
-    }
-
-    @Test
-    void retrieveInsertionIdsWithGroupShouldReturnEmptyWhenDefault() {
-        assertThat(cassandraEventDeadLettersDAO
-                .retrieveInsertionIdsWithGroup(GROUP_A)
-                .collectList().block())
-            .isEmpty();
-    }
-
-    @Test
-    void retrieveInsertionIdsWithGroupShouldReturnStoredInsertionId() {
-        cassandraEventDeadLettersDAO.store(GROUP_B, EVENT_1, INSERTION_ID_1).block();
-        cassandraEventDeadLettersDAO.store(GROUP_B, EVENT_2, INSERTION_ID_2).block();
-        cassandraEventDeadLettersDAO.store(GROUP_B, EVENT_3, INSERTION_ID_3).block();
-
-        assertThat(cassandraEventDeadLettersDAO
-                .retrieveInsertionIdsWithGroup(GROUP_B)
-                .collectList().block())
-            .containsOnly(INSERTION_ID_1, INSERTION_ID_2, INSERTION_ID_3);
-    }
-
-    @Test
-    void shouldReturnTrueWhenEventStored() {
-        cassandraEventDeadLettersDAO.store(GROUP_B, EVENT_1, INSERTION_ID_1).block();
-        assertThat(cassandraEventDeadLettersDAO.containEvents().block()).isTrue();
-    }
-
-    @Test
-    void shouldReturnTrueWhenNoEventStored() {
-        assertThat(cassandraEventDeadLettersDAO.containEvents().block()).isFalse();
-    }
-
-    @Test
-    void shouldReturnTrueWhenEventsStoredAndRemovedSome() {
-        cassandraEventDeadLettersDAO.store(GROUP_B, EVENT_1, INSERTION_ID_1).block();
-        cassandraEventDeadLettersDAO.store(GROUP_B, EVENT_1, INSERTION_ID_2).block();
-        cassandraEventDeadLettersDAO.store(GROUP_B, EVENT_1, INSERTION_ID_3).block();
-
-        assertThat(cassandraEventDeadLettersDAO.containEvents().block()).isTrue();
-
-        cassandraEventDeadLettersDAO.removeEvent(GROUP_B, INSERTION_ID_3).block();
-
-        assertThat(cassandraEventDeadLettersDAO.containEvents().block()).isTrue();
-    }
-
-    @Test
-    void shouldReturnFalseWhenRemovedAllEventsStored() {
-        cassandraEventDeadLettersDAO.store(GROUP_B, EVENT_1, INSERTION_ID_1).block();
-        cassandraEventDeadLettersDAO.store(GROUP_B, EVENT_1, INSERTION_ID_2).block();
-        cassandraEventDeadLettersDAO.store(GROUP_B, EVENT_1, INSERTION_ID_3).block();
-
-        assertThat(cassandraEventDeadLettersDAO.containEvents().block()).isTrue();
-
-        cassandraEventDeadLettersDAO.removeEvent(GROUP_B, INSERTION_ID_3).block();
-        cassandraEventDeadLettersDAO.removeEvent(GROUP_B, INSERTION_ID_2).block();
-        cassandraEventDeadLettersDAO.removeEvent(GROUP_B, INSERTION_ID_1).block();
-
-        assertThat(cassandraEventDeadLettersDAO.containEvents().block()).isFalse();
-    }
-
-}
diff --git a/mailbox/event/event-cassandra/src/test/java/org/apache/james/mailbox/events/CassandraEventDeadLettersGroupDAOTest.java b/mailbox/event/event-cassandra/src/test/java/org/apache/james/mailbox/events/CassandraEventDeadLettersGroupDAOTest.java
deleted file mode 100644
index c5bc092..0000000
--- a/mailbox/event/event-cassandra/src/test/java/org/apache/james/mailbox/events/CassandraEventDeadLettersGroupDAOTest.java
+++ /dev/null
@@ -1,60 +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.mailbox.events;
-
-import static org.apache.james.mailbox.events.EventDeadLettersContract.GROUP_A;
-import static org.apache.james.mailbox.events.EventDeadLettersContract.GROUP_B;
-import static org.assertj.core.api.Assertions.assertThat;
-
-import org.apache.james.backends.cassandra.CassandraCluster;
-import org.apache.james.backends.cassandra.CassandraClusterExtension;
-import org.junit.jupiter.api.BeforeAll;
-import org.junit.jupiter.api.Test;
-import org.junit.jupiter.api.extension.RegisterExtension;
-
-public class CassandraEventDeadLettersGroupDAOTest {
-
-    @RegisterExtension
-    static CassandraClusterExtension cassandraClusterExtension = new CassandraClusterExtension(CassandraEventDeadLettersModule.MODULE);
-
-    private static CassandraEventDeadLettersGroupDAO GROUP_DAO;
-
-    @BeforeAll
-    static void setUp(CassandraCluster cassandraCluster) {
-        GROUP_DAO = new CassandraEventDeadLettersGroupDAO(cassandraCluster.getConf());
-    }
-
-    @Test
-    void retrieveAllGroupsShouldReturnEmptyWhenDefault() {
-        assertThat(GROUP_DAO.retrieveAllGroups()
-                .collectList().block())
-            .isEmpty();
-    }
-
-    @Test
-    void retrieveAllGroupsShouldReturnStoredGroups() {
-        GROUP_DAO.storeGroup(GROUP_A).block();
-        GROUP_DAO.storeGroup(GROUP_B).block();
-
-        assertThat(GROUP_DAO.retrieveAllGroups()
-                .collectList().block())
-            .containsOnly(GROUP_A, GROUP_B);
-    }
-}
diff --git a/mailbox/event/event-cassandra/src/test/java/org/apache/james/mailbox/events/CassandraEventDeadLettersHealthCheckTest.java b/mailbox/event/event-cassandra/src/test/java/org/apache/james/mailbox/events/CassandraEventDeadLettersHealthCheckTest.java
deleted file mode 100644
index 027ad73..0000000
--- a/mailbox/event/event-cassandra/src/test/java/org/apache/james/mailbox/events/CassandraEventDeadLettersHealthCheckTest.java
+++ /dev/null
@@ -1,70 +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.mailbox.events;
-
-import org.apache.james.backends.cassandra.CassandraCluster;
-import org.apache.james.backends.cassandra.CassandraClusterExtension;
-import org.apache.james.backends.cassandra.DockerCassandra;
-import org.apache.james.event.json.EventSerializer;
-import org.apache.james.events.EventDeadLetters;
-import org.apache.james.events.EventDeadLettersHealthCheck;
-import org.apache.james.mailbox.model.TestId;
-import org.apache.james.mailbox.model.TestMessageId;
-import org.apache.james.mailbox.store.quota.DefaultUserQuotaRootResolver;
-import org.junit.jupiter.api.BeforeEach;
-import org.junit.jupiter.api.extension.RegisterExtension;
-
-
-class CassandraEventDeadLettersHealthCheckTest implements EventDeadLettersHealthCheckContract {
-    @RegisterExtension
-    static CassandraClusterExtension cassandraClusterExtension = new CassandraClusterExtension(CassandraEventDeadLettersModule.MODULE);
-    private EventDeadLettersHealthCheck testee;
-    private CassandraEventDeadLetters eventDeadLetters;
-    private DockerCassandra dockerCassandra;
-
-    @BeforeEach
-    void setUp(CassandraCluster cassandraCluster, DockerCassandra dockerCassandra) {
-        EventSerializer eventSerializer = new EventSerializer(new TestId.Factory(), new TestMessageId.Factory(), new DefaultUserQuotaRootResolver.DefaultQuotaRootDeserializer());
-        eventDeadLetters = new CassandraEventDeadLetters(new CassandraEventDeadLettersDAO(cassandraCluster.getConf(), eventSerializer),
-                                                         new CassandraEventDeadLettersGroupDAO(cassandraCluster.getConf()));
-        testee = new EventDeadLettersHealthCheck(eventDeadLetters);
-        this.dockerCassandra = dockerCassandra;
-    }
-
-    @Override
-    public EventDeadLettersHealthCheck testee() {
-        return testee;
-    }
-
-    @Override
-    public EventDeadLetters eventDeadLetters() {
-        return eventDeadLetters;
-    }
-
-    @Override
-    public void createErrorWhenDoingHealthCheck() {
-        dockerCassandra.pause();
-    }
-
-    @Override
-    public void resolveErrorWhenDoingHealthCheck() {
-        dockerCassandra.unpause();
-    }
-}
diff --git a/mailbox/event/event-cassandra/src/test/java/org/apache/james/mailbox/events/CassandraEventDeadLettersTest.java b/mailbox/event/event-cassandra/src/test/java/org/apache/james/mailbox/events/CassandraEventDeadLettersTest.java
deleted file mode 100644
index 7d81bcd..0000000
--- a/mailbox/event/event-cassandra/src/test/java/org/apache/james/mailbox/events/CassandraEventDeadLettersTest.java
+++ /dev/null
@@ -1,50 +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.mailbox.events;
-
-import org.apache.james.backends.cassandra.CassandraCluster;
-import org.apache.james.backends.cassandra.CassandraClusterExtension;
-import org.apache.james.event.json.EventSerializer;
-import org.apache.james.events.EventDeadLetters;
-import org.apache.james.mailbox.model.TestId;
-import org.apache.james.mailbox.model.TestMessageId;
-import org.apache.james.mailbox.store.quota.DefaultUserQuotaRootResolver;
-import org.junit.jupiter.api.BeforeEach;
-import org.junit.jupiter.api.extension.RegisterExtension;
-
-class CassandraEventDeadLettersTest implements EventDeadLettersContract.AllContracts {
-
-    @RegisterExtension
-    static CassandraClusterExtension cassandraClusterExtension = new CassandraClusterExtension(CassandraEventDeadLettersModule.MODULE);
-
-    private CassandraEventDeadLetters eventDeadLetters;
-
-    @BeforeEach
-    void setUp(CassandraCluster cassandraCluster) {
-        EventSerializer eventSerializer = new EventSerializer(new TestId.Factory(), new TestMessageId.Factory(), new DefaultUserQuotaRootResolver.DefaultQuotaRootDeserializer());
-        eventDeadLetters = new CassandraEventDeadLetters(new CassandraEventDeadLettersDAO(cassandraCluster.getConf(), eventSerializer),
-                                                         new CassandraEventDeadLettersGroupDAO(cassandraCluster.getConf()));
-    }
-
-    @Override
-    public EventDeadLetters eventDeadLetters() {
-        return eventDeadLetters;
-    }
-}
diff --git a/mailbox/event/event-memory/pom.xml b/mailbox/event/event-memory/pom.xml
deleted file mode 100644
index e421778..0000000
--- a/mailbox/event/event-memory/pom.xml
+++ /dev/null
@@ -1,79 +0,0 @@
-<?xml version="1.0" encoding="UTF-8"?>
-<!--
-    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.
--->
-<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/maven-v4_0_0.xsd">
-    <modelVersion>4.0.0</modelVersion>
-
-    <parent>
-        <groupId>org.apache.james</groupId>
-        <artifactId>apache-james-mailbox</artifactId>
-        <version>3.6.0-SNAPSHOT</version>
-        <relativePath>../../pom.xml</relativePath>
-    </parent>
-
-    <artifactId>apache-james-mailbox-event-memory</artifactId>
-    <name>Apache James :: Mailbox :: Event :: In VM implementation</name>
-    <description>In VM implementation for the eventbus API</description>
-
-    <dependencies>
-        <dependency>
-            <groupId>${james.groupId}</groupId>
-            <artifactId>metrics-tests</artifactId>
-            <scope>test</scope>
-        </dependency>
-        <dependency>
-            <groupId>${james.groupId}</groupId>
-            <artifactId>testing-base</artifactId>
-            <scope>test</scope>
-        </dependency>
-        <dependency>
-            <groupId>${project.groupId}</groupId>
-            <artifactId>apache-james-mailbox-api</artifactId>
-        </dependency>
-        <dependency>
-            <groupId>${project.groupId}</groupId>
-            <artifactId>apache-james-mailbox-api</artifactId>
-            <type>test-jar</type>
-            <scope>test</scope>
-        </dependency>
-        <dependency>
-            <groupId>${project.groupId}</groupId>
-            <artifactId>james-server-util</artifactId>
-        </dependency>
-        <dependency>
-            <groupId>${project.groupId}</groupId>
-            <artifactId>metrics-api</artifactId>
-        </dependency>
-        <dependency>
-            <groupId>io.projectreactor</groupId>
-            <artifactId>reactor-core</artifactId>
-        </dependency>
-        <dependency>
-            <groupId>org.awaitility</groupId>
-            <artifactId>awaitility</artifactId>
-            <scope>test</scope>
-        </dependency>
-        <dependency>
-            <groupId>org.mockito</groupId>
-            <artifactId>mockito-core</artifactId>
-            <scope>test</scope>
-        </dependency>
-    </dependencies>
-
-</project>
diff --git a/mailbox/event/event-memory/src/main/java/org/apache/james/mailbox/events/InVMEventBus.java b/mailbox/event/event-memory/src/main/java/org/apache/james/mailbox/events/InVMEventBus.java
deleted file mode 100644
index 1e92333..0000000
--- a/mailbox/event/event-memory/src/main/java/org/apache/james/mailbox/events/InVMEventBus.java
+++ /dev/null
@@ -1,134 +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.mailbox.events;
-
-import java.util.Optional;
-import java.util.Set;
-import java.util.concurrent.ConcurrentHashMap;
-
-import javax.inject.Inject;
-
-import org.apache.james.events.Event;
-import org.apache.james.events.EventBus;
-import org.apache.james.events.EventDeadLetters;
-import org.apache.james.events.EventListener;
-import org.apache.james.events.Group;
-import org.apache.james.events.GroupAlreadyRegistered;
-import org.apache.james.events.GroupRegistrationNotFound;
-import org.apache.james.events.Registration;
-import org.apache.james.events.RegistrationKey;
-import org.apache.james.mailbox.events.delivery.EventDelivery;
-import org.apache.james.mailbox.events.delivery.EventDelivery.PermanentFailureHandler.StoreToDeadLetters;
-import org.apache.james.mailbox.events.delivery.EventDelivery.Retryer.BackoffRetryer;
-
-import com.github.steveash.guavate.Guavate;
-import com.google.common.collect.HashMultimap;
-import com.google.common.collect.Multimap;
-import com.google.common.collect.Multimaps;
-
-import reactor.core.publisher.Flux;
-import reactor.core.publisher.Mono;
-
-public class InVMEventBus implements EventBus {
-
-    private final Multimap<RegistrationKey, EventListener.ReactiveEventListener> registrations;
-    private final ConcurrentHashMap<Group, EventListener.ReactiveEventListener> groups;
-    private final EventDelivery eventDelivery;
-    private final RetryBackoffConfiguration retryBackoff;
-    private final EventDeadLetters eventDeadLetters;
-
-    @Inject
-    public InVMEventBus(EventDelivery eventDelivery, RetryBackoffConfiguration retryBackoff, EventDeadLetters eventDeadLetters) {
-        this.eventDelivery = eventDelivery;
-        this.retryBackoff = retryBackoff;
-        this.eventDeadLetters = eventDeadLetters;
-        this.registrations = Multimaps.synchronizedSetMultimap(HashMultimap.create());
-        this.groups = new ConcurrentHashMap<>();
-    }
-
-    @Override
-    public Mono<Registration> register(EventListener.ReactiveEventListener listener, RegistrationKey key) {
-        registrations.put(key, listener);
-        return Mono.just(() -> registrations.remove(key, listener));
-    }
-
-    @Override
-    public Registration register(EventListener.ReactiveEventListener listener, Group group) {
-        EventListener previous = groups.putIfAbsent(group, listener);
-        if (previous == null) {
-            return () -> groups.remove(group, listener);
-        }
-        throw new GroupAlreadyRegistered(group);
-    }
-
-    @Override
-    public Mono<Void> dispatch(Event event, Set<RegistrationKey> keys) {
-        if (!event.isNoop()) {
-            return Flux.merge(groupDeliveries(event), keyDeliveries(event, keys))
-                .then()
-                .onErrorResume(throwable -> Mono.empty());
-        }
-        return Mono.empty();
-    }
-
-    @Override
-    public Mono<Void> reDeliver(Group group, Event event) {
-        if (!event.isNoop()) {
-            return groupDelivery(event, retrieveListenerFromGroup(group), group);
-        }
-        return Mono.empty();
-    }
-
-    private EventListener.ReactiveEventListener retrieveListenerFromGroup(Group group) {
-        return Optional.ofNullable(groups.get(group))
-            .orElseThrow(() -> new GroupRegistrationNotFound(group));
-    }
-
-    private Mono<Void> keyDeliveries(Event event, Set<RegistrationKey> keys) {
-        return Flux.fromIterable(registeredListenersByKeys(keys))
-            .flatMap(listener -> eventDelivery.deliver(listener, event, EventDelivery.DeliveryOption.none()), EventBus.EXECUTION_RATE)
-            .then();
-    }
-
-    private Mono<Void> groupDeliveries(Event event) {
-        return Flux.fromIterable(groups.entrySet())
-            .flatMap(entry -> groupDelivery(event, entry.getValue(), entry.getKey()), EventBus.EXECUTION_RATE)
-            .then();
-    }
-
-    private Mono<Void> groupDelivery(Event event, EventListener.ReactiveEventListener mailboxListener, Group group) {
-        return eventDelivery.deliver(
-            mailboxListener,
-            event,
-            EventDelivery.DeliveryOption.of(
-                BackoffRetryer.of(retryBackoff, mailboxListener),
-                StoreToDeadLetters.of(group, eventDeadLetters)));
-    }
-
-    public Set<Group> registeredGroups() {
-        return groups.keySet();
-    }
-
-    private Set<EventListener.ReactiveEventListener> registeredListenersByKeys(Set<RegistrationKey> keys) {
-        return keys.stream()
-            .flatMap(registrationKey -> registrations.get(registrationKey).stream())
-            .collect(Guavate.toImmutableSet());
-    }
-}
diff --git a/mailbox/event/event-memory/src/main/java/org/apache/james/mailbox/events/MemoryEventDeadLetters.java b/mailbox/event/event-memory/src/main/java/org/apache/james/mailbox/events/MemoryEventDeadLetters.java
deleted file mode 100644
index b11e26f..0000000
--- a/mailbox/event/event-memory/src/main/java/org/apache/james/mailbox/events/MemoryEventDeadLetters.java
+++ /dev/null
@@ -1,95 +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.mailbox.events;
-
-import org.apache.james.events.Event;
-import org.apache.james.events.EventDeadLetters;
-import org.apache.james.events.Group;
-
-import com.google.common.base.Preconditions;
-import com.google.common.collect.HashBasedTable;
-import com.google.common.collect.ImmutableList;
-import com.google.common.collect.Table;
-
-import reactor.core.publisher.Flux;
-import reactor.core.publisher.Mono;
-
-public class MemoryEventDeadLetters implements EventDeadLetters {
-
-    private final Table<Group, InsertionId, Event> deadLetters;
-
-    public MemoryEventDeadLetters() {
-        this.deadLetters = HashBasedTable.create();
-    }
-
-    @Override
-    public Mono<InsertionId> store(Group registeredGroup, Event failDeliveredEvent) {
-        Preconditions.checkArgument(registeredGroup != null, REGISTERED_GROUP_CANNOT_BE_NULL);
-        Preconditions.checkArgument(failDeliveredEvent != null, FAIL_DELIVERED_EVENT_CANNOT_BE_NULL);
-
-        InsertionId insertionId = InsertionId.random();
-        synchronized (deadLetters) {
-            deadLetters.put(registeredGroup, insertionId, failDeliveredEvent);
-            return Mono.just(insertionId);
-        }
-    }
-
-    @Override
-    public Mono<Void> remove(Group registeredGroup, InsertionId failDeliveredInsertionId) {
-        Preconditions.checkArgument(registeredGroup != null, REGISTERED_GROUP_CANNOT_BE_NULL);
-        Preconditions.checkArgument(failDeliveredInsertionId != null, FAIL_DELIVERED_ID_INSERTION_CANNOT_BE_NULL);
-
-        synchronized (deadLetters) {
-            deadLetters.remove(registeredGroup, failDeliveredInsertionId);
-            return Mono.empty();
-        }
-    }
-
-    @Override
-    public Mono<Event> failedEvent(Group registeredGroup, InsertionId failDeliveredInsertionId) {
-        Preconditions.checkArgument(registeredGroup != null, REGISTERED_GROUP_CANNOT_BE_NULL);
-        Preconditions.checkArgument(failDeliveredInsertionId != null, FAIL_DELIVERED_ID_INSERTION_CANNOT_BE_NULL);
-
-        synchronized (deadLetters) {
-            return Mono.justOrEmpty(deadLetters.get(registeredGroup, failDeliveredInsertionId));
-        }
-    }
-
-    @Override
-    public Flux<InsertionId> failedIds(Group registeredGroup) {
-        Preconditions.checkArgument(registeredGroup != null, REGISTERED_GROUP_CANNOT_BE_NULL);
-
-        synchronized (deadLetters) {
-            return Flux.fromIterable(ImmutableList.copyOf(deadLetters.row(registeredGroup).keySet()));
-        }
-    }
-
-    @Override
-    public Flux<Group> groupsWithFailedEvents() {
-        synchronized (deadLetters) {
-            return Flux.fromIterable(ImmutableList.copyOf(deadLetters.rowKeySet()));
-        }
-    }
-
-    @Override
-    public Mono<Boolean> containEvents() {
-        return Mono.just(!deadLetters.isEmpty());
-    }
-}
diff --git a/mailbox/event/event-memory/src/main/java/org/apache/james/mailbox/events/delivery/EventDelivery.java b/mailbox/event/event-memory/src/main/java/org/apache/james/mailbox/events/delivery/EventDelivery.java
deleted file mode 100644
index c0038ca..0000000
--- a/mailbox/event/event-memory/src/main/java/org/apache/james/mailbox/events/delivery/EventDelivery.java
+++ /dev/null
@@ -1,134 +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.mailbox.events.delivery;
-
-import static org.apache.james.mailbox.events.delivery.EventDelivery.PermanentFailureHandler.NO_HANDLER;
-import static org.apache.james.mailbox.events.delivery.EventDelivery.Retryer.NO_RETRYER;
-
-import org.apache.james.events.Event;
-import org.apache.james.events.EventDeadLetters;
-import org.apache.james.events.EventListener;
-import org.apache.james.events.Group;
-import org.apache.james.mailbox.events.RetryBackoffConfiguration;
-import org.slf4j.Logger;
-import org.slf4j.LoggerFactory;
-
-import reactor.core.publisher.Mono;
-import reactor.core.scheduler.Schedulers;
-import reactor.util.retry.Retry;
-
-public interface EventDelivery {
-
-    class DeliveryOption {
-        public static DeliveryOption of(Retryer retrier, PermanentFailureHandler permanentFailureHandler) {
-            return new DeliveryOption(retrier, permanentFailureHandler);
-        }
-
-        public static DeliveryOption none() {
-            return new DeliveryOption(NO_RETRYER, NO_HANDLER);
-        }
-
-        private final Retryer retrier;
-        private final PermanentFailureHandler permanentFailureHandler;
-
-        private DeliveryOption(Retryer retrier, PermanentFailureHandler permanentFailureHandler) {
-            this.retrier = retrier;
-            this.permanentFailureHandler = permanentFailureHandler;
-        }
-
-        Retryer getRetrier() {
-            return retrier;
-        }
-
-        PermanentFailureHandler getPermanentFailureHandler() {
-            return permanentFailureHandler;
-        }
-    }
-
-
-    interface Retryer {
-
-        Retryer NO_RETRYER = (executionResult, event) -> executionResult;
-
-        class BackoffRetryer implements EventDelivery.Retryer {
-
-            public static BackoffRetryer of(RetryBackoffConfiguration retryBackoff, EventListener mailboxListener) {
-                return new BackoffRetryer(retryBackoff, mailboxListener);
-            }
-
-            private static final Logger LOGGER = LoggerFactory.getLogger(BackoffRetryer.class);
-
-            private final RetryBackoffConfiguration retryBackoff;
-            private final EventListener mailboxListener;
-
-            public BackoffRetryer(RetryBackoffConfiguration retryBackoff, EventListener mailboxListener) {
-                this.retryBackoff = retryBackoff;
-                this.mailboxListener = mailboxListener;
-            }
-
-            @Override
-            public Mono<Void> doRetry(Mono<Void> executionResult, Event event) {
-                return executionResult
-                    .retryWhen(Retry.backoff(retryBackoff.getMaxRetries(), retryBackoff.getFirstBackoff()).jitter(retryBackoff.getJitterFactor()).scheduler(Schedulers.elastic()))
-                    .doOnError(throwable -> LOGGER.error("listener {} exceeded maximum retry({}) to handle event {}",
-                        mailboxListener.getClass().getCanonicalName(),
-                        retryBackoff.getMaxRetries(),
-                        event.getClass().getCanonicalName(),
-                        throwable))
-                    .then();
-            }
-        }
-
-        Mono<Void> doRetry(Mono<Void> executionResult, Event event);
-    }
-
-    interface PermanentFailureHandler {
-
-        PermanentFailureHandler NO_HANDLER = event -> Mono.error(new UnsupportedOperationException("doesn't handle error"));
-
-        class StoreToDeadLetters implements EventDelivery.PermanentFailureHandler {
-
-            public static StoreToDeadLetters of(Group group, EventDeadLetters eventDeadLetters) {
-                return new StoreToDeadLetters(group, eventDeadLetters);
-            }
-
-            private final Group group;
-            private final EventDeadLetters eventDeadLetters;
-
-            private StoreToDeadLetters(Group group, EventDeadLetters eventDeadLetters) {
-                this.group = group;
-                this.eventDeadLetters = eventDeadLetters;
-            }
-
-            @Override
-            public Mono<Void> handle(Event event) {
-                return eventDeadLetters.store(group, event).then();
-            }
-        }
-
-        Mono<Void> handle(Event event);
-    }
-
-    Mono<Void> deliver(EventListener.ReactiveEventListener listener, Event event, DeliveryOption option);
-
-    default Mono<Void> deliver(EventListener listener, Event event, DeliveryOption option) {
-        return deliver(EventListener.wrapReactive(listener), event, option);
-    }
-}
diff --git a/mailbox/event/event-memory/src/main/java/org/apache/james/mailbox/events/delivery/InVmEventDelivery.java b/mailbox/event/event-memory/src/main/java/org/apache/james/mailbox/events/delivery/InVmEventDelivery.java
deleted file mode 100644
index e8ed94c..0000000
--- a/mailbox/event/event-memory/src/main/java/org/apache/james/mailbox/events/delivery/InVmEventDelivery.java
+++ /dev/null
@@ -1,104 +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.mailbox.events.delivery;
-
-import static org.apache.james.events.EventBus.Metrics.timerName;
-import static org.apache.james.util.ReactorUtils.context;
-
-import javax.inject.Inject;
-
-import org.apache.james.events.Event;
-import org.apache.james.events.EventBus;
-import org.apache.james.events.EventListener;
-import org.apache.james.metrics.api.MetricFactory;
-import org.apache.james.util.MDCBuilder;
-import org.apache.james.util.MDCStructuredLogger;
-import org.apache.james.util.StructuredLogger;
-import org.slf4j.Logger;
-import org.slf4j.LoggerFactory;
-
-import com.google.common.annotations.VisibleForTesting;
-
-import reactor.core.publisher.Flux;
-import reactor.core.publisher.Mono;
-
-public class InVmEventDelivery implements EventDelivery {
-    private static final Logger LOGGER = LoggerFactory.getLogger(InVmEventDelivery.class);
-
-    private final MetricFactory metricFactory;
-
-    @Inject
-    @VisibleForTesting
-    public InVmEventDelivery(MetricFactory metricFactory) {
-        this.metricFactory = metricFactory;
-    }
-
-    @Override
-    public Mono<Void> deliver(EventListener.ReactiveEventListener listener, Event event, DeliveryOption option) {
-        Mono<Void> executionResult = deliverByOption(listener, event, option);
-
-        return waitForResultIfNeeded(listener.getExecutionMode(), executionResult);
-    }
-
-    private Mono<Void> waitForResultIfNeeded(EventListener.ExecutionMode executionMode, Mono<Void> executionResult) {
-        if (executionMode.equals(EventListener.ExecutionMode.SYNCHRONOUS)) {
-            return executionResult;
-        }
-        return Flux.merge(executionResult, Mono.empty())
-            .publishNext()
-            .onErrorResume(throwable -> Mono.empty());
-    }
-
-    private Mono<Void> deliverByOption(EventListener.ReactiveEventListener listener, Event event, DeliveryOption deliveryOption) {
-        Mono<Void> deliveryToListener = doDeliverToListener(listener, event)
-            .doOnError(throwable -> structuredLogger(event, listener)
-                .log(logger -> logger.error("Error while processing listener", throwable)))
-            .then();
-
-        return deliveryOption.getRetrier().doRetry(deliveryToListener, event)
-            .onErrorResume(throwable -> deliveryOption.getPermanentFailureHandler().handle(event))
-            .then();
-    }
-
-    private Mono<Void> doDeliverToListener(EventListener.ReactiveEventListener mailboxListener, Event event) {
-        if (mailboxListener.isHandling(event)) {
-            return Mono.defer(() -> Mono.from(metricFactory.decoratePublisherWithTimerMetric(timerName(mailboxListener),
-                    mailboxListener.reactiveEvent(event))))
-                .subscriberContext(context("deliver", buildMDC(mailboxListener, event)));
-        }
-        return Mono.empty();
-    }
-
-    private MDCBuilder buildMDC(EventListener mailboxListener, Event event) {
-        return MDCBuilder.create()
-            .addContext(EventBus.StructuredLoggingFields.EVENT_ID, event.getEventId())
-            .addContext(EventBus.StructuredLoggingFields.EVENT_CLASS, event.getClass())
-            .addContext(EventBus.StructuredLoggingFields.USER, event.getUsername())
-            .addContext(EventBus.StructuredLoggingFields.LISTENER_CLASS, mailboxListener.getClass());
-    }
-
-    private StructuredLogger structuredLogger(Event event, EventListener mailboxListener) {
-        return MDCStructuredLogger.forLogger(LOGGER)
-            .addField(EventBus.StructuredLoggingFields.EVENT_ID, event.getEventId())
-            .addField(EventBus.StructuredLoggingFields.EVENT_CLASS, event.getClass())
-            .addField(EventBus.StructuredLoggingFields.USER, event.getUsername())
-            .addField(EventBus.StructuredLoggingFields.LISTENER_CLASS, mailboxListener.getClass());
-    }
-}
diff --git a/mailbox/event/event-memory/src/test/java/org/apache/james/mailbox/events/InVMEventBusTest.java b/mailbox/event/event-memory/src/test/java/org/apache/james/mailbox/events/InVMEventBusTest.java
deleted file mode 100644
index c12963f..0000000
--- a/mailbox/event/event-memory/src/test/java/org/apache/james/mailbox/events/InVMEventBusTest.java
+++ /dev/null
@@ -1,55 +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.mailbox.events;
-
-import org.apache.james.events.EventBus;
-import org.apache.james.events.EventDeadLetters;
-import org.apache.james.mailbox.events.delivery.InVmEventDelivery;
-import org.apache.james.metrics.tests.RecordingMetricFactory;
-import org.junit.jupiter.api.BeforeEach;
-
-public class InVMEventBusTest implements KeyContract.SingleEventBusKeyContract, GroupContract.SingleEventBusGroupContract,
-    ErrorHandlingContract {
-
-    private InVMEventBus eventBus;
-    private MemoryEventDeadLetters deadLetters;
-
-    @BeforeEach
-    void setUp() {
-        deadLetters = new MemoryEventDeadLetters();
-        eventBus = new InVMEventBus(
-            new InVmEventDelivery(new RecordingMetricFactory()), EventBusTestFixture.RETRY_BACKOFF_CONFIGURATION, deadLetters);
-    }
-
-    @Override
-    public EnvironmentSpeedProfile getSpeedProfile() {
-        return EnvironmentSpeedProfile.FAST;
-    }
-
-    @Override
-    public EventBus eventBus() {
-        return eventBus;
-    }
-
-    @Override
-    public EventDeadLetters deadLetter() {
-        return deadLetters;
-    }
-}
\ No newline at end of file
diff --git a/mailbox/event/event-memory/src/test/java/org/apache/james/mailbox/events/MemoryEventDeadLettersHealthCheckTest.java b/mailbox/event/event-memory/src/test/java/org/apache/james/mailbox/events/MemoryEventDeadLettersHealthCheckTest.java
deleted file mode 100644
index 58c4e7e..0000000
--- a/mailbox/event/event-memory/src/test/java/org/apache/james/mailbox/events/MemoryEventDeadLettersHealthCheckTest.java
+++ /dev/null
@@ -1,59 +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.mailbox.events;
-
-import org.apache.commons.lang3.NotImplementedException;
-import org.apache.james.events.EventDeadLetters;
-import org.apache.james.events.EventDeadLettersHealthCheck;
-import org.junit.jupiter.api.Disabled;
-import org.junit.jupiter.api.Test;
-
-public class MemoryEventDeadLettersHealthCheckTest implements EventDeadLettersHealthCheckContract {
-
-    private MemoryEventDeadLetters eventDeadLetters = new MemoryEventDeadLetters();
-    private EventDeadLettersHealthCheck testee = new EventDeadLettersHealthCheck(eventDeadLetters);
-
-    @Override
-    public EventDeadLettersHealthCheck testee() {
-        return testee;
-    }
-
-    @Override
-    public EventDeadLetters eventDeadLetters() {
-        return eventDeadLetters;
-    }
-
-    @Override
-    public void createErrorWhenDoingHealthCheck() {
-        throw new NotImplementedException("We can not instrument implementation this test case.");
-    }
-
-    @Override
-    public void resolveErrorWhenDoingHealthCheck() {
-        throw new NotImplementedException("We can not instrument implementation this test case.");
-    }
-
-    @Override
-    @Test
-    @Disabled("Unable to trigger the EventDeadLetter error with memory version")
-    public void checkShouldReturnUnHealthyWhenEventDeadLetterError() {
-
-    }
-}
diff --git a/mailbox/event/event-memory/src/test/java/org/apache/james/mailbox/events/MemoryEventDeadLettersTest.java b/mailbox/event/event-memory/src/test/java/org/apache/james/mailbox/events/MemoryEventDeadLettersTest.java
deleted file mode 100644
index 43ae3df..0000000
--- a/mailbox/event/event-memory/src/test/java/org/apache/james/mailbox/events/MemoryEventDeadLettersTest.java
+++ /dev/null
@@ -1,38 +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.mailbox.events;
-
-import org.apache.james.events.EventDeadLetters;
-import org.junit.jupiter.api.BeforeEach;
-
-class MemoryEventDeadLettersTest implements EventDeadLettersContract.AllContracts {
-
-    private MemoryEventDeadLetters eventDeadLetters;
-
-    @BeforeEach
-    void setUp() {
-        eventDeadLetters = new MemoryEventDeadLetters();
-    }
-
-    @Override
-    public EventDeadLetters eventDeadLetters() {
-        return eventDeadLetters;
-    }
-}
\ No newline at end of file
diff --git a/mailbox/event/event-memory/src/test/java/org/apache/james/mailbox/events/delivery/InVmEventDeliveryTest.java b/mailbox/event/event-memory/src/test/java/org/apache/james/mailbox/events/delivery/InVmEventDeliveryTest.java
deleted file mode 100644
index 72f779a..0000000
--- a/mailbox/event/event-memory/src/test/java/org/apache/james/mailbox/events/delivery/InVmEventDeliveryTest.java
+++ /dev/null
@@ -1,253 +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.mailbox.events.delivery;
-
-import static org.apache.james.mailbox.events.EventBusTestFixture.EVENT;
-import static org.apache.james.mailbox.events.EventBusTestFixture.EventListenerCountingSuccessfulExecution;
-import static org.apache.james.mailbox.events.EventBusTestFixture.GROUP_A;
-import static org.apache.james.mailbox.events.delivery.EventDelivery.Retryer;
-import static org.assertj.core.api.Assertions.assertThat;
-import static org.assertj.core.api.Assertions.assertThatCode;
-import static org.assertj.core.api.Assertions.assertThatThrownBy;
-import static org.mockito.Mockito.doThrow;
-import static org.mockito.Mockito.spy;
-import static org.mockito.Mockito.when;
-
-import java.time.Duration;
-
-import org.apache.james.events.EventListener;
-import org.apache.james.mailbox.events.MemoryEventDeadLetters;
-import org.apache.james.mailbox.events.RetryBackoffConfiguration;
-import org.apache.james.mailbox.events.delivery.EventDelivery.DeliveryOption;
-import org.apache.james.mailbox.events.delivery.EventDelivery.PermanentFailureHandler;
-import org.apache.james.mailbox.events.delivery.EventDelivery.Retryer.BackoffRetryer;
-import org.apache.james.metrics.tests.RecordingMetricFactory;
-import org.assertj.core.api.SoftAssertions;
-import org.junit.jupiter.api.BeforeEach;
-import org.junit.jupiter.api.Nested;
-import org.junit.jupiter.api.Test;
-
-class InVmEventDeliveryTest {
-    private InVmEventDelivery inVmEventDelivery;
-    private EventListenerCountingSuccessfulExecution listener;
-
-    @BeforeEach
-    void setUp() {
-        listener = newListener();
-        inVmEventDelivery = new InVmEventDelivery(new RecordingMetricFactory());
-    }
-
-    EventListenerCountingSuccessfulExecution newListener() {
-        return spy(new EventListenerCountingSuccessfulExecution());
-    }
-
-    @Nested
-    class SynchronousListener {
-
-        @Test
-        void deliverShouldDeliverEvent() {
-            when(listener.getExecutionMode()).thenReturn(EventListener.ExecutionMode.SYNCHRONOUS);
-            inVmEventDelivery.deliver(listener, EVENT, DeliveryOption.none())
-                .block();
-
-            assertThat(listener.numberOfEventCalls())
-                .isEqualTo(1);
-        }
-
-        @Test
-        void deliverShouldReturnSuccessSynchronousMono() {
-            when(listener.getExecutionMode()).thenReturn(EventListener.ExecutionMode.SYNCHRONOUS);
-            assertThatCode(() -> inVmEventDelivery.deliver(listener, EVENT, DeliveryOption.none())
-                    .block())
-                .doesNotThrowAnyException();
-        }
-
-        @Test
-        void deliverShouldNotDeliverWhenListenerGetException() {
-            when(listener.getExecutionMode()).thenReturn(EventListener.ExecutionMode.SYNCHRONOUS);
-            doThrow(new RuntimeException())
-                .when(listener).event(EVENT);
-
-            assertThatThrownBy(() -> inVmEventDelivery.deliver(listener, EVENT, DeliveryOption.none())
-                .block())
-            .isInstanceOf(RuntimeException.class);
-
-            assertThat(listener.numberOfEventCalls())
-                .isEqualTo(0);
-        }
-
-        @Test
-        void deliverShouldReturnAnErrorMonoWhenListenerGetException() {
-            when(listener.getExecutionMode()).thenReturn(EventListener.ExecutionMode.SYNCHRONOUS);
-            doThrow(new RuntimeException())
-                .when(listener).event(EVENT);
-
-            assertThatThrownBy(() -> inVmEventDelivery.deliver(listener, EVENT, DeliveryOption.none())
-                .block())
-            .isInstanceOf(RuntimeException.class);
-        }
-    }
-
-    @Nested
-    class AsynchronousListener {
-
-        @Test
-        void deliverShouldDeliverEvent() {
-            when(listener.getExecutionMode()).thenReturn(EventListener.ExecutionMode.ASYNCHRONOUS);
-            inVmEventDelivery.deliver(listener, EVENT, DeliveryOption.none())
-                .block();
-
-            assertThat(listener.numberOfEventCalls())
-                .isEqualTo(1);
-        }
-
-        @Test
-        void deliverShouldReturnSuccessSynchronousMono() {
-            when(listener.getExecutionMode()).thenReturn(EventListener.ExecutionMode.ASYNCHRONOUS);
-            assertThatCode(() -> inVmEventDelivery.deliver(listener, EVENT, DeliveryOption.none())
-                    .block())
-                .doesNotThrowAnyException();
-        }
-
-        @Test
-        void deliverShouldNotFailWhenListenerGetException() {
-            when(listener.getExecutionMode()).thenReturn(EventListener.ExecutionMode.ASYNCHRONOUS);
-            doThrow(new RuntimeException())
-                .when(listener).event(EVENT);
-
-            assertThatCode(() -> inVmEventDelivery.deliver(listener, EVENT, DeliveryOption.none())
-                .block())
-            .doesNotThrowAnyException();
-        }
-
-        @Test
-        void deliverShouldReturnAnSuccessSyncMonoWhenListenerGetException() {
-            when(listener.getExecutionMode()).thenReturn(EventListener.ExecutionMode.ASYNCHRONOUS);
-            doThrow(new RuntimeException())
-                .when(listener).event(EVENT);
-
-            assertThatCode(() -> inVmEventDelivery.deliver(listener, EVENT, DeliveryOption.none())
-                .block())
-            .doesNotThrowAnyException();
-        }
-    }
-
-    @Nested
-    class WithOptions {
-
-        @Test
-        void retryShouldWorkWhenDeliverWithRetry() {
-            EventListenerCountingSuccessfulExecution listener = newListener();
-            doThrow(new RuntimeException())
-                .doThrow(new RuntimeException())
-                .doThrow(new RuntimeException())
-                .doCallRealMethod()
-                .when(listener).event(EVENT);
-
-            inVmEventDelivery.deliver(listener, EVENT,
-                DeliveryOption.of(
-                    BackoffRetryer.of(RetryBackoffConfiguration.DEFAULT, listener),
-                    PermanentFailureHandler.NO_HANDLER))
-                .block();
-
-            assertThat(listener.numberOfEventCalls())
-                .isEqualTo(1);
-        }
-
-        @Test
-        void failureHandlerShouldWorkWhenDeliverWithFailureHandler() {
-            EventListenerCountingSuccessfulExecution listener = newListener();
-            doThrow(new RuntimeException())
-                .when(listener).event(EVENT);
-
-            MemoryEventDeadLetters deadLetter = new MemoryEventDeadLetters();
-
-            inVmEventDelivery.deliver(listener, EVENT,
-                DeliveryOption.of(
-                    Retryer.NO_RETRYER,
-                    PermanentFailureHandler.StoreToDeadLetters.of(GROUP_A, deadLetter)))
-                .block();
-
-            assertThat(deadLetter.groupsWithFailedEvents().toStream())
-                .containsOnly(GROUP_A);
-        }
-
-        @Test
-        void failureHandlerShouldNotWorkWhenRetrySuccess() {
-            EventListenerCountingSuccessfulExecution listener = newListener();
-            doThrow(new RuntimeException())
-                .doThrow(new RuntimeException())
-                .doCallRealMethod()
-                .when(listener).event(EVENT);
-
-            MemoryEventDeadLetters deadLetter = new MemoryEventDeadLetters();
-
-            inVmEventDelivery.deliver(listener, EVENT,
-                DeliveryOption.of(
-                    BackoffRetryer.of(RetryBackoffConfiguration.DEFAULT, listener),
-                    PermanentFailureHandler.StoreToDeadLetters.of(GROUP_A, deadLetter)))
-                .block();
-
-            SoftAssertions.assertSoftly(softy -> {
-                softy.assertThat(listener.numberOfEventCalls())
-                    .isEqualTo(1);
-                softy.assertThat(deadLetter.groupsWithFailedEvents().toStream())
-                    .isEmpty();
-            });
-        }
-
-
-        @Test
-        void failureHandlerShouldWorkWhenRetryFails() {
-            EventListenerCountingSuccessfulExecution listener = newListener();
-            //do throw  RetryBackoffConfiguration.DEFAULT.DEFAULT_MAX_RETRIES + 1 times
-            doThrow(new RuntimeException())
-                .doThrow(new RuntimeException())
-                .doThrow(new RuntimeException())
-                .doThrow(new RuntimeException())
-                .doThrow(new RuntimeException())
-                .doThrow(new RuntimeException())
-                .doThrow(new RuntimeException())
-                .doThrow(new RuntimeException())
-                .doThrow(new RuntimeException())
-                .doCallRealMethod()
-                .when(listener).event(EVENT);
-
-            MemoryEventDeadLetters deadLetter = new MemoryEventDeadLetters();
-
-            inVmEventDelivery.deliver(listener, EVENT,
-                DeliveryOption.of(
-                    BackoffRetryer.of(RetryBackoffConfiguration.builder()
-                            .maxRetries(8)
-                            .firstBackoff(Duration.ofMillis(1))
-                            .jitterFactor(0.2)
-                            .build(), listener),
-                    PermanentFailureHandler.StoreToDeadLetters.of(GROUP_A, deadLetter)))
-                .block();
-
-            SoftAssertions.assertSoftly(softy -> {
-                softy.assertThat(listener.numberOfEventCalls())
-                    .isEqualTo(0);
-                assertThat(deadLetter.groupsWithFailedEvents().toStream())
-                    .containsOnly(GROUP_A);
-            });
-        }
-    }
-}
diff --git a/mailbox/event/event-rabbitmq/pom.xml b/mailbox/event/event-rabbitmq/pom.xml
index 693abc4..cdb79b3 100644
--- a/mailbox/event/event-rabbitmq/pom.xml
+++ b/mailbox/event/event-rabbitmq/pom.xml
@@ -34,11 +34,6 @@
     <dependencies>
         <dependency>
             <groupId>${james.groupId}</groupId>
-            <artifactId>apache-james-mailbox-event-memory</artifactId>
-            <scope>test</scope>
-        </dependency>
-        <dependency>
-            <groupId>${james.groupId}</groupId>
             <artifactId>apache-james-mailbox-store</artifactId>
             <scope>test</scope>
         </dependency>
@@ -86,6 +81,11 @@
             <artifactId>apache-james-mailbox-event-json</artifactId>
         </dependency>
         <dependency>
+            <groupId>${james.groupId}</groupId>
+            <artifactId>event-bus-in-vm</artifactId>
+            <scope>test</scope>
+        </dependency>
+        <dependency>
             <groupId>${project.groupId}</groupId>
             <artifactId>metrics-api</artifactId>
         </dependency>
diff --git a/mailbox/event/event-rabbitmq/src/main/java/org/apache/james/mailbox/events/EventBusId.java b/mailbox/event/event-rabbitmq/src/main/java/org/apache/james/mailbox/events/EventBusId.java
deleted file mode 100644
index eb6c812..0000000
--- a/mailbox/event/event-rabbitmq/src/main/java/org/apache/james/mailbox/events/EventBusId.java
+++ /dev/null
@@ -1,72 +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.mailbox.events;
-
-import java.util.Objects;
-import java.util.UUID;
-
-import com.google.common.base.MoreObjects;
-import com.google.common.base.Preconditions;
-
-public class EventBusId {
-    public static EventBusId of(UUID uuid) {
-        return new EventBusId(uuid);
-    }
-
-    public static EventBusId random() {
-        return new EventBusId(UUID.randomUUID());
-    }
-
-    public static EventBusId of(String serialized) {
-        return new EventBusId(UUID.fromString(serialized));
-    }
-
-    private final UUID id;
-
-    private EventBusId(UUID id) {
-        Preconditions.checkNotNull(id);
-        this.id = id;
-    }
-
-    @Override
-    public final boolean equals(Object o) {
-        if (o instanceof EventBusId) {
-            EventBusId eventBusId = (EventBusId) o;
-            return Objects.equals(this.id, eventBusId.id);
-        }
-        return false;
-    }
-
-    public String asString() {
-        return id.toString();
-    }
-
-    @Override
-    public int hashCode() {
-        return Objects.hash(id);
-    }
-
-    @Override
-    public String toString() {
-        return MoreObjects.toStringHelper(this)
-            .add("id", id)
-            .toString();
-    }
-}
diff --git a/mailbox/event/event-rabbitmq/src/main/java/org/apache/james/mailbox/events/EventDispatcher.java b/mailbox/event/event-rabbitmq/src/main/java/org/apache/james/mailbox/events/EventDispatcher.java
deleted file mode 100644
index e7d1e62..0000000
--- a/mailbox/event/event-rabbitmq/src/main/java/org/apache/james/mailbox/events/EventDispatcher.java
+++ /dev/null
@@ -1,201 +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.mailbox.events;
-
-import static com.rabbitmq.client.MessageProperties.PERSISTENT_TEXT_PLAIN;
-import static org.apache.james.backends.rabbitmq.Constants.AUTO_DELETE;
-import static org.apache.james.backends.rabbitmq.Constants.DIRECT_EXCHANGE;
-import static org.apache.james.backends.rabbitmq.Constants.DURABLE;
-import static org.apache.james.backends.rabbitmq.Constants.EMPTY_ROUTING_KEY;
-import static org.apache.james.backends.rabbitmq.Constants.EXCLUSIVE;
-import static org.apache.james.backends.rabbitmq.Constants.NO_ARGUMENTS;
-import static org.apache.james.mailbox.events.RabbitMQEventBus.EVENT_BUS_ID;
-import static org.apache.james.mailbox.events.RabbitMQEventBus.MAILBOX_EVENT_DEAD_LETTER_EXCHANGE_NAME;
-import static org.apache.james.mailbox.events.RabbitMQEventBus.MAILBOX_EVENT_DEAD_LETTER_QUEUE;
-import static org.apache.james.mailbox.events.RabbitMQEventBus.MAILBOX_EVENT_EXCHANGE_NAME;
-
-import java.nio.charset.StandardCharsets;
-import java.util.Collection;
-import java.util.Collections;
-import java.util.Set;
-
-import org.apache.james.event.json.EventSerializer;
-import org.apache.james.events.Event;
-import org.apache.james.events.EventBus;
-import org.apache.james.events.EventDeadLetters;
-import org.apache.james.events.EventListener;
-import org.apache.james.events.Group;
-import org.apache.james.events.RegistrationKey;
-import org.apache.james.mailbox.events.RoutingKeyConverter.RoutingKey;
-import org.apache.james.util.MDCBuilder;
-import org.apache.james.util.MDCStructuredLogger;
-import org.apache.james.util.StructuredLogger;
-import org.slf4j.Logger;
-import org.slf4j.LoggerFactory;
-
-import com.github.steveash.guavate.Guavate;
-import com.google.common.collect.ImmutableMap;
-import com.google.common.collect.ImmutableSet;
-import com.rabbitmq.client.AMQP;
-
-import reactor.core.publisher.Flux;
-import reactor.core.publisher.Mono;
-import reactor.core.publisher.MonoProcessor;
-import reactor.rabbitmq.BindingSpecification;
-import reactor.rabbitmq.ExchangeSpecification;
-import reactor.rabbitmq.OutboundMessage;
-import reactor.rabbitmq.QueueSpecification;
-import reactor.rabbitmq.Sender;
-import reactor.util.function.Tuples;
-
-public class EventDispatcher {
-    public static class DispatchingFailureGroup extends Group {
-        public static DispatchingFailureGroup INSTANCE = new DispatchingFailureGroup();
-    }
-
-    private static final Logger LOGGER = LoggerFactory.getLogger(EventDispatcher.class);
-
-    private final EventSerializer eventSerializer;
-    private final Sender sender;
-    private final LocalListenerRegistry localListenerRegistry;
-    private final AMQP.BasicProperties basicProperties;
-    private final MailboxListenerExecutor mailboxListenerExecutor;
-    private final EventDeadLetters deadLetters;
-
-    EventDispatcher(EventBusId eventBusId, EventSerializer eventSerializer, Sender sender,
-                    LocalListenerRegistry localListenerRegistry,
-                    MailboxListenerExecutor mailboxListenerExecutor,
-                    EventDeadLetters deadLetters) {
-        this.eventSerializer = eventSerializer;
-        this.sender = sender;
-        this.localListenerRegistry = localListenerRegistry;
-        this.basicProperties = new AMQP.BasicProperties.Builder()
-            .headers(ImmutableMap.of(EVENT_BUS_ID, eventBusId.asString()))
-            .deliveryMode(PERSISTENT_TEXT_PLAIN.getDeliveryMode())
-            .priority(PERSISTENT_TEXT_PLAIN.getPriority())
-            .contentType(PERSISTENT_TEXT_PLAIN.getContentType())
-            .build();
-        this.mailboxListenerExecutor = mailboxListenerExecutor;
-        this.deadLetters = deadLetters;
-    }
-
-    void start() {
-        Flux.concat(
-            sender.declareExchange(ExchangeSpecification.exchange(MAILBOX_EVENT_EXCHANGE_NAME)
-                .durable(DURABLE)
-                .type(DIRECT_EXCHANGE)),
-            sender.declareExchange(ExchangeSpecification.exchange(MAILBOX_EVENT_DEAD_LETTER_EXCHANGE_NAME)
-                .durable(DURABLE)
-                .type(DIRECT_EXCHANGE)),
-            sender.declareQueue(QueueSpecification.queue(MAILBOX_EVENT_DEAD_LETTER_QUEUE)
-                .durable(DURABLE)
-                .exclusive(!EXCLUSIVE)
-                .autoDelete(!AUTO_DELETE)
-                .arguments(NO_ARGUMENTS)),
-            sender.bind(BindingSpecification.binding()
-                .exchange(MAILBOX_EVENT_DEAD_LETTER_EXCHANGE_NAME)
-                .queue(MAILBOX_EVENT_DEAD_LETTER_QUEUE)
-                .routingKey(EMPTY_ROUTING_KEY)))
-            .then()
-            .block();
-    }
-
-    Mono<Void> dispatch(Event event, Set<RegistrationKey> keys) {
-        return Flux
-            .concat(
-                dispatchToLocalListeners(event, keys),
-                dispatchToRemoteListeners(event, keys))
-            .doOnError(throwable -> LOGGER.error("error while dispatching event", throwable))
-            .then()
-            .subscribeWith(MonoProcessor.create());
-    }
-
-    private Mono<Void> dispatchToLocalListeners(Event event, Set<RegistrationKey> keys) {
-        return Flux.fromIterable(keys)
-            .flatMap(key -> localListenerRegistry.getLocalMailboxListeners(key)
-                .map(listener -> Tuples.of(key, listener)), EventBus.EXECUTION_RATE)
-            .filter(pair -> pair.getT2().getExecutionMode() == EventListener.ExecutionMode.SYNCHRONOUS)
-            .flatMap(pair -> executeListener(event, pair.getT2(), pair.getT1()), EventBus.EXECUTION_RATE)
-            .then();
-    }
-
-    private Mono<Void> executeListener(Event event, EventListener.ReactiveEventListener mailboxListener, RegistrationKey registrationKey) {
-        return mailboxListenerExecutor.execute(mailboxListener,
-                    MDCBuilder.create()
-                        .addContext(EventBus.StructuredLoggingFields.REGISTRATION_KEY, registrationKey),
-                    event)
-            .onErrorResume(e -> {
-                structuredLogger(event, ImmutableSet.of(registrationKey))
-                    .log(logger -> logger.error("Exception happens when dispatching event", e));
-                return Mono.empty();
-            });
-    }
-
-    private StructuredLogger structuredLogger(Event event, Set<RegistrationKey> keys) {
-        return MDCStructuredLogger.forLogger(LOGGER)
-            .addField(EventBus.StructuredLoggingFields.EVENT_ID, event.getEventId())
-            .addField(EventBus.StructuredLoggingFields.EVENT_CLASS, event.getClass())
-            .addField(EventBus.StructuredLoggingFields.USER, event.getUsername())
-            .addField(EventBus.StructuredLoggingFields.REGISTRATION_KEYS, keys);
-    }
-
-    private Mono<Void> dispatchToRemoteListeners(Event event, Set<RegistrationKey> keys) {
-        return Mono.fromCallable(() -> serializeEvent(event))
-            .flatMap(serializedEvent -> Mono.zipDelayError(
-                remoteGroupsDispatch(serializedEvent, event),
-                remoteKeysDispatch(serializedEvent, keys)))
-            .then();
-    }
-
-    private Mono<Void> remoteGroupsDispatch(byte[] serializedEvent, Event event) {
-        return remoteDispatch(serializedEvent, Collections.singletonList(RoutingKey.empty()))
-            .doOnError(ex -> LOGGER.error(
-                "cannot dispatch event of type '{}' belonging '{}' with id '{}' to remote groups, store it into dead letter",
-                event.getClass().getSimpleName(),
-                event.getUsername().asString(),
-                event.getEventId().getId(),
-                ex))
-            .onErrorResume(ex -> deadLetters.store(DispatchingFailureGroup.INSTANCE, event)
-                .then(Mono.error(ex)));
-    }
-
-    private Mono<Void> remoteKeysDispatch(byte[] serializedEvent, Set<RegistrationKey> keys) {
-        return remoteDispatch(serializedEvent,
-            keys.stream()
-                .map(RoutingKey::of)
-                .collect(Guavate.toImmutableList()));
-    }
-
-    private Mono<Void> remoteDispatch(byte[] serializedEvent, Collection<RoutingKey> routingKeys) {
-        if (routingKeys.isEmpty()) {
-            return Mono.empty();
-        }
-        return sender.send(toMessages(serializedEvent, routingKeys));
-    }
-
-    private Flux<OutboundMessage> toMessages(byte[] serializedEvent, Collection<RoutingKey> routingKeys) {
-        return Flux.fromIterable(routingKeys)
-                .map(routingKey -> new OutboundMessage(MAILBOX_EVENT_EXCHANGE_NAME, routingKey.asString(), basicProperties, serializedEvent));
-    }
-
-    private byte[] serializeEvent(Event event) {
-        return eventSerializer.toJson(event).getBytes(StandardCharsets.UTF_8);
-    }
-}
diff --git a/mailbox/event/event-rabbitmq/src/main/java/org/apache/james/mailbox/events/GroupConsumerRetry.java b/mailbox/event/event-rabbitmq/src/main/java/org/apache/james/mailbox/events/GroupConsumerRetry.java
deleted file mode 100644
index d74cc64..0000000
--- a/mailbox/event/event-rabbitmq/src/main/java/org/apache/james/mailbox/events/GroupConsumerRetry.java
+++ /dev/null
@@ -1,145 +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.mailbox.events;
-
-import static com.rabbitmq.client.MessageProperties.PERSISTENT_TEXT_PLAIN;
-import static org.apache.james.backends.rabbitmq.Constants.DIRECT_EXCHANGE;
-import static org.apache.james.backends.rabbitmq.Constants.DURABLE;
-import static org.apache.james.backends.rabbitmq.Constants.EMPTY_ROUTING_KEY;
-import static org.apache.james.mailbox.events.GroupRegistration.RETRY_COUNT;
-import static org.apache.james.mailbox.events.RabbitMQEventBus.MAILBOX_EVENT;
-
-import java.nio.charset.StandardCharsets;
-
-import org.apache.james.event.json.EventSerializer;
-import org.apache.james.events.Event;
-import org.apache.james.events.EventBus;
-import org.apache.james.events.EventDeadLetters;
-import org.apache.james.events.Group;
-import org.apache.james.util.MDCStructuredLogger;
-import org.apache.james.util.StructuredLogger;
-import org.slf4j.Logger;
-import org.slf4j.LoggerFactory;
-
-import com.google.common.base.Preconditions;
-import com.google.common.base.Strings;
-import com.google.common.collect.ImmutableMap;
-import com.rabbitmq.client.AMQP;
-
-import reactor.core.publisher.Flux;
-import reactor.core.publisher.Mono;
-import reactor.rabbitmq.BindingSpecification;
-import reactor.rabbitmq.ExchangeSpecification;
-import reactor.rabbitmq.OutboundMessage;
-import reactor.rabbitmq.Sender;
-
-class GroupConsumerRetry {
-
-    static class RetryExchangeName {
-        static RetryExchangeName of(Group group) {
-            return new RetryExchangeName(group.asString());
-        }
-
-        static final String MAILBOX_EVENT_RETRY_EXCHANGE_PREFIX = MAILBOX_EVENT + "-retryExchange-";
-
-        private final String name;
-
-        private RetryExchangeName(String name) {
-            Preconditions.checkArgument(!Strings.isNullOrEmpty(name), "Exchange name must be specified");
-            this.name = name;
-        }
-
-        String asString() {
-            return MAILBOX_EVENT_RETRY_EXCHANGE_PREFIX + name;
-        }
-    }
-
-    private static final Logger LOGGER = LoggerFactory.getLogger(GroupConsumerRetry.class);
-
-    private final Sender sender;
-    private final RetryExchangeName retryExchangeName;
-    private final RetryBackoffConfiguration retryBackoff;
-    private final EventDeadLetters eventDeadLetters;
-    private final Group group;
-    private final EventSerializer eventSerializer;
-
-    GroupConsumerRetry(Sender sender, Group group, RetryBackoffConfiguration retryBackoff,
-                       EventDeadLetters eventDeadLetters, EventSerializer eventSerializer) {
-        this.sender = sender;
-        this.retryExchangeName = RetryExchangeName.of(group);
-        this.retryBackoff = retryBackoff;
-        this.eventDeadLetters = eventDeadLetters;
-        this.group = group;
-        this.eventSerializer = eventSerializer;
-    }
-
-    Mono<Void> createRetryExchange(GroupRegistration.WorkQueueName queueName) {
-        return Flux.concat(
-            sender.declareExchange(ExchangeSpecification.exchange(retryExchangeName.asString())
-                .durable(DURABLE)
-                .type(DIRECT_EXCHANGE)),
-            sender.bind(BindingSpecification.binding()
-                .exchange(retryExchangeName.asString())
-                .queue(queueName.asString())
-                .routingKey(EMPTY_ROUTING_KEY)))
-            .then();
-    }
-
-    Mono<Void> handleRetry(Event event, int currentRetryCount, Throwable throwable) {
-        createStructuredLogger(event).log(logger -> logger.error("Exception happens when handling event after {} retries", currentRetryCount, throwable));
-
-        return retryOrStoreToDeadLetter(event, currentRetryCount);
-    }
-
-    Mono<Void> retryOrStoreToDeadLetter(Event event, int currentRetryCount) {
-        if (currentRetryCount >= retryBackoff.getMaxRetries()) {
-            return eventDeadLetters.store(group, event).then();
-        }
-        return sendRetryMessage(event, currentRetryCount);
-    }
-
-    private Mono<Void> sendRetryMessage(Event event, int currentRetryCount) {
-        byte[] eventAsBytes = eventSerializer.toJson(event).getBytes(StandardCharsets.UTF_8);
-
-        Mono<OutboundMessage> retryMessage = Mono.just(new OutboundMessage(
-            retryExchangeName.asString(),
-            EMPTY_ROUTING_KEY,
-            new AMQP.BasicProperties.Builder()
-                .headers(ImmutableMap.of(RETRY_COUNT, currentRetryCount + 1))
-                .deliveryMode(PERSISTENT_TEXT_PLAIN.getDeliveryMode())
-                .priority(PERSISTENT_TEXT_PLAIN.getPriority())
-                .contentType(PERSISTENT_TEXT_PLAIN.getContentType())
-                .build(),
-            eventAsBytes));
-
-        return sender.send(retryMessage)
-            .doOnError(throwable -> createStructuredLogger(event)
-                .log(logger -> logger.error("Exception happens when publishing event to retry exchange, this event will be stored in deadLetter", throwable)))
-            .onErrorResume(e -> eventDeadLetters.store(group, event).then());
-    }
-
-    private StructuredLogger createStructuredLogger(Event event) {
-        return MDCStructuredLogger.forLogger(LOGGER)
-            .addField(EventBus.StructuredLoggingFields.EVENT_ID, event.getEventId())
-            .addField(EventBus.StructuredLoggingFields.EVENT_CLASS, event.getClass())
-            .addField(EventBus.StructuredLoggingFields.USER, event.getUsername())
-            .addField(EventBus.StructuredLoggingFields.GROUP, group.asString());
-    }
-}
diff --git a/mailbox/event/event-rabbitmq/src/main/java/org/apache/james/mailbox/events/GroupRegistration.java b/mailbox/event/event-rabbitmq/src/main/java/org/apache/james/mailbox/events/GroupRegistration.java
deleted file mode 100644
index e07d6a7..0000000
--- a/mailbox/event/event-rabbitmq/src/main/java/org/apache/james/mailbox/events/GroupRegistration.java
+++ /dev/null
@@ -1,198 +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.mailbox.events;
-
-import static org.apache.james.backends.rabbitmq.Constants.AUTO_DELETE;
-import static org.apache.james.backends.rabbitmq.Constants.DURABLE;
-import static org.apache.james.backends.rabbitmq.Constants.EMPTY_ROUTING_KEY;
-import static org.apache.james.backends.rabbitmq.Constants.EXCLUSIVE;
-import static org.apache.james.backends.rabbitmq.Constants.REQUEUE;
-import static org.apache.james.backends.rabbitmq.Constants.deadLetterQueue;
-import static org.apache.james.mailbox.events.RabbitMQEventBus.MAILBOX_EVENT;
-import static org.apache.james.mailbox.events.RabbitMQEventBus.MAILBOX_EVENT_DEAD_LETTER_EXCHANGE_NAME;
-import static org.apache.james.mailbox.events.RabbitMQEventBus.MAILBOX_EVENT_EXCHANGE_NAME;
-
-import java.nio.charset.StandardCharsets;
-import java.util.Objects;
-import java.util.Optional;
-import java.util.function.Predicate;
-
-import org.apache.james.backends.rabbitmq.ReactorRabbitMQChannelPool;
-import org.apache.james.backends.rabbitmq.ReceiverProvider;
-import org.apache.james.event.json.EventSerializer;
-import org.apache.james.events.Event;
-import org.apache.james.events.EventBus;
-import org.apache.james.events.EventDeadLetters;
-import org.apache.james.events.EventListener;
-import org.apache.james.events.Group;
-import org.apache.james.events.Registration;
-import org.apache.james.util.MDCBuilder;
-import org.slf4j.Logger;
-import org.slf4j.LoggerFactory;
-
-import com.google.common.base.Preconditions;
-
-import reactor.core.Disposable;
-import reactor.core.publisher.Mono;
-import reactor.core.scheduler.Schedulers;
-import reactor.rabbitmq.AcknowledgableDelivery;
-import reactor.rabbitmq.BindingSpecification;
-import reactor.rabbitmq.ConsumeOptions;
-import reactor.rabbitmq.QueueSpecification;
-import reactor.rabbitmq.Receiver;
-import reactor.rabbitmq.Sender;
-import reactor.util.retry.Retry;
-
-class GroupRegistration implements Registration {
-    static class WorkQueueName {
-        static WorkQueueName of(Group group) {
-            return new WorkQueueName(group);
-        }
-
-        static final String MAILBOX_EVENT_WORK_QUEUE_PREFIX = MAILBOX_EVENT + "-workQueue-";
-
-        private final Group group;
-
-        private WorkQueueName(Group group) {
-            Preconditions.checkNotNull(group, "Group must be specified");
-            this.group = group;
-        }
-
-        String asString() {
-            return MAILBOX_EVENT_WORK_QUEUE_PREFIX + group.asString();
-        }
-    }
-
-    private static final Logger LOGGER = LoggerFactory.getLogger(GroupRegistration.class);
-    static final String RETRY_COUNT = "retry-count";
-    static final int DEFAULT_RETRY_COUNT = 0;
-
-    private final ReactorRabbitMQChannelPool channelPool;
-    private final EventListener.ReactiveEventListener mailboxListener;
-    private final WorkQueueName queueName;
-    private final Receiver receiver;
-    private final Runnable unregisterGroup;
-    private final Sender sender;
-    private final EventSerializer eventSerializer;
-    private final GroupConsumerRetry retryHandler;
-    private final WaitDelayGenerator delayGenerator;
-    private final Group group;
-    private final RetryBackoffConfiguration retryBackoff;
-    private final MailboxListenerExecutor mailboxListenerExecutor;
-    private Optional<Disposable> receiverSubscriber;
-
-    GroupRegistration(ReactorRabbitMQChannelPool channelPool, Sender sender, ReceiverProvider receiverProvider, EventSerializer eventSerializer,
-                      EventListener.ReactiveEventListener mailboxListener, Group group, RetryBackoffConfiguration retryBackoff,
-                      EventDeadLetters eventDeadLetters,
-                      Runnable unregisterGroup, MailboxListenerExecutor mailboxListenerExecutor) {
-        this.channelPool = channelPool;
-        this.eventSerializer = eventSerializer;
-        this.mailboxListener = mailboxListener;
-        this.queueName = WorkQueueName.of(group);
-        this.sender = sender;
-        this.receiver = receiverProvider.createReceiver();
-        this.retryBackoff = retryBackoff;
-        this.mailboxListenerExecutor = mailboxListenerExecutor;
-        this.receiverSubscriber = Optional.empty();
-        this.unregisterGroup = unregisterGroup;
-        this.retryHandler = new GroupConsumerRetry(sender, group, retryBackoff, eventDeadLetters, eventSerializer);
-        this.delayGenerator = WaitDelayGenerator.of(retryBackoff);
-        this.group = group;
-    }
-
-    GroupRegistration start() {
-        receiverSubscriber = Optional
-            .of(createGroupWorkQueue()
-                .then(retryHandler.createRetryExchange(queueName))
-                .then(Mono.fromCallable(() -> this.consumeWorkQueue()))
-                .retryWhen(Retry.backoff(retryBackoff.getMaxRetries(), retryBackoff.getFirstBackoff()).jitter(retryBackoff.getJitterFactor()).scheduler(Schedulers.elastic()))
-                .block());
-        return this;
-    }
-
-    private Mono<Void> createGroupWorkQueue() {
-        return channelPool.createWorkQueue(
-            QueueSpecification.queue(queueName.asString())
-                .durable(DURABLE)
-                .exclusive(!EXCLUSIVE)
-                .autoDelete(!AUTO_DELETE)
-                .arguments(deadLetterQueue(MAILBOX_EVENT_DEAD_LETTER_EXCHANGE_NAME)),
-            BindingSpecification.binding()
-                .exchange(MAILBOX_EVENT_EXCHANGE_NAME)
-                .queue(queueName.asString())
-                .routingKey(EMPTY_ROUTING_KEY));
-    }
-
-    private Disposable consumeWorkQueue() {
-        return receiver.consumeManualAck(queueName.asString(), new ConsumeOptions().qos(EventBus.EXECUTION_RATE))
-            .publishOn(Schedulers.parallel())
-            .filter(delivery -> Objects.nonNull(delivery.getBody()))
-            .flatMap(this::deliver, EventBus.EXECUTION_RATE)
-            .subscribe();
-    }
-
-    private Mono<Void> deliver(AcknowledgableDelivery acknowledgableDelivery) {
-        byte[] eventAsBytes = acknowledgableDelivery.getBody();
-        int currentRetryCount = getRetryCount(acknowledgableDelivery);
-
-        return deserializeEvent(eventAsBytes)
-            .flatMap(event -> delayGenerator.delayIfHaveTo(currentRetryCount)
-                .flatMap(any -> runListener(event))
-                .onErrorResume(throwable -> retryHandler.handleRetry(event, currentRetryCount, throwable))
-                .then(Mono.<Void>fromRunnable(acknowledgableDelivery::ack)))
-            .onErrorResume(e -> {
-                LOGGER.error("Unable to process delivery for group {}", group, e);
-                return Mono.fromRunnable(() -> acknowledgableDelivery.nack(!REQUEUE));
-            });
-    }
-
-    private Mono<Event> deserializeEvent(byte[] eventAsBytes) {
-        return Mono.fromCallable(() -> eventSerializer.fromJson(new String(eventAsBytes, StandardCharsets.UTF_8)).get())
-            .subscribeOn(Schedulers.parallel());
-    }
-
-    Mono<Void> reDeliver(Event event) {
-        return retryHandler.retryOrStoreToDeadLetter(event, DEFAULT_RETRY_COUNT);
-    }
-
-    private Mono<Void> runListener(Event event) {
-        return mailboxListenerExecutor.execute(
-            mailboxListener,
-            MDCBuilder.create()
-                .addContext(EventBus.StructuredLoggingFields.GROUP, group),
-            event);
-    }
-
-    private int getRetryCount(AcknowledgableDelivery acknowledgableDelivery) {
-        return Optional.ofNullable(acknowledgableDelivery.getProperties().getHeaders())
-            .flatMap(headers -> Optional.ofNullable(headers.get(RETRY_COUNT)))
-            .filter(object -> object instanceof Integer)
-            .map(Integer.class::cast)
-            .orElse(DEFAULT_RETRY_COUNT);
-    }
-
-    @Override
-    public void unregister() {
-        receiverSubscriber.filter(Predicate.not(Disposable::isDisposed))
-            .ifPresent(Disposable::dispose);
-        receiver.close();
-        unregisterGroup.run();
-    }
-}
\ No newline at end of file
diff --git a/mailbox/event/event-rabbitmq/src/main/java/org/apache/james/mailbox/events/GroupRegistrationHandler.java b/mailbox/event/event-rabbitmq/src/main/java/org/apache/james/mailbox/events/GroupRegistrationHandler.java
deleted file mode 100644
index 950ac44..0000000
--- a/mailbox/event/event-rabbitmq/src/main/java/org/apache/james/mailbox/events/GroupRegistrationHandler.java
+++ /dev/null
@@ -1,93 +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.mailbox.events;
-
-import java.util.Map;
-import java.util.Optional;
-import java.util.concurrent.ConcurrentHashMap;
-
-import org.apache.james.backends.rabbitmq.ReactorRabbitMQChannelPool;
-import org.apache.james.backends.rabbitmq.ReceiverProvider;
-import org.apache.james.event.json.EventSerializer;
-import org.apache.james.events.EventDeadLetters;
-import org.apache.james.events.EventListener;
-import org.apache.james.events.Group;
-import org.apache.james.events.GroupAlreadyRegistered;
-import org.apache.james.events.GroupRegistrationNotFound;
-import org.apache.james.events.Registration;
-
-import reactor.rabbitmq.Sender;
-
-class GroupRegistrationHandler {
-    private final Map<Group, GroupRegistration> groupRegistrations;
-    private final EventSerializer eventSerializer;
-    private final ReactorRabbitMQChannelPool channelPool;
-    private final Sender sender;
-    private final ReceiverProvider receiverProvider;
-    private final RetryBackoffConfiguration retryBackoff;
-    private final EventDeadLetters eventDeadLetters;
-    private final MailboxListenerExecutor mailboxListenerExecutor;
-
-    GroupRegistrationHandler(EventSerializer eventSerializer, ReactorRabbitMQChannelPool channelPool, Sender sender, ReceiverProvider receiverProvider,
-                             RetryBackoffConfiguration retryBackoff,
-                             EventDeadLetters eventDeadLetters, MailboxListenerExecutor mailboxListenerExecutor) {
-        this.eventSerializer = eventSerializer;
-        this.channelPool = channelPool;
-        this.sender = sender;
-        this.receiverProvider = receiverProvider;
-        this.retryBackoff = retryBackoff;
-        this.eventDeadLetters = eventDeadLetters;
-        this.mailboxListenerExecutor = mailboxListenerExecutor;
-        this.groupRegistrations = new ConcurrentHashMap<>();
-    }
-
-    GroupRegistration retrieveGroupRegistration(Group group) {
-        return Optional.ofNullable(groupRegistrations.get(group))
-            .orElseThrow(() -> new GroupRegistrationNotFound(group));
-    }
-
-    void stop() {
-        groupRegistrations.values().forEach(GroupRegistration::unregister);
-    }
-
-    Registration register(EventListener.ReactiveEventListener listener, Group group) {
-        return groupRegistrations
-            .compute(group, (groupToRegister, oldGroupRegistration) -> {
-                if (oldGroupRegistration != null) {
-                    throw new GroupAlreadyRegistered(group);
-                }
-                return newGroupRegistration(listener, groupToRegister);
-            })
-            .start();
-    }
-
-    private GroupRegistration newGroupRegistration(EventListener.ReactiveEventListener listener, Group group) {
-        return new GroupRegistration(
-            channelPool, sender,
-            receiverProvider,
-            eventSerializer,
-            listener,
-            group,
-            retryBackoff,
-            eventDeadLetters,
-            () -> groupRegistrations.remove(group),
-            mailboxListenerExecutor);
-    }
-}
\ No newline at end of file
diff --git a/mailbox/event/event-rabbitmq/src/main/java/org/apache/james/mailbox/events/KeyReconnectionHandler.java b/mailbox/event/event-rabbitmq/src/main/java/org/apache/james/mailbox/events/KeyReconnectionHandler.java
deleted file mode 100644
index a8162d0..0000000
--- a/mailbox/event/event-rabbitmq/src/main/java/org/apache/james/mailbox/events/KeyReconnectionHandler.java
+++ /dev/null
@@ -1,60 +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.mailbox.events;
-
-import static org.apache.james.backends.rabbitmq.Constants.AUTO_DELETE;
-import static org.apache.james.backends.rabbitmq.Constants.DURABLE;
-import static org.apache.james.backends.rabbitmq.Constants.EXCLUSIVE;
-import static org.apache.james.mailbox.events.KeyRegistrationHandler.EVENTBUS_QUEUE_NAME_PREFIX;
-import static org.apache.james.mailbox.events.KeyRegistrationHandler.QUEUE_ARGUMENTS;
-
-import javax.inject.Inject;
-
-import org.apache.james.backends.rabbitmq.SimpleConnectionPool;
-import org.reactivestreams.Publisher;
-import org.slf4j.Logger;
-import org.slf4j.LoggerFactory;
-
-import com.rabbitmq.client.Channel;
-import com.rabbitmq.client.Connection;
-
-import reactor.core.publisher.Mono;
-
-public class KeyReconnectionHandler implements SimpleConnectionPool.ReconnectionHandler {
-    private static final Logger LOGGER = LoggerFactory.getLogger(KeyReconnectionHandler.class);
-
-    private final EventBusId eventBusId;
-
-    @Inject
-    public KeyReconnectionHandler(EventBusId eventBusId) {
-        this.eventBusId = eventBusId;
-    }
-
-    @Override
-    public Publisher<Void> handleReconnection(Connection connection) {
-        return Mono.fromRunnable(() -> {
-            try (Channel channel = connection.createChannel()) {
-                channel.queueDeclare(EVENTBUS_QUEUE_NAME_PREFIX + eventBusId.asString(), DURABLE, !EXCLUSIVE, AUTO_DELETE, QUEUE_ARGUMENTS);
-            } catch (Exception e) {
-                LOGGER.error("Error recovering connection", e);
-            }
-        });
-    }
-}
diff --git a/mailbox/event/event-rabbitmq/src/main/java/org/apache/james/mailbox/events/KeyRegistration.java b/mailbox/event/event-rabbitmq/src/main/java/org/apache/james/mailbox/events/KeyRegistration.java
deleted file mode 100644
index be1f399..0000000
--- a/mailbox/event/event-rabbitmq/src/main/java/org/apache/james/mailbox/events/KeyRegistration.java
+++ /dev/null
@@ -1,35 +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.mailbox.events;
-
-import org.apache.james.events.Registration;
-
-class KeyRegistration implements Registration {
-    private final Runnable unregister;
-
-    KeyRegistration(Runnable unregister) {
-        this.unregister = unregister;
-    }
-
-    @Override
-    public void unregister() {
-        unregister.run();
-    }
-}
\ No newline at end of file
diff --git a/mailbox/event/event-rabbitmq/src/main/java/org/apache/james/mailbox/events/KeyRegistrationHandler.java b/mailbox/event/event-rabbitmq/src/main/java/org/apache/james/mailbox/events/KeyRegistrationHandler.java
deleted file mode 100644
index 0731ca8..0000000
--- a/mailbox/event/event-rabbitmq/src/main/java/org/apache/james/mailbox/events/KeyRegistrationHandler.java
+++ /dev/null
@@ -1,204 +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.mailbox.events;
-
-import static org.apache.james.backends.rabbitmq.Constants.AUTO_DELETE;
-import static org.apache.james.backends.rabbitmq.Constants.DURABLE;
-import static org.apache.james.backends.rabbitmq.Constants.EXCLUSIVE;
-import static org.apache.james.mailbox.events.RabbitMQEventBus.EVENT_BUS_ID;
-
-import java.nio.charset.StandardCharsets;
-import java.time.Duration;
-import java.util.Map;
-import java.util.Optional;
-import java.util.function.Predicate;
-
-import org.apache.james.backends.rabbitmq.ReceiverProvider;
-import org.apache.james.event.json.EventSerializer;
-import org.apache.james.events.Event;
-import org.apache.james.events.EventBus;
-import org.apache.james.events.EventListener;
-import org.apache.james.events.Registration;
-import org.apache.james.events.RegistrationKey;
-import org.apache.james.util.MDCBuilder;
-import org.apache.james.util.MDCStructuredLogger;
-import org.apache.james.util.StructuredLogger;
-import org.slf4j.Logger;
-import org.slf4j.LoggerFactory;
-
-import com.google.common.annotations.VisibleForTesting;
-import com.google.common.collect.ImmutableMap;
-import com.rabbitmq.client.AMQP;
-import com.rabbitmq.client.Delivery;
-
-import reactor.core.Disposable;
-import reactor.core.publisher.Mono;
-import reactor.core.scheduler.Schedulers;
-import reactor.rabbitmq.ConsumeOptions;
-import reactor.rabbitmq.QueueSpecification;
-import reactor.rabbitmq.Receiver;
-import reactor.rabbitmq.Sender;
-import reactor.util.retry.Retry;
-
-class KeyRegistrationHandler {
-    private static final Logger LOGGER = LoggerFactory.getLogger(KeyRegistrationHandler.class);
-    static final String EVENTBUS_QUEUE_NAME_PREFIX = "eventbus-";
-    private static final Duration EXPIRATION_TIMEOUT = Duration.ofMinutes(30);
-    static final Map<String, Object> QUEUE_ARGUMENTS = ImmutableMap.of("x-expires", EXPIRATION_TIMEOUT.toMillis());
-
-    private static final Duration TOPOLOGY_CHANGES_TIMEOUT = Duration.ofMinutes(1);
-
-    private final EventBusId eventBusId;
-    private final LocalListenerRegistry localListenerRegistry;
-    private final EventSerializer eventSerializer;
-    private final Sender sender;
-    private final RoutingKeyConverter routingKeyConverter;
-    private final Receiver receiver;
-    private final RegistrationQueueName registrationQueue;
-    private final RegistrationBinder registrationBinder;
-    private final MailboxListenerExecutor mailboxListenerExecutor;
-    private final RetryBackoffConfiguration retryBackoff;
-    private Optional<Disposable> receiverSubscriber;
-
-    KeyRegistrationHandler(EventBusId eventBusId, EventSerializer eventSerializer,
-                           Sender sender, ReceiverProvider receiverProvider,
-                           RoutingKeyConverter routingKeyConverter, LocalListenerRegistry localListenerRegistry,
-                           MailboxListenerExecutor mailboxListenerExecutor, RetryBackoffConfiguration retryBackoff) {
-        this.eventBusId = eventBusId;
-        this.eventSerializer = eventSerializer;
-        this.sender = sender;
-        this.routingKeyConverter = routingKeyConverter;
-        this.localListenerRegistry = localListenerRegistry;
-        this.receiver = receiverProvider.createReceiver();
-        this.mailboxListenerExecutor = mailboxListenerExecutor;
-        this.retryBackoff = retryBackoff;
-        this.registrationQueue = new RegistrationQueueName(EVENTBUS_QUEUE_NAME_PREFIX + eventBusId.asString());
-        this.registrationBinder = new RegistrationBinder(sender, registrationQueue);
-        this.receiverSubscriber = Optional.empty();
-
-    }
-
-    void start() {
-        declareQueue();
-
-        receiverSubscriber = Optional.of(receiver.consumeAutoAck(registrationQueue.asString(), new ConsumeOptions().qos(EventBus.EXECUTION_RATE))
-            .subscribeOn(Schedulers.parallel())
-            .flatMap(this::handleDelivery, EventBus.EXECUTION_RATE)
-            .subscribe());
-    }
-
-    @VisibleForTesting
-    void declareQueue() {
-        declareQueue(sender);
-    }
-
-    private void declareQueue(Sender sender) {
-        sender.declareQueue(
-            QueueSpecification.queue(EVENTBUS_QUEUE_NAME_PREFIX + eventBusId.asString())
-                .durable(DURABLE)
-                .exclusive(!EXCLUSIVE)
-                .autoDelete(AUTO_DELETE)
-                .arguments(QUEUE_ARGUMENTS))
-            .timeout(TOPOLOGY_CHANGES_TIMEOUT)
-            .map(AMQP.Queue.DeclareOk::getQueue)
-            .retryWhen(Retry.backoff(retryBackoff.getMaxRetries(), retryBackoff.getFirstBackoff()).jitter(retryBackoff.getJitterFactor()))
-            .block();
-    }
-
-    void stop() {
-        sender.delete(QueueSpecification.queue(registrationQueue.asString()))
-            .timeout(TOPOLOGY_CHANGES_TIMEOUT)
-            .retryWhen(Retry.backoff(retryBackoff.getMaxRetries(), retryBackoff.getFirstBackoff()).jitter(retryBackoff.getJitterFactor()).scheduler(Schedulers.elastic()))
-            .block();
-        receiverSubscriber.filter(Predicate.not(Disposable::isDisposed))
-                .ifPresent(Disposable::dispose);
-        receiver.close();
-    }
-
-    Mono<Registration> register(EventListener.ReactiveEventListener listener, RegistrationKey key) {
-        LocalListenerRegistry.LocalRegistration registration = localListenerRegistry.addListener(key, listener);
-
-        return registerIfNeeded(key, registration)
-            .thenReturn(new KeyRegistration(() -> {
-                if (registration.unregister().lastListenerRemoved()) {
-                    registrationBinder.unbind(key)
-                        .timeout(TOPOLOGY_CHANGES_TIMEOUT)
-                        .retryWhen(Retry.backoff(retryBackoff.getMaxRetries(), retryBackoff.getFirstBackoff()).jitter(retryBackoff.getJitterFactor()).scheduler(Schedulers.elastic()))
-                        .subscribeOn(Schedulers.elastic())
-                        .block();
-                }
-            }));
-    }
-
-    private Mono<Void> registerIfNeeded(RegistrationKey key, LocalListenerRegistry.LocalRegistration registration) {
-        if (registration.isFirstListener()) {
-            return registrationBinder.bind(key)
-                .timeout(TOPOLOGY_CHANGES_TIMEOUT)
-                .retryWhen(Retry.backoff(retryBackoff.getMaxRetries(), retryBackoff.getFirstBackoff()).jitter(retryBackoff.getJitterFactor()).scheduler(Schedulers.elastic()));
-        }
-        return Mono.empty();
-    }
-
-    private Mono<Void> handleDelivery(Delivery delivery) {
-        if (delivery.getBody() == null) {
-            return Mono.empty();
-        }
-
-        String serializedEventBusId = delivery.getProperties().getHeaders().get(EVENT_BUS_ID).toString();
-        EventBusId eventBusId = EventBusId.of(serializedEventBusId);
-
-        String routingKey = delivery.getEnvelope().getRoutingKey();
-        RegistrationKey registrationKey = routingKeyConverter.toRegistrationKey(routingKey);
-        Event event = toEvent(delivery);
-
-        return localListenerRegistry.getLocalMailboxListeners(registrationKey)
-            .filter(listener -> !isLocalSynchronousListeners(eventBusId, listener))
-            .flatMap(listener -> executeListener(listener, event, registrationKey), EventBus.EXECUTION_RATE)
-            .then();
-    }
-
-    private Mono<Void> executeListener(EventListener.ReactiveEventListener listener, Event event, RegistrationKey key) {
-        MDCBuilder mdcBuilder = MDCBuilder.create()
-            .addContext(EventBus.StructuredLoggingFields.REGISTRATION_KEY, key);
-
-        return mailboxListenerExecutor.execute(listener, mdcBuilder, event)
-            .doOnError(e -> structuredLogger(event, key)
-                .log(logger -> logger.error("Exception happens when handling event", e)))
-            .onErrorResume(e -> Mono.empty())
-            .then();
-    }
-
-    private boolean isLocalSynchronousListeners(EventBusId eventBusId, EventListener listener) {
-        return eventBusId.equals(this.eventBusId) &&
-            listener.getExecutionMode().equals(EventListener.ExecutionMode.SYNCHRONOUS);
-    }
-
-    private Event toEvent(Delivery delivery) {
-        return eventSerializer.fromJson(new String(delivery.getBody(), StandardCharsets.UTF_8)).get();
-    }
-
-    private StructuredLogger structuredLogger(Event event, RegistrationKey key) {
-        return MDCStructuredLogger.forLogger(LOGGER)
-            .addField(EventBus.StructuredLoggingFields.EVENT_ID, event.getEventId())
-            .addField(EventBus.StructuredLoggingFields.EVENT_CLASS, event.getClass())
-            .addField(EventBus.StructuredLoggingFields.USER, event.getUsername())
-            .addField(EventBus.StructuredLoggingFields.REGISTRATION_KEY, key);
-    }
-}
diff --git a/mailbox/event/event-rabbitmq/src/main/java/org/apache/james/mailbox/events/LocalListenerRegistry.java b/mailbox/event/event-rabbitmq/src/main/java/org/apache/james/mailbox/events/LocalListenerRegistry.java
deleted file mode 100644
index 468bde6..0000000
--- a/mailbox/event/event-rabbitmq/src/main/java/org/apache/james/mailbox/events/LocalListenerRegistry.java
+++ /dev/null
@@ -1,112 +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.mailbox.events;
-
-import static com.google.common.base.Predicates.not;
-
-import java.util.Optional;
-import java.util.concurrent.ConcurrentHashMap;
-import java.util.concurrent.atomic.AtomicBoolean;
-import java.util.function.Supplier;
-
-import org.apache.james.events.EventListener;
-import org.apache.james.events.RegistrationKey;
-
-import com.github.steveash.guavate.Guavate;
-import com.google.common.collect.ImmutableSet;
-
-import reactor.core.publisher.Flux;
-
-class LocalListenerRegistry {
-
-    interface RemovalStatus {
-        boolean lastListenerRemoved();
-    }
-
-    public static class LocalRegistration {
-        private final boolean firstListener;
-        private final Supplier<RemovalStatus> unregister;
-
-        public LocalRegistration(boolean firstListener, Supplier<RemovalStatus> unregister) {
-            this.firstListener = firstListener;
-            this.unregister = unregister;
-        }
-
-        public boolean isFirstListener() {
-            return firstListener;
-        }
-
-        public RemovalStatus unregister() {
-            return unregister.get();
-        }
-    }
-
-    private final ConcurrentHashMap<RegistrationKey, ImmutableSet<EventListener.ReactiveEventListener>> listenersByKey;
-
-    LocalListenerRegistry() {
-        this.listenersByKey = new ConcurrentHashMap<>();
-    }
-
-    LocalRegistration addListener(RegistrationKey registrationKey, EventListener.ReactiveEventListener listener) {
-        AtomicBoolean firstListener = new AtomicBoolean(false);
-        listenersByKey.compute(registrationKey, (key, listeners) ->
-            Optional.ofNullable(listeners)
-                .map(set -> ImmutableSet.<EventListener.ReactiveEventListener>builder().addAll(set).add(listener).build())
-                .orElseGet(() -> {
-                    firstListener.set(true);
-                    return ImmutableSet.of(listener);
-                })
-        );
-        return new LocalRegistration(firstListener.get(), () -> removeListener(registrationKey, listener));
-    }
-
-    LocalRegistration addListener(RegistrationKey registrationKey, EventListener listener) {
-        return addListener(registrationKey, EventListener.wrapReactive(listener));
-    }
-
-    private RemovalStatus removeListener(RegistrationKey registrationKey, EventListener.ReactiveEventListener listener) {
-        AtomicBoolean lastListenerRemoved = new AtomicBoolean(false);
-        listenersByKey.compute(registrationKey, (key, listeners) -> {
-            boolean listenersContainRequested = Optional.ofNullable(listeners).orElse(ImmutableSet.of()).contains(listener);
-            if (listenersContainRequested) {
-                ImmutableSet<EventListener.ReactiveEventListener> remainingListeners = removeListenerFromSet(listener, listeners);
-                if (remainingListeners.isEmpty()) {
-                    lastListenerRemoved.set(true);
-                    return null;
-                }
-                return remainingListeners;
-            }
-            return listeners;
-        });
-        return lastListenerRemoved::get;
-    }
-
-    private ImmutableSet<EventListener.ReactiveEventListener> removeListenerFromSet(EventListener listener, ImmutableSet<EventListener.ReactiveEventListener> listeners) {
-        ImmutableSet<EventListener.ReactiveEventListener> remainingListeners = listeners.stream().filter(not(listener::equals)).collect(Guavate.toImmutableSet());
-        if (remainingListeners.isEmpty()) {
-            return ImmutableSet.of();
-        }
-        return remainingListeners;
-    }
-
-    Flux<EventListener.ReactiveEventListener> getLocalMailboxListeners(RegistrationKey registrationKey) {
-        return Flux.fromIterable(listenersByKey.getOrDefault(registrationKey, ImmutableSet.of()));
-    }
-}
\ No newline at end of file
diff --git a/mailbox/event/event-rabbitmq/src/main/java/org/apache/james/mailbox/events/MailboxListenerExecutor.java b/mailbox/event/event-rabbitmq/src/main/java/org/apache/james/mailbox/events/MailboxListenerExecutor.java
deleted file mode 100644
index f35dc77..0000000
--- a/mailbox/event/event-rabbitmq/src/main/java/org/apache/james/mailbox/events/MailboxListenerExecutor.java
+++ /dev/null
@@ -1,56 +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.mailbox.events;
-
-import static org.apache.james.events.EventBus.Metrics.timerName;
-
-import org.apache.james.events.Event;
-import org.apache.james.events.EventBus;
-import org.apache.james.events.EventListener;
-import org.apache.james.metrics.api.MetricFactory;
-import org.apache.james.util.MDCBuilder;
-import org.apache.james.util.ReactorUtils;
-
-import reactor.core.publisher.Mono;
-
-class MailboxListenerExecutor {
-    private final MetricFactory metricFactory;
-
-    MailboxListenerExecutor(MetricFactory metricFactory) {
-        this.metricFactory = metricFactory;
-    }
-
-    Mono<Void> execute(EventListener.ReactiveEventListener listener, MDCBuilder mdcBuilder, Event event) {
-        if (listener.isHandling(event)) {
-            return Mono.from(metricFactory.decoratePublisherWithTimerMetric(timerName(listener),
-                Mono.from(listener.reactiveEvent(event))
-                    .subscriberContext(ReactorUtils.context("MailboxListenerExecutor", mdc(listener, mdcBuilder, event)))));
-        }
-        return Mono.empty();
-    }
-
-    private MDCBuilder mdc(EventListener listener, MDCBuilder mdcBuilder, Event event) {
-        return mdcBuilder
-            .addContext(EventBus.StructuredLoggingFields.EVENT_ID, event.getEventId())
-            .addContext(EventBus.StructuredLoggingFields.EVENT_CLASS, event.getClass())
-            .addContext(EventBus.StructuredLoggingFields.USER, event.getUsername())
-            .addContext(EventBus.StructuredLoggingFields.LISTENER_CLASS, listener.getClass());
-    }
-}
diff --git a/mailbox/event/event-rabbitmq/src/main/java/org/apache/james/mailbox/events/RabbitMQEventBus.java b/mailbox/event/event-rabbitmq/src/main/java/org/apache/james/mailbox/events/RabbitMQEventBus.java
deleted file mode 100644
index 14c4804..0000000
--- a/mailbox/event/event-rabbitmq/src/main/java/org/apache/james/mailbox/events/RabbitMQEventBus.java
+++ /dev/null
@@ -1,177 +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.mailbox.events;
-
-import java.util.Set;
-
-import javax.annotation.PreDestroy;
-import javax.inject.Inject;
-
-import org.apache.james.backends.rabbitmq.ReactorRabbitMQChannelPool;
-import org.apache.james.backends.rabbitmq.ReceiverProvider;
-import org.apache.james.event.json.EventSerializer;
-import org.apache.james.events.Event;
-import org.apache.james.events.EventBus;
-import org.apache.james.events.EventDeadLetters;
-import org.apache.james.events.EventListener;
-import org.apache.james.events.Group;
-import org.apache.james.events.Registration;
-import org.apache.james.events.RegistrationKey;
-import org.apache.james.lifecycle.api.Startable;
-import org.apache.james.metrics.api.MetricFactory;
-
-import com.google.common.annotations.VisibleForTesting;
-import com.google.common.base.Preconditions;
-import com.google.common.collect.ImmutableSet;
-
-import reactor.core.publisher.Mono;
-import reactor.rabbitmq.Sender;
-
-public class RabbitMQEventBus implements EventBus, Startable {
-    private static final Set<RegistrationKey> NO_KEY = ImmutableSet.of();
-    private static final String NOT_RUNNING_ERROR_MESSAGE = "Event Bus is not running";
-    static final String MAILBOX_EVENT = "mailboxEvent";
-    static final String MAILBOX_EVENT_DEAD_LETTER_QUEUE = MAILBOX_EVENT + "-dead-letter-queue";
-    static final String MAILBOX_EVENT_EXCHANGE_NAME = MAILBOX_EVENT + "-exchange";
-    static final String MAILBOX_EVENT_DEAD_LETTER_EXCHANGE_NAME = MAILBOX_EVENT + "-dead-letter-exchange";
-    static final String EVENT_BUS_ID = "eventBusId";
-
-    private final EventSerializer eventSerializer;
-    private final RoutingKeyConverter routingKeyConverter;
-    private final RetryBackoffConfiguration retryBackoff;
-    private final EventBusId eventBusId;
-    private final EventDeadLetters eventDeadLetters;
-    private final MailboxListenerExecutor mailboxListenerExecutor;
-    private final Sender sender;
-    private final ReceiverProvider receiverProvider;
-    private final ReactorRabbitMQChannelPool channelPool;
-
-    private volatile boolean isRunning;
-    private volatile boolean isStopping;
-    private GroupRegistrationHandler groupRegistrationHandler;
-    private KeyRegistrationHandler keyRegistrationHandler;
-    private EventDispatcher eventDispatcher;
-
-    @Inject
-    public RabbitMQEventBus(Sender sender, ReceiverProvider receiverProvider, EventSerializer eventSerializer,
-                            RetryBackoffConfiguration retryBackoff,
-                            RoutingKeyConverter routingKeyConverter,
-                            EventDeadLetters eventDeadLetters, MetricFactory metricFactory, ReactorRabbitMQChannelPool channelPool,
-                            EventBusId eventBusId) {
-        this.sender = sender;
-        this.receiverProvider = receiverProvider;
-        this.mailboxListenerExecutor = new MailboxListenerExecutor(metricFactory);
-        this.channelPool = channelPool;
-        this.eventBusId = eventBusId;
-        this.eventSerializer = eventSerializer;
-        this.routingKeyConverter = routingKeyConverter;
-        this.retryBackoff = retryBackoff;
-        this.eventDeadLetters = eventDeadLetters;
-        this.isRunning = false;
-        this.isStopping = false;
-    }
-
-    public void start() {
-        if (!isRunning && !isStopping) {
-
-            LocalListenerRegistry localListenerRegistry = new LocalListenerRegistry();
-            keyRegistrationHandler = new KeyRegistrationHandler(eventBusId, eventSerializer, sender, receiverProvider, routingKeyConverter, localListenerRegistry, mailboxListenerExecutor, retryBackoff);
-            groupRegistrationHandler = new GroupRegistrationHandler(eventSerializer, channelPool, sender, receiverProvider, retryBackoff, eventDeadLetters, mailboxListenerExecutor);
-            eventDispatcher = new EventDispatcher(eventBusId, eventSerializer, sender, localListenerRegistry, mailboxListenerExecutor, eventDeadLetters);
-
-            eventDispatcher.start();
-            keyRegistrationHandler.start();
-            isRunning = true;
-        }
-    }
-
-    @VisibleForTesting
-    void startWithoutStartingKeyRegistrationHandler() {
-        if (!isRunning && !isStopping) {
-
-            LocalListenerRegistry localListenerRegistry = new LocalListenerRegistry();
-            keyRegistrationHandler = new KeyRegistrationHandler(eventBusId, eventSerializer, sender, receiverProvider, routingKeyConverter, localListenerRegistry, mailboxListenerExecutor, retryBackoff);
-            groupRegistrationHandler = new GroupRegistrationHandler(eventSerializer, channelPool, sender, receiverProvider, retryBackoff, eventDeadLetters, mailboxListenerExecutor);
-            eventDispatcher = new EventDispatcher(eventBusId, eventSerializer, sender, localListenerRegistry, mailboxListenerExecutor, eventDeadLetters);
-
-            keyRegistrationHandler.declareQueue();
-
-            eventDispatcher.start();
-            isRunning = true;
-        }
-    }
-
-    @VisibleForTesting
-    void startKeyRegistrationHandler() {
-        keyRegistrationHandler.start();
-    }
-
-    @PreDestroy
-    public void stop() {
-        if (isRunning && !isStopping) {
-            isStopping = true;
-            isRunning = false;
-            groupRegistrationHandler.stop();
-            keyRegistrationHandler.stop();
-        }
-    }
-
-    @Override
-    public Mono<Registration> register(EventListener.ReactiveEventListener listener, RegistrationKey key) {
-        Preconditions.checkState(isRunning, NOT_RUNNING_ERROR_MESSAGE);
-        return keyRegistrationHandler.register(listener, key);
-    }
-
-    @Override
-    public Registration register(EventListener.ReactiveEventListener listener, Group group) {
-        Preconditions.checkState(isRunning, NOT_RUNNING_ERROR_MESSAGE);
-        return groupRegistrationHandler.register(listener, group);
-    }
-
-    @Override
-    public Mono<Void> dispatch(Event event, Set<RegistrationKey> key) {
-        Preconditions.checkState(isRunning, NOT_RUNNING_ERROR_MESSAGE);
-        if (!event.isNoop()) {
-            return eventDispatcher.dispatch(event, key);
-        }
-        return Mono.empty();
-    }
-
-    @Override
-    public Mono<Void> reDeliver(Group group, Event event) {
-        Preconditions.checkState(isRunning, NOT_RUNNING_ERROR_MESSAGE);
-        if (!event.isNoop()) {
-            /*
-            if the eventBus.dispatch() gets error while dispatching an event (rabbitMQ network outage maybe),
-            which means all the group consumers will not be receiving that event.
-
-            We store the that event in the dead letter and expecting in the future, it will be dispatched
-            again not only for a specific consumer but all.
-
-            That's why it is special, and we need to check event type before processing further.
-            */
-            if (group instanceof EventDispatcher.DispatchingFailureGroup) {
-                return eventDispatcher.dispatch(event, NO_KEY);
-            }
-            return groupRegistrationHandler.retrieveGroupRegistration(group).reDeliver(event);
-        }
-        return Mono.empty();
-    }
-}
\ No newline at end of file
diff --git a/mailbox/event/event-rabbitmq/src/main/java/org/apache/james/mailbox/events/RegistrationBinder.java b/mailbox/event/event-rabbitmq/src/main/java/org/apache/james/mailbox/events/RegistrationBinder.java
deleted file mode 100644
index 88fa692..0000000
--- a/mailbox/event/event-rabbitmq/src/main/java/org/apache/james/mailbox/events/RegistrationBinder.java
+++ /dev/null
@@ -1,56 +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.mailbox.events;
-
-import static org.apache.james.mailbox.events.RabbitMQEventBus.MAILBOX_EVENT_EXCHANGE_NAME;
-
-import org.apache.james.events.RegistrationKey;
-
-import reactor.core.publisher.Mono;
-import reactor.rabbitmq.BindingSpecification;
-import reactor.rabbitmq.Sender;
-
-class RegistrationBinder {
-    private final Sender sender;
-    private final RegistrationQueueName registrationQueue;
-
-    RegistrationBinder(Sender sender, RegistrationQueueName registrationQueue) {
-        this.sender = sender;
-        this.registrationQueue = registrationQueue;
-    }
-
-    Mono<Void> bind(RegistrationKey key) {
-        return sender.bind(bindingSpecification(key))
-            .then();
-    }
-
-    Mono<Void> unbind(RegistrationKey key) {
-        return sender.unbind(bindingSpecification(key))
-            .then();
-    }
-
-    private BindingSpecification bindingSpecification(RegistrationKey key) {
-        RoutingKeyConverter.RoutingKey routingKey = RoutingKeyConverter.RoutingKey.of(key);
-        return BindingSpecification.binding()
-            .exchange(MAILBOX_EVENT_EXCHANGE_NAME)
-            .queue(registrationQueue.asString())
-            .routingKey(routingKey.asString());
-    }
-}
\ No newline at end of file
diff --git a/mailbox/event/event-rabbitmq/src/main/java/org/apache/james/mailbox/events/RegistrationQueueName.java b/mailbox/event/event-rabbitmq/src/main/java/org/apache/james/mailbox/events/RegistrationQueueName.java
deleted file mode 100644
index 33c837b..0000000
--- a/mailbox/event/event-rabbitmq/src/main/java/org/apache/james/mailbox/events/RegistrationQueueName.java
+++ /dev/null
@@ -1,32 +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.mailbox.events;
-
-class RegistrationQueueName {
-    private final String queueName;
-
-    RegistrationQueueName(String queueName) {
-        this.queueName = queueName;
-    }
-
-    String asString() {
-        return queueName;
-    }
-}
diff --git a/mailbox/event/event-rabbitmq/src/main/java/org/apache/james/mailbox/events/RoutingKeyConverter.java b/mailbox/event/event-rabbitmq/src/main/java/org/apache/james/mailbox/events/RoutingKeyConverter.java
deleted file mode 100644
index 755ef27..0000000
--- a/mailbox/event/event-rabbitmq/src/main/java/org/apache/james/mailbox/events/RoutingKeyConverter.java
+++ /dev/null
@@ -1,92 +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.mailbox.events;
-
-import static org.apache.james.backends.rabbitmq.Constants.EMPTY_ROUTING_KEY;
-
-import java.util.List;
-import java.util.Optional;
-import java.util.Set;
-
-import javax.inject.Inject;
-
-import org.apache.james.events.RegistrationKey;
-
-import com.google.common.annotations.VisibleForTesting;
-import com.google.common.base.Joiner;
-import com.google.common.base.Preconditions;
-import com.google.common.base.Splitter;
-import com.google.common.collect.ImmutableSet;
-import com.google.common.collect.Iterables;
-
-public class RoutingKeyConverter {
-    private static final String SEPARATOR = ":";
-
-    static class RoutingKey {
-
-        static RoutingKey empty() {
-            return new RoutingKey(Optional.empty());
-        }
-
-        static RoutingKey of(RegistrationKey key) {
-            return new RoutingKey(Optional.of(key));
-        }
-
-        private final Optional<RegistrationKey> registrationKey;
-
-        private RoutingKey(Optional<RegistrationKey> registrationKey) {
-            this.registrationKey = registrationKey;
-        }
-
-        String asString() {
-            return registrationKey.map(key -> key.getClass().getName() + SEPARATOR + key.asString())
-                .orElse(EMPTY_ROUTING_KEY);
-        }
-    }
-
-    @VisibleForTesting
-    static RoutingKeyConverter forFactories(RegistrationKey.Factory... factories) {
-        return new RoutingKeyConverter(ImmutableSet.copyOf(factories));
-    }
-
-    private final Set<RegistrationKey.Factory> factories;
-
-    @Inject
-    public RoutingKeyConverter(Set<RegistrationKey.Factory> factories) {
-        this.factories = factories;
-    }
-
-    RegistrationKey toRegistrationKey(String routingKey) {
-        return toRegistrationKey(Splitter.on(SEPARATOR).splitToList(routingKey));
-    }
-
-    private RegistrationKey toRegistrationKey(List<String> parts) {
-        Preconditions.checkArgument(parts.size() >= 2, "Routing key needs to match the 'classFQDN:value' pattern");
-
-        String registrationClass = parts.get(0);
-        String value = Joiner.on(SEPARATOR).join(Iterables.skip(parts, 1));
-
-        return factories.stream()
-            .filter(factory -> factory.forClass().getName().equals(registrationClass))
-            .findAny()
-            .orElseThrow(() -> new IllegalArgumentException("No factory for " + registrationClass))
-            .fromString(value);
-    }
-}
\ No newline at end of file
diff --git a/mailbox/event/event-rabbitmq/src/main/java/org/apache/james/mailbox/events/WaitDelayGenerator.java b/mailbox/event/event-rabbitmq/src/main/java/org/apache/james/mailbox/events/WaitDelayGenerator.java
deleted file mode 100644
index 9f2c0fd..0000000
--- a/mailbox/event/event-rabbitmq/src/main/java/org/apache/james/mailbox/events/WaitDelayGenerator.java
+++ /dev/null
@@ -1,83 +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.mailbox.events;
-
-import java.security.SecureRandom;
-import java.time.Duration;
-
-import com.google.common.annotations.VisibleForTesting;
-import com.google.common.base.Preconditions;
-import com.google.common.primitives.Ints;
-
-import reactor.core.publisher.Mono;
-import reactor.core.scheduler.Schedulers;
-
-class WaitDelayGenerator {
-
-    static WaitDelayGenerator of(RetryBackoffConfiguration retryBackoff) {
-        return new WaitDelayGenerator(retryBackoff);
-    }
-
-    private static Duration randomBetween(Duration base, Duration jitter) {
-        Preconditions.checkArgument(!jitter.isNegative(), "jitter value should always be positive");
-        if (jitter.isZero()) {
-            return base;
-        }
-        long maxJitterAsMillis = jitter.toMillis();
-        long jitterAsMillis = SECURE_RANDOM.nextInt(Ints.checkedCast(maxJitterAsMillis * 2)) / 2;
-        return base.plusMillis(jitterAsMillis);
-    }
-
-    private static final SecureRandom SECURE_RANDOM = new SecureRandom();
-
-    private final RetryBackoffConfiguration retryBackoff;
-
-    private WaitDelayGenerator(RetryBackoffConfiguration retryBackoff) {
-        this.retryBackoff = retryBackoff;
-    }
-
-    Mono<Integer> delayIfHaveTo(int retryCount) {
-        Mono<Integer> countRetryMono = Mono.just(retryCount);
-        if (!shouldDelay(retryCount)) {
-            return countRetryMono;
-        }
-
-        return countRetryMono
-            .delayElement(generateDelay(retryCount), Schedulers.elastic());
-    }
-
-    @VisibleForTesting
-    Duration generateDelay(int retryCount) {
-        if (!shouldDelay(retryCount)) {
-            return Duration.ZERO;
-        }
-        long exponentialFactor = Double.valueOf(Math.pow(2, retryCount - 1)).longValue();
-        Duration minDelay = retryBackoff.getFirstBackoff().multipliedBy(exponentialFactor);
-        Duration jitterDelay = retryBackoff.getFirstBackoff()
-            .multipliedBy(Double.valueOf(retryBackoff.getJitterFactor() * 100).intValue())
-            .dividedBy(100);
-
-        return randomBetween(minDelay, jitterDelay);
-    }
-
-    private boolean shouldDelay(int retryCount) {
-        return retryCount >= 1 && retryCount <= retryBackoff.getMaxRetries();
-    }
-}
diff --git a/mailbox/event/event-rabbitmq/src/test/java/org/apache/james/mailbox/events/EventBusIdTest.java b/mailbox/event/event-rabbitmq/src/test/java/org/apache/james/mailbox/events/EventBusIdTest.java
deleted file mode 100644
index 7c6920b..0000000
--- a/mailbox/event/event-rabbitmq/src/test/java/org/apache/james/mailbox/events/EventBusIdTest.java
+++ /dev/null
@@ -1,50 +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.mailbox.events;
-
-import static org.assertj.core.api.Assertions.assertThat;
-
-import java.util.UUID;
-
-import org.junit.jupiter.api.Test;
-
-import nl.jqno.equalsverifier.EqualsVerifier;
-
-class EventBusIdTest {
-
-    private static final UUID UUID_1 = UUID.fromString("6e0dd59d-660e-4d9b-b22f-0354479f47b4");
-
-    @Test
-    void eventBusIdShouldMatchBeanContract() {
-        EqualsVerifier.forClass(EventBusId.class);
-    }
-
-    @Test
-    void ofShouldDeserializeUUIDs() {
-        assertThat(EventBusId.of(UUID_1.toString()))
-            .isEqualTo(EventBusId.of(UUID_1));
-    }
-
-    @Test
-    void asStringShouldReturnWrappedValue() {
-        assertThat(EventBusId.of(UUID_1).asString())
-            .isEqualTo("6e0dd59d-660e-4d9b-b22f-0354479f47b4");
-    }
-}
diff --git a/mailbox/event/event-rabbitmq/src/test/java/org/apache/james/mailbox/events/LocalListenerRegistryTest.java b/mailbox/event/event-rabbitmq/src/test/java/org/apache/james/mailbox/events/LocalListenerRegistryTest.java
deleted file mode 100644
index aa54521..0000000
--- a/mailbox/event/event-rabbitmq/src/test/java/org/apache/james/mailbox/events/LocalListenerRegistryTest.java
+++ /dev/null
@@ -1,256 +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.mailbox.events;
-
-import static org.apache.james.events.EventListener.wrapReactive;
-import static org.assertj.core.api.Assertions.assertThat;
-
-import java.time.Duration;
-import java.util.List;
-import java.util.concurrent.atomic.AtomicInteger;
-
-import org.apache.james.events.EventListener;
-import org.apache.james.mailbox.model.TestId;
-import org.apache.james.util.concurrency.ConcurrentTestRunner;
-import org.junit.jupiter.api.BeforeEach;
-import org.junit.jupiter.api.Nested;
-import org.junit.jupiter.api.Test;
-
-import reactor.core.publisher.Mono;
-import reactor.core.scheduler.Schedulers;
-
-class LocalListenerRegistryTest {
-    private static final MailboxIdRegistrationKey KEY_1 = new MailboxIdRegistrationKey(TestId.of(42));
-
-    private LocalListenerRegistry testee;
-
-    @BeforeEach
-    void setUp() {
-        testee = new LocalListenerRegistry();
-    }
-
-    @Test
-    void getLocalMailboxListenersShouldReturnEmptyWhenNone() {
-        assertThat(testee.getLocalMailboxListeners(KEY_1).collectList().block())
-            .isEmpty();
-    }
-
-    @Test
-    void getLocalMailboxListenersShouldReturnPreviouslyAddedListener() {
-        EventListener listener = event -> { };
-        testee.addListener(KEY_1, listener);
-
-        assertThat(testee.getLocalMailboxListeners(KEY_1).collectList().block())
-            .containsOnly(wrapReactive(listener));
-    }
-
-    @Test
-    void getLocalMailboxListenersShouldReturnPreviouslyAddedListeners() {
-        EventListener listener1 = event -> { };
-        EventListener listener2 = event -> { };
-        testee.addListener(KEY_1, listener1);
-        testee.addListener(KEY_1, listener2);
-
-        assertThat(testee.getLocalMailboxListeners(KEY_1).collectList().block())
-            .containsOnly(wrapReactive(listener1), wrapReactive(listener2));
-    }
-
-    @Test
-    void getLocalMailboxListenersShouldNotReturnRemovedListeners() {
-        EventListener listener1 = event -> { };
-        EventListener listener2 = event -> { };
-        testee.addListener(KEY_1, listener1);
-        LocalListenerRegistry.LocalRegistration registration = testee.addListener(KEY_1, listener2);
-
-        registration.unregister();
-
-        assertThat(testee.getLocalMailboxListeners(KEY_1).collectList().block())
-            .containsOnly(wrapReactive(listener1));
-    }
-
-    @Test
-    void addListenerShouldReturnFirstListenerWhenNoPreviouslyRegisteredListeners() {
-        EventListener listener = event -> { };
-
-        assertThat(testee.addListener(KEY_1, listener).isFirstListener()).isTrue();
-    }
-
-    @Test
-    void addListenerShouldNotReturnFirstListenerWhenPreviouslyRegisteredListeners() {
-        EventListener listener = event -> { };
-        EventListener listener2 = event -> { };
-
-        testee.addListener(KEY_1, listener);
-
-        assertThat(testee.addListener(KEY_1, listener2).isFirstListener()).isFalse();
-    }
-
-    @Test
-    void removeListenerShouldNotReturnLastListenerRemovedWhenSeveralListener() {
-        EventListener listener = event -> { };
-        EventListener listener2 = event -> { };
-
-        LocalListenerRegistry.LocalRegistration registration = testee.addListener(KEY_1, listener);
-        testee.addListener(KEY_1, listener2);
-
-        assertThat(registration.unregister().lastListenerRemoved()).isFalse();
-    }
-
-    @Test
-    void removeListenerShouldReturnLastListenerRemovedWhenOneListener() {
-        EventListener listener = event -> { };
-
-
-        LocalListenerRegistry.LocalRegistration registration = testee.addListener(KEY_1, listener);
-
-        assertThat(registration.unregister().lastListenerRemoved()).isTrue();
-    }
-
-    @Nested
-    class ConcurrentTest {
-        private final Duration oneSecond = Duration.ofSeconds(1);
-
-        @Test
-        void getLocalMailboxListenersShouldReturnPreviousAddedListener() throws Exception {
-            EventListener listener = event -> { };
-
-            ConcurrentTestRunner.builder()
-                .operation((threadNumber, operationNumber) -> testee.addListener(KEY_1, listener))
-                .threadCount(10)
-                .operationCount(10)
-                .runSuccessfullyWithin(oneSecond);
-
-            assertThat(testee.getLocalMailboxListeners(KEY_1).collectList().block())
-                .containsOnly(wrapReactive(listener));
-        }
-
-        @Test
-        void getLocalMailboxListenersShouldReturnAllPreviousAddedListeners() throws Exception {
-            EventListener listener1 = event -> { };
-            EventListener listener2 = event -> { };
-            EventListener listener3 = event -> { };
-
-            ConcurrentTestRunner.builder()
-                .randomlyDistributedOperations(
-                    (threadNumber, operationNumber) -> testee.addListener(KEY_1, listener1),
-                    (threadNumber, operationNumber) -> testee.addListener(KEY_1, listener2),
-                    (threadNumber, operationNumber) -> testee.addListener(KEY_1, listener3))
-                .threadCount(6)
-                .operationCount(10)
-                .runSuccessfullyWithin(oneSecond);
-
-            assertThat(testee.getLocalMailboxListeners(KEY_1).collectList().block())
-                .containsOnly(wrapReactive(listener1), wrapReactive(listener2), wrapReactive(listener3));
-        }
-
-        @Test
-        void getLocalMailboxListenersShouldReturnEmptyWhenRemoveAddedListener() throws Exception {
-            EventListener listener1 = event -> { };
-
-            LocalListenerRegistry.LocalRegistration registration = testee.addListener(KEY_1, listener1);
-
-            ConcurrentTestRunner.builder()
-                .operation(((threadNumber, operationNumber) -> registration.unregister()))
-                .threadCount(10)
-                .operationCount(10)
-                .runSuccessfullyWithin(oneSecond);
-
-            assertThat(testee.getLocalMailboxListeners(KEY_1).collectList().block())
-                .isEmpty();
-        }
-
-        @Test
-        void addListenerOnlyReturnIsFirstListenerForEmptyRegistry() throws Exception {
-            EventListener listener1 = event -> { };
-            EventListener listener2 = event -> { };
-            EventListener listener3 = event -> { };
-
-            AtomicInteger firstListenerCount = new AtomicInteger(0);
-
-            ConcurrentTestRunner.builder()
-                .randomlyDistributedOperations((threadNumber, operationNumber) -> {
-                        LocalListenerRegistry.LocalRegistration registration = testee.addListener(KEY_1, listener1);
-                        if (registration.isFirstListener()) {
-                            firstListenerCount.incrementAndGet();
-                        }
-                    },
-                    (threadNumber, operationNumber) -> {
-                        LocalListenerRegistry.LocalRegistration registration = testee.addListener(KEY_1, listener2);
-                        if (registration.isFirstListener()) {
-                            firstListenerCount.incrementAndGet();
-                        }
-                    },
-                    (threadNumber, operationNumber) -> {
-                        LocalListenerRegistry.LocalRegistration registration = testee.addListener(KEY_1, listener3);
-                        if (registration.isFirstListener()) {
-                            firstListenerCount.incrementAndGet();
-                        }
-                    })
-                .threadCount(6)
-                .operationCount(10)
-                .runSuccessfullyWithin(oneSecond);
-
-            assertThat(firstListenerCount.get()).isEqualTo(1);
-        }
-
-        @Test
-        void removeListenerOnlyReturnLastListenerRemovedForEmptyRegistry() throws Exception {
-            EventListener listener1 = event -> { };
-            AtomicInteger lastListenerRemoved = new AtomicInteger(0);
-
-            LocalListenerRegistry.LocalRegistration registration = testee.addListener(KEY_1, listener1);
-            ConcurrentTestRunner.builder()
-                .operation(((threadNumber, operationNumber) -> {
-                    if (registration.unregister().lastListenerRemoved()) {
-                        lastListenerRemoved.incrementAndGet();
-                    }
-                }))
-                .threadCount(10)
-                .operationCount(10)
-                .runSuccessfullyWithin(oneSecond);
-
-            assertThat(lastListenerRemoved.get()).isEqualTo(1);
-        }
-
-        @Test
-        void iterationShouldPerformOnASnapshotOfListenersSet() {
-            EventListener listener1 = event -> { };
-            EventListener listener2 = event -> { };
-            EventListener listener3 = event -> { };
-            EventListener listener4 = event -> { };
-            EventListener listener5 = event -> { };
-
-            testee.addListener(KEY_1, listener1);
-            testee.addListener(KEY_1, listener2);
-            testee.addListener(KEY_1, listener3);
-            testee.addListener(KEY_1, listener4);
-            LocalListenerRegistry.LocalRegistration registration5 = testee.addListener(KEY_1, listener5);
-
-            Mono<List<EventListener.ReactiveEventListener>> listeners = testee.getLocalMailboxListeners(KEY_1)
-                .publishOn(Schedulers.elastic())
-                .delayElements(Duration.ofMillis(100))
-                .collectList();
-
-            registration5.unregister();
-
-            assertThat(listeners.block(Duration.ofSeconds(10))).hasSize(5);
-        }
-    }
-}
\ No newline at end of file
diff --git a/mailbox/event/event-rabbitmq/src/test/java/org/apache/james/mailbox/events/NetworkErrorTest.java b/mailbox/event/event-rabbitmq/src/test/java/org/apache/james/mailbox/events/NetworkErrorTest.java
deleted file mode 100644
index fd551ec..0000000
--- a/mailbox/event/event-rabbitmq/src/test/java/org/apache/james/mailbox/events/NetworkErrorTest.java
+++ /dev/null
@@ -1,89 +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.mailbox.events;
-
-import static org.apache.james.mailbox.events.EventBusTestFixture.EVENT;
-import static org.apache.james.mailbox.events.EventBusTestFixture.GROUP_A;
-import static org.apache.james.mailbox.events.EventBusTestFixture.NO_KEYS;
-import static org.apache.james.mailbox.events.EventBusTestFixture.RETRY_BACKOFF_CONFIGURATION;
-import static org.apache.james.mailbox.events.EventBusTestFixture.newListener;
-import static org.assertj.core.api.Assertions.assertThatThrownBy;
-import static org.mockito.Mockito.verify;
-
-import org.apache.james.backends.rabbitmq.RabbitMQExtension;
-import org.apache.james.backends.rabbitmq.RabbitMQFixture;
-import org.apache.james.event.json.EventSerializer;
-import org.apache.james.events.EventListener;
-import org.apache.james.mailbox.model.TestId;
-import org.apache.james.mailbox.model.TestMessageId;
-import org.apache.james.mailbox.store.quota.DefaultUserQuotaRootResolver;
-import org.apache.james.metrics.tests.RecordingMetricFactory;
-import org.junit.jupiter.api.AfterEach;
-import org.junit.jupiter.api.BeforeEach;
-import org.junit.jupiter.api.Test;
-import org.junit.jupiter.api.extension.RegisterExtension;
-
-class NetworkErrorTest {
-    @RegisterExtension
-    static RabbitMQExtension rabbitMQExtension = RabbitMQExtension.singletonRabbitMQ()
-        .isolationPolicy(RabbitMQExtension.IsolationPolicy.WEAK);
-
-    private RabbitMQEventBus eventBus;
-
-    @BeforeEach
-    void setUp() {
-        MemoryEventDeadLetters memoryEventDeadLetters = new MemoryEventDeadLetters();
-
-        TestId.Factory mailboxIdFactory = new TestId.Factory();
-        EventSerializer eventSerializer = new EventSerializer(mailboxIdFactory, new TestMessageId.Factory(), new DefaultUserQuotaRootResolver.DefaultQuotaRootDeserializer());
-        RoutingKeyConverter routingKeyConverter = RoutingKeyConverter.forFactories(new MailboxIdRegistrationKey.Factory(mailboxIdFactory));
-
-        eventBus = new RabbitMQEventBus(rabbitMQExtension.getSender(), rabbitMQExtension.getReceiverProvider(),
-            eventSerializer, RETRY_BACKOFF_CONFIGURATION, routingKeyConverter,
-            memoryEventDeadLetters, new RecordingMetricFactory(), rabbitMQExtension.getRabbitChannelPool(),
-            EventBusId.random());
-
-        eventBus.start();
-    }
-
-    @AfterEach
-    void tearDown() {
-        eventBus.stop();
-    }
-
-    @Test
-    void dispatchShouldWorkAfterNetworkIssuesForOldRegistration() {
-        EventListener listener = newListener();
-        eventBus.register(listener, GROUP_A);
-
-        rabbitMQExtension.getRabbitMQ().pause();
-
-        assertThatThrownBy(() -> eventBus.dispatch(EVENT, NO_KEYS).block())
-            .isInstanceOf(IllegalStateException.class)
-            .hasMessageContaining("Retries exhausted");
-
-        rabbitMQExtension.getRabbitMQ().unpause();
-
-        eventBus.dispatch(EVENT, NO_KEYS).block();
-        RabbitMQFixture.awaitAtMostThirtySeconds
-            .untilAsserted(() -> verify(listener).event(EVENT));
-    }
-
-}
diff --git a/mailbox/event/event-rabbitmq/src/test/java/org/apache/james/mailbox/events/RabbitMQEventBusDeadLetterQueueUpgradeTest.java b/mailbox/event/event-rabbitmq/src/test/java/org/apache/james/mailbox/events/RabbitMQEventBusDeadLetterQueueUpgradeTest.java
deleted file mode 100644
index 9ed6dad..0000000
--- a/mailbox/event/event-rabbitmq/src/test/java/org/apache/james/mailbox/events/RabbitMQEventBusDeadLetterQueueUpgradeTest.java
+++ /dev/null
@@ -1,88 +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.mailbox.events;
-
-import static org.apache.james.backends.rabbitmq.Constants.AUTO_DELETE;
-import static org.apache.james.backends.rabbitmq.Constants.DURABLE;
-import static org.apache.james.backends.rabbitmq.Constants.EXCLUSIVE;
-import static org.apache.james.mailbox.events.EventBusTestFixture.RETRY_BACKOFF_CONFIGURATION;
-import static org.assertj.core.api.Assertions.assertThatCode;
-
-import org.apache.james.backends.rabbitmq.RabbitMQExtension;
-import org.apache.james.event.json.EventSerializer;
-import org.apache.james.mailbox.events.EventBusTestFixture.GroupA;
-import org.apache.james.mailbox.events.GroupRegistration.WorkQueueName;
-import org.apache.james.mailbox.model.TestId;
-import org.apache.james.mailbox.model.TestMessageId;
-import org.apache.james.mailbox.store.quota.DefaultUserQuotaRootResolver;
-import org.apache.james.mailbox.util.EventCollector;
-import org.apache.james.metrics.tests.RecordingMetricFactory;
-import org.junit.jupiter.api.AfterEach;
-import org.junit.jupiter.api.BeforeEach;
-import org.junit.jupiter.api.Test;
-import org.junit.jupiter.api.extension.RegisterExtension;
-
-import reactor.rabbitmq.QueueSpecification;
-
-class RabbitMQEventBusDeadLetterQueueUpgradeTest {
-    @RegisterExtension
-    static RabbitMQExtension rabbitMQExtension = RabbitMQExtension.singletonRabbitMQ()
-        .isolationPolicy(RabbitMQExtension.IsolationPolicy.WEAK);
-
-    private RabbitMQEventBus eventBus;
-
-    @BeforeEach
-    void setUp() {
-        MemoryEventDeadLetters memoryEventDeadLetters = new MemoryEventDeadLetters();
-
-        TestId.Factory mailboxIdFactory = new TestId.Factory();
-        EventSerializer eventSerializer = new EventSerializer(mailboxIdFactory, new TestMessageId.Factory(), new DefaultUserQuotaRootResolver.DefaultQuotaRootDeserializer());
-        RoutingKeyConverter routingKeyConverter = RoutingKeyConverter.forFactories(new MailboxIdRegistrationKey.Factory(mailboxIdFactory));
-
-        eventBus = new RabbitMQEventBus(rabbitMQExtension.getSender(), rabbitMQExtension.getReceiverProvider(),
-            eventSerializer, RETRY_BACKOFF_CONFIGURATION, routingKeyConverter,
-            memoryEventDeadLetters, new RecordingMetricFactory(), rabbitMQExtension.getRabbitChannelPool(),
-            EventBusId.random());
-
-        eventBus.start();
-    }
-
-    @AfterEach
-    void tearDown() {
-        eventBus.stop();
-    }
-
-    @Test
-    void eventBusShouldStartWhenDeadLetterUpgradeWasNotPerformed() {
-        GroupA registeredGroup = new GroupA();
-        WorkQueueName workQueueName = WorkQueueName.of(registeredGroup);
-        
-        rabbitMQExtension.getSender()
-            .declareQueue(QueueSpecification.queue(workQueueName.asString())
-                .durable(DURABLE)
-                .exclusive(!EXCLUSIVE)
-                .autoDelete(!AUTO_DELETE))
-            .block();
-
-        assertThatCode(eventBus::start).doesNotThrowAnyException();
-        assertThatCode(() -> eventBus.register(new EventCollector(), registeredGroup)).doesNotThrowAnyException();
-    }
-
-}
diff --git a/mailbox/event/event-rabbitmq/src/test/java/org/apache/james/mailbox/events/RabbitMQEventBusTest.java b/mailbox/event/event-rabbitmq/src/test/java/org/apache/james/mailbox/events/RabbitMQEventBusTest.java
deleted file mode 100644
index a167ca9..0000000
--- a/mailbox/event/event-rabbitmq/src/test/java/org/apache/james/mailbox/events/RabbitMQEventBusTest.java
+++ /dev/null
@@ -1,980 +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.mailbox.events;
-
-import static org.apache.james.backends.rabbitmq.Constants.AUTO_DELETE;
-import static org.apache.james.backends.rabbitmq.Constants.DIRECT_EXCHANGE;
-import static org.apache.james.backends.rabbitmq.Constants.DURABLE;
-import static org.apache.james.backends.rabbitmq.Constants.EMPTY_ROUTING_KEY;
-import static org.apache.james.backends.rabbitmq.Constants.EXCLUSIVE;
-import static org.apache.james.backends.rabbitmq.Constants.NO_ARGUMENTS;
-import static org.apache.james.mailbox.events.EventBusConcurrentTestContract.newCountingListener;
-import static org.apache.james.mailbox.events.EventBusTestFixture.ALL_GROUPS;
-import static org.apache.james.mailbox.events.EventBusTestFixture.EVENT;
-import static org.apache.james.mailbox.events.EventBusTestFixture.EVENT_2;
-import static org.apache.james.mailbox.events.EventBusTestFixture.GROUP_A;
-import static org.apache.james.mailbox.events.EventBusTestFixture.GROUP_B;
-import static org.apache.james.mailbox.events.EventBusTestFixture.KEY_1;
-import static org.apache.james.mailbox.events.EventBusTestFixture.NO_KEYS;
-import static org.apache.james.mailbox.events.EventBusTestFixture.newAsyncListener;
-import static org.apache.james.mailbox.events.EventBusTestFixture.newListener;
-import static org.apache.james.mailbox.events.GroupRegistration.WorkQueueName.MAILBOX_EVENT_WORK_QUEUE_PREFIX;
-import static org.apache.james.mailbox.events.RabbitMQEventBus.MAILBOX_EVENT;
-import static org.apache.james.mailbox.events.RabbitMQEventBus.MAILBOX_EVENT_DEAD_LETTER_QUEUE;
-import static org.apache.james.mailbox.events.RabbitMQEventBus.MAILBOX_EVENT_EXCHANGE_NAME;
-import static org.assertj.core.api.Assertions.assertThat;
-import static org.assertj.core.api.Assertions.assertThatCode;
-import static org.assertj.core.api.Assertions.assertThatThrownBy;
-import static org.awaitility.Awaitility.await;
-import static org.mockito.ArgumentMatchers.any;
-import static org.mockito.Mockito.doAnswer;
-import static org.mockito.Mockito.mock;
-import static org.mockito.Mockito.spy;
-import static org.mockito.Mockito.verify;
-import static org.mockito.Mockito.when;
-
-import java.io.Closeable;
-import java.nio.charset.StandardCharsets;
-import java.time.Duration;
-import java.util.concurrent.TimeUnit;
-import java.util.concurrent.atomic.AtomicInteger;
-import java.util.stream.IntStream;
-import java.util.stream.Stream;
-
-import org.apache.james.backends.rabbitmq.RabbitMQExtension;
-import org.apache.james.backends.rabbitmq.RabbitMQExtension.DockerRestartPolicy;
-import org.apache.james.backends.rabbitmq.RabbitMQFixture;
-import org.apache.james.backends.rabbitmq.RabbitMQManagementAPI;
-import org.apache.james.backends.rabbitmq.ReceiverProvider;
-import org.apache.james.event.json.EventSerializer;
-import org.apache.james.events.Event;
-import org.apache.james.events.EventBus;
-import org.apache.james.events.EventDeadLetters;
-import org.apache.james.events.EventListener;
-import org.apache.james.events.Group;
-import org.apache.james.events.GroupRegistrationNotFound;
-import org.apache.james.mailbox.events.EventBusTestFixture.EventListenerCountingSuccessfulExecution;
-import org.apache.james.mailbox.events.EventBusTestFixture.GroupA;
-import org.apache.james.mailbox.events.EventDispatcher.DispatchingFailureGroup;
-import org.apache.james.mailbox.events.RoutingKeyConverter.RoutingKey;
-import org.apache.james.mailbox.model.TestId;
-import org.apache.james.mailbox.model.TestMessageId;
-import org.apache.james.mailbox.store.quota.DefaultUserQuotaRootResolver;
-import org.apache.james.mailbox.util.EventCollector;
-import org.apache.james.metrics.tests.RecordingMetricFactory;
-import org.apache.james.util.concurrency.ConcurrentTestRunner;
-import org.assertj.core.data.Percentage;
-import org.awaitility.Awaitility;
-import org.junit.jupiter.api.AfterEach;
-import org.junit.jupiter.api.BeforeEach;
-import org.junit.jupiter.api.Disabled;
-import org.junit.jupiter.api.Nested;
-import org.junit.jupiter.api.Test;
-import org.junit.jupiter.api.extension.RegisterExtension;
-import org.mockito.stubbing.Answer;
-
-import com.google.common.collect.ImmutableSet;
-
-import reactor.core.publisher.Mono;
-import reactor.core.scheduler.Schedulers;
-import reactor.rabbitmq.BindingSpecification;
-import reactor.rabbitmq.ExchangeSpecification;
-import reactor.rabbitmq.OutboundMessage;
-import reactor.rabbitmq.QueueSpecification;
-import reactor.rabbitmq.Receiver;
-import reactor.rabbitmq.Sender;
-
-class RabbitMQEventBusTest implements GroupContract.SingleEventBusGroupContract, GroupContract.MultipleEventBusGroupContract,
-    KeyContract.SingleEventBusKeyContract, KeyContract.MultipleEventBusKeyContract,
-    ErrorHandlingContract {
-
-    @RegisterExtension
-    static RabbitMQExtension rabbitMQExtension = RabbitMQExtension.singletonRabbitMQ()
-        .isolationPolicy(RabbitMQExtension.IsolationPolicy.WEAK);
-
-    private RabbitMQEventBus eventBus;
-    private RabbitMQEventBus eventBus2;
-    private RabbitMQEventBus eventBus3;
-    private RabbitMQEventBus eventBusWithKeyHandlerNotStarted;
-    private EventSerializer eventSerializer;
-    private RoutingKeyConverter routingKeyConverter;
-    private MemoryEventDeadLetters memoryEventDeadLetters;
-
-    @Override
-    public EnvironmentSpeedProfile getSpeedProfile() {
-        return EnvironmentSpeedProfile.SLOW;
-    }
-
-    @BeforeEach
-    void setUp() {
-        memoryEventDeadLetters = new MemoryEventDeadLetters();
-
-        TestId.Factory mailboxIdFactory = new TestId.Factory();
-        eventSerializer = new EventSerializer(mailboxIdFactory, new TestMessageId.Factory(), new DefaultUserQuotaRootResolver.DefaultQuotaRootDeserializer());
-        routingKeyConverter = RoutingKeyConverter.forFactories(new MailboxIdRegistrationKey.Factory(mailboxIdFactory));
-
-        eventBus = newEventBus();
-        eventBus2 = newEventBus();
-        eventBus3 = newEventBus();
-        eventBusWithKeyHandlerNotStarted = newEventBus();
-
-        eventBus.start();
-        eventBus2.start();
-        eventBus3.start();
-        eventBusWithKeyHandlerNotStarted.startWithoutStartingKeyRegistrationHandler();
-    }
-
-    @AfterEach
-    void tearDown() {
-        eventBus.stop();
-        eventBus2.stop();
-        eventBus3.stop();
-        eventBusWithKeyHandlerNotStarted.stop();
-        ALL_GROUPS.stream()
-            .map(GroupRegistration.WorkQueueName::of)
-            .forEach(queueName -> rabbitMQExtension.getSender().delete(QueueSpecification.queue(queueName.asString())).block());
-        rabbitMQExtension.getSender()
-            .delete(ExchangeSpecification.exchange(MAILBOX_EVENT_EXCHANGE_NAME))
-            .block();
-    }
-
-    private RabbitMQEventBus newEventBus() {
-        return newEventBus(rabbitMQExtension.getSender(), rabbitMQExtension.getReceiverProvider());
-    }
-
-    private RabbitMQEventBus newEventBus(Sender sender, ReceiverProvider receiverProvider) {
-        return new RabbitMQEventBus(sender, receiverProvider, eventSerializer,
-            EventBusTestFixture.RETRY_BACKOFF_CONFIGURATION, routingKeyConverter,
-            memoryEventDeadLetters, new RecordingMetricFactory(),
-            rabbitMQExtension.getRabbitChannelPool(), EventBusId.random());
-    }
-
-    @Override
-    public EventBus eventBus() {
-        return eventBus;
-    }
-
-    @Override
-    public EventBus eventBus2() {
-        return eventBus2;
-    }
-
-    @Override
-    public EventDeadLetters deadLetter() {
-        return memoryEventDeadLetters;
-    }
-
-    @Override
-    @Test
-    @Disabled("This test is failing by design as the different registration keys are handled by distinct messages")
-    public void dispatchShouldCallListenerOnceWhenSeveralKeysMatching() {
-
-    }
-
-    @Test
-    void eventProcessingShouldNotCrashOnInvalidMessage() {
-        EventCollector listener = new EventCollector();
-        EventBusTestFixture.GroupA registeredGroup = new EventBusTestFixture.GroupA();
-        eventBus.register(listener, registeredGroup);
-
-        String emptyRoutingKey = "";
-        rabbitMQExtension.getSender()
-            .send(Mono.just(new OutboundMessage(MAILBOX_EVENT_EXCHANGE_NAME,
-                emptyRoutingKey,
-                "BAD_PAYLOAD!".getBytes(StandardCharsets.UTF_8))))
-            .block();
-
-        eventBus.dispatch(EVENT, NO_KEYS).block();
-        await()
-            .timeout(org.awaitility.Duration.TEN_SECONDS).untilAsserted(() ->
-                assertThat(listener.getEvents()).containsOnly(EVENT));
-    }
-
-    @Test
-    void eventProcessingShouldNotCrashOnInvalidMessages() {
-        EventCollector listener = new EventCollector();
-        EventBusTestFixture.GroupA registeredGroup = new EventBusTestFixture.GroupA();
-        eventBus.register(listener, registeredGroup);
-
-        String emptyRoutingKey = "";
-        IntStream.range(0, 10).forEach(i -> rabbitMQExtension.getSender()
-            .send(Mono.just(new OutboundMessage(MAILBOX_EVENT_EXCHANGE_NAME,
-                emptyRoutingKey,
-                "BAD_PAYLOAD!".getBytes(StandardCharsets.UTF_8))))
-            .block());
-
-        eventBus.dispatch(EVENT, NO_KEYS).block();
-        await()
-            .timeout(org.awaitility.Duration.TEN_SECONDS).untilAsserted(() ->
-            assertThat(listener.getEvents()).containsOnly(EVENT));
-    }
-
-    @Test
-    void eventProcessingShouldStoreInvalidMessagesInDeadLetterQueue() {
-        EventCollector listener = new EventCollector();
-        EventBusTestFixture.GroupA registeredGroup = new EventBusTestFixture.GroupA();
-        eventBus.register(listener, registeredGroup);
-
-        String emptyRoutingKey = "";
-        rabbitMQExtension.getSender()
-            .send(Mono.just(new OutboundMessage(MAILBOX_EVENT_EXCHANGE_NAME,
-                emptyRoutingKey,
-                "BAD_PAYLOAD!".getBytes(StandardCharsets.UTF_8))))
-            .block();
-
-        AtomicInteger deadLetteredCount = new AtomicInteger();
-        rabbitMQExtension.getRabbitChannelPool()
-            .createReceiver()
-            .consumeAutoAck(MAILBOX_EVENT_DEAD_LETTER_QUEUE)
-            .doOnNext(next -> deadLetteredCount.incrementAndGet())
-            .subscribeOn(Schedulers.elastic())
-            .subscribe();
-
-        Awaitility.await().atMost(org.awaitility.Duration.TEN_SECONDS)
-            .untilAsserted(() -> assertThat(deadLetteredCount.get()).isEqualTo(1));
-    }
-
-    @Test
-    void registrationShouldNotCrashOnInvalidMessage() {
-        EventCollector listener = new EventCollector();
-        Mono.from(eventBus.register(listener, KEY_1)).block();
-
-        rabbitMQExtension.getSender()
-            .send(Mono.just(new OutboundMessage(MAILBOX_EVENT_EXCHANGE_NAME,
-                RoutingKey.of(KEY_1).asString(),
-                "BAD_PAYLOAD!".getBytes(StandardCharsets.UTF_8))))
-            .block();
-
-        eventBus.dispatch(EVENT, KEY_1).block();
-        await().timeout(org.awaitility.Duration.TEN_SECONDS)
-            .untilAsserted(() -> assertThat(listener.getEvents()).containsOnly(EVENT));
-    }
-
-    @Test
-    void registrationShouldNotCrashOnInvalidMessages() {
-        EventCollector listener = new EventCollector();
-        Mono.from(eventBus.register(listener, KEY_1)).block();
-
-        IntStream.range(0, 100)
-            .forEach(i -> rabbitMQExtension.getSender()
-                .send(Mono.just(new OutboundMessage(MAILBOX_EVENT_EXCHANGE_NAME,
-                    RoutingKey.of(KEY_1).asString(),
-                    "BAD_PAYLOAD!".getBytes(StandardCharsets.UTF_8))))
-                .block());
-
-        eventBus.dispatch(EVENT, KEY_1).block();
-        await().timeout(org.awaitility.Duration.TEN_SECONDS)
-            .untilAsserted(() -> assertThat(listener.getEvents()).containsOnly(EVENT));
-    }
-
-    @Test
-    void deserializeEventCollectorGroup() throws Exception {
-        assertThat(Group.deserialize("org.apache.james.mailbox.util.EventCollector$EventCollectorGroup"))
-            .isEqualTo(new EventCollector.EventCollectorGroup());
-    }
-
-    @Test
-    void registerGroupShouldCreateRetryExchange() throws Exception {
-        EventListener listener = newListener();
-        EventBusTestFixture.GroupA registeredGroup = new EventBusTestFixture.GroupA();
-        eventBus.register(listener, registeredGroup);
-
-        GroupConsumerRetry.RetryExchangeName retryExchangeName = GroupConsumerRetry.RetryExchangeName.of(registeredGroup);
-        assertThat(rabbitMQExtension.managementAPI().listExchanges())
-            .anyMatch(exchange -> exchange.getName().equals(retryExchangeName.asString()));
-    }
-
-    @Nested
-    class ConcurrentTest implements EventBusConcurrentTestContract.MultiEventBusConcurrentContract,
-        EventBusConcurrentTestContract.SingleEventBusConcurrentContract {
-
-        @Override
-        public EnvironmentSpeedProfile getSpeedProfile() {
-            return EnvironmentSpeedProfile.SLOW;
-        }
-
-        @Test
-        void rabbitMQEventBusShouldHandleBulksGracefully() throws Exception {
-            EventListenerCountingSuccessfulExecution countingListener1 = newCountingListener();
-            eventBus().register(countingListener1, new EventBusTestFixture.GroupA());
-            int totalGlobalRegistrations = 1; // GroupA
-
-            int threadCount = 10;
-            int operationCount = 10000;
-            int totalDispatchOperations = threadCount * operationCount;
-            eventBus = (RabbitMQEventBus) eventBus();
-            ConcurrentTestRunner.builder()
-                .operation((threadNumber, operationNumber) -> eventBus.dispatch(EVENT, NO_KEYS).block())
-                .threadCount(threadCount)
-                .operationCount(operationCount)
-                .runSuccessfullyWithin(Duration.ofMinutes(3));
-
-            await()
-                .pollInterval(org.awaitility.Duration.FIVE_SECONDS)
-                .timeout(org.awaitility.Duration.TEN_MINUTES).untilAsserted(() ->
-                    assertThat(countingListener1.numberOfEventCalls()).isEqualTo((totalGlobalRegistrations * totalDispatchOperations)));
-        }
-
-        @Override
-        public EventBus eventBus3() {
-            return eventBus3;
-        }
-
-        @Override
-        public EventBus eventBus2() {
-            return eventBus2;
-        }
-
-        @Override
-        public EventBus eventBus() {
-            return eventBus;
-        }
-    }
-
-    @Nested
-    class AtLeastOnceTest {
-
-        @Test
-        void inProcessingEventShouldBeReDispatchedToAnotherEventBusWhenOneIsDown() {
-            EventListenerCountingSuccessfulExecution eventBusListener = spy(new EventListenerCountingSuccessfulExecution());
-            EventListenerCountingSuccessfulExecution eventBus2Listener = spy(new EventListenerCountingSuccessfulExecution());
-            EventListenerCountingSuccessfulExecution eventBus3Listener = spy(new EventListenerCountingSuccessfulExecution());
-            Answer<?> callEventAndSleepForever = invocation -> {
-                invocation.callRealMethod();
-                TimeUnit.SECONDS.sleep(Long.MAX_VALUE);
-                return null;
-            };
-
-            doAnswer(callEventAndSleepForever).when(eventBusListener).event(any());
-            doAnswer(callEventAndSleepForever).when(eventBus2Listener).event(any());
-
-            eventBus.register(eventBusListener, GROUP_A);
-            eventBus2.register(eventBus2Listener, GROUP_A);
-            eventBus3.register(eventBus3Listener, GROUP_A);
-
-            eventBus.dispatch(EVENT, NO_KEYS).block();
-            getSpeedProfile().shortWaitCondition()
-                .untilAsserted(() -> assertThat(eventBusListener.numberOfEventCalls()).isEqualTo(1));
-            eventBus.stop();
-
-            getSpeedProfile().shortWaitCondition()
-                .untilAsserted(() -> assertThat(eventBus2Listener.numberOfEventCalls()).isEqualTo(1));
-            eventBus2.stop();
-
-            getSpeedProfile().shortWaitCondition()
-                .untilAsserted(() -> assertThat(eventBus3Listener.numberOfEventCalls()).isEqualTo(1));
-        }
-    }
-
-    @Nested
-    class PublishingTest {
-        private static final String MAILBOX_WORK_QUEUE_NAME = MAILBOX_EVENT + "-workQueue";
-
-        @BeforeEach
-        void setUp() {
-            Sender sender = rabbitMQExtension.getSender();
-
-            sender.declareQueue(QueueSpecification.queue(MAILBOX_WORK_QUEUE_NAME)
-                .durable(DURABLE)
-                .exclusive(!EXCLUSIVE)
-                .autoDelete(!AUTO_DELETE)
-                .arguments(NO_ARGUMENTS))
-                .block();
-            sender.bind(BindingSpecification.binding()
-                .exchange(MAILBOX_EVENT_EXCHANGE_NAME)
-                .queue(MAILBOX_WORK_QUEUE_NAME)
-                .routingKey(EMPTY_ROUTING_KEY))
-                .block();
-        }
-
-        @Test
-        void dispatchShouldPublishSerializedEventToRabbitMQ() {
-            eventBus.dispatch(EVENT, NO_KEYS).block();
-
-            assertThat(dequeueEvent()).isEqualTo(EVENT);
-        }
-
-        @Test
-        void dispatchShouldPublishSerializedEventToRabbitMQWhenNotBlocking() {
-            eventBus.dispatch(EVENT, NO_KEYS).block();
-
-            assertThat(dequeueEvent()).isEqualTo(EVENT);
-        }
-
-        private Event dequeueEvent() {
-            try (Receiver receiver = rabbitMQExtension.getReceiverProvider().createReceiver()) {
-                byte[] eventInBytes = receiver.consumeAutoAck(MAILBOX_WORK_QUEUE_NAME)
-                    .blockFirst()
-                    .getBody();
-
-                return eventSerializer.fromJson(new String(eventInBytes, StandardCharsets.UTF_8))
-                    .get();
-            }
-        }
-    }
-
-    @Nested
-    class LifeCycleTest {
-        private static final int THREAD_COUNT = 10;
-        private static final int OPERATION_COUNT = 100000;
-
-        private RabbitMQManagementAPI rabbitManagementAPI;
-
-        @BeforeEach
-        void setUp() throws Exception {
-            rabbitManagementAPI = rabbitMQExtension.managementAPI();
-        }
-
-        @AfterEach
-        void tearDown() {
-            rabbitMQExtension.getRabbitMQ().unpause();
-        }
-
-        @Nested
-        class SingleEventBus {
-
-            @Nested
-            class DispatchingWhenNetWorkIssue {
-
-                @RegisterExtension
-                RabbitMQExtension rabbitMQNetWorkIssueExtension = RabbitMQExtension.defaultRabbitMQ()
-                    .restartPolicy(DockerRestartPolicy.PER_TEST)
-                    .isolationPolicy(RabbitMQExtension.IsolationPolicy.WEAK);
-
-                private RabbitMQEventBus rabbitMQEventBusWithNetWorkIssue;
-
-                @BeforeEach
-                void beforeEach() {
-                    rabbitMQEventBusWithNetWorkIssue = newEventBus(rabbitMQNetWorkIssueExtension.getSender(), rabbitMQNetWorkIssueExtension.getReceiverProvider());
-                }
-
-                @Test
-                void dispatchShouldWorkAfterNetworkIssuesForOldRegistrationAndKey() {
-                    rabbitMQEventBusWithNetWorkIssue.start();
-                    EventListener listener = newListener();
-                    Mono.from(rabbitMQEventBusWithNetWorkIssue.register(listener, KEY_1)).block();
-
-                    rabbitMQNetWorkIssueExtension.getRabbitMQ().pause();
-
-                    assertThatThrownBy(() -> rabbitMQEventBusWithNetWorkIssue.dispatch(EVENT, NO_KEYS).block())
-                        .isInstanceOf(IllegalStateException.class)
-                        .hasMessageContaining("Retries exhausted");
-
-                    rabbitMQNetWorkIssueExtension.getRabbitMQ().unpause();
-
-                    rabbitMQEventBusWithNetWorkIssue.dispatch(EVENT, ImmutableSet.of(KEY_1)).block();
-                    assertThatListenerReceiveOneEvent(listener);
-                }
-            }
-
-            @Test
-            void startShouldCreateEventExchange() {
-                eventBus.start();
-                assertThat(rabbitManagementAPI.listExchanges())
-                    .filteredOn(exchange -> exchange.getName().equals(MAILBOX_EVENT_EXCHANGE_NAME))
-                    .hasOnlyOneElementSatisfying(exchange -> {
-                        assertThat(exchange.isDurable()).isTrue();
-                        assertThat(exchange.getType()).isEqualTo(DIRECT_EXCHANGE);
-                    });
-            }
-
-            @Test
-            void dispatchShouldWorkAfterRestartForOldRegistration() throws Exception {
-                eventBus.start();
-                EventListener listener = newListener();
-                eventBus.register(listener, GROUP_A);
-
-                rabbitMQExtension.getRabbitMQ().restart();
-
-                eventBus.dispatch(EVENT, NO_KEYS).block();
-                assertThatListenerReceiveOneEvent(listener);
-            }
-
-            @Test
-            void dispatchShouldWorkAfterRestartForNewRegistration() throws Exception {
-                eventBus.start();
-                EventListener listener = newListener();
-
-                rabbitMQExtension.getRabbitMQ().restart();
-
-                eventBus.register(listener, GROUP_A);
-
-                eventBus.dispatch(EVENT, NO_KEYS).block();
-
-                assertThatListenerReceiveOneEvent(listener);
-
-            }
-
-            @Test
-            void redeliverShouldWorkAfterRestartForOldRegistration() throws Exception {
-                eventBus.start();
-                EventListener listener = newListener();
-                eventBus.register(listener, GROUP_A);
-
-                rabbitMQExtension.getRabbitMQ().restart();
-
-                eventBus.reDeliver(GROUP_A, EVENT).block();
-                assertThatListenerReceiveOneEvent(listener);
-            }
-
-            @Test
-            void redeliverShouldWorkAfterRestartForNewRegistration() throws Exception {
-                eventBus.start();
-                EventListener listener = newListener();
-
-                rabbitMQExtension.getRabbitMQ().restart();
-
-                eventBus.register(listener, GROUP_A);
-
-                eventBus.reDeliver(GROUP_A, EVENT).block();
-                assertThatListenerReceiveOneEvent(listener);
-            }
-
-            @Test
-            void dispatchShouldWorkAfterRestartForOldKeyRegistration() throws Exception {
-                eventBus.start();
-                EventListener listener = newListener();
-                Mono.from(eventBus.register(listener, KEY_1)).block();
-
-                rabbitMQExtension.getRabbitMQ().restart();
-
-                eventBus.dispatch(EVENT, KEY_1).block();
-                assertThatListenerReceiveOneEvent(listener);
-            }
-
-            @Test
-            void dispatchedMessagesShouldSurviveARabbitMQRestart() throws Exception {
-                eventBusWithKeyHandlerNotStarted.startWithoutStartingKeyRegistrationHandler();
-                EventListener listener = newAsyncListener();
-                Mono.from(eventBusWithKeyHandlerNotStarted.register(listener, KEY_1)).block();
-                Mono<Void> dispatch = eventBusWithKeyHandlerNotStarted.dispatch(EVENT, KEY_1);
-                dispatch.block();
-
-                rabbitMQExtension.getRabbitMQ().restart();
-
-                eventBusWithKeyHandlerNotStarted.startKeyRegistrationHandler();
-
-                assertThatListenerReceiveOneEvent(listener);
-            }
-
-            @Disabled("JAMES-3083 Disable this unstable test")
-            @Test
-            void dispatchShouldWorkAfterRestartForNewKeyRegistration() throws Exception {
-                eventBus.start();
-                EventListener listener = newListener();
-
-                rabbitMQExtension.getRabbitMQ().restart();
-
-                Mono.from(eventBus.register(listener, KEY_1)).block();
-
-                eventBus.dispatch(EVENT, KEY_1).block();
-                assertThatListenerReceiveOneEvent(listener);
-            }
-
-            @Test
-            void dispatchShouldWorkAfterNetworkIssuesForNewRegistration() {
-                eventBus.start();
-                EventListener listener = newListener();
-
-                rabbitMQExtension.getRabbitMQ().pause();
-
-                assertThatThrownBy(() -> eventBus.dispatch(EVENT, NO_KEYS).block())
-                    .isInstanceOf(IllegalStateException.class)
-                    .hasMessageContaining("Retries exhausted");
-
-                rabbitMQExtension.getRabbitMQ().unpause();
-
-                eventBus.register(listener, GROUP_A);
-                eventBus.dispatch(EVENT, NO_KEYS).block();
-                assertThatListenerReceiveOneEvent(listener);
-            }
-
-            @Test
-            void redeliverShouldWorkAfterNetworkIssuesForNewRegistration() {
-                eventBus.start();
-                EventListener listener = newListener();
-
-                rabbitMQExtension.getRabbitMQ().pause();
-
-                assertThatThrownBy(() -> eventBus.reDeliver(GROUP_A, EVENT).block())
-                    .isInstanceOf(GroupRegistrationNotFound.class);
-
-                rabbitMQExtension.getRabbitMQ().unpause();
-
-                eventBus.register(listener, GROUP_A);
-                eventBus.reDeliver(GROUP_A, EVENT).block();
-                assertThatListenerReceiveOneEvent(listener);
-            }
-
-            @Test
-            void dispatchShouldWorkAfterNetworkIssuesForOldKeyRegistration() {
-                eventBus.start();
-                EventListener listener = newListener();
-                when(listener.getExecutionMode()).thenReturn(EventListener.ExecutionMode.ASYNCHRONOUS);
-                Mono.from(eventBus.register(listener, KEY_1)).block();
-
-                rabbitMQExtension.getRabbitMQ().pause();
-
-                assertThatThrownBy(() -> eventBus.dispatch(EVENT, NO_KEYS).block())
-                    .isInstanceOf(IllegalStateException.class)
-                    .hasMessageContaining("Retries exhausted");
-
-                rabbitMQExtension.getRabbitMQ().unpause();
-
-                eventBus.dispatch(EVENT, KEY_1).block();
-                assertThatListenerReceiveOneEvent(listener);
-            }
-
-            @Test
-            void dispatchShouldWorkAfterNetworkIssuesForNewKeyRegistration() {
-                eventBus.start();
-                EventListener listener = newListener();
-                when(listener.getExecutionMode()).thenReturn(EventListener.ExecutionMode.ASYNCHRONOUS);
-
-                rabbitMQExtension.getRabbitMQ().pause();
-
-                assertThatThrownBy(() -> eventBus.dispatch(EVENT, NO_KEYS).block())
-                    .isInstanceOf(IllegalStateException.class)
-                    .hasMessageContaining("Retries exhausted");
-
-                rabbitMQExtension.getRabbitMQ().unpause();
-
-                Mono.from(eventBus.register(listener, KEY_1)).block();
-                eventBus.dispatch(EVENT, KEY_1).block();
-                assertThatListenerReceiveOneEvent(listener);
-            }
-
-            @Test
-            void stopShouldNotDeleteEventBusExchange() {
-                eventBus.start();
-                eventBus.stop();
-
-                assertThat(rabbitManagementAPI.listExchanges())
-                    .anySatisfy(exchange -> assertThat(exchange.getName()).isEqualTo(MAILBOX_EVENT_EXCHANGE_NAME));
-            }
-
-            @Test
-            void stopShouldNotDeleteGroupRegistrationWorkQueue() {
-                eventBus.start();
-                eventBus.register(mock(EventListener.class), GROUP_A);
-                eventBus.stop();
-
-                assertThat(rabbitManagementAPI.listQueues())
-                    .anySatisfy(queue -> assertThat(queue.getName()).contains(GroupA.class.getName()));
-            }
-
-            @Test
-            void eventBusShouldNotThrowWhenContinuouslyStartAndStop() {
-                assertThatCode(() -> {
-                    eventBus.start();
-                    eventBus.stop();
-                    eventBus.stop();
-                    eventBus.start();
-                    eventBus.start();
-                    eventBus.start();
-                    eventBus.stop();
-                    eventBus.stop();
-                }).doesNotThrowAnyException();
-            }
-
-            @Test
-            void dispatchShouldStopDeliveringEventsShortlyAfterStopIsCalled() throws Exception {
-                eventBus.start();
-
-                EventListenerCountingSuccessfulExecution listener = new EventListenerCountingSuccessfulExecution();
-                eventBus.register(listener, GROUP_A);
-
-                try (Closeable closeable = ConcurrentTestRunner.builder()
-                    .operation((threadNumber, step) -> eventBus.dispatch(EVENT, KEY_1).block())
-                    .threadCount(THREAD_COUNT)
-                    .operationCount(OPERATION_COUNT)
-                    .noErrorLogs()
-                    .run()) {
-
-                    TimeUnit.SECONDS.sleep(2);
-
-                    eventBus.stop();
-                    eventBus2.stop();
-                    int callsAfterStop = listener.numberOfEventCalls();
-
-                    TimeUnit.SECONDS.sleep(1);
-                    assertThat(listener.numberOfEventCalls())
-                        .isCloseTo(callsAfterStop, Percentage.withPercentage(2));
-                }
-            }
-        }
-
-        @Nested
-        class MultiEventBus {
-
-            @Test
-            void multipleEventBusStartShouldCreateOnlyOneEventExchange() {
-                assertThat(rabbitManagementAPI.listExchanges())
-                    .filteredOn(exchange -> exchange.getName().equals(MAILBOX_EVENT_EXCHANGE_NAME))
-                    .hasSize(1);
-            }
-
-            @Test
-            void multipleEventBusShouldNotThrowWhenStartAndStopContinuously() {
-                assertThatCode(() -> {
-                    eventBus.start();
-                    eventBus.start();
-                    eventBus2.start();
-                    eventBus2.start();
-                    eventBus.stop();
-                    eventBus.stop();
-                    eventBus.stop();
-                    eventBus3.start();
-                    eventBus3.start();
-                    eventBus3.start();
-                    eventBus3.stop();
-                    eventBus.start();
-                    eventBus2.start();
-                    eventBus.stop();
-                    eventBus2.stop();
-                }).doesNotThrowAnyException();
-            }
-
-            @Test
-            void multipleEventBusStopShouldNotDeleteEventBusExchange() {
-                eventBus.stop();
-                eventBus2.stop();
-                eventBus3.stop();
-                eventBusWithKeyHandlerNotStarted.stop();
-
-                assertThat(rabbitManagementAPI.listExchanges())
-                    .anySatisfy(exchange -> assertThat(exchange.getName()).isEqualTo(MAILBOX_EVENT_EXCHANGE_NAME));
-            }
-
-            @Test
-            void multipleEventBusStopShouldNotDeleteGroupRegistrationWorkQueue() {
-                eventBus.register(mock(EventListener.class), GROUP_A);
-
-                eventBus.stop();
-                eventBus2.stop();
-                eventBus3.stop();
-                eventBusWithKeyHandlerNotStarted.stop();
-
-                assertThat(rabbitManagementAPI.listQueues())
-                    .anySatisfy(queue -> assertThat(queue.getName()).contains(GroupA.class.getName()));
-            }
-
-            @Test
-            void multipleEventBusStopShouldDeleteAllKeyRegistrationsWorkQueue() {
-                eventBus.stop();
-                eventBus2.stop();
-                eventBus3.stop();
-                eventBusWithKeyHandlerNotStarted.stop();
-
-                assertThat(rabbitManagementAPI.listQueues())
-                    .filteredOn(queue -> !queue.getName().startsWith(MAILBOX_EVENT_WORK_QUEUE_PREFIX)
-                        && !queue.getName().startsWith(MAILBOX_EVENT_DEAD_LETTER_QUEUE))
-                    .isEmpty();
-            }
-
-            @Test
-            void dispatchShouldStopDeliveringEventsShortlyAfterStopIsCalled() throws Exception {
-                eventBus.start();
-                eventBus2.start();
-
-                EventListenerCountingSuccessfulExecution listener = new EventListenerCountingSuccessfulExecution();
-                eventBus.register(listener, GROUP_A);
-                eventBus2.register(listener, GROUP_A);
-
-                try (Closeable closeable = ConcurrentTestRunner.builder()
-                    .operation((threadNumber, step) -> eventBus.dispatch(EVENT, KEY_1).block())
-                    .threadCount(THREAD_COUNT)
-                    .operationCount(OPERATION_COUNT)
-                    .noErrorLogs()
-                    .run()) {
-
-                    TimeUnit.SECONDS.sleep(2);
-
-                    eventBus.stop();
-                    eventBus2.stop();
-                    int callsAfterStop = listener.numberOfEventCalls();
-
-                    TimeUnit.SECONDS.sleep(1);
-                    assertThat(listener.numberOfEventCalls())
-                        .isCloseTo(callsAfterStop, Percentage.withPercentage(2));
-                }
-            }
-        }
-
-    }
-
-    @Nested
-    class ErrorDispatchingTest {
-
-        @AfterEach
-        void tearDown() {
-            rabbitMQExtension.getRabbitMQ().unpause();
-        }
-
-        @Test
-        void dispatchShouldNotSendToGroupListenerWhenError() {
-            EventCollector eventCollector = eventCollector();
-            eventBus().register(eventCollector, GROUP_A);
-
-            rabbitMQExtension.getRabbitMQ().pause();
-
-            doQuietly(() -> eventBus().dispatch(EVENT, NO_KEYS).block());
-
-            assertThat(eventCollector.getEvents()).isEmpty();
-        }
-
-        @Test
-        void dispatchShouldPersistEventWhenDispatchingNoKeyGetError() {
-            EventCollector eventCollector = eventCollector();
-            eventBus().register(eventCollector, GROUP_A);
-
-            rabbitMQExtension.getRabbitMQ().pause();
-
-            doQuietly(() -> eventBus().dispatch(EVENT, NO_KEYS).block());
-
-            assertThat(dispatchingFailureEvents()).containsOnly(EVENT);
-        }
-
-        @Test
-        void dispatchShouldPersistEventWhenDispatchingWithKeysGetError() {
-            EventCollector eventCollector = eventCollector();
-            eventBus().register(eventCollector, GROUP_A);
-            Mono.from(eventBus().register(eventCollector, KEY_1)).block();
-
-            rabbitMQExtension.getRabbitMQ().pause();
-
-            doQuietly(() -> eventBus().dispatch(EVENT, NO_KEYS).block());
-
-            assertThat(dispatchingFailureEvents()).containsOnly(EVENT);
-        }
-
-        @Test
-        void dispatchShouldPersistOnlyOneEventWhenDispatchingMultiGroupsGetError() {
-            EventCollector eventCollector = eventCollector();
-            eventBus().register(eventCollector, GROUP_A);
-            eventBus().register(eventCollector, GROUP_B);
-
-            rabbitMQExtension.getRabbitMQ().pause();
-
-            doQuietly(() -> eventBus().dispatch(EVENT, NO_KEYS).block());
-
-            assertThat(dispatchingFailureEvents()).containsOnly(EVENT);
-        }
-
-        @Test
-        void dispatchShouldPersistEventsWhenDispatchingGroupsGetErrorMultipleTimes() {
-            EventCollector eventCollector = eventCollector();
-            eventBus().register(eventCollector, GROUP_A);
-
-            rabbitMQExtension.getRabbitMQ().pause();
-            doQuietly(() -> eventBus().dispatch(EVENT, NO_KEYS).block());
-            doQuietly(() -> eventBus().dispatch(EVENT_2, NO_KEYS).block());
-
-            assertThat(dispatchingFailureEvents()).containsExactly(EVENT, EVENT_2);
-        }
-
-        @Test
-        void dispatchShouldPersistEventsWhenDispatchingTheSameEventGetErrorMultipleTimes() {
-            EventCollector eventCollector = eventCollector();
-            eventBus().register(eventCollector, GROUP_A);
-
-            rabbitMQExtension.getRabbitMQ().pause();
-            doQuietly(() -> eventBus().dispatch(EVENT, NO_KEYS).block());
-            doQuietly(() -> eventBus().dispatch(EVENT, NO_KEYS).block());
-
-            assertThat(dispatchingFailureEvents()).containsExactly(EVENT, EVENT);
-        }
-
-        @Test
-        void reDeliverShouldDeliverToAllGroupsWhenDispatchingFailure() {
-            EventCollector eventCollector = eventCollector();
-            eventBus().register(eventCollector, GROUP_A);
-
-            EventCollector eventCollector2 = eventCollector();
-            eventBus().register(eventCollector2, GROUP_B);
-
-            rabbitMQExtension.getRabbitMQ().pause();
-            doQuietly(() -> eventBus().dispatch(EVENT, NO_KEYS).block());
-            rabbitMQExtension.getRabbitMQ().unpause();
-            dispatchingFailureEvents()
-                .forEach(event -> eventBus().reDeliver(DispatchingFailureGroup.INSTANCE, event).block());
-
-            getSpeedProfile().shortWaitCondition()
-                .untilAsserted(() -> assertThat(eventCollector.getEvents())
-                    .hasSameElementsAs(eventCollector2.getEvents())
-                    .containsExactly(EVENT));
-        }
-
-        @Test
-        void reDeliverShouldAddEventInDeadLetterWhenGettingError() {
-            EventCollector eventCollector = eventCollector();
-            eventBus().register(eventCollector, GROUP_A);
-
-            rabbitMQExtension.getRabbitMQ().pause();
-            doQuietly(() -> eventBus().dispatch(EVENT, NO_KEYS).block());
-            getSpeedProfile().longWaitCondition()
-                .until(() -> deadLetter().containEvents().block());
-
-            doQuietly(() -> eventBus().reDeliver(DispatchingFailureGroup.INSTANCE, EVENT).block());
-            rabbitMQExtension.getRabbitMQ().unpause();
-
-            getSpeedProfile().shortWaitCondition()
-                .untilAsserted(() -> assertThat(dispatchingFailureEvents())
-                    .containsExactly(EVENT, EVENT));
-        }
-
-        @Test
-        void reDeliverShouldNotStoreEventInAnotherGroupWhenGettingError() {
-            EventCollector eventCollector = eventCollector();
-            eventBus().register(eventCollector, GROUP_A);
-
-            rabbitMQExtension.getRabbitMQ().pause();
-            doQuietly(() -> eventBus().dispatch(EVENT, NO_KEYS).block());
-            getSpeedProfile().longWaitCondition()
-                .until(() -> deadLetter().containEvents().block());
-
-            doQuietly(() -> eventBus().reDeliver(DispatchingFailureGroup.INSTANCE, EVENT).block());
-            rabbitMQExtension.getRabbitMQ().unpause();
-
-            getSpeedProfile().shortWaitCondition()
-                .untilAsserted(() -> assertThat(deadLetter().groupsWithFailedEvents().toStream())
-                    .hasOnlyElementsOfType(DispatchingFailureGroup.class));
-        }
-
-        private Stream<Event> dispatchingFailureEvents() {
-            return deadLetter().failedIds(DispatchingFailureGroup.INSTANCE)
-                .flatMap(insertionId -> deadLetter().failedEvent(DispatchingFailureGroup.INSTANCE, insertionId))
-                .toStream();
-        }
-
-        private void doQuietly(Runnable runnable) {
-            try {
-                runnable.run();
-            } catch (Exception e) {
-                // ignore
-            }
-        }
-    }
-
-    private void assertThatListenerReceiveOneEvent(EventListener listener) {
-        RabbitMQFixture.awaitAtMostThirtySeconds
-            .untilAsserted(() -> verify(listener).event(EVENT));
-    }
-}
diff --git a/mailbox/event/event-rabbitmq/src/test/java/org/apache/james/mailbox/events/RoutingKeyConverterTest.java b/mailbox/event/event-rabbitmq/src/test/java/org/apache/james/mailbox/events/RoutingKeyConverterTest.java
deleted file mode 100644
index 9fb93dc..0000000
--- a/mailbox/event/event-rabbitmq/src/test/java/org/apache/james/mailbox/events/RoutingKeyConverterTest.java
+++ /dev/null
@@ -1,144 +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.mailbox.events;
-
-import static org.assertj.core.api.Assertions.assertThat;
-import static org.assertj.core.api.Assertions.assertThatThrownBy;
-
-import java.util.Objects;
-
-import org.apache.james.events.RegistrationKey;
-import org.apache.james.mailbox.model.TestId;
-import org.junit.jupiter.api.Test;
-
-class RoutingKeyConverterTest {
-    static class TestRegistrationKey implements RegistrationKey {
-        static class Factory implements RegistrationKey.Factory {
-            @Override
-            public Class<? extends RegistrationKey> forClass() {
-                return TestRegistrationKey.class;
-            }
-
-            @Override
-            public RegistrationKey fromString(String asString) {
-                return new TestRegistrationKey(asString);
-            }
-        }
-
-        private final String value;
-
-        TestRegistrationKey(String value) {
-            this.value = value;
-        }
-
-        @Override
-        public String asString() {
-            return value;
-        }
-
-        @Override
-        public final boolean equals(Object o) {
-            if (o instanceof TestRegistrationKey) {
-                TestRegistrationKey that = (TestRegistrationKey) o;
-
-                return Objects.equals(this.value, that.value);
-            }
-            return false;
-        }
-
-        @Override
-        public final int hashCode() {
-            return Objects.hash(value);
-        }
-    }
-
-    private static final RegistrationKey REGISTRATION_KEY_1 = new MailboxIdRegistrationKey(TestId.of(42));
-    private static final String ROUTING_KEY_1 = "org.apache.james.mailbox.events.MailboxIdRegistrationKey:42";
-
-    private RoutingKeyConverter testee = RoutingKeyConverter.forFactories(
-        new TestRegistrationKey.Factory(),
-        new MailboxIdRegistrationKey.Factory(new TestId.Factory()));
-
-    @Test
-    void toRoutingKeyShouldTransformAKeyIntoAString() {
-        assertThat(RoutingKeyConverter.RoutingKey.of(REGISTRATION_KEY_1).asString())
-            .isEqualTo(ROUTING_KEY_1);
-    }
-
-    @Test
-    void toRegistrationKeyShouldReturnCorrespondingRoutingKey() {
-        assertThat(testee.toRegistrationKey(ROUTING_KEY_1))
-            .isEqualTo(REGISTRATION_KEY_1);
-    }
-
-    @Test
-    void toRoutingKeyShouldAcceptSeparator() {
-        assertThat(RoutingKeyConverter.RoutingKey.of(new TestRegistrationKey("a:b")).asString())
-            .isEqualTo("org.apache.james.mailbox.events.RoutingKeyConverterTest$TestRegistrationKey:a:b");
-    }
-
-    @Test
-    void toRegistrationKeyShouldAcceptSeparator() {
-        assertThat(testee.toRegistrationKey("org.apache.james.mailbox.events.RoutingKeyConverterTest$TestRegistrationKey:a:b"))
-            .isEqualTo(new TestRegistrationKey("a:b"));
-    }
-
-    @Test
-    void toRoutingKeyShouldAcceptEmptyValue() {
-        assertThat(RoutingKeyConverter.RoutingKey.of(new TestRegistrationKey("")).asString())
-            .isEqualTo("org.apache.james.mailbox.events.RoutingKeyConverterTest$TestRegistrationKey:");
-    }
-
-    @Test
-    void toRegistrationKeyShouldAcceptEmptyValue() {
-        assertThat(testee.toRegistrationKey("org.apache.james.mailbox.events.RoutingKeyConverterTest$TestRegistrationKey:"))
-            .isEqualTo(new TestRegistrationKey(""));
-    }
-
-    @Test
-    void toRegistrationKeyShouldRejectNull() {
-        assertThatThrownBy(() -> testee.toRegistrationKey(null))
-            .isInstanceOf(NullPointerException.class);
-    }
-
-    @Test
-    void toRegistrationKeyShouldRejectEmptyString() {
-        assertThatThrownBy(() -> testee.toRegistrationKey(""))
-            .isInstanceOf(IllegalArgumentException.class);
-    }
-
-    @Test
-    void toRegistrationKeyShouldRejectNoSeparator() {
-        assertThatThrownBy(() -> testee.toRegistrationKey("noSeparator"))
-            .isInstanceOf(IllegalArgumentException.class);
-    }
-
-    @Test
-    void toRegistrationKeyShouldRejectUnknownRegistrationKeyClass() {
-        assertThatThrownBy(() -> testee.toRegistrationKey("unknown:"))
-            .isInstanceOf(IllegalArgumentException.class);
-    }
-
-    @Test
-    void toRegistrationKeyShouldRejectInvalidValue() {
-        assertThatThrownBy(() -> testee.toRegistrationKey("org.apache.james.mailbox.events.MailboxIdRegistrationKey:invalid"))
-            .isInstanceOf(IllegalArgumentException.class);
-    }
-}
diff --git a/mailbox/event/event-rabbitmq/src/test/java/org/apache/james/mailbox/events/WaitDelayGeneratorTest.java b/mailbox/event/event-rabbitmq/src/test/java/org/apache/james/mailbox/events/WaitDelayGeneratorTest.java
deleted file mode 100644
index e7f1fb6..0000000
--- a/mailbox/event/event-rabbitmq/src/test/java/org/apache/james/mailbox/events/WaitDelayGeneratorTest.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.mailbox.events;
-
-import static org.assertj.core.api.Assertions.assertThat;
-
-import java.time.Duration;
-
-import org.assertj.core.api.SoftAssertions;
-import org.junit.jupiter.api.Test;
-
-class WaitDelayGeneratorTest {
-
-    @Test
-    void generateDelayShouldReturnZeroWhenZeroRetryCount() {
-        WaitDelayGenerator generator = WaitDelayGenerator.of(RetryBackoffConfiguration.DEFAULT);
-
-        assertThat(generator.generateDelay(0))
-            .isEqualTo(Duration.ofMillis(0));
-    }
-
-    @Test
-    void generateDelayShouldReturnByRandomInRangeOfExponentialGrowthOfRetryCount() {
-        WaitDelayGenerator generator = WaitDelayGenerator.of(RetryBackoffConfiguration.builder()
-            .maxRetries(4)
-            .firstBackoff(Duration.ofMillis(100))
-            .jitterFactor(0.5)
-            .build());
-
-        SoftAssertions.assertSoftly(softly -> {
-            softly.assertThat(generator.generateDelay(1).toMillis())
-                .isBetween(50L, 150L);
-            softly.assertThat(generator.generateDelay(2).toMillis())
-                .isBetween(100L, 300L);
-            softly.assertThat(generator.generateDelay(3).toMillis())
-                .isBetween(200L, 600L);
-            softly.assertThat(generator.generateDelay(4).toMillis())
-                .isBetween(300L, 1200L);
-        });
-    }
-
-    @Test
-    void generateDelayShouldReturnZeroWhenZeroMaxRetries() {
-        WaitDelayGenerator generator = WaitDelayGenerator.of(RetryBackoffConfiguration.builder()
-            .maxRetries(0)
-            .firstBackoff(Duration.ofMillis(1000))
-            .jitterFactor(0.5)
-            .build());
-
-        SoftAssertions.assertSoftly(softly -> {
-            softly.assertThat(generator.generateDelay(1)).isEqualTo(Duration.ZERO);
-            softly.assertThat(generator.generateDelay(2)).isEqualTo(Duration.ZERO);
-            softly.assertThat(generator.generateDelay(3)).isEqualTo(Duration.ZERO);
-        });
-    }
-
-    @Test
-    void generateDelayShouldReturnZeroWhenZeroFirstBackOff() {
-        WaitDelayGenerator generator = WaitDelayGenerator.of(RetryBackoffConfiguration.builder()
-            .maxRetries(3)
-            .firstBackoff(Duration.ZERO)
-            .jitterFactor(0.5)
-            .build());
-
-        SoftAssertions.assertSoftly(softly -> {
-            softly.assertThat(generator.generateDelay(1)).isEqualTo(Duration.ZERO);
-            softly.assertThat(generator.generateDelay(2)).isEqualTo(Duration.ZERO);
-            softly.assertThat(generator.generateDelay(3)).isEqualTo(Duration.ZERO);
-        });
-    }
-
-    @Test
-    void generateDelayShouldReturnFloorOfExponentialGrowthStepsWhenZeroJitterFactor() {
-        WaitDelayGenerator generator = WaitDelayGenerator.of(RetryBackoffConfiguration.builder()
-            .maxRetries(3)
-            .firstBackoff(Duration.ofMillis(100))
-            .jitterFactor(0.0)
-            .build());
-
-        SoftAssertions.assertSoftly(softly -> {
-            softly.assertThat(generator.generateDelay(1)).isEqualTo(Duration.ofMillis(100));
-            softly.assertThat(generator.generateDelay(2)).isEqualTo(Duration.ofMillis(200));
-            softly.assertThat(generator.generateDelay(3)).isEqualTo(Duration.ofMillis(400));
-        });
-    }
-}
\ No newline at end of file
diff --git a/mailbox/event/json/src/main/scala/org/apache/james/event/json/EventSerializer.scala b/mailbox/event/json/src/main/scala/org/apache/james/event/json/EventSerializer.scala
index fa7c110..6708055 100644
--- a/mailbox/event/json/src/main/scala/org/apache/james/event/json/EventSerializer.scala
+++ b/mailbox/event/json/src/main/scala/org/apache/james/event/json/EventSerializer.scala
@@ -30,9 +30,9 @@ import org.apache.james.event.json.DTOs.SystemFlag.SystemFlag
 import org.apache.james.event.json.DTOs._
 import org.apache.james.events
 import org.apache.james.events.Event.EventId
+import org.apache.james.events.MailboxEvents.{Added => JavaAdded, Expunged => JavaExpunged, FlagsUpdated => JavaFlagsUpdated, MailboxACLUpdated => JavaMailboxACLUpdated, MailboxAdded => JavaMailboxAdded, MailboxDeletion => JavaMailboxDeletion, MailboxRenamed => JavaMailboxRenamed, QuotaUsageUpdatedEvent => JavaQuotaUsageUpdatedEvent}
+import org.apache.james.events.MessageMoveEvent
 import org.apache.james.mailbox.MailboxSession.SessionId
-import org.apache.james.mailbox.events.MailboxEvents.{Added => JavaAdded, Expunged => JavaExpunged, FlagsUpdated => JavaFlagsUpdated, MailboxACLUpdated => JavaMailboxACLUpdated, MailboxAdded => JavaMailboxAdded, MailboxDeletion => JavaMailboxDeletion, MailboxRenamed => JavaMailboxRenamed, QuotaUsageUpdatedEvent => JavaQuotaUsageUpdatedEvent}
-import org.apache.james.mailbox.events.{MessageMoveEvent => JavaMessageMoveEvent}
 import org.apache.james.mailbox.model.{MailboxId, MessageId, MessageMoves, QuotaRoot, MailboxACL => JavaMailboxACL, MessageMetaData => JavaMessageMetaData, Quota => JavaQuota}
 import org.apache.james.mailbox.quota.QuotaRootDeserializer
 import org.apache.james.mailbox.{MessageUid, ModSeq}
@@ -174,7 +174,7 @@ private object ScalaConverter {
     mailboxId = event.getMailboxId,
     expunged = event.getExpunged.asScala.view.mapValues(DTOs.MessageMetaData.fromJava).toMap)
 
-  private def toScala(event: JavaMessageMoveEvent): DTO.MessageMoveEvent = DTO.MessageMoveEvent(
+  private def toScala(event: MessageMoveEvent): DTO.MessageMoveEvent = DTO.MessageMoveEvent(
     eventId = event.getEventId,
     user = event.getUsername,
     previousMailboxIds = event.getMessageMoves.getPreviousMailboxIds.asScala.toSet,
@@ -197,7 +197,7 @@ private object ScalaConverter {
     case e: JavaMailboxAdded => toScala(e)
     case e: JavaMailboxDeletion => toScala(e)
     case e: JavaMailboxRenamed => toScala(e)
-    case e: JavaMessageMoveEvent => toScala(e)
+    case e: MessageMoveEvent => toScala(e)
     case e: JavaQuotaUsageUpdatedEvent => toScala(e)
     case _ => throw new RuntimeException("no Scala conversion known")
   }
diff --git a/mailbox/event/json/src/test/java/org/apache/james/event/json/AddedSerializationTest.java b/mailbox/event/json/src/test/java/org/apache/james/event/json/AddedSerializationTest.java
index 7477cad..2f9c48a 100644
--- a/mailbox/event/json/src/test/java/org/apache/james/event/json/AddedSerializationTest.java
+++ b/mailbox/event/json/src/test/java/org/apache/james/event/json/AddedSerializationTest.java
@@ -33,11 +33,11 @@ import java.util.SortedMap;
 import javax.mail.Flags;
 
 import org.apache.james.core.Username;
+import org.apache.james.events.MailboxEvents.Added;
 import org.apache.james.mailbox.FlagsBuilder;
 import org.apache.james.mailbox.MailboxSession;
 import org.apache.james.mailbox.MessageUid;
 import org.apache.james.mailbox.ModSeq;
-import org.apache.james.mailbox.events.MailboxEvents.Added;
 import org.apache.james.mailbox.model.MailboxConstants;
 import org.apache.james.mailbox.model.MailboxId;
 import org.apache.james.mailbox.model.MailboxPath;
diff --git a/mailbox/event/json/src/test/java/org/apache/james/event/json/ExpungedSerializationTest.java b/mailbox/event/json/src/test/java/org/apache/james/event/json/ExpungedSerializationTest.java
index 866f241..ab5bd33 100644
--- a/mailbox/event/json/src/test/java/org/apache/james/event/json/ExpungedSerializationTest.java
+++ b/mailbox/event/json/src/test/java/org/apache/james/event/json/ExpungedSerializationTest.java
@@ -33,11 +33,11 @@ import java.util.NoSuchElementException;
 import javax.mail.Flags;
 
 import org.apache.james.core.Username;
+import org.apache.james.events.MailboxEvents.Expunged;
 import org.apache.james.mailbox.FlagsBuilder;
 import org.apache.james.mailbox.MailboxSession;
 import org.apache.james.mailbox.MessageUid;
 import org.apache.james.mailbox.ModSeq;
-import org.apache.james.mailbox.events.MailboxEvents.Expunged;
 import org.apache.james.mailbox.model.MailboxConstants;
 import org.apache.james.mailbox.model.MailboxId;
 import org.apache.james.mailbox.model.MailboxPath;
diff --git a/mailbox/event/json/src/test/java/org/apache/james/event/json/FlagsUpdatedSerializationTest.java b/mailbox/event/json/src/test/java/org/apache/james/event/json/FlagsUpdatedSerializationTest.java
index d90e7df..2e5fbf1 100644
--- a/mailbox/event/json/src/test/java/org/apache/james/event/json/FlagsUpdatedSerializationTest.java
+++ b/mailbox/event/json/src/test/java/org/apache/james/event/json/FlagsUpdatedSerializationTest.java
@@ -31,11 +31,11 @@ import java.util.NoSuchElementException;
 import javax.mail.Flags;
 
 import org.apache.james.core.Username;
+import org.apache.james.events.MailboxEvents.FlagsUpdated;
 import org.apache.james.mailbox.FlagsBuilder;
 import org.apache.james.mailbox.MailboxSession;
 import org.apache.james.mailbox.MessageUid;
 import org.apache.james.mailbox.ModSeq;
-import org.apache.james.mailbox.events.MailboxEvents.FlagsUpdated;
 import org.apache.james.mailbox.model.MailboxConstants;
 import org.apache.james.mailbox.model.MailboxId;
 import org.apache.james.mailbox.model.MailboxPath;
diff --git a/mailbox/event/json/src/test/java/org/apache/james/event/json/MailboxACLUpdatedEventSerializationTest.java b/mailbox/event/json/src/test/java/org/apache/james/event/json/MailboxACLUpdatedEventSerializationTest.java
index e957e53..20e1888 100644
--- a/mailbox/event/json/src/test/java/org/apache/james/event/json/MailboxACLUpdatedEventSerializationTest.java
+++ b/mailbox/event/json/src/test/java/org/apache/james/event/json/MailboxACLUpdatedEventSerializationTest.java
@@ -28,9 +28,9 @@ import static org.assertj.core.api.Assertions.assertThatThrownBy;
 import java.util.NoSuchElementException;
 
 import org.apache.james.core.Username;
+import org.apache.james.events.MailboxEvents.MailboxACLUpdated;
 import org.apache.james.mailbox.MailboxSession;
 import org.apache.james.mailbox.acl.ACLDiff;
-import org.apache.james.mailbox.events.MailboxEvents.MailboxACLUpdated;
 import org.apache.james.mailbox.model.MailboxACL;
 import org.apache.james.mailbox.model.MailboxConstants;
 import org.apache.james.mailbox.model.MailboxPath;
diff --git a/mailbox/event/json/src/test/java/org/apache/james/event/json/MailboxAddedSerializationTest.java b/mailbox/event/json/src/test/java/org/apache/james/event/json/MailboxAddedSerializationTest.java
index 1063d2f..6ebc085 100644
--- a/mailbox/event/json/src/test/java/org/apache/james/event/json/MailboxAddedSerializationTest.java
+++ b/mailbox/event/json/src/test/java/org/apache/james/event/json/MailboxAddedSerializationTest.java
@@ -28,8 +28,8 @@ import static org.assertj.core.api.Assertions.assertThatThrownBy;
 import java.util.NoSuchElementException;
 
 import org.apache.james.core.Username;
+import org.apache.james.events.MailboxEvents.MailboxAdded;
 import org.apache.james.mailbox.MailboxSession;
-import org.apache.james.mailbox.events.MailboxEvents.MailboxAdded;
 import org.apache.james.mailbox.model.MailboxConstants;
 import org.apache.james.mailbox.model.MailboxPath;
 import org.apache.james.mailbox.model.TestId;
diff --git a/mailbox/event/json/src/test/java/org/apache/james/event/json/MailboxDeletionSerializationTest.java b/mailbox/event/json/src/test/java/org/apache/james/event/json/MailboxDeletionSerializationTest.java
index 99f7072..4ee6d75 100644
--- a/mailbox/event/json/src/test/java/org/apache/james/event/json/MailboxDeletionSerializationTest.java
+++ b/mailbox/event/json/src/test/java/org/apache/james/event/json/MailboxDeletionSerializationTest.java
@@ -34,8 +34,8 @@ import org.apache.james.core.Domain;
 import org.apache.james.core.Username;
 import org.apache.james.core.quota.QuotaCountUsage;
 import org.apache.james.core.quota.QuotaSizeUsage;
+import org.apache.james.events.MailboxEvents.MailboxDeletion;
 import org.apache.james.mailbox.MailboxSession;
-import org.apache.james.mailbox.events.MailboxEvents.MailboxDeletion;
 import org.apache.james.mailbox.model.MailboxACL;
 import org.apache.james.mailbox.model.MailboxId;
 import org.apache.james.mailbox.model.MailboxPath;
diff --git a/mailbox/event/json/src/test/java/org/apache/james/event/json/MailboxRenamedSerializationTest.java b/mailbox/event/json/src/test/java/org/apache/james/event/json/MailboxRenamedSerializationTest.java
index 18e55d4..9f48940 100644
--- a/mailbox/event/json/src/test/java/org/apache/james/event/json/MailboxRenamedSerializationTest.java
+++ b/mailbox/event/json/src/test/java/org/apache/james/event/json/MailboxRenamedSerializationTest.java
@@ -29,8 +29,8 @@ import static org.assertj.core.api.Assertions.assertThatThrownBy;
 import java.util.NoSuchElementException;
 
 import org.apache.james.core.Username;
+import org.apache.james.events.MailboxEvents.MailboxRenamed;
 import org.apache.james.mailbox.MailboxSession;
-import org.apache.james.mailbox.events.MailboxEvents.MailboxRenamed;
 import org.apache.james.mailbox.model.MailboxId;
 import org.apache.james.mailbox.model.MailboxPath;
 import org.apache.james.mailbox.model.TestId;
diff --git a/mailbox/event/json/src/test/java/org/apache/james/event/json/MessageMoveEventSerializationTest.java b/mailbox/event/json/src/test/java/org/apache/james/event/json/MessageMoveEventSerializationTest.java
index b24bc93..9a74194 100644
--- a/mailbox/event/json/src/test/java/org/apache/james/event/json/MessageMoveEventSerializationTest.java
+++ b/mailbox/event/json/src/test/java/org/apache/james/event/json/MessageMoveEventSerializationTest.java
@@ -29,7 +29,7 @@ import java.util.NoSuchElementException;
 
 import org.apache.james.core.Username;
 import org.apache.james.events.Event;
-import org.apache.james.mailbox.events.MessageMoveEvent;
+import org.apache.james.events.MessageMoveEvent;
 import org.apache.james.mailbox.model.MessageMoves;
 import org.apache.james.mailbox.model.TestId;
 import org.apache.james.mailbox.model.TestMessageId;
diff --git a/mailbox/event/json/src/test/java/org/apache/james/event/json/QuotaUsageUpdatedEventSerializationTest.java b/mailbox/event/json/src/test/java/org/apache/james/event/json/QuotaUsageUpdatedEventSerializationTest.java
index 7991349..0295738 100644
--- a/mailbox/event/json/src/test/java/org/apache/james/event/json/QuotaUsageUpdatedEventSerializationTest.java
+++ b/mailbox/event/json/src/test/java/org/apache/james/event/json/QuotaUsageUpdatedEventSerializationTest.java
@@ -34,7 +34,7 @@ import org.apache.james.core.quota.QuotaCountLimit;
 import org.apache.james.core.quota.QuotaCountUsage;
 import org.apache.james.core.quota.QuotaSizeLimit;
 import org.apache.james.core.quota.QuotaSizeUsage;
-import org.apache.james.mailbox.events.MailboxEvents.QuotaUsageUpdatedEvent;
+import org.apache.james.events.MailboxEvents.QuotaUsageUpdatedEvent;
 import org.apache.james.mailbox.model.Quota;
 import org.apache.james.mailbox.model.QuotaRoot;
 import org.junit.jupiter.api.Test;
diff --git a/mailbox/jpa/pom.xml b/mailbox/jpa/pom.xml
index 6183cc6..a063405 100644
--- a/mailbox/jpa/pom.xml
+++ b/mailbox/jpa/pom.xml
@@ -54,11 +54,6 @@
         </dependency>
         <dependency>
             <groupId>${james.groupId}</groupId>
-            <artifactId>apache-james-mailbox-event-memory</artifactId>
-            <scope>test</scope>
-        </dependency>
-        <dependency>
-            <groupId>${james.groupId}</groupId>
             <artifactId>apache-james-mailbox-store</artifactId>
         </dependency>
         <dependency>
@@ -80,6 +75,11 @@
         </dependency>
         <dependency>
             <groupId>${james.groupId}</groupId>
+            <artifactId>event-bus-in-vm</artifactId>
+            <scope>test</scope>
+        </dependency>
+        <dependency>
+            <groupId>${james.groupId}</groupId>
             <artifactId>james-server-data-jpa</artifactId>
             <scope>test</scope>
         </dependency>
diff --git a/mailbox/jpa/src/test/java/org/apache/james/mailbox/jpa/JpaMailboxManagerProvider.java b/mailbox/jpa/src/test/java/org/apache/james/mailbox/jpa/JpaMailboxManagerProvider.java
index 79a6cb1..c7f5738 100644
--- a/mailbox/jpa/src/test/java/org/apache/james/mailbox/jpa/JpaMailboxManagerProvider.java
+++ b/mailbox/jpa/src/test/java/org/apache/james/mailbox/jpa/JpaMailboxManagerProvider.java
@@ -22,16 +22,16 @@ package org.apache.james.mailbox.jpa;
 import javax.persistence.EntityManagerFactory;
 
 import org.apache.james.backends.jpa.JpaTestCluster;
+import org.apache.james.events.EventBusTestFixture;
+import org.apache.james.events.InVMEventBus;
+import org.apache.james.events.MemoryEventDeadLetters;
+import org.apache.james.events.delivery.InVmEventDelivery;
 import org.apache.james.mailbox.Authenticator;
 import org.apache.james.mailbox.Authorizator;
 import org.apache.james.mailbox.acl.GroupMembershipResolver;
 import org.apache.james.mailbox.acl.MailboxACLResolver;
 import org.apache.james.mailbox.acl.SimpleGroupMembershipResolver;
 import org.apache.james.mailbox.acl.UnionMailboxACLResolver;
-import org.apache.james.mailbox.events.EventBusTestFixture;
-import org.apache.james.mailbox.events.InVMEventBus;
-import org.apache.james.mailbox.events.MemoryEventDeadLetters;
-import org.apache.james.mailbox.events.delivery.InVmEventDelivery;
 import org.apache.james.mailbox.jpa.mail.JPAModSeqProvider;
 import org.apache.james.mailbox.jpa.mail.JPAUidProvider;
 import org.apache.james.mailbox.jpa.openjpa.OpenJPAMailboxManager;
diff --git a/mailbox/lucene/pom.xml b/mailbox/lucene/pom.xml
index caeceb3..bc59f6a 100644
--- a/mailbox/lucene/pom.xml
+++ b/mailbox/lucene/pom.xml
@@ -44,11 +44,6 @@
         </dependency>
         <dependency>
             <groupId>${james.groupId}</groupId>
-            <artifactId>apache-james-mailbox-event-memory</artifactId>
-            <scope>test</scope>
-        </dependency>
-        <dependency>
-            <groupId>${james.groupId}</groupId>
             <artifactId>apache-james-mailbox-memory</artifactId>
             <scope>test</scope>
         </dependency>
@@ -70,6 +65,11 @@
         </dependency>
         <dependency>
             <groupId>${james.groupId}</groupId>
+            <artifactId>event-bus-in-vm</artifactId>
+            <scope>test</scope>
+        </dependency>
+        <dependency>
+            <groupId>${james.groupId}</groupId>
             <artifactId>metrics-tests</artifactId>
             <scope>test</scope>
         </dependency>
diff --git a/mailbox/maildir/pom.xml b/mailbox/maildir/pom.xml
index 29cd01c..562dcca 100644
--- a/mailbox/maildir/pom.xml
+++ b/mailbox/maildir/pom.xml
@@ -44,12 +44,12 @@
         </dependency>
         <dependency>
             <groupId>${james.groupId}</groupId>
-            <artifactId>apache-james-mailbox-event-memory</artifactId>
-            <scope>test</scope>
+            <artifactId>apache-james-mailbox-store</artifactId>
         </dependency>
         <dependency>
             <groupId>${james.groupId}</groupId>
-            <artifactId>apache-james-mailbox-store</artifactId>
+            <artifactId>event-bus-in-vm</artifactId>
+            <scope>test</scope>
         </dependency>
         <dependency>
             <groupId>${james.groupId}</groupId>
diff --git a/mailbox/maildir/src/test/java/org/apache/james/mailbox/maildir/MaildirMailboxManagerProvider.java b/mailbox/maildir/src/test/java/org/apache/james/mailbox/maildir/MaildirMailboxManagerProvider.java
index c68f597..6a90c97 100644
--- a/mailbox/maildir/src/test/java/org/apache/james/mailbox/maildir/MaildirMailboxManagerProvider.java
+++ b/mailbox/maildir/src/test/java/org/apache/james/mailbox/maildir/MaildirMailboxManagerProvider.java
@@ -21,16 +21,16 @@ package org.apache.james.mailbox.maildir;
 
 import java.io.File;
 
+import org.apache.james.events.EventBusTestFixture;
+import org.apache.james.events.InVMEventBus;
+import org.apache.james.events.MemoryEventDeadLetters;
+import org.apache.james.events.delivery.InVmEventDelivery;
 import org.apache.james.mailbox.Authenticator;
 import org.apache.james.mailbox.Authorizator;
 import org.apache.james.mailbox.acl.GroupMembershipResolver;
 import org.apache.james.mailbox.acl.MailboxACLResolver;
 import org.apache.james.mailbox.acl.SimpleGroupMembershipResolver;
 import org.apache.james.mailbox.acl.UnionMailboxACLResolver;
-import org.apache.james.mailbox.events.EventBusTestFixture;
-import org.apache.james.mailbox.events.InVMEventBus;
-import org.apache.james.mailbox.events.MemoryEventDeadLetters;
-import org.apache.james.mailbox.events.delivery.InVmEventDelivery;
 import org.apache.james.mailbox.store.JVMMailboxPathLocker;
 import org.apache.james.mailbox.store.MailboxManagerConfiguration;
 import org.apache.james.mailbox.store.PreDeletionHooks;
diff --git a/mailbox/memory/src/test/java/org/apache/james/mailbox/inmemory/manager/InMemoryIntegrationResources.java b/mailbox/memory/src/test/java/org/apache/james/mailbox/inmemory/manager/InMemoryIntegrationResources.java
index bc172a8..10cf638 100644
--- a/mailbox/memory/src/test/java/org/apache/james/mailbox/inmemory/manager/InMemoryIntegrationResources.java
+++ b/mailbox/memory/src/test/java/org/apache/james/mailbox/inmemory/manager/InMemoryIntegrationResources.java
@@ -24,7 +24,11 @@ import java.util.Optional;
 import java.util.function.Function;
 
 import org.apache.james.events.EventBus;
+import org.apache.james.events.EventBusTestFixture;
 import org.apache.james.events.EventListener;
+import org.apache.james.events.InVMEventBus;
+import org.apache.james.events.MemoryEventDeadLetters;
+import org.apache.james.events.delivery.InVmEventDelivery;
 import org.apache.james.mailbox.AttachmentContentLoader;
... 1361 lines suppressed ...


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