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 7abe77b1c81f76ff0efa5c7277bb8340b96ff8a7
Author: Rene Cordier <[email protected]>
AuthorDate: Fri Aug 29 09:42:38 2025 +0700

    JAMES-3340 Add threadId column in EmailQueryView and populate it via the 
listener
---
 .../projections/CassandraEmailQueryView.java       |  12 ++-
 .../CassandraEmailQueryViewDataDefinition.java     |   7 +-
 .../table/CassandraEmailQueryViewTable.java        |   1 +
 .../projections/CassandraEmailQueryViewTest.java   |   7 ++
 .../projections/PostgresEmailQueryView.java        |   5 +-
 .../projections/PostgresEmailQueryViewDAO.java     |   5 +-
 .../PostgresEmailQueryViewDataDefinition.java      |   2 +
 .../PostgresEmailQueryViewManagerRLSTest.java      |   6 +-
 .../projections/PostgresEmailQueryViewTest.java    |   7 ++
 .../james/jmap/api/projections/EmailQueryView.java |  16 ++-
 .../memory/projections/MemoryEmailQueryView.java   |   5 +-
 .../api/projections/EmailQueryViewContract.java    | 113 +++++++++++----------
 .../projections/MemoryEmailQueryViewTest.java      |   8 ++
 .../jmap/event/PopulateEmailQueryViewListener.java |   2 +-
 .../data/jmap/EmailQueryViewPopulator.java         |   6 +-
 15 files changed, 128 insertions(+), 74 deletions(-)

diff --git 
a/server/data/data-jmap-cassandra/src/main/java/org/apache/james/jmap/cassandra/projections/CassandraEmailQueryView.java
 
b/server/data/data-jmap-cassandra/src/main/java/org/apache/james/jmap/cassandra/projections/CassandraEmailQueryView.java
index a73ed7ffb9..2f674d5a10 100644
--- 
a/server/data/data-jmap-cassandra/src/main/java/org/apache/james/jmap/cassandra/projections/CassandraEmailQueryView.java
+++ 
b/server/data/data-jmap-cassandra/src/main/java/org/apache/james/jmap/cassandra/projections/CassandraEmailQueryView.java
@@ -31,6 +31,7 @@ import static 
org.apache.james.jmap.cassandra.projections.table.CassandraEmailQu
 import static 
org.apache.james.jmap.cassandra.projections.table.CassandraEmailQueryViewTable.SENT_AT;
 import static 
org.apache.james.jmap.cassandra.projections.table.CassandraEmailQueryViewTable.TABLE_NAME_RECEIVED_AT;
 import static 
org.apache.james.jmap.cassandra.projections.table.CassandraEmailQueryViewTable.TABLE_NAME_SENT_AT;
+import static 
org.apache.james.jmap.cassandra.projections.table.CassandraEmailQueryViewTable.THREAD_ID;
 
 import java.time.Instant;
 import java.time.ZonedDateTime;
@@ -45,6 +46,7 @@ import org.apache.james.mailbox.cassandra.ids.CassandraId;
 import org.apache.james.mailbox.cassandra.ids.CassandraMessageId;
 import org.apache.james.mailbox.model.MailboxId;
 import org.apache.james.mailbox.model.MessageId;
+import org.apache.james.mailbox.model.ThreadId;
 import org.apache.james.util.streams.Limit;
 
 import com.datastax.oss.driver.api.core.CqlSession;
@@ -128,6 +130,7 @@ public class CassandraEmailQueryView implements 
EmailQueryView {
             .value(MAILBOX_ID, bindMarker(MAILBOX_ID))
             .value(MESSAGE_ID, bindMarker(MESSAGE_ID))
             .value(SENT_AT, bindMarker(SENT_AT))
+            .value(THREAD_ID, bindMarker(THREAD_ID))
             .build());
 
         insertReceivedAt = session.prepare(insertInto(TABLE_NAME_RECEIVED_AT)
@@ -135,6 +138,7 @@ public class CassandraEmailQueryView implements 
EmailQueryView {
             .value(MESSAGE_ID, bindMarker(MESSAGE_ID))
             .value(RECEIVED_AT, bindMarker(RECEIVED_AT))
             .value(SENT_AT, bindMarker(SENT_AT))
+            .value(THREAD_ID, bindMarker(THREAD_ID))
             .build());
 
         deleteLookupRecord = session.prepare(deleteFrom(DATE_LOOKUP_TABLE)
@@ -297,7 +301,7 @@ public class CassandraEmailQueryView implements 
EmailQueryView {
     }
 
     @Override
-    public Mono<Void> save(MailboxId mailboxId, ZonedDateTime sentAt, 
ZonedDateTime receivedAt, MessageId messageId) {
+    public Mono<Void> save(MailboxId mailboxId, ZonedDateTime sentAt, 
ZonedDateTime receivedAt, MessageId messageId, ThreadId threadId) {
         CassandraMessageId cassandraMessageId = (CassandraMessageId) messageId;
         CassandraId cassandraId = (CassandraId) mailboxId;
 
@@ -310,12 +314,14 @@ public class CassandraEmailQueryView implements 
EmailQueryView {
                 executor.executeVoid(insertSentAt.bind()
                     .setUuid(MESSAGE_ID, cassandraMessageId.get())
                     .set(MAILBOX_ID, cassandraId.asUuid(), TypeCodecs.UUID)
-                    .setInstant(SENT_AT, sentAt.toInstant())),
+                    .setInstant(SENT_AT, sentAt.toInstant())
+                    .setUuid(THREAD_ID, ((CassandraMessageId) 
threadId.getBaseMessageId()).get())),
                 executor.executeVoid(insertReceivedAt.bind()
                     .setUuid(MESSAGE_ID, cassandraMessageId.get())
                     .set(MAILBOX_ID, cassandraId.asUuid(), TypeCodecs.UUID)
                     .setInstant(RECEIVED_AT, receivedAt.toInstant())
-                    .setInstant(SENT_AT, sentAt.toInstant())))
+                    .setInstant(SENT_AT, sentAt.toInstant())
+                    .setUuid(THREAD_ID, ((CassandraMessageId) 
threadId.getBaseMessageId()).get())))
                 .then());
     }
 }
diff --git 
a/server/data/data-jmap-cassandra/src/main/java/org/apache/james/jmap/cassandra/projections/CassandraEmailQueryViewDataDefinition.java
 
b/server/data/data-jmap-cassandra/src/main/java/org/apache/james/jmap/cassandra/projections/CassandraEmailQueryViewDataDefinition.java
index be8806e819..195f775eb2 100644
--- 
a/server/data/data-jmap-cassandra/src/main/java/org/apache/james/jmap/cassandra/projections/CassandraEmailQueryViewDataDefinition.java
+++ 
b/server/data/data-jmap-cassandra/src/main/java/org/apache/james/jmap/cassandra/projections/CassandraEmailQueryViewDataDefinition.java
@@ -29,6 +29,7 @@ import static 
org.apache.james.jmap.cassandra.projections.table.CassandraEmailQu
 import static 
