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

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


The following commit(s) were added to refs/heads/master by this push:
     new a2c89b007b JAMES-4154 Refactor deletion callback for Postgres app 
(#2886)
a2c89b007b is described below

commit a2c89b007bcf736cc1df3f143945dd0724b791a0
Author: Trần Hồng Quân <[email protected]>
AuthorDate: Fri Dec 19 13:45:46 2025 +0700

    JAMES-4154 Refactor deletion callback for Postgres app (#2886)
---
 .../apache/james/mailbox/events/MailboxEvents.java |   3 +-
 .../mailbox/cassandra/DeleteMessageListener.java   |   2 +-
 .../james/event/json/MailboxEventSerializer.scala  |  10 +-
 .../MessageContentDeletionSerializationTest.java   |  43 ++++++-
 ...ostgresDeletedMessageVaultDeletionCallback.java | 123 ---------------------
 .../DeletedMessageVaultDeletionListener.java       |  15 ++-
 .../mailbox/postgres/DeleteMessageListener.java    |  48 +++++---
 .../PostgresMailboxSessionMapperFactory.java       |   8 +-
 .../postgres/DeleteMessageListenerTest.java        |   2 +-
 .../postgres/DeleteMessageListenerWithRLSTest.java |   2 +-
 .../PostgresMailboxManagerAttachmentTest.java      |   4 +-
 .../postgres/PostgresMailboxManagerProvider.java   |   2 +-
 .../postgres/PostgresTestSystemFixture.java        |   2 +-
 .../james/mailbox/store/event/EventFactory.java    |  32 ++++--
 .../org/apache/james/PostgresJamesServerMain.java  |   4 +-
 .../james/modules/data/CassandraJmapModule.java    |   4 +-
 .../event/ContentDeletionEventBusModule.java       |  29 -----
 .../DistributedDeletedMessageVaultModule.java      |   1 +
 .../mailbox/PostgresDeletedMessageVaultModule.java |  11 +-
 .../modules/mailbox/PostgresMailboxModule.java     |   1 -
 ...stgresMemoryContentDeletionEventBusModule.java} |  47 ++++----
 .../james/modules/data/PostgresDataJmapModule.java |  11 +-
 ...sMessageFastViewProjectionDeletionCallback.java |  44 --------
 ...MessageFastViewProjectionDeletionListener.java} |  11 +-
 .../postgres-webadmin-integration-test/pom.xml     |   6 +
 ...PostgresDeletedMessageVaultIntegrationTest.java |  95 +++-------------
 ...PostgresDeletedMessageVaultIntegrationTest.java |  66 +++++++++++
 .../src/test/resources/listeners.xml               |   4 +
 28 files changed, 261 insertions(+), 369 deletions(-)

diff --git 
a/mailbox/api/src/main/java/org/apache/james/mailbox/events/MailboxEvents.java 
b/mailbox/api/src/main/java/org/apache/james/mailbox/events/MailboxEvents.java
index d9bba5159d..a7bdcf9d41 100644
--- 
a/mailbox/api/src/main/java/org/apache/james/mailbox/events/MailboxEvents.java
+++ 
b/mailbox/api/src/main/java/org/apache/james/mailbox/events/MailboxEvents.java
@@ -537,7 +537,8 @@ public interface MailboxEvents {
     }
 
     record MessageContentDeletionEvent(EventId eventId, Username username, 
MailboxId mailboxId, MessageId messageId, long size,
-                                       Instant internalDate, boolean 
hasAttachments, String headerBlobId, String bodyBlobId) implements Event {
+                                       Instant internalDate, boolean 
hasAttachments, Optional<String> headerBlobId, Optional<String> headerContent,
+                                       String bodyBlobId) implements Event {
 
         @Override
         public EventId getEventId() {
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 f20dc5ca3e..59278aad9b 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
@@ -216,8 +216,8 @@ public class DeleteMessageListener implements 
EventListener.ReactiveGroupEventLi
             .size(message.getSize())
             .instant(message.getInternalDate().toInstant())
             .hasAttachments(!message.getAttachments().isEmpty())
-            .headerBlobId(message.getHeaderId().asString())
             .bodyBlobId(message.getBodyId().asString())
+            .headerBlobId(message.getHeaderId().asString())
             .build(),
             ImmutableSet.of()));
     }
diff --git 
a/mailbox/event/json/src/main/scala/org/apache/james/event/json/MailboxEventSerializer.scala
 
b/mailbox/event/json/src/main/scala/org/apache/james/event/json/MailboxEventSerializer.scala
index 5e428aac42..9722b2dc6e 100644
--- 
a/mailbox/event/json/src/main/scala/org/apache/james/event/json/MailboxEventSerializer.scala
+++ 
b/mailbox/event/json/src/main/scala/org/apache/james/event/json/MailboxEventSerializer.scala
@@ -141,9 +141,10 @@ private object DTO {
                                          size: Long,
                                          internalDate: Instant,
                                          hasAttachments: Boolean,
-                                         headerBlobId: String,
+                                         headerBlobId: Option[String],
+                                         headerContent: Option[String],
                                          bodyBlobId: String) extends Event {
-    override def toJava: JavaEvent = new 
JavaMessageContentDeletionEvent(eventId, username, mailboxId, messageId, size, 
internalDate, hasAttachments, headerBlobId, bodyBlobId)
+    override def toJava: JavaEvent = new 
JavaMessageContentDeletionEvent(eventId, username, mailboxId, messageId, size, 
internalDate, hasAttachments, headerBlobId.toJava, headerContent.toJava, 
bodyBlobId)
   }
 }
 
