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:27 UTC

[james-project] 01/18: JAMES-3498 Move eventBus related classes to dedicated maven package

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 1bd539c9a22c91f98471197809edf8d44fb173b2
Author: Benoit Tellier <bt...@linagora.com>
AuthorDate: Mon Jan 25 12:40:45 2021 +0700

    JAMES-3498 Move eventBus related classes to dedicated maven package
    
    This enables reuse
---
 event-bus/api/pom.xml                              |  52 +++
 .../main/java/org/apache/james}/events/Event.java  |   2 +-
 .../java/org/apache/james}/events/EventBus.java    |  22 +-
 .../org/apache/james}/events/EventDeadLetters.java |   2 +-
 .../james}/events/EventDeadLettersHealthCheck.java |   4 +-
 .../org/apache/james/events/EventListener.java     | 142 ++++++
 .../main/java/org/apache/james}/events/Group.java  |   4 +-
 .../james}/events/GroupAlreadyRegistered.java      |   4 +-
 .../james}/events/GroupRegistrationNotFound.java   |   4 +-
 .../org/apache/james}/events/Registration.java     |   2 +-
 .../org/apache/james}/events/RegistrationKey.java  |   2 +-
 .../apache/james/mailbox/events/GenericGroup.java  |   4 +-
 event-bus/distributed/pom.xml                      |  34 ++
 event-bus/in-vm/pom.xml                            |  34 ++
 .../org/apache/james}/events/InVMEventBus.java     |  26 +-
 .../james}/events/MemoryEventDeadLetters.java      |   6 +-
 .../james}/events/delivery/EventDelivery.java      |  32 +-
 .../james}/events/delivery/InVmEventDelivery.java  |  24 +-
 .../org/apache/james}/events/InVMEventBusTest.java |   4 +-
 .../MemoryEventDeadLettersHealthCheckTest.java     |   2 +-
 .../james}/events/MemoryEventDeadLettersTest.java  |   2 +-
 .../events/delivery/InVmEventDeliveryTest.java     | 115 +++--
 event-bus/pom.xml                                  |  39 ++
 .../listeners/SetCustomFlagOnBigMessages.java      |  13 +-
 .../listeners/SetCustomFlagOnBigMessagesTest.java  |   2 +-
 mailbox/api/pom.xml                                |   4 +
 .../MailboxEvents.java}                            | 122 +-----
 .../events/MailboxIdRegistrationKey.java           |   2 +-
 .../{mailbox => }/events/MessageMoveEvent.java     |   2 +-
 .../james/events/RetryBackoffConfiguration.java    | 125 ++++++
 .../{MailboxListener.java => MailboxEvents.java}   | 120 +----
 .../mailbox/events/MailboxIdRegistrationKey.java   |   1 +
 .../james/mailbox/events/MessageMoveEvent.java     |   1 +
 .../events/ErrorHandlingContract.java              |  24 +-
 .../events/EventBusConcurrentTestContract.java     | 106 +++--
 .../{mailbox => }/events/EventBusContract.java     |   2 +-
 .../{mailbox => }/events/EventBusTestFixture.java  |  33 +-
 .../events/EventDeadLettersContract.java           |  11 +-
 .../EventDeadLettersHealthCheckContract.java       |   7 +-
 .../org/apache/james/events/GroupContract.java     | 487 +++++++++++++++++++++
 .../james/{mailbox => }/events/GroupTest.java      |   3 +-
 .../{mailbox => }/events/InsertionIdTest.java      |   3 +-
 .../java/org/apache/james/events/KeyContract.java  | 445 +++++++++++++++++++
 .../MailboxIdRegistrationKeyTest.java}             |  38 +-
 .../events/RetryBackoffConfigurationTest.java      | 141 ++++++
 .../java/org/apache/james/mailbox/EventTest.java   |  10 +-
 .../apache/james/mailbox/MailboxListenerTest.java  |  51 ++-
 .../mailbox/MailboxManagerStressContract.java      |   6 +-
 .../apache/james/mailbox/MailboxManagerTest.java   |  55 +--
 .../mailbox/events/ErrorHandlingContract.java      |   7 +-
 .../events/EventBusConcurrentTestContract.java     |  46 +-
 .../james/mailbox/events/EventBusContract.java     |   1 +
 .../james/mailbox/events/EventBusTestFixture.java  |  33 +-
 .../mailbox/events/EventDeadLettersContract.java   |  12 +-
 .../EventDeadLettersHealthCheckContract.java       |   9 +-
 .../apache/james/mailbox/events/GroupContract.java |  89 ++--
 .../org/apache/james/mailbox/events/GroupTest.java |  10 +-
 .../james/mailbox/events/InsertionIdTest.java      |   1 +
 .../apache/james/mailbox/events/KeyContract.java   |  81 ++--
 .../apache/james/mailbox/util/EventCollector.java  |   8 +-
 .../mailbox/cassandra/CassandraMailboxManager.java |   2 +-
 .../mailbox/cassandra/CassandraMessageManager.java |   2 +-
 .../mailbox/cassandra/DeleteMessageListener.java   |  10 +-
 .../cassandra/MailboxOperationLoggingListener.java |  11 +-
 .../CassandraCombinationManagerTestSystem.java     |   2 +-
 .../CassandraMailboxManagerStressTest.java         |   2 +-
 .../cassandra/CassandraMailboxManagerTest.java     |   2 +-
 .../CassandraMessageIdManagerSideEffectTest.java   |   2 +-
 .../CassandraMessageIdManagerTestSystem.java       |   2 +-
 .../cassandra/CassandraTestSystemFixture.java      |   2 +-
 .../MailboxOperationLoggingListenerTest.java       |   2 +-
 .../cassandra/mail/CassandraMailboxMapperTest.java |   1 -
 .../ElasticSearchListeningMessageSearchIndex.java  |   2 +-
 .../ElasticSearchIntegrationTest.java              |   4 -
 ...asticSearchListeningMessageSearchIndexTest.java |   3 +-
 .../events/CassandraEventDeadLetters.java          |   2 +-
 .../events/CassandraEventDeadLettersDAO.java       |  60 ++-
 .../events/CassandraEventDeadLettersGroupDAO.java  |  18 +-
 .../events/CassandraEventDeadLettersModule.java    |  46 ++
 .../CassandraEventDeadLettersGroupTable.java}      |   9 +-
 .../tables/CassandraEventDeadLettersTable.java}    |  10 +-
 .../mailbox/events/CassandraEventDeadLetters.java  |   4 +
 .../events/CassandraEventDeadLettersDAO.java       |   3 +
 .../events/CassandraEventDeadLettersGroupDAO.java  |   1 +
 .../events/CassandraEventDeadLettersDAOTest.java   | 137 ++++++
 .../CassandraEventDeadLettersGroupDAOTest.java}    |  41 +-
 .../CassandraEventDeadLettersHealthCheckTest.java  |   2 +-
 .../events/CassandraEventDeadLettersTest.java      |   2 +-
 .../CassandraEventDeadLettersHealthCheckTest.java  |   2 +
 .../events/CassandraEventDeadLettersTest.java      |   1 +
 .../apache/james/mailbox/events/InVMEventBus.java  |  25 +-
 .../mailbox/events/MemoryEventDeadLetters.java     |   4 +
 .../mailbox/events/delivery/EventDelivery.java     |  20 +-
 .../mailbox/events/delivery/InVmEventDelivery.java |  22 +-
 .../james/mailbox/events/InVMEventBusTest.java     |   2 +
 .../MemoryEventDeadLettersHealthCheckTest.java     |   2 +
 .../mailbox/events/MemoryEventDeadLettersTest.java |   1 +
 .../events/delivery/InVmEventDeliveryTest.java     |  34 +-
 .../java/org/apache/james/events/EventBusId.java}  |  51 ++-
 .../{mailbox => }/events/EventDispatcher.java      |  16 +-
 .../{mailbox => }/events/GroupConsumerRetry.java   |   7 +-
 .../{mailbox => }/events/GroupRegistration.java    |  15 +-
 .../events/GroupRegistrationHandler.java           |   6 +-
 .../james/events/KeyReconnectionHandler.java}      |  49 ++-
 .../{mailbox => }/events/KeyRegistration.java      |   4 +-
 .../events/KeyRegistrationHandler.java             |  12 +-
 .../events/LocalListenerRegistry.java              |  25 +-
 .../events/MailboxListenerExecutor.java            |  11 +-
 .../{mailbox => }/events/RabbitMQEventBus.java     |   6 +-
 .../{mailbox => }/events/RegistrationBinder.java   |   4 +-
 .../james/events/RegistrationQueueName.java}       |  15 +-
 .../{mailbox => }/events/RoutingKeyConverter.java  |   2 +-
 .../apache/james/events/WaitDelayGenerator.java    |  83 ++++
 .../james/mailbox/events/EventDispatcher.java      |  10 +-
 .../james/mailbox/events/GroupConsumerRetry.java   |   4 +
 .../james/mailbox/events/GroupRegistration.java    |  10 +-
 .../mailbox/events/GroupRegistrationHandler.java   |  10 +-
 .../james/mailbox/events/KeyRegistration.java      |   2 +
 .../mailbox/events/KeyRegistrationHandler.java     |  13 +-
 .../mailbox/events/LocalListenerRegistry.java      |  23 +-
 .../mailbox/events/MailboxListenerExecutor.java    |   9 +-
 .../james/mailbox/events/RabbitMQEventBus.java     |  11 +-
 .../james/mailbox/events/RegistrationBinder.java   |   2 +
 .../james/mailbox/events/RoutingKeyConverter.java  |   2 +
 .../org/apache/james/events/EventBusIdTest.java}   |  26 +-
 .../events/LocalListenerRegistryTest.java          |  56 +--
 .../{mailbox => }/events/NetworkErrorTest.java     |  14 +-
 ...abbitMQEventBusDeadLetterQueueUpgradeTest.java} |  50 +--
 .../{mailbox => }/events/RabbitMQEventBusTest.java |  86 ++--
 .../events/RoutingKeyConverterTest.java            |   2 +-
 .../james/events/WaitDelayGeneratorTest.java       | 103 +++++
 .../mailbox/events/LocalListenerRegistryTest.java  |  55 +--
 .../james/mailbox/events/NetworkErrorTest.java     |   3 +-
 .../james/mailbox/events/RabbitMQEventBusTest.java |  56 +--
 .../mailbox/events/RoutingKeyConverterTest.java    |   1 +
 .../apache/james/event/json/EventSerializer.scala  |  37 +-
 .../james/event/json/AddedSerializationTest.java   |   7 +-
 .../event/json/ExpungedSerializationTest.java      |   6 +-
 .../event/json/FlagsUpdatedSerializationTest.java  |   8 +-
 .../MailboxACLUpdatedEventSerializationTest.java   |   4 +-
 .../event/json/MailboxAddedSerializationTest.java  |   4 +-
 .../json/MailboxDeletionSerializationTest.java     |   6 +-
 .../json/MailboxRenamedSerializationTest.java      |   4 +-
 .../json/MessageMoveEventSerializationTest.java    |   2 +-
 .../QuotaUsageUpdatedEventSerializationTest.java   |   4 +-
 .../apache/james/event/json/SerializerFixture.java |   2 +-
 .../mailbox/jpa/openjpa/OpenJPAMailboxManager.java |   2 +-
 .../mailbox/jpa/openjpa/OpenJPAMessageManager.java |   2 +-
 .../james/mailbox/jpa/JPAMailboxManagerTest.java   |   2 +-
 .../mailbox/jpa/JpaMailboxManagerStressTest.java   |   2 +-
 .../lucene/search/LuceneMessageSearchIndex.java    |   6 +-
 .../search/LuceneMessageSearchIndexTest.java       |  13 -
 .../DomainUserMaildirMailboxManagerStressTest.java |   2 +-
 .../DomainUserMaildirMailboxManagerTest.java       |   2 +-
 .../FullUserMaildirMailboxManagerStressTest.java   |   2 +-
 .../maildir/FullUserMaildirMailboxManagerTest.java |   2 +-
 .../UserMaildirMailboxManagerStressTest.java       |   2 +-
 .../mailbox/inmemory/InMemoryMailboxManager.java   |   2 +-
 .../mailbox/inmemory/InMemoryMessageManager.java   |   2 +-
 .../inmemory/MemoryMailboxManagerStressTest.java   |   2 +-
 .../mailbox/inmemory/MemoryMailboxManagerTest.java |   2 +-
 .../manager/InMemoryIntegrationResources.java      |   6 +-
 .../InMemoryMessageIdManagerSideEffectTest.java    |   2 +-
 .../listeners/QuotaThresholdCrossingListener.java  |   9 +-
 .../QuotaThresholdConfigurationChangesTest.java    |   2 +-
 .../QuotaThresholdCrossingListenerTest.java        |   2 +-
 .../QuotaThresholdListenersTestSystem.java         |   6 +-
 .../QuotaThresholdMailingIntegrationTest.java      |   2 +-
 .../events/ElasticSearchQuotaMailboxListener.java  |   9 +-
 .../json/QuotaRatioToElasticSearchJson.java        |   2 +-
 .../ElasticSearchQuotaMailboxListenerTest.java     |   4 +-
 .../json/QuotaRatioToElasticSearchJsonTest.java    |   4 +-
 .../mailbox/spamassassin/SpamAssassinListener.java |   5 +-
 .../spamassassin/SpamAssassinListenerTest.java     |  11 +-
 .../james/mailbox/spring/MailboxInitializer.java   |   2 +-
 .../james/mailbox/store/StoreMailboxManager.java   |   2 +-
 .../james/mailbox/store/StoreMessageIdManager.java |   2 +-
 .../james/mailbox/store/StoreMessageManager.java   |   6 +-
 .../james/mailbox/store/StoreRightManager.java     |   2 +-
 .../james/mailbox/store/event/EventFactory.java    |  43 +-
 .../store/event/MailboxAnnotationListener.java     |   9 +-
 .../mailbox/store/event/SpamEventListener.java     |   4 +-
 .../store/quota/ListeningCurrentQuotaUpdater.java  |  16 +-
 .../store/search/LazyMessageSearchIndex.java       |   2 +-
 .../store/search/ListeningMessageSearchIndex.java  |  13 +-
 .../AbstractMessageIdManagerSideEffectTest.java    |  43 +-
 .../james/mailbox/store/StoreRightManagerTest.java |   2 +-
 .../store/event/MailboxAnnotationListenerTest.java |  11 +-
 .../quota/ListeningCurrentQuotaUpdaterTest.java    |  23 +-
 .../search/AbstractMessageSearchIndexTest.java     |   2 -
 .../store/search/CombinedComparatorTest.java       |   1 -
 .../store/search/LazyMessageSearchIndexTest.java   |   2 +-
 pom.xml                                            |   6 +
 .../imap/processor/AbstractSelectionProcessor.java |   2 +-
 .../imap/processor/DefaultProcessorChain.java      |   2 +-
 .../james/imap/processor/ExamineProcessor.java     |   2 +-
 .../apache/james/imap/processor/IdleProcessor.java |  13 +-
 .../james/imap/processor/SelectProcessor.java      |   2 +-
 .../imap/processor/base/SelectedMailboxImpl.java   |  16 +-
 .../main/DefaultImapProcessorFactory.java          |   2 +-
 .../processor/base/MailboxEventAnalyserTest.java   |  23 +-
 .../processor/base/SelectedMailboxImplTest.java    |  37 +-
 .../java/org/apache/james/SearchModuleChooser.java |   2 +-
 .../modules/mailbox/CassandraDeadLetterModule.java |   4 +-
 .../modules/mailbox/CassandraMailboxModule.java    |   4 +-
 .../modules/mailbox/CassandraQuotaModule.java      |   4 +-
 .../mailbox/ElasticSearchMailboxModule.java        |   4 +-
 .../mailbox/ElasticSearchQuotaSearcherModule.java  |   4 +-
 .../modules/event/RabbitMQEventBusModule.java      |   4 +-
 .../apache/james/PeriodicalHealthChecksTest.java   |   2 +-
 .../james/modules/mailbox/JPAMailboxModule.java    |   4 +-
 .../james/modules/mailbox/JpaQuotaModule.java      |   4 +-
 .../modules/mailbox/LuceneSearchMailboxModule.java |   4 +-
 .../james/modules/EventDeadLettersProbe.java       |   2 +-
 .../james/modules/mailbox/DefaultEventModule.java  |   8 +-
 .../modules/mailbox/MailboxListenerFactory.java    |  16 +-
 .../modules/mailbox/MailboxListenersLoader.java    |   8 +-
 .../mailbox/MailboxListenersLoaderImpl.java        |  46 +-
 .../modules/mailbox/MemoryDeadLetterModule.java    |   4 +-
 .../mailbox/MailboxListenersLoaderImplTest.java    |   9 +-
 .../james/modules/mailbox/NoopMailboxListener.java |   8 +-
 .../mailbox/ReactiveNoopMailboxListener.java       |   8 +-
 .../org/apache/james/FakeMessageSearchIndex.java   |   2 +-
 .../james/modules/mailbox/MemoryMailboxModule.java |   4 +-
 .../james/modules/mailbox/MemoryQuotaModule.java   |   4 +-
 .../apache/james/DisabledGroupExecutionTest.java   |  10 +-
 .../james/modules/protocols/IMAPServerModule.java  |   2 +-
 .../apache/james/jmap/draft/JMAPCommonModule.java  |   4 +-
 .../org/apache/james/jmap/draft/JMAPModule.java    |   6 +-
 .../apache/james/jmap/draft/JmapGuiceProbe.java    |   6 +-
 .../apache/james/jmap/api/change/EmailChange.java  |   9 +-
 .../james/jmap/api/change/MailboxChange.java       |  14 +-
 .../methods/integration/SetMessagesMethodTest.java |  10 +-
 .../ComputeMessageFastViewProjectionListener.java  |   9 +-
 .../jmap/event/PopulateEmailQueryViewListener.java |  11 +-
 .../jmap/event/PropagateLookupRightListener.java   |  10 +-
 ...mputeMessageFastViewProjectionListenerTest.java |   2 +-
 .../event/PopulateEmailQueryViewListenerTest.java  |   2 +-
 .../event/PropagateLookupRightListenerTest.java    |   6 +-
 .../james/jmap/change/MailboxChangeListener.scala  |  12 +-
 .../RabbitMQEventDeadLettersIntegrationTest.java   |  11 +-
 ...dminServerTaskSerializationIntegrationTest.java |  14 +-
 .../webadmin/routes/EventDeadLettersRoutes.java    |   6 +-
 .../EventDeadLettersRedeliverGroupTask.java        |   2 +-
 .../EventDeadLettersRedeliverGroupTaskDTO.java     |   2 +-
 .../service/EventDeadLettersRedeliverOneTask.java  |   4 +-
 .../EventDeadLettersRedeliverOneTaskDTO.java       |   4 +-
 .../service/EventDeadLettersRedeliverService.java  |   8 +-
 ...LettersRedeliveryTaskAdditionalInformation.java |   4 +-
 ...tersRedeliveryTaskAdditionalInformationDTO.java |   4 +-
 .../webadmin/service/EventDeadLettersService.java  |   6 +-
 .../james/webadmin/service/EventRetriever.java     |   6 +-
 .../routes/EventDeadLettersRoutesTest.java         |  16 +-
 .../james/webadmin/routes/MailboxesRoutesTest.java |   2 -
 .../webadmin/routes/UserMailboxesRoutesTest.java   |   2 -
 .../service/EventDeadLettersRedeliverTaskTest.java |   4 +-
 256 files changed, 3365 insertions(+), 1509 deletions(-)

diff --git a/event-bus/api/pom.xml b/event-bus/api/pom.xml
new file mode 100644
index 0000000..cbf7cc8
--- /dev/null
+++ b/event-bus/api/pom.xml
@@ -0,0 +1,52 @@
+<?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/xsd/maven-4.0.0.xsd">
+    <modelVersion>4.0.0</modelVersion>
+    <parent>
+        <groupId>org.apache.james</groupId>
+        <artifactId>event-bus</artifactId>
+        <version>3.6.0-SNAPSHOT</version>
+    </parent>
+
+    <artifactId>event-bus-api</artifactId>
+    <name>Apache James :: Event Bus :: API</name>
+    <description>API implementation for the eventBus, abstracting messaging patterns like workqueues and Pub/Sub</description>
+
+    <dependencies>
+        <dependency>
+            <groupId>${james.groupId}</groupId>
+            <artifactId>james-core</artifactId>
+        </dependency>
+        <dependency>
+            <groupId>com.google.guava</groupId>
+            <artifactId>guava</artifactId>
+        </dependency>
+        <dependency>
+            <groupId>io.projectreactor</groupId>
+            <artifactId>reactor-core</artifactId>
+        </dependency>
+        <dependency>
+            <groupId>javax.inject</groupId>
+            <artifactId>javax.inject</artifactId>
+        </dependency>
+    </dependencies>
+</project>
\ No newline at end of file
diff --git a/mailbox/api/src/main/java/org/apache/james/mailbox/events/Event.java b/event-bus/api/src/main/java/org/apache/james/events/Event.java
similarity index 98%
rename from mailbox/api/src/main/java/org/apache/james/mailbox/events/Event.java
rename to event-bus/api/src/main/java/org/apache/james/events/Event.java
index 43060a6..12693e6 100644
--- a/mailbox/api/src/main/java/org/apache/james/mailbox/events/Event.java
+++ b/event-bus/api/src/main/java/org/apache/james/events/Event.java
@@ -16,7 +16,7 @@
  * specific language governing permissions and limitations      *
  * under the License.                                           *
  ****************************************************************/
-package org.apache.james.mailbox.events;
+package org.apache.james.events;
 
 import java.util.Objects;
 import java.util.UUID;
diff --git a/mailbox/api/src/main/java/org/apache/james/mailbox/events/EventBus.java b/event-bus/api/src/main/java/org/apache/james/events/EventBus.java
similarity index 70%
rename from mailbox/api/src/main/java/org/apache/james/mailbox/events/EventBus.java
rename to event-bus/api/src/main/java/org/apache/james/events/EventBus.java
index c07cfb9..2429107 100644
--- a/mailbox/api/src/main/java/org/apache/james/mailbox/events/EventBus.java
+++ b/event-bus/api/src/main/java/org/apache/james/events/EventBus.java
@@ -17,7 +17,7 @@
  * under the License.                                           *
  ****************************************************************/
 
-package org.apache.james.mailbox.events;
+package org.apache.james.events;
 
 import java.util.Set;
 
@@ -41,21 +41,21 @@ public interface EventBus {
     }
 
     interface Metrics {
-        static String timerName(MailboxListener mailboxListener) {
+        static String timerName(EventListener mailboxListener) {
             return "mailbox-listener-" + mailboxListener.getClass().getSimpleName();
         }
     }
 
-    default Publisher<Registration> register(MailboxListener listener, RegistrationKey key) {
-        return register(MailboxListener.wrapReactive(listener), key);
+    default Publisher<Registration> register(EventListener listener, RegistrationKey key) {
+        return register(EventListener.wrapReactive(listener), key);
     }
 
-    Publisher<Registration> register(MailboxListener.ReactiveMailboxListener listener, RegistrationKey key);
+    Publisher<Registration> register(EventListener.ReactiveEventListener listener, RegistrationKey key);
 
-    Registration register(MailboxListener.ReactiveMailboxListener listener, Group group) throws GroupAlreadyRegistered;
+    Registration register(EventListener.ReactiveEventListener listener, Group group) throws GroupAlreadyRegistered;
 
-    default Registration register(MailboxListener listener, Group group) throws GroupAlreadyRegistered {
-        return register(MailboxListener.wrapReactive(listener), group);
+    default Registration register(EventListener listener, Group group) throws GroupAlreadyRegistered {
+        return register(EventListener.wrapReactive(listener), group);
     }
 
     Mono<Void> dispatch(Event event, Set<RegistrationKey> key);
@@ -66,11 +66,11 @@ public interface EventBus {
         return dispatch(event, ImmutableSet.of(key));
     }
 
-    default Registration register(MailboxListener.GroupMailboxListener groupMailboxListener) {
-        return register(MailboxListener.wrapReactive(groupMailboxListener));
+    default Registration register(EventListener.GroupEventListener groupMailboxListener) {
+        return register(EventListener.wrapReactive(groupMailboxListener));
     }
 
-    default Registration register(MailboxListener.ReactiveGroupMailboxListener groupMailboxListener) {
+    default Registration register(EventListener.ReactiveGroupEventListener groupMailboxListener) {
         return register(groupMailboxListener, groupMailboxListener.getDefaultGroup());
     }
 }
diff --git a/mailbox/api/src/main/java/org/apache/james/mailbox/events/EventDeadLetters.java b/event-bus/api/src/main/java/org/apache/james/events/EventDeadLetters.java
similarity index 98%
rename from mailbox/api/src/main/java/org/apache/james/mailbox/events/EventDeadLetters.java
rename to event-bus/api/src/main/java/org/apache/james/events/EventDeadLetters.java
index 053ba45..8987e18 100644
--- a/mailbox/api/src/main/java/org/apache/james/mailbox/events/EventDeadLetters.java
+++ b/event-bus/api/src/main/java/org/apache/james/events/EventDeadLetters.java
@@ -17,7 +17,7 @@
  * under the License.                                           *
  ****************************************************************/
 
-package org.apache.james.mailbox.events;
+package org.apache.james.events;
 
 import java.util.Objects;
 import java.util.UUID;
diff --git a/mailbox/api/src/main/java/org/apache/james/mailbox/events/EventDeadLettersHealthCheck.java b/event-bus/api/src/main/java/org/apache/james/events/EventDeadLettersHealthCheck.java
similarity index 95%
copy from mailbox/api/src/main/java/org/apache/james/mailbox/events/EventDeadLettersHealthCheck.java
copy to event-bus/api/src/main/java/org/apache/james/events/EventDeadLettersHealthCheck.java
index 27d33d6..98ccc0f 100644
--- a/mailbox/api/src/main/java/org/apache/james/mailbox/events/EventDeadLettersHealthCheck.java
+++ b/event-bus/api/src/main/java/org/apache/james/events/EventDeadLettersHealthCheck.java
@@ -17,7 +17,7 @@
  * under the License.                                           *
  ****************************************************************/
 
-package org.apache.james.mailbox.events;
+package org.apache.james.events;
 
 import javax.inject.Inject;
 
@@ -33,7 +33,7 @@ public class EventDeadLettersHealthCheck implements HealthCheck {
     private final EventDeadLetters eventDeadLetters;
 
     @Inject
-    EventDeadLettersHealthCheck(EventDeadLetters eventDeadLetters) {
+    public EventDeadLettersHealthCheck(EventDeadLetters eventDeadLetters) {
         this.eventDeadLetters = eventDeadLetters;
     }
 
diff --git a/event-bus/api/src/main/java/org/apache/james/events/EventListener.java b/event-bus/api/src/main/java/org/apache/james/events/EventListener.java
new file mode 100644
index 0000000..be50c12
--- /dev/null
+++ b/event-bus/api/src/main/java/org/apache/james/events/EventListener.java
@@ -0,0 +1,142 @@
+/****************************************************************
+ * 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.events;
+
+import java.util.Objects;
+
+import org.reactivestreams.Publisher;
+
+import com.github.fge.lambdas.Throwing;
+
+import reactor.core.publisher.Mono;
+import reactor.core.scheduler.Schedulers;
+
+/**
+ * Listens to events.<br>
+ */
+public interface EventListener {
+
+    interface ReactiveEventListener extends EventListener {
+        Publisher<Void> reactiveEvent(Event event);
+
+        default void event(Event event) throws Exception {
+            Mono.from(reactiveEvent(event))
+                .subscribeOn(Schedulers.elastic())
+                .block();
+        }
+    }
+
+    interface GroupEventListener extends EventListener {
+        Group getDefaultGroup();
+    }
+
+    interface ReactiveGroupEventListener extends ReactiveEventListener, GroupEventListener {
+        default void event(Event event) throws Exception {
+            Mono.from(reactiveEvent(event))
+                .subscribeOn(Schedulers.elastic())
+                .block();
+        }
+    }
+
+    class ReactiveWrapper<T extends EventListener> implements ReactiveEventListener {
+        protected final T delegate;
+
+        private ReactiveWrapper(T delegate) {
+            this.delegate = delegate;
+        }
+
+        @Override
+        public Publisher<Void> reactiveEvent(Event event) {
+            return Mono.fromRunnable(Throwing.runnable(() -> delegate.event(event)))
+                .subscribeOn(Schedulers.elastic())
+                .then();
+        }
+
+        @Override
+        public void event(Event event) throws Exception {
+            delegate.event(event);
+        }
+
+        @Override
+        public ExecutionMode getExecutionMode() {
+            return delegate.getExecutionMode();
+        }
+
+        @Override
+        public boolean isHandling(Event event) {
+            return delegate.isHandling(event);
+        }
+
+        @Override
+        public final boolean equals(Object o) {
+            if (o instanceof ReactiveWrapper) {
+                ReactiveWrapper<?> that = (ReactiveWrapper<?>) o;
+
+                return Objects.equals(this.delegate, that.delegate);
+            }
+            return false;
+        }
+
+        @Override
+        public final int hashCode() {
+            return Objects.hash(delegate);
+        }
+    }
+
+    class ReactiveGroupWrapper extends ReactiveWrapper<GroupEventListener> implements GroupEventListener, ReactiveGroupEventListener {
+        private ReactiveGroupWrapper(GroupEventListener delegate) {
+            super(delegate);
+        }
+
+        @Override
+        public Group getDefaultGroup() {
+            return delegate.getDefaultGroup();
+        }
+    }
+
+    enum ExecutionMode {
+        SYNCHRONOUS,
+        ASYNCHRONOUS
+    }
+
+    static ReactiveEventListener wrapReactive(EventListener listener) {
+        return new ReactiveWrapper<>(listener);
+    }
+
+    static ReactiveGroupEventListener wrapReactive(GroupEventListener groupMailboxListener) {
+        return new ReactiveGroupWrapper(groupMailboxListener);
+    }
+
+    default ExecutionMode getExecutionMode() {
+        return ExecutionMode.SYNCHRONOUS;
+    }
+
+
+    default boolean isHandling(Event event) {
+        return true;
+    }
+
+    /**
+     * Informs this listener about the given event.
+     *
+     * @param event not null
+     */
+    void event(Event event) throws Exception;
+}
diff --git a/mailbox/api/src/main/java/org/apache/james/mailbox/events/Group.java b/event-bus/api/src/main/java/org/apache/james/events/Group.java
similarity index 97%
rename from mailbox/api/src/main/java/org/apache/james/mailbox/events/Group.java
rename to event-bus/api/src/main/java/org/apache/james/events/Group.java
index ee3d049..50b1685 100644
--- a/mailbox/api/src/main/java/org/apache/james/mailbox/events/Group.java
+++ b/event-bus/api/src/main/java/org/apache/james/events/Group.java
@@ -17,11 +17,13 @@
  * under the License.                                           *
  ****************************************************************/
 
-package org.apache.james.mailbox.events;
+package org.apache.james.events;
 
 import java.lang.reflect.InvocationTargetException;
 import java.util.Objects;
 
+import org.apache.james.mailbox.events.GenericGroup;
+
 import com.google.common.base.Preconditions;
 import com.google.common.base.Strings;
 
diff --git a/mailbox/api/src/main/java/org/apache/james/mailbox/events/GroupAlreadyRegistered.java b/event-bus/api/src/main/java/org/apache/james/events/GroupAlreadyRegistered.java
similarity index 95%
rename from mailbox/api/src/main/java/org/apache/james/mailbox/events/GroupAlreadyRegistered.java
rename to event-bus/api/src/main/java/org/apache/james/events/GroupAlreadyRegistered.java
index 736fc66..40bfc40 100644
--- a/mailbox/api/src/main/java/org/apache/james/mailbox/events/GroupAlreadyRegistered.java
+++ b/event-bus/api/src/main/java/org/apache/james/events/GroupAlreadyRegistered.java
@@ -17,7 +17,9 @@
  * under the License.                                           *
  ****************************************************************/
 
-package org.apache.james.mailbox.events;
+package org.apache.james.events;
+
+import org.apache.james.events.Group;
 
 public class GroupAlreadyRegistered extends RuntimeException {
     private final Group group;
diff --git a/mailbox/api/src/main/java/org/apache/james/mailbox/events/GroupRegistrationNotFound.java b/event-bus/api/src/main/java/org/apache/james/events/GroupRegistrationNotFound.java
similarity index 95%
rename from mailbox/api/src/main/java/org/apache/james/mailbox/events/GroupRegistrationNotFound.java
rename to event-bus/api/src/main/java/org/apache/james/events/GroupRegistrationNotFound.java
index a268fc0..786132a 100644
--- a/mailbox/api/src/main/java/org/apache/james/mailbox/events/GroupRegistrationNotFound.java
+++ b/event-bus/api/src/main/java/org/apache/james/events/GroupRegistrationNotFound.java
@@ -17,7 +17,9 @@
  * under the License.                                           *
  ****************************************************************/
 
-package org.apache.james.mailbox.events;
+package org.apache.james.events;
+
+import org.apache.james.events.Group;
 
 public class GroupRegistrationNotFound extends RuntimeException {
     private final Group group;
diff --git a/mailbox/api/src/main/java/org/apache/james/mailbox/events/Registration.java b/event-bus/api/src/main/java/org/apache/james/events/Registration.java
similarity index 96%
copy from mailbox/api/src/main/java/org/apache/james/mailbox/events/Registration.java
copy to event-bus/api/src/main/java/org/apache/james/events/Registration.java
index c5a3a53..99cf17e 100644
--- a/mailbox/api/src/main/java/org/apache/james/mailbox/events/Registration.java
+++ b/event-bus/api/src/main/java/org/apache/james/events/Registration.java
@@ -17,7 +17,7 @@
  * under the License.                                           *
  ****************************************************************/
 
-package org.apache.james.mailbox.events;
+package org.apache.james.events;
 
 public interface Registration {
     void unregister();
diff --git a/mailbox/api/src/main/java/org/apache/james/mailbox/events/RegistrationKey.java b/event-bus/api/src/main/java/org/apache/james/events/RegistrationKey.java
similarity index 97%
copy from mailbox/api/src/main/java/org/apache/james/mailbox/events/RegistrationKey.java
copy to event-bus/api/src/main/java/org/apache/james/events/RegistrationKey.java
index 1d0e320..bff0203 100644
--- a/mailbox/api/src/main/java/org/apache/james/mailbox/events/RegistrationKey.java
+++ b/event-bus/api/src/main/java/org/apache/james/events/RegistrationKey.java
@@ -17,7 +17,7 @@
  * under the License.                                           *
  ****************************************************************/
 
-package org.apache.james.mailbox.events;
+package org.apache.james.events;
 
 public interface RegistrationKey {
 
diff --git a/mailbox/api/src/main/java/org/apache/james/mailbox/events/GenericGroup.java b/event-bus/api/src/main/java/org/apache/james/mailbox/events/GenericGroup.java
similarity index 95%
copy from mailbox/api/src/main/java/org/apache/james/mailbox/events/GenericGroup.java
copy to event-bus/api/src/main/java/org/apache/james/mailbox/events/GenericGroup.java
index a679682..7b93ba6 100644
--- a/mailbox/api/src/main/java/org/apache/james/mailbox/events/GenericGroup.java
+++ b/event-bus/api/src/main/java/org/apache/james/mailbox/events/GenericGroup.java
@@ -21,8 +21,10 @@ package org.apache.james.mailbox.events;
 
 import java.util.Objects;
 
+import org.apache.james.events.Group;
+
 public class GenericGroup extends Group {
-    static final String DELIMITER = "-";
+    public static final String DELIMITER = "-";
     private final String groupName;
 
     public GenericGroup(String groupName) {
diff --git a/event-bus/distributed/pom.xml b/event-bus/distributed/pom.xml
new file mode 100644
index 0000000..a202f2c
--- /dev/null
+++ b/event-bus/distributed/pom.xml
@@ -0,0 +1,34 @@
+<?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/xsd/maven-4.0.0.xsd">
+    <modelVersion>4.0.0</modelVersion>
+    <parent>
+        <groupId>org.apache.james</groupId>
+        <artifactId>event-bus</artifactId>
+        <version>3.6.0-SNAPSHOT</version>
+    </parent>
+
+    <artifactId>event-bus-distributed</artifactId>
+    <name>Apache James :: Event Bus :: Distributed</name>
+    <description>Distributed implementation for the eventBus</description>
+
+</project>
\ No newline at end of file
diff --git a/event-bus/in-vm/pom.xml b/event-bus/in-vm/pom.xml
new file mode 100644
index 0000000..99fc5c2
--- /dev/null
+++ b/event-bus/in-vm/pom.xml
@@ -0,0 +1,34 @@
+<?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/xsd/maven-4.0.0.xsd">
+    <modelVersion>4.0.0</modelVersion>
+    <parent>
+        <groupId>org.apache.james</groupId>
+        <artifactId>event-bus</artifactId>
+        <version>3.6.0-SNAPSHOT</version>
+    </parent>
+
+    <artifactId>event-bus-in-vm</artifactId>
+    <name>Apache James :: Event Bus :: In VM</name>
+    <description>In VM (non distributed) implementation for the eventBus</description>
+
+</project>
\ No newline at end of file
diff --git a/mailbox/event/event-memory/src/main/java/org/apache/james/mailbox/events/InVMEventBus.java b/event-bus/in-vm/src/main/java/org/apache/james/events/InVMEventBus.java
similarity index 77%
copy from mailbox/event/event-memory/src/main/java/org/apache/james/mailbox/events/InVMEventBus.java
copy to event-bus/in-vm/src/main/java/org/apache/james/events/InVMEventBus.java
index 6e73b0f..a3360c5 100644
--- a/mailbox/event/event-memory/src/main/java/org/apache/james/mailbox/events/InVMEventBus.java
+++ b/event-bus/in-vm/src/main/java/org/apache/james/events/InVMEventBus.java
@@ -17,7 +17,7 @@
  * under the License.                                           *
  ****************************************************************/
 
-package org.apache.james.mailbox.events;
+package org.apache.james.events;
 
 import java.util.Optional;
 import java.util.Set;
@@ -25,9 +25,7 @@ import java.util.concurrent.ConcurrentHashMap;
 
 import javax.inject.Inject;
 
-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 org.apache.james.events.delivery.EventDelivery;
 
 import com.github.steveash.guavate.Guavate;
 import com.google.common.collect.HashMultimap;
@@ -39,8 +37,8 @@ import reactor.core.publisher.Mono;
 
 public class InVMEventBus implements EventBus {
 
-    private final Multimap<RegistrationKey, MailboxListener.ReactiveMailboxListener> registrations;
-    private final ConcurrentHashMap<Group, MailboxListener.ReactiveMailboxListener> groups;
+    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;
@@ -55,14 +53,14 @@ public class InVMEventBus implements EventBus {
     }
 
     @Override
-    public Mono<Registration> register(MailboxListener.ReactiveMailboxListener listener, RegistrationKey key) {
+    public Mono<Registration> register(EventListener.ReactiveEventListener listener, RegistrationKey key) {
         registrations.put(key, listener);
         return Mono.just(() -> registrations.remove(key, listener));
     }
 
     @Override
-    public Registration register(MailboxListener.ReactiveMailboxListener listener, Group group) {
-        MailboxListener previous = groups.putIfAbsent(group, listener);
+    public Registration register(EventListener.ReactiveEventListener listener, Group group) {
+        EventListener previous = groups.putIfAbsent(group, listener);
         if (previous == null) {
             return () -> groups.remove(group, listener);
         }
@@ -87,7 +85,7 @@ public class InVMEventBus implements EventBus {
         return Mono.empty();
     }
 
-    private MailboxListener.ReactiveMailboxListener retrieveListenerFromGroup(Group group) {
+    private EventListener.ReactiveEventListener retrieveListenerFromGroup(Group group) {
         return Optional.ofNullable(groups.get(group))
             .orElseThrow(() -> new GroupRegistrationNotFound(group));
     }
@@ -104,20 +102,20 @@ public class InVMEventBus implements EventBus {
             .then();
     }
 
-    private Mono<Void> groupDelivery(Event event, MailboxListener.ReactiveMailboxListener mailboxListener, Group group) {
+    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)));
+                EventDelivery.Retryer.BackoffRetryer.of(retryBackoff, mailboxListener),
+                EventDelivery.PermanentFailureHandler.StoreToDeadLetters.of(group, eventDeadLetters)));
     }
 
     public Set<Group> registeredGroups() {
         return groups.keySet();
     }
 
-    private Set<MailboxListener.ReactiveMailboxListener> registeredListenersByKeys(Set<RegistrationKey> keys) {
+    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/event-bus/in-vm/src/main/java/org/apache/james/events/MemoryEventDeadLetters.java
similarity index 95%
copy from mailbox/event/event-memory/src/main/java/org/apache/james/mailbox/events/MemoryEventDeadLetters.java
copy to event-bus/in-vm/src/main/java/org/apache/james/events/MemoryEventDeadLetters.java
index 5f8af25..d96ef55 100644
--- a/mailbox/event/event-memory/src/main/java/org/apache/james/mailbox/events/MemoryEventDeadLetters.java
+++ b/event-bus/in-vm/src/main/java/org/apache/james/events/MemoryEventDeadLetters.java
@@ -17,7 +17,11 @@
  * under the License.                                           *
  ****************************************************************/
 
-package org.apache.james.mailbox.events;
+package org.apache.james.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;
diff --git a/mailbox/event/event-memory/src/main/java/org/apache/james/mailbox/events/delivery/EventDelivery.java b/event-bus/in-vm/src/main/java/org/apache/james/events/delivery/EventDelivery.java
similarity index 80%
copy from mailbox/event/event-memory/src/main/java/org/apache/james/mailbox/events/delivery/EventDelivery.java
copy to event-bus/in-vm/src/main/java/org/apache/james/events/delivery/EventDelivery.java
index d0f06dd..11f6593 100644
--- a/mailbox/event/event-memory/src/main/java/org/apache/james/mailbox/events/delivery/EventDelivery.java
+++ b/event-bus/in-vm/src/main/java/org/apache/james/events/delivery/EventDelivery.java
@@ -17,16 +17,16 @@
  * under the License.                                           *
  ****************************************************************/
 
-package org.apache.james.mailbox.events.delivery;
+package org.apache.james.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 static org.apache.james.events.delivery.EventDelivery.PermanentFailureHandler.NO_HANDLER;
+import static org.apache.james.events.delivery.EventDelivery.Retryer.NO_RETRYER;
 
-import org.apache.james.mailbox.events.Event;
-import org.apache.james.mailbox.events.EventDeadLetters;
-import org.apache.james.mailbox.events.Group;
-import org.apache.james.mailbox.events.MailboxListener;
-import org.apache.james.mailbox.events.RetryBackoffConfiguration;
+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.events.RetryBackoffConfiguration;
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
 
@@ -67,18 +67,18 @@ public interface EventDelivery {
 
         Retryer NO_RETRYER = (executionResult, event) -> executionResult;
 
-        class BackoffRetryer implements EventDelivery.Retryer {
+        class BackoffRetryer implements Retryer {
 
-            public static BackoffRetryer of(RetryBackoffConfiguration retryBackoff, MailboxListener mailboxListener) {
+            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 MailboxListener mailboxListener;
+            private final EventListener mailboxListener;
 
-            public BackoffRetryer(RetryBackoffConfiguration retryBackoff, MailboxListener mailboxListener) {
+            public BackoffRetryer(RetryBackoffConfiguration retryBackoff, EventListener mailboxListener) {
                 this.retryBackoff = retryBackoff;
                 this.mailboxListener = mailboxListener;
             }
@@ -103,7 +103,7 @@ public interface EventDelivery {
 
         PermanentFailureHandler NO_HANDLER = event -> Mono.error(new UnsupportedOperationException("doesn't handle error"));
 
-        class StoreToDeadLetters implements EventDelivery.PermanentFailureHandler {
+        class StoreToDeadLetters implements PermanentFailureHandler {
 
             public static StoreToDeadLetters of(Group group, EventDeadLetters eventDeadLetters) {
                 return new StoreToDeadLetters(group, eventDeadLetters);
@@ -126,9 +126,9 @@ public interface EventDelivery {
         Mono<Void> handle(Event event);
     }
 
-    Mono<Void> deliver(MailboxListener.ReactiveMailboxListener listener, Event event, DeliveryOption option);
+    Mono<Void> deliver(EventListener.ReactiveEventListener listener, Event event, DeliveryOption option);
 
-    default Mono<Void> deliver(MailboxListener listener, Event event, DeliveryOption option) {
-        return deliver(MailboxListener.wrapReactive(listener), event, 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/event-bus/in-vm/src/main/java/org/apache/james/events/delivery/InVmEventDelivery.java
similarity index 79%
copy from mailbox/event/event-memory/src/main/java/org/apache/james/mailbox/events/delivery/InVmEventDelivery.java
copy to event-bus/in-vm/src/main/java/org/apache/james/events/delivery/InVmEventDelivery.java
index f4f7036..f67c022 100644
--- a/mailbox/event/event-memory/src/main/java/org/apache/james/mailbox/events/delivery/InVmEventDelivery.java
+++ b/event-bus/in-vm/src/main/java/org/apache/james/events/delivery/InVmEventDelivery.java
@@ -17,16 +17,16 @@
  * under the License.                                           *
  ****************************************************************/
 
-package org.apache.james.mailbox.events.delivery;
+package org.apache.james.events.delivery;
 
-import static org.apache.james.mailbox.events.EventBus.Metrics.timerName;
+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.mailbox.events.Event;
-import org.apache.james.mailbox.events.EventBus;
-import org.apache.james.mailbox.events.MailboxListener;
+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;
@@ -51,14 +51,14 @@ public class InVmEventDelivery implements EventDelivery {
     }
 
     @Override
-    public Mono<Void> deliver(MailboxListener.ReactiveMailboxListener listener, Event event, DeliveryOption option) {
+    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(MailboxListener.ExecutionMode executionMode, Mono<Void> executionResult) {
-        if (executionMode.equals(MailboxListener.ExecutionMode.SYNCHRONOUS)) {
+    private Mono<Void> waitForResultIfNeeded(EventListener.ExecutionMode executionMode, Mono<Void> executionResult) {
+        if (executionMode.equals(EventListener.ExecutionMode.SYNCHRONOUS)) {
             return executionResult;
         }
         return Flux.merge(executionResult, Mono.empty())
@@ -66,7 +66,7 @@ public class InVmEventDelivery implements EventDelivery {
             .onErrorResume(throwable -> Mono.empty());
     }
 
-    private Mono<Void> deliverByOption(MailboxListener.ReactiveMailboxListener listener, Event event, DeliveryOption deliveryOption) {
+    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)))
@@ -77,7 +77,7 @@ public class InVmEventDelivery implements EventDelivery {
             .then();
     }
 
-    private Mono<Void> doDeliverToListener(MailboxListener.ReactiveMailboxListener mailboxListener, Event event) {
+    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))))
@@ -86,7 +86,7 @@ public class InVmEventDelivery implements EventDelivery {
         return Mono.empty();
     }
 
-    private MDCBuilder buildMDC(MailboxListener mailboxListener, Event event) {
+    private MDCBuilder buildMDC(EventListener mailboxListener, Event event) {
         return MDCBuilder.create()
             .addContext(EventBus.StructuredLoggingFields.EVENT_ID, event.getEventId())
             .addContext(EventBus.StructuredLoggingFields.EVENT_CLASS, event.getClass())
@@ -94,7 +94,7 @@ public class InVmEventDelivery implements EventDelivery {
             .addContext(EventBus.StructuredLoggingFields.LISTENER_CLASS, mailboxListener.getClass());
     }
 
-    private StructuredLogger structuredLogger(Event event, MailboxListener mailboxListener) {
+    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())
diff --git a/mailbox/event/event-memory/src/test/java/org/apache/james/mailbox/events/InVMEventBusTest.java b/event-bus/in-vm/src/test/java/org/apache/james/events/InVMEventBusTest.java
similarity index 95%
copy from mailbox/event/event-memory/src/test/java/org/apache/james/mailbox/events/InVMEventBusTest.java
copy to event-bus/in-vm/src/test/java/org/apache/james/events/InVMEventBusTest.java
index 5a6a6ea..7705203 100644
--- a/mailbox/event/event-memory/src/test/java/org/apache/james/mailbox/events/InVMEventBusTest.java
+++ b/event-bus/in-vm/src/test/java/org/apache/james/events/InVMEventBusTest.java
@@ -17,9 +17,9 @@
  * under the License.                                           *
  ****************************************************************/
 
-package org.apache.james.mailbox.events;
+package org.apache.james.events;
 
-import org.apache.james.mailbox.events.delivery.InVmEventDelivery;
+import org.apache.james.events.delivery.InVmEventDelivery;
 import org.apache.james.metrics.tests.RecordingMetricFactory;
 import org.junit.jupiter.api.BeforeEach;
 
diff --git a/mailbox/event/event-memory/src/test/java/org/apache/james/mailbox/events/MemoryEventDeadLettersHealthCheckTest.java b/event-bus/in-vm/src/test/java/org/apache/james/events/MemoryEventDeadLettersHealthCheckTest.java
similarity index 98%
copy from mailbox/event/event-memory/src/test/java/org/apache/james/mailbox/events/MemoryEventDeadLettersHealthCheckTest.java
copy to event-bus/in-vm/src/test/java/org/apache/james/events/MemoryEventDeadLettersHealthCheckTest.java
index c05deb0..bc4e5c3 100644
--- a/mailbox/event/event-memory/src/test/java/org/apache/james/mailbox/events/MemoryEventDeadLettersHealthCheckTest.java
+++ b/event-bus/in-vm/src/test/java/org/apache/james/events/MemoryEventDeadLettersHealthCheckTest.java
@@ -17,7 +17,7 @@
  * under the License.                                           *
  ****************************************************************/
 
-package org.apache.james.mailbox.events;
+package org.apache.james.events;
 
 import org.apache.commons.lang3.NotImplementedException;
 import org.junit.jupiter.api.Disabled;
diff --git a/mailbox/event/event-memory/src/test/java/org/apache/james/mailbox/events/MemoryEventDeadLettersTest.java b/event-bus/in-vm/src/test/java/org/apache/james/events/MemoryEventDeadLettersTest.java
similarity index 97%
copy from mailbox/event/event-memory/src/test/java/org/apache/james/mailbox/events/MemoryEventDeadLettersTest.java
copy to event-bus/in-vm/src/test/java/org/apache/james/events/MemoryEventDeadLettersTest.java
index 2ef0996..c6facc9 100644
--- a/mailbox/event/event-memory/src/test/java/org/apache/james/mailbox/events/MemoryEventDeadLettersTest.java
+++ b/event-bus/in-vm/src/test/java/org/apache/james/events/MemoryEventDeadLettersTest.java
@@ -17,7 +17,7 @@
  * under the License.                                           *
  ****************************************************************/
 
-package org.apache.james.mailbox.events;
+package org.apache.james.events;
 
 import org.junit.jupiter.api.BeforeEach;
 
diff --git a/mailbox/event/event-memory/src/test/java/org/apache/james/mailbox/events/delivery/InVmEventDeliveryTest.java b/event-bus/in-vm/src/test/java/org/apache/james/events/delivery/InVmEventDeliveryTest.java
similarity index 60%
copy from mailbox/event/event-memory/src/test/java/org/apache/james/mailbox/events/delivery/InVmEventDeliveryTest.java
copy to event-bus/in-vm/src/test/java/org/apache/james/events/delivery/InVmEventDeliveryTest.java
index dd210a9..a0536a0 100644
--- a/mailbox/event/event-memory/src/test/java/org/apache/james/mailbox/events/delivery/InVmEventDeliveryTest.java
+++ b/event-bus/in-vm/src/test/java/org/apache/james/events/delivery/InVmEventDeliveryTest.java
@@ -17,12 +17,8 @@
  * under the License.                                           *
  ****************************************************************/
 
-package org.apache.james.mailbox.events.delivery;
+package org.apache.james.events.delivery;
 
-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.MailboxListenerCountingSuccessfulExecution;
-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;
@@ -32,21 +28,20 @@ import static org.mockito.Mockito.when;
 
 import java.time.Duration;
 
-import org.apache.james.mailbox.events.MailboxListener;
-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.events.EventBusTestFixture;
+import org.apache.james.events.EventListener;
+import org.apache.james.events.MemoryEventDeadLetters;
+import org.apache.james.events.RetryBackoffConfiguration;
 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;
+import org.mockito.Mockito;
 
 class InVmEventDeliveryTest {
     private InVmEventDelivery inVmEventDelivery;
-    private MailboxListenerCountingSuccessfulExecution listener;
+    private EventBusTestFixture.EventListenerCountingSuccessfulExecution listener;
 
     @BeforeEach
     void setUp() {
@@ -54,8 +49,8 @@ class InVmEventDeliveryTest {
         inVmEventDelivery = new InVmEventDelivery(new RecordingMetricFactory());
     }
 
-    MailboxListenerCountingSuccessfulExecution newListener() {
-        return spy(new MailboxListenerCountingSuccessfulExecution());
+    EventBusTestFixture.EventListenerCountingSuccessfulExecution newListener() {
+        return Mockito.spy(new EventBusTestFixture.EventListenerCountingSuccessfulExecution());
     }
 
     @Nested
@@ -63,8 +58,8 @@ class InVmEventDeliveryTest {
 
         @Test
         void deliverShouldDeliverEvent() {
-            when(listener.getExecutionMode()).thenReturn(MailboxListener.ExecutionMode.SYNCHRONOUS);
-            inVmEventDelivery.deliver(listener, EVENT, DeliveryOption.none())
+            when(listener.getExecutionMode()).thenReturn(EventListener.ExecutionMode.SYNCHRONOUS);
+            inVmEventDelivery.deliver(listener, EventBusTestFixture.EVENT, EventDelivery.DeliveryOption.none())
                 .block();
 
             assertThat(listener.numberOfEventCalls())
@@ -73,19 +68,19 @@ class InVmEventDeliveryTest {
 
         @Test
         void deliverShouldReturnSuccessSynchronousMono() {
-            when(listener.getExecutionMode()).thenReturn(MailboxListener.ExecutionMode.SYNCHRONOUS);
-            assertThatCode(() -> inVmEventDelivery.deliver(listener, EVENT, DeliveryOption.none())
+            when(listener.getExecutionMode()).thenReturn(EventListener.ExecutionMode.SYNCHRONOUS);
+            assertThatCode(() -> inVmEventDelivery.deliver(listener, EventBusTestFixture.EVENT, EventDelivery.DeliveryOption.none())
                     .block())
                 .doesNotThrowAnyException();
         }
 
         @Test
         void deliverShouldNotDeliverWhenListenerGetException() {
-            when(listener.getExecutionMode()).thenReturn(MailboxListener.ExecutionMode.SYNCHRONOUS);
+            when(listener.getExecutionMode()).thenReturn(EventListener.ExecutionMode.SYNCHRONOUS);
             doThrow(new RuntimeException())
-                .when(listener).event(EVENT);
+                .when(listener).event(EventBusTestFixture.EVENT);
 
-            assertThatThrownBy(() -> inVmEventDelivery.deliver(listener, EVENT, DeliveryOption.none())
+            assertThatThrownBy(() -> inVmEventDelivery.deliver(listener, EventBusTestFixture.EVENT, EventDelivery.DeliveryOption.none())
                 .block())
             .isInstanceOf(RuntimeException.class);
 
@@ -95,11 +90,11 @@ class InVmEventDeliveryTest {
 
         @Test
         void deliverShouldReturnAnErrorMonoWhenListenerGetException() {
-            when(listener.getExecutionMode()).thenReturn(MailboxListener.ExecutionMode.SYNCHRONOUS);
+            when(listener.getExecutionMode()).thenReturn(EventListener.ExecutionMode.SYNCHRONOUS);
             doThrow(new RuntimeException())
-                .when(listener).event(EVENT);
+                .when(listener).event(EventBusTestFixture.EVENT);
 
-            assertThatThrownBy(() -> inVmEventDelivery.deliver(listener, EVENT, DeliveryOption.none())
+            assertThatThrownBy(() -> inVmEventDelivery.deliver(listener, EventBusTestFixture.EVENT, EventDelivery.DeliveryOption.none())
                 .block())
             .isInstanceOf(RuntimeException.class);
         }
@@ -110,8 +105,8 @@ class InVmEventDeliveryTest {
 
         @Test
         void deliverShouldDeliverEvent() {
-            when(listener.getExecutionMode()).thenReturn(MailboxListener.ExecutionMode.ASYNCHRONOUS);
-            inVmEventDelivery.deliver(listener, EVENT, DeliveryOption.none())
+            when(listener.getExecutionMode()).thenReturn(EventListener.ExecutionMode.ASYNCHRONOUS);
+            inVmEventDelivery.deliver(listener, EventBusTestFixture.EVENT, EventDelivery.DeliveryOption.none())
                 .block();
 
             assertThat(listener.numberOfEventCalls())
@@ -120,30 +115,30 @@ class InVmEventDeliveryTest {
 
         @Test
         void deliverShouldReturnSuccessSynchronousMono() {
-            when(listener.getExecutionMode()).thenReturn(MailboxListener.ExecutionMode.ASYNCHRONOUS);
-            assertThatCode(() -> inVmEventDelivery.deliver(listener, EVENT, DeliveryOption.none())
+            when(listener.getExecutionMode()).thenReturn(EventListener.ExecutionMode.ASYNCHRONOUS);
+            assertThatCode(() -> inVmEventDelivery.deliver(listener, EventBusTestFixture.EVENT, EventDelivery.DeliveryOption.none())
                     .block())
                 .doesNotThrowAnyException();
         }
 
         @Test
         void deliverShouldNotFailWhenListenerGetException() {
-            when(listener.getExecutionMode()).thenReturn(MailboxListener.ExecutionMode.ASYNCHRONOUS);
+            when(listener.getExecutionMode()).thenReturn(EventListener.ExecutionMode.ASYNCHRONOUS);
             doThrow(new RuntimeException())
-                .when(listener).event(EVENT);
+                .when(listener).event(EventBusTestFixture.EVENT);
 
-            assertThatCode(() -> inVmEventDelivery.deliver(listener, EVENT, DeliveryOption.none())
+            assertThatCode(() -> inVmEventDelivery.deliver(listener, EventBusTestFixture.EVENT, EventDelivery.DeliveryOption.none())
                 .block())
             .doesNotThrowAnyException();
         }
 
         @Test
         void deliverShouldReturnAnSuccessSyncMonoWhenListenerGetException() {
-            when(listener.getExecutionMode()).thenReturn(MailboxListener.ExecutionMode.ASYNCHRONOUS);
+            when(listener.getExecutionMode()).thenReturn(EventListener.ExecutionMode.ASYNCHRONOUS);
             doThrow(new RuntimeException())
-                .when(listener).event(EVENT);
+                .when(listener).event(EventBusTestFixture.EVENT);
 
-            assertThatCode(() -> inVmEventDelivery.deliver(listener, EVENT, DeliveryOption.none())
+            assertThatCode(() -> inVmEventDelivery.deliver(listener, EventBusTestFixture.EVENT, EventDelivery.DeliveryOption.none())
                 .block())
             .doesNotThrowAnyException();
         }
@@ -154,17 +149,17 @@ class InVmEventDeliveryTest {
 
         @Test
         void retryShouldWorkWhenDeliverWithRetry() {
-            MailboxListenerCountingSuccessfulExecution listener = newListener();
+            EventBusTestFixture.EventListenerCountingSuccessfulExecution listener = newListener();
             doThrow(new RuntimeException())
                 .doThrow(new RuntimeException())
                 .doThrow(new RuntimeException())
                 .doCallRealMethod()
-                .when(listener).event(EVENT);
+                .when(listener).event(EventBusTestFixture.EVENT);
 
-            inVmEventDelivery.deliver(listener, EVENT,
-                DeliveryOption.of(
-                    BackoffRetryer.of(RetryBackoffConfiguration.DEFAULT, listener),
-                    PermanentFailureHandler.NO_HANDLER))
+            inVmEventDelivery.deliver(listener, EventBusTestFixture.EVENT,
+                EventDelivery.DeliveryOption.of(
+                    EventDelivery.Retryer.BackoffRetryer.of(RetryBackoffConfiguration.DEFAULT, listener),
+                    EventDelivery.PermanentFailureHandler.NO_HANDLER))
                 .block();
 
             assertThat(listener.numberOfEventCalls())
@@ -173,36 +168,36 @@ class InVmEventDeliveryTest {
 
         @Test
         void failureHandlerShouldWorkWhenDeliverWithFailureHandler() {
-            MailboxListenerCountingSuccessfulExecution listener = newListener();
+            EventBusTestFixture.EventListenerCountingSuccessfulExecution listener = newListener();
             doThrow(new RuntimeException())
-                .when(listener).event(EVENT);
+                .when(listener).event(EventBusTestFixture.EVENT);
 
             MemoryEventDeadLetters deadLetter = new MemoryEventDeadLetters();
 
-            inVmEventDelivery.deliver(listener, EVENT,
-                DeliveryOption.of(
-                    Retryer.NO_RETRYER,
-                    PermanentFailureHandler.StoreToDeadLetters.of(GROUP_A, deadLetter)))
+            inVmEventDelivery.deliver(listener, EventBusTestFixture.EVENT,
+                EventDelivery.DeliveryOption.of(
+                    EventDelivery.Retryer.NO_RETRYER,
+                    EventDelivery.PermanentFailureHandler.StoreToDeadLetters.of(EventBusTestFixture.GROUP_A, deadLetter)))
                 .block();
 
             assertThat(deadLetter.groupsWithFailedEvents().toStream())
-                .containsOnly(GROUP_A);
+                .containsOnly(EventBusTestFixture.GROUP_A);
         }
 
         @Test
         void failureHandlerShouldNotWorkWhenRetrySuccess() {
-            MailboxListenerCountingSuccessfulExecution listener = newListener();
+            EventBusTestFixture.EventListenerCountingSuccessfulExecution listener = newListener();
             doThrow(new RuntimeException())
                 .doThrow(new RuntimeException())
                 .doCallRealMethod()
-                .when(listener).event(EVENT);
+                .when(listener).event(EventBusTestFixture.EVENT);
 
             MemoryEventDeadLetters deadLetter = new MemoryEventDeadLetters();
 
-            inVmEventDelivery.deliver(listener, EVENT,
-                DeliveryOption.of(
-                    BackoffRetryer.of(RetryBackoffConfiguration.DEFAULT, listener),
-                    PermanentFailureHandler.StoreToDeadLetters.of(GROUP_A, deadLetter)))
+            inVmEventDelivery.deliver(listener, EventBusTestFixture.EVENT,
+                EventDelivery.DeliveryOption.of(
+                    EventDelivery.Retryer.BackoffRetryer.of(RetryBackoffConfiguration.DEFAULT, listener),
+                    EventDelivery.PermanentFailureHandler.StoreToDeadLetters.of(EventBusTestFixture.GROUP_A, deadLetter)))
                 .block();
 
             SoftAssertions.assertSoftly(softy -> {
@@ -216,7 +211,7 @@ class InVmEventDeliveryTest {
 
         @Test
         void failureHandlerShouldWorkWhenRetryFails() {
-            MailboxListenerCountingSuccessfulExecution listener = newListener();
+            EventBusTestFixture.EventListenerCountingSuccessfulExecution listener = newListener();
             //do throw  RetryBackoffConfiguration.DEFAULT.DEFAULT_MAX_RETRIES + 1 times
             doThrow(new RuntimeException())
                 .doThrow(new RuntimeException())
@@ -228,25 +223,25 @@ class InVmEventDeliveryTest {
                 .doThrow(new RuntimeException())
                 .doThrow(new RuntimeException())
                 .doCallRealMethod()
-                .when(listener).event(EVENT);
+                .when(listener).event(EventBusTestFixture.EVENT);
 
             MemoryEventDeadLetters deadLetter = new MemoryEventDeadLetters();
 
-            inVmEventDelivery.deliver(listener, EVENT,
-                DeliveryOption.of(
-                    BackoffRetryer.of(RetryBackoffConfiguration.builder()
+            inVmEventDelivery.deliver(listener, EventBusTestFixture.EVENT,
+                EventDelivery.DeliveryOption.of(
+                    EventDelivery.Retryer.BackoffRetryer.of(RetryBackoffConfiguration.builder()
                             .maxRetries(8)
                             .firstBackoff(Duration.ofMillis(1))
                             .jitterFactor(0.2)
                             .build(), listener),
-                    PermanentFailureHandler.StoreToDeadLetters.of(GROUP_A, deadLetter)))
+                    EventDelivery.PermanentFailureHandler.StoreToDeadLetters.of(EventBusTestFixture.GROUP_A, deadLetter)))
                 .block();
 
             SoftAssertions.assertSoftly(softy -> {
                 softy.assertThat(listener.numberOfEventCalls())
                     .isEqualTo(0);
                 assertThat(deadLetter.groupsWithFailedEvents().toStream())
-                    .containsOnly(GROUP_A);
+                    .containsOnly(EventBusTestFixture.GROUP_A);
             });
         }
     }
diff --git a/event-bus/pom.xml b/event-bus/pom.xml
new file mode 100644
index 0000000..4e36b39
--- /dev/null
+++ b/event-bus/pom.xml
@@ -0,0 +1,39 @@
+<?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/xsd/maven-4.0.0.xsd">
+    <modelVersion>4.0.0</modelVersion>
+    <parent>
+        <groupId>org.apache.james</groupId>
+        <artifactId>james-project</artifactId>
+        <version>3.6.0-SNAPSHOT</version>
+    </parent>
+
+    <artifactId>event-bus</artifactId>
+    <packaging>pom</packaging>
+    <name>Apache James :: Event Bus</name>
+
+    <modules>
+        <module>api</module>
+        <module>distributed</module>
+        <module>in-vm</module>
+    </modules>
+</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 1d1b08d..d541029 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,14 +22,15 @@ package org.apache.james.examples.custom.listeners;
 import javax.inject.Inject;
 import javax.mail.Flags;
 
+import org.apache.james.events.EventListener;
 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.mailbox.events.Event;
-import org.apache.james.mailbox.events.Group;
-import org.apache.james.mailbox.events.MailboxListener;
+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;
@@ -42,7 +43,7 @@ import org.slf4j.LoggerFactory;
  * Then it will be considered as a big message and added BIG_MESSAGE {@value BIG_MESSAGE} flag
  *
  */
-class SetCustomFlagOnBigMessages implements MailboxListener.GroupMailboxListener {
+class SetCustomFlagOnBigMessages implements EventListener.GroupEventListener {
     public static class PositionCustomFlagOnBigMessagesGroup extends Group {
 
     }
@@ -63,8 +64,8 @@ class SetCustomFlagOnBigMessages implements MailboxListener.GroupMailboxListener
 
     @Override
     public void event(Event event) {
-        if (event instanceof MailboxListener.Added) {
-            MailboxListener.Added addedEvent = (MailboxListener.Added) event;
+        if (event instanceof Added) {
+            Added addedEvent = (Added) event;
             addedEvent.getUids().stream()
                 .filter(messageUid -> isBig(addedEvent, messageUid))
                 .forEach(messageUid -> setBigMessageFlag(addedEvent, messageUid));
diff --git a/examples/custom-listeners/src/test/java/org/apache/james/examples/custom/listeners/SetCustomFlagOnBigMessagesTest.java b/examples/custom-listeners/src/test/java/org/apache/james/examples/custom/listeners/SetCustomFlagOnBigMessagesTest.java
index 8972fff..0ccbeca 100644
--- a/examples/custom-listeners/src/test/java/org/apache/james/examples/custom/listeners/SetCustomFlagOnBigMessagesTest.java
+++ b/examples/custom-listeners/src/test/java/org/apache/james/examples/custom/listeners/SetCustomFlagOnBigMessagesTest.java
@@ -33,7 +33,7 @@ import org.apache.james.mailbox.MailboxSession;
 import org.apache.james.mailbox.MailboxSessionUtil;
 import org.apache.james.mailbox.MessageManager;
 import org.apache.james.mailbox.MessageUid;
-import org.apache.james.mailbox.events.Event;
+import org.apache.james.events.Event;
 import org.apache.james.mailbox.inmemory.InMemoryMailboxManager;
 import org.apache.james.mailbox.inmemory.manager.InMemoryIntegrationResources;
 import org.apache.james.mailbox.model.ComposedMessageId;
diff --git a/mailbox/api/pom.xml b/mailbox/api/pom.xml
index a6146c3..ff31374 100644
--- a/mailbox/api/pom.xml
+++ b/mailbox/api/pom.xml
@@ -34,6 +34,10 @@
     <dependencies>
         <dependency>
             <groupId>${james.groupId}</groupId>
+            <artifactId>event-bus-api</artifactId>
+        </dependency>
+        <dependency>
+            <groupId>${james.groupId}</groupId>
             <artifactId>james-core</artifactId>
         </dependency>
         <dependency>
diff --git a/mailbox/api/src/main/java/org/apache/james/mailbox/events/MailboxListener.java b/mailbox/api/src/main/java/org/apache/james/events/MailboxEvents.java
similarity index 85%
copy from mailbox/api/src/main/java/org/apache/james/mailbox/events/MailboxListener.java
copy to mailbox/api/src/main/java/org/apache/james/events/MailboxEvents.java
index 11bb4e6..20dbe89 100644
--- a/mailbox/api/src/main/java/org/apache/james/mailbox/events/MailboxListener.java
+++ b/mailbox/api/src/main/java/org/apache/james/events/MailboxEvents.java
@@ -17,7 +17,7 @@
  * under the License.                                           *
  ****************************************************************/
 
-package org.apache.james.mailbox.events;
+package org.apache.james.events;
 
 import java.time.Instant;
 import java.util.Collection;
@@ -32,6 +32,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.events.Event;
 import org.apache.james.mailbox.MailboxSession;
 import org.apache.james.mailbox.MessageUid;
 import org.apache.james.mailbox.acl.ACLDiff;
@@ -43,130 +44,13 @@ 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 org.reactivestreams.Publisher;
 
-import com.github.fge.lambdas.Throwing;
 import com.github.steveash.guavate.Guavate;
 import com.google.common.collect.ImmutableList;
 import com.google.common.collect.ImmutableMap;
 import com.google.common.collect.ImmutableSet;
 
-import reactor.core.publisher.Mono;
-import reactor.core.scheduler.Schedulers;
-
-
-/**
- * Listens to <code>Mailbox</code> events.<br>
- * Note that listeners may be removed asynchronously.
- */
-public interface MailboxListener {
-
-    interface ReactiveMailboxListener extends MailboxListener {
-        Publisher<Void> reactiveEvent(Event event);
-
-        default void event(Event event) throws Exception {
-            Mono.from(reactiveEvent(event))
-                .subscribeOn(Schedulers.elastic())
-                .block();
-        }
-    }
-
-    interface GroupMailboxListener extends MailboxListener {
-        Group getDefaultGroup();
-    }
-
-    interface ReactiveGroupMailboxListener extends ReactiveMailboxListener, GroupMailboxListener {
-        default void event(Event event) throws Exception {
-            Mono.from(reactiveEvent(event))
-                .subscribeOn(Schedulers.elastic())
-                .block();
-        }
-    }
-
-    class ReactiveWrapper<T extends MailboxListener> implements ReactiveMailboxListener {
-        protected final T delegate;
-
-        private ReactiveWrapper(T delegate) {
-            this.delegate = delegate;
-        }
-
-        @Override
-        public Publisher<Void> reactiveEvent(Event event) {
-            return Mono.fromRunnable(Throwing.runnable(() -> delegate.event(event)))
-                .subscribeOn(Schedulers.elastic())
-                .then();
-        }
-
-        @Override
-        public void event(Event event) throws Exception {
-            delegate.event(event);
-        }
-
-        @Override
-        public ExecutionMode getExecutionMode() {
-            return delegate.getExecutionMode();
-        }
-
-        @Override
-        public boolean isHandling(Event event) {
-            return delegate.isHandling(event);
-        }
-
-        @Override
-        public final boolean equals(Object o) {
-            if (o instanceof ReactiveWrapper) {
-                ReactiveWrapper<?> that = (ReactiveWrapper<?>) o;
-
-                return Objects.equals(this.delegate, that.delegate);
-            }
-            return false;
-        }
-
-        @Override
-        public final int hashCode() {
-            return Objects.hash(delegate);
-        }
-    }
-
-    class ReactiveGroupWrapper extends ReactiveWrapper<GroupMailboxListener> implements GroupMailboxListener, ReactiveGroupMailboxListener {
-        private ReactiveGroupWrapper(GroupMailboxListener delegate) {
-            super(delegate);
-        }
-
-        @Override
-        public Group getDefaultGroup() {
-            return delegate.getDefaultGroup();
-        }
-    }
-
-    enum ExecutionMode {
-        SYNCHRONOUS,
-        ASYNCHRONOUS
-    }
-
-    static ReactiveMailboxListener wrapReactive(MailboxListener listener) {
-        return new ReactiveWrapper<>(listener);
-    }
-
-    static ReactiveGroupMailboxListener wrapReactive(GroupMailboxListener groupMailboxListener) {
-        return new ReactiveGroupWrapper(groupMailboxListener);
-    }
-
-    default ExecutionMode getExecutionMode() {
-        return ExecutionMode.SYNCHRONOUS;
-    }
-
-
-    default boolean isHandling(Event event) {
-        return true;
-    }
-
-    /**
-     * Informs this listener about the given event.
-     *
-     * @param event not null
-     */
-    void event(Event event) throws Exception;
+public interface MailboxEvents {
 
     interface QuotaEvent extends Event {
         QuotaRoot getQuotaRoot();
diff --git a/mailbox/api/src/main/java/org/apache/james/mailbox/events/MailboxIdRegistrationKey.java b/mailbox/api/src/main/java/org/apache/james/events/MailboxIdRegistrationKey.java
similarity index 98%
copy from mailbox/api/src/main/java/org/apache/james/mailbox/events/MailboxIdRegistrationKey.java
copy to mailbox/api/src/main/java/org/apache/james/events/MailboxIdRegistrationKey.java
index e132429..44387cb 100644
--- a/mailbox/api/src/main/java/org/apache/james/mailbox/events/MailboxIdRegistrationKey.java
+++ b/mailbox/api/src/main/java/org/apache/james/events/MailboxIdRegistrationKey.java
@@ -17,7 +17,7 @@
  * under the License.                                           *
  ****************************************************************/
 
-package org.apache.james.mailbox.events;
+package org.apache.james.events;
 
 import java.util.Objects;
 
diff --git a/mailbox/api/src/main/java/org/apache/james/mailbox/events/MessageMoveEvent.java b/mailbox/api/src/main/java/org/apache/james/events/MessageMoveEvent.java
similarity index 99%
copy from mailbox/api/src/main/java/org/apache/james/mailbox/events/MessageMoveEvent.java
copy to mailbox/api/src/main/java/org/apache/james/events/MessageMoveEvent.java
index b149f25..2c2f89f 100644
--- a/mailbox/api/src/main/java/org/apache/james/mailbox/events/MessageMoveEvent.java
+++ b/mailbox/api/src/main/java/org/apache/james/events/MessageMoveEvent.java
@@ -16,7 +16,7 @@
  * specific language governing permissions and limitations      *
  * under the License.                                           *
  ****************************************************************/
-package org.apache.james.mailbox.events;
+package org.apache.james.events;
 
 import java.util.Collection;
 import java.util.Objects;
diff --git a/mailbox/api/src/main/java/org/apache/james/events/RetryBackoffConfiguration.java b/mailbox/api/src/main/java/org/apache/james/events/RetryBackoffConfiguration.java
new file mode 100644
index 0000000..aafeb2c
--- /dev/null
+++ b/mailbox/api/src/main/java/org/apache/james/events/RetryBackoffConfiguration.java
@@ -0,0 +1,125 @@
+/****************************************************************
+ * 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.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/main/java/org/apache/james/mailbox/events/MailboxListener.java b/mailbox/api/src/main/java/org/apache/james/mailbox/events/MailboxEvents.java
similarity index 85%
rename from mailbox/api/src/main/java/org/apache/james/mailbox/events/MailboxListener.java
rename to mailbox/api/src/main/java/org/apache/james/mailbox/events/MailboxEvents.java
index 11bb4e6..d544e35 100644
--- a/mailbox/api/src/main/java/org/apache/james/mailbox/events/MailboxListener.java
+++ b/mailbox/api/src/main/java/org/apache/james/mailbox/events/MailboxEvents.java
@@ -32,6 +32,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.events.Event;
 import org.apache.james.mailbox.MailboxSession;
 import org.apache.james.mailbox.MessageUid;
 import org.apache.james.mailbox.acl.ACLDiff;
@@ -43,130 +44,13 @@ 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 org.reactivestreams.Publisher;
 
-import com.github.fge.lambdas.Throwing;
 import com.github.steveash.guavate.Guavate;
 import com.google.common.collect.ImmutableList;
 import com.google.common.collect.ImmutableMap;
 import com.google.common.collect.ImmutableSet;
 
-import reactor.core.publisher.Mono;
-import reactor.core.scheduler.Schedulers;
-
-
-/**
- * Listens to <code>Mailbox</code> events.<br>
- * Note that listeners may be removed asynchronously.
- */
-public interface MailboxListener {
-
-    interface ReactiveMailboxListener extends MailboxListener {
-        Publisher<Void> reactiveEvent(Event event);
-
-        default void event(Event event) throws Exception {
-            Mono.from(reactiveEvent(event))
-                .subscribeOn(Schedulers.elastic())
-                .block();
-        }
-    }
-
-    interface GroupMailboxListener extends MailboxListener {
-        Group getDefaultGroup();
-    }
-
-    interface ReactiveGroupMailboxListener extends ReactiveMailboxListener, GroupMailboxListener {
-        default void event(Event event) throws Exception {
-            Mono.from(reactiveEvent(event))
-                .subscribeOn(Schedulers.elastic())
-                .block();
-        }
-    }
-
-    class ReactiveWrapper<T extends MailboxListener> implements ReactiveMailboxListener {
-        protected final T delegate;
-
-        private ReactiveWrapper(T delegate) {
-            this.delegate = delegate;
-        }
-
-        @Override
-        public Publisher<Void> reactiveEvent(Event event) {
-            return Mono.fromRunnable(Throwing.runnable(() -> delegate.event(event)))
-                .subscribeOn(Schedulers.elastic())
-                .then();
-        }
-
-        @Override
-        public void event(Event event) throws Exception {
-            delegate.event(event);
-        }
-
-        @Override
-        public ExecutionMode getExecutionMode() {
-            return delegate.getExecutionMode();
-        }
-
-        @Override
-        public boolean isHandling(Event event) {
-            return delegate.isHandling(event);
-        }
-
-        @Override
-        public final boolean equals(Object o) {
-            if (o instanceof ReactiveWrapper) {
-                ReactiveWrapper<?> that = (ReactiveWrapper<?>) o;
-
-                return Objects.equals(this.delegate, that.delegate);
-            }
-            return false;
-        }
-
-        @Override
-        public final int hashCode() {
-            return Objects.hash(delegate);
-        }
-    }
-
-    class ReactiveGroupWrapper extends ReactiveWrapper<GroupMailboxListener> implements GroupMailboxListener, ReactiveGroupMailboxListener {
-        private ReactiveGroupWrapper(GroupMailboxListener delegate) {
-            super(delegate);
-        }
-
-        @Override
-        public Group getDefaultGroup() {
-            return delegate.getDefaultGroup();
-        }
-    }
-
-    enum ExecutionMode {
-        SYNCHRONOUS,
-        ASYNCHRONOUS
-    }
-
-    static ReactiveMailboxListener wrapReactive(MailboxListener listener) {
-        return new ReactiveWrapper<>(listener);
-    }
-
-    static ReactiveGroupMailboxListener wrapReactive(GroupMailboxListener groupMailboxListener) {
-        return new ReactiveGroupWrapper(groupMailboxListener);
-    }
-
-    default ExecutionMode getExecutionMode() {
-        return ExecutionMode.SYNCHRONOUS;
-    }
-
-
-    default boolean isHandling(Event event) {
-        return true;
-    }
-
-    /**
-     * Informs this listener about the given event.
-     *
-     * @param event not null
-     */
-    void event(Event event) throws Exception;
+public interface MailboxEvents {
 
     interface QuotaEvent extends Event {
         QuotaRoot getQuotaRoot();
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
index e132429..cbbd20b 100644
--- 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
@@ -23,6 +23,7 @@ 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 {
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
index b149f25..69173d2 100644
--- 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
@@ -23,6 +23,7 @@ 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;
diff --git a/mailbox/api/src/test/java/org/apache/james/mailbox/events/ErrorHandlingContract.java b/mailbox/api/src/test/java/org/apache/james/events/ErrorHandlingContract.java
similarity index 94%
copy from mailbox/api/src/test/java/org/apache/james/mailbox/events/ErrorHandlingContract.java
copy to mailbox/api/src/test/java/org/apache/james/events/ErrorHandlingContract.java
index 18bcb18..3d20090 100644
--- a/mailbox/api/src/test/java/org/apache/james/mailbox/events/ErrorHandlingContract.java
+++ b/mailbox/api/src/test/java/org/apache/james/events/ErrorHandlingContract.java
@@ -17,16 +17,16 @@
  * 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;
+package org.apache.james.events;
+
+import static org.apache.james.events.EventBusTestFixture.DEFAULT_FIRST_BACKOFF;
+import static org.apache.james.events.EventBusTestFixture.EVENT;
+import static org.apache.james.events.EventBusTestFixture.EVENT_2;
+import static org.apache.james.events.EventBusTestFixture.EVENT_ID;
+import static org.apache.james.events.EventBusTestFixture.GROUP_A;
+import static org.apache.james.events.EventBusTestFixture.KEY_1;
+import static org.apache.james.events.EventBusTestFixture.NO_KEYS;
+import static org.apache.james.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;
@@ -48,7 +48,7 @@ import reactor.core.publisher.Mono;
 
 interface ErrorHandlingContract extends EventBusContract {
 
-    class ThrowingListener implements MailboxListener {
+    class ThrowingListener implements EventListener {
         private final List<Instant> timeElapsed;
 
         private ThrowingListener() {
@@ -200,7 +200,7 @@ interface ErrorHandlingContract extends EventBusContract {
     default void retryingListenerCallingDispatchShouldNotFail() {
         AtomicBoolean firstExecution = new AtomicBoolean(true);
         AtomicBoolean successfulRetry = new AtomicBoolean(false);
-        MailboxListener listener = event -> {
+        EventListener listener = event -> {
             if (event.getEventId().equals(EVENT_ID)) {
                 if (firstExecution.get()) {
                     firstExecution.set(false);
diff --git a/mailbox/api/src/test/java/org/apache/james/mailbox/events/EventBusConcurrentTestContract.java b/mailbox/api/src/test/java/org/apache/james/events/EventBusConcurrentTestContract.java
similarity index 64%
copy from mailbox/api/src/test/java/org/apache/james/mailbox/events/EventBusConcurrentTestContract.java
copy to mailbox/api/src/test/java/org/apache/james/events/EventBusConcurrentTestContract.java
index 1aa3c2e..6648458 100644
--- a/mailbox/api/src/test/java/org/apache/james/mailbox/events/EventBusConcurrentTestContract.java
+++ b/mailbox/api/src/test/java/org/apache/james/events/EventBusConcurrentTestContract.java
@@ -17,14 +17,8 @@
  * 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;
+package org.apache.james.events;
+
 import static org.assertj.core.api.Assertions.assertThat;
 import static org.awaitility.Awaitility.await;
 
@@ -50,15 +44,15 @@ public interface EventBusConcurrentTestContract {
     int OPERATION_COUNT = 30;
     int TOTAL_DISPATCH_OPERATIONS = THREAD_COUNT * OPERATION_COUNT;
 
-    Set<RegistrationKey> ALL_KEYS = ImmutableSet.of(KEY_1, KEY_2, KEY_3);
+    Set<RegistrationKey> ALL_KEYS = ImmutableSet.of(EventBusTestFixture.KEY_1, EventBusTestFixture.KEY_2, EventBusTestFixture.KEY_3);
 
-    static EventBusTestFixture.MailboxListenerCountingSuccessfulExecution newCountingListener() {
-        return new EventBusTestFixture.MailboxListenerCountingSuccessfulExecution();
+    static EventBusTestFixture.EventListenerCountingSuccessfulExecution newCountingListener() {
+        return new EventBusTestFixture.EventListenerCountingSuccessfulExecution();
     }
 
-    static int totalEventsReceived(ImmutableList<EventBusTestFixture.MailboxListenerCountingSuccessfulExecution> allListeners) {
+    static int totalEventsReceived(ImmutableList<EventBusTestFixture.EventListenerCountingSuccessfulExecution> allListeners) {
         return allListeners.stream()
-            .mapToInt(EventBusTestFixture.MailboxListenerCountingSuccessfulExecution::numberOfEventCalls)
+            .mapToInt(EventBusTestFixture.EventListenerCountingSuccessfulExecution::numberOfEventCalls)
             .sum();
     }
 
@@ -66,9 +60,9 @@ public interface EventBusConcurrentTestContract {
 
         @Test
         default void concurrentDispatchGroupShouldDeliverAllEventsToListenersWithSingleEventBus() throws Exception {
-            EventBusTestFixture.MailboxListenerCountingSuccessfulExecution countingListener1 = newCountingListener();
-            EventBusTestFixture.MailboxListenerCountingSuccessfulExecution countingListener2 = newCountingListener();
-            EventBusTestFixture.MailboxListenerCountingSuccessfulExecution countingListener3 = newCountingListener();
+            EventBusTestFixture.EventListenerCountingSuccessfulExecution countingListener1 = newCountingListener();
+            EventBusTestFixture.EventListenerCountingSuccessfulExecution countingListener2 = newCountingListener();
+            EventBusTestFixture.EventListenerCountingSuccessfulExecution countingListener3 = newCountingListener();
 
             eventBus().register(countingListener1, new EventBusTestFixture.GroupA());
             eventBus().register(countingListener2, new EventBusTestFixture.GroupB());
@@ -76,7 +70,7 @@ public interface EventBusConcurrentTestContract {
             int totalGlobalRegistrations = 3; // GroupA + GroupB + GroupC
 
             ConcurrentTestRunner.builder()
-                .operation((threadNumber, operationNumber) -> eventBus().dispatch(EVENT, NO_KEYS).block())
+                .operation((threadNumber, operationNumber) -> eventBus().dispatch(EventBusTestFixture.EVENT, EventBusTestFixture.NO_KEYS).block())
                 .threadCount(THREAD_COUNT)
                 .operationCount(OPERATION_COUNT)
                 .runSuccessfullyWithin(FIVE_SECONDS);
@@ -88,18 +82,18 @@ public interface EventBusConcurrentTestContract {
 
         @Test
         default void concurrentDispatchKeyShouldDeliverAllEventsToListenersWithSingleEventBus() throws Exception {
-            EventBusTestFixture.MailboxListenerCountingSuccessfulExecution countingListener1 = newCountingListener();
-            EventBusTestFixture.MailboxListenerCountingSuccessfulExecution countingListener2 = newCountingListener();
-            EventBusTestFixture.MailboxListenerCountingSuccessfulExecution 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();
+            EventBusTestFixture.EventListenerCountingSuccessfulExecution countingListener1 = newCountingListener();
+            EventBusTestFixture.EventListenerCountingSuccessfulExecution countingListener2 = newCountingListener();
+            EventBusTestFixture.EventListenerCountingSuccessfulExecution countingListener3 = newCountingListener();
+            Mono.from(eventBus().register(countingListener1, EventBusTestFixture.KEY_1)).block();
+            Mono.from(eventBus().register(countingListener2, EventBusTestFixture.KEY_2)).block();
+            Mono.from(eventBus().register(countingListener3, EventBusTestFixture.KEY_3)).block();
 
             int totalKeyListenerRegistrations = 3; // KEY1 + KEY2 + KEY3
             int totalEventBus = 1;
 
             ConcurrentTestRunner.builder()
-                .operation((threadNumber, operationNumber) -> eventBus().dispatch(EVENT, ALL_KEYS).block())
+                .operation((threadNumber, operationNumber) -> eventBus().dispatch(EventBusTestFixture.EVENT, ALL_KEYS).block())
                 .threadCount(THREAD_COUNT)
                 .operationCount(OPERATION_COUNT)
                 .runSuccessfullyWithin(FIVE_SECONDS);
@@ -111,9 +105,9 @@ public interface EventBusConcurrentTestContract {
 
         @Test
         default void concurrentDispatchShouldDeliverAllEventsToListenersWithSingleEventBus() throws Exception {
-            EventBusTestFixture.MailboxListenerCountingSuccessfulExecution countingListener1 = newCountingListener();
-            EventBusTestFixture.MailboxListenerCountingSuccessfulExecution countingListener2 = newCountingListener();
-            EventBusTestFixture.MailboxListenerCountingSuccessfulExecution countingListener3 = newCountingListener();
+            EventBusTestFixture.EventListenerCountingSuccessfulExecution countingListener1 = newCountingListener();
+            EventBusTestFixture.EventListenerCountingSuccessfulExecution countingListener2 = newCountingListener();
+            EventBusTestFixture.EventListenerCountingSuccessfulExecution countingListener3 = newCountingListener();
 
             eventBus().register(countingListener1, new EventBusTestFixture.GroupA());
             eventBus().register(countingListener2, new EventBusTestFixture.GroupB());
@@ -122,14 +116,14 @@ public interface EventBusConcurrentTestContract {
             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();
+            Mono.from(eventBus().register(countingListener1, EventBusTestFixture.KEY_1)).block();
+            Mono.from(eventBus().register(countingListener2, EventBusTestFixture.KEY_2)).block();
+            Mono.from(eventBus().register(countingListener3, EventBusTestFixture.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())
+                .operation((threadNumber, operationNumber) -> eventBus().dispatch(EventBusTestFixture.EVENT, ALL_KEYS).block())
                 .threadCount(THREAD_COUNT)
                 .operationCount(OPERATION_COUNT)
                 .runSuccessfullyWithin(FIVE_SECONDS);
@@ -146,9 +140,9 @@ public interface EventBusConcurrentTestContract {
 
         @Test
         default void concurrentDispatchGroupShouldDeliverAllEventsToListenersWithMultipleEventBus() throws Exception {
-            EventBusTestFixture.MailboxListenerCountingSuccessfulExecution countingListener1 = newCountingListener();
-            EventBusTestFixture.MailboxListenerCountingSuccessfulExecution countingListener2 = newCountingListener();
-            EventBusTestFixture.MailboxListenerCountingSuccessfulExecution countingListener3 = newCountingListener();
+            EventBusTestFixture.EventListenerCountingSuccessfulExecution countingListener1 = newCountingListener();
+            EventBusTestFixture.EventListenerCountingSuccessfulExecution countingListener2 = newCountingListener();
+            EventBusTestFixture.EventListenerCountingSuccessfulExecution countingListener3 = newCountingListener();
 
             eventBus().register(countingListener1, new EventBusTestFixture.GroupA());
             eventBus().register(countingListener2, new EventBusTestFixture.GroupB());
@@ -161,7 +155,7 @@ public interface EventBusConcurrentTestContract {
             int totalGlobalRegistrations = 3; // GroupA + GroupB + GroupC
 
             ConcurrentTestRunner.builder()
-                .operation((threadNumber, operationNumber) -> eventBus().dispatch(EVENT, NO_KEYS).block())
+                .operation((threadNumber, operationNumber) -> eventBus().dispatch(EventBusTestFixture.EVENT, EventBusTestFixture.NO_KEYS).block())
                 .threadCount(THREAD_COUNT)
                 .operationCount(OPERATION_COUNT)
                 .runSuccessfullyWithin(FIVE_SECONDS);
@@ -173,23 +167,23 @@ public interface EventBusConcurrentTestContract {
 
         @Test
         default void concurrentDispatchKeyShouldDeliverAllEventsToListenersWithMultipleEventBus() throws Exception {
-            EventBusTestFixture.MailboxListenerCountingSuccessfulExecution countingListener1 = newCountingListener();
-            EventBusTestFixture.MailboxListenerCountingSuccessfulExecution countingListener2 = newCountingListener();
-            EventBusTestFixture.MailboxListenerCountingSuccessfulExecution countingListener3 = newCountingListener();
+            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(eventBus().register(countingListener1, EventBusTestFixture.KEY_1)).block();
+            Mono.from(eventBus().register(countingListener2, EventBusTestFixture.KEY_2)).block();
+            Mono.from(eventBus().register(countingListener3, EventBusTestFixture.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();
+            Mono.from(eventBus2().register(countingListener1, EventBusTestFixture.KEY_1)).block();
+            Mono.from(eventBus2().register(countingListener2, EventBusTestFixture.KEY_2)).block();
+            Mono.from(eventBus2().register(countingListener3, EventBusTestFixture.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())
+                .operation((threadNumber, operationNumber) -> eventBus().dispatch(EventBusTestFixture.EVENT, ALL_KEYS).block())
                 .threadCount(THREAD_COUNT)
                 .operationCount(OPERATION_COUNT)
                 .runSuccessfullyWithin(FIVE_SECONDS);
@@ -201,31 +195,31 @@ public interface EventBusConcurrentTestContract {
 
         @Test
         default void concurrentDispatchShouldDeliverAllEventsToListenersWithMultipleEventBus() throws Exception {
-            EventBusTestFixture.MailboxListenerCountingSuccessfulExecution countingListener1 = newCountingListener();
-            EventBusTestFixture.MailboxListenerCountingSuccessfulExecution countingListener2 = newCountingListener();
-            EventBusTestFixture.MailboxListenerCountingSuccessfulExecution countingListener3 = newCountingListener();
+            EventBusTestFixture.EventListenerCountingSuccessfulExecution countingListener1 = newCountingListener();
+            EventBusTestFixture.EventListenerCountingSuccessfulExecution countingListener2 = newCountingListener();
+            EventBusTestFixture.EventListenerCountingSuccessfulExecution countingListener3 = newCountingListener();
 
-            eventBus2().register(countingListener1, GROUP_A);
+            eventBus2().register(countingListener1, EventDeadLettersContract.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(eventBus().register(countingListener1, EventBusTestFixture.KEY_1)).block();
+            Mono.from(eventBus().register(countingListener2, EventBusTestFixture.KEY_2)).block();
 
-            Mono.from(eventBus2().register(countingListener1, KEY_1)).block();
-            Mono.from(eventBus2().register(countingListener2, KEY_2)).block();
+            Mono.from(eventBus2().register(countingListener1, EventBusTestFixture.KEY_1)).block();
+            Mono.from(eventBus2().register(countingListener2, EventBusTestFixture.KEY_2)).block();
 
-            Mono.from(eventBus3().register(countingListener3, KEY_1)).block();
-            Mono.from(eventBus3().register(countingListener3, KEY_2)).block();
+            Mono.from(eventBus3().register(countingListener3, EventBusTestFixture.KEY_1)).block();
+            Mono.from(eventBus3().register(countingListener3, EventBusTestFixture.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())
+                .operation((threadNumber, operationNumber) -> eventBus().dispatch(EventBusTestFixture.EVENT, ALL_KEYS).block())
                 .threadCount(THREAD_COUNT)
                 .operationCount(OPERATION_COUNT)
                 .runSuccessfullyWithin(FIVE_SECONDS);
diff --git a/mailbox/api/src/test/java/org/apache/james/mailbox/events/EventBusContract.java b/mailbox/api/src/test/java/org/apache/james/events/EventBusContract.java
similarity index 98%
copy from mailbox/api/src/test/java/org/apache/james/mailbox/events/EventBusContract.java
copy to mailbox/api/src/test/java/org/apache/james/events/EventBusContract.java
index 577697e..c1b52f9 100644
--- a/mailbox/api/src/test/java/org/apache/james/mailbox/events/EventBusContract.java
+++ b/mailbox/api/src/test/java/org/apache/james/events/EventBusContract.java
@@ -17,7 +17,7 @@
  * under the License.                                           *
  ****************************************************************/
 
-package org.apache.james.mailbox.events;
+package org.apache.james.events;
 
 import static org.awaitility.Awaitility.await;
 
diff --git a/mailbox/api/src/test/java/org/apache/james/mailbox/events/EventBusTestFixture.java b/mailbox/api/src/test/java/org/apache/james/events/EventBusTestFixture.java
similarity index 76%
copy from mailbox/api/src/test/java/org/apache/james/mailbox/events/EventBusTestFixture.java
copy to mailbox/api/src/test/java/org/apache/james/events/EventBusTestFixture.java
index b0bd987..e415382 100644
--- a/mailbox/api/src/test/java/org/apache/james/mailbox/events/EventBusTestFixture.java
+++ b/mailbox/api/src/test/java/org/apache/james/events/EventBusTestFixture.java
@@ -17,9 +17,9 @@
  * under the License.                                           *
  ****************************************************************/
 
-package org.apache.james.mailbox.events;
+package org.apache.james.events;
 
-import static org.apache.james.mailbox.events.RetryBackoffConfiguration.DEFAULT_JITTER_FACTOR;
+import static org.apache.james.events.RetryBackoffConfiguration.DEFAULT_JITTER_FACTOR;
 import static org.mockito.ArgumentMatchers.any;
 import static org.mockito.Mockito.mock;
 import static org.mockito.Mockito.when;
@@ -29,6 +29,9 @@ import java.util.concurrent.atomic.AtomicInteger;
 
 import org.apache.james.core.Username;
 import org.apache.james.mailbox.MailboxSession;
+import org.apache.james.events.MailboxEvents.MailboxAdded;
+import org.apache.james.events.MailboxEvents.MailboxEvent;
+import org.apache.james.events.MailboxEvents.MailboxRenamed;
 import org.apache.james.mailbox.model.MailboxConstants;
 import org.apache.james.mailbox.model.MailboxId;
 import org.apache.james.mailbox.model.MailboxPath;
@@ -39,7 +42,7 @@ import com.google.common.collect.ImmutableSet;
 
 public interface EventBusTestFixture {
 
-    class MailboxListenerCountingSuccessfulExecution implements MailboxListener {
+    class EventListenerCountingSuccessfulExecution implements EventListener {
         private final AtomicInteger calls = new AtomicInteger(0);
 
         @Override
@@ -57,7 +60,7 @@ public interface EventBusTestFixture {
         }
     }
 
-    class EventMatcherThrowingListener extends MailboxListenerCountingSuccessfulExecution {
+    class EventMatcherThrowingListener extends EventListenerCountingSuccessfulExecution {
         private final ImmutableSet<Event> eventsCauseThrowing;
 
         EventMatcherThrowingListener(ImmutableSet<Event> eventsCauseThrowing) {
@@ -96,9 +99,9 @@ public interface EventBusTestFixture {
     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");
-    MailboxListener.MailboxEvent EVENT = new MailboxListener.MailboxAdded(SESSION_ID, USERNAME, MAILBOX_PATH, TEST_ID, EVENT_ID);
-    MailboxListener.MailboxEvent EVENT_2 = new MailboxListener.MailboxAdded(SESSION_ID, USERNAME, MAILBOX_PATH, TEST_ID, EVENT_ID_2);
-    MailboxListener.MailboxRenamed EVENT_UNSUPPORTED_BY_LISTENER = new MailboxListener.MailboxRenamed(SESSION_ID, USERNAME, MAILBOX_PATH, TEST_ID, MAILBOX_PATH, EVENT_ID_2);
+    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);
@@ -122,17 +125,17 @@ public interface EventBusTestFixture {
         .jitterFactor(DEFAULT_JITTER_FACTOR)
         .build();
 
-    static MailboxListener newListener() {
-        MailboxListener listener = mock(MailboxListener.class);
-        when(listener.getExecutionMode()).thenReturn(MailboxListener.ExecutionMode.SYNCHRONOUS);
-        when(listener.isHandling(any(MailboxListener.MailboxAdded.class))).thenReturn(true);
+    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 MailboxListener newAsyncListener() {
-        MailboxListener listener = mock(MailboxListener.class);
-        when(listener.getExecutionMode()).thenReturn(MailboxListener.ExecutionMode.ASYNCHRONOUS);
-        when(listener.isHandling(any(MailboxListener.MailboxAdded.class))).thenReturn(true);
+    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/events/EventDeadLettersContract.java
similarity index 97%
copy from mailbox/api/src/test/java/org/apache/james/mailbox/events/EventDeadLettersContract.java
copy to mailbox/api/src/test/java/org/apache/james/events/EventDeadLettersContract.java
index ebbbdbc..c8f158c 100644
--- a/mailbox/api/src/test/java/org/apache/james/mailbox/events/EventDeadLettersContract.java
+++ b/mailbox/api/src/test/java/org/apache/james/events/EventDeadLettersContract.java
@@ -17,7 +17,7 @@
  * under the License.                                           *
  ****************************************************************/
 
-package org.apache.james.mailbox.events;
+package org.apache.james.events;
 
 import static org.assertj.core.api.Assertions.assertThat;
 import static org.assertj.core.api.Assertions.assertThatCode;
@@ -32,6 +32,7 @@ import java.util.stream.Stream;
 
 import org.apache.james.core.Username;
 import org.apache.james.mailbox.MailboxSession;
+import org.apache.james.events.MailboxEvents.MailboxAdded;
 import org.apache.james.mailbox.model.MailboxConstants;
 import org.apache.james.mailbox.model.MailboxPath;
 import org.apache.james.mailbox.model.TestId;
@@ -93,7 +94,7 @@ interface EventDeadLettersContract {
     }
 
     static Event event(Event.EventId eventId) {
-        return new MailboxListener.MailboxAdded(SESSION_ID, USERNAME, MAILBOX_PATH, MAILBOX_ID, 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(),
@@ -109,9 +110,9 @@ interface EventDeadLettersContract {
     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");
-    MailboxListener.MailboxAdded EVENT_1 = new MailboxListener.MailboxAdded(SESSION_ID, USERNAME, MAILBOX_PATH, MAILBOX_ID, EVENT_ID_1);
-    MailboxListener.MailboxAdded EVENT_2 = new MailboxListener.MailboxAdded(SESSION_ID, USERNAME, MAILBOX_PATH, MAILBOX_ID, EVENT_ID_2);
-    MailboxListener.MailboxAdded EVENT_3 = new MailboxListener.MailboxAdded(SESSION_ID, USERNAME, MAILBOX_PATH, MAILBOX_ID, EVENT_ID_3);
+    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");
diff --git a/mailbox/api/src/test/java/org/apache/james/mailbox/events/EventDeadLettersHealthCheckContract.java b/mailbox/api/src/test/java/org/apache/james/events/EventDeadLettersHealthCheckContract.java
similarity index 94%
copy from mailbox/api/src/test/java/org/apache/james/mailbox/events/EventDeadLettersHealthCheckContract.java
copy to mailbox/api/src/test/java/org/apache/james/events/EventDeadLettersHealthCheckContract.java
index 7c16b7b..6e4dc63 100644
--- a/mailbox/api/src/test/java/org/apache/james/mailbox/events/EventDeadLettersHealthCheckContract.java
+++ b/mailbox/api/src/test/java/org/apache/james/events/EventDeadLettersHealthCheckContract.java
@@ -17,7 +17,7 @@
  * under the License.                                           *
  ****************************************************************/
 
-package org.apache.james.mailbox.events;
+package org.apache.james.events;
 
 import static org.assertj.core.api.Assertions.assertThat;
 
@@ -25,6 +25,7 @@ import org.apache.james.core.Username;
 import org.apache.james.core.healthcheck.ComponentName;
 import org.apache.james.core.healthcheck.Result;
 import org.apache.james.mailbox.MailboxSession;
+import org.apache.james.events.MailboxEvents.MailboxAdded;
 import org.apache.james.mailbox.model.MailboxConstants;
 import org.apache.james.mailbox.model.MailboxPath;
 import org.apache.james.mailbox.model.TestId;
@@ -41,8 +42,8 @@ interface EventDeadLettersHealthCheckContract {
     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");
-    MailboxListener.MailboxAdded EVENT_1 = new MailboxListener.MailboxAdded(SESSION_ID, USERNAME, MAILBOX_PATH, MAILBOX_ID, EVENT_ID_1);
-    MailboxListener.MailboxAdded EVENT_2 = new MailboxListener.MailboxAdded(SESSION_ID, USERNAME, MAILBOX_PATH, MAILBOX_ID, EVENT_ID_2);
+    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();
diff --git a/mailbox/api/src/test/java/org/apache/james/events/GroupContract.java b/mailbox/api/src/test/java/org/apache/james/events/GroupContract.java
new file mode 100644
index 0000000..648b6e2
--- /dev/null
+++ b/mailbox/api/src/test/java/org/apache/james/events/GroupContract.java
@@ -0,0 +1,487 @@
+/****************************************************************
+ * 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.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 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.mailbox.MailboxSession;
+import org.apache.james.events.MailboxEvents.Added;
+import org.apache.james.mailbox.model.MailboxPath;
+import org.apache.james.mailbox.model.TestId;
+import org.apache.james.events.EventBusTestFixture.TestEvent;
+import org.apache.james.mailbox.events.GenericGroup;
+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();
+
+                }
+            }, EventBusTestFixture.GROUP_A);
+
+            IntStream.range(0, eventCount)
+                .forEach(i -> eventBus().dispatch(EventBusTestFixture.EVENT, EventBusTestFixture.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();
+                    }
+                }, EventBusTestFixture.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();
+                    }
+                }, EventBusTestFixture.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();
+                    }
+                }, EventBusTestFixture.GROUP_C);
+
+                eventBus().dispatch(EventBusTestFixture.EVENT, EventBusTestFixture.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(EventBusTestFixture.EVENT_ID)) {
+                    eventBus().dispatch(EventBusTestFixture.EVENT_2, EventBusTestFixture.NO_KEYS)
+                        .subscribeOn(Schedulers.elastic())
+                        .block();
+                    successfulRetry.set(true);
+                }
+            };
+
+            eventBus().register(listener, EventBusTestFixture.GROUP_A);
+            eventBus().dispatch(EventBusTestFixture.EVENT, EventBusTestFixture.NO_KEYS).block();
+
+            getSpeedProfile().shortWaitCondition().until(successfulRetry::get);
+        }
+
+        @Test
+        default void registerShouldNotDispatchPastEventsForGroups() throws Exception {
+            EventListener listener = EventBusTestFixture.newListener();
+
+            eventBus().dispatch(EventBusTestFixture.EVENT, EventBusTestFixture.NO_KEYS).block();
+
+            eventBus().register(listener, EventBusTestFixture.GROUP_A);
+
+            verify(listener, after(EventBusTestFixture.FIVE_HUNDRED_MS.toMillis()).never())
+                .event(any());
+        }
+
+        @Test
+        default void listenerGroupShouldReceiveEvents() throws Exception {
+            EventListener listener = EventBusTestFixture.newListener();
+
+            eventBus().register(listener, EventBusTestFixture.GROUP_A);
+
+            eventBus().dispatch(EventBusTestFixture.EVENT, EventBusTestFixture.NO_KEYS).block();
+
+            verify(listener, timeout(EventBusTestFixture.ONE_SECOND.toMillis()).times(1)).event(any());
+        }
+
+        @Test
+        default void groupListenersShouldNotReceiveNoopEvents() throws Exception {
+            EventListener listener = EventBusTestFixture.newListener();
+
+            eventBus().register(listener, EventBusTestFixture.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, EventBusTestFixture.NO_KEYS).block();
+
+            verify(listener, after(EventBusTestFixture.FIVE_HUNDRED_MS.toMillis()).never())
+                .event(any());
+        }
+
+        @Test
+        default void groupListenersShouldReceiveOnlyHandledEvents() throws Exception {
+            EventListener listener = EventBusTestFixture.newListener();
+
+            eventBus().register(listener, EventBusTestFixture.GROUP_A);
+
+            eventBus().dispatch(EventBusTestFixture.EVENT_UNSUPPORTED_BY_LISTENER, EventBusTestFixture.NO_KEYS).block();
+
+            verify(listener, after(EventBusTestFixture.FIVE_HUNDRED_MS.toMillis()).never())
+                .event(any());
+        }
+
+        @Test
+        default void dispatchShouldNotThrowWhenAGroupListenerFails() throws Exception {
+            EventListener listener = EventBusTestFixture.newListener();
+            doThrow(new RuntimeException()).when(listener).event(any());
+
+            eventBus().register(listener, EventBusTestFixture.GROUP_A);
+
+            assertThatCode(() -> eventBus().dispatch(EventBusTestFixture.EVENT, EventBusTestFixture.NO_KEYS).block())
+                .doesNotThrowAnyException();
+        }
+
+        @Test
+        default void eachListenerGroupShouldReceiveEvents() throws Exception {
+            EventListener listener = EventBusTestFixture.newListener();
+            EventListener listener2 = EventBusTestFixture.newListener();
+            eventBus().register(listener, EventBusTestFixture.GROUP_A);
+            eventBus().register(listener2, EventBusTestFixture.GROUP_B);
+
+            eventBus().dispatch(EventBusTestFixture.EVENT, EventBusTestFixture.NO_KEYS).block();
+
+            verify(listener, timeout(EventBusTestFixture.ONE_SECOND.toMillis()).times(1)).event(any());
+            verify(listener2, timeout(EventBusTestFixture.ONE_SECOND.toMillis()).times(1)).event(any());
+        }
+
+        @Test
+        default void unregisteredGroupListenerShouldNotReceiveEvents() throws Exception {
+            EventListener listener = EventBusTestFixture.newListener();
+            Registration registration = eventBus().register(listener, EventBusTestFixture.GROUP_A);
+
+            registration.unregister();
+
+            eventBus().dispatch(EventBusTestFixture.EVENT, EventBusTestFixture.NO_KEYS).block();
+            verify(listener, after(EventBusTestFixture.FIVE_HUNDRED_MS.toMillis()).never())
+                .event(any());
+        }
+
+        @Test
+        default void registerShouldThrowWhenAGroupIsAlreadyUsed() {
+            EventListener listener = EventBusTestFixture.newListener();
+            EventListener listener2 = EventBusTestFixture.newListener();
+
+            eventBus().register(listener, EventBusTestFixture.GROUP_A);
+
+            assertThatThrownBy(() -> eventBus().register(listener2, EventBusTestFixture.GROUP_A))
+                .isInstanceOf(GroupAlreadyRegistered.class);
+        }
+
+        @Test
+        default void registerShouldNotThrowOnAnUnregisteredGroup() {
+            EventListener listener = EventBusTestFixture.newListener();
+            EventListener listener2 = EventBusTestFixture.newListener();
+
+            eventBus().register(listener, EventBusTestFixture.GROUP_A).unregister();
+
+            assertThatCode(() -> eventBus().register(listener2, EventBusTestFixture.GROUP_A))
+                .doesNotThrowAnyException();
+        }
+
+        @Test
+        default void unregisterShouldBeIdempotentForGroups() {
+            EventListener listener = EventBusTestFixture.newListener();
+
+            Registration registration = eventBus().register(listener, EventBusTestFixture.GROUP_A);
+            registration.unregister();
+
+            assertThatCode(registration::unregister)
+                .doesNotThrowAnyException();
+        }
+
+        @Test
+        default void registerShouldAcceptAlreadyUnregisteredGroups() throws Exception {
+            EventListener listener = EventBusTestFixture.newListener();
+
+            eventBus().register(listener, EventBusTestFixture.GROUP_A).unregister();
+            eventBus().register(listener, EventBusTestFixture.GROUP_A);
+
+            eventBus().dispatch(EventBusTestFixture.EVENT, EventBusTestFixture.NO_KEYS).block();
+
+            verify(listener, timeout(EventBusTestFixture.ONE_SECOND.toMillis()).times(1)).event(any());
+        }
+
+        @Test
+        default void dispatchShouldCallSynchronousListener() throws Exception {
+            EventListener listener = EventBusTestFixture.newListener();
+
+            eventBus().register(listener, EventBusTestFixture.GROUP_A);
+
+            eventBus().dispatch(EventBusTestFixture.EVENT, EventBusTestFixture.NO_KEYS).block();
+
+            verify(listener, timeout(EventBusTestFixture.ONE_SECOND.toMillis()).times(1)).event(any());
+        }
+
+        @Test
+        default void failingGroupListenersShouldNotAbortGroupDelivery() {
+            EventBusTestFixture.EventListenerCountingSuccessfulExecution listener = new EventBusTestFixture.EventMatcherThrowingListener(ImmutableSet.of(EventBusTestFixture.EVENT));
+            eventBus().register(listener, EventBusTestFixture.GROUP_A);
+
+            eventBus().dispatch(EventBusTestFixture.EVENT, EventBusTestFixture.NO_KEYS).block();
+            eventBus().dispatch(EventBusTestFixture.EVENT_2, EventBusTestFixture.NO_KEYS).block();
+
+            getSpeedProfile().shortWaitCondition()
+                .untilAsserted(() -> assertThat(listener.numberOfEventCalls()).isEqualTo(1));
+        }
+
+        @Test
+        default void allGroupListenersShouldBeExecutedWhenAGroupListenerFails() throws Exception {
+            EventListener listener = EventBusTestFixture.newListener();
+
+            EventListener failingListener = mock(EventListener.class);
+            when(failingListener.getExecutionMode()).thenReturn(EventListener.ExecutionMode.SYNCHRONOUS);
+            doThrow(new RuntimeException()).when(failingListener).event(any());
+
+            eventBus().register(failingListener, EventBusTestFixture.GROUP_A);
+            eventBus().register(listener, EventBusTestFixture.GROUP_B);
+
+            eventBus().dispatch(EventBusTestFixture.EVENT, EventBusTestFixture.NO_KEYS).block();
+
+            verify(listener, timeout(EventBusTestFixture.ONE_SECOND.toMillis()).times(1)).event(any());
+        }
+
+        @Test
+        default void allGroupListenersShouldBeExecutedWhenGenericGroups() throws Exception {
+            EventListener listener1 = EventBusTestFixture.newListener();
+            EventListener listener2 = EventBusTestFixture.newListener();
+
+            eventBus().register(listener1, new GenericGroup("a"));
+            eventBus().register(listener2, new GenericGroup("b"));
+
+            eventBus().dispatch(EventBusTestFixture.EVENT, EventBusTestFixture.NO_KEYS).block();
+
+            verify(listener1, timeout(EventBusTestFixture.ONE_SECOND.toMillis()).times(1)).event(any());
+            verify(listener2, timeout(EventBusTestFixture.ONE_SECOND.toMillis()).times(1)).event(any());
+        }
+
+        @Test
+        default void groupListenerShouldReceiveEventWhenRedeliver() throws Exception {
+            EventListener listener = EventBusTestFixture.newListener();
+
+            eventBus().register(listener, EventBusTestFixture.GROUP_A);
+
+            eventBus().reDeliver(EventBusTestFixture.GROUP_A, EventBusTestFixture.EVENT).block();
+
+            verify(listener, timeout(EventBusTestFixture.ONE_SECOND.toMillis()).times(1)).event(any());
+        }
+
+        @Test
+        default void redeliverShouldNotThrowWhenAGroupListenerFails() throws Exception {
+            EventListener listener = EventBusTestFixture.newListener();
+            doThrow(new RuntimeException()).when(listener).event(any());
+
+            eventBus().register(listener, EventBusTestFixture.GROUP_A);
+
+            assertThatCode(() -> eventBus().reDeliver(EventBusTestFixture.GROUP_A, EventBusTestFixture.EVENT).block())
+                .doesNotThrowAnyException();
+        }
+
+        @Test
+        default void redeliverShouldThrowWhenGroupNotRegistered() {
+            assertThatThrownBy(() -> eventBus().reDeliver(EventBusTestFixture.GROUP_A, EventBusTestFixture.EVENT).block())
+                .isInstanceOf(GroupRegistrationNotFound.class);
+        }
+
+        @Test
+        default void redeliverShouldThrowAfterGroupIsUnregistered() {
+            EventListener listener = EventBusTestFixture.newListener();
+
+            eventBus().register(listener, EventBusTestFixture.GROUP_A).unregister();
+
+            assertThatThrownBy(() -> eventBus().reDeliver(EventBusTestFixture.GROUP_A, EventBusTestFixture.EVENT).block())
+                .isInstanceOf(GroupRegistrationNotFound.class);
+        }
+
+        @Test
+        default void redeliverShouldOnlySendEventToDefinedGroup() throws Exception {
+            EventListener listener = EventBusTestFixture.newListener();
+            EventListener listener2 = EventBusTestFixture.newListener();
+            eventBus().register(listener, EventBusTestFixture.GROUP_A);
+            eventBus().register(listener2, EventBusTestFixture.GROUP_B);
+
+            eventBus().reDeliver(EventBusTestFixture.GROUP_A, EventBusTestFixture.EVENT).block();
+
+            verify(listener, timeout(EventBusTestFixture.ONE_SECOND.toMillis()).times(1)).event(any());
+            verify(listener2, after(EventBusTestFixture.FIVE_HUNDRED_MS.toMillis()).never()).event(any());
+        }
+
+        @Test
+        default void groupListenersShouldNotReceiveNoopRedeliveredEvents() throws Exception {
+            EventListener listener = EventBusTestFixture.newListener();
+
+            eventBus().register(listener, EventBusTestFixture.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(EventBusTestFixture.GROUP_A, noopEvent).block();
+
+            verify(listener, after(EventBusTestFixture.FIVE_HUNDRED_MS.toMillis()).never()).event(any());
+        }
+    }
+
+    interface MultipleEventBusGroupContract extends EventBusContract.MultipleEventBusContract {
+
+        @Test
+        default void groupsDefinedOnlyOnSomeNodesShouldBeNotifiedWhenDispatch() throws Exception {
+            EventListener mailboxListener = EventBusTestFixture.newListener();
+
+            eventBus().register(mailboxListener, EventBusTestFixture.GROUP_A);
+
+            eventBus2().dispatch(EventBusTestFixture.EVENT, EventBusTestFixture.NO_KEYS).block();
+
+            verify(mailboxListener, timeout(EventBusTestFixture.ONE_SECOND.toMillis()).times(1)).event(any());
+        }
+
+        @Test
+        default void groupsDefinedOnlyOnSomeNodesShouldNotBeNotifiedWhenRedeliver() {
+            EventListener mailboxListener = EventBusTestFixture.newListener();
+
+            eventBus().register(mailboxListener, EventBusTestFixture.GROUP_A);
+
+            assertThatThrownBy(() -> eventBus2().reDeliver(EventBusTestFixture.GROUP_A, EventBusTestFixture.EVENT).block())
+                .isInstanceOf(GroupRegistrationNotFound.class);
+        }
+
+        @Test
+        default void groupListenersShouldBeExecutedOnceWhenRedeliverInADistributedEnvironment() throws Exception {
+            EventListener mailboxListener = EventBusTestFixture.newListener();
+
+            eventBus().register(mailboxListener, EventBusTestFixture.GROUP_A);
+            eventBus2().register(mailboxListener, EventBusTestFixture.GROUP_A);
+
+            eventBus2().reDeliver(EventBusTestFixture.GROUP_A, EventBusTestFixture.EVENT).block();
+
+            verify(mailboxListener, timeout(EventBusTestFixture.ONE_SECOND.toMillis()).times(1)).event(any());
+        }
+
+        @Test
+        default void groupListenersShouldBeExecutedOnceInAControlledEnvironment() throws Exception {
+            EventListener mailboxListener = EventBusTestFixture.newListener();
+
+            eventBus().register(mailboxListener, EventBusTestFixture.GROUP_A);
+            eventBus2().register(mailboxListener, EventBusTestFixture.GROUP_A);
+
+            eventBus2().dispatch(EventBusTestFixture.EVENT, EventBusTestFixture.NO_KEYS).block();
+
+            verify(mailboxListener, timeout(EventBusTestFixture.ONE_SECOND.toMillis()).times(1)).event(any());
+        }
+
+        @Test
+        default void unregisterShouldStopNotificationForDistantGroups() throws Exception {
+            EventListener mailboxListener = EventBusTestFixture.newListener();
+
+            eventBus().register(mailboxListener, EventBusTestFixture.GROUP_A).unregister();
+
+            eventBus2().dispatch(EventBusTestFixture.EVENT, EventBusTestFixture.NO_KEYS).block();
+
+
+            verify(mailboxListener, after(EventBusTestFixture.FIVE_HUNDRED_MS.toMillis()).never())
+                .event(any());
+        }
+
+        @Test
+        default void registerShouldNotDispatchPastEventsForGroupsInADistributedContext() throws Exception {
+            EventListener listener = EventBusTestFixture.newListener();
+
+            eventBus().dispatch(EventBusTestFixture.EVENT, EventBusTestFixture.NO_KEYS).block();
+
+            eventBus2().register(listener, EventBusTestFixture.GROUP_A);
+
+            verify(listener, after(EventBusTestFixture.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/events/GroupTest.java
similarity index 98%
copy from mailbox/api/src/test/java/org/apache/james/mailbox/events/GroupTest.java
copy to mailbox/api/src/test/java/org/apache/james/events/GroupTest.java
index 617e191..1b02148 100644
--- a/mailbox/api/src/test/java/org/apache/james/mailbox/events/GroupTest.java
+++ b/mailbox/api/src/test/java/org/apache/james/events/GroupTest.java
@@ -17,11 +17,12 @@
  * under the License.                                           *
  ****************************************************************/
 
-package org.apache.james.mailbox.events;
+package org.apache.james.events;
 
 import static org.assertj.core.api.Assertions.assertThat;
 import static org.assertj.core.api.Assertions.assertThatThrownBy;
 
+import org.apache.james.mailbox.events.GenericGroup;
 import org.junit.jupiter.api.Test;
 
 import nl.jqno.equalsverifier.EqualsVerifier;
diff --git a/mailbox/api/src/test/java/org/apache/james/mailbox/events/InsertionIdTest.java b/mailbox/api/src/test/java/org/apache/james/events/InsertionIdTest.java
similarity index 96%
copy from mailbox/api/src/test/java/org/apache/james/mailbox/events/InsertionIdTest.java
copy to mailbox/api/src/test/java/org/apache/james/events/InsertionIdTest.java
index f8a1e0e..d592590 100644
--- a/mailbox/api/src/test/java/org/apache/james/mailbox/events/InsertionIdTest.java
+++ b/mailbox/api/src/test/java/org/apache/james/events/InsertionIdTest.java
@@ -17,13 +17,14 @@
  * under the License.                                           *
  ****************************************************************/
 
-package org.apache.james.mailbox.events;
+package org.apache.james.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;
diff --git a/mailbox/api/src/test/java/org/apache/james/events/KeyContract.java b/mailbox/api/src/test/java/org/apache/james/events/KeyContract.java
new file mode 100644
index 0000000..9eb4819
--- /dev/null
+++ b/mailbox/api/src/test/java/org/apache/james/events/KeyContract.java
@@ -0,0 +1,445 @@
+/****************************************************************
+ * 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.events;
+
+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.mailbox.MailboxSession;
+import org.apache.james.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();
+
+            }, EventBusTestFixture.KEY_1)).block();
+
+            IntStream.range(0, eventCount)
+                .forEach(i -> eventBus().dispatch(EventBusTestFixture.EVENT, EventBusTestFixture.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();
+                }, EventBusTestFixture.KEY_1)).block();
+                Mono.from(eventBus().register(event -> {
+                    threads.add(Thread.currentThread().getName());
+                    countDownLatch.await();
+                }, EventBusTestFixture.KEY_1)).block();
+                Mono.from(eventBus().register(event -> {
+                    threads.add(Thread.currentThread().getName());
+                    countDownLatch.await();
+                }, EventBusTestFixture.KEY_1)).block();
+
+                eventBus().dispatch(EventBusTestFixture.EVENT, EventBusTestFixture.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 = EventBusTestFixture.newListener();
+
+            Mono.from(eventBus().register(listener, EventBusTestFixture.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, EventBusTestFixture.KEY_1).block();
+
+            verify(listener, after(EventBusTestFixture.FIVE_HUNDRED_MS.toMillis()).never())
+                .event(any());
+        }
+
+       @Test
+        default void registeredListenersShouldReceiveOnlyHandledEvents() throws Exception {
+            EventListener listener = EventBusTestFixture.newListener();
+
+            Mono.from(eventBus().register(listener, EventBusTestFixture.KEY_1)).block();
+
+            eventBus().dispatch(EventBusTestFixture.EVENT_UNSUPPORTED_BY_LISTENER, EventBusTestFixture.KEY_1).block();
+
+            verify(listener, after(EventBusTestFixture.FIVE_HUNDRED_MS.toMillis()).never())
+                .event(any());
+        }
+
+        @Test
+        default void dispatchShouldNotThrowWhenARegisteredListenerFails() throws Exception {
+            EventListener listener = EventBusTestFixture.newListener();
+            doThrow(new RuntimeException()).when(listener).event(any());
+
+            Mono.from(eventBus().register(listener, EventBusTestFixture.KEY_1)).block();
+
+            assertThatCode(() -> eventBus().dispatch(EventBusTestFixture.EVENT, EventBusTestFixture.NO_KEYS).block())
+                .doesNotThrowAnyException();
+        }
+
+        @Test
+        default void dispatchShouldNotNotifyRegisteredListenerWhenEmptyKeySet() throws Exception {
+            EventListener listener = EventBusTestFixture.newListener();
+            Mono.from(eventBus().register(listener, EventBusTestFixture.KEY_1)).block();
+
+            eventBus().dispatch(EventBusTestFixture.EVENT, EventBusTestFixture.NO_KEYS).block();
+
+            verify(listener, after(EventBusTestFixture.FIVE_HUNDRED_MS.toMillis()).never())
+                .event(any());
+        }
+
+        @Test
+        default void dispatchShouldNotNotifyListenerRegisteredOnOtherKeys() throws Exception {
+            EventListener listener = EventBusTestFixture.newListener();
+            Mono.from(eventBus().register(listener, EventBusTestFixture.KEY_1)).block();
+
+            eventBus().dispatch(EventBusTestFixture.EVENT, ImmutableSet.of(EventBusTestFixture.KEY_2)).block();
+
+            verify(listener, after(EventBusTestFixture.FIVE_HUNDRED_MS.toMillis()).never())
+                .event(any());
+        }
+
+        @Test
+        default void dispatchShouldNotifyRegisteredListeners() throws Exception {
+            EventListener listener = EventBusTestFixture.newListener();
+            Mono.from(eventBus().register(listener, EventBusTestFixture.KEY_1)).block();
+
+            eventBus().dispatch(EventBusTestFixture.EVENT, ImmutableSet.of(EventBusTestFixture.KEY_1)).block();
+
+            verify(listener, timeout(EventBusTestFixture.ONE_SECOND.toMillis()).times(1)).event(any());
+        }
+
+        @Test
+        default void dispatchShouldNotifyLocalRegisteredListenerWithoutDelay() throws Exception {
+            EventListener listener = EventBusTestFixture.newListener();
+            Mono.from(eventBus().register(listener, EventBusTestFixture.KEY_1)).block();
+
+            eventBus().dispatch(EventBusTestFixture.EVENT, ImmutableSet.of(EventBusTestFixture.KEY_1)).block();
+
+            verify(listener, times(1)).event(any());
+        }
+
+        @Test
+        default void dispatchShouldNotifyOnlyRegisteredListener() throws Exception {
+            EventListener listener = EventBusTestFixture.newListener();
+            EventListener listener2 = EventBusTestFixture.newListener();
+            Mono.from(eventBus().register(listener, EventBusTestFixture.KEY_1)).block();
+            Mono.from(eventBus().register(listener2, EventBusTestFixture.KEY_2)).block();
+
+            eventBus().dispatch(EventBusTestFixture.EVENT, ImmutableSet.of(EventBusTestFixture.KEY_1)).block();
+
+            verify(listener, timeout(EventBusTestFixture.ONE_SECOND.toMillis()).times(1)).event(any());
+            verify(listener2, after(EventBusTestFixture.FIVE_HUNDRED_MS.toMillis()).never())
+                .event(any());
+        }
+
+        @Test
+        default void dispatchShouldNotifyAllListenersRegisteredOnAKey() throws Exception {
+            EventListener listener = EventBusTestFixture.newListener();
+            EventListener listener2 = EventBusTestFixture.newListener();
+            Mono.from(eventBus().register(listener, EventBusTestFixture.KEY_1)).block();
+            Mono.from(eventBus().register(listener2, EventBusTestFixture.KEY_1)).block();
+
+            eventBus().dispatch(EventBusTestFixture.EVENT, ImmutableSet.of(EventBusTestFixture.KEY_1)).block();
+
+            verify(listener, timeout(EventBusTestFixture.ONE_SECOND.toMillis()).times(1)).event(any());
+            verify(listener2, timeout(EventBusTestFixture.ONE_SECOND.toMillis()).times(1)).event(any());
+        }
+
+        @Test
+        default void registerShouldAllowDuplicatedRegistration() throws Exception {
+            EventListener listener = EventBusTestFixture.newListener();
+            Mono.from(eventBus().register(listener, EventBusTestFixture.KEY_1)).block();
+            Mono.from(eventBus().register(listener, EventBusTestFixture.KEY_1)).block();
+
+            eventBus().dispatch(EventBusTestFixture.EVENT, ImmutableSet.of(EventBusTestFixture.KEY_1)).block();
+
+            verify(listener, timeout(EventBusTestFixture.ONE_SECOND.toMillis()).times(1)).event(any());
+        }
+
+        @Test
+        default void unregisterShouldRemoveDoubleRegisteredListener() throws Exception {
+            EventListener listener = EventBusTestFixture.newListener();
+            Mono.from(eventBus().register(listener, EventBusTestFixture.KEY_1)).block();
+            Mono.from(eventBus().register(listener, EventBusTestFixture.KEY_1)).block().unregister();
+
+            eventBus().dispatch(EventBusTestFixture.EVENT, ImmutableSet.of(EventBusTestFixture.KEY_1)).block();
+
+            verify(listener, after(EventBusTestFixture.FIVE_HUNDRED_MS.toMillis()).never())
+                .event(any());
+        }
+
+        @Test
+        default void registerShouldNotDispatchPastEvents() throws Exception {
+            EventListener listener = EventBusTestFixture.newListener();
+
+            eventBus().dispatch(EventBusTestFixture.EVENT, ImmutableSet.of(EventBusTestFixture.KEY_1)).block();
+
+            Mono.from(eventBus().register(listener, EventBusTestFixture.KEY_1)).block();
+
+            verify(listener, after(EventBusTestFixture.FIVE_HUNDRED_MS.toMillis()).never())
+                .event(any());
+        }
+
+        @Test
+        default void callingAllUnregisterMethodShouldUnregisterTheListener() throws Exception {
+            EventListener listener = EventBusTestFixture.newListener();
+            Registration registration = Mono.from(eventBus().register(listener, EventBusTestFixture.KEY_1)).block();
+            Mono.from(eventBus().register(listener, EventBusTestFixture.KEY_1)).block().unregister();
+            registration.unregister();
+
+            eventBus().dispatch(EventBusTestFixture.EVENT, ImmutableSet.of(EventBusTestFixture.KEY_1)).block();
+
+            verify(listener, after(EventBusTestFixture.FIVE_HUNDRED_MS.toMillis()).never())
+                .event(any());
+        }
+
+        @Test
+        default void unregisterShouldHaveNotNotifyWhenCalledOnDifferentKeys() throws Exception {
+            EventListener listener = EventBusTestFixture.newListener();
+            Mono.from(eventBus().register(listener, EventBusTestFixture.KEY_1)).block();
+            Mono.from(eventBus().register(listener, EventBusTestFixture.KEY_2)).block().unregister();
+
+            eventBus().dispatch(EventBusTestFixture.EVENT, ImmutableSet.of(EventBusTestFixture.KEY_1)).block();
+
+            verify(listener, timeout(EventBusTestFixture.ONE_SECOND.toMillis()).times(1)).event(any());
+        }
+
+        @Test
+        default void unregisterShouldBeIdempotentForKeyRegistrations() {
+            EventListener listener = EventBusTestFixture.newListener();
+
+            Registration registration = Mono.from(eventBus().register(listener, EventBusTestFixture.KEY_1)).block();
+            registration.unregister();
+
+            assertThatCode(registration::unregister)
+                .doesNotThrowAnyException();
+        }
+
+        @Test
+        default void dispatchShouldAcceptSeveralKeys() throws Exception {
+            EventListener listener = EventBusTestFixture.newListener();
+            Mono.from(eventBus().register(listener, EventBusTestFixture.KEY_1)).block();
+
+            eventBus().dispatch(EventBusTestFixture.EVENT, ImmutableSet.of(EventBusTestFixture.KEY_1, EventBusTestFixture.KEY_2)).block();
+
+            verify(listener, timeout(EventBusTestFixture.ONE_SECOND.toMillis()).times(1)).event(any());
+        }
+
+        @Test
+        default void dispatchShouldCallListenerOnceWhenSeveralKeysMatching() throws Exception {
+            EventListener listener = EventBusTestFixture.newListener();
+            Mono.from(eventBus().register(listener, EventBusTestFixture.KEY_1)).block();
+            Mono.from(eventBus().register(listener, EventBusTestFixture.KEY_2)).block();
+
+            eventBus().dispatch(EventBusTestFixture.EVENT, ImmutableSet.of(EventBusTestFixture.KEY_1, EventBusTestFixture.KEY_2)).block();
+
+            verify(listener, timeout(EventBusTestFixture.ONE_SECOND.toMillis()).times(1)).event(any());
+        }
+
+        @Test
+        default void dispatchShouldNotNotifyUnregisteredListener() throws Exception {
+            EventListener listener = EventBusTestFixture.newListener();
+            Mono.from(eventBus().register(listener, EventBusTestFixture.KEY_1)).block().unregister();
+
+            eventBus().dispatch(EventBusTestFixture.EVENT, ImmutableSet.of(EventBusTestFixture.KEY_1)).block();
+
+            verify(listener, after(EventBusTestFixture.FIVE_HUNDRED_MS.toMillis()).never())
+                .event(any());
+        }
+
+
+        @Test
+        default void dispatchShouldNotifyAsynchronousListener() throws Exception {
+            EventListener listener = EventBusTestFixture.newListener();
+            when(listener.getExecutionMode()).thenReturn(EventListener.ExecutionMode.ASYNCHRONOUS);
+            Mono.from(eventBus().register(listener, EventBusTestFixture.KEY_1)).block();
+
+            eventBus().dispatch(EventBusTestFixture.EVENT, EventBusTestFixture.KEY_1).block();
+
+            verify(listener, after(EventBusTestFixture.FIVE_HUNDRED_MS.toMillis())).event(EventBusTestFixture.EVENT);
+        }
+
+        @Test
+        default void dispatchShouldNotBlockAsynchronousListener() throws Exception {
+            EventListener listener = EventBusTestFixture.newListener();
+            when(listener.getExecutionMode()).thenReturn(EventListener.ExecutionMode.ASYNCHRONOUS);
+            CountDownLatch latch = new CountDownLatch(1);
+            doAnswer(invocation -> {
+                latch.await();
+                return null;
+            }).when(listener).event(EventBusTestFixture.EVENT);
+
+            assertTimeout(Duration.ofSeconds(2),
+                () -> {
+                    eventBus().dispatch(EventBusTestFixture.EVENT, EventBusTestFixture.NO_KEYS).block();
+                    latch.countDown();
+                });
+        }
+
+        @Test
+        default void failingRegisteredListenersShouldNotAbortRegisteredDelivery() {
+            EventBusTestFixture.EventListenerCountingSuccessfulExecution listener = new EventBusTestFixture.EventMatcherThrowingListener(ImmutableSet.of(EventBusTestFixture.EVENT));
+            Mono.from(eventBus().register(listener, EventBusTestFixture.KEY_1)).block();
+
+            eventBus().dispatch(EventBusTestFixture.EVENT, EventBusTestFixture.KEY_1).block();
+            eventBus().dispatch(EventBusTestFixture.EVENT_2, EventBusTestFixture.KEY_1).block();
+
+            getSpeedProfile().shortWaitCondition()
+                .untilAsserted(() -> assertThat(listener.numberOfEventCalls()).isEqualTo(1));
+        }
+
+        @Test
+        default void allRegisteredListenersShouldBeExecutedWhenARegisteredListenerFails() throws Exception {
+            EventListener listener = EventBusTestFixture.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, EventBusTestFixture.KEY_1)).block();
+            Mono.from(eventBus().register(listener, EventBusTestFixture.KEY_1)).block();
+
+            eventBus().dispatch(EventBusTestFixture.EVENT, ImmutableSet.of(EventBusTestFixture.KEY_1)).block();
+
+            verify(listener, timeout(EventBusTestFixture.ONE_SECOND.toMillis()).times(1)).event(any());
+        }
+    }
+
+    interface MultipleEventBusKeyContract extends MultipleEventBusContract {
+
+        @Test
+        default void crossEventBusRegistrationShouldBeAllowed() throws Exception {
+            EventListener mailboxListener = EventBusTestFixture.newListener();
+
+            Mono.from(eventBus().register(mailboxListener, EventBusTestFixture.KEY_1)).block();
+
+            eventBus2().dispatch(EventBusTestFixture.EVENT, EventBusTestFixture.KEY_1).block();
+
+            verify(mailboxListener, timeout(EventBusTestFixture.ONE_SECOND.toMillis()).times(1)).event(any());
+        }
+
+        @Test
+        default void unregisteredDistantListenersShouldNotBeNotified() throws Exception {
+            EventListener eventListener = EventBusTestFixture.newListener();
+
+            Mono.from(eventBus().register(eventListener, EventBusTestFixture.KEY_1)).block().unregister();
+
+            eventBus2().dispatch(EventBusTestFixture.EVENT, ImmutableSet.of(EventBusTestFixture.KEY_1)).block();
+
+            verify(eventListener, after(EventBusTestFixture.FIVE_HUNDRED_MS.toMillis()).never())
+                .event(any());
+        }
+
+        @Test
+        default void allRegisteredListenersShouldBeDispatched() throws Exception {
+            EventListener mailboxListener1 = EventBusTestFixture.newListener();
+            EventListener mailboxListener2 = EventBusTestFixture.newListener();
+
+            Mono.from(eventBus().register(mailboxListener1, EventBusTestFixture.KEY_1)).block();
+            Mono.from(eventBus2().register(mailboxListener2, EventBusTestFixture.KEY_1)).block();
+
+            eventBus2().dispatch(EventBusTestFixture.EVENT, EventBusTestFixture.KEY_1).block();
+
+            verify(mailboxListener1, timeout(EventBusTestFixture.ONE_SECOND.toMillis()).times(1)).event(any());
+            verify(mailboxListener2, timeout(EventBusTestFixture.ONE_SECOND.toMillis()).times(1)).event(any());
+        }
+
+        @Test
+        default void registerShouldNotDispatchPastEventsInDistributedContext() throws Exception {
+            EventListener listener = EventBusTestFixture.newListener();
+
+            eventBus2().dispatch(EventBusTestFixture.EVENT, ImmutableSet.of(EventBusTestFixture.KEY_1)).block();
+
+            Mono.from(eventBus().register(listener, EventBusTestFixture.KEY_1)).block();
+
+            verify(listener, after(EventBusTestFixture.FIVE_HUNDRED_MS.toMillis()).never())
+                .event(any());
+        }
+
+        @Test
+        default void localDispatchedListenersShouldBeDispatchedWithoutDelay() throws Exception {
+            EventListener mailboxListener1 = EventBusTestFixture.newListener();
+            EventListener mailboxListener2 = EventBusTestFixture.newListener();
+
+            Mono.from(eventBus().register(mailboxListener1, EventBusTestFixture.KEY_1)).block();
+            Mono.from(eventBus2().register(mailboxListener2, EventBusTestFixture.KEY_1)).block();
+
+            eventBus2().dispatch(EventBusTestFixture.EVENT, EventBusTestFixture.KEY_1).block();
+
+            verify(mailboxListener2, times(1)).event(any());
+            verify(mailboxListener1, timeout(EventBusTestFixture.ONE_SECOND.toMillis()).times(1)).event(any());
+        }
+
+    }
+}
diff --git a/mailbox/api/src/test/java/org/apache/james/mailbox/events/InsertionIdTest.java b/mailbox/api/src/test/java/org/apache/james/events/MailboxIdRegistrationKeyTest.java
similarity index 59%
copy from mailbox/api/src/test/java/org/apache/james/mailbox/events/InsertionIdTest.java
copy to mailbox/api/src/test/java/org/apache/james/events/MailboxIdRegistrationKeyTest.java
index f8a1e0e..0fb1de2 100644
--- a/mailbox/api/src/test/java/org/apache/james/mailbox/events/InsertionIdTest.java
+++ b/mailbox/api/src/test/java/org/apache/james/events/MailboxIdRegistrationKeyTest.java
@@ -17,40 +17,44 @@
  * under the License.                                           *
  ****************************************************************/
 
-package org.apache.james.mailbox.events;
+package org.apache.james.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.mailbox.model.TestId;
 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");
+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 eventIdShouldMatchBeanContract() {
-        EqualsVerifier.forClass(EventDeadLetters.InsertionId.class).verify();
+    void shouldRespectBeanContract() {
+        EqualsVerifier.forClass(MailboxIdRegistrationKey.class)
+            .verify();
     }
 
     @Test
-    void ofShouldDeserializeUUIDs() {
-        assertThat(EventDeadLetters.InsertionId.of(UUID_1.toString()))
-            .isEqualTo(EventDeadLetters.InsertionId.of(UUID_1));
+    void asStringShouldReturnSerializedMailboxId() {
+        assertThat(MAILBOX_ID_REGISTRATION_KEY.asString())
+            .isEqualTo(ID);
     }
 
     @Test
-    void ofStringShouldThrowOnNullValue() {
-        assertThatThrownBy(() -> EventDeadLetters.InsertionId.of((String) null))
-            .isInstanceOf(NullPointerException.class);
+    void fromStringShouldReturnCorrespondingRegistrationKey() {
+        assertThat(FACTORY.fromString(ID))
+            .isEqualTo(MAILBOX_ID_REGISTRATION_KEY);
     }
 
     @Test
-    void ofUuidShouldThrowOnNullValue() {
-        assertThatThrownBy(() -> EventDeadLetters.InsertionId.of((UUID) null))
-            .isInstanceOf(NullPointerException.class);
+    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/events/RetryBackoffConfigurationTest.java b/mailbox/api/src/test/java/org/apache/james/events/RetryBackoffConfigurationTest.java
new file mode 100644
index 0000000..5718e63
--- /dev/null
+++ b/mailbox/api/src/test/java/org/apache/james/events/RetryBackoffConfigurationTest.java
@@ -0,0 +1,141 @@
+/****************************************************************
+ * 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.events;
+
+import static org.apache.james.events.RetryBackoffConfiguration.DEFAULT_FIRST_BACKOFF;
+import static org.apache.james.events.RetryBackoffConfiguration.DEFAULT_JITTER_FACTOR;
+import static org.apache.james.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/EventTest.java b/mailbox/api/src/test/java/org/apache/james/mailbox/EventTest.java
index 6c1c687..c25f7df 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
@@ -27,8 +27,8 @@ import java.util.UUID;
 import javax.mail.Flags;
 
 import org.apache.james.core.Username;
-import org.apache.james.mailbox.events.Event;
-import org.apache.james.mailbox.events.MailboxListener;
+import org.apache.james.events.Event;
+import org.apache.james.mailbox.events.MailboxEvents.Added;
 import org.apache.james.mailbox.model.MailboxPath;
 import org.apache.james.mailbox.model.MessageMetaData;
 import org.apache.james.mailbox.model.TestId;
@@ -56,7 +56,7 @@ class EventTest {
 
     @Test
     void getMessageIdsShouldReturnEmptyWhenAddedEmpty() {
-        MailboxListener.Added added = new MailboxListener.Added(MailboxSession.SessionId.of(36), BOB, MailboxPath.inbox(BOB), TestId.of(48), ImmutableSortedMap.of(), Event.EventId.of(UUID_1));
+        Added added = new Added(MailboxSession.SessionId.of(36), BOB, MailboxPath.inbox(BOB), TestId.of(48), ImmutableSortedMap.of(), Event.EventId.of(UUID_1));
 
         assertThat(added.getMessageIds()).isEmpty();
     }
@@ -70,7 +70,7 @@ class EventTest {
         MessageMetaData metaData1 = new MessageMetaData(uid1, ModSeq.of(85), new Flags(), 36, new Date(), messageId1);
         MessageMetaData metaData2 = new MessageMetaData(uid2, ModSeq.of(85), new Flags(), 36, new Date(), messageId2);
 
-        MailboxListener.Added added = new MailboxListener.Added(MailboxSession.SessionId.of(36), BOB, MailboxPath.inbox(BOB), TestId.of(48),
+        Added added = new Added(MailboxSession.SessionId.of(36), BOB, MailboxPath.inbox(BOB), TestId.of(48),
             ImmutableSortedMap.of(
                 uid1, metaData1,
                 uid2, metaData2),
@@ -87,7 +87,7 @@ class EventTest {
         MessageMetaData metaData1 = new MessageMetaData(uid1, ModSeq.of(85), new Flags(), 36, new Date(), messageId);
         MessageMetaData metaData2 = new MessageMetaData(uid2, ModSeq.of(85), new Flags(), 36, new Date(), messageId);
 
-        MailboxListener.Added added = new MailboxListener.Added(MailboxSession.SessionId.of(36), BOB, MailboxPath.inbox(BOB), TestId.of(48),
+        Added added = new Added(MailboxSession.SessionId.of(36), BOB, MailboxPath.inbox(BOB), TestId.of(48),
             ImmutableSortedMap.of(
                 uid1, metaData1,
                 uid2, metaData2),
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 646af57..13fa417 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
@@ -33,9 +33,16 @@ 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.acl.ACLDiff;
-import org.apache.james.mailbox.events.Event;
-import org.apache.james.mailbox.events.MailboxListener;
+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;
@@ -69,42 +76,42 @@ class MailboxListenerTest {
 
     @Test
     void mailboxAddedShouldMatchBeanContract() {
-        EqualsVerifier.forClass(MailboxListener.MailboxAdded.class).verify();
+        EqualsVerifier.forClass(MailboxAdded.class).verify();
     }
 
     @Test
     void mailboxRenamedShouldMatchBeanContract() {
-        EqualsVerifier.forClass(MailboxListener.MailboxRenamed.class).verify();
+        EqualsVerifier.forClass(MailboxRenamed.class).verify();
     }
 
     @Test
     void mailboxDeletionShouldMatchBeanContract() {
-        EqualsVerifier.forClass(MailboxListener.MailboxDeletion.class).verify();
+        EqualsVerifier.forClass(MailboxDeletion.class).verify();
     }
 
     @Test
     void mailboxACLUpdatedShouldMatchBeanContract() {
-        EqualsVerifier.forClass(MailboxListener.MailboxACLUpdated.class).verify();
+        EqualsVerifier.forClass(MailboxACLUpdated.class).verify();
     }
 
     @Test
     void addedShouldMatchBeanContract() {
-        EqualsVerifier.forClass(MailboxListener.Added.class).verify();
+        EqualsVerifier.forClass(Added.class).verify();
     }
 
     @Test
     void expungedShouldMatchBeanContract() {
-        EqualsVerifier.forClass(MailboxListener.Expunged.class).verify();
+        EqualsVerifier.forClass(Expunged.class).verify();
     }
 
     @Test
     void flagUpdatedShouldMatchBeanContract() {
-        EqualsVerifier.forClass(MailboxListener.FlagsUpdated.class).verify();
+        EqualsVerifier.forClass(FlagsUpdated.class).verify();
     }
 
     @Test
     void renameWithSameNameShouldBeNoop() {
-        MailboxListener.MailboxRenamed mailboxRenamed = new MailboxListener.MailboxRenamed(SESSION_ID, BOB, PATH, MAILBOX_ID, PATH,
+        MailboxRenamed mailboxRenamed = new MailboxRenamed(SESSION_ID, BOB, PATH, MAILBOX_ID, PATH,
             Event.EventId.random());
 
         assertThat(mailboxRenamed.isNoop()).isTrue();
@@ -112,7 +119,7 @@ class MailboxListenerTest {
 
     @Test
     void renameWithDifferentNameShouldNotBeNoop() {
-        MailboxListener.MailboxRenamed mailboxRenamed = new MailboxListener.MailboxRenamed(SESSION_ID, BOB, PATH, MAILBOX_ID, OTHER_PATH,
+        MailboxRenamed mailboxRenamed = new MailboxRenamed(SESSION_ID, BOB, PATH, MAILBOX_ID, OTHER_PATH,
             Event.EventId.random());
 
         assertThat(mailboxRenamed.isNoop()).isFalse();
@@ -120,7 +127,7 @@ class MailboxListenerTest {
 
     @Test
     void addedShouldNotBeNoop() {
-        MailboxListener.MailboxAdded added = new MailboxListener.MailboxAdded(SESSION_ID, BOB, PATH, MAILBOX_ID,
+        MailboxAdded added = new MailboxAdded(SESSION_ID, BOB, PATH, MAILBOX_ID,
             Event.EventId.random());
 
         assertThat(added.isNoop()).isFalse();
@@ -128,7 +135,7 @@ class MailboxListenerTest {
 
     @Test
     void removedShouldNotBeNoop() {
-        MailboxListener.MailboxDeletion deletion = new MailboxListener.MailboxDeletion(SESSION_ID, BOB, PATH, new MailboxACL(), QUOTA_ROOT,
+        MailboxDeletion deletion = new MailboxDeletion(SESSION_ID, BOB, PATH, new MailboxACL(), QUOTA_ROOT,
             QUOTA_COUNT, QUOTA_SIZE, MAILBOX_ID, Event.EventId.random());
 
         assertThat(deletion.isNoop()).isFalse();
@@ -136,7 +143,7 @@ class MailboxListenerTest {
 
     @Test
     void aclDiffWithSameAclShouldBeNoop() {
-        MailboxListener.MailboxACLUpdated aclUpdated = new MailboxListener.MailboxACLUpdated(SESSION_ID, BOB, PATH, ACLDiff.computeDiff(ACL_1, ACL_1), MAILBOX_ID,
+        MailboxACLUpdated aclUpdated = new MailboxACLUpdated(SESSION_ID, BOB, PATH, ACLDiff.computeDiff(ACL_1, ACL_1), MAILBOX_ID,
             Event.EventId.random());
 
         assertThat(aclUpdated.isNoop()).isTrue();
@@ -144,7 +151,7 @@ class MailboxListenerTest {
 
     @Test
     void aclDiffWithDifferentAclShouldNotBeNoop() {
-        MailboxListener.MailboxACLUpdated aclUpdated = new MailboxListener.MailboxACLUpdated(SESSION_ID, BOB, PATH, ACLDiff.computeDiff(ACL_1, ACL_2), MAILBOX_ID,
+        MailboxACLUpdated aclUpdated = new MailboxACLUpdated(SESSION_ID, BOB, PATH, ACLDiff.computeDiff(ACL_1, ACL_2), MAILBOX_ID,
             Event.EventId.random());
 
         assertThat(aclUpdated.isNoop()).isFalse();
@@ -152,7 +159,7 @@ class MailboxListenerTest {
 
     @Test
     void addedShouldBeNoopWhenEmpty() {
-        MailboxListener.Added added = new MailboxListener.Added(SESSION_ID, BOB, PATH, MAILBOX_ID, ImmutableSortedMap.of(),
+        Added added = new Added(SESSION_ID, BOB, PATH, MAILBOX_ID, ImmutableSortedMap.of(),
             Event.EventId.random());
 
         assertThat(added.isNoop()).isTrue();
@@ -160,7 +167,7 @@ class MailboxListenerTest {
 
     @Test
     void addedShouldNotBeNoopWhenNotEmpty() {
-        MailboxListener.Added added = new MailboxListener.Added(SESSION_ID, BOB, PATH, MAILBOX_ID, ImmutableSortedMap.of(UID, META_DATA),
+        Added added = new Added(SESSION_ID, BOB, PATH, MAILBOX_ID, ImmutableSortedMap.of(UID, META_DATA),
             Event.EventId.random());
 
         assertThat(added.isNoop()).isFalse();
@@ -168,7 +175,7 @@ class MailboxListenerTest {
 
     @Test
     void expungedShouldBeNoopWhenEmpty() {
-        MailboxListener.Expunged expunged = new MailboxListener.Expunged(SESSION_ID, BOB, PATH, MAILBOX_ID, ImmutableSortedMap.of(),
+        Expunged expunged = new Expunged(SESSION_ID, BOB, PATH, MAILBOX_ID, ImmutableSortedMap.of(),
             Event.EventId.random());
 
         assertThat(expunged.isNoop()).isTrue();
@@ -176,7 +183,7 @@ class MailboxListenerTest {
 
     @Test
     void expungedShouldNotBeNoopWhenNotEmpty() {
-        MailboxListener.Expunged expunged = new MailboxListener.Expunged(SESSION_ID, BOB, PATH, MAILBOX_ID, ImmutableSortedMap.of(UID, META_DATA),
+        Expunged expunged = new Expunged(SESSION_ID, BOB, PATH, MAILBOX_ID, ImmutableSortedMap.of(UID, META_DATA),
             Event.EventId.random());
 
         assertThat(expunged.isNoop()).isFalse();
@@ -184,14 +191,14 @@ class MailboxListenerTest {
 
     @Test
     void flagsUpdatedShouldBeNoopWhenEmpty() {
-        MailboxListener.FlagsUpdated flagsUpdated = new MailboxListener.FlagsUpdated(SESSION_ID, BOB, PATH, MAILBOX_ID, ImmutableList.of(), Event.EventId.random());
+        FlagsUpdated flagsUpdated = new FlagsUpdated(SESSION_ID, BOB, PATH, MAILBOX_ID, ImmutableList.of(), Event.EventId.random());
 
         assertThat(flagsUpdated.isNoop()).isTrue();
     }
 
     @Test
     void flagsUpdatedShouldNotBeNoopWhenNotEmpty() {
-        MailboxListener.FlagsUpdated flagsUpdated = new MailboxListener.FlagsUpdated(SESSION_ID, BOB, PATH, MAILBOX_ID,
+        FlagsUpdated flagsUpdated = new FlagsUpdated(SESSION_ID, BOB, PATH, MAILBOX_ID,
             ImmutableList.of(UpdatedFlags.builder()
                 .uid(UID)
                 .modSeq(ModSeq.of(45))
@@ -205,7 +212,7 @@ class MailboxListenerTest {
 
     @Test
     void quotaUsageUpdatedEventShouldNotBeNoop() {
-        MailboxListener.QuotaUsageUpdatedEvent event = new MailboxListener.QuotaUsageUpdatedEvent(Event.EventId.random(), BOB, QUOTA_ROOT,
+        QuotaUsageUpdatedEvent event = new QuotaUsageUpdatedEvent(Event.EventId.random(), BOB, QUOTA_ROOT,
             Quota.<QuotaCountLimit, QuotaCountUsage>builder()
                 .used(QUOTA_COUNT)
                 .computedLimit(QuotaCountLimit.unlimited())
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 192140f..d8667e2 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
@@ -32,9 +32,9 @@ import java.util.concurrent.TimeUnit;
 import java.util.concurrent.atomic.AtomicBoolean;
 
 import org.apache.james.core.Username;
-import org.apache.james.mailbox.events.EventBus;
+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.mailbox.events.MailboxListener;
 import org.apache.james.mailbox.exception.MailboxException;
 import org.apache.james.mailbox.model.ComposedMessageId;
 import org.apache.james.mailbox.model.MailboxId;
@@ -69,7 +69,7 @@ public interface MailboxManagerStressContract<T extends MailboxManager> {
         MailboxId mailboxId = getManager().createMailbox(path, session).get();
         Mono.from(retrieveEventBus()
             .register(event -> {
-                MessageUid u = ((MailboxListener.Added) event).getUids().iterator().next();
+                MessageUid u = ((Added) event).getUids().iterator().next();
                 uList.add(u);
             }, new MailboxIdRegistrationKey(mailboxId)))
             .block();
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 c9a5f9f..7a23c69 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
@@ -46,12 +46,17 @@ 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.EventBus;
 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.EventBus;
+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.MailboxListener;
 import org.apache.james.mailbox.events.MessageMoveEvent;
 import org.apache.james.mailbox.exception.AnnotationException;
 import org.apache.james.mailbox.exception.HasEmptyMailboxNameInHierarchyException;
@@ -731,9 +736,9 @@ public abstract class MailboxManagerTest<T extends MailboxManager> {
             mailboxManager.deleteMailbox(inbox, session);
 
             assertThat(listener.getEvents())
-                .filteredOn(event -> event instanceof MailboxListener.MailboxDeletion)
+                .filteredOn(event -> event instanceof MailboxDeletion)
                 .hasSize(1)
-                .extracting(event -> (MailboxListener.MailboxDeletion) event)
+                .extracting(event -> (MailboxDeletion) event)
                 .element(0)
                 .satisfies(event -> assertThat(event.getMailboxId()).isEqualTo(inboxId))
                 .satisfies(event -> assertThat(event.getQuotaRoot()).isEqualTo(quotaRoot))
@@ -749,9 +754,9 @@ public abstract class MailboxManagerTest<T extends MailboxManager> {
             mailboxManager.deleteMailbox(inboxId, session);
 
             assertThat(listener.getEvents())
-                .filteredOn(event -> event instanceof MailboxListener.MailboxDeletion)
+                .filteredOn(event -> event instanceof MailboxDeletion)
                 .hasSize(1)
-                .extracting(event -> (MailboxListener.MailboxDeletion) event)
+                .extracting(event -> (MailboxDeletion) event)
                 .element(0)
                 .satisfies(event -> assertThat(event.getMailboxId()).isEqualTo(inboxId))
                 .satisfies(event -> assertThat(event.getQuotaRoot()).isEqualTo(quotaRoot))
@@ -766,9 +771,9 @@ public abstract class MailboxManagerTest<T extends MailboxManager> {
             Optional<MailboxId> newId = mailboxManager.createMailbox(newPath, session);
 
             assertThat(listener.getEvents())
-                .filteredOn(event -> event instanceof MailboxListener.MailboxAdded)
+                .filteredOn(event -> event instanceof MailboxAdded)
                 .hasSize(1)
-                .extracting(event -> (MailboxListener.MailboxAdded) event)
+                .extracting(event -> (MailboxAdded) event)
                 .element(0)
                 .satisfies(event -> assertThat(event.getMailboxId()).isEqualTo(newId.get()));
         }
@@ -782,9 +787,9 @@ public abstract class MailboxManagerTest<T extends MailboxManager> {
                     .build(message), session);
 
             assertThat(listener.getEvents())
-                .filteredOn(event -> event instanceof MailboxListener.QuotaUsageUpdatedEvent)
+                .filteredOn(event -> event instanceof QuotaUsageUpdatedEvent)
                 .hasSize(1)
-                .extracting(event -> (MailboxListener.QuotaUsageUpdatedEvent) event)
+                .extracting(event -> (QuotaUsageUpdatedEvent) event)
                 .element(0)
                 .satisfies(event -> assertThat(event.getQuotaRoot()).isEqualTo(quotaRoot))
                 .satisfies(event -> assertThat(event.getSizeQuota()).isEqualTo(Quota.<QuotaSizeLimit, QuotaSizeUsage>builder()
@@ -804,9 +809,9 @@ public abstract class MailboxManagerTest<T extends MailboxManager> {
                     .build(message), session);
 
             assertThat(listener.getEvents())
-                .filteredOn(event -> event instanceof MailboxListener.Added)
+                .filteredOn(event -> event instanceof Added)
                 .hasSize(1)
-                .extracting(event -> (MailboxListener.Added) event)
+                .extracting(event -> (Added) event)
                 .element(0)
                 .satisfies(event -> assertThat(event.getMailboxId()).isEqualTo(inboxId))
                 .satisfies(event -> assertThat(event.getUids()).hasSize(1));
@@ -821,9 +826,9 @@ public abstract class MailboxManagerTest<T extends MailboxManager> {
             inboxManager.expunge(MessageRange.all(), session);
 
             assertThat(listener.getEvents())
-                .filteredOn(event -> event instanceof MailboxListener.Expunged)
+                .filteredOn(event -> event instanceof Expunged)
                 .hasSize(1)
-                .extracting(event -> (MailboxListener.Expunged) event)
+                .extracting(event -> (Expunged) event)
                 .element(0)
                 .satisfies(event -> assertThat(event.getMailboxId()).isEqualTo(inboxId))
                 .satisfies(event -> assertThat(event.getUids()).hasSize(1));
@@ -838,9 +843,9 @@ public abstract class MailboxManagerTest<T extends MailboxManager> {
             inboxManager.delete(ImmutableList.of(messageId.getUid()), session);
 
             assertThat(listener.getEvents())
-                .filteredOn(event -> event instanceof MailboxListener.Expunged)
+                .filteredOn(event -> event instanceof Expunged)
                 .hasSize(1)
-                .extracting(event -> (MailboxListener.Expunged) event)
+                .extracting(event -> (Expunged) event)
                 .element(0)
                 .satisfies(event -> assertThat(event.getMailboxId()).isEqualTo(inboxId))
                 .satisfies(event -> assertThat(event.getUids()).hasSize(1));
@@ -854,9 +859,9 @@ public abstract class MailboxManagerTest<T extends MailboxManager> {
             inboxManager.setFlags(new Flags(Flags.Flag.FLAGGED), MessageManager.FlagsUpdateMode.ADD, MessageRange.all(), session);
 
             assertThat(listener.getEvents())
-                .filteredOn(event -> event instanceof MailboxListener.FlagsUpdated)
+                .filteredOn(event -> event instanceof FlagsUpdated)
                 .hasSize(1)
-                .extracting(event -> (MailboxListener.FlagsUpdated) event)
+                .extracting(event -> (FlagsUpdated) event)
                 .element(0)
                 .satisfies(event -> assertThat(event.getMailboxId()).isEqualTo(inboxId))
                 .satisfies(event -> assertThat(event.getUids()).hasSize(1));
@@ -872,9 +877,9 @@ public abstract class MailboxManagerTest<T extends MailboxManager> {
             mailboxManager.moveMessages(MessageRange.all(), inbox, newPath, session);
 
             assertThat(listener.getEvents())
-                .filteredOn(event -> event instanceof MailboxListener.Added)
+                .filteredOn(event -> event instanceof Added)
                 .hasSize(1)
-                .extracting(event -> (MailboxListener.Added) event)
+                .extracting(event -> (Added) event)
                 .element(0)
                 .satisfies(event -> assertThat(event.getMailboxId()).isEqualTo(targetMailboxId.get()))
                 .satisfies(event -> assertThat(event.getUids()).hasSize(1));
@@ -890,9 +895,9 @@ public abstract class MailboxManagerTest<T extends MailboxManager> {
             mailboxManager.moveMessages(MessageRange.all(), inbox, newPath, session);
 
             assertThat(listener.getEvents())
-                .filteredOn(event -> event instanceof MailboxListener.Expunged)
+                .filteredOn(event -> event instanceof Expunged)
                 .hasSize(1)
-                .extracting(event -> (MailboxListener.Expunged) event)
+                .extracting(event -> (Expunged) event)
                 .element(0)
                 .satisfies(event -> assertThat(event.getMailboxId()).isEqualTo(inboxId))
                 .satisfies(event -> assertThat(event.getUids()).hasSize(1));
@@ -907,9 +912,9 @@ public abstract class MailboxManagerTest<T extends MailboxManager> {
             mailboxManager.copyMessages(MessageRange.all(), inbox, newPath, session);
 
             assertThat(listener.getEvents())
-                .filteredOn(event -> event instanceof MailboxListener.Added)
+                .filteredOn(event -> event instanceof Added)
                 .hasSize(1)
-                .extracting(event -> (MailboxListener.Added) event)
+                .extracting(event -> (Added) event)
                 .element(0)
                 .satisfies(event -> assertThat(event.getMailboxId()).isEqualTo(targetMailboxId.get()))
                 .satisfies(event -> assertThat(event.getUids()).hasSize(1));
@@ -993,7 +998,7 @@ public abstract class MailboxManagerTest<T extends MailboxManager> {
             mailboxManager.copyMessages(MessageRange.all(), inbox, newPath, session);
 
             assertThat(listener.getEvents())
-                .filteredOn(event -> event instanceof MailboxListener.Expunged)
+                .filteredOn(event -> event instanceof Expunged)
                 .isEmpty();
         }
     }
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
index 18bcb18..226f1bb 100644
--- 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
@@ -37,6 +37,9 @@ 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;
@@ -48,7 +51,7 @@ import reactor.core.publisher.Mono;
 
 interface ErrorHandlingContract extends EventBusContract {
 
-    class ThrowingListener implements MailboxListener {
+    class ThrowingListener implements EventListener {
         private final List<Instant> timeElapsed;
 
         private ThrowingListener() {
@@ -200,7 +203,7 @@ interface ErrorHandlingContract extends EventBusContract {
     default void retryingListenerCallingDispatchShouldNotFail() {
         AtomicBoolean firstExecution = new AtomicBoolean(true);
         AtomicBoolean successfulRetry = new AtomicBoolean(false);
-        MailboxListener listener = event -> {
+        EventListener listener = event -> {
             if (event.getEventId().equals(EVENT_ID)) {
                 if (firstExecution.get()) {
                     firstExecution.set(false);
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
index 1aa3c2e..8b73023 100644
--- 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
@@ -32,6 +32,8 @@ 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;
@@ -52,13 +54,13 @@ public interface EventBusConcurrentTestContract {
 
     Set<RegistrationKey> ALL_KEYS = ImmutableSet.of(KEY_1, KEY_2, KEY_3);
 
-    static EventBusTestFixture.MailboxListenerCountingSuccessfulExecution newCountingListener() {
-        return new EventBusTestFixture.MailboxListenerCountingSuccessfulExecution();
+    static EventBusTestFixture.EventListenerCountingSuccessfulExecution newCountingListener() {
+        return new EventBusTestFixture.EventListenerCountingSuccessfulExecution();
     }
 
-    static int totalEventsReceived(ImmutableList<EventBusTestFixture.MailboxListenerCountingSuccessfulExecution> allListeners) {
+    static int totalEventsReceived(ImmutableList<EventBusTestFixture.EventListenerCountingSuccessfulExecution> allListeners) {
         return allListeners.stream()
-            .mapToInt(EventBusTestFixture.MailboxListenerCountingSuccessfulExecution::numberOfEventCalls)
+            .mapToInt(EventBusTestFixture.EventListenerCountingSuccessfulExecution::numberOfEventCalls)
             .sum();
     }
 
@@ -66,9 +68,9 @@ public interface EventBusConcurrentTestContract {
 
         @Test
         default void concurrentDispatchGroupShouldDeliverAllEventsToListenersWithSingleEventBus() throws Exception {
-            EventBusTestFixture.MailboxListenerCountingSuccessfulExecution countingListener1 = newCountingListener();
-            EventBusTestFixture.MailboxListenerCountingSuccessfulExecution countingListener2 = newCountingListener();
-            EventBusTestFixture.MailboxListenerCountingSuccessfulExecution countingListener3 = newCountingListener();
+            EventBusTestFixture.EventListenerCountingSuccessfulExecution countingListener1 = newCountingListener();
+            EventBusTestFixture.EventListenerCountingSuccessfulExecution countingListener2 = newCountingListener();
+            EventBusTestFixture.EventListenerCountingSuccessfulExecution countingListener3 = newCountingListener();
 
             eventBus().register(countingListener1, new EventBusTestFixture.GroupA());
             eventBus().register(countingListener2, new EventBusTestFixture.GroupB());
@@ -88,9 +90,9 @@ public interface EventBusConcurrentTestContract {
 
         @Test
         default void concurrentDispatchKeyShouldDeliverAllEventsToListenersWithSingleEventBus() throws Exception {
-            EventBusTestFixture.MailboxListenerCountingSuccessfulExecution countingListener1 = newCountingListener();
-            EventBusTestFixture.MailboxListenerCountingSuccessfulExecution countingListener2 = newCountingListener();
-            EventBusTestFixture.MailboxListenerCountingSuccessfulExecution countingListener3 = newCountingListener();
+            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();
@@ -111,9 +113,9 @@ public interface EventBusConcurrentTestContract {
 
         @Test
         default void concurrentDispatchShouldDeliverAllEventsToListenersWithSingleEventBus() throws Exception {
-            EventBusTestFixture.MailboxListenerCountingSuccessfulExecution countingListener1 = newCountingListener();
-            EventBusTestFixture.MailboxListenerCountingSuccessfulExecution countingListener2 = newCountingListener();
-            EventBusTestFixture.MailboxListenerCountingSuccessfulExecution countingListener3 = newCountingListener();
+            EventBusTestFixture.EventListenerCountingSuccessfulExecution countingListener1 = newCountingListener();
+            EventBusTestFixture.EventListenerCountingSuccessfulExecution countingListener2 = newCountingListener();
+            EventBusTestFixture.EventListenerCountingSuccessfulExecution countingListener3 = newCountingListener();
 
             eventBus().register(countingListener1, new EventBusTestFixture.GroupA());
             eventBus().register(countingListener2, new EventBusTestFixture.GroupB());
@@ -146,9 +148,9 @@ public interface EventBusConcurrentTestContract {
 
         @Test
         default void concurrentDispatchGroupShouldDeliverAllEventsToListenersWithMultipleEventBus() throws Exception {
-            EventBusTestFixture.MailboxListenerCountingSuccessfulExecution countingListener1 = newCountingListener();
-            EventBusTestFixture.MailboxListenerCountingSuccessfulExecution countingListener2 = newCountingListener();
-            EventBusTestFixture.MailboxListenerCountingSuccessfulExecution countingListener3 = newCountingListener();
+            EventBusTestFixture.EventListenerCountingSuccessfulExecution countingListener1 = newCountingListener();
+            EventBusTestFixture.EventListenerCountingSuccessfulExecution countingListener2 = newCountingListener();
+            EventBusTestFixture.EventListenerCountingSuccessfulExecution countingListener3 = newCountingListener();
 
             eventBus().register(countingListener1, new EventBusTestFixture.GroupA());
             eventBus().register(countingListener2, new EventBusTestFixture.GroupB());
@@ -173,9 +175,9 @@ public interface EventBusConcurrentTestContract {
 
         @Test
         default void concurrentDispatchKeyShouldDeliverAllEventsToListenersWithMultipleEventBus() throws Exception {
-            EventBusTestFixture.MailboxListenerCountingSuccessfulExecution countingListener1 = newCountingListener();
-            EventBusTestFixture.MailboxListenerCountingSuccessfulExecution countingListener2 = newCountingListener();
-            EventBusTestFixture.MailboxListenerCountingSuccessfulExecution countingListener3 = newCountingListener();
+            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();
@@ -201,9 +203,9 @@ public interface EventBusConcurrentTestContract {
 
         @Test
         default void concurrentDispatchShouldDeliverAllEventsToListenersWithMultipleEventBus() throws Exception {
-            EventBusTestFixture.MailboxListenerCountingSuccessfulExecution countingListener1 = newCountingListener();
-            EventBusTestFixture.MailboxListenerCountingSuccessfulExecution countingListener2 = newCountingListener();
-            EventBusTestFixture.MailboxListenerCountingSuccessfulExecution countingListener3 = newCountingListener();
+            EventBusTestFixture.EventListenerCountingSuccessfulExecution countingListener1 = newCountingListener();
+            EventBusTestFixture.EventListenerCountingSuccessfulExecution countingListener2 = newCountingListener();
+            EventBusTestFixture.EventListenerCountingSuccessfulExecution countingListener3 = newCountingListener();
 
             eventBus2().register(countingListener1, GROUP_A);
             eventBus2().register(countingListener2, new EventBusTestFixture.GroupB());
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
index 577697e..c94c5a3 100644
--- 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
@@ -24,6 +24,7 @@ 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 {
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
index b0bd987..dccec61 100644
--- 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
@@ -28,7 +28,14 @@ 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;
@@ -39,7 +46,7 @@ import com.google.common.collect.ImmutableSet;
 
 public interface EventBusTestFixture {
 
-    class MailboxListenerCountingSuccessfulExecution implements MailboxListener {
+    class EventListenerCountingSuccessfulExecution implements EventListener {
         private final AtomicInteger calls = new AtomicInteger(0);
 
         @Override
@@ -57,7 +64,7 @@ public interface EventBusTestFixture {
         }
     }
 
-    class EventMatcherThrowingListener extends MailboxListenerCountingSuccessfulExecution {
+    class EventMatcherThrowingListener extends EventListenerCountingSuccessfulExecution {
         private final ImmutableSet<Event> eventsCauseThrowing;
 
         EventMatcherThrowingListener(ImmutableSet<Event> eventsCauseThrowing) {
@@ -96,9 +103,9 @@ public interface EventBusTestFixture {
     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");
-    MailboxListener.MailboxEvent EVENT = new MailboxListener.MailboxAdded(SESSION_ID, USERNAME, MAILBOX_PATH, TEST_ID, EVENT_ID);
-    MailboxListener.MailboxEvent EVENT_2 = new MailboxListener.MailboxAdded(SESSION_ID, USERNAME, MAILBOX_PATH, TEST_ID, EVENT_ID_2);
-    MailboxListener.MailboxRenamed EVENT_UNSUPPORTED_BY_LISTENER = new MailboxListener.MailboxRenamed(SESSION_ID, USERNAME, MAILBOX_PATH, TEST_ID, MAILBOX_PATH, EVENT_ID_2);
+    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);
@@ -122,17 +129,17 @@ public interface EventBusTestFixture {
         .jitterFactor(DEFAULT_JITTER_FACTOR)
         .build();
 
-    static MailboxListener newListener() {
-        MailboxListener listener = mock(MailboxListener.class);
-        when(listener.getExecutionMode()).thenReturn(MailboxListener.ExecutionMode.SYNCHRONOUS);
-        when(listener.isHandling(any(MailboxListener.MailboxAdded.class))).thenReturn(true);
+    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 MailboxListener newAsyncListener() {
-        MailboxListener listener = mock(MailboxListener.class);
-        when(listener.getExecutionMode()).thenReturn(MailboxListener.ExecutionMode.ASYNCHRONOUS);
-        when(listener.isHandling(any(MailboxListener.MailboxAdded.class))).thenReturn(true);
+    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
index ebbbdbc..1e8f003 100644
--- 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
@@ -31,7 +31,11 @@ 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;
@@ -93,7 +97,7 @@ interface EventDeadLettersContract {
     }
 
     static Event event(Event.EventId eventId) {
-        return new MailboxListener.MailboxAdded(SESSION_ID, USERNAME, MAILBOX_PATH, MAILBOX_ID, 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(),
@@ -109,9 +113,9 @@ interface EventDeadLettersContract {
     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");
-    MailboxListener.MailboxAdded EVENT_1 = new MailboxListener.MailboxAdded(SESSION_ID, USERNAME, MAILBOX_PATH, MAILBOX_ID, EVENT_ID_1);
-    MailboxListener.MailboxAdded EVENT_2 = new MailboxListener.MailboxAdded(SESSION_ID, USERNAME, MAILBOX_PATH, MAILBOX_ID, EVENT_ID_2);
-    MailboxListener.MailboxAdded EVENT_3 = new MailboxListener.MailboxAdded(SESSION_ID, USERNAME, MAILBOX_PATH, MAILBOX_ID, EVENT_ID_3);
+    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");
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
index 7c16b7b..4479714 100644
--- 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
@@ -24,7 +24,12 @@ 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;
@@ -41,8 +46,8 @@ interface EventDeadLettersHealthCheckContract {
     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");
-    MailboxListener.MailboxAdded EVENT_1 = new MailboxListener.MailboxAdded(SESSION_ID, USERNAME, MAILBOX_PATH, MAILBOX_ID, EVENT_ID_1);
-    MailboxListener.MailboxAdded EVENT_2 = new MailboxListener.MailboxAdded(SESSION_ID, USERNAME, MAILBOX_PATH, MAILBOX_ID, EVENT_ID_2);
+    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();
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
index 24046a1..fb5131d 100644
--- 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
@@ -49,7 +49,16 @@ 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;
@@ -70,7 +79,7 @@ public interface GroupContract {
             AtomicInteger finishedExecutions = new AtomicInteger(0);
             AtomicBoolean rateExceeded = new AtomicBoolean(false);
 
-            eventBus().register(new MailboxListener.GroupMailboxListener() {
+            eventBus().register(new EventListener.GroupEventListener() {
                 @Override
                 public Group getDefaultGroup() {
                     return new GenericGroup("group");
@@ -106,7 +115,7 @@ public interface GroupContract {
             CountDownLatch countDownLatch = new CountDownLatch(1);
             try {
                 ConcurrentLinkedQueue<String> threads = new ConcurrentLinkedQueue<>();
-                eventBus().register(new MailboxListener.GroupMailboxListener() {
+                eventBus().register(new EventListener.GroupEventListener() {
                     @Override
                     public Group getDefaultGroup() {
                         return new GenericGroup("groupA");
@@ -118,7 +127,7 @@ public interface GroupContract {
                         countDownLatch.await();
                     }
                 }, GROUP_A);
-                eventBus().register(new MailboxListener.GroupMailboxListener() {
+                eventBus().register(new EventListener.GroupEventListener() {
                     @Override
                     public Group getDefaultGroup() {
                         return new GenericGroup("groupB");
@@ -130,7 +139,7 @@ public interface GroupContract {
                         countDownLatch.await();
                     }
                 }, GROUP_B);
-                eventBus().register(new MailboxListener.GroupMailboxListener() {
+                eventBus().register(new EventListener.GroupEventListener() {
                     @Override
                     public Group getDefaultGroup() {
                         return new GenericGroup("groupC");
@@ -157,7 +166,7 @@ public interface GroupContract {
         @Test
         default void listenersShouldBeAbleToDispatch() {
             AtomicBoolean successfulRetry = new AtomicBoolean(false);
-            MailboxListener listener = event -> {
+            EventListener listener = event -> {
                 if (event.getEventId().equals(EVENT_ID)) {
                     eventBus().dispatch(EVENT_2, NO_KEYS)
                         .subscribeOn(Schedulers.elastic())
@@ -174,7 +183,7 @@ public interface GroupContract {
 
         @Test
         default void registerShouldNotDispatchPastEventsForGroups() throws Exception {
-            MailboxListener listener = newListener();
+            EventListener listener = newListener();
 
             eventBus().dispatch(EVENT, NO_KEYS).block();
 
@@ -186,7 +195,7 @@ public interface GroupContract {
 
         @Test
         default void listenerGroupShouldReceiveEvents() throws Exception {
-            MailboxListener listener = newListener();
+            EventListener listener = newListener();
 
             eventBus().register(listener, GROUP_A);
 
@@ -197,12 +206,12 @@ public interface GroupContract {
 
         @Test
         default void groupListenersShouldNotReceiveNoopEvents() throws Exception {
-            MailboxListener listener = newListener();
+            EventListener listener = newListener();
 
             eventBus().register(listener, GROUP_A);
 
             Username bob = Username.of("bob");
-            MailboxListener.Added noopEvent = new MailboxListener.Added(MailboxSession.SessionId.of(18), bob, MailboxPath.forUser(bob, "mailbox"), TestId.of(58), ImmutableSortedMap.of(), Event.EventId.random());
+            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())
@@ -211,7 +220,7 @@ public interface GroupContract {
 
         @Test
         default void groupListenersShouldReceiveOnlyHandledEvents() throws Exception {
-            MailboxListener listener = newListener();
+            EventListener listener = newListener();
 
             eventBus().register(listener, GROUP_A);
 
@@ -223,7 +232,7 @@ public interface GroupContract {
 
         @Test
         default void dispatchShouldNotThrowWhenAGroupListenerFails() throws Exception {
-            MailboxListener listener = newListener();
+            EventListener listener = newListener();
             doThrow(new RuntimeException()).when(listener).event(any());
 
             eventBus().register(listener, GROUP_A);
@@ -234,8 +243,8 @@ public interface GroupContract {
 
         @Test
         default void eachListenerGroupShouldReceiveEvents() throws Exception {
-            MailboxListener listener = newListener();
-            MailboxListener listener2 = newListener();
+            EventListener listener = newListener();
+            EventListener listener2 = newListener();
             eventBus().register(listener, GROUP_A);
             eventBus().register(listener2, GROUP_B);
 
@@ -247,7 +256,7 @@ public interface GroupContract {
 
         @Test
         default void unregisteredGroupListenerShouldNotReceiveEvents() throws Exception {
-            MailboxListener listener = newListener();
+            EventListener listener = newListener();
             Registration registration = eventBus().register(listener, GROUP_A);
 
             registration.unregister();
@@ -259,8 +268,8 @@ public interface GroupContract {
 
         @Test
         default void registerShouldThrowWhenAGroupIsAlreadyUsed() {
-            MailboxListener listener = newListener();
-            MailboxListener listener2 = newListener();
+            EventListener listener = newListener();
+            EventListener listener2 = newListener();
 
             eventBus().register(listener, GROUP_A);
 
@@ -270,8 +279,8 @@ public interface GroupContract {
 
         @Test
         default void registerShouldNotThrowOnAnUnregisteredGroup() {
-            MailboxListener listener = newListener();
-            MailboxListener listener2 = newListener();
+            EventListener listener = newListener();
+            EventListener listener2 = newListener();
 
             eventBus().register(listener, GROUP_A).unregister();
 
@@ -281,7 +290,7 @@ public interface GroupContract {
 
         @Test
         default void unregisterShouldBeIdempotentForGroups() {
-            MailboxListener listener = newListener();
+            EventListener listener = newListener();
 
             Registration registration = eventBus().register(listener, GROUP_A);
             registration.unregister();
@@ -292,7 +301,7 @@ public interface GroupContract {
 
         @Test
         default void registerShouldAcceptAlreadyUnregisteredGroups() throws Exception {
-            MailboxListener listener = newListener();
+            EventListener listener = newListener();
 
             eventBus().register(listener, GROUP_A).unregister();
             eventBus().register(listener, GROUP_A);
@@ -304,7 +313,7 @@ public interface GroupContract {
 
         @Test
         default void dispatchShouldCallSynchronousListener() throws Exception {
-            MailboxListener listener = newListener();
+            EventListener listener = newListener();
 
             eventBus().register(listener, GROUP_A);
 
@@ -315,7 +324,7 @@ public interface GroupContract {
 
         @Test
         default void failingGroupListenersShouldNotAbortGroupDelivery() {
-            EventBusTestFixture.MailboxListenerCountingSuccessfulExecution listener = new EventBusTestFixture.EventMatcherThrowingListener(ImmutableSet.of(EVENT));
+            EventBusTestFixture.EventListenerCountingSuccessfulExecution listener = new EventBusTestFixture.EventMatcherThrowingListener(ImmutableSet.of(EVENT));
             eventBus().register(listener, GROUP_A);
 
             eventBus().dispatch(EVENT, NO_KEYS).block();
@@ -327,10 +336,10 @@ public interface GroupContract {
 
         @Test
         default void allGroupListenersShouldBeExecutedWhenAGroupListenerFails() throws Exception {
-            MailboxListener listener = newListener();
+            EventListener listener = newListener();
 
-            MailboxListener failingListener = mock(MailboxListener.class);
-            when(failingListener.getExecutionMode()).thenReturn(MailboxListener.ExecutionMode.SYNCHRONOUS);
+            EventListener failingListener = mock(EventListener.class);
+            when(failingListener.getExecutionMode()).thenReturn(EventListener.ExecutionMode.SYNCHRONOUS);
             doThrow(new RuntimeException()).when(failingListener).event(any());
 
             eventBus().register(failingListener, GROUP_A);
@@ -343,8 +352,8 @@ public interface GroupContract {
 
         @Test
         default void allGroupListenersShouldBeExecutedWhenGenericGroups() throws Exception {
-            MailboxListener listener1 = newListener();
-            MailboxListener listener2 = newListener();
+            EventListener listener1 = newListener();
+            EventListener listener2 = newListener();
 
             eventBus().register(listener1, new GenericGroup("a"));
             eventBus().register(listener2, new GenericGroup("b"));
@@ -357,7 +366,7 @@ public interface GroupContract {
 
         @Test
         default void groupListenerShouldReceiveEventWhenRedeliver() throws Exception {
-            MailboxListener listener = newListener();
+            EventListener listener = newListener();
 
             eventBus().register(listener, GROUP_A);
 
@@ -368,7 +377,7 @@ public interface GroupContract {
 
         @Test
         default void redeliverShouldNotThrowWhenAGroupListenerFails() throws Exception {
-            MailboxListener listener = newListener();
+            EventListener listener = newListener();
             doThrow(new RuntimeException()).when(listener).event(any());
 
             eventBus().register(listener, GROUP_A);
@@ -385,7 +394,7 @@ public interface GroupContract {
 
         @Test
         default void redeliverShouldThrowAfterGroupIsUnregistered() {
-            MailboxListener listener = newListener();
+            EventListener listener = newListener();
 
             eventBus().register(listener, GROUP_A).unregister();
 
@@ -395,8 +404,8 @@ public interface GroupContract {
 
         @Test
         default void redeliverShouldOnlySendEventToDefinedGroup() throws Exception {
-            MailboxListener listener = newListener();
-            MailboxListener listener2 = newListener();
+            EventListener listener = newListener();
+            EventListener listener2 = newListener();
             eventBus().register(listener, GROUP_A);
             eventBus().register(listener2, GROUP_B);
 
@@ -408,12 +417,12 @@ public interface GroupContract {
 
         @Test
         default void groupListenersShouldNotReceiveNoopRedeliveredEvents() throws Exception {
-            MailboxListener listener = newListener();
+            EventListener listener = newListener();
 
             eventBus().register(listener, GROUP_A);
 
             Username bob = Username.of("bob");
-            MailboxListener.Added noopEvent = new MailboxListener.Added(MailboxSession.SessionId.of(18), bob, MailboxPath.forUser(bob, "mailbox"), TestId.of(58), ImmutableSortedMap.of(), Event.EventId.random());
+            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());
@@ -424,7 +433,7 @@ public interface GroupContract {
 
         @Test
         default void groupsDefinedOnlyOnSomeNodesShouldBeNotifiedWhenDispatch() throws Exception {
-            MailboxListener mailboxListener = newListener();
+            EventListener mailboxListener = newListener();
 
             eventBus().register(mailboxListener, GROUP_A);
 
@@ -435,7 +444,7 @@ public interface GroupContract {
 
         @Test
         default void groupsDefinedOnlyOnSomeNodesShouldNotBeNotifiedWhenRedeliver() {
-            MailboxListener mailboxListener = newListener();
+            EventListener mailboxListener = newListener();
 
             eventBus().register(mailboxListener, GROUP_A);
 
@@ -445,7 +454,7 @@ public interface GroupContract {
 
         @Test
         default void groupListenersShouldBeExecutedOnceWhenRedeliverInADistributedEnvironment() throws Exception {
-            MailboxListener mailboxListener = newListener();
+            EventListener mailboxListener = newListener();
 
             eventBus().register(mailboxListener, GROUP_A);
             eventBus2().register(mailboxListener, GROUP_A);
@@ -457,7 +466,7 @@ public interface GroupContract {
 
         @Test
         default void groupListenersShouldBeExecutedOnceInAControlledEnvironment() throws Exception {
-            MailboxListener mailboxListener = newListener();
+            EventListener mailboxListener = newListener();
 
             eventBus().register(mailboxListener, GROUP_A);
             eventBus2().register(mailboxListener, GROUP_A);
@@ -469,7 +478,7 @@ public interface GroupContract {
 
         @Test
         default void unregisterShouldStopNotificationForDistantGroups() throws Exception {
-            MailboxListener mailboxListener = newListener();
+            EventListener mailboxListener = newListener();
 
             eventBus().register(mailboxListener, GROUP_A).unregister();
 
@@ -482,7 +491,7 @@ public interface GroupContract {
 
         @Test
         default void registerShouldNotDispatchPastEventsForGroupsInADistributedContext() throws Exception {
-            MailboxListener listener = newListener();
+            EventListener listener = newListener();
 
             eventBus().dispatch(EVENT, NO_KEYS).block();
 
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
index 617e191..53176df 100644
--- 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
@@ -22,6 +22,8 @@ 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;
@@ -80,18 +82,18 @@ class GroupTest {
 
     @Test
     void asStringShouldReturnNameWhenGenericGroup() {
-        assertThat(new GenericGroup("abc").asString()).isEqualTo("org.apache.james.mailbox.events.GenericGroup-abc");
+        assertThat(new GenericGroup("abc").asString()).isEqualTo("org.apache.james.events.GenericGroup-abc");
     }
 
     @Test
     void deserializeShouldReturnGroupWhenGenericGroup() throws Exception {
-        assertThat(Group.deserialize("org.apache.james.mailbox.events.GenericGroup-abc"))
+        assertThat(Group.deserialize("org.apache.james.events.GenericGroup-abc"))
             .isEqualTo(new GenericGroup("abc"));
     }
 
     @Test
     void deserializeShouldReturnGroupWhenEmptyGenericGroup() throws Exception {
-        assertThat(Group.deserialize("org.apache.james.mailbox.events.GenericGroup-"))
+        assertThat(Group.deserialize("org.apache.james.events.GenericGroup-"))
             .isEqualTo(new GenericGroup(""));
     }
 
@@ -115,7 +117,7 @@ class GroupTest {
 
     @Test
     void deserializeShouldThrowWhenConstructorArgumentsRequired() {
-        assertThatThrownBy(() -> Group.deserialize("org.apache.james.mailbox.events.GenericGroup"))
+        assertThatThrownBy(() -> Group.deserialize("org.apache.james.events.GenericGroup"))
             .isInstanceOf(Group.GroupDeserializationException.class);
     }
 
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
index f8a1e0e..c951edd 100644
--- 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
@@ -24,6 +24,7 @@ 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;
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
index f652377..4c22d4b 100644
--- 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
@@ -49,7 +49,12 @@ 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;
@@ -120,12 +125,12 @@ public interface KeyContract extends EventBusContract {
 
         @Test
         default void registeredListenersShouldNotReceiveNoopEvents() throws Exception {
-            MailboxListener listener = newListener();
+            EventListener listener = newListener();
 
             Mono.from(eventBus().register(listener, KEY_1)).block();
 
             Username bob = Username.of("bob");
-            MailboxListener.Added noopEvent = new MailboxListener.Added(MailboxSession.SessionId.of(18), bob, MailboxPath.forUser(bob, "mailbox"), TestId.of(58), ImmutableSortedMap.of(), Event.EventId.random());
+            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())
@@ -134,7 +139,7 @@ public interface KeyContract extends EventBusContract {
 
        @Test
         default void registeredListenersShouldReceiveOnlyHandledEvents() throws Exception {
-            MailboxListener listener = newListener();
+            EventListener listener = newListener();
 
             Mono.from(eventBus().register(listener, KEY_1)).block();
 
@@ -146,7 +151,7 @@ public interface KeyContract extends EventBusContract {
 
         @Test
         default void dispatchShouldNotThrowWhenARegisteredListenerFails() throws Exception {
-            MailboxListener listener = newListener();
+            EventListener listener = newListener();
             doThrow(new RuntimeException()).when(listener).event(any());
 
             Mono.from(eventBus().register(listener, KEY_1)).block();
@@ -157,7 +162,7 @@ public interface KeyContract extends EventBusContract {
 
         @Test
         default void dispatchShouldNotNotifyRegisteredListenerWhenEmptyKeySet() throws Exception {
-            MailboxListener listener = newListener();
+            EventListener listener = newListener();
             Mono.from(eventBus().register(listener, KEY_1)).block();
 
             eventBus().dispatch(EVENT, NO_KEYS).block();
@@ -168,7 +173,7 @@ public interface KeyContract extends EventBusContract {
 
         @Test
         default void dispatchShouldNotNotifyListenerRegisteredOnOtherKeys() throws Exception {
-            MailboxListener listener = newListener();
+            EventListener listener = newListener();
             Mono.from(eventBus().register(listener, KEY_1)).block();
 
             eventBus().dispatch(EVENT, ImmutableSet.of(KEY_2)).block();
@@ -179,7 +184,7 @@ public interface KeyContract extends EventBusContract {
 
         @Test
         default void dispatchShouldNotifyRegisteredListeners() throws Exception {
-            MailboxListener listener = newListener();
+            EventListener listener = newListener();
             Mono.from(eventBus().register(listener, KEY_1)).block();
 
             eventBus().dispatch(EVENT, ImmutableSet.of(KEY_1)).block();
@@ -189,7 +194,7 @@ public interface KeyContract extends EventBusContract {
 
         @Test
         default void dispatchShouldNotifyLocalRegisteredListenerWithoutDelay() throws Exception {
-            MailboxListener listener = newListener();
+            EventListener listener = newListener();
             Mono.from(eventBus().register(listener, KEY_1)).block();
 
             eventBus().dispatch(EVENT, ImmutableSet.of(KEY_1)).block();
@@ -199,8 +204,8 @@ public interface KeyContract extends EventBusContract {
 
         @Test
         default void dispatchShouldNotifyOnlyRegisteredListener() throws Exception {
-            MailboxListener listener = newListener();
-            MailboxListener listener2 = newListener();
+            EventListener listener = newListener();
+            EventListener listener2 = newListener();
             Mono.from(eventBus().register(listener, KEY_1)).block();
             Mono.from(eventBus().register(listener2, KEY_2)).block();
 
@@ -213,8 +218,8 @@ public interface KeyContract extends EventBusContract {
 
         @Test
         default void dispatchShouldNotifyAllListenersRegisteredOnAKey() throws Exception {
-            MailboxListener listener = newListener();
-            MailboxListener listener2 = newListener();
+            EventListener listener = newListener();
+            EventListener listener2 = newListener();
             Mono.from(eventBus().register(listener, KEY_1)).block();
             Mono.from(eventBus().register(listener2, KEY_1)).block();
 
@@ -226,7 +231,7 @@ public interface KeyContract extends EventBusContract {
 
         @Test
         default void registerShouldAllowDuplicatedRegistration() throws Exception {
-            MailboxListener listener = newListener();
+            EventListener listener = newListener();
             Mono.from(eventBus().register(listener, KEY_1)).block();
             Mono.from(eventBus().register(listener, KEY_1)).block();
 
@@ -237,7 +242,7 @@ public interface KeyContract extends EventBusContract {
 
         @Test
         default void unregisterShouldRemoveDoubleRegisteredListener() throws Exception {
-            MailboxListener listener = newListener();
+            EventListener listener = newListener();
             Mono.from(eventBus().register(listener, KEY_1)).block();
             Mono.from(eventBus().register(listener, KEY_1)).block().unregister();
 
@@ -249,7 +254,7 @@ public interface KeyContract extends EventBusContract {
 
         @Test
         default void registerShouldNotDispatchPastEvents() throws Exception {
-            MailboxListener listener = newListener();
+            EventListener listener = newListener();
 
             eventBus().dispatch(EVENT, ImmutableSet.of(KEY_1)).block();
 
@@ -261,7 +266,7 @@ public interface KeyContract extends EventBusContract {
 
         @Test
         default void callingAllUnregisterMethodShouldUnregisterTheListener() throws Exception {
-            MailboxListener listener = newListener();
+            EventListener listener = newListener();
             Registration registration = Mono.from(eventBus().register(listener, KEY_1)).block();
             Mono.from(eventBus().register(listener, KEY_1)).block().unregister();
             registration.unregister();
@@ -274,7 +279,7 @@ public interface KeyContract extends EventBusContract {
 
         @Test
         default void unregisterShouldHaveNotNotifyWhenCalledOnDifferentKeys() throws Exception {
-            MailboxListener listener = newListener();
+            EventListener listener = newListener();
             Mono.from(eventBus().register(listener, KEY_1)).block();
             Mono.from(eventBus().register(listener, KEY_2)).block().unregister();
 
@@ -285,7 +290,7 @@ public interface KeyContract extends EventBusContract {
 
         @Test
         default void unregisterShouldBeIdempotentForKeyRegistrations() {
-            MailboxListener listener = newListener();
+            EventListener listener = newListener();
 
             Registration registration = Mono.from(eventBus().register(listener, KEY_1)).block();
             registration.unregister();
@@ -296,7 +301,7 @@ public interface KeyContract extends EventBusContract {
 
         @Test
         default void dispatchShouldAcceptSeveralKeys() throws Exception {
-            MailboxListener listener = newListener();
+            EventListener listener = newListener();
             Mono.from(eventBus().register(listener, KEY_1)).block();
 
             eventBus().dispatch(EVENT, ImmutableSet.of(KEY_1, KEY_2)).block();
@@ -306,7 +311,7 @@ public interface KeyContract extends EventBusContract {
 
         @Test
         default void dispatchShouldCallListenerOnceWhenSeveralKeysMatching() throws Exception {
-            MailboxListener listener = newListener();
+            EventListener listener = newListener();
             Mono.from(eventBus().register(listener, KEY_1)).block();
             Mono.from(eventBus().register(listener, KEY_2)).block();
 
@@ -317,7 +322,7 @@ public interface KeyContract extends EventBusContract {
 
         @Test
         default void dispatchShouldNotNotifyUnregisteredListener() throws Exception {
-            MailboxListener listener = newListener();
+            EventListener listener = newListener();
             Mono.from(eventBus().register(listener, KEY_1)).block().unregister();
 
             eventBus().dispatch(EVENT, ImmutableSet.of(KEY_1)).block();
@@ -329,8 +334,8 @@ public interface KeyContract extends EventBusContract {
 
         @Test
         default void dispatchShouldNotifyAsynchronousListener() throws Exception {
-            MailboxListener listener = newListener();
-            when(listener.getExecutionMode()).thenReturn(MailboxListener.ExecutionMode.ASYNCHRONOUS);
+            EventListener listener = newListener();
+            when(listener.getExecutionMode()).thenReturn(EventListener.ExecutionMode.ASYNCHRONOUS);
             Mono.from(eventBus().register(listener, KEY_1)).block();
 
             eventBus().dispatch(EVENT, KEY_1).block();
@@ -340,8 +345,8 @@ public interface KeyContract extends EventBusContract {
 
         @Test
         default void dispatchShouldNotBlockAsynchronousListener() throws Exception {
-            MailboxListener listener = newListener();
-            when(listener.getExecutionMode()).thenReturn(MailboxListener.ExecutionMode.ASYNCHRONOUS);
+            EventListener listener = newListener();
+            when(listener.getExecutionMode()).thenReturn(EventListener.ExecutionMode.ASYNCHRONOUS);
             CountDownLatch latch = new CountDownLatch(1);
             doAnswer(invocation -> {
                 latch.await();
@@ -357,7 +362,7 @@ public interface KeyContract extends EventBusContract {
 
         @Test
         default void failingRegisteredListenersShouldNotAbortRegisteredDelivery() {
-            EventBusTestFixture.MailboxListenerCountingSuccessfulExecution listener = new EventBusTestFixture.EventMatcherThrowingListener(ImmutableSet.of(EVENT));
+            EventBusTestFixture.EventListenerCountingSuccessfulExecution listener = new EventBusTestFixture.EventMatcherThrowingListener(ImmutableSet.of(EVENT));
             Mono.from(eventBus().register(listener, KEY_1)).block();
 
             eventBus().dispatch(EVENT, KEY_1).block();
@@ -369,10 +374,10 @@ public interface KeyContract extends EventBusContract {
 
         @Test
         default void allRegisteredListenersShouldBeExecutedWhenARegisteredListenerFails() throws Exception {
-            MailboxListener listener = newListener();
+            EventListener listener = newListener();
 
-            MailboxListener failingListener = mock(MailboxListener.class);
-            when(failingListener.getExecutionMode()).thenReturn(MailboxListener.ExecutionMode.SYNCHRONOUS);
+            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();
@@ -388,7 +393,7 @@ public interface KeyContract extends EventBusContract {
 
         @Test
         default void crossEventBusRegistrationShouldBeAllowed() throws Exception {
-            MailboxListener mailboxListener = newListener();
+            EventListener mailboxListener = newListener();
 
             Mono.from(eventBus().register(mailboxListener, KEY_1)).block();
 
@@ -399,20 +404,20 @@ public interface KeyContract extends EventBusContract {
 
         @Test
         default void unregisteredDistantListenersShouldNotBeNotified() throws Exception {
-            MailboxListener mailboxListener = newListener();
+            EventListener eventListener = newListener();
 
-            Mono.from(eventBus().register(mailboxListener, KEY_1)).block().unregister();
+            Mono.from(eventBus().register(eventListener, KEY_1)).block().unregister();
 
             eventBus2().dispatch(EVENT, ImmutableSet.of(KEY_1)).block();
 
-            verify(mailboxListener, after(FIVE_HUNDRED_MS.toMillis()).never())
+            verify(eventListener, after(FIVE_HUNDRED_MS.toMillis()).never())
                 .event(any());
         }
 
         @Test
         default void allRegisteredListenersShouldBeDispatched() throws Exception {
-            MailboxListener mailboxListener1 = newListener();
-            MailboxListener mailboxListener2 = newListener();
+            EventListener mailboxListener1 = newListener();
+            EventListener mailboxListener2 = newListener();
 
             Mono.from(eventBus().register(mailboxListener1, KEY_1)).block();
             Mono.from(eventBus2().register(mailboxListener2, KEY_1)).block();
@@ -425,7 +430,7 @@ public interface KeyContract extends EventBusContract {
 
         @Test
         default void registerShouldNotDispatchPastEventsInDistributedContext() throws Exception {
-            MailboxListener listener = newListener();
+            EventListener listener = newListener();
 
             eventBus2().dispatch(EVENT, ImmutableSet.of(KEY_1)).block();
 
@@ -437,8 +442,8 @@ public interface KeyContract extends EventBusContract {
 
         @Test
         default void localDispatchedListenersShouldBeDispatchedWithoutDelay() throws Exception {
-            MailboxListener mailboxListener1 = newListener();
-            MailboxListener mailboxListener2 = newListener();
+            EventListener mailboxListener1 = newListener();
+            EventListener mailboxListener2 = newListener();
 
             Mono.from(eventBus().register(mailboxListener1, KEY_1)).block();
             Mono.from(eventBus2().register(mailboxListener2, KEY_1)).block();
diff --git a/mailbox/api/src/test/java/org/apache/james/mailbox/util/EventCollector.java b/mailbox/api/src/test/java/org/apache/james/mailbox/util/EventCollector.java
index d149fc8..1b18ed3 100644
--- a/mailbox/api/src/test/java/org/apache/james/mailbox/util/EventCollector.java
+++ b/mailbox/api/src/test/java/org/apache/james/mailbox/util/EventCollector.java
@@ -22,11 +22,11 @@ package org.apache.james.mailbox.util;
 import java.util.Collection;
 import java.util.concurrent.ConcurrentLinkedDeque;
 
-import org.apache.james.mailbox.events.Event;
-import org.apache.james.mailbox.events.Group;
-import org.apache.james.mailbox.events.MailboxListener;
+import org.apache.james.events.Event;
+import org.apache.james.events.EventListener;
+import org.apache.james.events.Group;
 
-public class EventCollector implements MailboxListener.GroupMailboxListener {
+public class EventCollector implements EventListener.GroupEventListener {
     public static class EventCollectorGroup extends Group {
 
     }
diff --git a/mailbox/cassandra/src/main/java/org/apache/james/mailbox/cassandra/CassandraMailboxManager.java b/mailbox/cassandra/src/main/java/org/apache/james/mailbox/cassandra/CassandraMailboxManager.java
index f765922..35d9f40 100644
--- a/mailbox/cassandra/src/main/java/org/apache/james/mailbox/cassandra/CassandraMailboxManager.java
+++ b/mailbox/cassandra/src/main/java/org/apache/james/mailbox/cassandra/CassandraMailboxManager.java
@@ -23,11 +23,11 @@ import java.util.EnumSet;
 
 import javax.inject.Inject;
 
+import org.apache.james.events.EventBus;
 import org.apache.james.mailbox.MailboxManager;
 import org.apache.james.mailbox.MailboxPathLocker;
 import org.apache.james.mailbox.MailboxSession;
 import org.apache.james.mailbox.SessionProvider;
-import org.apache.james.mailbox.events.EventBus;
 import org.apache.james.mailbox.model.Mailbox;
 import org.apache.james.mailbox.model.MessageId;
 import org.apache.james.mailbox.store.MailboxManagerConfiguration;
diff --git a/mailbox/cassandra/src/main/java/org/apache/james/mailbox/cassandra/CassandraMessageManager.java b/mailbox/cassandra/src/main/java/org/apache/james/mailbox/cassandra/CassandraMessageManager.java
index 928e627..e40d175 100644
--- a/mailbox/cassandra/src/main/java/org/apache/james/mailbox/cassandra/CassandraMessageManager.java
+++ b/mailbox/cassandra/src/main/java/org/apache/james/mailbox/cassandra/CassandraMessageManager.java
@@ -21,9 +21,9 @@ package org.apache.james.mailbox.cassandra;
 
 import javax.mail.Flags;
 
+import org.apache.james.events.EventBus;
 import org.apache.james.mailbox.MailboxPathLocker;
 import org.apache.james.mailbox.MailboxSession;
-import org.apache.james.mailbox.events.EventBus;
 import org.apache.james.mailbox.model.Mailbox;
 import org.apache.james.mailbox.model.MessageId;
 import org.apache.james.mailbox.quota.QuotaManager;
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 3122449..728bd81 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
@@ -28,6 +28,9 @@ import java.util.function.Predicate;
 import javax.inject.Inject;
 
 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.mailbox.acl.ACLDiff;
 import org.apache.james.mailbox.cassandra.ids.CassandraId;
 import org.apache.james.mailbox.cassandra.ids.CassandraMessageId;
@@ -47,9 +50,8 @@ 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.Event;
-import org.apache.james.mailbox.events.Group;
-import org.apache.james.mailbox.events.MailboxListener;
+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;
@@ -71,7 +73,7 @@ import reactor.core.publisher.Mono;
  * Mailbox listener failures lead to eventBus retrying their execution, it ensures the result of the deletion to be
  * idempotent.
  */
-public class DeleteMessageListener implements MailboxListener.GroupMailboxListener {
+public class DeleteMessageListener implements EventListener.GroupEventListener {
     private static final Optional<CassandraId> ALL_MAILBOXES = Optional.empty();
 
     public static class DeleteMessageListenerGroup extends Group {
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 e5915aa..dcfd070 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
@@ -23,16 +23,19 @@ import static org.apache.james.mailbox.cassandra.GhostMailbox.MAILBOX_ID;
 import static org.apache.james.mailbox.cassandra.GhostMailbox.MAILBOX_NAME;
 import static org.apache.james.mailbox.cassandra.GhostMailbox.TYPE;
 
-import org.apache.james.mailbox.events.Event;
-import org.apache.james.mailbox.events.Group;
-import org.apache.james.mailbox.events.MailboxListener;
+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;
 
 /**
  * See https://issues.apache.org/jira/browse/MAILBOX-322 for reading about the Ghost mailbox bug.
  *
  * This class logs mailboxes writes in order to give context to analyse ghost mailbox bug.
  */
-public class MailboxOperationLoggingListener implements MailboxListener.GroupMailboxListener {
+public class MailboxOperationLoggingListener implements EventListener.GroupEventListener {
     public static class MailboxOperationLoggingListenerGroup extends Group {
 
     }
diff --git a/mailbox/cassandra/src/test/java/org/apache/james/mailbox/cassandra/CassandraCombinationManagerTestSystem.java b/mailbox/cassandra/src/test/java/org/apache/james/mailbox/cassandra/CassandraCombinationManagerTestSystem.java
index 1e0c20e..1317934 100644
--- a/mailbox/cassandra/src/test/java/org/apache/james/mailbox/cassandra/CassandraCombinationManagerTestSystem.java
+++ b/mailbox/cassandra/src/test/java/org/apache/james/mailbox/cassandra/CassandraCombinationManagerTestSystem.java
@@ -20,11 +20,11 @@
 package org.apache.james.mailbox.cassandra;
 
 import org.apache.james.backends.cassandra.CassandraCluster;
+import org.apache.james.events.EventBus;
 import org.apache.james.mailbox.MailboxManager;
 import org.apache.james.mailbox.MailboxSession;
 import org.apache.james.mailbox.MessageIdManager;
 import org.apache.james.mailbox.MessageManager;
-import org.apache.james.mailbox.events.EventBus;
 import org.apache.james.mailbox.exception.MailboxException;
 import org.apache.james.mailbox.exception.MailboxNotFoundException;
 import org.apache.james.mailbox.model.Mailbox;
diff --git a/mailbox/cassandra/src/test/java/org/apache/james/mailbox/cassandra/CassandraMailboxManagerStressTest.java b/mailbox/cassandra/src/test/java/org/apache/james/mailbox/cassandra/CassandraMailboxManagerStressTest.java
index 6120bbd..b55f8d7 100644
--- a/mailbox/cassandra/src/test/java/org/apache/james/mailbox/cassandra/CassandraMailboxManagerStressTest.java
+++ b/mailbox/cassandra/src/test/java/org/apache/james/mailbox/cassandra/CassandraMailboxManagerStressTest.java
@@ -20,9 +20,9 @@
 package org.apache.james.mailbox.cassandra;
 
 import org.apache.james.backends.cassandra.CassandraClusterExtension;
+import org.apache.james.events.EventBus;
 import org.apache.james.mailbox.MailboxManagerStressContract;
 import org.apache.james.mailbox.cassandra.mail.MailboxAggregateModule;
-import org.apache.james.mailbox.events.EventBus;
 import org.apache.james.mailbox.store.PreDeletionHooks;
 import org.junit.jupiter.api.BeforeEach;
 import org.junit.jupiter.api.extension.RegisterExtension;
diff --git a/mailbox/cassandra/src/test/java/org/apache/james/mailbox/cassandra/CassandraMailboxManagerTest.java b/mailbox/cassandra/src/test/java/org/apache/james/mailbox/cassandra/CassandraMailboxManagerTest.java
index cc974d9..7012984 100644
--- a/mailbox/cassandra/src/test/java/org/apache/james/mailbox/cassandra/CassandraMailboxManagerTest.java
+++ b/mailbox/cassandra/src/test/java/org/apache/james/mailbox/cassandra/CassandraMailboxManagerTest.java
@@ -40,6 +40,7 @@ import org.apache.james.blob.api.BlobStore;
 import org.apache.james.blob.api.HashBlobId;
 import org.apache.james.blob.cassandra.BlobTables;
 import org.apache.james.core.Username;
+import org.apache.james.events.EventBus;
 import org.apache.james.eventsourcing.eventstore.cassandra.CassandraEventStore;
 import org.apache.james.eventsourcing.eventstore.cassandra.EventStoreDao;
 import org.apache.james.eventsourcing.eventstore.cassandra.JsonEventSerializer;
@@ -67,7 +68,6 @@ import org.apache.james.mailbox.cassandra.mail.CassandraMessageIdToImapUidDAO;
 import org.apache.james.mailbox.cassandra.mail.CassandraUserMailboxRightsDAO;
 import org.apache.james.mailbox.cassandra.mail.MailboxAggregateModule;
 import org.apache.james.mailbox.cassandra.mail.eventsourcing.acl.ACLModule;
-import org.apache.james.mailbox.events.EventBus;
 import org.apache.james.mailbox.model.AttachmentId;
 import org.apache.james.mailbox.model.FetchGroup;
 import org.apache.james.mailbox.model.MailboxACL;
diff --git a/mailbox/cassandra/src/test/java/org/apache/james/mailbox/cassandra/CassandraMessageIdManagerSideEffectTest.java b/mailbox/cassandra/src/test/java/org/apache/james/mailbox/cassandra/CassandraMessageIdManagerSideEffectTest.java
index 082ee2a..e4ee044 100644
--- a/mailbox/cassandra/src/test/java/org/apache/james/mailbox/cassandra/CassandraMessageIdManagerSideEffectTest.java
+++ b/mailbox/cassandra/src/test/java/org/apache/james/mailbox/cassandra/CassandraMessageIdManagerSideEffectTest.java
@@ -24,8 +24,8 @@ import java.util.Set;
 import org.apache.james.backends.cassandra.CassandraCluster;
 import org.apache.james.backends.cassandra.CassandraClusterExtension;
 import org.apache.james.backends.cassandra.StatementRecorder;
+import org.apache.james.events.EventBus;
 import org.apache.james.mailbox.cassandra.mail.MailboxAggregateModule;
-import org.apache.james.mailbox.events.EventBus;
 import org.apache.james.mailbox.extension.PreDeletionHook;
 import org.apache.james.mailbox.model.MessageId;
 import org.apache.james.mailbox.quota.QuotaManager;
diff --git a/mailbox/cassandra/src/test/java/org/apache/james/mailbox/cassandra/CassandraMessageIdManagerTestSystem.java b/mailbox/cassandra/src/test/java/org/apache/james/mailbox/cassandra/CassandraMessageIdManagerTestSystem.java
index ee64a24..c845175 100644
--- a/mailbox/cassandra/src/test/java/org/apache/james/mailbox/cassandra/CassandraMessageIdManagerTestSystem.java
+++ b/mailbox/cassandra/src/test/java/org/apache/james/mailbox/cassandra/CassandraMessageIdManagerTestSystem.java
@@ -22,8 +22,8 @@ package org.apache.james.mailbox.cassandra;
 import java.util.Set;
 
 import org.apache.james.backends.cassandra.CassandraCluster;
+import org.apache.james.events.EventBus;
 import org.apache.james.mailbox.cassandra.ids.CassandraMessageId;
-import org.apache.james.mailbox.events.EventBus;
 import org.apache.james.mailbox.extension.PreDeletionHook;
 import org.apache.james.mailbox.quota.CurrentQuotaManager;
 import org.apache.james.mailbox.quota.QuotaManager;
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 dea017b..1b4f270 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
@@ -22,6 +22,7 @@ package org.apache.james.mailbox.cassandra;
 import static org.mockito.Mockito.mock;
 
 import org.apache.james.backends.cassandra.CassandraCluster;
+import org.apache.james.events.EventBus;
 import org.apache.james.mailbox.AttachmentContentLoader;
 import org.apache.james.mailbox.Authenticator;
 import org.apache.james.mailbox.Authorizator;
@@ -33,7 +34,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.EventBus;
 import org.apache.james.mailbox.events.EventBusTestFixture;
 import org.apache.james.mailbox.events.InVMEventBus;
 import org.apache.james.mailbox.events.MemoryEventDeadLetters;
diff --git a/mailbox/cassandra/src/test/java/org/apache/james/mailbox/cassandra/MailboxOperationLoggingListenerTest.java b/mailbox/cassandra/src/test/java/org/apache/james/mailbox/cassandra/MailboxOperationLoggingListenerTest.java
index 45adb03..6bb9b8c 100644
--- a/mailbox/cassandra/src/test/java/org/apache/james/mailbox/cassandra/MailboxOperationLoggingListenerTest.java
+++ b/mailbox/cassandra/src/test/java/org/apache/james/mailbox/cassandra/MailboxOperationLoggingListenerTest.java
@@ -21,7 +21,7 @@ package org.apache.james.mailbox.cassandra;
 
 import static org.assertj.core.api.Assertions.assertThat;
 
-import org.apache.james.mailbox.events.Group;
+import org.apache.james.events.Group;
 import org.junit.jupiter.api.Test;
 
 class MailboxOperationLoggingListenerTest {
diff --git a/mailbox/cassandra/src/test/java/org/apache/james/mailbox/cassandra/mail/CassandraMailboxMapperTest.java b/mailbox/cassandra/src/test/java/org/apache/james/mailbox/cassandra/mail/CassandraMailboxMapperTest.java
index d2f060b..8fe8fac 100644
--- a/mailbox/cassandra/src/test/java/org/apache/james/mailbox/cassandra/mail/CassandraMailboxMapperTest.java
+++ b/mailbox/cassandra/src/test/java/org/apache/james/mailbox/cassandra/mail/CassandraMailboxMapperTest.java
@@ -69,7 +69,6 @@ import com.github.fge.lambdas.Throwing;
 import com.github.fge.lambdas.runnable.ThrowingRunnable;
 
 import reactor.core.publisher.Mono;
-import reactor.core.scheduler.Schedulers;
 
 class CassandraMailboxMapperTest {
     private static final UidValidity UID_VALIDITY = UidValidity.of(52);
diff --git a/mailbox/elasticsearch/src/main/java/org/apache/james/mailbox/elasticsearch/events/ElasticSearchListeningMessageSearchIndex.java b/mailbox/elasticsearch/src/main/java/org/apache/james/mailbox/elasticsearch/events/ElasticSearchListeningMessageSearchIndex.java
index 6554bb6..244189c 100644
--- a/mailbox/elasticsearch/src/main/java/org/apache/james/mailbox/elasticsearch/events/ElasticSearchListeningMessageSearchIndex.java
+++ b/mailbox/elasticsearch/src/main/java/org/apache/james/mailbox/elasticsearch/events/ElasticSearchListeningMessageSearchIndex.java
@@ -43,6 +43,7 @@ import org.apache.james.backends.es.DocumentId;
 import org.apache.james.backends.es.ElasticSearchIndexer;
 import org.apache.james.backends.es.RoutingKey;
 import org.apache.james.backends.es.UpdatedRepresentation;
+import org.apache.james.events.Group;
 import org.apache.james.mailbox.FlagsBuilder;
 import org.apache.james.mailbox.MailboxManager.MessageCapabilities;
 import org.apache.james.mailbox.MailboxManager.SearchCapabilities;
@@ -52,7 +53,6 @@ import org.apache.james.mailbox.SessionProvider;
 import org.apache.james.mailbox.elasticsearch.MailboxElasticSearchConstants;
 import org.apache.james.mailbox.elasticsearch.json.MessageToElasticSearchJson;
 import org.apache.james.mailbox.elasticsearch.search.ElasticSearchSearcher;
-import org.apache.james.mailbox.events.Group;
 import org.apache.james.mailbox.model.Mailbox;
 import org.apache.james.mailbox.model.MailboxId;
 import org.apache.james.mailbox.model.MessageId;
diff --git a/mailbox/elasticsearch/src/test/java/org/apache/james/mailbox/elasticsearch/ElasticSearchIntegrationTest.java b/mailbox/elasticsearch/src/test/java/org/apache/james/mailbox/elasticsearch/ElasticSearchIntegrationTest.java
index 9178820..a6f5476 100644
--- a/mailbox/elasticsearch/src/test/java/org/apache/james/mailbox/elasticsearch/ElasticSearchIntegrationTest.java
+++ b/mailbox/elasticsearch/src/test/java/org/apache/james/mailbox/elasticsearch/ElasticSearchIntegrationTest.java
@@ -20,7 +20,6 @@
 package org.apache.james.mailbox.elasticsearch;
 
 import static org.assertj.core.api.Assertions.assertThat;
-import static org.junit.jupiter.api.Assumptions.assumeTrue;
 
 import java.io.IOException;
 import java.nio.charset.StandardCharsets;
@@ -29,7 +28,6 @@ import java.time.ZoneId;
 import org.apache.james.backends.es.DockerElasticSearchExtension;
 import org.apache.james.backends.es.ElasticSearchIndexer;
 import org.apache.james.backends.es.ReactorElasticSearchClient;
-import org.apache.james.mailbox.MailboxManager;
 import org.apache.james.mailbox.MailboxSession;
 import org.apache.james.mailbox.MailboxSessionUtil;
 import org.apache.james.mailbox.MessageManager;
@@ -38,7 +36,6 @@ import org.apache.james.mailbox.elasticsearch.json.MessageToElasticSearchJson;
 import org.apache.james.mailbox.elasticsearch.query.CriterionConverter;
 import org.apache.james.mailbox.elasticsearch.query.QueryConverter;
 import org.apache.james.mailbox.elasticsearch.search.ElasticSearchSearcher;
-import org.apache.james.mailbox.exception.MailboxException;
 import org.apache.james.mailbox.inmemory.InMemoryId;
 import org.apache.james.mailbox.inmemory.InMemoryMessageId;
 import org.apache.james.mailbox.inmemory.manager.InMemoryIntegrationResources;
@@ -59,7 +56,6 @@ import org.junit.jupiter.api.Test;
 import org.junit.jupiter.api.extension.RegisterExtension;
 
 import com.google.common.base.Strings;
-import com.google.common.collect.ImmutableList;
 
 import reactor.core.publisher.Flux;
 
diff --git a/mailbox/elasticsearch/src/test/java/org/apache/james/mailbox/elasticsearch/events/ElasticSearchListeningMessageSearchIndexTest.java b/mailbox/elasticsearch/src/test/java/org/apache/james/mailbox/elasticsearch/events/ElasticSearchListeningMessageSearchIndexTest.java
index fcfa31e..cee6c69 100644
--- a/mailbox/elasticsearch/src/test/java/org/apache/james/mailbox/elasticsearch/events/ElasticSearchListeningMessageSearchIndexTest.java
+++ b/mailbox/elasticsearch/src/test/java/org/apache/james/mailbox/elasticsearch/events/ElasticSearchListeningMessageSearchIndexTest.java
@@ -35,6 +35,7 @@ import org.apache.james.backends.es.DockerElasticSearchExtension;
 import org.apache.james.backends.es.ElasticSearchIndexer;
 import org.apache.james.backends.es.ReactorElasticSearchClient;
 import org.apache.james.core.Username;
+import org.apache.james.events.Group;
 import org.apache.james.mailbox.Authorizator;
 import org.apache.james.mailbox.DefaultMailboxes;
 import org.apache.james.mailbox.MailboxSession;
@@ -48,7 +49,6 @@ import org.apache.james.mailbox.elasticsearch.json.MessageToElasticSearchJson;
 import org.apache.james.mailbox.elasticsearch.query.CriterionConverter;
 import org.apache.james.mailbox.elasticsearch.query.QueryConverter;
 import org.apache.james.mailbox.elasticsearch.search.ElasticSearchSearcher;
-import org.apache.james.mailbox.events.Group;
 import org.apache.james.mailbox.exception.MailboxException;
 import org.apache.james.mailbox.extractor.ParsedContent;
 import org.apache.james.mailbox.extractor.TextExtractor;
@@ -78,7 +78,6 @@ import org.apache.james.mailbox.store.mail.model.impl.SimpleMailboxMessage;
 import org.apache.james.mailbox.store.search.ListeningMessageSearchIndex;
 import org.apache.james.mailbox.store.search.ListeningMessageSearchIndexContract;
 import org.awaitility.Duration;
-import org.elasticsearch.index.IndexNotFoundException;
 import org.junit.jupiter.api.BeforeEach;
 import org.junit.jupiter.api.Nested;
 import org.junit.jupiter.api.Test;
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/events/CassandraEventDeadLetters.java
similarity index 98%
copy from mailbox/event/event-cassandra/src/main/java/org/apache/james/mailbox/events/CassandraEventDeadLetters.java
copy to mailbox/event/event-cassandra/src/main/java/org/apache/james/events/CassandraEventDeadLetters.java
index 97e4a8e..e170221 100644
--- 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/events/CassandraEventDeadLetters.java
@@ -17,7 +17,7 @@
  * under the License.                                           *
  ****************************************************************/
 
-package org.apache.james.mailbox.events;
+package org.apache.james.events;
 
 import javax.inject.Inject;
 
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/events/CassandraEventDeadLettersDAO.java
similarity index 62%
copy from mailbox/event/event-cassandra/src/main/java/org/apache/james/mailbox/events/CassandraEventDeadLettersDAO.java
copy to mailbox/event/event-cassandra/src/main/java/org/apache/james/events/CassandraEventDeadLettersDAO.java
index 7b62fc0..4bfbd32 100644
--- 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/events/CassandraEventDeadLettersDAO.java
@@ -17,25 +17,23 @@
  * under the License.                                           *
  ****************************************************************/
 
-package org.apache.james.mailbox.events;
+package org.apache.james.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.tables.CassandraEventDeadLettersTable;
 
 import com.datastax.driver.core.PreparedStatement;
 import com.datastax.driver.core.Session;
+import com.datastax.driver.core.querybuilder.QueryBuilder;
 
 import reactor.core.publisher.Flux;
 import reactor.core.publisher.Mono;
@@ -61,62 +59,62 @@ public class CassandraEventDeadLettersDAO {
     }
 
     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)));
+        return session.prepare(QueryBuilder.insertInto(CassandraEventDeadLettersTable.TABLE_NAME)
+            .value(CassandraEventDeadLettersTable.GROUP, bindMarker(CassandraEventDeadLettersTable.GROUP))
+            .value(CassandraEventDeadLettersTable.INSERTION_ID, bindMarker(CassandraEventDeadLettersTable.INSERTION_ID))
+            .value(CassandraEventDeadLettersTable.EVENT, bindMarker(CassandraEventDeadLettersTable.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))));
+            .from(CassandraEventDeadLettersTable.TABLE_NAME)
+            .where(QueryBuilder.eq(CassandraEventDeadLettersTable.GROUP, bindMarker(CassandraEventDeadLettersTable.GROUP)))
+            .and(QueryBuilder.eq(CassandraEventDeadLettersTable.INSERTION_ID, bindMarker(CassandraEventDeadLettersTable.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))));
+        return session.prepare(QueryBuilder.select(CassandraEventDeadLettersTable.EVENT)
+            .from(CassandraEventDeadLettersTable.TABLE_NAME)
+            .where(QueryBuilder.eq(CassandraEventDeadLettersTable.GROUP, bindMarker(CassandraEventDeadLettersTable.GROUP)))
+            .and(QueryBuilder.eq(CassandraEventDeadLettersTable.INSERTION_ID, bindMarker(CassandraEventDeadLettersTable.INSERTION_ID))));
     }
 
     private PreparedStatement prepareSelectInsertionIdsWithGroupStatement(Session session) {
-        return session.prepare(select(INSERTION_ID)
-            .from(TABLE_NAME)
-            .where(eq(GROUP, bindMarker(GROUP))));
+        return session.prepare(QueryBuilder.select(CassandraEventDeadLettersTable.INSERTION_ID)
+            .from(CassandraEventDeadLettersTable.TABLE_NAME)
+            .where(QueryBuilder.eq(CassandraEventDeadLettersTable.GROUP, bindMarker(CassandraEventDeadLettersTable.GROUP))));
     }
 
     private PreparedStatement prepareContainEventStatement(Session session) {
-        return session.prepare(select(EVENT)
-            .from(TABLE_NAME)
+        return session.prepare(QueryBuilder.select(CassandraEventDeadLettersTable.EVENT)
+            .from(CassandraEventDeadLettersTable.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)));
+                .setString(CassandraEventDeadLettersTable.GROUP, group.asString())
+                .setUUID(CassandraEventDeadLettersTable.INSERTION_ID, insertionId.getId())
+                .setString(CassandraEventDeadLettersTable.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()));
+                .setString(CassandraEventDeadLettersTable.GROUP, group.asString())
+                .setUUID(CassandraEventDeadLettersTable.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)));
+                .setString(CassandraEventDeadLettersTable.GROUP, group.asString())
+                .setUUID(CassandraEventDeadLettersTable.INSERTION_ID, insertionId.getId()))
+            .map(row -> deserializeEvent(row.getString(CassandraEventDeadLettersTable.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)));
+                .setString(CassandraEventDeadLettersTable.GROUP, group.asString()))
+            .map(row -> EventDeadLetters.InsertionId.of(row.getUUID(CassandraEventDeadLettersTable.INSERTION_ID)));
     }
 
     Mono<Boolean> containEvents() {
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/events/CassandraEventDeadLettersGroupDAO.java
similarity index 79%
copy from mailbox/event/event-cassandra/src/main/java/org/apache/james/mailbox/events/CassandraEventDeadLettersGroupDAO.java
copy to mailbox/event/event-cassandra/src/main/java/org/apache/james/events/CassandraEventDeadLettersGroupDAO.java
index bb37a3d..766d507 100644
--- 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/events/CassandraEventDeadLettersGroupDAO.java
@@ -17,20 +17,20 @@
  * under the License.                                           *
  ****************************************************************/
 
-package org.apache.james.mailbox.events;
+package org.apache.james.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.tables.CassandraEventDeadLettersGroupTable;
 
 import com.datastax.driver.core.PreparedStatement;
 import com.datastax.driver.core.Session;
+import com.datastax.driver.core.querybuilder.QueryBuilder;
 import com.github.fge.lambdas.Throwing;
 
 import reactor.core.publisher.Flux;
@@ -49,22 +49,22 @@ public class CassandraEventDeadLettersGroupDAO {
     }
 
     private PreparedStatement prepareInsertStatement(Session session) {
-        return session.prepare(insertInto(TABLE_NAME)
-            .value(GROUP, bindMarker(GROUP)));
+        return session.prepare(QueryBuilder.insertInto(CassandraEventDeadLettersGroupTable.TABLE_NAME)
+            .value(CassandraEventDeadLettersGroupTable.GROUP, bindMarker(CassandraEventDeadLettersGroupTable.GROUP)));
     }
 
     private PreparedStatement prepareSelectStatement(Session session) {
-        return session.prepare(select(GROUP)
-            .from(TABLE_NAME));
+        return session.prepare(QueryBuilder.select(CassandraEventDeadLettersGroupTable.GROUP)
+            .from(CassandraEventDeadLettersGroupTable.TABLE_NAME));
     }
 
     Mono<Void> storeGroup(Group group) {
         return executor.executeVoid(insertStatement.bind()
-                .setString(GROUP, group.asString()));
+                .setString(CassandraEventDeadLettersGroupTable.GROUP, group.asString()));
     }
 
     Flux<Group> retrieveAllGroups() {
         return executor.executeRows(selectAllStatement.bind())
-            .map(Throwing.function(row -> Group.deserialize(row.getString(GROUP))));
+            .map(Throwing.function(row -> Group.deserialize(row.getString(CassandraEventDeadLettersGroupTable.GROUP))));
     }
 }
diff --git a/mailbox/event/event-cassandra/src/main/java/org/apache/james/events/CassandraEventDeadLettersModule.java b/mailbox/event/event-cassandra/src/main/java/org/apache/james/events/CassandraEventDeadLettersModule.java
new file mode 100644
index 0000000..53053e8
--- /dev/null
+++ b/mailbox/event/event-cassandra/src/main/java/org/apache/james/events/CassandraEventDeadLettersModule.java
@@ -0,0 +1,46 @@
+/****************************************************************
+ * 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.events;
+
+import org.apache.james.backends.cassandra.components.CassandraModule;
+import org.apache.james.backends.cassandra.utils.CassandraConstants;
+import org.apache.james.events.tables.CassandraEventDeadLettersGroupTable;
+import org.apache.james.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/api/src/main/java/org/apache/james/mailbox/events/Registration.java b/mailbox/event/event-cassandra/src/main/java/org/apache/james/events/tables/CassandraEventDeadLettersGroupTable.java
similarity index 87%
rename from mailbox/api/src/main/java/org/apache/james/mailbox/events/Registration.java
rename to mailbox/event/event-cassandra/src/main/java/org/apache/james/events/tables/CassandraEventDeadLettersGroupTable.java
index c5a3a53..fff28aa 100644
--- a/mailbox/api/src/main/java/org/apache/james/mailbox/events/Registration.java
+++ b/mailbox/event/event-cassandra/src/main/java/org/apache/james/events/tables/CassandraEventDeadLettersGroupTable.java
@@ -17,8 +17,11 @@
  * under the License.                                           *
  ****************************************************************/
 
-package org.apache.james.mailbox.events;
+package org.apache.james.events.tables;
 
-public interface Registration {
-    void unregister();
+public interface CassandraEventDeadLettersGroupTable {
+
+    String TABLE_NAME = "group_table";
+
+    String GROUP = "group";
 }
diff --git a/mailbox/store/src/main/java/org/apache/james/mailbox/store/event/SpamEventListener.java b/mailbox/event/event-cassandra/src/main/java/org/apache/james/events/tables/CassandraEventDeadLettersTable.java
similarity index 83%
copy from mailbox/store/src/main/java/org/apache/james/mailbox/store/event/SpamEventListener.java
copy to mailbox/event/event-cassandra/src/main/java/org/apache/james/events/tables/CassandraEventDeadLettersTable.java
index 4e8e9c9..51cbef8 100644
--- a/mailbox/store/src/main/java/org/apache/james/mailbox/store/event/SpamEventListener.java
+++ b/mailbox/event/event-cassandra/src/main/java/org/apache/james/events/tables/CassandraEventDeadLettersTable.java
@@ -16,10 +16,14 @@
  * specific language governing permissions and limitations      *
  * under the License.                                           *
  ****************************************************************/
-package org.apache.james.mailbox.store.event;
 
-import org.apache.james.mailbox.events.MailboxListener;
+package org.apache.james.events.tables;
 
-public interface SpamEventListener extends MailboxListener.GroupMailboxListener {
+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/main/java/org/apache/james/mailbox/events/CassandraEventDeadLetters.java b/mailbox/event/event-cassandra/src/main/java/org/apache/james/mailbox/events/CassandraEventDeadLetters.java
index 97e4a8e..77a1c5e 100644
--- 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
@@ -21,6 +21,10 @@ 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;
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
index 7b62fc0..0d20d43 100644
--- 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
@@ -33,6 +33,9 @@ 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;
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
index bb37a3d..20b283e 100644
--- 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
@@ -28,6 +28,7 @@ import static org.apache.james.mailbox.events.tables.CassandraEventDeadLettersGr
 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;
diff --git a/mailbox/event/event-cassandra/src/test/java/org/apache/james/events/CassandraEventDeadLettersDAOTest.java b/mailbox/event/event-cassandra/src/test/java/org/apache/james/events/CassandraEventDeadLettersDAOTest.java
new file mode 100644
index 0000000..d6ba016
--- /dev/null
+++ b/mailbox/event/event-cassandra/src/test/java/org/apache/james/events/CassandraEventDeadLettersDAOTest.java
@@ -0,0 +1,137 @@
+/****************************************************************
+ * 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.events;
+
+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(EventDeadLettersContract.GROUP_A, EventDeadLettersContract.EVENT_1, EventDeadLettersContract.INSERTION_ID_1).block();
+
+        cassandraEventDeadLettersDAO.removeEvent(EventDeadLettersContract.GROUP_A, EventDeadLettersContract.INSERTION_ID_1).block();
+
+        assertThat(cassandraEventDeadLettersDAO
+                .retrieveInsertionIdsWithGroup(EventDeadLettersContract.GROUP_A)
+                .collectList().block())
+            .isEmpty();
+    }
+
+    @Test
+    void retrieveFailedEventShouldReturnEmptyWhenDefault() {
+        assertThat(cassandraEventDeadLettersDAO
+                .retrieveFailedEvent(EventDeadLettersContract.GROUP_A, EventDeadLettersContract.INSERTION_ID_1)
+                .blockOptional().isPresent())
+            .isFalse();
+    }
+
+    @Test
+    void retrieveFailedEventShouldReturnStoredEvent() {
+        cassandraEventDeadLettersDAO.store(EventDeadLettersContract.GROUP_A, EventDeadLettersContract.EVENT_1, EventDeadLettersContract.INSERTION_ID_1).block();
+        cassandraEventDeadLettersDAO.store(EventDeadLettersContract.GROUP_B, EventDeadLettersContract.EVENT_2, EventDeadLettersContract.INSERTION_ID_2).block();
+
+        assertThat(cassandraEventDeadLettersDAO
+                .retrieveFailedEvent(EventDeadLettersContract.GROUP_B, EventDeadLettersContract.INSERTION_ID_2)
+                .blockOptional().get())
+            .isEqualTo(EventDeadLettersContract.EVENT_2);
+    }
+
+    @Test
+    void retrieveInsertionIdsWithGroupShouldReturnEmptyWhenDefault() {
+        assertThat(cassandraEventDeadLettersDAO
+                .retrieveInsertionIdsWithGroup(EventDeadLettersContract.GROUP_A)
+                .collectList().block())
+            .isEmpty();
+    }
+
+    @Test
+    void retrieveInsertionIdsWithGroupShouldReturnStoredInsertionId() {
+        cassandraEventDeadLettersDAO.store(EventDeadLettersContract.GROUP_B, EventDeadLettersContract.EVENT_1, EventDeadLettersContract.INSERTION_ID_1).block();
+        cassandraEventDeadLettersDAO.store(EventDeadLettersContract.GROUP_B, EventDeadLettersContract.EVENT_2, EventDeadLettersContract.INSERTION_ID_2).block();
+        cassandraEventDeadLettersDAO.store(EventDeadLettersContract.GROUP_B, EventDeadLettersContract.EVENT_3, EventDeadLettersContract.INSERTION_ID_3).block();
+
+        assertThat(cassandraEventDeadLettersDAO
+                .retrieveInsertionIdsWithGroup(EventDeadLettersContract.GROUP_B)
+                .collectList().block())
+            .containsOnly(EventDeadLettersContract.INSERTION_ID_1, EventDeadLettersContract.INSERTION_ID_2, EventDeadLettersContract.INSERTION_ID_3);
+    }
+
+    @Test
+    void shouldReturnTrueWhenEventStored() {
+        cassandraEventDeadLettersDAO.store(EventDeadLettersContract.GROUP_B, EventDeadLettersContract.EVENT_1, EventDeadLettersContract.INSERTION_ID_1).block();
+        assertThat(cassandraEventDeadLettersDAO.containEvents().block()).isTrue();
+    }
+
+    @Test
+    void shouldReturnTrueWhenNoEventStored() {
+        assertThat(cassandraEventDeadLettersDAO.containEvents().block()).isFalse();
+    }
+
+    @Test
+    void shouldReturnTrueWhenEventsStoredAndRemovedSome() {
+        cassandraEventDeadLettersDAO.store(EventDeadLettersContract.GROUP_B, EventDeadLettersContract.EVENT_1, EventDeadLettersContract.INSERTION_ID_1).block();
+        cassandraEventDeadLettersDAO.store(EventDeadLettersContract.GROUP_B, EventDeadLettersContract.EVENT_1, EventDeadLettersContract.INSERTION_ID_2).block();
+        cassandraEventDeadLettersDAO.store(EventDeadLettersContract.GROUP_B, EventDeadLettersContract.EVENT_1, EventDeadLettersContract.INSERTION_ID_3).block();
+
+        assertThat(cassandraEventDeadLettersDAO.containEvents().block()).isTrue();
+
+        cassandraEventDeadLettersDAO.removeEvent(EventDeadLettersContract.GROUP_B, EventDeadLettersContract.INSERTION_ID_3).block();
+
+        assertThat(cassandraEventDeadLettersDAO.containEvents().block()).isTrue();
+    }
+
+    @Test
+    void shouldReturnFalseWhenRemovedAllEventsStored() {
+        cassandraEventDeadLettersDAO.store(EventDeadLettersContract.GROUP_B, EventDeadLettersContract.EVENT_1, EventDeadLettersContract.INSERTION_ID_1).block();
+        cassandraEventDeadLettersDAO.store(EventDeadLettersContract.GROUP_B, EventDeadLettersContract.EVENT_1, EventDeadLettersContract.INSERTION_ID_2).block();
+        cassandraEventDeadLettersDAO.store(EventDeadLettersContract.GROUP_B, EventDeadLettersContract.EVENT_1, EventDeadLettersContract.INSERTION_ID_3).block();
+
+        assertThat(cassandraEventDeadLettersDAO.containEvents().block()).isTrue();
+
+        cassandraEventDeadLettersDAO.removeEvent(EventDeadLettersContract.GROUP_B, EventDeadLettersContract.INSERTION_ID_3).block();
+        cassandraEventDeadLettersDAO.removeEvent(EventDeadLettersContract.GROUP_B, EventDeadLettersContract.INSERTION_ID_2).block();
+        cassandraEventDeadLettersDAO.removeEvent(EventDeadLettersContract.GROUP_B, EventDeadLettersContract.INSERTION_ID_1).block();
+
+        assertThat(cassandraEventDeadLettersDAO.containEvents().block()).isFalse();
+    }
+
+}
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/events/CassandraEventDeadLettersGroupDAOTest.java
similarity index 59%
copy from mailbox/event/event-cassandra/src/test/java/org/apache/james/mailbox/events/CassandraEventDeadLettersTest.java
copy to mailbox/event/event-cassandra/src/test/java/org/apache/james/events/CassandraEventDeadLettersGroupDAOTest.java
index 9930e9f..f5eef74 100644
--- 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/events/CassandraEventDeadLettersGroupDAOTest.java
@@ -17,33 +17,42 @@
  * under the License.                                           *
  ****************************************************************/
 
-package org.apache.james.mailbox.events;
+package org.apache.james.events;
+
+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.BeforeAll;
+import org.junit.jupiter.api.Test;
 import org.junit.jupiter.api.extension.RegisterExtension;
 
-class CassandraEventDeadLettersTest implements EventDeadLettersContract.AllContracts {
+public class CassandraEventDeadLettersGroupDAOTest {
 
     @RegisterExtension
     static CassandraClusterExtension cassandraClusterExtension = new CassandraClusterExtension(CassandraEventDeadLettersModule.MODULE);
 
-    private CassandraEventDeadLetters eventDeadLetters;
+    private static CassandraEventDeadLettersGroupDAO GROUP_DAO;
+
+    @BeforeAll
+    static void setUp(CassandraCluster cassandraCluster) {
+        GROUP_DAO = new CassandraEventDeadLettersGroupDAO(cassandraCluster.getConf());
+    }
 
-    @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()));
+    @Test
+    void retrieveAllGroupsShouldReturnEmptyWhenDefault() {
+        assertThat(GROUP_DAO.retrieveAllGroups()
+                .collectList().block())
+            .isEmpty();
     }
 
-    @Override
-    public EventDeadLetters eventDeadLetters() {
-        return eventDeadLetters;
+    @Test
+    void retrieveAllGroupsShouldReturnStoredGroups() {
+        GROUP_DAO.storeGroup(EventDeadLettersContract.GROUP_A).block();
+        GROUP_DAO.storeGroup(EventDeadLettersContract.GROUP_B).block();
+
+        assertThat(GROUP_DAO.retrieveAllGroups()
+                .collectList().block())
+            .containsOnly(EventDeadLettersContract.GROUP_A, EventDeadLettersContract.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/events/CassandraEventDeadLettersHealthCheckTest.java
similarity index 98%
copy from mailbox/event/event-cassandra/src/test/java/org/apache/james/mailbox/events/CassandraEventDeadLettersHealthCheckTest.java
copy to mailbox/event/event-cassandra/src/test/java/org/apache/james/events/CassandraEventDeadLettersHealthCheckTest.java
index cd8e7db..dce43af 100644
--- 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/events/CassandraEventDeadLettersHealthCheckTest.java
@@ -17,7 +17,7 @@
  * under the License.                                           *
  ****************************************************************/
 
-package org.apache.james.mailbox.events;
+package org.apache.james.events;
 
 import org.apache.james.backends.cassandra.CassandraCluster;
 import org.apache.james.backends.cassandra.CassandraClusterExtension;
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/events/CassandraEventDeadLettersTest.java
similarity index 98%
copy from mailbox/event/event-cassandra/src/test/java/org/apache/james/mailbox/events/CassandraEventDeadLettersTest.java
copy to mailbox/event/event-cassandra/src/test/java/org/apache/james/events/CassandraEventDeadLettersTest.java
index 9930e9f..2e3b85c 100644
--- 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/events/CassandraEventDeadLettersTest.java
@@ -17,7 +17,7 @@
  * under the License.                                           *
  ****************************************************************/
 
-package org.apache.james.mailbox.events;
+package org.apache.james.events;
 
 import org.apache.james.backends.cassandra.CassandraCluster;
 import org.apache.james.backends.cassandra.CassandraClusterExtension;
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
index cd8e7db..027ad73 100644
--- 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
@@ -23,6 +23,8 @@ 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;
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
index 9930e9f..7d81bcd 100644
--- 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
@@ -22,6 +22,7 @@ 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;
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
index 6e73b0f..1e92333 100644
--- 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
@@ -25,6 +25,15 @@ 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;
@@ -39,8 +48,8 @@ import reactor.core.publisher.Mono;
 
 public class InVMEventBus implements EventBus {
 
-    private final Multimap<RegistrationKey, MailboxListener.ReactiveMailboxListener> registrations;
-    private final ConcurrentHashMap<Group, MailboxListener.ReactiveMailboxListener> groups;
+    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;
@@ -55,14 +64,14 @@ public class InVMEventBus implements EventBus {
     }
 
     @Override
-    public Mono<Registration> register(MailboxListener.ReactiveMailboxListener listener, RegistrationKey key) {
+    public Mono<Registration> register(EventListener.ReactiveEventListener listener, RegistrationKey key) {
         registrations.put(key, listener);
         return Mono.just(() -> registrations.remove(key, listener));
     }
 
     @Override
-    public Registration register(MailboxListener.ReactiveMailboxListener listener, Group group) {
-        MailboxListener previous = groups.putIfAbsent(group, listener);
+    public Registration register(EventListener.ReactiveEventListener listener, Group group) {
+        EventListener previous = groups.putIfAbsent(group, listener);
         if (previous == null) {
             return () -> groups.remove(group, listener);
         }
@@ -87,7 +96,7 @@ public class InVMEventBus implements EventBus {
         return Mono.empty();
     }
 
-    private MailboxListener.ReactiveMailboxListener retrieveListenerFromGroup(Group group) {
+    private EventListener.ReactiveEventListener retrieveListenerFromGroup(Group group) {
         return Optional.ofNullable(groups.get(group))
             .orElseThrow(() -> new GroupRegistrationNotFound(group));
     }
@@ -104,7 +113,7 @@ public class InVMEventBus implements EventBus {
             .then();
     }
 
-    private Mono<Void> groupDelivery(Event event, MailboxListener.ReactiveMailboxListener mailboxListener, Group group) {
+    private Mono<Void> groupDelivery(Event event, EventListener.ReactiveEventListener mailboxListener, Group group) {
         return eventDelivery.deliver(
             mailboxListener,
             event,
@@ -117,7 +126,7 @@ public class InVMEventBus implements EventBus {
         return groups.keySet();
     }
 
-    private Set<MailboxListener.ReactiveMailboxListener> registeredListenersByKeys(Set<RegistrationKey> keys) {
+    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
index 5f8af25..b11e26f 100644
--- 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
@@ -19,6 +19,10 @@
 
 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;
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
index d0f06dd..c0038ca 100644
--- 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
@@ -22,10 +22,10 @@ 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.mailbox.events.Event;
-import org.apache.james.mailbox.events.EventDeadLetters;
-import org.apache.james.mailbox.events.Group;
-import org.apache.james.mailbox.events.MailboxListener;
+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;
@@ -69,16 +69,16 @@ public interface EventDelivery {
 
         class BackoffRetryer implements EventDelivery.Retryer {
 
-            public static BackoffRetryer of(RetryBackoffConfiguration retryBackoff, MailboxListener mailboxListener) {
+            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 MailboxListener mailboxListener;
+            private final EventListener mailboxListener;
 
-            public BackoffRetryer(RetryBackoffConfiguration retryBackoff, MailboxListener mailboxListener) {
+            public BackoffRetryer(RetryBackoffConfiguration retryBackoff, EventListener mailboxListener) {
                 this.retryBackoff = retryBackoff;
                 this.mailboxListener = mailboxListener;
             }
@@ -126,9 +126,9 @@ public interface EventDelivery {
         Mono<Void> handle(Event event);
     }
 
-    Mono<Void> deliver(MailboxListener.ReactiveMailboxListener listener, Event event, DeliveryOption option);
+    Mono<Void> deliver(EventListener.ReactiveEventListener listener, Event event, DeliveryOption option);
 
-    default Mono<Void> deliver(MailboxListener listener, Event event, DeliveryOption option) {
-        return deliver(MailboxListener.wrapReactive(listener), event, 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
index f4f7036..e8ed94c 100644
--- 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
@@ -19,14 +19,14 @@
 
 package org.apache.james.mailbox.events.delivery;
 
-import static org.apache.james.mailbox.events.EventBus.Metrics.timerName;
+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.mailbox.events.Event;
-import org.apache.james.mailbox.events.EventBus;
-import org.apache.james.mailbox.events.MailboxListener;
+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;
@@ -51,14 +51,14 @@ public class InVmEventDelivery implements EventDelivery {
     }
 
     @Override
-    public Mono<Void> deliver(MailboxListener.ReactiveMailboxListener listener, Event event, DeliveryOption option) {
+    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(MailboxListener.ExecutionMode executionMode, Mono<Void> executionResult) {
-        if (executionMode.equals(MailboxListener.ExecutionMode.SYNCHRONOUS)) {
+    private Mono<Void> waitForResultIfNeeded(EventListener.ExecutionMode executionMode, Mono<Void> executionResult) {
+        if (executionMode.equals(EventListener.ExecutionMode.SYNCHRONOUS)) {
             return executionResult;
         }
         return Flux.merge(executionResult, Mono.empty())
@@ -66,7 +66,7 @@ public class InVmEventDelivery implements EventDelivery {
             .onErrorResume(throwable -> Mono.empty());
     }
 
-    private Mono<Void> deliverByOption(MailboxListener.ReactiveMailboxListener listener, Event event, DeliveryOption deliveryOption) {
+    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)))
@@ -77,7 +77,7 @@ public class InVmEventDelivery implements EventDelivery {
             .then();
     }
 
-    private Mono<Void> doDeliverToListener(MailboxListener.ReactiveMailboxListener mailboxListener, Event event) {
+    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))))
@@ -86,7 +86,7 @@ public class InVmEventDelivery implements EventDelivery {
         return Mono.empty();
     }
 
-    private MDCBuilder buildMDC(MailboxListener mailboxListener, Event event) {
+    private MDCBuilder buildMDC(EventListener mailboxListener, Event event) {
         return MDCBuilder.create()
             .addContext(EventBus.StructuredLoggingFields.EVENT_ID, event.getEventId())
             .addContext(EventBus.StructuredLoggingFields.EVENT_CLASS, event.getClass())
@@ -94,7 +94,7 @@ public class InVmEventDelivery implements EventDelivery {
             .addContext(EventBus.StructuredLoggingFields.LISTENER_CLASS, mailboxListener.getClass());
     }
 
-    private StructuredLogger structuredLogger(Event event, MailboxListener mailboxListener) {
+    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())
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
index 5a6a6ea..c12963f 100644
--- 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
@@ -19,6 +19,8 @@
 
 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;
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
index c05deb0..58c4e7e 100644
--- 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
@@ -20,6 +20,8 @@
 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;
 
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
index 2ef0996..43ae3df 100644
--- 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
@@ -19,6 +19,7 @@
 
 package org.apache.james.mailbox.events;
 
+import org.apache.james.events.EventDeadLetters;
 import org.junit.jupiter.api.BeforeEach;
 
 class MemoryEventDeadLettersTest implements EventDeadLettersContract.AllContracts {
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
index dd210a9..72f779a 100644
--- 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
@@ -20,8 +20,8 @@
 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.EventBusTestFixture.MailboxListenerCountingSuccessfulExecution;
 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;
@@ -32,7 +32,7 @@ import static org.mockito.Mockito.when;
 
 import java.time.Duration;
 
-import org.apache.james.mailbox.events.MailboxListener;
+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;
@@ -46,7 +46,7 @@ import org.junit.jupiter.api.Test;
 
 class InVmEventDeliveryTest {
     private InVmEventDelivery inVmEventDelivery;
-    private MailboxListenerCountingSuccessfulExecution listener;
+    private EventListenerCountingSuccessfulExecution listener;
 
     @BeforeEach
     void setUp() {
@@ -54,8 +54,8 @@ class InVmEventDeliveryTest {
         inVmEventDelivery = new InVmEventDelivery(new RecordingMetricFactory());
     }
 
-    MailboxListenerCountingSuccessfulExecution newListener() {
-        return spy(new MailboxListenerCountingSuccessfulExecution());
+    EventListenerCountingSuccessfulExecution newListener() {
+        return spy(new EventListenerCountingSuccessfulExecution());
     }
 
     @Nested
@@ -63,7 +63,7 @@ class InVmEventDeliveryTest {
 
         @Test
         void deliverShouldDeliverEvent() {
-            when(listener.getExecutionMode()).thenReturn(MailboxListener.ExecutionMode.SYNCHRONOUS);
+            when(listener.getExecutionMode()).thenReturn(EventListener.ExecutionMode.SYNCHRONOUS);
             inVmEventDelivery.deliver(listener, EVENT, DeliveryOption.none())
                 .block();
 
@@ -73,7 +73,7 @@ class InVmEventDeliveryTest {
 
         @Test
         void deliverShouldReturnSuccessSynchronousMono() {
-            when(listener.getExecutionMode()).thenReturn(MailboxListener.ExecutionMode.SYNCHRONOUS);
+            when(listener.getExecutionMode()).thenReturn(EventListener.ExecutionMode.SYNCHRONOUS);
             assertThatCode(() -> inVmEventDelivery.deliver(listener, EVENT, DeliveryOption.none())
                     .block())
                 .doesNotThrowAnyException();
@@ -81,7 +81,7 @@ class InVmEventDeliveryTest {
 
         @Test
         void deliverShouldNotDeliverWhenListenerGetException() {
-            when(listener.getExecutionMode()).thenReturn(MailboxListener.ExecutionMode.SYNCHRONOUS);
+            when(listener.getExecutionMode()).thenReturn(EventListener.ExecutionMode.SYNCHRONOUS);
             doThrow(new RuntimeException())
                 .when(listener).event(EVENT);
 
@@ -95,7 +95,7 @@ class InVmEventDeliveryTest {
 
         @Test
         void deliverShouldReturnAnErrorMonoWhenListenerGetException() {
-            when(listener.getExecutionMode()).thenReturn(MailboxListener.ExecutionMode.SYNCHRONOUS);
+            when(listener.getExecutionMode()).thenReturn(EventListener.ExecutionMode.SYNCHRONOUS);
             doThrow(new RuntimeException())
                 .when(listener).event(EVENT);
 
@@ -110,7 +110,7 @@ class InVmEventDeliveryTest {
 
         @Test
         void deliverShouldDeliverEvent() {
-            when(listener.getExecutionMode()).thenReturn(MailboxListener.ExecutionMode.ASYNCHRONOUS);
+            when(listener.getExecutionMode()).thenReturn(EventListener.ExecutionMode.ASYNCHRONOUS);
             inVmEventDelivery.deliver(listener, EVENT, DeliveryOption.none())
                 .block();
 
@@ -120,7 +120,7 @@ class InVmEventDeliveryTest {
 
         @Test
         void deliverShouldReturnSuccessSynchronousMono() {
-            when(listener.getExecutionMode()).thenReturn(MailboxListener.ExecutionMode.ASYNCHRONOUS);
+            when(listener.getExecutionMode()).thenReturn(EventListener.ExecutionMode.ASYNCHRONOUS);
             assertThatCode(() -> inVmEventDelivery.deliver(listener, EVENT, DeliveryOption.none())
                     .block())
                 .doesNotThrowAnyException();
@@ -128,7 +128,7 @@ class InVmEventDeliveryTest {
 
         @Test
         void deliverShouldNotFailWhenListenerGetException() {
-            when(listener.getExecutionMode()).thenReturn(MailboxListener.ExecutionMode.ASYNCHRONOUS);
+            when(listener.getExecutionMode()).thenReturn(EventListener.ExecutionMode.ASYNCHRONOUS);
             doThrow(new RuntimeException())
                 .when(listener).event(EVENT);
 
@@ -139,7 +139,7 @@ class InVmEventDeliveryTest {
 
         @Test
         void deliverShouldReturnAnSuccessSyncMonoWhenListenerGetException() {
-            when(listener.getExecutionMode()).thenReturn(MailboxListener.ExecutionMode.ASYNCHRONOUS);
+            when(listener.getExecutionMode()).thenReturn(EventListener.ExecutionMode.ASYNCHRONOUS);
             doThrow(new RuntimeException())
                 .when(listener).event(EVENT);
 
@@ -154,7 +154,7 @@ class InVmEventDeliveryTest {
 
         @Test
         void retryShouldWorkWhenDeliverWithRetry() {
-            MailboxListenerCountingSuccessfulExecution listener = newListener();
+            EventListenerCountingSuccessfulExecution listener = newListener();
             doThrow(new RuntimeException())
                 .doThrow(new RuntimeException())
                 .doThrow(new RuntimeException())
@@ -173,7 +173,7 @@ class InVmEventDeliveryTest {
 
         @Test
         void failureHandlerShouldWorkWhenDeliverWithFailureHandler() {
-            MailboxListenerCountingSuccessfulExecution listener = newListener();
+            EventListenerCountingSuccessfulExecution listener = newListener();
             doThrow(new RuntimeException())
                 .when(listener).event(EVENT);
 
@@ -191,7 +191,7 @@ class InVmEventDeliveryTest {
 
         @Test
         void failureHandlerShouldNotWorkWhenRetrySuccess() {
-            MailboxListenerCountingSuccessfulExecution listener = newListener();
+            EventListenerCountingSuccessfulExecution listener = newListener();
             doThrow(new RuntimeException())
                 .doThrow(new RuntimeException())
                 .doCallRealMethod()
@@ -216,7 +216,7 @@ class InVmEventDeliveryTest {
 
         @Test
         void failureHandlerShouldWorkWhenRetryFails() {
-            MailboxListenerCountingSuccessfulExecution listener = newListener();
+            EventListenerCountingSuccessfulExecution listener = newListener();
             //do throw  RetryBackoffConfiguration.DEFAULT.DEFAULT_MAX_RETRIES + 1 times
             doThrow(new RuntimeException())
                 .doThrow(new RuntimeException())
diff --git a/mailbox/api/src/main/java/org/apache/james/mailbox/events/GenericGroup.java b/mailbox/event/event-rabbitmq/src/main/java/org/apache/james/events/EventBusId.java
similarity index 58%
rename from mailbox/api/src/main/java/org/apache/james/mailbox/events/GenericGroup.java
rename to mailbox/event/event-rabbitmq/src/main/java/org/apache/james/events/EventBusId.java
index a679682..53f9d2c 100644
--- a/mailbox/api/src/main/java/org/apache/james/mailbox/events/GenericGroup.java
+++ b/mailbox/event/event-rabbitmq/src/main/java/org/apache/james/events/EventBusId.java
@@ -17,35 +17,56 @@
  * under the License.                                           *
  ****************************************************************/
 
-package org.apache.james.mailbox.events;
+package org.apache.james.events;
 
 import java.util.Objects;
+import java.util.UUID;
 
-public class GenericGroup extends Group {
-    static final String DELIMITER = "-";
-    private final String groupName;
+import com.google.common.base.MoreObjects;
+import com.google.common.base.Preconditions;
 
-    public GenericGroup(String groupName) {
-        this.groupName = groupName;
+public class EventBusId {
+    public static EventBusId of(UUID uuid) {
+        return new EventBusId(uuid);
     }
 
-    @Override
-    public String asString() {
-        return super.asString() + DELIMITER + groupName;
+    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 GenericGroup) {
-            GenericGroup that = (GenericGroup) o;
-
-            return Objects.equals(this.groupName, that.groupName);
+        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 final int hashCode() {
-        return Objects.hash(groupName);
+    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/events/EventDispatcher.java
similarity index 92%
copy from mailbox/event/event-rabbitmq/src/main/java/org/apache/james/mailbox/events/EventDispatcher.java
copy to mailbox/event/event-rabbitmq/src/main/java/org/apache/james/events/EventDispatcher.java
index af13994..99d0a7d 100644
--- 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/events/EventDispatcher.java
@@ -17,7 +17,7 @@
  * under the License.                                           *
  ****************************************************************/
 
-package org.apache.james.mailbox.events;
+package org.apache.james.events;
 
 import static com.rabbitmq.client.MessageProperties.PERSISTENT_TEXT_PLAIN;
 import static org.apache.james.backends.rabbitmq.Constants.AUTO_DELETE;
@@ -26,10 +26,10 @@ 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 static org.apache.james.events.RabbitMQEventBus.EVENT_BUS_ID;
+import static org.apache.james.events.RabbitMQEventBus.MAILBOX_EVENT_DEAD_LETTER_EXCHANGE_NAME;
+import static org.apache.james.events.RabbitMQEventBus.MAILBOX_EVENT_DEAD_LETTER_QUEUE;
+import static org.apache.james.events.RabbitMQEventBus.MAILBOX_EVENT_EXCHANGE_NAME;
 
 import java.nio.charset.StandardCharsets;
 import java.util.Collection;
@@ -37,7 +37,7 @@ import java.util.Collections;
 import java.util.Set;
 
 import org.apache.james.event.json.EventSerializer;
-import org.apache.james.mailbox.events.RoutingKeyConverter.RoutingKey;
+import org.apache.james.events.RoutingKeyConverter.RoutingKey;
 import org.apache.james.util.MDCBuilder;
 import org.apache.james.util.MDCStructuredLogger;
 import org.apache.james.util.StructuredLogger;
@@ -125,12 +125,12 @@ public class EventDispatcher {
         return Flux.fromIterable(keys)
             .flatMap(key -> localListenerRegistry.getLocalMailboxListeners(key)
                 .map(listener -> Tuples.of(key, listener)), EventBus.EXECUTION_RATE)
-            .filter(pair -> pair.getT2().getExecutionMode() == MailboxListener.ExecutionMode.SYNCHRONOUS)
+            .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, MailboxListener.ReactiveMailboxListener mailboxListener, RegistrationKey registrationKey) {
+    private Mono<Void> executeListener(Event event, EventListener.ReactiveEventListener mailboxListener, RegistrationKey registrationKey) {
         return mailboxListenerExecutor.execute(mailboxListener,
                     MDCBuilder.create()
                         .addContext(EventBus.StructuredLoggingFields.REGISTRATION_KEY, registrationKey),
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/events/GroupConsumerRetry.java
similarity index 96%
copy from mailbox/event/event-rabbitmq/src/main/java/org/apache/james/mailbox/events/GroupConsumerRetry.java
copy to mailbox/event/event-rabbitmq/src/main/java/org/apache/james/events/GroupConsumerRetry.java
index 8286d30..b8526f8 100644
--- 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/events/GroupConsumerRetry.java
@@ -17,14 +17,13 @@
  * under the License.                                           *
  ****************************************************************/
 
-package org.apache.james.mailbox.events;
+package org.apache.james.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 static org.apache.james.events.GroupRegistration.RETRY_COUNT;
 
 import java.nio.charset.StandardCharsets;
 
@@ -53,7 +52,7 @@ class GroupConsumerRetry {
             return new RetryExchangeName(group.asString());
         }
 
-        static final String MAILBOX_EVENT_RETRY_EXCHANGE_PREFIX = MAILBOX_EVENT + "-retryExchange-";
+        static final String MAILBOX_EVENT_RETRY_EXCHANGE_PREFIX = RabbitMQEventBus.MAILBOX_EVENT + "-retryExchange-";
 
         private final String name;
 
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/events/GroupRegistration.java
similarity index 91%
copy from mailbox/event/event-rabbitmq/src/main/java/org/apache/james/mailbox/events/GroupRegistration.java
copy to mailbox/event/event-rabbitmq/src/main/java/org/apache/james/events/GroupRegistration.java
index 7d80a82..5c6285c 100644
--- 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/events/GroupRegistration.java
@@ -17,7 +17,7 @@
  * under the License.                                           *
  ****************************************************************/
 
-package org.apache.james.mailbox.events;
+package org.apache.james.events;
 
 import static org.apache.james.backends.rabbitmq.Constants.AUTO_DELETE;
 import static org.apache.james.backends.rabbitmq.Constants.DURABLE;
@@ -25,9 +25,6 @@ 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;
@@ -60,7 +57,7 @@ class GroupRegistration implements Registration {
             return new WorkQueueName(group);
         }
 
-        static final String MAILBOX_EVENT_WORK_QUEUE_PREFIX = MAILBOX_EVENT + "-workQueue-";
+        static final String MAILBOX_EVENT_WORK_QUEUE_PREFIX = RabbitMQEventBus.MAILBOX_EVENT + "-workQueue-";
 
         private final Group group;
 
@@ -79,7 +76,7 @@ class GroupRegistration implements Registration {
     static final int DEFAULT_RETRY_COUNT = 0;
 
     private final ReactorRabbitMQChannelPool channelPool;
-    private final MailboxListener.ReactiveMailboxListener mailboxListener;
+    private final EventListener.ReactiveEventListener mailboxListener;
     private final WorkQueueName queueName;
     private final Receiver receiver;
     private final Runnable unregisterGroup;
@@ -93,7 +90,7 @@ class GroupRegistration implements Registration {
     private Optional<Disposable> receiverSubscriber;
 
     GroupRegistration(ReactorRabbitMQChannelPool channelPool, Sender sender, ReceiverProvider receiverProvider, EventSerializer eventSerializer,
-                      MailboxListener.ReactiveMailboxListener mailboxListener, Group group, RetryBackoffConfiguration retryBackoff,
+                      EventListener.ReactiveEventListener mailboxListener, Group group, RetryBackoffConfiguration retryBackoff,
                       EventDeadLetters eventDeadLetters,
                       Runnable unregisterGroup, MailboxListenerExecutor mailboxListenerExecutor) {
         this.channelPool = channelPool;
@@ -127,9 +124,9 @@ class GroupRegistration implements Registration {
                 .durable(DURABLE)
                 .exclusive(!EXCLUSIVE)
                 .autoDelete(!AUTO_DELETE)
-                .arguments(deadLetterQueue(MAILBOX_EVENT_DEAD_LETTER_EXCHANGE_NAME)),
+                .arguments(deadLetterQueue(RabbitMQEventBus.MAILBOX_EVENT_DEAD_LETTER_EXCHANGE_NAME)),
             BindingSpecification.binding()
-                .exchange(MAILBOX_EVENT_EXCHANGE_NAME)
+                .exchange(RabbitMQEventBus.MAILBOX_EVENT_EXCHANGE_NAME)
                 .queue(queueName.asString())
                 .routingKey(EMPTY_ROUTING_KEY));
     }
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/events/GroupRegistrationHandler.java
similarity index 93%
copy from mailbox/event/event-rabbitmq/src/main/java/org/apache/james/mailbox/events/GroupRegistrationHandler.java
copy to mailbox/event/event-rabbitmq/src/main/java/org/apache/james/events/GroupRegistrationHandler.java
index 251b375..c4f7814 100644
--- 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/events/GroupRegistrationHandler.java
@@ -17,7 +17,7 @@
  * under the License.                                           *
  ****************************************************************/
 
-package org.apache.james.mailbox.events;
+package org.apache.james.events;
 
 import java.util.Map;
 import java.util.Optional;
@@ -61,7 +61,7 @@ class GroupRegistrationHandler {
         groupRegistrations.values().forEach(GroupRegistration::unregister);
     }
 
-    Registration register(MailboxListener.ReactiveMailboxListener listener, Group group) {
+    Registration register(EventListener.ReactiveEventListener listener, Group group) {
         return groupRegistrations
             .compute(group, (groupToRegister, oldGroupRegistration) -> {
                 if (oldGroupRegistration != null) {
@@ -72,7 +72,7 @@ class GroupRegistrationHandler {
             .start();
     }
 
-    private GroupRegistration newGroupRegistration(MailboxListener.ReactiveMailboxListener listener, Group group) {
+    private GroupRegistration newGroupRegistration(EventListener.ReactiveEventListener listener, Group group) {
         return new GroupRegistration(
             channelPool, sender,
             receiverProvider,
diff --git a/mailbox/api/src/main/java/org/apache/james/mailbox/events/EventDeadLettersHealthCheck.java b/mailbox/event/event-rabbitmq/src/main/java/org/apache/james/events/KeyReconnectionHandler.java
similarity index 50%
rename from mailbox/api/src/main/java/org/apache/james/mailbox/events/EventDeadLettersHealthCheck.java
rename to mailbox/event/event-rabbitmq/src/main/java/org/apache/james/events/KeyReconnectionHandler.java
index 27d33d6..24b5dd1 100644
--- a/mailbox/api/src/main/java/org/apache/james/mailbox/events/EventDeadLettersHealthCheck.java
+++ b/mailbox/event/event-rabbitmq/src/main/java/org/apache/james/events/KeyReconnectionHandler.java
@@ -17,41 +17,42 @@
  * under the License.                                           *
  ****************************************************************/
 
-package org.apache.james.mailbox.events;
+package org.apache.james.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 javax.inject.Inject;
 
-import org.apache.james.core.healthcheck.ComponentName;
-import org.apache.james.core.healthcheck.HealthCheck;
-import org.apache.james.core.healthcheck.Result;
+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 EventDeadLettersHealthCheck implements HealthCheck {
-    private static final ComponentName COMPONENT_NAME = new ComponentName("EventDeadLettersHealthCheck");
+public class KeyReconnectionHandler implements SimpleConnectionPool.ReconnectionHandler {
+    private static final Logger LOGGER = LoggerFactory.getLogger(KeyReconnectionHandler.class);
 
-    private final EventDeadLetters eventDeadLetters;
+    private final EventBusId eventBusId;
 
     @Inject
-    EventDeadLettersHealthCheck(EventDeadLetters eventDeadLetters) {
-        this.eventDeadLetters = eventDeadLetters;
-    }
-
-    @Override
-    public ComponentName componentName() {
-        return COMPONENT_NAME;
+    public KeyReconnectionHandler(EventBusId eventBusId) {
+        this.eventBusId = eventBusId;
     }
 
     @Override
-    public Mono<Result> check() {
-        return eventDeadLetters.containEvents()
-            .map(containEvents -> {
-                if (containEvents) {
-                    return Result.degraded(COMPONENT_NAME, "EventDeadLetters contain events. This might indicate transient failure on mailbox event processing.");
-                }
-
-                return Result.healthy(COMPONENT_NAME);
-            })
-            .onErrorResume(e -> Mono.just(Result.unhealthy(COMPONENT_NAME, "Error checking EventDeadLettersHealthCheck", e)));
+    public Publisher<Void> handleReconnection(Connection connection) {
+        return Mono.fromRunnable(() -> {
+            try (Channel channel = connection.createChannel()) {
+                channel.queueDeclare(KeyRegistrationHandler.EVENTBUS_QUEUE_NAME_PREFIX + eventBusId.asString(), DURABLE, !EXCLUSIVE, AUTO_DELETE, KeyRegistrationHandler.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/events/KeyRegistration.java
similarity index 94%
copy from mailbox/event/event-rabbitmq/src/main/java/org/apache/james/mailbox/events/KeyRegistration.java
copy to mailbox/event/event-rabbitmq/src/main/java/org/apache/james/events/KeyRegistration.java
index 8dd002d..b7d6c28 100644
--- 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/events/KeyRegistration.java
@@ -17,7 +17,9 @@
  * under the License.                                           *
  ****************************************************************/
 
-package org.apache.james.mailbox.events;
+package org.apache.james.events;
+
+import org.apache.james.events.Registration;
 
 class KeyRegistration implements Registration {
     private final Runnable unregister;
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/events/KeyRegistrationHandler.java
similarity index 95%
copy from mailbox/event/event-rabbitmq/src/main/java/org/apache/james/mailbox/events/KeyRegistrationHandler.java
copy to mailbox/event/event-rabbitmq/src/main/java/org/apache/james/events/KeyRegistrationHandler.java
index f4d1de5..be06184 100644
--- 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/events/KeyRegistrationHandler.java
@@ -17,12 +17,12 @@
  * under the License.                                           *
  ****************************************************************/
 
-package org.apache.james.mailbox.events;
+package org.apache.james.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 static org.apache.james.events.RabbitMQEventBus.EVENT_BUS_ID;
 
 import java.nio.charset.StandardCharsets;
 import java.time.Duration;
@@ -127,7 +127,7 @@ class KeyRegistrationHandler {
         receiver.close();
     }
 
-    Mono<Registration> register(MailboxListener.ReactiveMailboxListener listener, RegistrationKey key) {
+    Mono<Registration> register(EventListener.ReactiveEventListener listener, RegistrationKey key) {
         LocalListenerRegistry.LocalRegistration registration = localListenerRegistry.addListener(key, listener);
 
         return registerIfNeeded(key, registration)
@@ -169,7 +169,7 @@ class KeyRegistrationHandler {
             .then();
     }
 
-    private Mono<Void> executeListener(MailboxListener.ReactiveMailboxListener listener, Event event, RegistrationKey key) {
+    private Mono<Void> executeListener(EventListener.ReactiveEventListener listener, Event event, RegistrationKey key) {
         MDCBuilder mdcBuilder = MDCBuilder.create()
             .addContext(EventBus.StructuredLoggingFields.REGISTRATION_KEY, key);
 
@@ -180,9 +180,9 @@ class KeyRegistrationHandler {
             .then();
     }
 
-    private boolean isLocalSynchronousListeners(EventBusId eventBusId, MailboxListener listener) {
+    private boolean isLocalSynchronousListeners(EventBusId eventBusId, EventListener listener) {
         return eventBusId.equals(this.eventBusId) &&
-            listener.getExecutionMode().equals(MailboxListener.ExecutionMode.SYNCHRONOUS);
+            listener.getExecutionMode().equals(EventListener.ExecutionMode.SYNCHRONOUS);
     }
 
     private Event toEvent(Delivery delivery) {
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/events/LocalListenerRegistry.java
similarity index 77%
copy from mailbox/event/event-rabbitmq/src/main/java/org/apache/james/mailbox/events/LocalListenerRegistry.java
copy to mailbox/event/event-rabbitmq/src/main/java/org/apache/james/events/LocalListenerRegistry.java
index a76302d..05306ae 100644
--- 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/events/LocalListenerRegistry.java
@@ -17,7 +17,7 @@
  * under the License.                                           *
  ****************************************************************/
 
-package org.apache.james.mailbox.events;
+package org.apache.james.events;
 
 import static com.google.common.base.Predicates.not;
 
@@ -26,6 +26,9 @@ 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;
 
@@ -55,17 +58,17 @@ class LocalListenerRegistry {
         }
     }
 
-    private final ConcurrentHashMap<RegistrationKey, ImmutableSet<MailboxListener.ReactiveMailboxListener>> listenersByKey;
+    private final ConcurrentHashMap<RegistrationKey, ImmutableSet<EventListener.ReactiveEventListener>> listenersByKey;
 
     LocalListenerRegistry() {
         this.listenersByKey = new ConcurrentHashMap<>();
     }
 
-    LocalRegistration addListener(RegistrationKey registrationKey, MailboxListener.ReactiveMailboxListener listener) {
+    LocalRegistration addListener(RegistrationKey registrationKey, EventListener.ReactiveEventListener listener) {
         AtomicBoolean firstListener = new AtomicBoolean(false);
         listenersByKey.compute(registrationKey, (key, listeners) ->
             Optional.ofNullable(listeners)
-                .map(set -> ImmutableSet.<MailboxListener.ReactiveMailboxListener>builder().addAll(set).add(listener).build())
+                .map(set -> ImmutableSet.<EventListener.ReactiveEventListener>builder().addAll(set).add(listener).build())
                 .orElseGet(() -> {
                     firstListener.set(true);
                     return ImmutableSet.of(listener);
@@ -74,16 +77,16 @@ class LocalListenerRegistry {
         return new LocalRegistration(firstListener.get(), () -> removeListener(registrationKey, listener));
     }
 
-    LocalRegistration addListener(RegistrationKey registrationKey, MailboxListener listener) {
-        return addListener(registrationKey, MailboxListener.wrapReactive(listener));
+    LocalRegistration addListener(RegistrationKey registrationKey, EventListener listener) {
+        return addListener(registrationKey, EventListener.wrapReactive(listener));
     }
 
-    private RemovalStatus removeListener(RegistrationKey registrationKey, MailboxListener.ReactiveMailboxListener 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<MailboxListener.ReactiveMailboxListener> remainingListeners = removeListenerFromSet(listener, listeners);
+                ImmutableSet<EventListener.ReactiveEventListener> remainingListeners = removeListenerFromSet(listener, listeners);
                 if (remainingListeners.isEmpty()) {
                     lastListenerRemoved.set(true);
                     return null;
@@ -95,15 +98,15 @@ class LocalListenerRegistry {
         return lastListenerRemoved::get;
     }
 
-    private ImmutableSet<MailboxListener.ReactiveMailboxListener> removeListenerFromSet(MailboxListener listener, ImmutableSet<MailboxListener.ReactiveMailboxListener> listeners) {
-        ImmutableSet<MailboxListener.ReactiveMailboxListener> remainingListeners = listeners.stream().filter(not(listener::equals)).collect(Guavate.toImmutableSet());
+    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<MailboxListener.ReactiveMailboxListener> getLocalMailboxListeners(RegistrationKey registrationKey) {
+    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/events/MailboxListenerExecutor.java
similarity index 84%
copy from mailbox/event/event-rabbitmq/src/main/java/org/apache/james/mailbox/events/MailboxListenerExecutor.java
copy to mailbox/event/event-rabbitmq/src/main/java/org/apache/james/events/MailboxListenerExecutor.java
index deb0098..7b6afef 100644
--- 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/events/MailboxListenerExecutor.java
@@ -17,10 +17,13 @@
  * under the License.                                           *
  ****************************************************************/
 
-package org.apache.james.mailbox.events;
+package org.apache.james.events;
 
-import static org.apache.james.mailbox.events.EventBus.Metrics.timerName;
+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;
@@ -34,7 +37,7 @@ class MailboxListenerExecutor {
         this.metricFactory = metricFactory;
     }
 
-    Mono<Void> execute(MailboxListener.ReactiveMailboxListener listener, MDCBuilder mdcBuilder, Event event) {
+    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))
@@ -43,7 +46,7 @@ class MailboxListenerExecutor {
         return Mono.empty();
     }
 
-    private MDCBuilder mdc(MailboxListener listener, MDCBuilder mdcBuilder, Event event) {
+    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())
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/events/RabbitMQEventBus.java
similarity index 96%
copy from mailbox/event/event-rabbitmq/src/main/java/org/apache/james/mailbox/events/RabbitMQEventBus.java
copy to mailbox/event/event-rabbitmq/src/main/java/org/apache/james/events/RabbitMQEventBus.java
index eff6278..73a2209 100644
--- 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/events/RabbitMQEventBus.java
@@ -17,7 +17,7 @@
  * under the License.                                           *
  ****************************************************************/
 
-package org.apache.james.mailbox.events;
+package org.apache.james.events;
 
 import java.util.Set;
 
@@ -127,13 +127,13 @@ public class RabbitMQEventBus implements EventBus, Startable {
     }
 
     @Override
-    public Mono<Registration> register(MailboxListener.ReactiveMailboxListener listener, RegistrationKey key) {
+    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(MailboxListener.ReactiveMailboxListener listener, Group group) {
+    public Registration register(EventListener.ReactiveEventListener listener, Group group) {
         Preconditions.checkState(isRunning, NOT_RUNNING_ERROR_MESSAGE);
         return groupRegistrationHandler.register(listener, group);
     }
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/events/RegistrationBinder.java
similarity index 94%
copy from mailbox/event/event-rabbitmq/src/main/java/org/apache/james/mailbox/events/RegistrationBinder.java
copy to mailbox/event/event-rabbitmq/src/main/java/org/apache/james/events/RegistrationBinder.java
index f4405a6..45fbd49 100644
--- 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/events/RegistrationBinder.java
@@ -17,9 +17,9 @@
  * under the License.                                           *
  ****************************************************************/
 
-package org.apache.james.mailbox.events;
+package org.apache.james.events;
 
-import static org.apache.james.mailbox.events.RabbitMQEventBus.MAILBOX_EVENT_EXCHANGE_NAME;
+import static org.apache.james.events.RabbitMQEventBus.MAILBOX_EVENT_EXCHANGE_NAME;
 
 import reactor.core.publisher.Mono;
 import reactor.rabbitmq.BindingSpecification;
diff --git a/mailbox/api/src/main/java/org/apache/james/mailbox/events/RegistrationKey.java b/mailbox/event/event-rabbitmq/src/main/java/org/apache/james/events/RegistrationQueueName.java
similarity index 83%
rename from mailbox/api/src/main/java/org/apache/james/mailbox/events/RegistrationKey.java
rename to mailbox/event/event-rabbitmq/src/main/java/org/apache/james/events/RegistrationQueueName.java
index 1d0e320..9da51a4 100644
--- a/mailbox/api/src/main/java/org/apache/james/mailbox/events/RegistrationKey.java
+++ b/mailbox/event/event-rabbitmq/src/main/java/org/apache/james/events/RegistrationQueueName.java
@@ -17,15 +17,16 @@
  * under the License.                                           *
  ****************************************************************/
 
-package org.apache.james.mailbox.events;
+package org.apache.james.events;
 
-public interface RegistrationKey {
+class RegistrationQueueName {
+    private final String queueName;
 
-    interface Factory {
-        Class<? extends RegistrationKey> forClass();
-
-        RegistrationKey fromString(String asString);
+    RegistrationQueueName(String queueName) {
+        this.queueName = queueName;
     }
 
-    String asString();
+    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/events/RoutingKeyConverter.java
similarity index 98%
copy from mailbox/event/event-rabbitmq/src/main/java/org/apache/james/mailbox/events/RoutingKeyConverter.java
copy to mailbox/event/event-rabbitmq/src/main/java/org/apache/james/events/RoutingKeyConverter.java
index bf84ec1..79c6500 100644
--- 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/events/RoutingKeyConverter.java
@@ -17,7 +17,7 @@
  * under the License.                                           *
  ****************************************************************/
 
-package org.apache.james.mailbox.events;
+package org.apache.james.events;
 
 import static org.apache.james.backends.rabbitmq.Constants.EMPTY_ROUTING_KEY;
 
diff --git a/mailbox/event/event-rabbitmq/src/main/java/org/apache/james/events/WaitDelayGenerator.java b/mailbox/event/event-rabbitmq/src/main/java/org/apache/james/events/WaitDelayGenerator.java
new file mode 100644
index 0000000..01e604d
--- /dev/null
+++ b/mailbox/event/event-rabbitmq/src/main/java/org/apache/james/events/WaitDelayGenerator.java
@@ -0,0 +1,83 @@
+/****************************************************************
+ * 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.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/main/java/org/apache/james/mailbox/events/EventDispatcher.java b/mailbox/event/event-rabbitmq/src/main/java/org/apache/james/mailbox/events/EventDispatcher.java
index af13994..e7d1e62 100644
--- 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
@@ -37,6 +37,12 @@ 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;
@@ -125,12 +131,12 @@ public class EventDispatcher {
         return Flux.fromIterable(keys)
             .flatMap(key -> localListenerRegistry.getLocalMailboxListeners(key)
                 .map(listener -> Tuples.of(key, listener)), EventBus.EXECUTION_RATE)
-            .filter(pair -> pair.getT2().getExecutionMode() == MailboxListener.ExecutionMode.SYNCHRONOUS)
+            .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, MailboxListener.ReactiveMailboxListener mailboxListener, RegistrationKey registrationKey) {
+    private Mono<Void> executeListener(Event event, EventListener.ReactiveEventListener mailboxListener, RegistrationKey registrationKey) {
         return mailboxListenerExecutor.execute(mailboxListener,
                     MDCBuilder.create()
                         .addContext(EventBus.StructuredLoggingFields.REGISTRATION_KEY, registrationKey),
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
index 8286d30..d74cc64 100644
--- 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
@@ -29,6 +29,10 @@ 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;
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
index 7d80a82..e07d6a7 100644
--- 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
@@ -37,6 +37,12 @@ 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;
@@ -79,7 +85,7 @@ class GroupRegistration implements Registration {
     static final int DEFAULT_RETRY_COUNT = 0;
 
     private final ReactorRabbitMQChannelPool channelPool;
-    private final MailboxListener.ReactiveMailboxListener mailboxListener;
+    private final EventListener.ReactiveEventListener mailboxListener;
     private final WorkQueueName queueName;
     private final Receiver receiver;
     private final Runnable unregisterGroup;
@@ -93,7 +99,7 @@ class GroupRegistration implements Registration {
     private Optional<Disposable> receiverSubscriber;
 
     GroupRegistration(ReactorRabbitMQChannelPool channelPool, Sender sender, ReceiverProvider receiverProvider, EventSerializer eventSerializer,
-                      MailboxListener.ReactiveMailboxListener mailboxListener, Group group, RetryBackoffConfiguration retryBackoff,
+                      EventListener.ReactiveEventListener mailboxListener, Group group, RetryBackoffConfiguration retryBackoff,
                       EventDeadLetters eventDeadLetters,
                       Runnable unregisterGroup, MailboxListenerExecutor mailboxListenerExecutor) {
         this.channelPool = channelPool;
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
index 251b375..950ac44 100644
--- 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
@@ -26,6 +26,12 @@ 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;
 
@@ -61,7 +67,7 @@ class GroupRegistrationHandler {
         groupRegistrations.values().forEach(GroupRegistration::unregister);
     }
 
-    Registration register(MailboxListener.ReactiveMailboxListener listener, Group group) {
+    Registration register(EventListener.ReactiveEventListener listener, Group group) {
         return groupRegistrations
             .compute(group, (groupToRegister, oldGroupRegistration) -> {
                 if (oldGroupRegistration != null) {
@@ -72,7 +78,7 @@ class GroupRegistrationHandler {
             .start();
     }
 
-    private GroupRegistration newGroupRegistration(MailboxListener.ReactiveMailboxListener listener, Group group) {
+    private GroupRegistration newGroupRegistration(EventListener.ReactiveEventListener listener, Group group) {
         return new GroupRegistration(
             channelPool, sender,
             receiverProvider,
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
index 8dd002d..be1f399 100644
--- 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
@@ -19,6 +19,8 @@
 
 package org.apache.james.mailbox.events;
 
+import org.apache.james.events.Registration;
+
 class KeyRegistration implements Registration {
     private final Runnable unregister;
 
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
index f4d1de5..0731ca8 100644
--- 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
@@ -32,6 +32,11 @@ 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;
@@ -127,7 +132,7 @@ class KeyRegistrationHandler {
         receiver.close();
     }
 
-    Mono<Registration> register(MailboxListener.ReactiveMailboxListener listener, RegistrationKey key) {
+    Mono<Registration> register(EventListener.ReactiveEventListener listener, RegistrationKey key) {
         LocalListenerRegistry.LocalRegistration registration = localListenerRegistry.addListener(key, listener);
 
         return registerIfNeeded(key, registration)
@@ -169,7 +174,7 @@ class KeyRegistrationHandler {
             .then();
     }
 
-    private Mono<Void> executeListener(MailboxListener.ReactiveMailboxListener listener, Event event, RegistrationKey key) {
+    private Mono<Void> executeListener(EventListener.ReactiveEventListener listener, Event event, RegistrationKey key) {
         MDCBuilder mdcBuilder = MDCBuilder.create()
             .addContext(EventBus.StructuredLoggingFields.REGISTRATION_KEY, key);
 
@@ -180,9 +185,9 @@ class KeyRegistrationHandler {
             .then();
     }
 
-    private boolean isLocalSynchronousListeners(EventBusId eventBusId, MailboxListener listener) {
+    private boolean isLocalSynchronousListeners(EventBusId eventBusId, EventListener listener) {
         return eventBusId.equals(this.eventBusId) &&
-            listener.getExecutionMode().equals(MailboxListener.ExecutionMode.SYNCHRONOUS);
+            listener.getExecutionMode().equals(EventListener.ExecutionMode.SYNCHRONOUS);
     }
 
     private Event toEvent(Delivery delivery) {
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
index a76302d..468bde6 100644
--- 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
@@ -26,6 +26,9 @@ 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;
 
@@ -55,17 +58,17 @@ class LocalListenerRegistry {
         }
     }
 
-    private final ConcurrentHashMap<RegistrationKey, ImmutableSet<MailboxListener.ReactiveMailboxListener>> listenersByKey;
+    private final ConcurrentHashMap<RegistrationKey, ImmutableSet<EventListener.ReactiveEventListener>> listenersByKey;
 
     LocalListenerRegistry() {
         this.listenersByKey = new ConcurrentHashMap<>();
     }
 
-    LocalRegistration addListener(RegistrationKey registrationKey, MailboxListener.ReactiveMailboxListener listener) {
+    LocalRegistration addListener(RegistrationKey registrationKey, EventListener.ReactiveEventListener listener) {
         AtomicBoolean firstListener = new AtomicBoolean(false);
         listenersByKey.compute(registrationKey, (key, listeners) ->
             Optional.ofNullable(listeners)
-                .map(set -> ImmutableSet.<MailboxListener.ReactiveMailboxListener>builder().addAll(set).add(listener).build())
+                .map(set -> ImmutableSet.<EventListener.ReactiveEventListener>builder().addAll(set).add(listener).build())
                 .orElseGet(() -> {
                     firstListener.set(true);
                     return ImmutableSet.of(listener);
@@ -74,16 +77,16 @@ class LocalListenerRegistry {
         return new LocalRegistration(firstListener.get(), () -> removeListener(registrationKey, listener));
     }
 
-    LocalRegistration addListener(RegistrationKey registrationKey, MailboxListener listener) {
-        return addListener(registrationKey, MailboxListener.wrapReactive(listener));
+    LocalRegistration addListener(RegistrationKey registrationKey, EventListener listener) {
+        return addListener(registrationKey, EventListener.wrapReactive(listener));
     }
 
-    private RemovalStatus removeListener(RegistrationKey registrationKey, MailboxListener.ReactiveMailboxListener 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<MailboxListener.ReactiveMailboxListener> remainingListeners = removeListenerFromSet(listener, listeners);
+                ImmutableSet<EventListener.ReactiveEventListener> remainingListeners = removeListenerFromSet(listener, listeners);
                 if (remainingListeners.isEmpty()) {
                     lastListenerRemoved.set(true);
                     return null;
@@ -95,15 +98,15 @@ class LocalListenerRegistry {
         return lastListenerRemoved::get;
     }
 
-    private ImmutableSet<MailboxListener.ReactiveMailboxListener> removeListenerFromSet(MailboxListener listener, ImmutableSet<MailboxListener.ReactiveMailboxListener> listeners) {
-        ImmutableSet<MailboxListener.ReactiveMailboxListener> remainingListeners = listeners.stream().filter(not(listener::equals)).collect(Guavate.toImmutableSet());
+    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<MailboxListener.ReactiveMailboxListener> getLocalMailboxListeners(RegistrationKey registrationKey) {
+    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
index deb0098..f35dc77 100644
--- 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
@@ -19,8 +19,11 @@
 
 package org.apache.james.mailbox.events;
 
-import static org.apache.james.mailbox.events.EventBus.Metrics.timerName;
+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;
@@ -34,7 +37,7 @@ class MailboxListenerExecutor {
         this.metricFactory = metricFactory;
     }
 
-    Mono<Void> execute(MailboxListener.ReactiveMailboxListener listener, MDCBuilder mdcBuilder, Event event) {
+    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))
@@ -43,7 +46,7 @@ class MailboxListenerExecutor {
         return Mono.empty();
     }
 
-    private MDCBuilder mdc(MailboxListener listener, MDCBuilder mdcBuilder, Event event) {
+    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())
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
index eff6278..14c4804 100644
--- 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
@@ -27,6 +27,13 @@ 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;
 
@@ -127,13 +134,13 @@ public class RabbitMQEventBus implements EventBus, Startable {
     }
 
     @Override
-    public Mono<Registration> register(MailboxListener.ReactiveMailboxListener listener, RegistrationKey key) {
+    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(MailboxListener.ReactiveMailboxListener listener, Group group) {
+    public Registration register(EventListener.ReactiveEventListener listener, Group group) {
         Preconditions.checkState(isRunning, NOT_RUNNING_ERROR_MESSAGE);
         return groupRegistrationHandler.register(listener, group);
     }
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
index f4405a6..88fa692 100644
--- 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
@@ -21,6 +21,8 @@ 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;
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
index bf84ec1..755ef27 100644
--- 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
@@ -27,6 +27,8 @@ 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;
diff --git a/mailbox/api/src/test/java/org/apache/james/mailbox/events/InsertionIdTest.java b/mailbox/event/event-rabbitmq/src/test/java/org/apache/james/events/EventBusIdTest.java
similarity index 66%
copy from mailbox/api/src/test/java/org/apache/james/mailbox/events/InsertionIdTest.java
copy to mailbox/event/event-rabbitmq/src/test/java/org/apache/james/events/EventBusIdTest.java
index f8a1e0e..67220dc 100644
--- a/mailbox/api/src/test/java/org/apache/james/mailbox/events/InsertionIdTest.java
+++ b/mailbox/event/event-rabbitmq/src/test/java/org/apache/james/events/EventBusIdTest.java
@@ -17,10 +17,9 @@
  * under the License.                                           *
  ****************************************************************/
 
-package org.apache.james.mailbox.events;
+package org.apache.james.events;
 
 import static org.assertj.core.api.Assertions.assertThat;
-import static org.assertj.core.api.Assertions.assertThatThrownBy;
 
 import java.util.UUID;
 
@@ -28,29 +27,24 @@ import org.junit.jupiter.api.Test;
 
 import nl.jqno.equalsverifier.EqualsVerifier;
 
-class InsertionIdTest {
+class EventBusIdTest {
+
     private static final UUID UUID_1 = UUID.fromString("6e0dd59d-660e-4d9b-b22f-0354479f47b4");
 
     @Test
-    void eventIdShouldMatchBeanContract() {
-        EqualsVerifier.forClass(EventDeadLetters.InsertionId.class).verify();
+    void eventBusIdShouldMatchBeanContract() {
+        EqualsVerifier.forClass(EventBusId.class);
     }
 
     @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);
+        assertThat(EventBusId.of(UUID_1.toString()))
+            .isEqualTo(EventBusId.of(UUID_1));
     }
 
     @Test
-    void ofUuidShouldThrowOnNullValue() {
-        assertThatThrownBy(() -> EventDeadLetters.InsertionId.of((UUID) null))
-            .isInstanceOf(NullPointerException.class);
+    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/events/LocalListenerRegistryTest.java
similarity index 85%
copy from mailbox/event/event-rabbitmq/src/test/java/org/apache/james/mailbox/events/LocalListenerRegistryTest.java
copy to mailbox/event/event-rabbitmq/src/test/java/org/apache/james/events/LocalListenerRegistryTest.java
index 10ee4d8..a3de3f6 100644
--- 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/events/LocalListenerRegistryTest.java
@@ -17,9 +17,9 @@
  * under the License.                                           *
  ****************************************************************/
 
-package org.apache.james.mailbox.events;
+package org.apache.james.events;
 
-import static org.apache.james.mailbox.events.MailboxListener.wrapReactive;
+import static org.apache.james.events.EventListener.wrapReactive;
 import static org.assertj.core.api.Assertions.assertThat;
 
 import java.time.Duration;
@@ -53,7 +53,7 @@ class LocalListenerRegistryTest {
 
     @Test
     void getLocalMailboxListenersShouldReturnPreviouslyAddedListener() {
-        MailboxListener listener = event -> { };
+        EventListener listener = event -> { };
         testee.addListener(KEY_1, listener);
 
         assertThat(testee.getLocalMailboxListeners(KEY_1).collectList().block())
@@ -62,8 +62,8 @@ class LocalListenerRegistryTest {
 
     @Test
     void getLocalMailboxListenersShouldReturnPreviouslyAddedListeners() {
-        MailboxListener listener1 = event -> { };
-        MailboxListener listener2 = event -> { };
+        EventListener listener1 = event -> { };
+        EventListener listener2 = event -> { };
         testee.addListener(KEY_1, listener1);
         testee.addListener(KEY_1, listener2);
 
@@ -73,8 +73,8 @@ class LocalListenerRegistryTest {
 
     @Test
     void getLocalMailboxListenersShouldNotReturnRemovedListeners() {
-        MailboxListener listener1 = event -> { };
-        MailboxListener listener2 = event -> { };
+        EventListener listener1 = event -> { };
+        EventListener listener2 = event -> { };
         testee.addListener(KEY_1, listener1);
         LocalListenerRegistry.LocalRegistration registration = testee.addListener(KEY_1, listener2);
 
@@ -86,15 +86,15 @@ class LocalListenerRegistryTest {
 
     @Test
     void addListenerShouldReturnFirstListenerWhenNoPreviouslyRegisteredListeners() {
-        MailboxListener listener = event -> { };
+        EventListener listener = event -> { };
 
         assertThat(testee.addListener(KEY_1, listener).isFirstListener()).isTrue();
     }
 
     @Test
     void addListenerShouldNotReturnFirstListenerWhenPreviouslyRegisteredListeners() {
-        MailboxListener listener = event -> { };
-        MailboxListener listener2 = event -> { };
+        EventListener listener = event -> { };
+        EventListener listener2 = event -> { };
 
         testee.addListener(KEY_1, listener);
 
@@ -103,8 +103,8 @@ class LocalListenerRegistryTest {
 
     @Test
     void removeListenerShouldNotReturnLastListenerRemovedWhenSeveralListener() {
-        MailboxListener listener = event -> { };
-        MailboxListener listener2 = event -> { };
+        EventListener listener = event -> { };
+        EventListener listener2 = event -> { };
 
         LocalListenerRegistry.LocalRegistration registration = testee.addListener(KEY_1, listener);
         testee.addListener(KEY_1, listener2);
@@ -114,7 +114,7 @@ class LocalListenerRegistryTest {
 
     @Test
     void removeListenerShouldReturnLastListenerRemovedWhenOneListener() {
-        MailboxListener listener = event -> { };
+        EventListener listener = event -> { };
 
 
         LocalListenerRegistry.LocalRegistration registration = testee.addListener(KEY_1, listener);
@@ -128,7 +128,7 @@ class LocalListenerRegistryTest {
 
         @Test
         void getLocalMailboxListenersShouldReturnPreviousAddedListener() throws Exception {
-            MailboxListener listener = event -> { };
+            EventListener listener = event -> { };
 
             ConcurrentTestRunner.builder()
                 .operation((threadNumber, operationNumber) -> testee.addListener(KEY_1, listener))
@@ -142,9 +142,9 @@ class LocalListenerRegistryTest {
 
         @Test
         void getLocalMailboxListenersShouldReturnAllPreviousAddedListeners() throws Exception {
-            MailboxListener listener1 = event -> { };
-            MailboxListener listener2 = event -> { };
-            MailboxListener listener3 = event -> { };
+            EventListener listener1 = event -> { };
+            EventListener listener2 = event -> { };
+            EventListener listener3 = event -> { };
 
             ConcurrentTestRunner.builder()
                 .randomlyDistributedOperations(
@@ -161,7 +161,7 @@ class LocalListenerRegistryTest {
 
         @Test
         void getLocalMailboxListenersShouldReturnEmptyWhenRemoveAddedListener() throws Exception {
-            MailboxListener listener1 = event -> { };
+            EventListener listener1 = event -> { };
 
             LocalListenerRegistry.LocalRegistration registration = testee.addListener(KEY_1, listener1);
 
@@ -177,9 +177,9 @@ class LocalListenerRegistryTest {
 
         @Test
         void addListenerOnlyReturnIsFirstListenerForEmptyRegistry() throws Exception {
-            MailboxListener listener1 = event -> { };
-            MailboxListener listener2 = event -> { };
-            MailboxListener listener3 = event -> { };
+            EventListener listener1 = event -> { };
+            EventListener listener2 = event -> { };
+            EventListener listener3 = event -> { };
 
             AtomicInteger firstListenerCount = new AtomicInteger(0);
 
@@ -211,7 +211,7 @@ class LocalListenerRegistryTest {
 
         @Test
         void removeListenerOnlyReturnLastListenerRemovedForEmptyRegistry() throws Exception {
-            MailboxListener listener1 = event -> { };
+            EventListener listener1 = event -> { };
             AtomicInteger lastListenerRemoved = new AtomicInteger(0);
 
             LocalListenerRegistry.LocalRegistration registration = testee.addListener(KEY_1, listener1);
@@ -230,11 +230,11 @@ class LocalListenerRegistryTest {
 
         @Test
         void iterationShouldPerformOnASnapshotOfListenersSet() {
-            MailboxListener listener1 = event -> { };
-            MailboxListener listener2 = event -> { };
-            MailboxListener listener3 = event -> { };
-            MailboxListener listener4 = event -> { };
-            MailboxListener listener5 = event -> { };
+            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);
@@ -242,7 +242,7 @@ class LocalListenerRegistryTest {
             testee.addListener(KEY_1, listener4);
             LocalListenerRegistry.LocalRegistration registration5 = testee.addListener(KEY_1, listener5);
 
-            Mono<List<MailboxListener.ReactiveMailboxListener>> listeners = testee.getLocalMailboxListeners(KEY_1)
+            Mono<List<EventListener.ReactiveEventListener>> listeners = testee.getLocalMailboxListeners(KEY_1)
                 .publishOn(Schedulers.elastic())
                 .delayElements(Duration.ofMillis(100))
                 .collectList();
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/events/NetworkErrorTest.java
similarity index 88%
copy from mailbox/event/event-rabbitmq/src/test/java/org/apache/james/mailbox/events/NetworkErrorTest.java
copy to mailbox/event/event-rabbitmq/src/test/java/org/apache/james/events/NetworkErrorTest.java
index ab7fa36..2e9ec01 100644
--- 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/events/NetworkErrorTest.java
@@ -17,13 +17,13 @@
  * under the License.                                           *
  ****************************************************************/
 
-package org.apache.james.mailbox.events;
+package org.apache.james.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.apache.james.events.EventBusTestFixture.EVENT;
+import static org.apache.james.events.EventBusTestFixture.GROUP_A;
+import static org.apache.james.events.EventBusTestFixture.NO_KEYS;
+import static org.apache.james.events.EventBusTestFixture.RETRY_BACKOFF_CONFIGURATION;
+import static org.apache.james.events.EventBusTestFixture.newListener;
 import static org.assertj.core.api.Assertions.assertThatThrownBy;
 import static org.mockito.Mockito.verify;
 
@@ -69,7 +69,7 @@ class NetworkErrorTest {
 
     @Test
     void dispatchShouldWorkAfterNetworkIssuesForOldRegistration() {
-        MailboxListener listener = newListener();
+        EventListener listener = newListener();
         eventBus.register(listener, GROUP_A);
 
         rabbitMQExtension.getRabbitMQ().pause();
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/events/RabbitMQEventBusDeadLetterQueueUpgradeTest.java
similarity index 69%
copy from mailbox/event/event-rabbitmq/src/test/java/org/apache/james/mailbox/events/NetworkErrorTest.java
copy to mailbox/event/event-rabbitmq/src/test/java/org/apache/james/events/RabbitMQEventBusDeadLetterQueueUpgradeTest.java
index ab7fa36..a7371d9 100644
--- 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/events/RabbitMQEventBusDeadLetterQueueUpgradeTest.java
@@ -17,29 +17,31 @@
  * under the License.                                           *
  ****************************************************************/
 
-package org.apache.james.mailbox.events;
+package org.apache.james.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 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.events.EventBusTestFixture.RETRY_BACKOFF_CONFIGURATION;
+import static org.assertj.core.api.Assertions.assertThatCode;
 
 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.EventBusTestFixture.GroupA;
+import org.apache.james.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;
 
-class NetworkErrorTest {
+import reactor.rabbitmq.QueueSpecification;
+
+class RabbitMQEventBusDeadLetterQueueUpgradeTest {
     @RegisterExtension
     static RabbitMQExtension rabbitMQExtension = RabbitMQExtension.singletonRabbitMQ()
         .isolationPolicy(RabbitMQExtension.IsolationPolicy.WEAK);
@@ -68,21 +70,19 @@ class NetworkErrorTest {
     }
 
     @Test
-    void dispatchShouldWorkAfterNetworkIssuesForOldRegistration() {
-        MailboxListener 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));
+    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/events/RabbitMQEventBusTest.java
similarity index 91%
copy from mailbox/event/event-rabbitmq/src/test/java/org/apache/james/mailbox/events/RabbitMQEventBusTest.java
copy to mailbox/event/event-rabbitmq/src/test/java/org/apache/james/events/RabbitMQEventBusTest.java
index ff88499..47e84be 100644
--- 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/events/RabbitMQEventBusTest.java
@@ -17,7 +17,7 @@
  * under the License.                                           *
  ****************************************************************/
 
-package org.apache.james.mailbox.events;
+package org.apache.james.events;
 
 import static org.apache.james.backends.rabbitmq.Constants.AUTO_DELETE;
 import static org.apache.james.backends.rabbitmq.Constants.DIRECT_EXCHANGE;
@@ -25,20 +25,20 @@ 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.apache.james.events.EventBusConcurrentTestContract.newCountingListener;
+import static org.apache.james.events.EventBusTestFixture.ALL_GROUPS;
+import static org.apache.james.events.EventBusTestFixture.EVENT;
+import static org.apache.james.events.EventBusTestFixture.EVENT_2;
+import static org.apache.james.events.EventBusTestFixture.GROUP_A;
+import static org.apache.james.events.EventBusTestFixture.GROUP_B;
+import static org.apache.james.events.EventBusTestFixture.KEY_1;
+import static org.apache.james.events.EventBusTestFixture.NO_KEYS;
+import static org.apache.james.events.EventBusTestFixture.newAsyncListener;
+import static org.apache.james.events.EventBusTestFixture.newListener;
+import static org.apache.james.events.GroupRegistration.WorkQueueName.MAILBOX_EVENT_WORK_QUEUE_PREFIX;
+import static org.apache.james.events.RabbitMQEventBus.MAILBOX_EVENT;
+import static org.apache.james.events.RabbitMQEventBus.MAILBOX_EVENT_DEAD_LETTER_QUEUE;
+import static org.apache.james.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;
@@ -64,10 +64,10 @@ 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.mailbox.events.EventBusTestFixture.GroupA;
-import org.apache.james.mailbox.events.EventBusTestFixture.MailboxListenerCountingSuccessfulExecution;
-import org.apache.james.mailbox.events.EventDispatcher.DispatchingFailureGroup;
-import org.apache.james.mailbox.events.RoutingKeyConverter.RoutingKey;
+import org.apache.james.events.EventBusTestFixture.EventListenerCountingSuccessfulExecution;
+import org.apache.james.events.EventBusTestFixture.GroupA;
+import org.apache.james.events.EventDispatcher.DispatchingFailureGroup;
+import org.apache.james.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;
@@ -286,7 +286,7 @@ class RabbitMQEventBusTest implements GroupContract.SingleEventBusGroupContract,
 
     @Test
     void registerGroupShouldCreateRetryExchange() throws Exception {
-        MailboxListener listener = newListener();
+        EventListener listener = newListener();
         EventBusTestFixture.GroupA registeredGroup = new EventBusTestFixture.GroupA();
         eventBus.register(listener, registeredGroup);
 
@@ -306,7 +306,7 @@ class RabbitMQEventBusTest implements GroupContract.SingleEventBusGroupContract,
 
         @Test
         void rabbitMQEventBusShouldHandleBulksGracefully() throws Exception {
-            EventBusTestFixture.MailboxListenerCountingSuccessfulExecution countingListener1 = newCountingListener();
+            EventListenerCountingSuccessfulExecution countingListener1 = newCountingListener();
             eventBus().register(countingListener1, new EventBusTestFixture.GroupA());
             int totalGlobalRegistrations = 1; // GroupA
 
@@ -347,9 +347,9 @@ class RabbitMQEventBusTest implements GroupContract.SingleEventBusGroupContract,
 
         @Test
         void inProcessingEventShouldBeReDispatchedToAnotherEventBusWhenOneIsDown() {
-            MailboxListenerCountingSuccessfulExecution eventBusListener = spy(new EventBusTestFixture.MailboxListenerCountingSuccessfulExecution());
-            MailboxListenerCountingSuccessfulExecution eventBus2Listener = spy(new EventBusTestFixture.MailboxListenerCountingSuccessfulExecution());
-            MailboxListenerCountingSuccessfulExecution eventBus3Listener = spy(new EventBusTestFixture.MailboxListenerCountingSuccessfulExecution());
+            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);
@@ -462,7 +462,7 @@ class RabbitMQEventBusTest implements GroupContract.SingleEventBusGroupContract,
                 @Test
                 void dispatchShouldWorkAfterNetworkIssuesForOldRegistrationAndKey() {
                     rabbitMQEventBusWithNetWorkIssue.start();
-                    MailboxListener listener = newListener();
+                    EventListener listener = newListener();
                     Mono.from(rabbitMQEventBusWithNetWorkIssue.register(listener, KEY_1)).block();
 
                     rabbitMQNetWorkIssueExtension.getRabbitMQ().pause();
@@ -492,7 +492,7 @@ class RabbitMQEventBusTest implements GroupContract.SingleEventBusGroupContract,
             @Test
             void dispatchShouldWorkAfterRestartForOldRegistration() throws Exception {
                 eventBus.start();
-                MailboxListener listener = newListener();
+                EventListener listener = newListener();
                 eventBus.register(listener, GROUP_A);
 
                 rabbitMQExtension.getRabbitMQ().restart();
@@ -504,7 +504,7 @@ class RabbitMQEventBusTest implements GroupContract.SingleEventBusGroupContract,
             @Test
             void dispatchShouldWorkAfterRestartForNewRegistration() throws Exception {
                 eventBus.start();
-                MailboxListener listener = newListener();
+                EventListener listener = newListener();
 
                 rabbitMQExtension.getRabbitMQ().restart();
 
@@ -519,7 +519,7 @@ class RabbitMQEventBusTest implements GroupContract.SingleEventBusGroupContract,
             @Test
             void redeliverShouldWorkAfterRestartForOldRegistration() throws Exception {
                 eventBus.start();
-                MailboxListener listener = newListener();
+                EventListener listener = newListener();
                 eventBus.register(listener, GROUP_A);
 
                 rabbitMQExtension.getRabbitMQ().restart();
@@ -531,7 +531,7 @@ class RabbitMQEventBusTest implements GroupContract.SingleEventBusGroupContract,
             @Test
             void redeliverShouldWorkAfterRestartForNewRegistration() throws Exception {
                 eventBus.start();
-                MailboxListener listener = newListener();
+                EventListener listener = newListener();
 
                 rabbitMQExtension.getRabbitMQ().restart();
 
@@ -544,7 +544,7 @@ class RabbitMQEventBusTest implements GroupContract.SingleEventBusGroupContract,
             @Test
             void dispatchShouldWorkAfterRestartForOldKeyRegistration() throws Exception {
                 eventBus.start();
-                MailboxListener listener = newListener();
+                EventListener listener = newListener();
                 Mono.from(eventBus.register(listener, KEY_1)).block();
 
                 rabbitMQExtension.getRabbitMQ().restart();
@@ -556,7 +556,7 @@ class RabbitMQEventBusTest implements GroupContract.SingleEventBusGroupContract,
             @Test
             void dispatchedMessagesShouldSurviveARabbitMQRestart() throws Exception {
                 eventBusWithKeyHandlerNotStarted.startWithoutStartingKeyRegistrationHandler();
-                MailboxListener listener = newAsyncListener();
+                EventListener listener = newAsyncListener();
                 Mono.from(eventBusWithKeyHandlerNotStarted.register(listener, KEY_1)).block();
                 Mono<Void> dispatch = eventBusWithKeyHandlerNotStarted.dispatch(EVENT, KEY_1);
                 dispatch.block();
@@ -572,7 +572,7 @@ class RabbitMQEventBusTest implements GroupContract.SingleEventBusGroupContract,
             @Test
             void dispatchShouldWorkAfterRestartForNewKeyRegistration() throws Exception {
                 eventBus.start();
-                MailboxListener listener = newListener();
+                EventListener listener = newListener();
 
                 rabbitMQExtension.getRabbitMQ().restart();
 
@@ -585,7 +585,7 @@ class RabbitMQEventBusTest implements GroupContract.SingleEventBusGroupContract,
             @Test
             void dispatchShouldWorkAfterNetworkIssuesForNewRegistration() {
                 eventBus.start();
-                MailboxListener listener = newListener();
+                EventListener listener = newListener();
 
                 rabbitMQExtension.getRabbitMQ().pause();
 
@@ -603,7 +603,7 @@ class RabbitMQEventBusTest implements GroupContract.SingleEventBusGroupContract,
             @Test
             void redeliverShouldWorkAfterNetworkIssuesForNewRegistration() {
                 eventBus.start();
-                MailboxListener listener = newListener();
+                EventListener listener = newListener();
 
                 rabbitMQExtension.getRabbitMQ().pause();
 
@@ -620,8 +620,8 @@ class RabbitMQEventBusTest implements GroupContract.SingleEventBusGroupContract,
             @Test
             void dispatchShouldWorkAfterNetworkIssuesForOldKeyRegistration() {
                 eventBus.start();
-                MailboxListener listener = newListener();
-                when(listener.getExecutionMode()).thenReturn(MailboxListener.ExecutionMode.ASYNCHRONOUS);
+                EventListener listener = newListener();
+                when(listener.getExecutionMode()).thenReturn(EventListener.ExecutionMode.ASYNCHRONOUS);
                 Mono.from(eventBus.register(listener, KEY_1)).block();
 
                 rabbitMQExtension.getRabbitMQ().pause();
@@ -639,8 +639,8 @@ class RabbitMQEventBusTest implements GroupContract.SingleEventBusGroupContract,
             @Test
             void dispatchShouldWorkAfterNetworkIssuesForNewKeyRegistration() {
                 eventBus.start();
-                MailboxListener listener = newListener();
-                when(listener.getExecutionMode()).thenReturn(MailboxListener.ExecutionMode.ASYNCHRONOUS);
+                EventListener listener = newListener();
+                when(listener.getExecutionMode()).thenReturn(EventListener.ExecutionMode.ASYNCHRONOUS);
 
                 rabbitMQExtension.getRabbitMQ().pause();
 
@@ -667,7 +667,7 @@ class RabbitMQEventBusTest implements GroupContract.SingleEventBusGroupContract,
             @Test
             void stopShouldNotDeleteGroupRegistrationWorkQueue() {
                 eventBus.start();
-                eventBus.register(mock(MailboxListener.class), GROUP_A);
+                eventBus.register(mock(EventListener.class), GROUP_A);
                 eventBus.stop();
 
                 assertThat(rabbitManagementAPI.listQueues())
@@ -692,7 +692,7 @@ class RabbitMQEventBusTest implements GroupContract.SingleEventBusGroupContract,
             void dispatchShouldStopDeliveringEventsShortlyAfterStopIsCalled() throws Exception {
                 eventBus.start();
 
-                MailboxListenerCountingSuccessfulExecution listener = new MailboxListenerCountingSuccessfulExecution();
+                EventListenerCountingSuccessfulExecution listener = new EventListenerCountingSuccessfulExecution();
                 eventBus.register(listener, GROUP_A);
 
                 try (Closeable closeable = ConcurrentTestRunner.builder()
@@ -759,7 +759,7 @@ class RabbitMQEventBusTest implements GroupContract.SingleEventBusGroupContract,
 
             @Test
             void multipleEventBusStopShouldNotDeleteGroupRegistrationWorkQueue() {
-                eventBus.register(mock(MailboxListener.class), GROUP_A);
+                eventBus.register(mock(EventListener.class), GROUP_A);
 
                 eventBus.stop();
                 eventBus2.stop();
@@ -788,7 +788,7 @@ class RabbitMQEventBusTest implements GroupContract.SingleEventBusGroupContract,
                 eventBus.start();
                 eventBus2.start();
 
-                MailboxListenerCountingSuccessfulExecution listener = new MailboxListenerCountingSuccessfulExecution();
+                EventListenerCountingSuccessfulExecution listener = new EventListenerCountingSuccessfulExecution();
                 eventBus.register(listener, GROUP_A);
                 eventBus2.register(listener, GROUP_A);
 
@@ -967,7 +967,7 @@ class RabbitMQEventBusTest implements GroupContract.SingleEventBusGroupContract,
         }
     }
 
-    private void assertThatListenerReceiveOneEvent(MailboxListener listener) {
+    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/events/RoutingKeyConverterTest.java
similarity index 99%
copy from mailbox/event/event-rabbitmq/src/test/java/org/apache/james/mailbox/events/RoutingKeyConverterTest.java
copy to mailbox/event/event-rabbitmq/src/test/java/org/apache/james/events/RoutingKeyConverterTest.java
index 4b158dc..d07d95a 100644
--- 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/events/RoutingKeyConverterTest.java
@@ -17,7 +17,7 @@
  * under the License.                                           *
  ****************************************************************/
 
-package org.apache.james.mailbox.events;
+package org.apache.james.events;
 
 import static org.assertj.core.api.Assertions.assertThat;
 import static org.assertj.core.api.Assertions.assertThatThrownBy;
diff --git a/mailbox/event/event-rabbitmq/src/test/java/org/apache/james/events/WaitDelayGeneratorTest.java b/mailbox/event/event-rabbitmq/src/test/java/org/apache/james/events/WaitDelayGeneratorTest.java
new file mode 100644
index 0000000..045e114
--- /dev/null
+++ b/mailbox/event/event-rabbitmq/src/test/java/org/apache/james/events/WaitDelayGeneratorTest.java
@@ -0,0 +1,103 @@
+/****************************************************************
+ * 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.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/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
index 10ee4d8..aa54521 100644
--- 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
@@ -19,13 +19,14 @@
 
 package org.apache.james.mailbox.events;
 
-import static org.apache.james.mailbox.events.MailboxListener.wrapReactive;
+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;
@@ -53,7 +54,7 @@ class LocalListenerRegistryTest {
 
     @Test
     void getLocalMailboxListenersShouldReturnPreviouslyAddedListener() {
-        MailboxListener listener = event -> { };
+        EventListener listener = event -> { };
         testee.addListener(KEY_1, listener);
 
         assertThat(testee.getLocalMailboxListeners(KEY_1).collectList().block())
@@ -62,8 +63,8 @@ class LocalListenerRegistryTest {
 
     @Test
     void getLocalMailboxListenersShouldReturnPreviouslyAddedListeners() {
-        MailboxListener listener1 = event -> { };
-        MailboxListener listener2 = event -> { };
+        EventListener listener1 = event -> { };
+        EventListener listener2 = event -> { };
         testee.addListener(KEY_1, listener1);
         testee.addListener(KEY_1, listener2);
 
@@ -73,8 +74,8 @@ class LocalListenerRegistryTest {
 
     @Test
     void getLocalMailboxListenersShouldNotReturnRemovedListeners() {
-        MailboxListener listener1 = event -> { };
-        MailboxListener listener2 = event -> { };
+        EventListener listener1 = event -> { };
+        EventListener listener2 = event -> { };
         testee.addListener(KEY_1, listener1);
         LocalListenerRegistry.LocalRegistration registration = testee.addListener(KEY_1, listener2);
 
@@ -86,15 +87,15 @@ class LocalListenerRegistryTest {
 
     @Test
     void addListenerShouldReturnFirstListenerWhenNoPreviouslyRegisteredListeners() {
-        MailboxListener listener = event -> { };
+        EventListener listener = event -> { };
 
         assertThat(testee.addListener(KEY_1, listener).isFirstListener()).isTrue();
     }
 
     @Test
     void addListenerShouldNotReturnFirstListenerWhenPreviouslyRegisteredListeners() {
-        MailboxListener listener = event -> { };
-        MailboxListener listener2 = event -> { };
+        EventListener listener = event -> { };
+        EventListener listener2 = event -> { };
 
         testee.addListener(KEY_1, listener);
 
@@ -103,8 +104,8 @@ class LocalListenerRegistryTest {
 
     @Test
     void removeListenerShouldNotReturnLastListenerRemovedWhenSeveralListener() {
-        MailboxListener listener = event -> { };
-        MailboxListener listener2 = event -> { };
+        EventListener listener = event -> { };
+        EventListener listener2 = event -> { };
 
         LocalListenerRegistry.LocalRegistration registration = testee.addListener(KEY_1, listener);
         testee.addListener(KEY_1, listener2);
@@ -114,7 +115,7 @@ class LocalListenerRegistryTest {
 
     @Test
     void removeListenerShouldReturnLastListenerRemovedWhenOneListener() {
-        MailboxListener listener = event -> { };
+        EventListener listener = event -> { };
 
 
         LocalListenerRegistry.LocalRegistration registration = testee.addListener(KEY_1, listener);
@@ -128,7 +129,7 @@ class LocalListenerRegistryTest {
 
         @Test
         void getLocalMailboxListenersShouldReturnPreviousAddedListener() throws Exception {
-            MailboxListener listener = event -> { };
+            EventListener listener = event -> { };
 
             ConcurrentTestRunner.builder()
                 .operation((threadNumber, operationNumber) -> testee.addListener(KEY_1, listener))
@@ -142,9 +143,9 @@ class LocalListenerRegistryTest {
 
         @Test
         void getLocalMailboxListenersShouldReturnAllPreviousAddedListeners() throws Exception {
-            MailboxListener listener1 = event -> { };
-            MailboxListener listener2 = event -> { };
-            MailboxListener listener3 = event -> { };
+            EventListener listener1 = event -> { };
+            EventListener listener2 = event -> { };
+            EventListener listener3 = event -> { };
 
             ConcurrentTestRunner.builder()
                 .randomlyDistributedOperations(
@@ -161,7 +162,7 @@ class LocalListenerRegistryTest {
 
         @Test
         void getLocalMailboxListenersShouldReturnEmptyWhenRemoveAddedListener() throws Exception {
-            MailboxListener listener1 = event -> { };
+            EventListener listener1 = event -> { };
 
             LocalListenerRegistry.LocalRegistration registration = testee.addListener(KEY_1, listener1);
 
@@ -177,9 +178,9 @@ class LocalListenerRegistryTest {
 
         @Test
         void addListenerOnlyReturnIsFirstListenerForEmptyRegistry() throws Exception {
-            MailboxListener listener1 = event -> { };
-            MailboxListener listener2 = event -> { };
-            MailboxListener listener3 = event -> { };
+            EventListener listener1 = event -> { };
+            EventListener listener2 = event -> { };
+            EventListener listener3 = event -> { };
 
             AtomicInteger firstListenerCount = new AtomicInteger(0);
 
@@ -211,7 +212,7 @@ class LocalListenerRegistryTest {
 
         @Test
         void removeListenerOnlyReturnLastListenerRemovedForEmptyRegistry() throws Exception {
-            MailboxListener listener1 = event -> { };
+            EventListener listener1 = event -> { };
             AtomicInteger lastListenerRemoved = new AtomicInteger(0);
 
             LocalListenerRegistry.LocalRegistration registration = testee.addListener(KEY_1, listener1);
@@ -230,11 +231,11 @@ class LocalListenerRegistryTest {
 
         @Test
         void iterationShouldPerformOnASnapshotOfListenersSet() {
-            MailboxListener listener1 = event -> { };
-            MailboxListener listener2 = event -> { };
-            MailboxListener listener3 = event -> { };
-            MailboxListener listener4 = event -> { };
-            MailboxListener listener5 = event -> { };
+            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);
@@ -242,7 +243,7 @@ class LocalListenerRegistryTest {
             testee.addListener(KEY_1, listener4);
             LocalListenerRegistry.LocalRegistration registration5 = testee.addListener(KEY_1, listener5);
 
-            Mono<List<MailboxListener.ReactiveMailboxListener>> listeners = testee.getLocalMailboxListeners(KEY_1)
+            Mono<List<EventListener.ReactiveEventListener>> listeners = testee.getLocalMailboxListeners(KEY_1)
                 .publishOn(Schedulers.elastic())
                 .delayElements(Duration.ofMillis(100))
                 .collectList();
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
index ab7fa36..fd551ec 100644
--- 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
@@ -30,6 +30,7 @@ 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;
@@ -69,7 +70,7 @@ class NetworkErrorTest {
 
     @Test
     void dispatchShouldWorkAfterNetworkIssuesForOldRegistration() {
-        MailboxListener listener = newListener();
+        EventListener listener = newListener();
         eventBus.register(listener, GROUP_A);
 
         rabbitMQExtension.getRabbitMQ().pause();
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
index ff88499..a167ca9 100644
--- 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
@@ -64,8 +64,14 @@ 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.EventBusTestFixture.MailboxListenerCountingSuccessfulExecution;
 import org.apache.james.mailbox.events.EventDispatcher.DispatchingFailureGroup;
 import org.apache.james.mailbox.events.RoutingKeyConverter.RoutingKey;
 import org.apache.james.mailbox.model.TestId;
@@ -286,7 +292,7 @@ class RabbitMQEventBusTest implements GroupContract.SingleEventBusGroupContract,
 
     @Test
     void registerGroupShouldCreateRetryExchange() throws Exception {
-        MailboxListener listener = newListener();
+        EventListener listener = newListener();
         EventBusTestFixture.GroupA registeredGroup = new EventBusTestFixture.GroupA();
         eventBus.register(listener, registeredGroup);
 
@@ -306,7 +312,7 @@ class RabbitMQEventBusTest implements GroupContract.SingleEventBusGroupContract,
 
         @Test
         void rabbitMQEventBusShouldHandleBulksGracefully() throws Exception {
-            EventBusTestFixture.MailboxListenerCountingSuccessfulExecution countingListener1 = newCountingListener();
+            EventListenerCountingSuccessfulExecution countingListener1 = newCountingListener();
             eventBus().register(countingListener1, new EventBusTestFixture.GroupA());
             int totalGlobalRegistrations = 1; // GroupA
 
@@ -347,9 +353,9 @@ class RabbitMQEventBusTest implements GroupContract.SingleEventBusGroupContract,
 
         @Test
         void inProcessingEventShouldBeReDispatchedToAnotherEventBusWhenOneIsDown() {
-            MailboxListenerCountingSuccessfulExecution eventBusListener = spy(new EventBusTestFixture.MailboxListenerCountingSuccessfulExecution());
-            MailboxListenerCountingSuccessfulExecution eventBus2Listener = spy(new EventBusTestFixture.MailboxListenerCountingSuccessfulExecution());
-            MailboxListenerCountingSuccessfulExecution eventBus3Listener = spy(new EventBusTestFixture.MailboxListenerCountingSuccessfulExecution());
+            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);
@@ -462,7 +468,7 @@ class RabbitMQEventBusTest implements GroupContract.SingleEventBusGroupContract,
                 @Test
                 void dispatchShouldWorkAfterNetworkIssuesForOldRegistrationAndKey() {
                     rabbitMQEventBusWithNetWorkIssue.start();
-                    MailboxListener listener = newListener();
+                    EventListener listener = newListener();
                     Mono.from(rabbitMQEventBusWithNetWorkIssue.register(listener, KEY_1)).block();
 
                     rabbitMQNetWorkIssueExtension.getRabbitMQ().pause();
@@ -492,7 +498,7 @@ class RabbitMQEventBusTest implements GroupContract.SingleEventBusGroupContract,
             @Test
             void dispatchShouldWorkAfterRestartForOldRegistration() throws Exception {
                 eventBus.start();
-                MailboxListener listener = newListener();
+                EventListener listener = newListener();
                 eventBus.register(listener, GROUP_A);
 
                 rabbitMQExtension.getRabbitMQ().restart();
@@ -504,7 +510,7 @@ class RabbitMQEventBusTest implements GroupContract.SingleEventBusGroupContract,
             @Test
             void dispatchShouldWorkAfterRestartForNewRegistration() throws Exception {
                 eventBus.start();
-                MailboxListener listener = newListener();
+                EventListener listener = newListener();
 
                 rabbitMQExtension.getRabbitMQ().restart();
 
@@ -519,7 +525,7 @@ class RabbitMQEventBusTest implements GroupContract.SingleEventBusGroupContract,
             @Test
             void redeliverShouldWorkAfterRestartForOldRegistration() throws Exception {
                 eventBus.start();
-                MailboxListener listener = newListener();
+                EventListener listener = newListener();
                 eventBus.register(listener, GROUP_A);
 
                 rabbitMQExtension.getRabbitMQ().restart();
@@ -531,7 +537,7 @@ class RabbitMQEventBusTest implements GroupContract.SingleEventBusGroupContract,
             @Test
             void redeliverShouldWorkAfterRestartForNewRegistration() throws Exception {
                 eventBus.start();
-                MailboxListener listener = newListener();
+                EventListener listener = newListener();
 
                 rabbitMQExtension.getRabbitMQ().restart();
 
@@ -544,7 +550,7 @@ class RabbitMQEventBusTest implements GroupContract.SingleEventBusGroupContract,
             @Test
             void dispatchShouldWorkAfterRestartForOldKeyRegistration() throws Exception {
                 eventBus.start();
-                MailboxListener listener = newListener();
+                EventListener listener = newListener();
                 Mono.from(eventBus.register(listener, KEY_1)).block();
 
                 rabbitMQExtension.getRabbitMQ().restart();
@@ -556,7 +562,7 @@ class RabbitMQEventBusTest implements GroupContract.SingleEventBusGroupContract,
             @Test
             void dispatchedMessagesShouldSurviveARabbitMQRestart() throws Exception {
                 eventBusWithKeyHandlerNotStarted.startWithoutStartingKeyRegistrationHandler();
-                MailboxListener listener = newAsyncListener();
+                EventListener listener = newAsyncListener();
                 Mono.from(eventBusWithKeyHandlerNotStarted.register(listener, KEY_1)).block();
                 Mono<Void> dispatch = eventBusWithKeyHandlerNotStarted.dispatch(EVENT, KEY_1);
                 dispatch.block();
@@ -572,7 +578,7 @@ class RabbitMQEventBusTest implements GroupContract.SingleEventBusGroupContract,
             @Test
             void dispatchShouldWorkAfterRestartForNewKeyRegistration() throws Exception {
                 eventBus.start();
-                MailboxListener listener = newListener();
+                EventListener listener = newListener();
 
                 rabbitMQExtension.getRabbitMQ().restart();
 
@@ -585,7 +591,7 @@ class RabbitMQEventBusTest implements GroupContract.SingleEventBusGroupContract,
             @Test
             void dispatchShouldWorkAfterNetworkIssuesForNewRegistration() {
                 eventBus.start();
-                MailboxListener listener = newListener();
+                EventListener listener = newListener();
 
                 rabbitMQExtension.getRabbitMQ().pause();
 
@@ -603,7 +609,7 @@ class RabbitMQEventBusTest implements GroupContract.SingleEventBusGroupContract,
             @Test
             void redeliverShouldWorkAfterNetworkIssuesForNewRegistration() {
                 eventBus.start();
-                MailboxListener listener = newListener();
+                EventListener listener = newListener();
 
                 rabbitMQExtension.getRabbitMQ().pause();
 
@@ -620,8 +626,8 @@ class RabbitMQEventBusTest implements GroupContract.SingleEventBusGroupContract,
             @Test
             void dispatchShouldWorkAfterNetworkIssuesForOldKeyRegistration() {
                 eventBus.start();
-                MailboxListener listener = newListener();
-                when(listener.getExecutionMode()).thenReturn(MailboxListener.ExecutionMode.ASYNCHRONOUS);
+                EventListener listener = newListener();
+                when(listener.getExecutionMode()).thenReturn(EventListener.ExecutionMode.ASYNCHRONOUS);
                 Mono.from(eventBus.register(listener, KEY_1)).block();
 
                 rabbitMQExtension.getRabbitMQ().pause();
@@ -639,8 +645,8 @@ class RabbitMQEventBusTest implements GroupContract.SingleEventBusGroupContract,
             @Test
             void dispatchShouldWorkAfterNetworkIssuesForNewKeyRegistration() {
                 eventBus.start();
-                MailboxListener listener = newListener();
-                when(listener.getExecutionMode()).thenReturn(MailboxListener.ExecutionMode.ASYNCHRONOUS);
+                EventListener listener = newListener();
+                when(listener.getExecutionMode()).thenReturn(EventListener.ExecutionMode.ASYNCHRONOUS);
 
                 rabbitMQExtension.getRabbitMQ().pause();
 
@@ -667,7 +673,7 @@ class RabbitMQEventBusTest implements GroupContract.SingleEventBusGroupContract,
             @Test
             void stopShouldNotDeleteGroupRegistrationWorkQueue() {
                 eventBus.start();
-                eventBus.register(mock(MailboxListener.class), GROUP_A);
+                eventBus.register(mock(EventListener.class), GROUP_A);
                 eventBus.stop();
 
                 assertThat(rabbitManagementAPI.listQueues())
@@ -692,7 +698,7 @@ class RabbitMQEventBusTest implements GroupContract.SingleEventBusGroupContract,
             void dispatchShouldStopDeliveringEventsShortlyAfterStopIsCalled() throws Exception {
                 eventBus.start();
 
-                MailboxListenerCountingSuccessfulExecution listener = new MailboxListenerCountingSuccessfulExecution();
+                EventListenerCountingSuccessfulExecution listener = new EventListenerCountingSuccessfulExecution();
                 eventBus.register(listener, GROUP_A);
 
                 try (Closeable closeable = ConcurrentTestRunner.builder()
@@ -759,7 +765,7 @@ class RabbitMQEventBusTest implements GroupContract.SingleEventBusGroupContract,
 
             @Test
             void multipleEventBusStopShouldNotDeleteGroupRegistrationWorkQueue() {
-                eventBus.register(mock(MailboxListener.class), GROUP_A);
+                eventBus.register(mock(EventListener.class), GROUP_A);
 
                 eventBus.stop();
                 eventBus2.stop();
@@ -788,7 +794,7 @@ class RabbitMQEventBusTest implements GroupContract.SingleEventBusGroupContract,
                 eventBus.start();
                 eventBus2.start();
 
-                MailboxListenerCountingSuccessfulExecution listener = new MailboxListenerCountingSuccessfulExecution();
+                EventListenerCountingSuccessfulExecution listener = new EventListenerCountingSuccessfulExecution();
                 eventBus.register(listener, GROUP_A);
                 eventBus2.register(listener, GROUP_A);
 
@@ -967,7 +973,7 @@ class RabbitMQEventBusTest implements GroupContract.SingleEventBusGroupContract,
         }
     }
 
-    private void assertThatListenerReceiveOneEvent(MailboxListener listener) {
+    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
index 4b158dc..9fb93dc 100644
--- 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
@@ -24,6 +24,7 @@ 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;
 
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 92f0160..fa7c110 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
@@ -28,10 +28,11 @@ import org.apache.james.core.Username
 import org.apache.james.core.quota.{QuotaCountLimit, QuotaCountUsage, QuotaSizeLimit, QuotaSizeUsage}
 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.mailbox.MailboxSession.SessionId
-import org.apache.james.mailbox.events.Event.EventId
-import org.apache.james.mailbox.events.MailboxListener.{Added => JavaAdded, Expunged => JavaExpunged, FlagsUpdated => JavaFlagsUpdated, MailboxACLUpdated => JavaMailboxACLUpdated, MailboxAdded => JavaMailboxAdded, MailboxDeletion => JavaMailboxDeletion, MailboxRenamed => JavaMailboxRenamed, QuotaUsageUpdatedEvent => JavaQuotaUsageUpdatedEvent}
-import org.apache.james.mailbox.events.{Event => JavaEvent, MessageMoveEvent => JavaMessageMoveEvent}
+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}
@@ -40,36 +41,36 @@ import play.api.libs.json._
 import scala.jdk.CollectionConverters._
 
 private sealed trait Event {
-  def toJava: JavaEvent
+  def toJava: events.Event
 }
 
 private object DTO {
   case class MailboxACLUpdated(eventId: EventId, sessionId: SessionId, user: Username, mailboxPath: MailboxPath, aclDiff: ACLDiff, mailboxId: MailboxId) extends Event {
-    override def toJava: JavaEvent = new JavaMailboxACLUpdated(sessionId, user, mailboxPath.toJava, aclDiff.toJava, mailboxId, eventId)
+    override def toJava: events.Event = new JavaMailboxACLUpdated(sessionId, user, mailboxPath.toJava, aclDiff.toJava, mailboxId, eventId)
   }
 
   case class MailboxAdded(eventId: EventId, mailboxPath: MailboxPath, mailboxId: MailboxId, user: Username, sessionId: SessionId) extends Event {
-    override def toJava: JavaEvent = new JavaMailboxAdded(sessionId, user, mailboxPath.toJava, mailboxId, eventId)
+    override def toJava: events.Event = new JavaMailboxAdded(sessionId, user, mailboxPath.toJava, mailboxId, eventId)
   }
 
   case class MailboxDeletion(eventId: EventId, sessionId: SessionId, user: Username, path: MailboxPath, mailboxACL: Option[MailboxACL], quotaRoot: QuotaRoot,
                              deletedMessageCount: QuotaCountUsage, totalDeletedSize: QuotaSizeUsage, mailboxId: MailboxId) extends Event {
-    override def toJava: JavaEvent = new JavaMailboxDeletion(sessionId, user, path.toJava, mailboxACL.map(mailboxACL => mailboxACL.toJava).getOrElse(new JavaMailboxACL()), quotaRoot, deletedMessageCount,
+    override def toJava: events.Event = new JavaMailboxDeletion(sessionId, user, path.toJava, mailboxACL.map(mailboxACL => mailboxACL.toJava).getOrElse(new JavaMailboxACL()), quotaRoot, deletedMessageCount,
       totalDeletedSize, mailboxId, eventId)
   }
 
   case class MailboxRenamed(eventId: EventId, sessionId: SessionId, user: Username, path: MailboxPath, mailboxId: MailboxId, newPath: MailboxPath) extends Event {
-    override def toJava: JavaEvent = new JavaMailboxRenamed(sessionId, user, path.toJava, mailboxId, newPath.toJava, eventId)
+    override def toJava: events.Event = new JavaMailboxRenamed(sessionId, user, path.toJava, mailboxId, newPath.toJava, eventId)
   }
 
   case class QuotaUsageUpdatedEvent(eventId: EventId, user: Username, quotaRoot: QuotaRoot, countQuota: Quota[QuotaCountLimit, QuotaCountUsage],
                                     sizeQuota: Quota[QuotaSizeLimit, QuotaSizeUsage], time: Instant) extends Event {
-    override def toJava: JavaEvent = new JavaQuotaUsageUpdatedEvent(eventId, user, quotaRoot, countQuota.toJava, sizeQuota.toJava, time)
+    override def toJava: events.Event = new JavaQuotaUsageUpdatedEvent(eventId, user, quotaRoot, countQuota.toJava, sizeQuota.toJava, time)
   }
 
   case class Added(eventId: EventId, sessionId: SessionId, user: Username, path: MailboxPath, mailboxId: MailboxId,
                    added: Map[MessageUid, DTOs.MessageMetaData]) extends Event {
-    override def toJava: JavaEvent = new JavaAdded(
+    override def toJava: events.Event = new JavaAdded(
       sessionId,
       user,
       path.toJava,
@@ -80,7 +81,7 @@ private object DTO {
 
   case class Expunged(eventId: EventId, sessionId: SessionId, user: Username, path: MailboxPath, mailboxId: MailboxId,
                       expunged: Map[MessageUid, DTOs.MessageMetaData]) extends Event {
-    override def toJava: JavaEvent = new JavaExpunged(
+    override def toJava: events.Event = new JavaExpunged(
       sessionId,
       user,
       path.toJava,
@@ -91,7 +92,7 @@ private object DTO {
 
   case class MessageMoveEvent(eventId: EventId, user: Username, previousMailboxIds: Iterable[MailboxId], targetMailboxIds: Iterable[MailboxId],
                               messageIds: Iterable[MessageId]) extends Event {
-    override def toJava: JavaEvent = JavaMessageMoveEvent.builder()
+    override def toJava: events.Event = JavaMessageMoveEvent.builder()
       .eventId(eventId)
       .user(user)
       .messageId(messageIds.asJava)
@@ -104,7 +105,7 @@ private object DTO {
 
   case class FlagsUpdated(eventId: EventId, sessionId: SessionId, user: Username, path: MailboxPath, mailboxId: MailboxId,
                           updatedFlags: List[DTOs.UpdatedFlags]) extends Event {
-    override def toJava: JavaEvent = new JavaFlagsUpdated(
+    override def toJava: events.Event = new JavaFlagsUpdated(
       sessionId,
       user,
       path.toJava,
@@ -188,7 +189,7 @@ private object ScalaConverter {
     mailboxId = event.getMailboxId,
     updatedFlags = event.getUpdatedFlags.asScala.toList.map(DTOs.UpdatedFlags.toUpdatedFlags))
 
-  def toScala(javaEvent: JavaEvent): Event = javaEvent match {
+  def toScala(javaEvent: events.Event): Event = javaEvent match {
     case e: JavaAdded => toScala(e)
     case e: JavaExpunged => toScala(e)
     case e: JavaFlagsUpdated => toScala(e)
@@ -347,15 +348,15 @@ class JsonSerialize(mailboxIdFactory: MailboxId.Factory, messageIdFactory: Messa
   }
 
   private val eventSerializerPrivateWrapper = new EventSerializerPrivateWrapper()
-  def toJson(event: JavaEvent): String = eventSerializerPrivateWrapper.toJson(ScalaConverter.toScala(event))
-  def fromJson(json: String): JsResult[JavaEvent] = eventSerializerPrivateWrapper.fromJson(json)
+  def toJson(event: events.Event): String = eventSerializerPrivateWrapper.toJson(ScalaConverter.toScala(event))
+  def fromJson(json: String): JsResult[events.Event] = eventSerializerPrivateWrapper.fromJson(json)
     .map(event => event.toJava)
 }
 
 class EventSerializer @Inject() (mailboxIdFactory: MailboxId.Factory, messageIdFactory: MessageId.Factory, quotaRootDeserializer: QuotaRootDeserializer) {
   private val jsonSerialize = new JsonSerialize(mailboxIdFactory, messageIdFactory, quotaRootDeserializer)
 
-  def toJson(event: JavaEvent): String = jsonSerialize.toJson(event)
-  def fromJson(json: String): JsResult[JavaEvent] = jsonSerialize.fromJson(json)
+  def toJson(event: events.Event): String = jsonSerialize.toJson(event)
+  def fromJson(json: String): JsResult[events.Event] = jsonSerialize.fromJson(json)
 }
 
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 483123f..7477cad 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
@@ -37,7 +37,7 @@ 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.MailboxListener;
+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;
@@ -68,8 +68,7 @@ class AddedSerializationTest {
     private static final SortedMap<MessageUid, MessageMetaData> ADDED = ImmutableSortedMap.of(
         MESSAGE_UID, new MessageMetaData(MESSAGE_UID, MOD_SEQ, FLAGS, SIZE, Date.from(INSTANT), MESSAGE_ID));
 
-    private static final MailboxListener.Added DEFAULT_ADDED_EVENT = new MailboxListener.Added(SESSION_ID, USERNAME,
-        MAILBOX_PATH, MAILBOX_ID, ADDED, EVENT_ID);
+    private static final Added DEFAULT_ADDED_EVENT = new Added(SESSION_ID, USERNAME, MAILBOX_PATH, MAILBOX_ID, ADDED, EVENT_ID);
     private static final String DEFAULT_ADDED_EVENT_JSON = 
         "{" +
         "  \"Added\": {" +
@@ -112,7 +111,7 @@ class AddedSerializationTest {
     @Nested
     class WithEmptyAddedMap {
 
-        private final MailboxListener.Added emptyAddedEvent = new MailboxListener.Added(SESSION_ID, USERNAME, MAILBOX_PATH,
+        private final Added emptyAddedEvent = new Added(SESSION_ID, USERNAME, MAILBOX_PATH,
             MAILBOX_ID, ImmutableSortedMap.of(), EVENT_ID);
         private final String emptyAddedEventJson =
             "{" +
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 06066c3..866f241 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
@@ -37,7 +37,7 @@ 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.MailboxListener;
+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;
@@ -68,7 +68,7 @@ class ExpungedSerializationTest {
     private static final Map<MessageUid, MessageMetaData> EXPUNGED = ImmutableMap.of(
         MESSAGE_UID, new MessageMetaData(MESSAGE_UID, MOD_SEQ, FLAGS, SIZE, Date.from(INSTANT), MESSAGE_ID));
 
-    private static final MailboxListener.Expunged DEFAULT_EXPUNGED_EVENT = new MailboxListener.Expunged(SESSION_ID, USERNAME,
+    private static final Expunged DEFAULT_EXPUNGED_EVENT = new Expunged(SESSION_ID, USERNAME,
         MAILBOX_PATH, MAILBOX_ID, EXPUNGED, EVENT_ID);
     private static final String DEFAULT_EXPUNGED_EVENT_JSON =
         "{" +
@@ -112,7 +112,7 @@ class ExpungedSerializationTest {
     @Nested
     class WithEmptyExpungedMap {
 
-        private final MailboxListener.Expunged emptyExpungedEvent = new MailboxListener.Expunged(SESSION_ID, USERNAME,
+        private final Expunged emptyExpungedEvent = new Expunged(SESSION_ID, USERNAME,
             MAILBOX_PATH, MAILBOX_ID, ImmutableMap.of(), EVENT_ID);
         private final String emptyExpungedEventJson =
             "{" +
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 6cb82f3..d90e7df 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
@@ -35,7 +35,7 @@ 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.MailboxListener;
+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;
@@ -94,7 +94,7 @@ class FlagsUpdatedSerializationTest {
 
     private static List<UpdatedFlags> UPDATED_FLAGS_LIST = ImmutableList.of(UPDATED_FLAG_1, UPDATED_FLAG_2);
 
-    private static final MailboxListener.FlagsUpdated DEFAULT_EVENT = new MailboxListener.FlagsUpdated(SESSION_ID, USERNAME,
+    private static final FlagsUpdated DEFAULT_EVENT = new FlagsUpdated(SESSION_ID, USERNAME,
         MAILBOX_PATH, MAILBOX_ID, UPDATED_FLAGS_LIST, EVENT_ID);
     private static final String DEFAULT_EVENT_JSON =
         "{" +
@@ -141,7 +141,7 @@ class FlagsUpdatedSerializationTest {
     @Nested
     class WithEmptyUpdatedFlags {
         private final List<UpdatedFlags> emptyUpdatedFlags = ImmutableList.of();
-        private final MailboxListener.FlagsUpdated emptyUpdatedFlagsEvent = new MailboxListener.FlagsUpdated(SESSION_ID, USERNAME, MAILBOX_PATH,
+        private final FlagsUpdated emptyUpdatedFlagsEvent = new FlagsUpdated(SESSION_ID, USERNAME, MAILBOX_PATH,
             MAILBOX_ID, emptyUpdatedFlags, EVENT_ID);
 
         private static final String EVENT_JSON_WITH_EMPTY_UPDATED_FLAGS =
@@ -196,7 +196,7 @@ class FlagsUpdatedSerializationTest {
 
         private final List<UpdatedFlags> updatedFlagsListWithMessageIds = ImmutableList.of(updatedFlagsWithMessageId1, updatedFlagsWithMessageId2);
 
-        private final MailboxListener.FlagsUpdated eventWithMessageIds = new MailboxListener.FlagsUpdated(SESSION_ID, USERNAME,
+        private final FlagsUpdated eventWithMessageIds = new FlagsUpdated(SESSION_ID, USERNAME,
             MAILBOX_PATH, MAILBOX_ID, updatedFlagsListWithMessageIds, EVENT_ID);
 
         private static final String EVENT_WITH_MESSAGE_IDS_JSON =
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 d80c0ec..e957e53 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
@@ -30,7 +30,7 @@ import java.util.NoSuchElementException;
 import org.apache.james.core.Username;
 import org.apache.james.mailbox.MailboxSession;
 import org.apache.james.mailbox.acl.ACLDiff;
-import org.apache.james.mailbox.events.MailboxListener;
+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;
@@ -48,7 +48,7 @@ class MailboxACLUpdatedEventSerializationTest {
         new MailboxACL.Entry(MailboxACL.EntryKey.createUserEntryKey(Username.of("alice"), true),
             new MailboxACL.Rfc4314Rights(MailboxACL.Right.Insert)));
 
-    private static final MailboxListener.MailboxACLUpdated MAILBOX_ACL_UPDATED = new MailboxListener.MailboxACLUpdated(
+    private static final MailboxACLUpdated MAILBOX_ACL_UPDATED = new MailboxACLUpdated(
                 MailboxSession.SessionId.of(6),
         USERNAME,
                 new MailboxPath(MailboxConstants.USER_NAMESPACE, Username.of("bob"), "mailboxName"),
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 082237d..1063d2f 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
@@ -29,7 +29,7 @@ import java.util.NoSuchElementException;
 
 import org.apache.james.core.Username;
 import org.apache.james.mailbox.MailboxSession;
-import org.apache.james.mailbox.events.MailboxListener;
+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;
@@ -38,7 +38,7 @@ import org.junit.jupiter.api.Test;
 
 class MailboxAddedSerializationTest {
     private static final Username USERNAME = Username.of("user");
-    private static final MailboxListener.MailboxAdded EVENT_1 = new MailboxListener.MailboxAdded(
+    private static final MailboxAdded EVENT_1 = new MailboxAdded(
         MailboxSession.SessionId.of(42),
         USERNAME,
         new MailboxPath(MailboxConstants.USER_NAMESPACE, Username.of("bob"), "mailboxName"),
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 d4ca296..99f7072 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
@@ -35,7 +35,7 @@ import org.apache.james.core.Username;
 import org.apache.james.core.quota.QuotaCountUsage;
 import org.apache.james.core.quota.QuotaSizeUsage;
 import org.apache.james.mailbox.MailboxSession;
-import org.apache.james.mailbox.events.MailboxListener;
+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;
@@ -53,7 +53,7 @@ class MailboxDeletionSerializationTest {
     private static final QuotaRoot QUOTA_ROOT = QuotaRoot.quotaRoot("#private&user@domain", Optional.of(Domain.of("domain")));
     private static final QuotaCountUsage DELETED_MESSAGE_COUNT = QuotaCountUsage.count(60);
     private static final QuotaSizeUsage TOTAL_DELETED_SIZE = QuotaSizeUsage.size(100);
-    private static final MailboxListener.MailboxDeletion DEFAULT_MAILBOX_DELETION_EVENT = new MailboxListener.MailboxDeletion(
+    private static final MailboxDeletion DEFAULT_MAILBOX_DELETION_EVENT = new MailboxDeletion(
         SESSION_ID,
         USERNAME,
         MAILBOX_PATH,
@@ -64,7 +64,7 @@ class MailboxDeletionSerializationTest {
         MAILBOX_ID,
         EVENT_ID);
 
-    private static final MailboxListener.MailboxDeletion EMPTY_ACL_MAILBOX_DELETION_EVENT = new MailboxListener.MailboxDeletion(
+    private static final MailboxDeletion EMPTY_ACL_MAILBOX_DELETION_EVENT = new MailboxDeletion(
         SESSION_ID,
         USERNAME,
         MAILBOX_PATH,
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 4de9225..18e55d4 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
@@ -30,7 +30,7 @@ import java.util.NoSuchElementException;
 
 import org.apache.james.core.Username;
 import org.apache.james.mailbox.MailboxSession;
-import org.apache.james.mailbox.events.MailboxListener;
+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;
@@ -46,7 +46,7 @@ class MailboxRenamedSerializationTest {
     private static final MailboxPath DEFAULT_NEW_MAILBOX_PATH = new MailboxPath(USER_NAMESPACE, DEFAULT_USERNAME, NEW_MAILBOX_NAME);
     private static final MailboxSession.SessionId DEFAULT_SESSION_ID = MailboxSession.SessionId.of(123456789);
     private static final MailboxId DEFAULT_MAILBOX_ID = TestId.of(123456);
-    private static final MailboxListener.MailboxRenamed DEFAULT_MAILBOX_RENAMED_EVENT = new MailboxListener.MailboxRenamed(
+    private static final MailboxRenamed DEFAULT_MAILBOX_RENAMED_EVENT = new MailboxRenamed(
         DEFAULT_SESSION_ID,
         DEFAULT_USERNAME,
         DEFAULT_OLD_MAILBOX_PATH,
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 68a32a2..b24bc93 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
@@ -28,7 +28,7 @@ import static org.assertj.core.api.Assertions.assertThatThrownBy;
 import java.util.NoSuchElementException;
 
 import org.apache.james.core.Username;
-import org.apache.james.mailbox.events.Event;
+import org.apache.james.events.Event;
 import org.apache.james.mailbox.events.MessageMoveEvent;
 import org.apache.james.mailbox.model.MessageMoves;
 import org.apache.james.mailbox.model.TestId;
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 66e07e3..7991349 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.MailboxListener;
+import org.apache.james.mailbox.events.MailboxEvents.QuotaUsageUpdatedEvent;
 import org.apache.james.mailbox.model.Quota;
 import org.apache.james.mailbox.model.QuotaRoot;
 import org.junit.jupiter.api.Test;
@@ -50,7 +50,7 @@ class QuotaUsageUpdatedEventSerializationTest {
         .computedLimit(QuotaSizeLimit.size(10000))
         .build();
     private static final Instant INSTANT = Instant.parse("2018-11-13T12:00:55Z");
-    private final MailboxListener.QuotaUsageUpdatedEvent eventWithUserContainsUsername = new MailboxListener.QuotaUsageUpdatedEvent(
+    private final QuotaUsageUpdatedEvent eventWithUserContainsUsername = new QuotaUsageUpdatedEvent(
         EVENT_ID,
         Username.of("onlyusername"),
         QUOTA_ROOT,
diff --git a/mailbox/event/json/src/test/java/org/apache/james/event/json/SerializerFixture.java b/mailbox/event/json/src/test/java/org/apache/james/event/json/SerializerFixture.java
index bd8ad0d..a9e6deb 100644
--- a/mailbox/event/json/src/test/java/org/apache/james/event/json/SerializerFixture.java
+++ b/mailbox/event/json/src/test/java/org/apache/james/event/json/SerializerFixture.java
@@ -19,7 +19,7 @@
 
 package org.apache.james.event.json;
 
-import org.apache.james.mailbox.events.Event;
+import org.apache.james.events.Event;
 import org.apache.james.mailbox.model.TestId;
 import org.apache.james.mailbox.model.TestMessageId;
 import org.apache.james.mailbox.store.quota.DefaultUserQuotaRootResolver;
diff --git a/mailbox/jpa/src/main/java/org/apache/james/mailbox/jpa/openjpa/OpenJPAMailboxManager.java b/mailbox/jpa/src/main/java/org/apache/james/mailbox/jpa/openjpa/OpenJPAMailboxManager.java
index 764868d..5259366 100644
--- a/mailbox/jpa/src/main/java/org/apache/james/mailbox/jpa/openjpa/OpenJPAMailboxManager.java
+++ b/mailbox/jpa/src/main/java/org/apache/james/mailbox/jpa/openjpa/OpenJPAMailboxManager.java
@@ -23,9 +23,9 @@ import java.util.EnumSet;
 
 import javax.inject.Inject;
 
+import org.apache.james.events.EventBus;
 import org.apache.james.mailbox.MailboxSession;
 import org.apache.james.mailbox.SessionProvider;
-import org.apache.james.mailbox.events.EventBus;
 import org.apache.james.mailbox.jpa.JPAMailboxSessionMapperFactory;
 import org.apache.james.mailbox.model.Mailbox;
 import org.apache.james.mailbox.model.MessageId;
diff --git a/mailbox/jpa/src/main/java/org/apache/james/mailbox/jpa/openjpa/OpenJPAMessageManager.java b/mailbox/jpa/src/main/java/org/apache/james/mailbox/jpa/openjpa/OpenJPAMessageManager.java
index b11c70b..a43ae7c 100644
--- a/mailbox/jpa/src/main/java/org/apache/james/mailbox/jpa/openjpa/OpenJPAMessageManager.java
+++ b/mailbox/jpa/src/main/java/org/apache/james/mailbox/jpa/openjpa/OpenJPAMessageManager.java
@@ -21,9 +21,9 @@ package org.apache.james.mailbox.jpa.openjpa;
 
 import javax.mail.Flags;
 
+import org.apache.james.events.EventBus;
 import org.apache.james.mailbox.MailboxPathLocker;
 import org.apache.james.mailbox.MailboxSession;
-import org.apache.james.mailbox.events.EventBus;
 import org.apache.james.mailbox.model.Mailbox;
 import org.apache.james.mailbox.model.MessageId;
 import org.apache.james.mailbox.quota.QuotaManager;
diff --git a/mailbox/jpa/src/test/java/org/apache/james/mailbox/jpa/JPAMailboxManagerTest.java b/mailbox/jpa/src/test/java/org/apache/james/mailbox/jpa/JPAMailboxManagerTest.java
index 530a596..bd632cc 100644
--- a/mailbox/jpa/src/test/java/org/apache/james/mailbox/jpa/JPAMailboxManagerTest.java
+++ b/mailbox/jpa/src/test/java/org/apache/james/mailbox/jpa/JPAMailboxManagerTest.java
@@ -21,9 +21,9 @@ package org.apache.james.mailbox.jpa;
 import java.util.Optional;
 
 import org.apache.james.backends.jpa.JpaTestCluster;
+import org.apache.james.events.EventBus;
 import org.apache.james.mailbox.MailboxManagerTest;
 import org.apache.james.mailbox.SubscriptionManager;
-import org.apache.james.mailbox.events.EventBus;
 import org.apache.james.mailbox.jpa.openjpa.OpenJPAMailboxManager;
 import org.apache.james.mailbox.store.StoreSubscriptionManager;
 import org.junit.jupiter.api.AfterEach;
diff --git a/mailbox/jpa/src/test/java/org/apache/james/mailbox/jpa/JpaMailboxManagerStressTest.java b/mailbox/jpa/src/test/java/org/apache/james/mailbox/jpa/JpaMailboxManagerStressTest.java
index 520c195..6917668 100644
--- a/mailbox/jpa/src/test/java/org/apache/james/mailbox/jpa/JpaMailboxManagerStressTest.java
+++ b/mailbox/jpa/src/test/java/org/apache/james/mailbox/jpa/JpaMailboxManagerStressTest.java
@@ -22,8 +22,8 @@ package org.apache.james.mailbox.jpa;
 import java.util.Optional;
 
 import org.apache.james.backends.jpa.JpaTestCluster;
+import org.apache.james.events.EventBus;
 import org.apache.james.mailbox.MailboxManagerStressContract;
-import org.apache.james.mailbox.events.EventBus;
 import org.apache.james.mailbox.jpa.openjpa.OpenJPAMailboxManager;
 import org.junit.jupiter.api.AfterEach;
 import org.junit.jupiter.api.BeforeEach;
diff --git a/mailbox/lucene/src/main/java/org/apache/james/mailbox/lucene/search/LuceneMessageSearchIndex.java b/mailbox/lucene/src/main/java/org/apache/james/mailbox/lucene/search/LuceneMessageSearchIndex.java
index 6d76bea..a382198 100644
--- a/mailbox/lucene/src/main/java/org/apache/james/mailbox/lucene/search/LuceneMessageSearchIndex.java
+++ b/mailbox/lucene/src/main/java/org/apache/james/mailbox/lucene/search/LuceneMessageSearchIndex.java
@@ -131,14 +131,14 @@ import reactor.core.publisher.Mono;
  * Lucene based {@link ListeningMessageSearchIndex} which offers message searching via a Lucene index
  */
 public class LuceneMessageSearchIndex extends ListeningMessageSearchIndex {
-    public static class LuceneMessageSearchIndexGroup extends org.apache.james.mailbox.events.Group {
+    public static class LuceneMessageSearchIndexGroup extends org.apache.james.events.Group {
 
     }
 
     private static final Logger LOGGER = LoggerFactory.getLogger(LuceneMessageSearchIndex.class);
     private static final Date MAX_DATE;
     private static final Date MIN_DATE;
-    public static final org.apache.james.mailbox.events.Group GROUP = new LuceneMessageSearchIndexGroup();
+    public static final org.apache.james.events.Group GROUP = new LuceneMessageSearchIndexGroup();
     
     static {
         Calendar cal = Calendar.getInstance();
@@ -404,7 +404,7 @@ public class LuceneMessageSearchIndex extends ListeningMessageSearchIndex {
     }
 
     @Override
-    public org.apache.james.mailbox.events.Group getDefaultGroup() {
+    public org.apache.james.events.Group getDefaultGroup() {
         return GROUP;
     }
 
diff --git a/mailbox/lucene/src/test/java/org/apache/james/mailbox/lucene/search/LuceneMessageSearchIndexTest.java b/mailbox/lucene/src/test/java/org/apache/james/mailbox/lucene/search/LuceneMessageSearchIndexTest.java
index d274a37..dab83c0 100644
--- a/mailbox/lucene/src/test/java/org/apache/james/mailbox/lucene/search/LuceneMessageSearchIndexTest.java
+++ b/mailbox/lucene/src/test/java/org/apache/james/mailbox/lucene/search/LuceneMessageSearchIndexTest.java
@@ -19,29 +19,16 @@
 
 package org.apache.james.mailbox.lucene.search;
 
-import static org.assertj.core.api.Assertions.assertThat;
-
-import java.nio.charset.StandardCharsets;
-
-import org.apache.james.mailbox.MailboxSession;
-import org.apache.james.mailbox.MailboxSessionUtil;
-import org.apache.james.mailbox.MessageManager;
 import org.apache.james.mailbox.inmemory.InMemoryId;
 import org.apache.james.mailbox.inmemory.InMemoryMessageId;
 import org.apache.james.mailbox.inmemory.manager.InMemoryIntegrationResources;
-import org.apache.james.mailbox.model.ComposedMessageId;
-import org.apache.james.mailbox.model.MailboxPath;
-import org.apache.james.mailbox.model.SearchQuery;
 import org.apache.james.mailbox.store.search.AbstractMessageSearchIndexTest;
-import org.apache.james.mime4j.dom.Message;
 import org.apache.lucene.store.RAMDirectory;
 import org.junit.jupiter.api.Disabled;
 import org.junit.jupiter.api.Test;
 
 import com.github.fge.lambdas.Throwing;
 
-import reactor.core.publisher.Flux;
-
 class LuceneMessageSearchIndexTest extends AbstractMessageSearchIndexTest {
 
     @Override
diff --git a/mailbox/maildir/src/test/java/org/apache/james/mailbox/maildir/DomainUserMaildirMailboxManagerStressTest.java b/mailbox/maildir/src/test/java/org/apache/james/mailbox/maildir/DomainUserMaildirMailboxManagerStressTest.java
index ff61e53..09adfb7 100644
--- a/mailbox/maildir/src/test/java/org/apache/james/mailbox/maildir/DomainUserMaildirMailboxManagerStressTest.java
+++ b/mailbox/maildir/src/test/java/org/apache/james/mailbox/maildir/DomainUserMaildirMailboxManagerStressTest.java
@@ -21,8 +21,8 @@ package org.apache.james.mailbox.maildir;
 
 import java.io.File;
 
+import org.apache.james.events.EventBus;
 import org.apache.james.mailbox.MailboxManagerStressContract;
-import org.apache.james.mailbox.events.EventBus;
 import org.apache.james.mailbox.exception.MailboxException;
 import org.apache.james.mailbox.store.StoreMailboxManager;
 import org.junit.jupiter.api.BeforeEach;
diff --git a/mailbox/maildir/src/test/java/org/apache/james/mailbox/maildir/DomainUserMaildirMailboxManagerTest.java b/mailbox/maildir/src/test/java/org/apache/james/mailbox/maildir/DomainUserMaildirMailboxManagerTest.java
index 601b019..55ae598 100644
--- a/mailbox/maildir/src/test/java/org/apache/james/mailbox/maildir/DomainUserMaildirMailboxManagerTest.java
+++ b/mailbox/maildir/src/test/java/org/apache/james/mailbox/maildir/DomainUserMaildirMailboxManagerTest.java
@@ -20,10 +20,10 @@ package org.apache.james.mailbox.maildir;
 
 import java.util.Optional;
 
+import org.apache.james.events.EventBus;
 import org.apache.james.junit.TemporaryFolderExtension;
 import org.apache.james.mailbox.MailboxManagerTest;
 import org.apache.james.mailbox.SubscriptionManager;
-import org.apache.james.mailbox.events.EventBus;
 import org.apache.james.mailbox.store.StoreMailboxManager;
 import org.apache.james.mailbox.store.StoreSubscriptionManager;
 import org.junit.jupiter.api.Disabled;
diff --git a/mailbox/maildir/src/test/java/org/apache/james/mailbox/maildir/FullUserMaildirMailboxManagerStressTest.java b/mailbox/maildir/src/test/java/org/apache/james/mailbox/maildir/FullUserMaildirMailboxManagerStressTest.java
index 6bb20fc..33cd409 100644
--- a/mailbox/maildir/src/test/java/org/apache/james/mailbox/maildir/FullUserMaildirMailboxManagerStressTest.java
+++ b/mailbox/maildir/src/test/java/org/apache/james/mailbox/maildir/FullUserMaildirMailboxManagerStressTest.java
@@ -21,8 +21,8 @@ package org.apache.james.mailbox.maildir;
 
 import java.io.File;
 
+import org.apache.james.events.EventBus;
 import org.apache.james.mailbox.MailboxManagerStressContract;
-import org.apache.james.mailbox.events.EventBus;
 import org.apache.james.mailbox.exception.MailboxException;
 import org.apache.james.mailbox.store.StoreMailboxManager;
 import org.junit.jupiter.api.BeforeEach;
diff --git a/mailbox/maildir/src/test/java/org/apache/james/mailbox/maildir/FullUserMaildirMailboxManagerTest.java b/mailbox/maildir/src/test/java/org/apache/james/mailbox/maildir/FullUserMaildirMailboxManagerTest.java
index d9ff4c4..633cc6e 100644
--- a/mailbox/maildir/src/test/java/org/apache/james/mailbox/maildir/FullUserMaildirMailboxManagerTest.java
+++ b/mailbox/maildir/src/test/java/org/apache/james/mailbox/maildir/FullUserMaildirMailboxManagerTest.java
@@ -20,10 +20,10 @@ package org.apache.james.mailbox.maildir;
 
 import java.util.Optional;
 
+import org.apache.james.events.EventBus;
 import org.apache.james.junit.TemporaryFolderExtension;
 import org.apache.james.mailbox.MailboxManagerTest;
 import org.apache.james.mailbox.SubscriptionManager;
-import org.apache.james.mailbox.events.EventBus;
 import org.apache.james.mailbox.store.StoreMailboxManager;
 import org.apache.james.mailbox.store.StoreSubscriptionManager;
 import org.junit.jupiter.api.Disabled;
diff --git a/mailbox/maildir/src/test/java/org/apache/james/mailbox/maildir/UserMaildirMailboxManagerStressTest.java b/mailbox/maildir/src/test/java/org/apache/james/mailbox/maildir/UserMaildirMailboxManagerStressTest.java
index 03acce9..3c2b2ce 100644
--- a/mailbox/maildir/src/test/java/org/apache/james/mailbox/maildir/UserMaildirMailboxManagerStressTest.java
+++ b/mailbox/maildir/src/test/java/org/apache/james/mailbox/maildir/UserMaildirMailboxManagerStressTest.java
@@ -21,8 +21,8 @@ package org.apache.james.mailbox.maildir;
 
 import java.io.File;
 
+import org.apache.james.events.EventBus;
 import org.apache.james.mailbox.MailboxManagerStressContract;
-import org.apache.james.mailbox.events.EventBus;
 import org.apache.james.mailbox.exception.MailboxException;
 import org.apache.james.mailbox.store.StoreMailboxManager;
 import org.junit.jupiter.api.BeforeEach;
diff --git a/mailbox/memory/src/main/java/org/apache/james/mailbox/inmemory/InMemoryMailboxManager.java b/mailbox/memory/src/main/java/org/apache/james/mailbox/inmemory/InMemoryMailboxManager.java
index 6ec12db..a71a2b8 100644
--- a/mailbox/memory/src/main/java/org/apache/james/mailbox/inmemory/InMemoryMailboxManager.java
+++ b/mailbox/memory/src/main/java/org/apache/james/mailbox/inmemory/InMemoryMailboxManager.java
@@ -23,10 +23,10 @@ import java.util.EnumSet;
 
 import javax.inject.Inject;
 
+import org.apache.james.events.EventBus;
 import org.apache.james.mailbox.MailboxPathLocker;
 import org.apache.james.mailbox.MailboxSession;
 import org.apache.james.mailbox.SessionProvider;
-import org.apache.james.mailbox.events.EventBus;
 import org.apache.james.mailbox.model.Mailbox;
 import org.apache.james.mailbox.model.MessageId;
 import org.apache.james.mailbox.store.MailboxManagerConfiguration;
diff --git a/mailbox/memory/src/main/java/org/apache/james/mailbox/inmemory/InMemoryMessageManager.java b/mailbox/memory/src/main/java/org/apache/james/mailbox/inmemory/InMemoryMessageManager.java
index 59567b9..7b56397 100644
--- a/mailbox/memory/src/main/java/org/apache/james/mailbox/inmemory/InMemoryMessageManager.java
+++ b/mailbox/memory/src/main/java/org/apache/james/mailbox/inmemory/InMemoryMessageManager.java
@@ -2,9 +2,9 @@ package org.apache.james.mailbox.inmemory;
 
 import javax.mail.Flags;
 
+import org.apache.james.events.EventBus;
 import org.apache.james.mailbox.MailboxPathLocker;
 import org.apache.james.mailbox.MailboxSession;
-import org.apache.james.mailbox.events.EventBus;
 import org.apache.james.mailbox.model.Mailbox;
 import org.apache.james.mailbox.model.MessageId;
 import org.apache.james.mailbox.quota.QuotaManager;
diff --git a/mailbox/memory/src/test/java/org/apache/james/mailbox/inmemory/MemoryMailboxManagerStressTest.java b/mailbox/memory/src/test/java/org/apache/james/mailbox/inmemory/MemoryMailboxManagerStressTest.java
index ea5e1ea..c060065 100644
--- a/mailbox/memory/src/test/java/org/apache/james/mailbox/inmemory/MemoryMailboxManagerStressTest.java
+++ b/mailbox/memory/src/test/java/org/apache/james/mailbox/inmemory/MemoryMailboxManagerStressTest.java
@@ -19,8 +19,8 @@
 
 package org.apache.james.mailbox.inmemory;
 
+import org.apache.james.events.EventBus;
 import org.apache.james.mailbox.MailboxManagerStressContract;
-import org.apache.james.mailbox.events.EventBus;
 import org.apache.james.mailbox.extension.PreDeletionHook;
 import org.junit.jupiter.api.BeforeEach;
 
diff --git a/mailbox/memory/src/test/java/org/apache/james/mailbox/inmemory/MemoryMailboxManagerTest.java b/mailbox/memory/src/test/java/org/apache/james/mailbox/inmemory/MemoryMailboxManagerTest.java
index c02c55f..4bde607 100644
--- a/mailbox/memory/src/test/java/org/apache/james/mailbox/inmemory/MemoryMailboxManagerTest.java
+++ b/mailbox/memory/src/test/java/org/apache/james/mailbox/inmemory/MemoryMailboxManagerTest.java
@@ -19,9 +19,9 @@
 
 package org.apache.james.mailbox.inmemory;
 
+import org.apache.james.events.EventBus;
 import org.apache.james.mailbox.MailboxManagerTest;
 import org.apache.james.mailbox.SubscriptionManager;
-import org.apache.james.mailbox.events.EventBus;
 import org.apache.james.mailbox.store.StoreSubscriptionManager;
 
 class MemoryMailboxManagerTest extends MailboxManagerTest<InMemoryMailboxManager> {
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 a80ff7a..bc172a8 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
@@ -23,6 +23,8 @@ import java.util.Collection;
 import java.util.Optional;
 import java.util.function.Function;
 
+import org.apache.james.events.EventBus;
+import org.apache.james.events.EventListener;
 import org.apache.james.mailbox.AttachmentContentLoader;
 import org.apache.james.mailbox.Authenticator;
 import org.apache.james.mailbox.Authorizator;
@@ -31,10 +33,8 @@ import org.apache.james.mailbox.SessionProvider;
 import org.apache.james.mailbox.acl.GroupMembershipResolver;
 import org.apache.james.mailbox.acl.SimpleGroupMembershipResolver;
 import org.apache.james.mailbox.acl.UnionMailboxACLResolver;
-import org.apache.james.mailbox.events.EventBus;
 import org.apache.james.mailbox.events.EventBusTestFixture;
 import org.apache.james.mailbox.events.InVMEventBus;
-import org.apache.james.mailbox.events.MailboxListener;
 import org.apache.james.mailbox.events.MemoryEventDeadLetters;
 import org.apache.james.mailbox.events.delivery.InVmEventDelivery;
 import org.apache.james.mailbox.extension.PreDeletionHook;
@@ -208,7 +208,7 @@ public class InMemoryIntegrationResources implements IntegrationResources<StoreM
         private Optional<MessageParser> messageParser;
         private Optional<Function<MailboxManagerSearchIndexStage, MessageSearchIndex>> searchIndexFactory;
         private ImmutableSet.Builder<Function<MailboxManagerPreInstanciationStage, PreDeletionHook>> preDeletionHooksFactories;
-        private ImmutableList.Builder<MailboxListener.GroupMailboxListener> listenersToBeRegistered;
+        private ImmutableList.Builder<EventListener.GroupEventListener> listenersToBeRegistered;
 
         private Builder() {
             this.authenticator = Optional.empty();
diff --git a/mailbox/memory/src/test/java/org/apache/james/mailbox/inmemory/manager/InMemoryMessageIdManagerSideEffectTest.java b/mailbox/memory/src/test/java/org/apache/james/mailbox/inmemory/manager/InMemoryMessageIdManagerSideEffectTest.java
index fc8f774..5949260 100644
--- a/mailbox/memory/src/test/java/org/apache/james/mailbox/inmemory/manager/InMemoryMessageIdManagerSideEffectTest.java
+++ b/mailbox/memory/src/test/java/org/apache/james/mailbox/inmemory/manager/InMemoryMessageIdManagerSideEffectTest.java
@@ -21,7 +21,7 @@ package org.apache.james.mailbox.inmemory.manager;
 
 import java.util.Set;
 
-import org.apache.james.mailbox.events.EventBus;
+import org.apache.james.events.EventBus;
 import org.apache.james.mailbox.extension.PreDeletionHook;
 import org.apache.james.mailbox.inmemory.InMemoryMessageId;
 import org.apache.james.mailbox.quota.QuotaManager;
diff --git a/mailbox/plugin/quota-mailing/src/main/java/org/apache/james/mailbox/quota/mailing/listeners/QuotaThresholdCrossingListener.java b/mailbox/plugin/quota-mailing/src/main/java/org/apache/james/mailbox/quota/mailing/listeners/QuotaThresholdCrossingListener.java
index 7c9760c..da86cd6 100644
--- a/mailbox/plugin/quota-mailing/src/main/java/org/apache/james/mailbox/quota/mailing/listeners/QuotaThresholdCrossingListener.java
+++ b/mailbox/plugin/quota-mailing/src/main/java/org/apache/james/mailbox/quota/mailing/listeners/QuotaThresholdCrossingListener.java
@@ -24,15 +24,16 @@ import javax.inject.Inject;
 import org.apache.commons.configuration2.HierarchicalConfiguration;
 import org.apache.commons.configuration2.tree.ImmutableNode;
 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.eventsourcing.Command;
 import org.apache.james.eventsourcing.CommandHandler;
 import org.apache.james.eventsourcing.EventSourcingSystem;
 import org.apache.james.eventsourcing.Subscriber;
 import org.apache.james.eventsourcing.eventstore.EventStore;
 import org.apache.james.filesystem.api.FileSystem;
-import org.apache.james.mailbox.events.Event;
-import org.apache.james.mailbox.events.Group;
-import org.apache.james.mailbox.events.MailboxListener;
+import org.apache.james.mailbox.events.MailboxEvents.QuotaUsageUpdatedEvent;
 import org.apache.james.mailbox.quota.mailing.QuotaMailingListenerConfiguration;
 import org.apache.james.mailbox.quota.mailing.commands.DetectThresholdCrossing;
 import org.apache.james.mailbox.quota.mailing.commands.DetectThresholdCrossingHandler;
@@ -45,7 +46,7 @@ import com.google.common.collect.ImmutableSet;
 
 import reactor.core.publisher.Mono;
 
-public class QuotaThresholdCrossingListener implements MailboxListener.ReactiveGroupMailboxListener {
+public class QuotaThresholdCrossingListener implements EventListener.ReactiveGroupEventListener {
     public static class QuotaThresholdCrossingListenerGroup extends Group {
 
     }
diff --git a/mailbox/plugin/quota-mailing/src/test/java/org/apache/james/mailbox/quota/mailing/listeners/QuotaThresholdConfigurationChangesTest.java b/mailbox/plugin/quota-mailing/src/test/java/org/apache/james/mailbox/quota/mailing/listeners/QuotaThresholdConfigurationChangesTest.java
index 1691454..7fc047d 100644
--- a/mailbox/plugin/quota-mailing/src/test/java/org/apache/james/mailbox/quota/mailing/listeners/QuotaThresholdConfigurationChangesTest.java
+++ b/mailbox/plugin/quota-mailing/src/test/java/org/apache/james/mailbox/quota/mailing/listeners/QuotaThresholdConfigurationChangesTest.java
@@ -28,8 +28,8 @@ import static org.apache.james.mailbox.quota.model.QuotaThresholdFixture._75;
 import static org.apache.james.mailbox.quota.model.QuotaThresholdFixture.mailetContext;
 import static org.assertj.core.api.Assertions.assertThat;
 
+import org.apache.james.events.Event;
 import org.apache.james.eventsourcing.eventstore.EventStore;
-import org.apache.james.mailbox.events.Event;
 import org.apache.james.mailbox.quota.QuotaFixture.Counts;
 import org.apache.james.mailbox.quota.QuotaFixture.Sizes;
 import org.apache.james.mailbox.quota.mailing.QuotaMailingListenerConfiguration;
diff --git a/mailbox/plugin/quota-mailing/src/test/java/org/apache/james/mailbox/quota/mailing/listeners/QuotaThresholdCrossingListenerTest.java b/mailbox/plugin/quota-mailing/src/test/java/org/apache/james/mailbox/quota/mailing/listeners/QuotaThresholdCrossingListenerTest.java
index 6b76fd5..3a8b32b 100644
--- a/mailbox/plugin/quota-mailing/src/test/java/org/apache/james/mailbox/quota/mailing/listeners/QuotaThresholdCrossingListenerTest.java
+++ b/mailbox/plugin/quota-mailing/src/test/java/org/apache/james/mailbox/quota/mailing/listeners/QuotaThresholdCrossingListenerTest.java
@@ -21,7 +21,7 @@ package org.apache.james.mailbox.quota.mailing.listeners;
 
 import static org.assertj.core.api.Assertions.assertThat;
 
-import org.apache.james.mailbox.events.Group;
+import org.apache.james.events.Group;
 import org.junit.jupiter.api.Test;
 
 class QuotaThresholdCrossingListenerTest {
diff --git a/mailbox/plugin/quota-mailing/src/test/java/org/apache/james/mailbox/quota/mailing/listeners/QuotaThresholdListenersTestSystem.java b/mailbox/plugin/quota-mailing/src/test/java/org/apache/james/mailbox/quota/mailing/listeners/QuotaThresholdListenersTestSystem.java
index 7969d46..8cea5bc 100644
--- a/mailbox/plugin/quota-mailing/src/test/java/org/apache/james/mailbox/quota/mailing/listeners/QuotaThresholdListenersTestSystem.java
+++ b/mailbox/plugin/quota-mailing/src/test/java/org/apache/james/mailbox/quota/mailing/listeners/QuotaThresholdListenersTestSystem.java
@@ -20,14 +20,14 @@
 package org.apache.james.mailbox.quota.mailing.listeners;
 
 import org.apache.james.domainlist.api.DomainList;
+import org.apache.james.events.Event;
+import org.apache.james.events.EventBus;
+import org.apache.james.events.RegistrationKey;
 import org.apache.james.eventsourcing.eventstore.EventStore;
 import org.apache.james.filesystem.api.FileSystem;
-import org.apache.james.mailbox.events.Event;
-import org.apache.james.mailbox.events.EventBus;
 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.RegistrationKey;
 import org.apache.james.mailbox.events.delivery.InVmEventDelivery;
 import org.apache.james.mailbox.exception.MailboxException;
 import org.apache.james.mailbox.quota.mailing.QuotaMailingListenerConfiguration;
diff --git a/mailbox/plugin/quota-mailing/src/test/java/org/apache/james/mailbox/quota/mailing/listeners/QuotaThresholdMailingIntegrationTest.java b/mailbox/plugin/quota-mailing/src/test/java/org/apache/james/mailbox/quota/mailing/listeners/QuotaThresholdMailingIntegrationTest.java
index ff891eb..3a44044 100644
--- a/mailbox/plugin/quota-mailing/src/test/java/org/apache/james/mailbox/quota/mailing/listeners/QuotaThresholdMailingIntegrationTest.java
+++ b/mailbox/plugin/quota-mailing/src/test/java/org/apache/james/mailbox/quota/mailing/listeners/QuotaThresholdMailingIntegrationTest.java
@@ -37,8 +37,8 @@ import static org.assertj.core.api.Assertions.assertThat;
 
 import java.time.Duration;
 
+import org.apache.james.events.Event;
 import org.apache.james.eventsourcing.eventstore.EventStore;
-import org.apache.james.mailbox.events.Event;
 import org.apache.james.mailbox.quota.QuotaFixture.Counts;
 import org.apache.james.mailbox.quota.QuotaFixture.Sizes;
 import org.apache.james.mailbox.quota.mailing.QuotaMailingListenerConfiguration;
diff --git a/mailbox/plugin/quota-search-elasticsearch/src/main/java/org/apache/james/quota/search/elasticsearch/events/ElasticSearchQuotaMailboxListener.java b/mailbox/plugin/quota-search-elasticsearch/src/main/java/org/apache/james/quota/search/elasticsearch/events/ElasticSearchQuotaMailboxListener.java
index fe585c6..f12af37 100644
--- a/mailbox/plugin/quota-search-elasticsearch/src/main/java/org/apache/james/quota/search/elasticsearch/events/ElasticSearchQuotaMailboxListener.java
+++ b/mailbox/plugin/quota-search-elasticsearch/src/main/java/org/apache/james/quota/search/elasticsearch/events/ElasticSearchQuotaMailboxListener.java
@@ -25,16 +25,17 @@ import org.apache.james.backends.es.DocumentId;
 import org.apache.james.backends.es.ElasticSearchIndexer;
 import org.apache.james.backends.es.RoutingKey;
 import org.apache.james.core.Username;
-import org.apache.james.mailbox.events.Event;
-import org.apache.james.mailbox.events.Group;
-import org.apache.james.mailbox.events.MailboxListener;
+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.QuotaUsageUpdatedEvent;
 import org.apache.james.quota.search.elasticsearch.QuotaRatioElasticSearchConstants;
 import org.apache.james.quota.search.elasticsearch.json.QuotaRatioToElasticSearchJson;
 import org.reactivestreams.Publisher;
 
 import reactor.core.publisher.Mono;
 
-public class ElasticSearchQuotaMailboxListener implements MailboxListener.ReactiveGroupMailboxListener {
+public class ElasticSearchQuotaMailboxListener implements EventListener.ReactiveGroupEventListener {
     public static class ElasticSearchQuotaMailboxListenerGroup extends Group {
 
     }
diff --git a/mailbox/plugin/quota-search-elasticsearch/src/main/java/org/apache/james/quota/search/elasticsearch/json/QuotaRatioToElasticSearchJson.java b/mailbox/plugin/quota-search-elasticsearch/src/main/java/org/apache/james/quota/search/elasticsearch/json/QuotaRatioToElasticSearchJson.java
index 7bbe25c..39b7a0d 100644
--- a/mailbox/plugin/quota-search-elasticsearch/src/main/java/org/apache/james/quota/search/elasticsearch/json/QuotaRatioToElasticSearchJson.java
+++ b/mailbox/plugin/quota-search-elasticsearch/src/main/java/org/apache/james/quota/search/elasticsearch/json/QuotaRatioToElasticSearchJson.java
@@ -22,7 +22,7 @@ package org.apache.james.quota.search.elasticsearch.json;
 import javax.inject.Inject;
 
 import org.apache.james.core.Domain;
-import org.apache.james.mailbox.events.MailboxListener.QuotaUsageUpdatedEvent;
+import org.apache.james.mailbox.events.MailboxEvents.QuotaUsageUpdatedEvent;
 import org.apache.james.mailbox.model.QuotaRatio;
 
 import com.fasterxml.jackson.core.JsonProcessingException;
diff --git a/mailbox/plugin/quota-search-elasticsearch/src/test/java/org/apache/james/quota/search/elasticsearch/events/ElasticSearchQuotaMailboxListenerTest.java b/mailbox/plugin/quota-search-elasticsearch/src/test/java/org/apache/james/quota/search/elasticsearch/events/ElasticSearchQuotaMailboxListenerTest.java
index 9e5671b..1011b07 100644
--- a/mailbox/plugin/quota-search-elasticsearch/src/test/java/org/apache/james/quota/search/elasticsearch/events/ElasticSearchQuotaMailboxListenerTest.java
+++ b/mailbox/plugin/quota-search-elasticsearch/src/test/java/org/apache/james/quota/search/elasticsearch/events/ElasticSearchQuotaMailboxListenerTest.java
@@ -31,8 +31,8 @@ import org.apache.james.backends.es.ElasticSearchConfiguration;
 import org.apache.james.backends.es.ElasticSearchIndexer;
 import org.apache.james.backends.es.NodeMappingFactory;
 import org.apache.james.backends.es.ReactorElasticSearchClient;
-import org.apache.james.mailbox.events.Event;
-import org.apache.james.mailbox.events.Group;
+import org.apache.james.events.Event;
+import org.apache.james.events.Group;
 import org.apache.james.mailbox.quota.QuotaFixture.Counts;
 import org.apache.james.mailbox.quota.QuotaFixture.Sizes;
 import org.apache.james.mailbox.store.event.EventFactory;
diff --git a/mailbox/plugin/quota-search-elasticsearch/src/test/java/org/apache/james/quota/search/elasticsearch/json/QuotaRatioToElasticSearchJsonTest.java b/mailbox/plugin/quota-search-elasticsearch/src/test/java/org/apache/james/quota/search/elasticsearch/json/QuotaRatioToElasticSearchJsonTest.java
index a992127..6432375 100644
--- a/mailbox/plugin/quota-search-elasticsearch/src/test/java/org/apache/james/quota/search/elasticsearch/json/QuotaRatioToElasticSearchJsonTest.java
+++ b/mailbox/plugin/quota-search-elasticsearch/src/test/java/org/apache/james/quota/search/elasticsearch/json/QuotaRatioToElasticSearchJsonTest.java
@@ -27,8 +27,8 @@ import java.util.Optional;
 
 import org.apache.james.core.Domain;
 import org.apache.james.core.Username;
-import org.apache.james.mailbox.events.Event;
-import org.apache.james.mailbox.events.MailboxListener.QuotaUsageUpdatedEvent;
+import org.apache.james.events.Event;
+import org.apache.james.mailbox.events.MailboxEvents.QuotaUsageUpdatedEvent;
 import org.apache.james.mailbox.model.QuotaRoot;
 import org.apache.james.mailbox.quota.QuotaFixture;
 import org.apache.james.mailbox.store.event.EventFactory;
diff --git a/mailbox/plugin/spamassassin/src/main/java/org/apache/james/mailbox/spamassassin/SpamAssassinListener.java b/mailbox/plugin/spamassassin/src/main/java/org/apache/james/mailbox/spamassassin/SpamAssassinListener.java
index a842a30..3d7b4d3 100644
--- a/mailbox/plugin/spamassassin/src/main/java/org/apache/james/mailbox/spamassassin/SpamAssassinListener.java
+++ b/mailbox/plugin/spamassassin/src/main/java/org/apache/james/mailbox/spamassassin/SpamAssassinListener.java
@@ -25,12 +25,13 @@ import java.util.stream.Stream;
 import javax.inject.Inject;
 
 import org.apache.james.core.Username;
+import org.apache.james.events.Event;
+import org.apache.james.events.Group;
 import org.apache.james.mailbox.MailboxManager;
 import org.apache.james.mailbox.MailboxSession;
 import org.apache.james.mailbox.Role;
 import org.apache.james.mailbox.SystemMailboxesProvider;
-import org.apache.james.mailbox.events.Event;
-import org.apache.james.mailbox.events.Group;
+import org.apache.james.mailbox.events.MailboxEvents.Added;
 import org.apache.james.mailbox.events.MessageMoveEvent;
 import org.apache.james.mailbox.exception.MailboxException;
 import org.apache.james.mailbox.model.Mailbox;
diff --git a/mailbox/plugin/spamassassin/src/test/java/org/apache/james/mailbox/spamassassin/SpamAssassinListenerTest.java b/mailbox/plugin/spamassassin/src/test/java/org/apache/james/mailbox/spamassassin/SpamAssassinListenerTest.java
index c24ee8e..ce3a993 100644
--- a/mailbox/plugin/spamassassin/src/test/java/org/apache/james/mailbox/spamassassin/SpamAssassinListenerTest.java
+++ b/mailbox/plugin/spamassassin/src/test/java/org/apache/james/mailbox/spamassassin/SpamAssassinListenerTest.java
@@ -33,11 +33,12 @@ import javax.mail.Flags;
 import javax.mail.util.SharedByteArrayInputStream;
 
 import org.apache.james.core.Username;
+import org.apache.james.events.EventListener;
+import org.apache.james.events.Group;
 import org.apache.james.mailbox.DefaultMailboxes;
 import org.apache.james.mailbox.MailboxSession;
 import org.apache.james.mailbox.MailboxSessionUtil;
-import org.apache.james.mailbox.events.Group;
-import org.apache.james.mailbox.events.MailboxListener;
+import org.apache.james.mailbox.events.MailboxEvents.Added;
 import org.apache.james.mailbox.events.MessageMoveEvent;
 import org.apache.james.mailbox.exception.MailboxException;
 import org.apache.james.mailbox.inmemory.manager.InMemoryIntegrationResources;
@@ -95,7 +96,7 @@ class SpamAssassinListenerTest {
         spamCapitalMailboxId = mailboxMapper.create(MailboxPath.forUser(USER, "SPAM"), UID_VALIDITY).block().getMailboxId();
         trashMailboxId = mailboxMapper.create(MailboxPath.forUser(USER, "Trash"), UID_VALIDITY).block().getMailboxId();
 
-        listener = new SpamAssassinListener(spamAssassin, systemMailboxesProvider, mailboxManager, mapperFactory, MailboxListener.ExecutionMode.SYNCHRONOUS);
+        listener = new SpamAssassinListener(spamAssassin, systemMailboxesProvider, mailboxManager, mapperFactory, EventListener.ExecutionMode.SYNCHRONOUS);
     }
 
     @Test
@@ -238,7 +239,7 @@ class SpamAssassinListenerTest {
     void eventShouldCallSpamAssassinHamLearningWhenTheMessageIsAddedInInbox() throws Exception {
         SimpleMailboxMessage message = createMessage(inbox);
 
-        MailboxListener.Added addedEvent = EventFactory.added()
+        Added addedEvent = EventFactory.added()
             .randomEventId()
             .mailboxSession(MAILBOX_SESSION)
             .mailbox(inbox)
@@ -254,7 +255,7 @@ class SpamAssassinListenerTest {
     void eventShouldNotCallSpamAssassinHamLearningWhenTheMessageIsAddedInAMailboxOtherThanInbox() throws Exception {
         SimpleMailboxMessage message = createMessage(mailbox1);
 
-        MailboxListener.Added addedEvent = EventFactory.added()
+        Added addedEvent = EventFactory.added()
             .randomEventId()
             .mailboxSession(MAILBOX_SESSION)
             .mailbox(mailbox1)
diff --git a/mailbox/spring/src/main/java/org/apache/james/mailbox/spring/MailboxInitializer.java b/mailbox/spring/src/main/java/org/apache/james/mailbox/spring/MailboxInitializer.java
index 7d8453b..91938c7 100644
--- a/mailbox/spring/src/main/java/org/apache/james/mailbox/spring/MailboxInitializer.java
+++ b/mailbox/spring/src/main/java/org/apache/james/mailbox/spring/MailboxInitializer.java
@@ -21,9 +21,9 @@ package org.apache.james.mailbox.spring;
 
 import javax.inject.Inject;
 
+import org.apache.james.events.EventBus;
 import org.apache.james.mailbox.MailboxManager;
 import org.apache.james.mailbox.SessionProvider;
-import org.apache.james.mailbox.events.EventBus;
 import org.apache.james.mailbox.store.MailboxSessionMapperFactory;
 import org.apache.james.mailbox.store.event.MailboxAnnotationListener;
 import org.apache.james.mailbox.store.quota.ListeningCurrentQuotaUpdater;
diff --git a/mailbox/store/src/main/java/org/apache/james/mailbox/store/StoreMailboxManager.java b/mailbox/store/src/main/java/org/apache/james/mailbox/store/StoreMailboxManager.java
index 3ec0836..df7eb76 100644
--- a/mailbox/store/src/main/java/org/apache/james/mailbox/store/StoreMailboxManager.java
+++ b/mailbox/store/src/main/java/org/apache/james/mailbox/store/StoreMailboxManager.java
@@ -38,6 +38,7 @@ import javax.inject.Inject;
 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.EventBus;
 import org.apache.james.mailbox.MailboxAnnotationManager;
 import org.apache.james.mailbox.MailboxManager;
 import org.apache.james.mailbox.MailboxPathLocker;
@@ -46,7 +47,6 @@ import org.apache.james.mailbox.MailboxSession;
 import org.apache.james.mailbox.MessageManager;
 import org.apache.james.mailbox.MetadataWithMailboxId;
 import org.apache.james.mailbox.SessionProvider;
-import org.apache.james.mailbox.events.EventBus;
 import org.apache.james.mailbox.events.MailboxIdRegistrationKey;
 import org.apache.james.mailbox.exception.InboxAlreadyCreated;
 import org.apache.james.mailbox.exception.InsufficientRightsException;
diff --git a/mailbox/store/src/main/java/org/apache/james/mailbox/store/StoreMessageIdManager.java b/mailbox/store/src/main/java/org/apache/james/mailbox/store/StoreMessageIdManager.java
index eecc808..9083844 100644
--- a/mailbox/store/src/main/java/org/apache/james/mailbox/store/StoreMessageIdManager.java
+++ b/mailbox/store/src/main/java/org/apache/james/mailbox/store/StoreMessageIdManager.java
@@ -34,6 +34,7 @@ import java.util.stream.Stream;
 import javax.inject.Inject;
 import javax.mail.Flags;
 
+import org.apache.james.events.EventBus;
 import org.apache.james.mailbox.MailboxSession;
 import org.apache.james.mailbox.MessageIdManager;
 import org.apache.james.mailbox.MessageManager;
@@ -41,7 +42,6 @@ import org.apache.james.mailbox.MessageUid;
 import org.apache.james.mailbox.MetadataWithMailboxId;
 import org.apache.james.mailbox.ModSeq;
 import org.apache.james.mailbox.RightManager;
-import org.apache.james.mailbox.events.EventBus;
 import org.apache.james.mailbox.events.MailboxIdRegistrationKey;
 import org.apache.james.mailbox.exception.MailboxException;
 import org.apache.james.mailbox.exception.MailboxNotFoundException;
diff --git a/mailbox/store/src/main/java/org/apache/james/mailbox/store/StoreMessageManager.java b/mailbox/store/src/main/java/org/apache/james/mailbox/store/StoreMessageManager.java
index cb17d19..0437b04 100644
--- a/mailbox/store/src/main/java/org/apache/james/mailbox/store/StoreMessageManager.java
+++ b/mailbox/store/src/main/java/org/apache/james/mailbox/store/StoreMessageManager.java
@@ -45,6 +45,8 @@ import javax.mail.util.SharedFileInputStream;
 
 import org.apache.commons.io.input.TeeInputStream;
 import org.apache.commons.lang3.tuple.Pair;
+import org.apache.james.events.EventBus;
+import org.apache.james.events.EventListener;
 import org.apache.james.mailbox.MailboxManager;
 import org.apache.james.mailbox.MailboxManager.MessageCapabilities;
 import org.apache.james.mailbox.MailboxPathLocker;
@@ -53,9 +55,7 @@ import org.apache.james.mailbox.MessageManager;
 import org.apache.james.mailbox.MessageUid;
 import org.apache.james.mailbox.MetadataWithMailboxId;
 import org.apache.james.mailbox.ModSeq;
-import org.apache.james.mailbox.events.EventBus;
 import org.apache.james.mailbox.events.MailboxIdRegistrationKey;
-import org.apache.james.mailbox.events.MailboxListener;
 import org.apache.james.mailbox.exception.MailboxException;
 import org.apache.james.mailbox.exception.ReadOnlyException;
 import org.apache.james.mailbox.exception.UnsupportedRightException;
@@ -114,7 +114,7 @@ import reactor.core.scheduler.Schedulers;
  * implementations.
  * 
  * This base class take care of dispatching events to the registered
- * {@link MailboxListener} and so help with handling concurrent
+ * {@link EventListener} and so help with handling concurrent
  * {@link MailboxSession}'s.
  */
 public class StoreMessageManager implements MessageManager {
diff --git a/mailbox/store/src/main/java/org/apache/james/mailbox/store/StoreRightManager.java b/mailbox/store/src/main/java/org/apache/james/mailbox/store/StoreRightManager.java
index 89a2213..43578ea 100644
--- a/mailbox/store/src/main/java/org/apache/james/mailbox/store/StoreRightManager.java
+++ b/mailbox/store/src/main/java/org/apache/james/mailbox/store/StoreRightManager.java
@@ -31,11 +31,11 @@ import javax.mail.Flags;
 
 import org.apache.james.core.Domain;
 import org.apache.james.core.Username;
+import org.apache.james.events.EventBus;
 import org.apache.james.mailbox.MailboxSession;
 import org.apache.james.mailbox.RightManager;
 import org.apache.james.mailbox.acl.GroupMembershipResolver;
 import org.apache.james.mailbox.acl.MailboxACLResolver;
-import org.apache.james.mailbox.events.EventBus;
 import org.apache.james.mailbox.events.MailboxIdRegistrationKey;
 import org.apache.james.mailbox.exception.DifferentDomainException;
 import org.apache.james.mailbox.exception.InsufficientRightsException;
diff --git a/mailbox/store/src/main/java/org/apache/james/mailbox/store/event/EventFactory.java b/mailbox/store/src/main/java/org/apache/james/mailbox/store/event/EventFactory.java
index ad2fbed..3caaa3e 100644
--- a/mailbox/store/src/main/java/org/apache/james/mailbox/store/event/EventFactory.java
+++ b/mailbox/store/src/main/java/org/apache/james/mailbox/store/event/EventFactory.java
@@ -29,11 +29,18 @@ 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.events.Event;
-import org.apache.james.mailbox.events.MailboxListener;
+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.events.MessageMoveEvent;
 import org.apache.james.mailbox.model.Mailbox;
 import org.apache.james.mailbox.model.MailboxACL;
@@ -203,13 +210,13 @@ public class EventFactory {
             this.sessionId = sessionId;
         }
 
-        public MailboxListener.MailboxAdded build() {
+        public MailboxAdded build() {
             Preconditions.checkNotNull(path);
             Preconditions.checkNotNull(mailboxId);
             Preconditions.checkNotNull(username);
             Preconditions.checkNotNull(sessionId);
 
-            return new MailboxListener.MailboxAdded(sessionId, username, path, mailboxId, eventId);
+            return new MailboxAdded(sessionId, username, path, mailboxId, eventId);
         }
     }
 
@@ -230,14 +237,14 @@ public class EventFactory {
             this.metaData = ImmutableSortedMap.copyOf(metaData);
         }
 
-        public MailboxListener.Added build() {
+        public Added build() {
             Preconditions.checkNotNull(path);
             Preconditions.checkNotNull(mailboxId);
             Preconditions.checkNotNull(username);
             Preconditions.checkNotNull(sessionId);
             Preconditions.checkNotNull(metaData);
 
-            return new MailboxListener.Added(sessionId, username, path, mailboxId, metaData, eventId);
+            return new Added(sessionId, username, path, mailboxId, metaData, eventId);
         }
     }
 
@@ -258,14 +265,14 @@ public class EventFactory {
             this.metaData = ImmutableSortedMap.copyOf(metaData);
         }
 
-        public MailboxListener.Expunged build() {
+        public Expunged build() {
             Preconditions.checkNotNull(path);
             Preconditions.checkNotNull(mailboxId);
             Preconditions.checkNotNull(username);
             Preconditions.checkNotNull(sessionId);
             Preconditions.checkNotNull(metaData);
 
-            return new MailboxListener.Expunged(sessionId, username, path, mailboxId, metaData, eventId);
+            return new Expunged(sessionId, username, path, mailboxId, metaData, eventId);
         }
     }
 
@@ -286,14 +293,14 @@ public class EventFactory {
             this.aclDiff = aclDiff;
         }
 
-        public MailboxListener.MailboxACLUpdated build() {
+        public MailboxACLUpdated build() {
             Preconditions.checkNotNull(path);
             Preconditions.checkNotNull(mailboxId);
             Preconditions.checkNotNull(username);
             Preconditions.checkNotNull(sessionId);
             Preconditions.checkNotNull(aclDiff);
 
-            return new MailboxListener.MailboxACLUpdated(sessionId, username, path, aclDiff, mailboxId, eventId);
+            return new MailboxACLUpdated(sessionId, username, path, aclDiff, mailboxId, eventId);
         }
     }
 
@@ -320,7 +327,7 @@ public class EventFactory {
             this.totalDeletedSize = totalDeletedSize;
         }
 
-        public MailboxListener.MailboxDeletion build() {
+        public MailboxDeletion build() {
             Preconditions.checkNotNull(path);
             Preconditions.checkNotNull(mailboxId);
             Preconditions.checkNotNull(username);
@@ -329,7 +336,7 @@ public class EventFactory {
             Preconditions.checkNotNull(deletedMessageCount);
             Preconditions.checkNotNull(totalDeletedSize);
 
-            return new MailboxListener.MailboxDeletion(sessionId, username, path, mailboxACL, quotaRoot, deletedMessageCount, totalDeletedSize, mailboxId, eventId);
+            return new MailboxDeletion(sessionId, username, path, mailboxACL, quotaRoot, deletedMessageCount, totalDeletedSize, mailboxId, eventId);
         }
     }
 
@@ -351,14 +358,14 @@ public class EventFactory {
         }
 
 
-        public MailboxListener.MailboxRenamed build() {
+        public MailboxRenamed build() {
             Preconditions.checkNotNull(oldPath);
             Preconditions.checkNotNull(newPath);
             Preconditions.checkNotNull(mailboxId);
             Preconditions.checkNotNull(username);
             Preconditions.checkNotNull(sessionId);
 
-            return new MailboxListener.MailboxRenamed(sessionId, username, oldPath, mailboxId, newPath, eventId);
+            return new MailboxRenamed(sessionId, username, oldPath, mailboxId, newPath, eventId);
         }
     }
 
@@ -380,14 +387,14 @@ public class EventFactory {
         }
 
 
-        public MailboxListener.FlagsUpdated build() {
+        public FlagsUpdated build() {
             Preconditions.checkNotNull(path);
             Preconditions.checkNotNull(mailboxId);
             Preconditions.checkNotNull(username);
             Preconditions.checkNotNull(sessionId);
             Preconditions.checkNotNull(updatedFlags);
 
-            return new MailboxListener.FlagsUpdated(sessionId, username, path, mailboxId, updatedFlags, eventId);
+            return new FlagsUpdated(sessionId, username, path, mailboxId, updatedFlags, eventId);
         }
     }
 
@@ -408,8 +415,8 @@ public class EventFactory {
             this.instant = instant;
         }
 
-        public MailboxListener.QuotaUsageUpdatedEvent build() {
-            return new MailboxListener.QuotaUsageUpdatedEvent(eventId, username, quotaRoot, countQuota, sizeQuota, instant);
+        public QuotaUsageUpdatedEvent build() {
+            return new QuotaUsageUpdatedEvent(eventId, username, quotaRoot, countQuota, sizeQuota, instant);
         }
     }
 
diff --git a/mailbox/store/src/main/java/org/apache/james/mailbox/store/event/MailboxAnnotationListener.java b/mailbox/store/src/main/java/org/apache/james/mailbox/store/event/MailboxAnnotationListener.java
index a26717a..1935b08 100644
--- a/mailbox/store/src/main/java/org/apache/james/mailbox/store/event/MailboxAnnotationListener.java
+++ b/mailbox/store/src/main/java/org/apache/james/mailbox/store/event/MailboxAnnotationListener.java
@@ -22,17 +22,18 @@ import java.util.List;
 
 import javax.inject.Inject;
 
+import org.apache.james.events.Event;
+import org.apache.james.events.EventListener;
+import org.apache.james.events.Group;
 import org.apache.james.mailbox.MailboxSession;
 import org.apache.james.mailbox.SessionProvider;
-import org.apache.james.mailbox.events.Event;
-import org.apache.james.mailbox.events.Group;
-import org.apache.james.mailbox.events.MailboxListener;
+import org.apache.james.mailbox.events.MailboxEvents.MailboxDeletion;
 import org.apache.james.mailbox.model.MailboxAnnotation;
 import org.apache.james.mailbox.model.MailboxId;
 import org.apache.james.mailbox.store.MailboxSessionMapperFactory;
 import org.apache.james.mailbox.store.mail.AnnotationMapper;
 
-public class MailboxAnnotationListener implements MailboxListener.GroupMailboxListener {
+public class MailboxAnnotationListener implements EventListener.GroupEventListener {
     public static final class MailboxAnnotationListenerGroup extends Group {
 
     }
diff --git a/mailbox/store/src/main/java/org/apache/james/mailbox/store/event/SpamEventListener.java b/mailbox/store/src/main/java/org/apache/james/mailbox/store/event/SpamEventListener.java
index 4e8e9c9..3eb5d2d 100644
--- a/mailbox/store/src/main/java/org/apache/james/mailbox/store/event/SpamEventListener.java
+++ b/mailbox/store/src/main/java/org/apache/james/mailbox/store/event/SpamEventListener.java
@@ -18,8 +18,8 @@
  ****************************************************************/
 package org.apache.james.mailbox.store.event;
 
-import org.apache.james.mailbox.events.MailboxListener;
+import org.apache.james.events.EventListener;
 
-public interface SpamEventListener extends MailboxListener.GroupMailboxListener {
+public interface SpamEventListener extends EventListener.GroupEventListener {
 
 }
diff --git a/mailbox/store/src/main/java/org/apache/james/mailbox/store/quota/ListeningCurrentQuotaUpdater.java b/mailbox/store/src/main/java/org/apache/james/mailbox/store/quota/ListeningCurrentQuotaUpdater.java
index d7cbb35..2bafe64 100644
--- a/mailbox/store/src/main/java/org/apache/james/mailbox/store/quota/ListeningCurrentQuotaUpdater.java
+++ b/mailbox/store/src/main/java/org/apache/james/mailbox/store/quota/ListeningCurrentQuotaUpdater.java
@@ -25,11 +25,15 @@ import javax.inject.Inject;
 import org.apache.james.core.Username;
 import org.apache.james.core.quota.QuotaCountUsage;
 import org.apache.james.core.quota.QuotaSizeUsage;
-import org.apache.james.mailbox.events.Event;
-import org.apache.james.mailbox.events.EventBus;
-import org.apache.james.mailbox.events.Group;
-import org.apache.james.mailbox.events.MailboxListener;
-import org.apache.james.mailbox.events.RegistrationKey;
+import org.apache.james.events.Event;
+import org.apache.james.events.EventBus;
+import org.apache.james.events.EventListener;
+import org.apache.james.events.Group;
+import org.apache.james.events.RegistrationKey;
+import org.apache.james.mailbox.events.MailboxEvents.Added;
+import org.apache.james.mailbox.events.MailboxEvents.Expunged;
+import org.apache.james.mailbox.events.MailboxEvents.MailboxDeletion;
+import org.apache.james.mailbox.events.MailboxEvents.MetaDataHoldingEvent;
 import org.apache.james.mailbox.model.QuotaOperation;
 import org.apache.james.mailbox.model.QuotaRoot;
 import org.apache.james.mailbox.quota.CurrentQuotaManager;
@@ -43,7 +47,7 @@ import com.google.common.collect.ImmutableSet;
 import reactor.core.publisher.Mono;
 import reactor.core.scheduler.Schedulers;
 
-public class ListeningCurrentQuotaUpdater implements MailboxListener.ReactiveGroupMailboxListener, QuotaUpdater {
+public class ListeningCurrentQuotaUpdater implements EventListener.ReactiveGroupEventListener, QuotaUpdater {
     public static class ListeningCurrentQuotaUpdaterGroup extends Group {
 
     }
diff --git a/mailbox/store/src/main/java/org/apache/james/mailbox/store/search/LazyMessageSearchIndex.java b/mailbox/store/src/main/java/org/apache/james/mailbox/store/search/LazyMessageSearchIndex.java
index 65c588b..6b71496 100644
--- a/mailbox/store/src/main/java/org/apache/james/mailbox/store/search/LazyMessageSearchIndex.java
+++ b/mailbox/store/src/main/java/org/apache/james/mailbox/store/search/LazyMessageSearchIndex.java
@@ -26,12 +26,12 @@ import java.util.concurrent.ConcurrentHashMap;
 
 import javax.mail.Flags;
 
+import org.apache.james.events.Group;
 import org.apache.james.mailbox.MailboxManager;
 import org.apache.james.mailbox.MailboxManager.SearchCapabilities;
 import org.apache.james.mailbox.MailboxSession;
 import org.apache.james.mailbox.MessageUid;
 import org.apache.james.mailbox.SessionProvider;
-import org.apache.james.mailbox.events.Group;
 import org.apache.james.mailbox.exception.MailboxException;
 import org.apache.james.mailbox.exception.UnsupportedSearchException;
 import org.apache.james.mailbox.model.Mailbox;
diff --git a/mailbox/store/src/main/java/org/apache/james/mailbox/store/search/ListeningMessageSearchIndex.java b/mailbox/store/src/main/java/org/apache/james/mailbox/store/search/ListeningMessageSearchIndex.java
index 5f06c3d..1eae3e9 100644
--- a/mailbox/store/src/main/java/org/apache/james/mailbox/store/search/ListeningMessageSearchIndex.java
+++ b/mailbox/store/src/main/java/org/apache/james/mailbox/store/search/ListeningMessageSearchIndex.java
@@ -23,11 +23,16 @@ import java.util.List;
 
 import javax.mail.Flags;
 
+import org.apache.james.events.Event;
+import org.apache.james.events.EventListener;
 import org.apache.james.mailbox.MailboxSession;
 import org.apache.james.mailbox.MessageUid;
 import org.apache.james.mailbox.SessionProvider;
-import org.apache.james.mailbox.events.Event;
-import org.apache.james.mailbox.events.MailboxListener;
+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.MailboxDeletion;
+import org.apache.james.mailbox.events.MailboxEvents.MailboxEvent;
 import org.apache.james.mailbox.model.Mailbox;
 import org.apache.james.mailbox.model.MailboxId;
 import org.apache.james.mailbox.model.MessageRange;
@@ -42,10 +47,10 @@ import reactor.core.publisher.Flux;
 import reactor.core.publisher.Mono;
 
 /**
- * {@link MessageSearchIndex} which needs to get registered as global {@link MailboxListener} and so get
+ * {@link MessageSearchIndex} which needs to get registered as global {@link EventListener} and so get
  * notified about message changes. This will then allow to update the underlying index.
  */
-public abstract class ListeningMessageSearchIndex implements MessageSearchIndex, MailboxListener.ReactiveGroupMailboxListener {
+public abstract class ListeningMessageSearchIndex implements MessageSearchIndex, EventListener.ReactiveGroupEventListener {
     protected static final int UNLIMITED = -1;
     private final MailboxSessionMapperFactory factory;
     private final SessionProvider sessionProvider;
diff --git a/mailbox/store/src/test/java/org/apache/james/mailbox/store/AbstractMessageIdManagerSideEffectTest.java b/mailbox/store/src/test/java/org/apache/james/mailbox/store/AbstractMessageIdManagerSideEffectTest.java
index 63e87f1..8381a1e 100644
--- a/mailbox/store/src/test/java/org/apache/james/mailbox/store/AbstractMessageIdManagerSideEffectTest.java
+++ b/mailbox/store/src/test/java/org/apache/james/mailbox/store/AbstractMessageIdManagerSideEffectTest.java
@@ -38,6 +38,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.events.EventBus;
 import org.apache.james.mailbox.MailboxSession;
 import org.apache.james.mailbox.MailboxSessionUtil;
 import org.apache.james.mailbox.MessageIdManager;
@@ -46,10 +47,12 @@ import org.apache.james.mailbox.MessageManager.FlagsUpdateMode;
 import org.apache.james.mailbox.MessageUid;
 import org.apache.james.mailbox.MetadataWithMailboxId;
 import org.apache.james.mailbox.ModSeq;
-import org.apache.james.mailbox.events.EventBus;
 import org.apache.james.mailbox.events.EventBusTestFixture;
 import org.apache.james.mailbox.events.InVMEventBus;
-import org.apache.james.mailbox.events.MailboxListener;
+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.MailboxEvent;
 import org.apache.james.mailbox.events.MemoryEventDeadLetters;
 import org.apache.james.mailbox.events.MessageMoveEvent;
 import org.apache.james.mailbox.events.delivery.InVmEventDelivery;
@@ -143,10 +146,10 @@ public abstract class AbstractMessageIdManagerSideEffectTest {
         messageIdManager.delete(messageId, ImmutableList.of(mailbox1.getMailboxId()), session);
 
         assertThat(eventCollector.getEvents())
-            .filteredOn(event -> event instanceof MailboxListener.Expunged)
+            .filteredOn(event -> event instanceof Expunged)
             .hasSize(1).first()
             .satisfies(e -> {
-                MailboxListener.Expunged event = (MailboxListener.Expunged) e;
+                Expunged event = (Expunged) e;
                 assertThat(event.getMailboxId()).isEqualTo(mailbox1.getMailboxId());
                 assertThat(event.getMailboxPath()).isEqualTo(mailbox1.generateAssociatedPath());
                 assertThat(event.getExpunged().values()).containsOnly(simpleMessageMetaData);
@@ -168,13 +171,13 @@ public abstract class AbstractMessageIdManagerSideEffectTest {
         eventBus.register(eventCollector);
         messageIdManager.delete(ImmutableList.of(messageId1, messageId2), session);
 
-        AbstractListAssert<?, List<? extends MailboxListener.Expunged>, MailboxListener.Expunged, ObjectAssert<MailboxListener.Expunged>> events =
+        AbstractListAssert<?, List<? extends Expunged>, Expunged, ObjectAssert<Expunged>> events =
             assertThat(eventCollector.getEvents())
-                .filteredOn(event -> event instanceof MailboxListener.Expunged)
+                .filteredOn(event -> event instanceof Expunged)
                 .hasSize(2)
-                .extracting(event -> (MailboxListener.Expunged) event);
-        events.extracting(MailboxListener.MailboxEvent::getMailboxId).containsOnly(mailbox1.getMailboxId(), mailbox1.getMailboxId());
-        events.extracting(MailboxListener.Expunged::getExpunged)
+                .extracting(event -> (Expunged) event);
+        events.extracting(MailboxEvent::getMailboxId).containsOnly(mailbox1.getMailboxId(), mailbox1.getMailboxId());
+        events.extracting(Expunged::getExpunged)
             .containsOnly(ImmutableSortedMap.of(simpleMessageMetaData1.getUid(), simpleMessageMetaData1),
                 ImmutableSortedMap.of(simpleMessageMetaData2.getUid(), simpleMessageMetaData2));
     }
@@ -332,8 +335,8 @@ public abstract class AbstractMessageIdManagerSideEffectTest {
         messageIdManager.setInMailboxes(messageId, ImmutableList.of(mailbox1.getMailboxId(), mailbox2.getMailboxId()), session);
 
         assertThat(eventCollector.getEvents()).filteredOn(event -> event instanceof MessageMoveEvent).hasSize(1);
-        assertThat(eventCollector.getEvents()).filteredOn(event -> event instanceof MailboxListener.Added).hasSize(1)
-            .extracting(event -> (MailboxListener.Added) event).extracting(MailboxListener.Added::getMailboxId)
+        assertThat(eventCollector.getEvents()).filteredOn(event -> event instanceof Added).hasSize(1)
+            .extracting(event -> (Added) event).extracting(Added::getMailboxId)
             .containsOnly(mailbox1.getMailboxId());
     }
 
@@ -348,8 +351,8 @@ public abstract class AbstractMessageIdManagerSideEffectTest {
         messageIdManager.getMessage(messageId, FetchGroup.MINIMAL, session);
 
         assertThat(eventCollector.getEvents()).filteredOn(event -> event instanceof MessageMoveEvent).hasSize(1);
-        assertThat(eventCollector.getEvents()).filteredOn(event -> event instanceof MailboxListener.Added).hasSize(2)
-            .extracting(event -> (MailboxListener.Added) event).extracting(MailboxListener.Added::getMailboxId)
+        assertThat(eventCollector.getEvents()).filteredOn(event -> event instanceof Added).hasSize(2)
+            .extracting(event -> (Added) event).extracting(Added::getMailboxId)
             .containsOnly(mailbox1.getMailboxId(), mailbox3.getMailboxId());
     }
 
@@ -381,11 +384,11 @@ public abstract class AbstractMessageIdManagerSideEffectTest {
         messageIdManager.setInMailboxes(messageId, ImmutableList.of(mailbox1.getMailboxId(), mailbox3.getMailboxId()), session);
 
         assertThat(eventCollector.getEvents()).filteredOn(event -> event instanceof MessageMoveEvent).hasSize(1);
-        assertThat(eventCollector.getEvents()).filteredOn(event -> event instanceof MailboxListener.Added).hasSize(1)
-            .extracting(event -> (MailboxListener.Added) event).extracting(MailboxListener.Added::getMailboxId)
+        assertThat(eventCollector.getEvents()).filteredOn(event -> event instanceof Added).hasSize(1)
+            .extracting(event -> (Added) event).extracting(Added::getMailboxId)
             .containsOnly(mailbox3.getMailboxId());
-        assertThat(eventCollector.getEvents()).filteredOn(event -> event instanceof MailboxListener.Expunged).hasSize(1)
-            .extracting(event -> (MailboxListener.Expunged) event).extracting(MailboxListener.Expunged::getMailboxId)
+        assertThat(eventCollector.getEvents()).filteredOn(event -> event instanceof Expunged).hasSize(1)
+            .extracting(event -> (Expunged) event).extracting(Expunged::getMailboxId)
             .containsOnly(mailbox2.getMailboxId());
     }
 
@@ -448,7 +451,7 @@ public abstract class AbstractMessageIdManagerSideEffectTest {
         eventBus.register(eventCollector);
         messageIdManager.setFlags(newFlags, MessageManager.FlagsUpdateMode.ADD, messageId, ImmutableList.of(mailbox1.getMailboxId(), mailbox2.getMailboxId()), session);
 
-        assertThat(eventCollector.getEvents()).hasSize(2).allSatisfy(event -> assertThat(event).isInstanceOf(MailboxListener.FlagsUpdated.class));
+        assertThat(eventCollector.getEvents()).hasSize(2).allSatisfy(event -> assertThat(event).isInstanceOf(FlagsUpdated.class));
     }
 
     @Test
@@ -473,9 +476,9 @@ public abstract class AbstractMessageIdManagerSideEffectTest {
             .newFlags(newFlags)
             .build();
 
-        assertThat(eventCollector.getEvents()).hasSize(1).first().isInstanceOf(MailboxListener.FlagsUpdated.class)
+        assertThat(eventCollector.getEvents()).hasSize(1).first().isInstanceOf(FlagsUpdated.class)
             .satisfies(e -> {
-                MailboxListener.FlagsUpdated event = (MailboxListener.FlagsUpdated) e;
+                FlagsUpdated event = (FlagsUpdated) e;
                 assertThat(event.getUpdatedFlags()).containsOnly(updatedFlags);
                 assertThat(event.getMailboxId()).isEqualTo(mailbox2.getMailboxId());
             });
diff --git a/mailbox/store/src/test/java/org/apache/james/mailbox/store/StoreRightManagerTest.java b/mailbox/store/src/test/java/org/apache/james/mailbox/store/StoreRightManagerTest.java
index a315927..8d78e2c 100644
--- a/mailbox/store/src/test/java/org/apache/james/mailbox/store/StoreRightManagerTest.java
+++ b/mailbox/store/src/test/java/org/apache/james/mailbox/store/StoreRightManagerTest.java
@@ -31,13 +31,13 @@ import static org.mockito.Mockito.when;
 import javax.mail.Flags;
 
 import org.apache.james.core.Username;
+import org.apache.james.events.EventBus;
 import org.apache.james.mailbox.MailboxSession;
 import org.apache.james.mailbox.MailboxSessionUtil;
 import org.apache.james.mailbox.acl.GroupMembershipResolver;
 import org.apache.james.mailbox.acl.MailboxACLResolver;
... 2036 lines suppressed ...


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