org.apache.james.jmap.cassandra.projections.table.CassandraEmailQueryViewTable.SENT_AT;
 import static 
org.apache.james.jmap.cassandra.projections.table.CassandraEmailQueryViewTable.TABLE_NAME_RECEIVED_AT;
 import static 
org.apache.james.jmap.cassandra.projections.table.CassandraEmailQueryViewTable.TABLE_NAME_SENT_AT;
+import static 
org.apache.james.jmap.cassandra.projections.table.CassandraEmailQueryViewTable.THREAD_ID;
 
 import org.apache.james.backends.cassandra.components.CassandraDataDefinition;
 
@@ -43,7 +44,8 @@ public interface CassandraEmailQueryViewDataDefinition {
         .statement(statement -> types -> statement
             .withPartitionKey(MAILBOX_ID, DataTypes.UUID)
             .withClusteringColumn(SENT_AT, DataTypes.TIMESTAMP)
-            .withClusteringColumn(MESSAGE_ID, DataTypes.UUID))
+            .withClusteringColumn(MESSAGE_ID, DataTypes.UUID)
+            .withColumn(THREAD_ID, DataTypes.UUID))
 
         .table(TABLE_NAME_RECEIVED_AT)
         .comment("Storing the JMAP projections for list of emails within a 
mailbox to not rely on OpenSearch for basic Email/query (sorts and filter on 
receivedAt).")
@@ -54,7 +56,8 @@ public interface CassandraEmailQueryViewDataDefinition {
             .withPartitionKey(MAILBOX_ID, DataTypes.UUID)
             .withClusteringColumn(RECEIVED_AT, DataTypes.TIMESTAMP)
             .withClusteringColumn(MESSAGE_ID, DataTypes.UUID)
-            .withColumn(SENT_AT, DataTypes.TIMESTAMP))
+            .withColumn(SENT_AT, DataTypes.TIMESTAMP)
+            .withColumn(THREAD_ID, DataTypes.UUID))
 
         .table(DATE_LOOKUP_TABLE)
         .comment("Given a MailboxId+MessageId lookup the dates of a message to 
delete it.")
diff --git 
a/server/data/data-jmap-cassandra/src/main/java/org/apache/james/jmap/cassandra/projections/table/CassandraEmailQueryViewTable.java
 
b/server/data/data-jmap-cassandra/src/main/java/org/apache/james/jmap/cassandra/projections/table/CassandraEmailQueryViewTable.java
index 65747c722f..a7ccea8f1b 100644
--- 
a/server/data/data-jmap-cassandra/src/main/java/org/apache/james/jmap/cassandra/projections/table/CassandraEmailQueryViewTable.java
+++ 
b/server/data/data-jmap-cassandra/src/main/java/org/apache/james/jmap/cassandra/projections/table/CassandraEmailQueryViewTable.java
@@ -30,4 +30,5 @@ public interface CassandraEmailQueryViewTable {
     CqlIdentifier MESSAGE_ID = CqlIdentifier.fromCql("messageId");
     CqlIdentifier RECEIVED_AT = CqlIdentifier.fromCql("receivedAt");
     CqlIdentifier SENT_AT = CqlIdentifier.fromCql("sentAt");
+    CqlIdentifier THREAD_ID = CqlIdentifier.fromCql("thread_id");
 }
diff --git 
a/server/data/data-jmap-cassandra/src/test/java/org/apache/james/jmap/cassandra/projections/CassandraEmailQueryViewTest.java
 
b/server/data/data-jmap-cassandra/src/test/java/org/apache/james/jmap/cassandra/projections/CassandraEmailQueryViewTest.java
index f43d4fd8a0..33f0eabada 100644
--- 
a/server/data/data-jmap-cassandra/src/test/java/org/apache/james/jmap/cassandra/projections/CassandraEmailQueryViewTest.java
+++ 
b/server/data/data-jmap-cassandra/src/test/java/org/apache/james/jmap/cassandra/projections/CassandraEmailQueryViewTest.java
@@ -27,6 +27,7 @@ import org.apache.james.mailbox.cassandra.ids.CassandraId;
 import org.apache.james.mailbox.cassandra.ids.CassandraMessageId;
 import org.apache.james.mailbox.model.MailboxId;
 import org.apache.james.mailbox.model.MessageId;
+import org.apache.james.mailbox.model.ThreadId;
 import org.junit.jupiter.api.BeforeEach;
 import org.junit.jupiter.api.extension.RegisterExtension;
 
@@ -37,6 +38,7 @@ public class CassandraEmailQueryViewTest implements 
EmailQueryViewContract {
     public static final CassandraMessageId MESSAGE_ID_2 = 
MESSAGE_ID_FACTORY.generate();
     public static final CassandraMessageId MESSAGE_ID_3 = 
MESSAGE_ID_FACTORY.generate();
     public static final CassandraMessageId MESSAGE_ID_4 = 
MESSAGE_ID_FACTORY.generate();
+    public static final ThreadId THREAD_ID = 
ThreadId.fromBaseMessageId(MESSAGE_ID_FACTORY.generate());
 
     @RegisterExtension
     static CassandraClusterExtension cassandra = new 
CassandraClusterExtension(CassandraEmailQueryViewDataDefinition.MODULE);
@@ -77,4 +79,9 @@ public class CassandraEmailQueryViewTest implements 
EmailQueryViewContract {
     public MessageId messageId4() {
         return MESSAGE_ID_4;
     }
+
+    @Override
+    public ThreadId threadId() {
+        return THREAD_ID;
+    }
 }
diff --git 
a/server/data/data-jmap-postgres/src/main/java/org/apache/james/jmap/postgres/projections/PostgresEmailQueryView.java
 
b/server/data/data-jmap-postgres/src/main/java/org/apache/james/jmap/postgres/projections/PostgresEmailQueryView.java
index 0f801feecf..1e1b866faf 100644
--- 
a/server/data/data-jmap-postgres/src/main/java/org/apache/james/jmap/postgres/projections/PostgresEmailQueryView.java
+++ 
b/server/data/data-jmap-postgres/src/main/java/org/apache/james/jmap/postgres/projections/PostgresEmailQueryView.java
@@ -26,6 +26,7 @@ import jakarta.inject.Inject;
 import org.apache.james.jmap.api.projections.EmailQueryView;
 import org.apache.james.mailbox.model.MailboxId;
 import org.apache.james.mailbox.model.MessageId;
+import org.apache.james.mailbox.model.ThreadId;
 import org.apache.james.mailbox.postgres.PostgresMailboxId;
 import org.apache.james.mailbox.postgres.PostgresMessageId;
 import org.apache.james.util.streams.Limit;
@@ -82,7 +83,7 @@ public class PostgresEmailQueryView implements EmailQueryView 
{
     }
 
     @Override
-    public Mono<Void> save(MailboxId mailboxId, ZonedDateTime sentAt, 
ZonedDateTime receivedAt, MessageId messageId) {
-        return emailQueryViewDAO.save(PostgresMailboxId.class.cast(mailboxId), 
sentAt, receivedAt, PostgresMessageId.class.cast(messageId));
+    public Mono<Void> save(MailboxId mailboxId, ZonedDateTime sentAt, 
ZonedDateTime receivedAt, MessageId messageId, ThreadId threadId) {
+        return emailQueryViewDAO.save(PostgresMailboxId.class.cast(mailboxId), 
sentAt, receivedAt, PostgresMessageId.class.cast(messageId), threadId);
     }
 }
diff --git 
a/server/data/data-jmap-postgres/src/main/java/org/apache/james/jmap/postgres/projections/PostgresEmailQueryViewDAO.java
 
b/server/data/data-jmap-postgres/src/main/java/org/apache/james/jmap/postgres/projections/PostgresEmailQueryViewDAO.java
index 4cc5045957..609662856c 100644
--- 
a/server/data/data-jmap-postgres/src/main/java/org/apache/james/jmap/postgres/projections/PostgresEmailQueryViewDAO.java
+++ 
b/server/data/data-jmap-postgres/src/main/java/org/apache/james/jmap/postgres/projections/PostgresEmailQueryViewDAO.java
@@ -25,6 +25,7 @@ import static 
org.apache.james.jmap.postgres.projections.PostgresEmailQueryViewD
 import static 
org.apache.james.jmap.postgres.projections.PostgresEmailQueryViewDataDefinition.PostgresEmailQueryViewTable.RECEIVED_AT;
 import static 
org.apache.james.jmap.postgres.projections.PostgresEmailQueryViewDataDefinition.PostgresEmailQueryViewTable.SENT_AT;
 import static 
org.apache.james.jmap.postgres.projections.PostgresEmailQueryViewDataDefinition.PostgresEmailQueryViewTable.TABLE_NAME;
+import static 
org.apache.james.jmap.postgres.projections.PostgresEmailQueryViewDataDefinition.PostgresEmailQueryViewTable.THREAD_ID;
 
 import java.time.ZonedDateTime;
 
@@ -33,6 +34,7 @@ import jakarta.inject.Named;
 
 import org.apache.james.backends.postgres.utils.PostgresExecutor;
 import org.apache.james.mailbox.model.MessageId;
+import org.apache.james.mailbox.model.ThreadId;
 import org.apache.james.mailbox.postgres.PostgresMailboxId;
 import org.apache.james.mailbox.postgres.PostgresMessageId;
 import org.apache.james.util.streams.Limit;
@@ -131,12 +133,13 @@ public class PostgresEmailQueryViewDAO {
             .where(MAILBOX_ID.eq(mailboxId.asUuid()))));
     }
 