@@ -247,8 +248,9 @@ private object ScalaConverter {
       size = event.size(),
       internalDate = event.internalDate(),
       hasAttachments = event.hasAttachments,
-      headerBlobId = event.headerBlobId(),
-      bodyBlobId = event.bodyBlobId())
+      headerBlobId = event.headerBlobId().toScala,
+      bodyBlobId = event.bodyBlobId(),
+      headerContent = event.headerContent().toScala)
 
   def toScala(javaEvent: JavaEvent): Event = javaEvent match {
     case e: JavaAdded => toScala(e)
diff --git 
a/mailbox/event/json/src/test/java/org/apache/james/event/json/MessageContentDeletionSerializationTest.java
 
b/mailbox/event/json/src/test/java/org/apache/james/event/json/MessageContentDeletionSerializationTest.java
index 9edb6e5d2d..4ac8929cc4 100644
--- 
a/mailbox/event/json/src/test/java/org/apache/james/event/json/MessageContentDeletionSerializationTest.java
+++ 
b/mailbox/event/json/src/test/java/org/apache/james/event/json/MessageContentDeletionSerializationTest.java
@@ -25,6 +25,7 @@ import static 
org.apache.james.event.json.SerializerFixture.EVENT_SERIALIZER;
 import static org.assertj.core.api.Assertions.assertThat;
 
 import java.time.Instant;
+import java.util.Optional;
 
 import org.apache.james.core.Username;
 import 
org.apache.james.mailbox.events.MailboxEvents.MessageContentDeletionEvent;
@@ -41,7 +42,9 @@ class MessageContentDeletionSerializationTest {
     private static final long SIZE = 12345L;
     private static final Instant INTERNAL_DATE = 
Instant.parse("2024-12-15T08:23:45Z");
     private static final boolean HAS_ATTACHMENTS = true;
-    private static final String HEADER_BLOB_ID = "header-blob-id";
+    private static final Optional<String> HEADER_BLOB_ID = 
Optional.of("header-blob-id");
+    private static final Optional<String> HEADER_CONTENT = 
Optional.of("Header: value");
+    private static final Optional<String> EMPTY_HEADER_CONTENT = 
Optional.empty();
     private static final String BODY_BLOB_ID = "body-blob-id";
 
     private static final MessageContentDeletionEvent EVENT = new 
MessageContentDeletionEvent(
@@ -53,9 +56,39 @@ class MessageContentDeletionSerializationTest {
         INTERNAL_DATE,
         HAS_ATTACHMENTS,
         HEADER_BLOB_ID,
+        HEADER_CONTENT,
+        BODY_BLOB_ID);
+
+    private static final MessageContentDeletionEvent 
EVENT_WITHOUT_HEADER_CONTENT = new MessageContentDeletionEvent(
+        EVENT_ID,
+        USERNAME,
+        MAILBOX_ID,
+        MESSAGE_ID,
+        SIZE,
+        INTERNAL_DATE,
+        HAS_ATTACHMENTS,
+        HEADER_BLOB_ID,
+        EMPTY_HEADER_CONTENT,
         BODY_BLOB_ID);
 
     private static final String JSON = """
+        {
+            "MessageContentDeletionEvent": {
+                "eventId": "6e0dd59d-660e-4d9b-b22f-0354479f47b4",
+                "username": "[email protected]",
+                "size": 12345,
+                "hasAttachments": true,
+                "internalDate": "2024-12-15T08:23:45Z",
+                "mailboxId": "18",
+                "headerBlobId": "header-blob-id",
+                "messageId": "42",
+                "bodyBlobId": "body-blob-id",
+                "headerContent": "Header: value"
+            }
+        }
+        """;
+
+    private static final String JSON_WITHOUT_HEADER_CONTENT = """
         {
             "MessageContentDeletionEvent": {
                 "eventId": "6e0dd59d-660e-4d9b-b22f-0354479f47b4",
@@ -73,14 +106,14 @@ class MessageContentDeletionSerializationTest {
 
     @Test
     void messageContentDeletionEventShouldBeWellSerialized() {
-        assertThatJson(EVENT_SERIALIZER.toJson(EVENT))
-            .isEqualTo(JSON);
+        assertThatJson(EVENT_SERIALIZER.toJson(EVENT)).isEqualTo(JSON);
+        
assertThatJson(EVENT_SERIALIZER.toJson(EVENT_WITHOUT_HEADER_CONTENT)).isEqualTo(JSON_WITHOUT_HEADER_CONTENT);
     }
 
     @Test
     void messageContentDeletionEventShouldBeWellDeserialized() {
-        assertThat(EVENT_SERIALIZER.fromJson(JSON).get())
-            .isEqualTo(EVENT);
+        assertThat(EVENT_SERIALIZER.fromJson(JSON).get()).isEqualTo(EVENT);
+        
assertThat(EVENT_SERIALIZER.fromJson(JSON_WITHOUT_HEADER_CONTENT).get()).isEqualTo(EVENT_WITHOUT_HEADER_CONTENT);
     }
 
 }
diff --git 
a/mailbox/plugin/deleted-messages-vault-postgres/src/main/java/org/apache/james/vault/metadata/PostgresDeletedMessageVaultDeletionCallback.java
 
b/mailbox/plugin/deleted-messages-vault-postgres/src/main/java/org/apache/james/vault/metadata/PostgresDeletedMessageVaultDeletionCallback.java
deleted file mode 100644
index 224d2a492e..0000000000
--- 
a/mailbox/plugin/deleted-messages-vault-postgres/src/main/java/org/apache/james/vault/metadata/PostgresDeletedMessageVaultDeletionCallback.java
+++ /dev/null
@@ -1,123 +0,0 @@
-/****************************************************************
- * Licensed to the Apache Software Foundation (ASF) under one   *
- * or more contributor license agreements.  See the NOTICE file *
- * distributed with this work for additional information        *
- * regarding copyright ownership.  The ASF licenses this file   *
- * to you under the Apache License, Version 2.0 (the            *
- * "License"); you may not use this file except in compliance   *
- * with the License.  You may obtain a copy of the License at   *
- *                                                              *
- *   http://www.apache.org/licenses/LICENSE-2.0                 *
- *                                                              *
- * Unless required by applicable law or agreed to in writing,   *
- * software distributed under the License is distributed on an  *
- * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY       *
- * KIND, either express or implied.  See the License for the    *
- * specific language governing permissions and limitations      *
- * under the License.                                           *
- ****************************************************************/
-
-package org.apache.james.vault.metadata;
-
-import java.io.IOException;
-import java.io.InputStream;
-import java.io.SequenceInputStream;
-import java.time.Clock;
-import java.time.ZoneOffset;
-import java.time.ZonedDateTime;
-import java.util.Optional;
-import java.util.Set;
-
-import jakarta.inject.Inject;
-
-import org.apache.james.blob.api.BlobStore;
-import org.apache.james.core.MailAddress;
-import org.apache.james.core.MaybeSender;
-import org.apache.james.core.Username;
-import org.apache.james.mailbox.model.MailboxId;
-import org.apache.james.mailbox.model.MessageId;
-import org.apache.james.mailbox.postgres.DeleteMessageListener;
-import org.apache.james.mailbox.postgres.mail.MessageRepresentation;
-import org.apache.james.mime4j.MimeIOException;
-import org.apache.james.mime4j.codec.DecodeMonitor;
-import org.apache.james.mime4j.dom.Message;
-import org.apache.james.mime4j.dom.address.Mailbox;
-import org.apache.james.mime4j.message.DefaultMessageBuilder;
-import org.apache.james.mime4j.stream.MimeConfig;
-import org.apache.james.server.core.Envelope;
-import org.apache.james.vault.DeletedMessage;
-import org.apache.james.vault.DeletedMessageVault;
-import org.slf4j.Logger;
-import org.slf4j.LoggerFactory;
-
-import com.github.fge.lambdas.Throwing;
-import com.google.common.collect.ImmutableSet;
-
-import reactor.core.publisher.Mono;
-
-public class PostgresDeletedMessageVaultDeletionCallback implements 
DeleteMessageListener.DeletionCallback {
-    private static final Logger LOGGER = 
LoggerFactory.getLogger(PostgresDeletedMessageVaultDeletionCallback.class);
-
-    private final DeletedMessageVault deletedMessageVault;
-    private final BlobStore blobStore;
-    private final Clock clock;
-
-    @Inject
-    public PostgresDeletedMessageVaultDeletionCallback(DeletedMessageVault 
deletedMessageVault, BlobStore blobStore, Clock clock) {
-        this.deletedMessageVault = deletedMessageVault;
-        this.blobStore = blobStore;
-        this.clock = clock;
-    }
-
-    @Override
-    public Mono<Void> forMessage(MessageRepresentation message, MailboxId 
mailboxId, Username owner) {
-        return Mono.fromSupplier(Throwing.supplier(() -> 
message.getHeaderContent().getInputStream()))
-            .flatMap(headerStream -> {
-                Optional<Message> mimeMessage = parseMessage(headerStream, 
message.getMessageId());
-                DeletedMessage deletedMessage = DeletedMessage.builder()
-                    .messageId(message.getMessageId())
-                    .originMailboxes(mailboxId)
-                    .user(owner)
-                    
.deliveryDate(ZonedDateTime.ofInstant(message.getInternalDate().toInstant(), 
ZoneOffset.UTC))
-                    .deletionDate(ZonedDateTime.ofInstant(clock.instant(), 
ZoneOffset.UTC))
-                    .sender(retrieveSender(mimeMessage))
-                    .recipients(retrieveRecipients(mimeMessage))
-                    .hasAttachment(!message.getAttachments().isEmpty())
-                    .size(message.getSize())
-                    .subject(mimeMessage.map(Message::getSubject))
-                    .build();
-
-                return 
Mono.from(blobStore.readReactive(blobStore.getDefaultBucketName(), 
message.getBodyBlobId(), BlobStore.StoragePolicy.LOW_COST))
-                    .map(bodyStream -> new SequenceInputStream(headerStream, 
bodyStream))
-                    .flatMap(bodyStream -> 
Mono.from(deletedMessageVault.append(deletedMessage, bodyStream)));
-            });
-    }
-
-    private Optional<Message> parseMessage(InputStream inputStream, MessageId 
messageId) {
-        DefaultMessageBuilder messageBuilder = new DefaultMessageBuilder();
-        messageBuilder.setMimeEntityConfig(MimeConfig.PERMISSIVE);
-        messageBuilder.setDecodeMonitor(DecodeMonitor.SILENT);
-        try {
-            return 
Optional.ofNullable(messageBuilder.parseMessage(inputStream));
-        } catch (MimeIOException e) {
-            LOGGER.warn("Can not parse the message {}", messageId, e);
-            return Optional.empty();
-        } catch (IOException e) {
-            throw new RuntimeException(e);
-        }
-    }
-
-    private MaybeSender retrieveSender(Optional<Message> mimeMessage) {
-        return mimeMessage
-            .map(Message::getSender)
-            .map(Mailbox::getAddress)
-            .map(MaybeSender::getMailSender)
-            .orElse(MaybeSender.nullSender());
-    }
-
-    private Set<MailAddress> retrieveRecipients(Optional<Message> 
maybeMessage) {
-        return maybeMessage.map(message -> Envelope.fromMime4JMessage(message, 
Envelope.ValidationPolicy.IGNORE))
-            .map(Envelope::getRecipients)
-            .orElse(ImmutableSet.of());
-    }
-}
diff --git 
a/server/container/guice/distributed/src/main/java/org/apache/james/modules/mailbox/DeletedMessageVaultDeletionListener.java
 
b/mailbox/plugin/deleted-messages-vault/src/main/java/org/apache/james/vault/DeletedMessageVaultDeletionListener.java
similarity index 89%
rename from 
server/container/guice/distributed/src/main/java/org/apache/james/modules/mailbox/DeletedMessageVaultDeletionListener.java
rename to 
mailbox/plugin/deleted-messages-vault/src/main/java/org/apache/james/vault/DeletedMessageVaultDeletionListener.java
index f80eb04e26..bfdc1cc9e0 100644
--- 
a/server/container/guice/distributed/src/main/java/org/apache/james/modules/mailbox/DeletedMessageVaultDeletionListener.java
+++ 
b/mailbox/plugin/deleted-messages-vault/src/main/java/org/apache/james/vault/DeletedMessageVaultDeletionListener.java
@@ -17,12 +17,13 @@
  * under the License.                                           *
  ****************************************************************/
 
-package org.apache.james.modules.mailbox;
+package org.apache.james.vault;
 
 import java.io.ByteArrayInputStream;
 import java.io.IOException;
 import java.io.InputStream;
 import java.io.SequenceInputStream;
+import java.nio.charset.StandardCharsets;
 import java.time.Clock;
 import java.time.ZoneOffset;
 import java.time.ZonedDateTime;
@@ -47,8 +48,6 @@ import org.apache.james.mime4j.dom.address.Mailbox;
 import org.apache.james.mime4j.message.DefaultMessageBuilder;
 import org.apache.james.mime4j.stream.MimeConfig;
 import org.apache.james.server.core.Envelope;
-import org.apache.james.vault.DeletedMessage;
-import org.apache.james.vault.DeletedMessageVault;
 import org.reactivestreams.Publisher;
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
@@ -99,7 +98,7 @@ public class DeletedMessageVaultDeletionListener implements 
EventListener.Reacti
     }
 
     public Mono<Void> forMessage(MessageContentDeletionEvent 
messageContentDeletionEvent) {
-        return Mono.from(blobStore.readBytes(blobStore.getDefaultBucketName(), 
blobIdFactory.parse(messageContentDeletionEvent.headerBlobId()), 
BlobStore.StoragePolicy.LOW_COST))
+        return fetchMessageHeaderBytes(messageContentDeletionEvent)
             .flatMap(bytes -> {
                 Optional<Message> mimeMessage = parseMessage(new 
ByteArrayInputStream(bytes), messageContentDeletionEvent.messageId());
                 DeletedMessage deletedMessage = DeletedMessage.builder()
@@ -121,6 +120,14 @@ public class DeletedMessageVaultDeletionListener 
implements EventListener.Reacti
             });
     }
 
+    private Mono<byte[]> fetchMessageHeaderBytes(MessageContentDeletionEvent 
messageContentDeletionEvent) {
+        return Mono.justOrEmpty(messageContentDeletionEvent.headerBlobId())
+            .flatMap(headerBlobId -> 
Mono.from(blobStore.readBytes(blobStore.getDefaultBucketName(), 
blobIdFactory.parse(headerBlobId), BlobStore.StoragePolicy.LOW_COST)))
+            
.switchIfEmpty(Mono.justOrEmpty(messageContentDeletionEvent.headerContent())
+                .map(headerContent -> 
headerContent.getBytes(StandardCharsets.UTF_8))
+                .switchIfEmpty(Mono.error(() -> new 
IllegalArgumentException("No header content nor header blob id provided"))));
+    }
+
     private Optional<Message> parseMessage(InputStream inputStream, MessageId 
messageId) {
         DefaultMessageBuilder messageBuilder = new DefaultMessageBuilder();
         messageBuilder.setMimeEntityConfig(MimeConfig.PERMISSIVE);
diff --git 
a/mailbox/postgres/src/main/java/org/apache/james/mailbox/postgres/DeleteMessageListener.java
 
b/mailbox/postgres/src/main/java/org/apache/james/mailbox/postgres/DeleteMessageListener.java
index c6fc63c868..5f31c3ba9b 100644
--- 
a/mailbox/postgres/src/main/java/org/apache/james/mailbox/postgres/DeleteMessageListener.java
+++ 
b/mailbox/postgres/src/main/java/org/apache/james/mailbox/postgres/DeleteMessageListener.java
@@ -19,16 +19,19 @@
 
 package org.apache.james.mailbox.postgres;
 
-import java.util.Set;
-import java.util.function.Function;
+import java.nio.charset.StandardCharsets;
 
 import jakarta.inject.Inject;
+import jakarta.inject.Named;
 
+import org.apache.commons.io.IOUtils;
 import org.apache.james.blob.api.BlobStore;
 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.Group;
+import org.apache.james.mailbox.events.MailboxEvents;
 import org.apache.james.mailbox.events.MailboxEvents.Expunged;
 import org.apache.james.mailbox.events.MailboxEvents.MailboxDeletion;
 import org.apache.james.mailbox.model.MailboxId;
@@ -38,31 +41,29 @@ import 
org.apache.james.mailbox.postgres.mail.dao.PostgresAttachmentDAO;
 import org.apache.james.mailbox.postgres.mail.dao.PostgresMailboxMessageDAO;
 import org.apache.james.mailbox.postgres.mail.dao.PostgresMessageDAO;
 import org.apache.james.mailbox.postgres.mail.dao.PostgresThreadDAO;
+import org.apache.james.mailbox.store.event.EventFactory;
 import org.apache.james.util.FunctionalUtils;
 import org.apache.james.util.ReactorUtils;
 import org.reactivestreams.Publisher;
 
+import com.google.common.collect.ImmutableSet;
+
 import reactor.core.publisher.Flux;
 import reactor.core.publisher.Mono;
 
 public class DeleteMessageListener implements 
EventListener.ReactiveGroupEventListener {
-    @FunctionalInterface
-    public interface DeletionCallback {
-        Mono<Void> forMessage(MessageRepresentation messageRepresentation, 
MailboxId mailboxId, Username owner);
-    }
-
     public static class DeleteMessageListenerGroup extends Group {
     }
 
     public static final int LOW_CONCURRENCY = 4;
+    public static final String CONTENT_DELETION = "contentDeletion";
 
     private final BlobStore blobStore;
-    private final Set<DeletionCallback> deletionCallbackList;
-
     private final PostgresMessageDAO.Factory messageDAOFactory;
     private final PostgresMailboxMessageDAO.Factory mailboxMessageDAOFactory;
     private final PostgresAttachmentDAO.Factory attachmentDAOFactory;
     private final PostgresThreadDAO.Factory threadDAOFactory;
+    private final EventBus contentDeletionEventBus;
 
     @Inject
     public DeleteMessageListener(BlobStore blobStore,
@@ -70,13 +71,13 @@ public class DeleteMessageListener implements 
EventListener.ReactiveGroupEventLi
                                  PostgresMessageDAO.Factory messageDAOFactory,
                                  PostgresAttachmentDAO.Factory 
attachmentDAOFactory,
                                  PostgresThreadDAO.Factory threadDAOFactory,
-                                 Set<DeletionCallback> deletionCallbackList) {
+                                 @Named(CONTENT_DELETION) EventBus 
contentDeletionEventBus) {
         this.messageDAOFactory = messageDAOFactory;
         this.mailboxMessageDAOFactory = mailboxMessageDAOFactory;
         this.blobStore = blobStore;
-        this.deletionCallbackList = deletionCallbackList;
         this.attachmentDAOFactory = attachmentDAOFactory;
         this.threadDAOFactory = threadDAOFactory;
+        this.contentDeletionEventBus = contentDeletionEventBus;
     }
 
     @Override
@@ -138,17 +139,32 @@ public class DeleteMessageListener implements 
EventListener.ReactiveGroupEventLi
         return Mono.just(messageId)
             .filterWhen(msgId -> isUnreferenced(msgId, 
postgresMailboxMessageDAO))
             .flatMap(msgId -> postgresMessageDAO.retrieveMessage(messageId)
-                .flatMap(executeDeletionCallbacks(mailboxId, owner))
+                .flatMap(messageRepresentation -> 
dispatchMessageContentDeletionEvent(mailboxId, owner, messageRepresentation))
                 .then(deleteBodyBlob(msgId, postgresMessageDAO))
                 .then(deleteAttachment(msgId, attachmentDAO))
                 .then(threadDAO.deleteSome(owner, msgId))
                 .then(postgresMessageDAO.deleteByMessageId(msgId)));
     }
 
-    private Function<MessageRepresentation, Mono<Void>> 
executeDeletionCallbacks(MailboxId mailboxId, Username owner) {
-        return messageRepresentation -> Flux.fromIterable(deletionCallbackList)
-            .concatMap(callback -> callback.forMessage(messageRepresentation, 
mailboxId, owner))
-            .then();
+    private Mono<Void> dispatchMessageContentDeletionEvent(MailboxId 
mailboxId, Username owner, MessageRepresentation message) {
+        return Mono.fromCallable(() -> 
IOUtils.toString(message.getHeaderContent().getInputStream(), 
StandardCharsets.UTF_8))
+            .subscribeOn(ReactorUtils.BLOCKING_CALL_WRAPPER)
+            .flatMap(headerContent -> 
Mono.from(contentDeletionEventBus.dispatch(messageContentDeletionEvent(mailboxId,
 owner, message, headerContent),
+                ImmutableSet.of())));
+    }
+
+    private MailboxEvents.MessageContentDeletionEvent 
messageContentDeletionEvent(MailboxId mailboxId, Username owner, 
MessageRepresentation message, String headerContent) {
+        return EventFactory.messageContentDeleted()
+            .randomEventId()
+            .user(owner)
+            .mailboxId(mailboxId)
+            .messageId(message.getMessageId())
+            .size(message.getSize())
+            .instant(message.getInternalDate().toInstant())
+            .hasAttachments(!message.getAttachments().isEmpty())
+            .bodyBlobId(message.getBodyBlobId().asString())
+            .headerContent(headerContent)
+            .build();
     }
 
     private Mono<Void> deleteBodyBlob(PostgresMessageId id, PostgresMessageDAO 
postgresMessageDAO) {
diff --git 
a/mailbox/postgres/src/main/java/org/apache/james/mailbox/postgres/PostgresMailboxSessionMapperFactory.java
 
b/mailbox/postgres/src/main/java/org/apache/james/mailbox/postgres/PostgresMailboxSessionMapperFactory.java
index 5685d64602..d4743b2f6a 100644
--- 
a/mailbox/postgres/src/main/java/org/apache/james/mailbox/postgres/PostgresMailboxSessionMapperFactory.java
+++ 
b/mailbox/postgres/src/main/java/org/apache/james/mailbox/postgres/PostgresMailboxSessionMapperFactory.java
@@ -27,6 +27,7 @@ import org.apache.james.backends.postgres.RowLevelSecurity;
 import org.apache.james.backends.postgres.utils.PostgresExecutor;
 import org.apache.james.blob.api.BlobId;
 import org.apache.james.blob.api.BlobStore;
+import org.apache.james.events.EventBus;
 import org.apache.james.mailbox.MailboxSession;
 import org.apache.james.mailbox.postgres.mail.PostgresAnnotationMapper;
 import org.apache.james.mailbox.postgres.mail.PostgresAttachmentMapper;
@@ -54,7 +55,7 @@ import org.apache.james.mailbox.store.mail.MessageIdMapper;
 import org.apache.james.mailbox.store.mail.MessageMapper;
 import org.apache.james.mailbox.store.user.SubscriptionMapper;
 
-import com.google.common.collect.ImmutableSet;
+import com.google.common.annotations.VisibleForTesting;
 
 public class PostgresMailboxSessionMapperFactory extends 
MailboxSessionMapperFactory implements AttachmentMapperFactory {
 
@@ -145,13 +146,14 @@ public class PostgresMailboxSessionMapperFactory extends 
MailboxSessionMapperFac
         return createAttachmentMapper(session);
     }
 
-    protected DeleteMessageListener deleteMessageListener() {
+    @VisibleForTesting
+    protected DeleteMessageListener deleteMessageListener(EventBus 
contentDeletionEventBus) {
         PostgresMessageDAO.Factory postgresMessageDAOFactory = new 
PostgresMessageDAO.Factory(blobIdFactory, executorFactory);
         PostgresMailboxMessageDAO.Factory postgresMailboxMessageDAOFactory = 
new PostgresMailboxMessageDAO.Factory(executorFactory);
         PostgresAttachmentDAO.Factory attachmentDAOFactory = new 
PostgresAttachmentDAO.Factory(executorFactory, blobIdFactory);
         PostgresThreadDAO.Factory threadDAOFactory = new 
PostgresThreadDAO.Factory(executorFactory);
 
         return new DeleteMessageListener(blobStore, 
postgresMailboxMessageDAOFactory, postgresMessageDAOFactory,
-            attachmentDAOFactory, threadDAOFactory, ImmutableSet.of());
+            attachmentDAOFactory, threadDAOFactory, contentDeletionEventBus);
     }
 }
diff --git 
a/mailbox/postgres/src/test/java/org/apache/james/mailbox/postgres/DeleteMessageListenerTest.java
 
b/mailbox/postgres/src/test/java/org/apache/james/mailbox/postgres/DeleteMessageListenerTest.java
index 453e088eff..8534477fb9 100644
--- 
a/mailbox/postgres/src/test/java/org/apache/james/mailbox/postgres/DeleteMessageListenerTest.java
+++ 
b/mailbox/postgres/src/test/java/org/apache/james/mailbox/postgres/DeleteMessageListenerTest.java
@@ -84,7 +84,7 @@ public class DeleteMessageListenerTest extends 
DeleteMessageListenerContract {
         QuotaComponents quotaComponents = 
QuotaComponents.disabled(sessionProvider, mapperFactory);
         MessageSearchIndex index = new SimpleMessageSearchIndex(mapperFactory, 
mapperFactory, new DefaultTextExtractor(), new 
UnsupportAttachmentContentLoader());
 
-        eventBus.register(mapperFactory.deleteMessageListener());
+        eventBus.register(mapperFactory.deleteMessageListener(eventBus));
 
         mailboxManager = new PostgresMailboxManager(mapperFactory, 
sessionProvider,
             messageParser, new PostgresMessageId.Factory(),
diff --git 
a/mailbox/postgres/src/test/java/org/apache/james/mailbox/postgres/DeleteMessageListenerWithRLSTest.java
 
b/mailbox/postgres/src/test/java/org/apache/james/mailbox/postgres/DeleteMessageListenerWithRLSTest.java
index b2f5f67b21..be1fd7b721 100644
--- 
a/mailbox/postgres/src/test/java/org/apache/james/mailbox/postgres/DeleteMessageListenerWithRLSTest.java
+++ 
b/mailbox/postgres/src/test/java/org/apache/james/mailbox/postgres/DeleteMessageListenerWithRLSTest.java
@@ -90,7 +90,7 @@ public class DeleteMessageListenerWithRLSTest extends 
DeleteMessageListenerContr
         QuotaComponents quotaComponents = 
QuotaComponents.disabled(sessionProvider, mapperFactory);
         MessageSearchIndex index = new SimpleMessageSearchIndex(mapperFactory, 
mapperFactory, new DefaultTextExtractor(), new 
UnsupportAttachmentContentLoader());
 
-        eventBus.register(mapperFactory.deleteMessageListener());
+        eventBus.register(mapperFactory.deleteMessageListener(eventBus));
 
         mailboxManager = new PostgresMailboxManager(mapperFactory, 
sessionProvider,
             messageParser, new PostgresMessageId.Factory(),
diff --git 
a/mailbox/postgres/src/test/java/org/apache/james/mailbox/postgres/PostgresMailboxManagerAttachmentTest.java
 
b/mailbox/postgres/src/test/java/org/apache/james/mailbox/postgres/PostgresMailboxManagerAttachmentTest.java
index e8beb011e3..a3dbc27696 100644
--- 
a/mailbox/postgres/src/test/java/org/apache/james/mailbox/postgres/PostgresMailboxManagerAttachmentTest.java
+++ 
b/mailbox/postgres/src/test/java/org/apache/james/mailbox/postgres/PostgresMailboxManagerAttachmentTest.java
@@ -70,8 +70,6 @@ import org.apache.james.utils.UpdatableTickingClock;
 import org.junit.jupiter.api.BeforeEach;
 import org.junit.jupiter.api.extension.RegisterExtension;
 
-import com.google.common.collect.ImmutableSet;
-
 public class PostgresMailboxManagerAttachmentTest extends 
AbstractMailboxManagerAttachmentTest {
 
     @RegisterExtension
@@ -110,7 +108,7 @@ public class PostgresMailboxManagerAttachmentTest extends 
AbstractMailboxManager
         PostgresThreadDAO.Factory threadDAOFactory = new 
PostgresThreadDAO.Factory(postgresExtension.getExecutorFactory());
 
         eventBus.register(new DeleteMessageListener(blobStore, 
postgresMailboxMessageDAOFactory, postgresMessageDAOFactory,
-            attachmentDAOFactory, threadDAOFactory, ImmutableSet.of()));
+            attachmentDAOFactory, threadDAOFactory, eventBus));
 
         mailboxManager = new PostgresMailboxManager(mapperFactory, 
sessionProvider,
             messageParser, new PostgresMessageId.Factory(),
diff --git 
a/mailbox/postgres/src/test/java/org/apache/james/mailbox/postgres/PostgresMailboxManagerProvider.java
 
b/mailbox/postgres/src/test/java/org/apache/james/mailbox/postgres/PostgresMailboxManagerProvider.java
index 3ffcf74a3e..3f466d365c 100644
--- 
a/mailbox/postgres/src/test/java/org/apache/james/mailbox/postgres/PostgresMailboxManagerProvider.java
+++ 
b/mailbox/postgres/src/test/java/org/apache/james/mailbox/postgres/PostgresMailboxManagerProvider.java
@@ -76,7 +76,7 @@ public class PostgresMailboxManagerProvider {
         QuotaComponents quotaComponents = 
QuotaComponents.disabled(sessionProvider, mapperFactory);
         MessageSearchIndex index = new SimpleMessageSearchIndex(mapperFactory, 
mapperFactory, new DefaultTextExtractor(), new 
UnsupportAttachmentContentLoader());
 
-        eventBus.register(mapperFactory.deleteMessageListener());
+        eventBus.register(mapperFactory.deleteMessageListener(eventBus));
 
         return new PostgresMailboxManager(mapperFactory, sessionProvider,
             messageParser, new PostgresMessageId.Factory(),
diff --git 
a/mailbox/postgres/src/test/java/org/apache/james/mailbox/postgres/PostgresTestSystemFixture.java
 
b/mailbox/postgres/src/test/java/org/apache/james/mailbox/postgres/PostgresTestSystemFixture.java
index b2f7569c0f..1f2b556813 100644
--- 
a/mailbox/postgres/src/test/java/org/apache/james/mailbox/postgres/PostgresTestSystemFixture.java
+++ 
b/mailbox/postgres/src/test/java/org/apache/james/mailbox/postgres/PostgresTestSystemFixture.java
@@ -91,7 +91,7 @@ public class PostgresTestSystemFixture {
             new UpdatableTickingClock(Instant.now()));
 
         eventBus.register(new MailboxAnnotationListener(mapperFactory, 
sessionProvider));
-        eventBus.register(mapperFactory.deleteMessageListener());
+        eventBus.register(mapperFactory.deleteMessageListener(eventBus));
 
         return postgresMailboxManager;
     }
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 2c19a0b7cb..19990c73ff 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
@@ -213,11 +213,6 @@ public class EventFactory {
         T hasAttachments(boolean hasAttachments);
     }
 
-    @FunctionalInterface
-    public interface RequireHeaderBlobId<T> {
-        T headerBlobId(String headerBlobId);
-    }
-
     @FunctionalInterface
     public interface RequireBodyBlobId<T> {
         T bodyBlobId(String bodyBlobId);
@@ -554,8 +549,9 @@ public class EventFactory {
         private final long size;
         private final Instant internalDate;
         private final boolean hasAttachments;
-        private final String headerBlobId;
         private final String bodyBlobId;
+        private Optional<String> headerBlobId;
+        private Optional<String> headerContent;
 
         MessageContentDeletionFinalStage(Event.EventId eventId,
                                          Username username,
@@ -564,7 +560,6 @@ public class EventFactory {
                                          long size,
                                          Instant internalDate,
                                          boolean hasAttachments,
-                                         String headerBlobId,
                                          String bodyBlobId) {
             this.eventId = eventId;
             this.username = username;
@@ -573,17 +568,29 @@ public class EventFactory {
             this.size = size;
             this.internalDate = internalDate;
             this.hasAttachments = hasAttachments;
-            this.headerBlobId = headerBlobId;
             this.bodyBlobId = bodyBlobId;
+            this.headerBlobId = Optional.empty();
+            this.headerContent = Optional.empty();
+        }
+
+        public MessageContentDeletionFinalStage headerBlobId(String 
headerBlobId) {
+            this.headerBlobId = Optional.ofNullable(headerBlobId);
+            return this;
+        }
+
+        public MessageContentDeletionFinalStage headerContent(String 
headerContent) {
+            this.headerContent = Optional.ofNullable(headerContent);
+            return this;
         }
 
         public MailboxEvents.MessageContentDeletionEvent build() {
+            Preconditions.checkNotNull(eventId);
             Preconditions.checkNotNull(username);
             Preconditions.checkNotNull(mailboxId);
             Preconditions.checkNotNull(messageId);
             Preconditions.checkNotNull(internalDate);
-            Preconditions.checkNotNull(headerBlobId);
             Preconditions.checkNotNull(bodyBlobId);
+            Preconditions.checkArgument(headerBlobId.isPresent() || 
headerContent.isPresent(), "Either headerBlobId or headerContent must be 
present");
 
             return new MailboxEvents.MessageContentDeletionEvent(
                 eventId,
@@ -594,6 +601,7 @@ public class EventFactory {
                 internalDate,
                 hasAttachments,
                 headerBlobId,
+                headerContent,
                 bodyBlobId);
         }
     }
@@ -684,9 +692,9 @@ public class EventFactory {
         return eventId -> user -> quotaRoot -> quotaCount -> quotaSize -> 
instant -> new QuotaUsageUpdatedFinalStage(eventId, user, quotaRoot, 
quotaCount, quotaSize, instant);
     }
 
-    public static 
RequireEventId<RequireUser<RequireMailboxId<RequireMessageId<RequireSize<RequireInstant<RequireHasAttachments<RequireHeaderBlobId<RequireBodyBlobId<MessageContentDeletionFinalStage>>>>>>>>>
 messageContentDeleted() {
-        return eventId -> user -> mailboxId -> messageId -> size -> instant -> 
hasAttachments -> headerBlobId -> bodyBlobId ->
-            new MessageContentDeletionFinalStage(eventId, user, mailboxId, 
messageId, size, instant, hasAttachments, headerBlobId, bodyBlobId);
+    public static 
RequireEventId<RequireUser<RequireMailboxId<RequireMessageId<RequireSize<RequireInstant<RequireHasAttachments<RequireBodyBlobId<MessageContentDeletionFinalStage>>>>>>>>
 messageContentDeleted() {
+        return eventId -> user -> mailboxId -> messageId -> size -> instant -> 
hasAttachments -> bodyBlobId ->
+            new MessageContentDeletionFinalStage(eventId, user, mailboxId, 
messageId, size, instant, hasAttachments, bodyBlobId);
     }
 
     public static RequireMailboxEvent<MailboxSubscribedFinalStage> 
mailboxSubscribed() {
diff --git 
a/server/apps/postgres-app/src/main/java/org/apache/james/PostgresJamesServerMain.java
 
b/server/apps/postgres-app/src/main/java/org/apache/james/PostgresJamesServerMain.java
index 0ebd94cca6..c8c0e8b041 100644
--- 
a/server/apps/postgres-app/src/main/java/org/apache/james/PostgresJamesServerMain.java
+++ 
b/server/apps/postgres-app/src/main/java/org/apache/james/PostgresJamesServerMain.java
@@ -55,6 +55,7 @@ import 
org.apache.james.modules.events.PostgresDeadLetterModule;
 import org.apache.james.modules.mailbox.DefaultEventModule;
 import org.apache.james.modules.mailbox.PostgresDeletedMessageVaultModule;
 import org.apache.james.modules.mailbox.PostgresMailboxModule;
+import 
org.apache.james.modules.mailbox.PostgresMemoryContentDeletionEventBusModule;
 import org.apache.james.modules.mailbox.RLSSupportPostgresMailboxModule;
 import org.apache.james.modules.mailbox.TikaMailboxModule;
 import org.apache.james.modules.plugins.QuotaMailingModule;
@@ -229,7 +230,8 @@ public class PostgresJamesServerMain implements 
JamesServerMain {
             case IN_MEMORY:
                 return List.of(
                     new DefaultEventModule(),
-                    new ActiveMQQueueModule());
+                    new ActiveMQQueueModule(),
+                    new PostgresMemoryContentDeletionEventBusModule());
             case RABBITMQ:
                 return List.of(
                     Modules.override(new DefaultEventModule()).with(new 
MailboxEventBusModule()),
diff --git 
a/server/container/guice/cassandra/src/main/java/org/apache/james/modules/data/CassandraJmapModule.java
 
b/server/container/guice/cassandra/src/main/java/org/apache/james/modules/data/CassandraJmapModule.java
index 4a53aa0b20..b710d14515 100644
--- 
a/server/container/guice/cassandra/src/main/java/org/apache/james/modules/data/CassandraJmapModule.java
+++ 
b/server/container/guice/cassandra/src/main/java/org/apache/james/modules/data/CassandraJmapModule.java
@@ -42,6 +42,7 @@ import 
org.apache.james.jmap.api.projections.DefaultEmailQueryViewManager;
 import org.apache.james.jmap.api.projections.EmailQueryView;
 import org.apache.james.jmap.api.projections.EmailQueryViewManager;
 import org.apache.james.jmap.api.projections.MessageFastViewProjection;
+import 
org.apache.james.jmap.api.projections.MessageFastViewProjectionDeletionListener;
 import 
org.apache.james.jmap.api.projections.MessageFastViewProjectionHealthCheck;
 import org.apache.james.jmap.api.pushsubscription.PushDeleteUserDataTaskStep;
 import org.apache.james.jmap.api.pushsubscription.PushSubscriptionRepository;
@@ -57,7 +58,6 @@ import 
org.apache.james.jmap.cassandra.projections.CassandraEmailQueryView;
 import 
org.apache.james.jmap.cassandra.projections.CassandraEmailQueryViewDataDefinition;
 import 
org.apache.james.jmap.cassandra.projections.CassandraMessageFastViewProjection;
 import 
org.apache.james.jmap.cassandra.projections.CassandraMessageFastViewProjectionDataDefinition;
-import 
org.apache.james.jmap.cassandra.projections.CassandraMessageFastViewProjectionDeletionListener;
 import 
org.apache.james.jmap.cassandra.pushsubscription.CassandraPushSubscriptionDataDefinition;
 import 
org.apache.james.jmap.cassandra.pushsubscription.CassandraPushSubscriptionRepository;
 import org.apache.james.jmap.cassandra.upload.CassandraUploadRepository;
@@ -121,7 +121,7 @@ public class CassandraJmapModule extends AbstractModule {
 
         Multibinder.newSetBinder(binder(), 
EventListener.ReactiveGroupEventListener.class, Names.named(CONTENT_DELETION))
             .addBinding()
-            .to(CassandraMessageFastViewProjectionDeletionListener.class);
+            .to(MessageFastViewProjectionDeletionListener.class);
 
         Multibinder.newSetBinder(binder(), UsernameChangeTaskStep.class)
             .addBinding()
diff --git 
a/server/container/guice/distributed/src/main/java/org/apache/james/modules/event/ContentDeletionEventBusModule.java
 
b/server/container/guice/distributed/src/main/java/org/apache/james/modules/event/ContentDeletionEventBusModule.java
index 72a4cc07ae..5e14f09063 100644
--- 
a/server/container/guice/distributed/src/main/java/org/apache/james/modules/event/ContentDeletionEventBusModule.java
+++ 
b/server/container/guice/distributed/src/main/java/org/apache/james/modules/event/ContentDeletionEventBusModule.java
@@ -31,13 +31,11 @@ import org.apache.james.backends.rabbitmq.ReceiverProvider;
 import org.apache.james.backends.rabbitmq.SimpleConnectionPool;
 import org.apache.james.core.healthcheck.HealthCheck;
 import org.apache.james.event.json.MailboxEventSerializer;
-import org.apache.james.events.Event;
 import org.apache.james.events.EventBus;
 import org.apache.james.events.EventBusId;
 import org.apache.james.events.EventBusReconnectionHandler;
 import org.apache.james.events.EventDeadLetters;
 import org.apache.james.events.EventListener;
-import org.apache.james.events.Group;
 import org.apache.james.events.GroupRegistrationHandler;
 import org.apache.james.events.KeyReconnectionHandler;
 import org.apache.james.events.RabbitEventBusConsumerHealthCheck;
@@ -50,7 +48,6 @@ import 
org.apache.james.mailbox.cassandra.DeleteMessageListener;
 import org.apache.james.metrics.api.MetricFactory;
 import org.apache.james.utils.InitializationOperation;
 import org.apache.james.utils.InitilizationOperationBuilder;
-import org.reactivestreams.Publisher;
 
 import com.google.common.collect.ImmutableSet;
 import com.google.inject.AbstractModule;
@@ -60,31 +57,9 @@ import com.google.inject.multibindings.Multibinder;
 import com.google.inject.multibindings.ProvidesIntoSet;
 import com.google.inject.name.Names;
 
-import reactor.core.publisher.Mono;
 import reactor.rabbitmq.Sender;
 
 public class ContentDeletionEventBusModule extends AbstractModule {
-    public static class NoopListener implements 
EventListener.ReactiveGroupEventListener {
-        public static class NoopListenerGroup extends Group {
-
-        }
-
-        @Override
-        public Group getDefaultGroup() {
-            return new NoopListenerGroup();
-        }
-
-        @Override
-        public Publisher<Void> reactiveEvent(Event event) {
-            return Mono.empty();
-        }
-
-        @Override
-        public boolean isHandling(Event event) {
-            return false;
-        }
-    }
-
     public static final String CONTENT_DELETION = "contentDeletion";
 
     @Override
@@ -102,10 +77,6 @@ public class ContentDeletionEventBusModule extends 
AbstractModule {
             .init(() -> {
                 instance.start();
                 contentDeletionListeners.forEach(instance::register);
-
-                // workaround for Postgres app to make the content deletion 
queue created and pass tests
-                // TODO remove after refactoring JAMES-4154 for Postgres app
-                instance.register(new NoopListener());
             });
     }
 
diff --git 
a/server/container/guice/distributed/src/main/java/org/apache/james/modules/mailbox/DistributedDeletedMessageVaultModule.java
 
b/server/container/guice/distributed/src/main/java/org/apache/james/modules/mailbox/DistributedDeletedMessageVaultModule.java
index 319a69fd69..e39b8fa0fa 100644
--- 
a/server/container/guice/distributed/src/main/java/org/apache/james/modules/mailbox/DistributedDeletedMessageVaultModule.java
+++ 
b/server/container/guice/distributed/src/main/java/org/apache/james/modules/mailbox/DistributedDeletedMessageVaultModule.java
@@ -24,6 +24,7 @@ import org.apache.james.events.EventListener;
 import org.apache.james.mailbox.cassandra.DeleteMessageListener;
 import org.apache.james.modules.vault.DeletedMessageVaultModule;
 import org.apache.james.vault.DeletedMessageVault;
+import org.apache.james.vault.DeletedMessageVaultDeletionListener;
 import org.apache.james.vault.blob.BlobStoreDeletedMessageVault;
 import org.apache.james.vault.blob.BucketNameGenerator;
 import 
org.apache.james.vault.dto.DeletedMessageWithStorageInformationConverter;
diff --git 
a/server/container/guice/mailbox-postgres/src/main/java/org/apache/james/modules/mailbox/PostgresDeletedMessageVaultModule.java
 
b/server/container/guice/mailbox-postgres/src/main/java/org/apache/james/modules/mailbox/PostgresDeletedMessageVaultModule.java
index a5fd44f7e6..cd39b3463e 100644
--- 
a/server/container/guice/mailbox-postgres/src/main/java/org/apache/james/modules/mailbox/PostgresDeletedMessageVaultModule.java
+++ 
b/server/container/guice/mailbox-postgres/src/main/java/org/apache/james/modules/mailbox/PostgresDeletedMessageVaultModule.java
@@ -19,17 +19,20 @@
 
 package org.apache.james.modules.mailbox;
 
+import static 
org.apache.james.mailbox.postgres.DeleteMessageListener.CONTENT_DELETION;
+
 import org.apache.james.backends.postgres.PostgresDataDefinition;
-import org.apache.james.mailbox.postgres.DeleteMessageListener;
+import org.apache.james.events.EventListener;
 import org.apache.james.modules.vault.DeletedMessageVaultModule;
+import org.apache.james.vault.DeletedMessageVaultDeletionListener;
 import org.apache.james.vault.metadata.DeletedMessageMetadataVault;
 import 
org.apache.james.vault.metadata.PostgresDeletedMessageMetadataDataDefinition;
 import org.apache.james.vault.metadata.PostgresDeletedMessageMetadataVault;
-import 
org.apache.james.vault.metadata.PostgresDeletedMessageVaultDeletionCallback;
 
 import com.google.inject.AbstractModule;
 import com.google.inject.Scopes;
 import com.google.inject.multibindings.Multibinder;
+import com.google.inject.name.Names;
 
 public class PostgresDeletedMessageVaultModule extends AbstractModule {
     @Override
@@ -43,8 +46,8 @@ public class PostgresDeletedMessageVaultModule extends 
AbstractModule {
         bind(DeletedMessageMetadataVault.class)
             .to(PostgresDeletedMessageMetadataVault.class);
 
-        Multibinder.newSetBinder(binder(), 
DeleteMessageListener.DeletionCallback.class)
+        Multibinder.newSetBinder(binder(), 
EventListener.ReactiveGroupEventListener.class, Names.named(CONTENT_DELETION))
             .addBinding()
-            .to(PostgresDeletedMessageVaultDeletionCallback.class);
+            .to(DeletedMessageVaultDeletionListener.class);
     }
 }
diff --git 
a/server/container/guice/mailbox-postgres/src/main/java/org/apache/james/modules/mailbox/PostgresMailboxModule.java
 
b/server/container/guice/mailbox-postgres/src/main/java/org/apache/james/modules/mailbox/PostgresMailboxModule.java
index 50f6f96525..e7e9d35226 100644
--- 
a/server/container/guice/mailbox-postgres/src/main/java/org/apache/james/modules/mailbox/PostgresMailboxModule.java
+++ 
b/server/container/guice/mailbox-postgres/src/main/java/org/apache/james/modules/mailbox/PostgresMailboxModule.java
@@ -168,7 +168,6 @@ public class PostgresMailboxModule extends AbstractModule {
 
         Multibinder.newSetBinder(binder(), 
EventListener.ReactiveGroupEventListener.class)
             .addBinding().to(DeleteMessageListener.class);
-        Multibinder.newSetBinder(binder(), 
DeleteMessageListener.DeletionCallback.class);
 
         
bind(MailboxManager.class).annotatedWith(Names.named(MAILBOXMANAGER_NAME)).to(MailboxManager.class);
         
bind(MailboxManagerConfiguration.class).toInstance(MailboxManagerConfiguration.DEFAULT);
diff --git 
a/server/container/guice/mailbox-postgres/src/main/java/org/apache/james/modules/mailbox/PostgresDeletedMessageVaultModule.java
 
b/server/container/guice/mailbox-postgres/src/main/java/org/apache/james/modules/mailbox/PostgresMemoryContentDeletionEventBusModule.java
similarity index 50%
copy from 
server/container/guice/mailbox-postgres/src/main/java/org/apache/james/modules/mailbox/PostgresDeletedMessageVaultModule.java
copy to 
server/container/guice/mailbox-postgres/src/main/java/org/apache/james/modules/mailbox/PostgresMemoryContentDeletionEventBusModule.java
index a5fd44f7e6..19316aa1dc 100644
--- 
a/server/container/guice/mailbox-postgres/src/main/java/org/apache/james/modules/mailbox/PostgresDeletedMessageVaultModule.java
+++ 
b/server/container/guice/mailbox-postgres/src/main/java/org/apache/james/modules/mailbox/PostgresMemoryContentDeletionEventBusModule.java
@@ -19,32 +19,39 @@
 
 package org.apache.james.modules.mailbox;
 
-import org.apache.james.backends.postgres.PostgresDataDefinition;
-import org.apache.james.mailbox.postgres.DeleteMessageListener;
-import org.apache.james.modules.vault.DeletedMessageVaultModule;
-import org.apache.james.vault.metadata.DeletedMessageMetadataVault;
-import 
org.apache.james.vault.metadata.PostgresDeletedMessageMetadataDataDefinition;
-import org.apache.james.vault.metadata.PostgresDeletedMessageMetadataVault;
-import 
org.apache.james.vault.metadata.PostgresDeletedMessageVaultDeletionCallback;
+import static 
org.apache.james.mailbox.postgres.DeleteMessageListener.CONTENT_DELETION;
+
+import java.util.Set;
+
+import jakarta.inject.Named;
+
+import org.apache.james.events.EventBus;
+import org.apache.james.events.EventListener;
+import org.apache.james.lifecycle.api.Startable;
+import org.apache.james.utils.InitializationOperation;
+import org.apache.james.utils.InitilizationOperationBuilder;
 
 import com.google.inject.AbstractModule;
-import com.google.inject.Scopes;
 import com.google.inject.multibindings.Multibinder;
+import com.google.inject.multibindings.ProvidesIntoSet;
+import com.google.inject.name.Names;
 
-public class PostgresDeletedMessageVaultModule extends AbstractModule {
-    @Override
-    protected void configure() {
-        install(new DeletedMessageVaultModule());
+public class PostgresMemoryContentDeletionEventBusModule extends 
AbstractModule {
+    public static class ContentDeletionListenersLoader implements Startable {
 
-        Multibinder<PostgresDataDefinition> postgresDataDefinitions = 
Multibinder.newSetBinder(binder(), PostgresDataDefinition.class);
-        
postgresDataDefinitions.addBinding().toInstance(PostgresDeletedMessageMetadataDataDefinition.MODULE);
+    }
 
-        bind(PostgresDeletedMessageMetadataVault.class).in(Scopes.SINGLETON);
-        bind(DeletedMessageMetadataVault.class)
-            .to(PostgresDeletedMessageMetadataVault.class);
+    @Override
+    protected void configure() {
+        
bind(EventBus.class).annotatedWith(Names.named(CONTENT_DELETION)).to(EventBus.class);
+        Multibinder.newSetBinder(binder(), 
EventListener.ReactiveGroupEventListener.class, Names.named(CONTENT_DELETION));
+    }
 
-        Multibinder.newSetBinder(binder(), 
DeleteMessageListener.DeletionCallback.class)
-            .addBinding()
-            .to(PostgresDeletedMessageVaultDeletionCallback.class);
+    @ProvidesIntoSet
+    public InitializationOperation registerListener(@Named(CONTENT_DELETION) 
EventBus contentDeletionEventBus,
+                                                    @Named(CONTENT_DELETION) 
Set<EventListener.ReactiveGroupEventListener> contentDeletionListeners) {
+        return InitilizationOperationBuilder
+            .forClass(ContentDeletionListenersLoader.class)
+            .init(() -> 
contentDeletionListeners.forEach(contentDeletionEventBus::register));
     }
 }
diff --git 
a/server/container/guice/postgres-common/src/main/java/org/apache/james/modules/data/PostgresDataJmapModule.java
 
b/server/container/guice/postgres-common/src/main/java/org/apache/james/modules/data/PostgresDataJmapModule.java
index 19ecf9a84e..ca9883e9ca 100644
--- 
a/server/container/guice/postgres-common/src/main/java/org/apache/james/modules/data/PostgresDataJmapModule.java
+++ 
b/server/container/guice/postgres-common/src/main/java/org/apache/james/modules/data/PostgresDataJmapModule.java
@@ -19,7 +19,10 @@
 
 package org.apache.james.modules.data;
 
+import static 
org.apache.james.mailbox.postgres.DeleteMessageListener.CONTENT_DELETION;
+
 import org.apache.james.core.healthcheck.HealthCheck;
+import org.apache.james.events.EventListener;
 import org.apache.james.jmap.api.filtering.FilteringManagement;
 import org.apache.james.jmap.api.filtering.FiltersDeleteUserDataTaskStep;
 import 
org.apache.james.jmap.api.filtering.impl.EventSourcingFilteringManagement;
@@ -29,6 +32,7 @@ import 
org.apache.james.jmap.api.identity.IdentityUserDeletionTaskStep;
 import org.apache.james.jmap.api.projections.EmailQueryView;
 import org.apache.james.jmap.api.projections.EmailQueryViewManager;
 import org.apache.james.jmap.api.projections.MessageFastViewProjection;
+import 
org.apache.james.jmap.api.projections.MessageFastViewProjectionDeletionListener;
 import 
org.apache.james.jmap.api.projections.MessageFastViewProjectionHealthCheck;
 import org.apache.james.jmap.api.pushsubscription.PushDeleteUserDataTaskStep;
 import org.apache.james.jmap.api.upload.UploadRepository;
@@ -37,9 +41,7 @@ import 
org.apache.james.jmap.postgres.identity.PostgresCustomIdentityDAO;
 import org.apache.james.jmap.postgres.projections.PostgresEmailQueryView;
 import 
org.apache.james.jmap.postgres.projections.PostgresEmailQueryViewManager;
 import 
org.apache.james.jmap.postgres.projections.PostgresMessageFastViewProjection;
-import 
org.apache.james.jmap.postgres.projections.PostgresMessageFastViewProjectionDeletionCallback;
 import org.apache.james.jmap.postgres.upload.PostgresUploadRepository;
-import org.apache.james.mailbox.postgres.DeleteMessageListener;
 import org.apache.james.mailbox.store.extractor.DefaultTextExtractor;
 import org.apache.james.user.api.DeleteUserDataTaskStep;
 import org.apache.james.user.api.UsernameChangeTaskStep;
@@ -47,6 +49,7 @@ import org.apache.james.user.api.UsernameChangeTaskStep;
 import com.google.inject.AbstractModule;
 import com.google.inject.Scopes;
 import com.google.inject.multibindings.Multibinder;
+import com.google.inject.name.Names;
 
 public class PostgresDataJmapModule extends AbstractModule {
 
@@ -67,9 +70,9 @@ public class PostgresDataJmapModule extends AbstractModule {
         bind(PostgresMessageFastViewProjection.class).in(Scopes.SINGLETON);
         
bind(MessageFastViewProjection.class).to(PostgresMessageFastViewProjection.class);
 
-        Multibinder.newSetBinder(binder(), 
DeleteMessageListener.DeletionCallback.class)
+        Multibinder.newSetBinder(binder(), 
EventListener.ReactiveGroupEventListener.class, Names.named(CONTENT_DELETION))
             .addBinding()
-            .to(PostgresMessageFastViewProjectionDeletionCallback.class);
+            .to(MessageFastViewProjectionDeletionListener.class);
 
         bind(PostgresEmailQueryView.class).in(Scopes.SINGLETON);
         bind(EmailQueryView.class).to(PostgresEmailQueryView.class);
diff --git 
a/server/data/data-jmap-postgres/src/main/java/org/apache/james/jmap/postgres/projections/PostgresMessageFastViewProjectionDeletionCallback.java
 
b/server/data/data-jmap-postgres/src/main/java/org/apache/james/jmap/postgres/projections/PostgresMessageFastViewProjectionDeletionCallback.java
deleted file mode 100644
index 3cbacec71a..0000000000
--- 
a/server/data/data-jmap-postgres/src/main/java/org/apache/james/jmap/postgres/projections/PostgresMessageFastViewProjectionDeletionCallback.java
+++ /dev/null
@@ -1,44 +0,0 @@
-/****************************************************************
- * Licensed to the Apache Software Foundation (ASF) under one   *
- * or more contributor license agreements.  See the NOTICE file *
- * distributed with this work for additional information        *
- * regarding copyright ownership.  The ASF licenses this file   *
- * to you under the Apache License, Version 2.0 (the            *
- * "License"); you may not use this file except in compliance   *
- * with the License.  You may obtain a copy of the License at   *
- *                                                              *
- *   http://www.apache.org/licenses/LICENSE-2.0                 *
- *                                                              *
- * Unless required by applicable law or agreed to in writing,   *
- * software distributed under the License is distributed on an  *
- * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY       *
- * KIND, either express or implied.  See the License for the    *
- * specific language governing permissions and limitations      *
- * under the License.                                           *
- ****************************************************************/
-
-package org.apache.james.jmap.postgres.projections;
-
-import jakarta.inject.Inject;
-
-import org.apache.james.core.Username;
-import org.apache.james.jmap.api.projections.MessageFastViewProjection;
-import org.apache.james.mailbox.model.MailboxId;
-import org.apache.james.mailbox.postgres.DeleteMessageListener;
-import org.apache.james.mailbox.postgres.mail.MessageRepresentation;
-
-import reactor.core.publisher.Mono;
-
-public class PostgresMessageFastViewProjectionDeletionCallback implements 
DeleteMessageListener.DeletionCallback {
-    private final MessageFastViewProjection messageFastViewProjection;
-
-    @Inject
-    public 
PostgresMessageFastViewProjectionDeletionCallback(MessageFastViewProjection 
messageFastViewProjection) {
-        this.messageFastViewProjection = messageFastViewProjection;
-    }
-
-    @Override
-    public Mono<Void> forMessage(MessageRepresentation messageRepresentation, 
MailboxId mailboxId, Username owner) {
-        return 
Mono.from(messageFastViewProjection.delete(messageRepresentation.getMessageId()));
-    }
-}
diff --git 
a/server/data/data-jmap-cassandra/src/main/java/org/apache/james/jmap/cassandra/projections/CassandraMessageFastViewProjectionDeletionListener.java
 
b/server/data/data-jmap/src/main/java/org/apache/james/jmap/api/projections/MessageFastViewProjectionDeletionListener.java
similarity index 79%
rename from 
server/data/data-jmap-cassandra/src/main/java/org/apache/james/jmap/cassandra/projections/CassandraMessageFastViewProjectionDeletionListener.java
rename to 
server/data/data-jmap/src/main/java/org/apache/james/jmap/api/projections/MessageFastViewProjectionDeletionListener.java
index ec5fd46e3c..3ffc9973f2 100644
--- 
a/server/data/data-jmap-cassandra/src/main/java/org/apache/james/jmap/cassandra/projections/CassandraMessageFastViewProjectionDeletionListener.java
+++ 
b/server/data/data-jmap/src/main/java/org/apache/james/jmap/api/projections/MessageFastViewProjectionDeletionListener.java
@@ -17,30 +17,29 @@
  * under the License.                                           *
  ****************************************************************/
 
-package org.apache.james.jmap.cassandra.projections;
+package org.apache.james.jmap.api.projections;
 
 import jakarta.inject.Inject;
 
 import org.apache.james.events.Event;
 import org.apache.james.events.EventListener;
 import org.apache.james.events.Group;
-import org.apache.james.jmap.api.projections.MessageFastViewProjection;
 import org.apache.james.mailbox.events.MailboxEvents;
 import org.reactivestreams.Publisher;
 
 import reactor.core.publisher.Mono;
 
-public class CassandraMessageFastViewProjectionDeletionListener implements 
EventListener.ReactiveGroupEventListener {
-    public static class 
CassandraMessageFastViewProjectionDeletionListenerGroup extends Group {
+public class MessageFastViewProjectionDeletionListener implements 
EventListener.ReactiveGroupEventListener {
+    public static class MessageFastViewProjectionDeletionListenerGroup extends 
Group {
 
     }
 
-    private static final Group GROUP = new 
CassandraMessageFastViewProjectionDeletionListenerGroup();
+    private static final Group GROUP = new 
MessageFastViewProjectionDeletionListenerGroup();
 
     private final MessageFastViewProjection messageFastViewProjection;
 
     @Inject
-    public 
CassandraMessageFastViewProjectionDeletionListener(MessageFastViewProjection 
messageFastViewProjection) {
+    public MessageFastViewProjectionDeletionListener(MessageFastViewProjection 
messageFastViewProjection) {
         this.messageFastViewProjection = messageFastViewProjection;
     }
 
diff --git 
a/server/protocols/webadmin-integration-test/postgres-webadmin-integration-test/pom.xml
 
b/server/protocols/webadmin-integration-test/postgres-webadmin-integration-test/pom.xml
index aa8a06b6b3..7adc5557bb 100644
--- 
a/server/protocols/webadmin-integration-test/postgres-webadmin-integration-test/pom.xml
+++ 
b/server/protocols/webadmin-integration-test/postgres-webadmin-integration-test/pom.xml
@@ -51,6 +51,12 @@
             <type>test-jar</type>
             <scope>test</scope>
         </dependency>
+        <dependency>
+            <groupId>${james.groupId}</groupId>
+            <artifactId>apache-james-backends-rabbitmq</artifactId>
+            <type>test-jar</type>
+            <scope>test</scope>
+        </dependency>
         <dependency>
             <groupId>${james.groupId}</groupId>
             <artifactId>apache-james-mailbox-opensearch</artifactId>
diff --git 
a/server/protocols/webadmin-integration-test/postgres-webadmin-integration-test/src/test/java/org/apache/james/webadmin/integration/vault/PostgresDeletedMessageVaultIntegrationTest.java
 
b/server/protocols/webadmin-integration-test/postgres-webadmin-integration-test/src/test/java/org/apache/james/webadmin/integration/vault/PostgresDeletedMessageVaultIntegrationTest.java
index e7bcb0daaa..4ea638622b 100644
--- 
a/server/protocols/webadmin-integration-test/postgres-webadmin-integration-test/src/test/java/org/apache/james/webadmin/integration/vault/PostgresDeletedMessageVaultIntegrationTest.java
+++ 
b/server/protocols/webadmin-integration-test/postgres-webadmin-integration-test/src/test/java/org/apache/james/webadmin/integration/vault/PostgresDeletedMessageVaultIntegrationTest.java
@@ -20,35 +20,19 @@
 package org.apache.james.webadmin.integration.vault;
 
 import static 
org.apache.james.data.UsersRepositoryModuleChooser.Implementation.DEFAULT;
-import static org.awaitility.Durations.FIVE_HUNDRED_MILLISECONDS;
-import static org.awaitility.Durations.ONE_MINUTE;
 
-import org.apache.james.GuiceJamesServer;
 import org.apache.james.JamesServerBuilder;
 import org.apache.james.JamesServerExtension;
 import org.apache.james.PostgresJamesConfiguration;
 import org.apache.james.PostgresJamesServerMain;
 import org.apache.james.SearchConfiguration;
 import org.apache.james.backends.postgres.PostgresExtension;
-import org.apache.james.mailbox.DefaultMailboxes;
-import org.apache.james.modules.protocols.ImapGuiceProbe;
-import org.apache.james.modules.protocols.SmtpGuiceProbe;
-import org.apache.james.utils.DataProbeImpl;
-import org.apache.james.utils.SMTPMessageSender;
-import org.apache.james.utils.TestIMAPClient;
-import org.apache.james.utils.WebAdminGuiceProbe;
+import org.apache.james.modules.TestJMAPServerModule;
+import org.apache.james.modules.blobstore.BlobStoreConfiguration;
 import org.apache.james.vault.VaultConfiguration;
-import org.apache.james.webadmin.WebAdminUtils;
-import org.awaitility.Awaitility;
-import org.awaitility.core.ConditionFactory;
-import org.junit.jupiter.api.BeforeEach;
-import org.junit.jupiter.api.Test;
 import org.junit.jupiter.api.extension.RegisterExtension;
 
-import io.restassured.config.ParamConfig;
-import io.restassured.specification.RequestSpecification;
-
-class PostgresDeletedMessageVaultIntegrationTest {
+class PostgresDeletedMessageVaultIntegrationTest extends 
DeletedMessageVaultIntegrationTest {
     @RegisterExtension
     static JamesServerExtension jamesServerExtension = new 
JamesServerBuilder<PostgresJamesConfiguration>(tmpDir ->
         PostgresJamesConfiguration.builder()
@@ -58,73 +42,20 @@ class PostgresDeletedMessageVaultIntegrationTest {
             .usersRepository(DEFAULT)
             .eventBusImpl(PostgresJamesConfiguration.EventBusImpl.IN_MEMORY)
             
.deletedMessageVaultConfiguration(VaultConfiguration.ENABLED_DEFAULT)
+            .blobStore(BlobStoreConfiguration.builder()
+                .postgres()
+                .disableCache()
+                .deduplication()
+                .noCryptoConfig())
             .build())
-        .server(PostgresJamesServerMain::createServer)
+        .server(configuration -> 
PostgresJamesServerMain.createServer(configuration)
+            .overrideWith(new TestJMAPServerModule()))
         .extension(PostgresExtension.empty())
-        .lifeCycle(JamesServerExtension.Lifecycle.PER_CLASS)
+        .extension(new ClockExtension())
         .build();
 
-    private static final ConditionFactory AWAIT = Awaitility.await()
-        .atMost(ONE_MINUTE)
-        .with()
-        .pollInterval(FIVE_HUNDRED_MILLISECONDS);
-    private static final String DOMAIN = "james.local";
-    private static final String USER = "toto@" + DOMAIN;
-    private static final String PASSWORD = "123456";
-    private static final String JAMES_SERVER_HOST = "127.0.0.1";
-
-    private TestIMAPClient testIMAPClient;
-    private SMTPMessageSender smtpMessageSender;
-    private RequestSpecification webAdminApi;
-
-    @BeforeEach
-    void setUp(GuiceJamesServer jamesServer) throws Exception {
-        this.testIMAPClient = new TestIMAPClient();
-        this.smtpMessageSender = new SMTPMessageSender(DOMAIN);
-        this.webAdminApi = 
WebAdminUtils.spec(jamesServer.getProbe(WebAdminGuiceProbe.class).getWebAdminPort())
-            .config(WebAdminUtils.defaultConfig()
-                .paramConfig(new ParamConfig().replaceAllParameters()));
+    @Override
+    protected void awaitSearchUpToDate() {
 
-        jamesServer.getProbe(DataProbeImpl.class)
-            .fluent()
-            .addDomain(DOMAIN)
-            .addUser(USER, PASSWORD);
     }
-
-    @Test
-    void restoreDeletedMessageShouldSucceed(GuiceJamesServer jamesServer) 
throws Exception {
-        // Create a message
-        int imapPort = 
jamesServer.getProbe(ImapGuiceProbe.class).getImapPort();
-        smtpMessageSender.connect(JAMES_SERVER_HOST, 
jamesServer.getProbe(SmtpGuiceProbe.class).getSmtpPort())
-            .authenticate(USER, PASSWORD)
-            .sendMessageWithHeaders(USER, USER, "Subject: 
thisIsASubject\r\n\r\nBody");
-        testIMAPClient.connect(JAMES_SERVER_HOST, imapPort)
-            .login(USER, PASSWORD)
-            .select(TestIMAPClient.INBOX)
-            .awaitMessageCount(AWAIT, 1);
-
-        // Delete the message
-        testIMAPClient.setFlagsForAllMessagesInMailbox("\\Deleted");
-        testIMAPClient.expunge();
-        testIMAPClient.awaitNoMessage(AWAIT);
-
-        // Restore the message using the Deleted message vault webadmin 
endpoint
-        String restoreBySubjectQuery = "{" +
-            "  \"combinator\": \"and\"," +
-            "  \"limit\": 1," +
-            "  \"criteria\": [" +
-            "    {" +
-            "      \"fieldName\": \"subject\"," +
-            "      \"operator\": \"equals\"," +
-            "      \"value\": \"thisIsASubject\"" +
-            "    }" +
-            "  ]" +
-            "}";
-        
DeletedMessagesVaultRequests.restoreMessagesForUserWithQuery(webAdminApi, USER, 
restoreBySubjectQuery);
-
-        // await the message to be restored
-        testIMAPClient.select(DefaultMailboxes.RESTORED_MESSAGES)
-            .awaitMessageCount(AWAIT, 1);
-    }
-
 }
diff --git 
a/server/protocols/webadmin-integration-test/postgres-webadmin-integration-test/src/test/java/org/apache/james/webadmin/integration/vault/RabbitMQPostgresDeletedMessageVaultIntegrationTest.java
 
b/server/protocols/webadmin-integration-test/postgres-webadmin-integration-test/src/test/java/org/apache/james/webadmin/integration/vault/RabbitMQPostgresDeletedMessageVaultIntegrationTest.java
new file mode 100644
index 0000000000..7bbe7dfebb
--- /dev/null
+++ 
b/server/protocols/webadmin-integration-test/postgres-webadmin-integration-test/src/test/java/org/apache/james/webadmin/integration/vault/RabbitMQPostgresDeletedMessageVaultIntegrationTest.java
@@ -0,0 +1,66 @@
+/****************************************************************
+ * 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.webadmin.integration.vault;
+
+import static 
org.apache.james.data.UsersRepositoryModuleChooser.Implementation.DEFAULT;
+
+import org.apache.james.JamesServerBuilder;
+import org.apache.james.JamesServerExtension;
+import org.apache.james.PostgresJamesConfiguration;
+import org.apache.james.PostgresJamesServerMain;
+import org.apache.james.SearchConfiguration;
+import org.apache.james.backends.postgres.PostgresExtension;
+import org.apache.james.modules.RabbitMQExtension;
+import org.apache.james.modules.TestJMAPServerModule;
+import org.apache.james.modules.blobstore.BlobStoreConfiguration;
+import org.apache.james.vault.VaultConfiguration;
+import org.junit.jupiter.api.extension.RegisterExtension;
+
+class RabbitMQPostgresDeletedMessageVaultIntegrationTest extends 
DeletedMessageVaultIntegrationTest {
+    @RegisterExtension
+    static RabbitMQExtension rabbitMQExtension = new RabbitMQExtension();
+
+    @RegisterExtension
+    static JamesServerExtension jamesServerExtension = new 
JamesServerBuilder<PostgresJamesConfiguration>(tmpDir ->
+        PostgresJamesConfiguration.builder()
+            .workingDirectory(tmpDir)
+            .configurationFromClasspath()
+            .searchConfiguration(SearchConfiguration.scanning())
+            .usersRepository(DEFAULT)
+            .eventBusImpl(PostgresJamesConfiguration.EventBusImpl.RABBITMQ)
+            
.deletedMessageVaultConfiguration(VaultConfiguration.ENABLED_DEFAULT)
+            .blobStore(BlobStoreConfiguration.builder()
+                .postgres()
+                .disableCache()
+                .deduplication()
+                .noCryptoConfig())
+            .build())
+        .server(configuration -> 
PostgresJamesServerMain.createServer(configuration)
+            .overrideWith(new TestJMAPServerModule()))
+        .extension(PostgresExtension.empty())
+        .extension(new ClockExtension())
+        .extension(rabbitMQExtension)
+        .build();
+
+    @Override
+    protected void awaitSearchUpToDate() {
+
+    }
+}
diff --git 
a/server/protocols/webadmin-integration-test/postgres-webadmin-integration-test/src/test/resources/listeners.xml
 
b/server/protocols/webadmin-integration-test/postgres-webadmin-integration-test/src/test/resources/listeners.xml
index ff2e517232..828ef9009b 100644
--- 
a/server/protocols/webadmin-integration-test/postgres-webadmin-integration-test/src/test/resources/listeners.xml
+++ 
b/server/protocols/webadmin-integration-test/postgres-webadmin-integration-test/src/test/resources/listeners.xml
@@ -46,4 +46,8 @@
       <name>second</name>
     </configuration>
   </listener>
+  <listener>
+      <class>org.apache.james.jmap.event.PopulateEmailQueryViewListener</class>
+      <async>true</async>
+  </listener>
 </listeners>
\ No newline at end of file


---------------------------------------------------------------------
To unsubscribe, e-mail: [email protected]
For additional commands, e-mail: [email protected]

Reply via email to