-    public Mono<Void> save(PostgresMailboxId mailboxId, ZonedDateTime sentAt, 
ZonedDateTime receivedAt, PostgresMessageId messageId) {
+    public Mono<Void> save(PostgresMailboxId mailboxId, ZonedDateTime sentAt, 
ZonedDateTime receivedAt, PostgresMessageId messageId, ThreadId threadId) {
         return postgresExecutor.executeVoid(dslContext -> 
Mono.from(dslContext.insertInto(TABLE_NAME)
             .set(MAILBOX_ID, mailboxId.asUuid())
             .set(MESSAGE_ID, messageId.asUuid())
             .set(SENT_AT, sentAt.toOffsetDateTime())
             .set(RECEIVED_AT, receivedAt.toOffsetDateTime())
+            .set(THREAD_ID, ((PostgresMessageId) 
threadId.getBaseMessageId()).asUuid())
             .onConflictOnConstraint(PK_CONSTRAINT_NAME)
             .doNothing()));
     }
diff --git 
a/server/data/data-jmap-postgres/src/main/java/org/apache/james/jmap/postgres/projections/PostgresEmailQueryViewDataDefinition.java
 
b/server/data/data-jmap-postgres/src/main/java/org/apache/james/jmap/postgres/projections/PostgresEmailQueryViewDataDefinition.java
index b2eb132100..d023576f51 100644
--- 
a/server/data/data-jmap-postgres/src/main/java/org/apache/james/jmap/postgres/projections/PostgresEmailQueryViewDataDefinition.java
+++ 
b/server/data/data-jmap-postgres/src/main/java/org/apache/james/jmap/postgres/projections/PostgresEmailQueryViewDataDefinition.java
@@ -46,6 +46,7 @@ public interface PostgresEmailQueryViewDataDefinition {
         Field<UUID> MESSAGE_ID = PostgresMessageDataDefinition.MESSAGE_ID;
         Field<OffsetDateTime> RECEIVED_AT = DSL.field("received_at", 
SQLDataType.TIMESTAMPWITHTIMEZONE.notNull());
         Field<OffsetDateTime> SENT_AT = DSL.field("sent_at", 
SQLDataType.TIMESTAMPWITHTIMEZONE.notNull());
+        Field<UUID> THREAD_ID = 
PostgresMessageDataDefinition.MessageToMailboxTable.THREAD_ID;
 
         Name PK_CONSTRAINT_NAME = DSL.name("email_query_view_pkey");
 
@@ -55,6 +56,7 @@ public interface PostgresEmailQueryViewDataDefinition {
                 .column(MESSAGE_ID)
                 .column(RECEIVED_AT)
                 .column(SENT_AT)
+                .column(THREAD_ID)
                 
.constraint(DSL.constraint(PK_CONSTRAINT_NAME).primaryKey(MAILBOX_ID, 
MESSAGE_ID))))
             .supportsRowLevelSecurity()
             .build();
diff --git 
a/server/data/data-jmap-postgres/src/test/java/org/apache/james/jmap/postgres/projections/PostgresEmailQueryViewManagerRLSTest.java
 
b/server/data/data-jmap-postgres/src/test/java/org/apache/james/jmap/postgres/projections/PostgresEmailQueryViewManagerRLSTest.java
index fbd6d96693..99427ba58e 100644
--- 
a/server/data/data-jmap-postgres/src/test/java/org/apache/james/jmap/postgres/projections/PostgresEmailQueryViewManagerRLSTest.java
+++ 
b/server/data/data-jmap-postgres/src/test/java/org/apache/james/jmap/postgres/projections/PostgresEmailQueryViewManagerRLSTest.java
@@ -26,6 +26,7 @@ import java.time.ZonedDateTime;
 import org.apache.james.backends.postgres.PostgresExtension;
 import org.apache.james.core.Username;
 import org.apache.james.jmap.api.projections.EmailQueryViewManager;
+import org.apache.james.mailbox.model.ThreadId;
 import org.apache.james.mailbox.postgres.PostgresMailboxId;
 import org.apache.james.mailbox.postgres.PostgresMessageId;
 import org.apache.james.util.streams.Limit;
@@ -37,6 +38,7 @@ public class PostgresEmailQueryViewManagerRLSTest {
     public static final PostgresMailboxId MAILBOX_ID_1 = 
PostgresMailboxId.generate();
     public static final PostgresMessageId.Factory MESSAGE_ID_FACTORY = new 
PostgresMessageId.Factory();
     public static final PostgresMessageId MESSAGE_ID_1 = 
MESSAGE_ID_FACTORY.generate();
+    public static final ThreadId THREAD_ID_1 = 
ThreadId.fromBaseMessageId(MESSAGE_ID_FACTORY.generate());
     private static final ZonedDateTime DATE_1 = 
ZonedDateTime.parse("2010-10-30T15:12:00Z");
     private static final ZonedDateTime DATE_2 = 
ZonedDateTime.parse("2010-10-30T16:12:00Z");
 
@@ -54,7 +56,7 @@ public class PostgresEmailQueryViewManagerRLSTest {
     void emailQueryViewCanBeAccessedAtTheDataLevelByMembersOfTheSameDomain() {
         Username username = Username.of("alice@domain1");
 
-        emailQueryViewManager.getEmailQueryView(username).save(MAILBOX_ID_1, 
DATE_1, DATE_2, MESSAGE_ID_1).block();
+        emailQueryViewManager.getEmailQueryView(username).save(MAILBOX_ID_1, 
DATE_1, DATE_2, MESSAGE_ID_1, THREAD_ID_1).block();
 
         
assertThat(emailQueryViewManager.getEmailQueryView(username).listMailboxContentSortedByReceivedAt(MAILBOX_ID_1,
 Limit.limit(1)).collectList().block())
             .isNotEmpty();
@@ -65,7 +67,7 @@ public class PostgresEmailQueryViewManagerRLSTest {
         Username username = Username.of("alice@domain1");
         Username username2 = Username.of("bob@domain2");
 
-        emailQueryViewManager.getEmailQueryView(username).save(MAILBOX_ID_1, 
DATE_1, DATE_2, MESSAGE_ID_1).block();
+        emailQueryViewManager.getEmailQueryView(username).save(MAILBOX_ID_1, 
DATE_1, DATE_2, MESSAGE_ID_1, THREAD_ID_1).block();
 
         
assertThat(emailQueryViewManager.getEmailQueryView(username2).listMailboxContentSortedByReceivedAt(MAILBOX_ID_1,
 Limit.limit(1)).collectList().block())
             .isEmpty();
diff --git 
a/server/data/data-jmap-postgres/src/test/java/org/apache/james/jmap/postgres/projections/PostgresEmailQueryViewTest.java
 
b/server/data/data-jmap-postgres/src/test/java/org/apache/james/jmap/postgres/projections/PostgresEmailQueryViewTest.java
index 652fa676d1..29c366d2ca 100644
--- 
a/server/data/data-jmap-postgres/src/test/java/org/apache/james/jmap/postgres/projections/PostgresEmailQueryViewTest.java
+++ 
b/server/data/data-jmap-postgres/src/test/java/org/apache/james/jmap/postgres/projections/PostgresEmailQueryViewTest.java
@@ -24,6 +24,7 @@ import org.apache.james.jmap.api.projections.EmailQueryView;
 import org.apache.james.jmap.api.projections.EmailQueryViewContract;
 import org.apache.james.mailbox.model.MailboxId;
 import org.apache.james.mailbox.model.MessageId;
+import org.apache.james.mailbox.model.ThreadId;
 import org.apache.james.mailbox.postgres.PostgresMailboxId;
 import org.apache.james.mailbox.postgres.PostgresMessageId;
 import org.junit.jupiter.api.extension.RegisterExtension;
@@ -35,6 +36,7 @@ public class PostgresEmailQueryViewTest implements 
EmailQueryViewContract {
     public static final PostgresMessageId MESSAGE_ID_2 = 
MESSAGE_ID_FACTORY.generate();
     public static final PostgresMessageId MESSAGE_ID_3 = 
MESSAGE_ID_FACTORY.generate();
     public static final PostgresMessageId MESSAGE_ID_4 = 
MESSAGE_ID_FACTORY.generate();
+    public static final ThreadId THREAD_ID = 
ThreadId.fromBaseMessageId(MESSAGE_ID_FACTORY.generate());
 
     @RegisterExtension
     static PostgresExtension postgresExtension = 
PostgresExtension.withoutRowLevelSecurity(PostgresEmailQueryViewDataDefinition.MODULE);
@@ -68,4 +70,9 @@ public class PostgresEmailQueryViewTest implements 
EmailQueryViewContract {
     public MessageId messageId4() {
         return MESSAGE_ID_4;
     }
+
+    @Override
+    public ThreadId threadId() {
+        return THREAD_ID;
+    }
 }
diff --git 
a/server/data/data-jmap/src/main/java/org/apache/james/jmap/api/projections/EmailQueryView.java
 
b/server/data/data-jmap/src/main/java/org/apache/james/jmap/api/projections/EmailQueryView.java
index 11afa60599..e7b1975613 100644
--- 
a/server/data/data-jmap/src/main/java/org/apache/james/jmap/api/projections/EmailQueryView.java
+++ 
b/server/data/data-jmap/src/main/java/org/apache/james/jmap/api/projections/EmailQueryView.java
@@ -24,6 +24,7 @@ import java.util.Objects;
 
 import org.apache.james.mailbox.model.MailboxId;
 import org.apache.james.mailbox.model.MessageId;
+import org.apache.james.mailbox.model.ThreadId;
 import org.apache.james.util.streams.Limit;
 
 import reactor.core.publisher.Flux;
@@ -35,12 +36,14 @@ public interface EmailQueryView {
         private final MessageId messageId;
         private final ZonedDateTime sentAt;
         private final ZonedDateTime receivedAt;
+        private final ThreadId threadId;
 
-        public Entry(MailboxId mailboxId, MessageId messageId, ZonedDateTime 
sentAt, ZonedDateTime receivedAt) {
+        public Entry(MailboxId mailboxId, MessageId messageId, ZonedDateTime 
sentAt, ZonedDateTime receivedAt, ThreadId threadId) {
             this.mailboxId = mailboxId;
             this.messageId = messageId;
             this.sentAt = sentAt;
             this.receivedAt = receivedAt;
+            this.threadId = threadId;
         }
 
         public MailboxId getMailboxId() {
@@ -59,6 +62,10 @@ public interface EmailQueryView {
             return receivedAt;
         }
 
+        public ThreadId getThreadId() {
+            return threadId;
+        }
+
         @Override
         public final boolean equals(Object o) {
             if (o instanceof Entry) {
@@ -67,14 +74,15 @@ public interface EmailQueryView {
                 return Objects.equals(this.mailboxId, entry.mailboxId)
                     && Objects.equals(this.messageId, entry.messageId)
                     && Objects.equals(this.sentAt, entry.sentAt)
-                    && Objects.equals(this.receivedAt, entry.receivedAt);
+                    && Objects.equals(this.receivedAt, entry.receivedAt)
+                    && Objects.equals(this.threadId, entry.threadId);
             }
             return false;
         }
 
         @Override
         public final int hashCode() {
-            return Objects.hash(mailboxId, messageId, sentAt, receivedAt);
+            return Objects.hash(mailboxId, messageId, sentAt, receivedAt, 
threadId);
         }
     }
 
@@ -212,5 +220,5 @@ public interface EmailQueryView {
 
     Mono<Void> delete(MailboxId mailboxId);
 
-    Mono<Void> save(MailboxId mailboxId, ZonedDateTime sentAt, ZonedDateTime 
receivedAt, MessageId messageId);
+    Mono<Void> save(MailboxId mailboxId, ZonedDateTime sentAt, ZonedDateTime 
receivedAt, MessageId messageId, ThreadId threadId);
 }
diff --git 
a/server/data/data-jmap/src/main/java/org/apache/james/jmap/memory/projections/MemoryEmailQueryView.java
 
b/server/data/data-jmap/src/main/java/org/apache/james/jmap/memory/projections/MemoryEmailQueryView.java
index a75b75ca18..27b4493aae 100644
--- 
a/server/data/data-jmap/src/main/java/org/apache/james/jmap/memory/projections/MemoryEmailQueryView.java
+++ 
b/server/data/data-jmap/src/main/java/org/apache/james/jmap/memory/projections/MemoryEmailQueryView.java
@@ -27,6 +27,7 @@ import jakarta.inject.Inject;
 import org.apache.james.jmap.api.projections.EmailQueryView;
 import org.apache.james.mailbox.model.MailboxId;
 import org.apache.james.mailbox.model.MessageId;
+import org.apache.james.mailbox.model.ThreadId;
 import org.apache.james.util.streams.Limit;
 
 import com.google.common.base.Preconditions;
@@ -114,7 +115,7 @@ public class MemoryEmailQueryView implements EmailQueryView 
{
     }
 
     @Override
-    public Mono<Void> save(MailboxId mailboxId, ZonedDateTime sentAt, 
ZonedDateTime receivedAt, MessageId messageId) {
-        return Mono.fromRunnable(() -> entries.put(mailboxId, messageId, new 
Entry(mailboxId, messageId, sentAt, receivedAt)));
+    public Mono<Void> save(MailboxId mailboxId, ZonedDateTime sentAt, 
ZonedDateTime receivedAt, MessageId messageId, ThreadId threadId) {
+        return Mono.fromRunnable(() -> entries.put(mailboxId, messageId, new 
Entry(mailboxId, messageId, sentAt, receivedAt, threadId)));
     }
 }
diff --git 
a/server/data/data-jmap/src/test/java/org/apache/james/jmap/api/projections/EmailQueryViewContract.java
 
b/server/data/data-jmap/src/test/java/org/apache/james/jmap/api/projections/EmailQueryViewContract.java
index ac99142ec4..5283f37939 100644
--- 
a/server/data/data-jmap/src/test/java/org/apache/james/jmap/api/projections/EmailQueryViewContract.java
+++ 
b/server/data/data-jmap/src/test/java/org/apache/james/jmap/api/projections/EmailQueryViewContract.java
@@ -27,6 +27,7 @@ import java.time.ZonedDateTime;
 
 import org.apache.james.mailbox.model.MailboxId;
 import org.apache.james.mailbox.model.MessageId;
+import org.apache.james.mailbox.model.ThreadId;
 import org.apache.james.util.streams.Limit;
 import org.junit.jupiter.api.Test;
 
@@ -51,6 +52,8 @@ public interface EmailQueryViewContract {
 
     MessageId messageId4();
 
+    ThreadId threadId();
+
     @Test
     default void listMailboxContentShouldReturnEmptyByDefault() {
         assertThat(testee().listMailboxContentSortedBySentAt(mailboxId1(), 
Limit.limit(12)).collectList().block())
@@ -59,9 +62,9 @@ public interface EmailQueryViewContract {
 
     @Test
     default void listMailboxContentShouldBeOrderedBySentAt() {
-        testee().save(mailboxId1(), DATE_1, DATE_2, messageId1()).block();
-        testee().save(mailboxId1(), DATE_3, DATE_4, messageId2()).block();
-        testee().save(mailboxId1(), DATE_2, DATE_6, messageId3()).block();
+        testee().save(mailboxId1(), DATE_1, DATE_2, messageId1(), 
threadId()).block();
+        testee().save(mailboxId1(), DATE_3, DATE_4, messageId2(), 
threadId()).block();
+        testee().save(mailboxId1(), DATE_2, DATE_6, messageId3(), 
threadId()).block();
 
         assertThat(testee().listMailboxContentSortedBySentAt(mailboxId1(), 
Limit.limit(12)).collectList().block())
             .containsExactly(messageId2(), messageId3(), messageId1());
@@ -69,9 +72,9 @@ public interface EmailQueryViewContract {
 
     @Test
     default void listMailboxContentShouldApplyLimit() {
-        testee().save(mailboxId1(), DATE_1, DATE_2, messageId1()).block();
-        testee().save(mailboxId1(), DATE_3, DATE_4, messageId2()).block();
-        testee().save(mailboxId1(), DATE_2, DATE_6, messageId3()).block();
+        testee().save(mailboxId1(), DATE_1, DATE_2, messageId1(), 
threadId()).block();
+        testee().save(mailboxId1(), DATE_3, DATE_4, messageId2(), 
threadId()).block();
+        testee().save(mailboxId1(), DATE_2, DATE_6, messageId3(), 
threadId()).block();
 
         assertThat(testee().listMailboxContentSortedBySentAt(mailboxId1(), 
Limit.limit(2)).collectList().block())
             .containsExactly(messageId2(), messageId3());
@@ -79,9 +82,9 @@ public interface EmailQueryViewContract {
 
     @Test
     default void listMailboxContentSinceReceivedAtShouldExcludeTooOldItems() {
-        testee().save(mailboxId1(), DATE_1, DATE_2, messageId1()).block();
-        testee().save(mailboxId1(), DATE_3, DATE_4, messageId2()).block();
-        testee().save(mailboxId1(), DATE_5, DATE_6, messageId3()).block();
+        testee().save(mailboxId1(), DATE_1, DATE_2, messageId1(), 
threadId()).block();
+        testee().save(mailboxId1(), DATE_3, DATE_4, messageId2(), 
threadId()).block();
+        testee().save(mailboxId1(), DATE_5, DATE_6, messageId3(), 
threadId()).block();
 
         
assertThat(testee().listMailboxContentSinceAfterSortedBySentAt(mailboxId1(), 
DATE_3, Limit.limit(12)).collectList().block())
             .containsExactly(messageId3(), messageId2());
@@ -89,9 +92,9 @@ public interface EmailQueryViewContract {
 
     @Test
     default void 
listMailboxContentSinceReceivedAtShouldReturnEmptyWhenNoneMatch() {
-        testee().save(mailboxId1(), DATE_1, DATE_2, messageId1()).block();
-        testee().save(mailboxId1(), DATE_3, DATE_4, messageId2()).block();
-        testee().save(mailboxId1(), DATE_5, DATE_6, messageId3()).block();
+        testee().save(mailboxId1(), DATE_1, DATE_2, messageId1(), 
threadId()).block();
+        testee().save(mailboxId1(), DATE_3, DATE_4, messageId2(), 
threadId()).block();
+        testee().save(mailboxId1(), DATE_5, DATE_6, messageId3(), 
threadId()).block();
 
         
assertThat(testee().listMailboxContentSinceAfterSortedBySentAt(mailboxId1(), 
DATE_7, Limit.limit(12)).collectList().block())
             .isEmpty();
@@ -99,9 +102,9 @@ public interface EmailQueryViewContract {
 
     @Test
     default void listMailboxContentSinceReceivedAtAtShouldApplyLimit() {
-        testee().save(mailboxId1(), DATE_1, DATE_2, messageId1()).block();
-        testee().save(mailboxId1(), DATE_3, DATE_4, messageId2()).block();
-        testee().save(mailboxId1(), DATE_5, DATE_6, messageId3()).block();
+        testee().save(mailboxId1(), DATE_1, DATE_2, messageId1(), 
threadId()).block();
+        testee().save(mailboxId1(), DATE_3, DATE_4, messageId2(), 
threadId()).block();
+        testee().save(mailboxId1(), DATE_5, DATE_6, messageId3(), 
threadId()).block();
 
         
assertThat(testee().listMailboxContentSinceAfterSortedBySentAt(mailboxId1(), 
DATE_1, Limit.limit(2)).collectList().block())
             .containsExactly(messageId3(), messageId2());
@@ -109,9 +112,9 @@ public interface EmailQueryViewContract {
 
     @Test
     default void listMailboxContentSinceSentdAtShouldExcludeTooOldItems() {
-        testee().save(mailboxId1(), DATE_1, DATE_2, messageId1()).block();
-        testee().save(mailboxId1(), DATE_3, DATE_4, messageId2()).block();
-        testee().save(mailboxId1(), DATE_5, DATE_6, messageId3()).block();
+        testee().save(mailboxId1(), DATE_1, DATE_2, messageId1(), 
threadId()).block();
+        testee().save(mailboxId1(), DATE_3, DATE_4, messageId2(), 
threadId()).block();
+        testee().save(mailboxId1(), DATE_5, DATE_6, messageId3(), 
threadId()).block();
 
         assertThat(testee().listMailboxContentSinceSentAt(mailboxId1(), 
DATE_2, Limit.limit(12)).collectList().block())
             .containsExactly(messageId3(), messageId2());
@@ -119,9 +122,9 @@ public interface EmailQueryViewContract {
 
     @Test
     default void listMailboxContentSinceSentAtAtShouldApplyLimit() {
-        testee().save(mailboxId1(), DATE_1, DATE_2, messageId1()).block();
-        testee().save(mailboxId1(), DATE_3, DATE_4, messageId2()).block();
-        testee().save(mailboxId1(), DATE_5, DATE_6, messageId3()).block();
+        testee().save(mailboxId1(), DATE_1, DATE_2, messageId1(), 
threadId()).block();
+        testee().save(mailboxId1(), DATE_3, DATE_4, messageId2(), 
threadId()).block();
+        testee().save(mailboxId1(), DATE_5, DATE_6, messageId3(), 
threadId()).block();
 
         assertThat(testee().listMailboxContentSinceSentAt(mailboxId1(), 
DATE_1, Limit.limit(2)).collectList().block())
             .containsExactly(messageId3(), messageId2());
@@ -129,9 +132,9 @@ public interface EmailQueryViewContract {
 
     @Test
     default void listMailboxContentSinceSentAtShouldReturnEmptyWhenNoneMatch() 
{
-        testee().save(mailboxId1(), DATE_1, DATE_2, messageId1()).block();
-        testee().save(mailboxId1(), DATE_3, DATE_4, messageId2()).block();
-        testee().save(mailboxId1(), DATE_5, DATE_6, messageId3()).block();
+        testee().save(mailboxId1(), DATE_1, DATE_2, messageId1(), 
threadId()).block();
+        testee().save(mailboxId1(), DATE_3, DATE_4, messageId2(), 
threadId()).block();
+        testee().save(mailboxId1(), DATE_5, DATE_6, messageId3(), 
threadId()).block();
 
         assertThat(testee().listMailboxContentSinceSentAt(mailboxId1(), 
DATE_7, Limit.limit(12)).collectList().block())
             .isEmpty();
@@ -139,9 +142,9 @@ public interface EmailQueryViewContract {
 
     @Test
     default void listMailboxContentShouldNotReturnClearedContent() {
-        testee().save(mailboxId1(), DATE_1, DATE_2, messageId1()).block();
-        testee().save(mailboxId1(), DATE_3, DATE_4, messageId2()).block();
-        testee().save(mailboxId1(), DATE_2, DATE_6, messageId3()).block();
+        testee().save(mailboxId1(), DATE_1, DATE_2, messageId1(), 
threadId()).block();
+        testee().save(mailboxId1(), DATE_3, DATE_4, messageId2(), 
threadId()).block();
+        testee().save(mailboxId1(), DATE_2, DATE_6, messageId3(), 
threadId()).block();
 
         testee().delete(mailboxId1()).block();
 
@@ -151,9 +154,9 @@ public interface EmailQueryViewContract {
 
     @Test
     default void listMailboxContentShouldNotReturnDeletedContent() {
-        testee().save(mailboxId1(), DATE_1, DATE_2, messageId1()).block();
-        testee().save(mailboxId1(), DATE_3, DATE_4, messageId2()).block();
-        testee().save(mailboxId1(), DATE_2, DATE_6, messageId3()).block();
+        testee().save(mailboxId1(), DATE_1, DATE_2, messageId1(), 
threadId()).block();
+        testee().save(mailboxId1(), DATE_3, DATE_4, messageId2(), 
threadId()).block();
+        testee().save(mailboxId1(), DATE_2, DATE_6, messageId3(), 
threadId()).block();
 
         testee().delete(mailboxId1(), messageId2()).block();
 
@@ -163,9 +166,9 @@ public interface EmailQueryViewContract {
 
     @Test
     default void 
listMailboxContentSinceReceivedAtShouldNotReturnClearedContent() {
-        testee().save(mailboxId1(), DATE_1, DATE_2, messageId1()).block();
-        testee().save(mailboxId1(), DATE_3, DATE_4, messageId2()).block();
-        testee().save(mailboxId1(), DATE_5, DATE_6, messageId3()).block();
+        testee().save(mailboxId1(), DATE_1, DATE_2, messageId1(), 
threadId()).block();
+        testee().save(mailboxId1(), DATE_3, DATE_4, messageId2(), 
threadId()).block();
+        testee().save(mailboxId1(), DATE_5, DATE_6, messageId3(), 
threadId()).block();
 
         testee().delete(mailboxId1()).block();
 
@@ -175,9 +178,9 @@ public interface EmailQueryViewContract {
 
     @Test
     default void listMailboxContentSinceSentAtShouldNotReturnClearedContent() {
-        testee().save(mailboxId1(), DATE_1, DATE_2, messageId1()).block();
-        testee().save(mailboxId1(), DATE_3, DATE_4, messageId2()).block();
-        testee().save(mailboxId1(), DATE_5, DATE_6, messageId3()).block();
+        testee().save(mailboxId1(), DATE_1, DATE_2, messageId1(), 
threadId()).block();
+        testee().save(mailboxId1(), DATE_3, DATE_4, messageId2(), 
threadId()).block();
+        testee().save(mailboxId1(), DATE_5, DATE_6, messageId3(), 
threadId()).block();
 
         testee().delete(mailboxId1()).block();
 
@@ -187,8 +190,8 @@ public interface EmailQueryViewContract {
 
     @Test
     default void saveShouldBeIdempotent() {
-        testee().save(mailboxId1(), DATE_1, DATE_2, messageId1()).block();
-        testee().save(mailboxId1(), DATE_1, DATE_2, messageId1()).block();
+        testee().save(mailboxId1(), DATE_1, DATE_2, messageId1(), 
threadId()).block();
+        testee().save(mailboxId1(), DATE_1, DATE_2, messageId1(), 
threadId()).block();
 
         assertThat(testee().listMailboxContentSortedBySentAt(mailboxId1(), 
Limit.limit(12)).collectList().block())
             .containsExactly(messageId1());
@@ -196,8 +199,8 @@ public interface EmailQueryViewContract {
 
     @Test
     default void datesCanBeDuplicated() {
-        testee().save(mailboxId1(), DATE_1, DATE_2, messageId1()).block();
-        testee().save(mailboxId1(), DATE_1, DATE_2, messageId2()).block();
+        testee().save(mailboxId1(), DATE_1, DATE_2, messageId1(), 
threadId()).block();
+        testee().save(mailboxId1(), DATE_1, DATE_2, messageId2(), 
threadId()).block();
 
         assertThat(testee().listMailboxContentSortedBySentAt(mailboxId1(), 
Limit.limit(12)).collectList().block())
             .containsExactlyInAnyOrder(messageId1(), messageId2());
@@ -205,9 +208,9 @@ public interface EmailQueryViewContract {
 
     @Test
     default void 
listMailboxContentSinceReceivedAtShouldNotReturnDeletedContent() {
-        testee().save(mailboxId1(), DATE_1, DATE_2, messageId1()).block();
-        testee().save(mailboxId1(), DATE_3, DATE_4, messageId2()).block();
-        testee().save(mailboxId1(), DATE_5, DATE_6, messageId3()).block();
+        testee().save(mailboxId1(), DATE_1, DATE_2, messageId1(), 
threadId()).block();
+        testee().save(mailboxId1(), DATE_3, DATE_4, messageId2(), 
threadId()).block();
+        testee().save(mailboxId1(), DATE_5, DATE_6, messageId3(), 
threadId()).block();
 
         testee().delete(mailboxId1(), messageId2()).block();
 
@@ -217,9 +220,9 @@ public interface EmailQueryViewContract {
 
     @Test
     default void listMailboxContentSinceSentAtShouldNotReturnDeletedContent() {
-        testee().save(mailboxId1(), DATE_1, DATE_2, messageId1()).block();
-        testee().save(mailboxId1(), DATE_3, DATE_4, messageId2()).block();
-        testee().save(mailboxId1(), DATE_5, DATE_6, messageId3()).block();
+        testee().save(mailboxId1(), DATE_1, DATE_2, messageId1(), 
threadId()).block();
+        testee().save(mailboxId1(), DATE_3, DATE_4, messageId2(), 
threadId()).block();
+        testee().save(mailboxId1(), DATE_5, DATE_6, messageId3(), 
threadId()).block();
 
         testee().delete(mailboxId1(), messageId2()).block();
 
@@ -229,9 +232,9 @@ public interface EmailQueryViewContract {
 
     @Test
     default void 
listMailboxContentSortedByReceivedAtShouldBeSortedByReceivedAt() {
-        testee().save(mailboxId1(), DATE_1, DATE_4, messageId1()).block();
-        testee().save(mailboxId1(), DATE_2, DATE_3, messageId2()).block();
-        testee().save(mailboxId1(), DATE_5, DATE_6, messageId3()).block();
+        testee().save(mailboxId1(), DATE_1, DATE_4, messageId1(), 
threadId()).block();
+        testee().save(mailboxId1(), DATE_2, DATE_3, messageId2(), 
threadId()).block();
+        testee().save(mailboxId1(), DATE_5, DATE_6, messageId3(), 
threadId()).block();
 
         assertThat(testee().listMailboxContentSortedByReceivedAt(mailboxId1(), 
Limit.limit(12)).collectList().block())
             .containsExactly(messageId3(), messageId1(), messageId2());
@@ -239,9 +242,9 @@ public interface EmailQueryViewContract {
 
     @Test
     default void 
listMailboxContentSinceSortedByReceivedAtShouldBeSortedByReceivedAt() {
-        testee().save(mailboxId1(), DATE_1, DATE_4, messageId1()).block();
-        testee().save(mailboxId1(), DATE_2, DATE_3, messageId2()).block();
-        testee().save(mailboxId1(), DATE_5, DATE_6, messageId3()).block();
+        testee().save(mailboxId1(), DATE_1, DATE_4, messageId1(), 
threadId()).block();
+        testee().save(mailboxId1(), DATE_2, DATE_3, messageId2(), 
threadId()).block();
+        testee().save(mailboxId1(), DATE_5, DATE_6, messageId3(), 
threadId()).block();
 
         
assertThat(testee().listMailboxContentSinceAfterSortedByReceivedAt(mailboxId1(),
 DATE_4, Limit.limit(12)).collectList().block())
             .containsExactly(messageId3(), messageId1());
@@ -249,9 +252,9 @@ public interface EmailQueryViewContract {
 
     @Test
     default void 
listMailboxContentBeforeSortedByReceivedAtShouldBeSortedByReceivedAt() {
-        testee().save(mailboxId1(), DATE_1, DATE_4, messageId1()).block();
-        testee().save(mailboxId1(), DATE_2, DATE_3, messageId2()).block();
-        testee().save(mailboxId1(), DATE_5, DATE_6, messageId3()).block();
+        testee().save(mailboxId1(), DATE_1, DATE_4, messageId1(), 
threadId()).block();
+        testee().save(mailboxId1(), DATE_2, DATE_3, messageId2(), 
threadId()).block();
+        testee().save(mailboxId1(), DATE_5, DATE_6, messageId3(), 
threadId()).block();
 
         
assertThat(testee().listMailboxContentBeforeSortedByReceivedAt(mailboxId1(), 
DATE_4, Limit.limit(12)).collectList().block())
             .containsExactly(messageId1(), messageId2());
diff --git 
a/server/data/data-jmap/src/test/java/org/apache/james/jmap/memory/projections/MemoryEmailQueryViewTest.java
 
b/server/data/data-jmap/src/test/java/org/apache/james/jmap/memory/projections/MemoryEmailQueryViewTest.java
index 13838942bc..8c53060187 100644
--- 
a/server/data/data-jmap/src/test/java/org/apache/james/jmap/memory/projections/MemoryEmailQueryViewTest.java
+++ 
b/server/data/data-jmap/src/test/java/org/apache/james/jmap/memory/projections/MemoryEmailQueryViewTest.java
@@ -25,6 +25,7 @@ import org.apache.james.mailbox.model.MailboxId;
 import org.apache.james.mailbox.model.MessageId;
 import org.apache.james.mailbox.model.TestId;
 import org.apache.james.mailbox.model.TestMessageId;
+import org.apache.james.mailbox.model.ThreadId;
 import org.junit.jupiter.api.BeforeEach;
 
 public class MemoryEmailQueryViewTest implements EmailQueryViewContract {
@@ -64,4 +65,11 @@ public class MemoryEmailQueryViewTest implements 
EmailQueryViewContract {
     public MessageId messageId4() {
         return TestMessageId.of(4);
     }
+
+    @Override
+    public ThreadId threadId() {
+        return ThreadId.fromBaseMessageId(TestMessageId.of(1));
+    }
+
+
 }
diff --git 
a/server/protocols/jmap-rfc-8621/src/main/java/org/apache/james/jmap/event/PopulateEmailQueryViewListener.java
 
b/server/protocols/jmap-rfc-8621/src/main/java/org/apache/james/jmap/event/PopulateEmailQueryViewListener.java
index af9faf78c2..253b954440 100644
--- 
a/server/protocols/jmap-rfc-8621/src/main/java/org/apache/james/jmap/event/PopulateEmailQueryViewListener.java
+++ 
b/server/protocols/jmap-rfc-8621/src/main/java/org/apache/james/jmap/event/PopulateEmailQueryViewListener.java
@@ -185,7 +185,7 @@ public class PopulateEmailQueryViewListener implements 
ReactiveGroupEventListene
         return Mono.fromCallable(() -> parseMessage(messageResult))
             .map(header -> 
date(header).orElse(messageResult.getInternalDate()))
             .map(date -> ZonedDateTime.ofInstant(date.toInstant(), 
ZoneOffset.UTC))
-            .flatMap(sentAt -> 
viewManager.getEmailQueryView(username).save(mailboxId, sentAt, receivedAt, 
messageResult.getMessageId()))
+            .flatMap(sentAt -> 
viewManager.getEmailQueryView(username).save(mailboxId, sentAt, receivedAt, 
messageResult.getMessageId(), messageResult.getThreadId()))
             .then();
     }
 
diff --git 
a/server/protocols/webadmin/webadmin-jmap/src/main/java/org/apache/james/webadmin/data/jmap/EmailQueryViewPopulator.java
 
b/server/protocols/webadmin/webadmin-jmap/src/main/java/org/apache/james/webadmin/data/jmap/EmailQueryViewPopulator.java
index 207dc4af8f..144ca3e362 100644
--- 
a/server/protocols/webadmin/webadmin-jmap/src/main/java/org/apache/james/webadmin/data/jmap/EmailQueryViewPopulator.java
+++ 
b/server/protocols/webadmin/webadmin-jmap/src/main/java/org/apache/james/webadmin/data/jmap/EmailQueryViewPopulator.java
@@ -43,6 +43,7 @@ import org.apache.james.mailbox.model.MailboxMetaData;
 import org.apache.james.mailbox.model.MessageId;
 import org.apache.james.mailbox.model.MessageRange;
 import org.apache.james.mailbox.model.MessageResult;
+import org.apache.james.mailbox.model.ThreadId;
 import org.apache.james.mailbox.model.search.MailboxQuery;
 import org.apache.james.mime4j.dom.Message;
 import org.apache.james.mime4j.message.DefaultMessageBuilder;
@@ -152,15 +153,16 @@ public class EmailQueryViewPopulator {
         return Mono.fromCallable(() -> {
             MailboxId mailboxId = messageResult.getMailboxId();
             MessageId messageId = messageResult.getMessageId();
+            ThreadId threadId = messageResult.getThreadId();
             ZonedDateTime receivedAt = 
ZonedDateTime.ofInstant(messageResult.getInternalDate().toInstant(), 
ZoneOffset.UTC);
             Message mime4JMessage = parseMessage(messageResult);
             Date sentAtDate = 
Optional.ofNullable(mime4JMessage.getDate()).orElse(messageResult.getInternalDate());
             ZonedDateTime sentAt = 
ZonedDateTime.ofInstant(sentAtDate.toInstant(), ZoneOffset.UTC);
             mime4JMessage.dispose();
 
-            return new EmailQueryView.Entry(mailboxId, messageId, sentAt, 
receivedAt);
+            return new EmailQueryView.Entry(mailboxId, messageId, sentAt, 
receivedAt, threadId);
         })
-            .flatMap(entry -> emailQueryView.save(entry.getMailboxId(), 
entry.getSentAt(), entry.getReceivedAt(), entry.getMessageId()))
+            .flatMap(entry -> emailQueryView.save(entry.getMailboxId(), 
entry.getSentAt(), entry.getReceivedAt(), entry.getMessageId(), 
entry.getThreadId()))
             .thenReturn(Result.COMPLETED)
             .doOnSuccess(any -> progress.incrementProcessedMessageCount())
             .onErrorResume(e -> {


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


Reply via email to