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

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

commit 3705f31b892a1db843c869154b0b97718ff8cc90
Author: vttran <[email protected]>
AuthorDate: Tue Apr 9 11:02:38 2024 +0700

    JAMES-4025 Rewrite some tests of JMAP draft on top of JMAP RFC-8621 
(module: webadmin-integration-test)
---
 .../rabbitmq/FixingGhostMailboxTest.java           | 141 +++--
 ...RabbitMQReindexingWithEventDeadLettersTest.java |  54 +-
 ...ewProjectionHealthCheckIntegrationContract.java | 138 +++--
 .../integration/ForwardIntegrationTest.java        | 348 +++--------
 .../james/webadmin/integration/TestFixture.java    |  34 ++
 .../vault/DeletedMessageVaultIntegrationTest.java  | 675 +++++++++++----------
 ...LinshareBlobExportMechanismIntegrationTest.java | 119 ++--
 .../apache/james/jmap/JmapRFCCommonRequests.java   | 314 ++++++++++
 8 files changed, 1120 insertions(+), 703 deletions(-)

diff --git 
a/server/protocols/webadmin-integration-test/distributed-webadmin-integration-test/src/test/java/org/apache/james/webadmin/integration/rabbitmq/FixingGhostMailboxTest.java
 
b/server/protocols/webadmin-integration-test/distributed-webadmin-integration-test/src/test/java/org/apache/james/webadmin/integration/rabbitmq/FixingGhostMailboxTest.java
index 6418beffea..1f46a15d74 100644
--- 
a/server/protocols/webadmin-integration-test/distributed-webadmin-integration-test/src/test/java/org/apache/james/webadmin/integration/rabbitmq/FixingGhostMailboxTest.java
+++ 
b/server/protocols/webadmin-integration-test/distributed-webadmin-integration-test/src/test/java/org/apache/james/webadmin/integration/rabbitmq/FixingGhostMailboxTest.java
@@ -27,12 +27,10 @@ import static io.restassured.RestAssured.with;
 import static io.restassured.config.EncoderConfig.encoderConfig;
 import static io.restassured.config.RestAssuredConfig.newConfig;
 import static org.apache.james.backends.rabbitmq.RabbitMQFixture.calmlyAwait;
-import static 
org.apache.james.jmap.HttpJmapAuthentication.authenticateJamesUser;
-import static org.apache.james.jmap.LocalHostURIBuilder.baseUri;
+import static org.apache.james.jmap.JmapRFCCommonRequests.UserCredential;
 import static org.assertj.core.api.Assertions.assertThat;
 import static org.hamcrest.Matchers.contains;
 import static org.hamcrest.Matchers.containsInAnyOrder;
-import static org.hamcrest.Matchers.equalTo;
 import static org.hamcrest.Matchers.hasKey;
 import static org.hamcrest.Matchers.hasSize;
 import static org.hamcrest.Matchers.is;
@@ -55,7 +53,7 @@ import 
org.apache.james.backends.cassandra.init.ClusterFactory;
 import 
org.apache.james.backends.cassandra.init.configuration.CassandraConfiguration;
 import 
org.apache.james.backends.cassandra.init.configuration.ClusterConfiguration;
 import org.apache.james.core.Username;
-import org.apache.james.jmap.AccessToken;
+import org.apache.james.jmap.JmapRFCCommonRequests;
 import org.apache.james.jmap.draft.JmapGuiceProbe;
 import org.apache.james.junit.categories.BasicFeature;
 import org.apache.james.junit.categories.Unstable;
@@ -84,6 +82,7 @@ import org.apache.james.utils.WebAdminGuiceProbe;
 import org.apache.james.webadmin.WebAdminUtils;
 import org.apache.james.webadmin.routes.CassandraMailboxMergingRoutes;
 import org.apache.james.webadmin.routes.TasksRoutes;
+import org.hamcrest.Matchers;
 import org.junit.jupiter.api.BeforeEach;
 import org.junit.jupiter.api.Tag;
 import org.junit.jupiter.api.Test;
@@ -98,10 +97,6 @@ import io.restassured.specification.RequestSpecification;
 
 @Tag(BasicFeature.TAG)
 class FixingGhostMailboxTest {
-    private static final String NAME = "[0][0]";
-    private static final String ARGUMENTS = "[0][1]";
-    private static final String FIRST_MAILBOX = ARGUMENTS + ".list[0]";
-
     private static final String DOMAIN = "domain.tld";
     private static final String CEDRIC = "cedric@" + DOMAIN;
     private static final String BOB = "bob@" + DOMAIN;
@@ -136,7 +131,7 @@ class FixingGhostMailboxTest {
                     .build())))
         .build();
 
-    private AccessToken accessToken;
+    private UserCredential aliceCredential;
     private MailboxProbeImpl mailboxProbe;
     private ACLProbe aclProbe;
     private ComposedMessageId message1;
@@ -157,6 +152,7 @@ class FixingGhostMailboxTest {
             .setAccept(ContentType.JSON)
             
.setConfig(newConfig().encoderConfig(encoderConfig().defaultContentCharset(StandardCharsets.UTF_8)))
             .setPort(jmapPort.getValue())
+            .addHeader("accept", "application/json; jmapVersion=rfc-8621")
             .build();
         RestAssured.enableLoggingOfRequestAndResponseIfValidationFails();
         webadminSpecification = 
WebAdminUtils.buildRequestSpecification(webAdminProbe.getWebAdminPort())
@@ -166,7 +162,7 @@ class FixingGhostMailboxTest {
             .addDomain(DOMAIN)
             .addUser(ALICE, ALICE_SECRET)
             .addUser(BOB, BOB_SECRET);
-        accessToken = authenticateJamesUser(baseUri(jmapPort), 
Username.of(ALICE), ALICE_SECRET);
+        aliceCredential = 
JmapRFCCommonRequests.getUserCredential(Username.of(ALICE), ALICE_SECRET);
 
         CassandraProbe probe = server.getProbe(CassandraProbe.class);
         ClusterConfiguration cassandraConfiguration = probe.getConfiguration();
@@ -193,8 +189,24 @@ class FixingGhostMailboxTest {
 
         // trigger provisioning
         given()
-            .header("Authorization", accessToken.asString())
-            .body("[[\"getMailboxes\", {}, \"#0\"]]")
+            .auth().basic(aliceCredential.username().asString(), 
aliceCredential.password())
+            .body("""
+                {
+                    "using": [
+                        "urn:ietf:params:jmap:core",
+                        "urn:ietf:params:jmap:mail"
+                    ],
+                    "methodCalls": [
+                        [
+                            "Mailbox/get",
+                            {
+                                "accountId": "%s",
+                                "ids": null
+                            },
+                            "c1"
+                        ]
+                    ]
+                }""".formatted(aliceCredential.accountId()))
         .when()
             .post("/jmap")
         .then()
@@ -227,16 +239,31 @@ class FixingGhostMailboxTest {
             .timeout(THIRTY_SECONDS)
             .untilAsserted(() ->
                 given()
-                    .header("Authorization", accessToken.asString())
-                    .body("[[\"getMessageList\", 
{\"filter\":{\"inMailboxes\":[\"" + newAliceInbox.serialize() + "\"]}}, 
\"#0\"]]")
+                    .auth().basic(aliceCredential.username().asString(), 
aliceCredential.password())
+                    .body("""
+                        {
+                            "using": [ "urn:ietf:params:jmap:core", 
"urn:ietf:params:jmap:mail", "urn:apache:james:params:jmap:mail:shares" ],
+                            "methodCalls": [
+                                [
+                                    "Email/query",
+                                    {
+                                        "accountId": "%s",
+                                        "filter": {
+                                            "inMailbox": "%s"
+                                        }
+                                    },
+                                    "c1"
+                                ]
+                            ]
+                        }
+                        """.formatted(aliceCredential.accountId(), 
newAliceInbox.serialize()))
                 .when()
                     .post("/jmap")
                 .then()
                     .statusCode(200)
-                    .body(NAME, equalTo("messageList"))
-                    .body(ARGUMENTS + ".messageIds", hasSize(1))
-                    .body(ARGUMENTS + ".messageIds", 
not(contains(message1.getMessageId().serialize())))
-                    .body(ARGUMENTS + ".messageIds", 
contains(message2.getMessageId().serialize())));
+                    .body("methodResponses[0][1].ids", hasSize(1))
+                    .body("methodResponses[0][1].ids", 
not(contains(message1.getMessageId().serialize())))
+                    .body("methodResponses[0][1].ids", 
contains(message2.getMessageId().serialize())));
     }
 
 
@@ -254,18 +281,35 @@ class FixingGhostMailboxTest {
 
         fixGhostMailboxes(newAliceInbox);
 
-        given()
-            .header("Authorization", accessToken.asString())
-            .body("[[\"getMessageList\", {\"filter\":{\"inMailboxes\":[\"" + 
newAliceInbox.serialize() + "\"]}}, \"#0\"]]")
+        calmlyAwait
+            .timeout(THIRTY_SECONDS)
+            .untilAsserted(() -> given()
+            .auth().basic(aliceCredential.username().asString(), 
aliceCredential.password())
+            .body("""
+                {
+                    "using": [ "urn:ietf:params:jmap:core", 
"urn:ietf:params:jmap:mail", "urn:apache:james:params:jmap:mail:shares" ],
+                    "methodCalls": [
+                        [
+                            "Email/query",
+                            {
+                                "accountId": "%s",
+                                "filter": {
+                                    "inMailbox": "%s"
+                                }
+                            },
+                            "c1"
+                        ]
+                    ]
+                }
+                """.formatted(aliceCredential.accountId(), 
newAliceInbox.serialize()))
         .when()
             .post("/jmap")
         .then()
             .statusCode(200)
-            .body(NAME, equalTo("messageList"))
-            .body(ARGUMENTS + ".messageIds", hasSize(2))
-            .body(ARGUMENTS + ".messageIds", containsInAnyOrder(
+            .body("methodResponses[0][1].ids", hasSize(2))
+            .body("methodResponses[0][1].ids", containsInAnyOrder(
                 message1.getMessageId().serialize(),
-                message2.getMessageId().serialize()));
+                message2.getMessageId().serialize())));
     }
 
     @Test
@@ -276,15 +320,28 @@ class FixingGhostMailboxTest {
         fixGhostMailboxes(newAliceInbox);
 
         given()
-            .header("Authorization", accessToken.asString())
-            .body("[[\"getMailboxes\", {\"ids\": [\"" + 
newAliceInbox.serialize() + "\"]}, \"#0\"]]")
+            .auth().basic(aliceCredential.username().asString(), 
aliceCredential.password())
+            .header("accept", "application/json; jmapVersion=rfc-8621")
+            .body("""
+                {
+                    "using": [ "urn:ietf:params:jmap:core", 
"urn:ietf:params:jmap:mail", "urn:apache:james:params:jmap:mail:shares" ],
+                    "methodCalls": [
+                        [
+                            "Mailbox/get",
+                            {
+                                "accountId": "%s",
+                                "ids": ["%s"]
+                            },
+                            "c1"
+                        ]
+                    ]
+                }""".formatted(aliceCredential.accountId(), 
newAliceInbox.serialize()))
         .when()
             .post("/jmap")
         .then()
             .statusCode(200)
-            .body(NAME, equalTo("mailboxes"))
-            .body(FIRST_MAILBOX + ".sharedWith", hasKey(BOB))
-            .body(FIRST_MAILBOX + ".sharedWith", hasKey(CEDRIC));
+            .body("methodResponses[0][1].list[0].rights", hasKey(BOB))
+            .body("methodResponses[0][1].list[0].rights", hasKey(CEDRIC));
     }
 
     @Test
@@ -295,14 +352,30 @@ class FixingGhostMailboxTest {
         fixGhostMailboxes(newAliceInbox);
 
         given()
-            .header("Authorization", accessToken.asString())
-            .body("[[\"getMailboxes\", {\"ids\": [\"" + 
aliceGhostInboxId.serialize() + "\"]}, \"#0\"]]")
+            .auth().basic(aliceCredential.username().asString(), 
aliceCredential.password())
+            .body("""
+                {
+                    "using": [ "urn:ietf:params:jmap:core", 
"urn:ietf:params:jmap:mail", "urn:apache:james:params:jmap:mail:shares"],
+                    "methodCalls": [
+                        [
+                            "Email/query",
+                            {
+                                "accountId": "%s",
+                                "filter": {
+                                    "inMailbox": "%s"
+                                }
+                            },
+                            "c1"
+                        ]
+                    ]
+                }
+                """.formatted(aliceCredential.accountId(), 
aliceGhostInboxId.serialize()))
         .when()
             .post("/jmap")
         .then()
             .statusCode(200)
-            .body(NAME, equalTo("mailboxes"))
-            .body(ARGUMENTS + ".list", hasSize(0));
+            .body("methodResponses[0][1].type", 
Matchers.is("invalidArguments"))
+            .body("methodResponses[0][1].description", 
Matchers.is(aliceGhostInboxId.serialize() + " can not be found"));
     }
 
     @Test
diff --git 
a/server/protocols/webadmin-integration-test/distributed-webadmin-integration-test/src/test/java/org/apache/james/webadmin/integration/rabbitmq/RabbitMQReindexingWithEventDeadLettersTest.java
 
b/server/protocols/webadmin-integration-test/distributed-webadmin-integration-test/src/test/java/org/apache/james/webadmin/integration/rabbitmq/RabbitMQReindexingWithEventDeadLettersTest.java
index 360c40128b..0f53563638 100644
--- 
a/server/protocols/webadmin-integration-test/distributed-webadmin-integration-test/src/test/java/org/apache/james/webadmin/integration/rabbitmq/RabbitMQReindexingWithEventDeadLettersTest.java
+++ 
b/server/protocols/webadmin-integration-test/distributed-webadmin-integration-test/src/test/java/org/apache/james/webadmin/integration/rabbitmq/RabbitMQReindexingWithEventDeadLettersTest.java
@@ -20,13 +20,14 @@
 package org.apache.james.webadmin.integration.rabbitmq;
 
 import static io.restassured.RestAssured.with;
-import static 
org.apache.james.jmap.HttpJmapAuthentication.authenticateJamesUser;
 import static org.apache.james.jmap.JMAPTestingConstants.ALICE;
 import static org.apache.james.jmap.JMAPTestingConstants.ALICE_PASSWORD;
 import static org.apache.james.jmap.JMAPTestingConstants.DOMAIN;
 import static 
org.apache.james.jmap.JMAPTestingConstants.jmapRequestSpecBuilder;
-import static org.apache.james.jmap.JmapCommonRequests.getDraftId;
-import static 
org.apache.james.jmap.JmapCommonRequests.listMessageIdsForAccount;
+import static org.apache.james.jmap.JmapRFCCommonRequests.UserCredential;
+import static org.apache.james.jmap.JmapRFCCommonRequests.getDraftId;
+import static org.apache.james.jmap.JmapRFCCommonRequests.getUserCredential;
+import static 
org.apache.james.jmap.JmapRFCCommonRequests.listMessageIdsForAccount;
 import static org.assertj.core.api.Assertions.assertThat;
 
 import java.time.Duration;
@@ -41,8 +42,6 @@ import org.apache.james.JamesServerBuilder;
 import org.apache.james.JamesServerExtension;
 import org.apache.james.SearchConfiguration;
 import org.apache.james.events.RetryBackoffConfiguration;
-import org.apache.james.jmap.AccessToken;
-import org.apache.james.jmap.LocalHostURIBuilder;
 import org.apache.james.jmap.draft.JmapGuiceProbe;
 import org.apache.james.junit.categories.BasicFeature;
 import org.apache.james.modules.AwsS3BlobStoreExtension;
@@ -106,7 +105,7 @@ class RabbitMQReindexingWithEventDeadLettersTest {
         .build();
 
     private RequestSpecification webAdminApi;
-    private AccessToken aliceAccessToken;
+    private UserCredential aliceCredential;
 
     @BeforeEach
     void setUp(GuiceJamesServer jamesServer) throws Exception {
@@ -123,7 +122,7 @@ class RabbitMQReindexingWithEventDeadLettersTest {
 
         webAdminApi = 
WebAdminUtils.spec(jamesServer.getProbe(WebAdminGuiceProbe.class).getWebAdminPort());
 
-        aliceAccessToken = 
authenticateJamesUser(LocalHostURIBuilder.baseUri(jmapPort), ALICE, 
ALICE_PASSWORD);
+        aliceCredential = getUserCredential(ALICE, ALICE_PASSWORD);
 
         dockerOpenSearch.getDockerOS().pause();
         Thread.sleep(Duration.ofSeconds(2).toMillis()); // Docker pause is 
asynchronous and we found no way to poll for it
@@ -137,7 +136,7 @@ class RabbitMQReindexingWithEventDeadLettersTest {
         CALMLY_AWAIT.until(() -> listOpenSearchFailedEvents().size() == 1);
 
         unpauseOpenSearch();
-        assertThat(listMessageIdsForAccount(aliceAccessToken)).isEmpty();
+        assertThat(listMessageIdsForAccount(aliceCredential)).isEmpty();
     }
 
     @Test
@@ -148,7 +147,7 @@ class RabbitMQReindexingWithEventDeadLettersTest {
         unpauseOpenSearch();
         redeliverAllFailedEvents();
 
-        CALMLY_AWAIT.until(() -> 
listMessageIdsForAccount(aliceAccessToken).size() == 1);
+        CALMLY_AWAIT.until(() -> 
listMessageIdsForAccount(aliceCredential).size() == 1);
         assertThat(listOpenSearchFailedEvents()).isEmpty();
     }
 
@@ -158,25 +157,28 @@ class RabbitMQReindexingWithEventDeadLettersTest {
     }
 
     private void aliceSavesADraft() {
-        String messageCreationId = "creationId1337";
-        String requestBody = "[" +
-            "  [" +
-            "    \"setMessages\"," +
-            "    {" +
-            "      \"create\": { \"" + messageCreationId  + "\" : {" +
-            "        \"from\": { \"name\": \"Me\", \"email\": \"" + 
ALICE.asString() + "\"}," +
-            "        \"to\": [{ \"name\": \"BOB\", \"email\": 
\"[email protected]\"}]," +
-            "        \"subject\": \"subject\"," +
-            "        \"keywords\": {\"$Draft\": true}," +
-            "        \"mailboxIds\": [\"" + getDraftId(aliceAccessToken) + 
"\"]" +
-            "      }}" +
-            "    }," +
-            "    \"#0\"" +
-            "  ]" +
-            "]";
+        String draftMailboxId = getDraftId(aliceCredential);
+        String requestBody =
+            "{" +
+                "    \"using\": [\"urn:ietf:params:jmap:core\", 
\"urn:ietf:params:jmap:mail\"]," +
+                "    \"methodCalls\": [" +
+                "        [\"Email/set\", {" +
+                "            \"accountId\": \"" + aliceCredential.accountId() 
+ "\"," +
+                "            \"create\": {" +
+                "                \"e1526\": {" +
+                "                    \"mailboxIds\": { \"" + draftMailboxId + 
"\": true }," +
+                "                    \"subject\": \"subject\"," +
+                "                    \"keywords\": {\"$Draft\": true}," +
+                "                    \"to\": [{\"email\": 
\"[email protected]\"}]," +
+                "                    \"from\": [{\"email\": \"" + 
ALICE.asString() + "\"}]" +
+                "                }" +
+                "            }" +
+                "        }, \"c1\"]" +
+                "    ]" +
+                "}";
 
         with()
-            .header("Authorization", aliceAccessToken.asString())
+            .auth().basic(aliceCredential.username().asString(), 
aliceCredential.password())
             .body(requestBody)
             .post("/jmap");
     }
diff --git 
a/server/protocols/webadmin-integration-test/webadmin-integration-test-common/src/main/java/org/apache/james/webadmin/integration/FastViewProjectionHealthCheckIntegrationContract.java
 
b/server/protocols/webadmin-integration-test/webadmin-integration-test-common/src/main/java/org/apache/james/webadmin/integration/FastViewProjectionHealthCheckIntegrationContract.java
index 24acfa192d..21f1fdfbc5 100644
--- 
a/server/protocols/webadmin-integration-test/webadmin-integration-test-common/src/main/java/org/apache/james/webadmin/integration/FastViewProjectionHealthCheckIntegrationContract.java
+++ 
b/server/protocols/webadmin-integration-test/webadmin-integration-test-common/src/main/java/org/apache/james/webadmin/integration/FastViewProjectionHealthCheckIntegrationContract.java
@@ -20,30 +20,29 @@
 package org.apache.james.webadmin.integration;
 
 import static io.restassured.RestAssured.with;
-import static 
org.apache.james.jmap.HttpJmapAuthentication.authenticateJamesUser;
 import static org.apache.james.jmap.JMAPTestingConstants.ALICE;
 import static org.apache.james.jmap.JMAPTestingConstants.ALICE_PASSWORD;
-import static org.apache.james.jmap.JMAPTestingConstants.ARGUMENTS;
 import static org.apache.james.jmap.JMAPTestingConstants.BOB;
 import static org.apache.james.jmap.JMAPTestingConstants.BOB_PASSWORD;
 import static org.apache.james.jmap.JMAPTestingConstants.CEDRIC;
 import static org.apache.james.jmap.JMAPTestingConstants.CEDRIC_PASSWORD;
 import static org.apache.james.jmap.JMAPTestingConstants.DOMAIN;
-import static org.apache.james.jmap.JMAPTestingConstants.calmlyAwait;
 import static 
org.apache.james.jmap.JMAPTestingConstants.jmapRequestSpecBuilder;
-import static org.apache.james.jmap.JmapCommonRequests.bodyOfMessage;
-import static org.apache.james.jmap.JmapCommonRequests.getLastMessageId;
-import static org.apache.james.jmap.JmapCommonRequests.getOutboxId;
-import static 
org.apache.james.jmap.JmapCommonRequests.listMessageIdsForAccount;
-import static org.apache.james.jmap.LocalHostURIBuilder.baseUri;
+import static 
org.apache.james.jmap.JmapRFCCommonRequests.ACCEPT_JMAP_RFC_HEADER;
+import static org.apache.james.jmap.JmapRFCCommonRequests.UserCredential;
+import static org.apache.james.jmap.JmapRFCCommonRequests.getLastMessageId;
+import static org.apache.james.jmap.JmapRFCCommonRequests.getUserCredential;
+import static 
org.apache.james.jmap.JmapRFCCommonRequests.listMessageIdsForAccount;
+import static 
org.apache.james.webadmin.integration.TestFixture.WAIT_THIRTY_SECONDS;
 import static org.assertj.core.api.Assertions.assertThat;
 import static org.hamcrest.Matchers.equalTo;
+import static org.hamcrest.Matchers.notNullValue;
 
 import java.util.stream.IntStream;
 
 import org.apache.james.GuiceJamesServer;
 import org.apache.james.core.healthcheck.ResultStatus;
-import org.apache.james.jmap.AccessToken;
+import org.apache.james.jmap.JmapRFCCommonRequests;
 import org.apache.james.jmap.draft.JmapGuiceProbe;
 import org.apache.james.probe.DataProbe;
 import org.apache.james.util.Port;
@@ -51,18 +50,20 @@ import org.apache.james.utils.DataProbeImpl;
 import org.apache.james.utils.WebAdminGuiceProbe;
 import org.apache.james.webadmin.WebAdminUtils;
 import org.eclipse.jetty.http.HttpStatus;
+import org.hamcrest.Matchers;
 import org.junit.jupiter.api.BeforeEach;
 import org.junit.jupiter.api.Test;
 
 import io.restassured.RestAssured;
+import io.restassured.http.ContentType;
 import io.restassured.specification.RequestSpecification;
 
 public abstract class FastViewProjectionHealthCheckIntegrationContract {
     private static final String MESSAGE_FAST_VIEW_PROJECTION = 
"MessageFastViewProjection";
 
     private RequestSpecification webAdminApi;
-    private AccessToken bobAccessToken;
-    private AccessToken aliceAccessToken;
+    private UserCredential bobCredential;
+    private UserCredential aliceCredential;
 
     @BeforeEach
     void setUp(GuiceJamesServer jamesServer) throws Exception {
@@ -76,9 +77,8 @@ public abstract class 
FastViewProjectionHealthCheckIntegrationContract {
         RestAssured.requestSpecification = jmapRequestSpecBuilder
             .setPort(jmapPort.getValue())
             .build();
-
-        bobAccessToken = authenticateJamesUser(baseUri(jmapPort), BOB, 
BOB_PASSWORD);
-        aliceAccessToken = authenticateJamesUser(baseUri(jmapPort), ALICE, 
ALICE_PASSWORD);
+        bobCredential = getUserCredential(BOB, BOB_PASSWORD);
+        aliceCredential = getUserCredential(ALICE, ALICE_PASSWORD);
 
         webAdminApi = 
WebAdminUtils.spec(jamesServer.getProbe(WebAdminGuiceProbe.class).getWebAdminPort());
     }
@@ -96,7 +96,7 @@ public abstract class 
FastViewProjectionHealthCheckIntegrationContract {
 
     @Test
     void checkShouldReturnHealthyAfterSendingAMessageWithReads() {
-        bobSendAMessageToAlice();
+        bobSendAnEmailToAlice();
 
         IntStream.rangeClosed(1, 20)
             .forEach(counter -> aliceReadLastMessage());
@@ -112,7 +112,7 @@ public abstract class 
FastViewProjectionHealthCheckIntegrationContract {
 
     @Test
     void 
checkShouldReturnDegradedAfterFewReadsOnAMissedProjection(GuiceJamesServer 
guiceJamesServer) throws Exception {
-        bobSendAMessageToAlice();
+        bobSendAnEmailToAlice();
 
         makeHealthCheckDegraded(guiceJamesServer);
 
@@ -130,7 +130,7 @@ public abstract class 
FastViewProjectionHealthCheckIntegrationContract {
 
     @Test
     void 
checkShouldTurnFromDegradedToHealthyAfterMoreReadsOnAMissedProjection(GuiceJamesServer
 guiceJamesServer) {
-        bobSendAMessageToAlice();
+        bobSendAnEmailToAlice();
 
         makeHealthCheckDegraded(guiceJamesServer);
 
@@ -152,39 +152,89 @@ public abstract class 
FastViewProjectionHealthCheckIntegrationContract {
         aliceReadLastMessage();
     }
 
-    private void bobSendAMessageToAlice() {
-        String messageCreationId = "creationId";
-        String outboxId = getOutboxId(bobAccessToken);
-        String requestBody = "[" +
-            "  [" +
-            "    \"setMessages\"," +
-            "    {" +
-            "      \"create\": { \"" + messageCreationId  + "\" : {" +
-            "        \"from\": { \"name\": \"Bob\", \"email\": \"" + 
BOB.asString() + "\"}," +
-            "        \"to\": [{ \"name\": \"Alice\", \"email\": \"" + 
ALICE.asString() + "\"}]," +
-            "        \"subject\": \"bob to alice\"," +
-            "        \"textBody\": \"body\"," +
-            "        \"htmlBody\": \"Test <b>body</b>, HTML version\"," +
-            "        \"mailboxIds\": [\"" + outboxId + "\"] " +
-            "      }}" +
-            "    }," +
-            "    \"#0\"" +
-            "  ]" +
-            "]";
+    private void bobSendAnEmailToAlice() {
+        JmapRFCCommonRequests.UserCredential bobCredential = 
getUserCredential(BOB, BOB_PASSWORD);
+        String bobOutboxId = JmapRFCCommonRequests.getOutboxId(bobCredential);
+        String request =
+            "{" +
+                "    \"using\": [\"urn:ietf:params:jmap:core\", 
\"urn:ietf:params:jmap:mail\", \"urn:ietf:params:jmap:submission\"]," +
+                "    \"methodCalls\": [" +
+                "        [\"Email/set\", {" +
+                "            \"accountId\": \"" + bobCredential.accountId() + 
"\"," +
+                "            \"create\": {" +
+                "                \"e1526\": {" +
+                "                    \"mailboxIds\": { \"" + bobOutboxId + 
"\": true }," +
+                "                    \"subject\": \"subject\"," +
+                "                    \"htmlBody\": [{" +
+                "                        \"partId\": \"a49d\"," +
+                "                        \"type\": \"text/html\"" +
+                "                    }]," +
+                "                    \"bodyValues\": {" +
+                "                        \"a49d\": {" +
+                "                            \"value\": \"Test <b>body</b>, 
HTML version\"" +
+                "                        }" +
+                "                    }," +
+                "                    \"to\": [{\"email\": \"" + 
ALICE.asString() + "\"}]," +
+                "                    \"from\": [{\"email\": \"" + 
BOB.asString() + "\"}]" +
+                "                }" +
+                "            }" +
+                "        }, \"c1\"]," +
+                "        [\"EmailSubmission/set\", {" +
+                "            \"accountId\": \"" + bobCredential.accountId() + 
"\"," +
+                "            \"create\": {" +
+                "                \"k1490\": {" +
+                "                    \"emailId\": \"#e1526\"," +
+                "                    \"envelope\": {" +
+                "                        \"mailFrom\": {\"email\": \"" + 
BOB.asString() + "\"}," +
+                "                        \"rcptTo\": [{\"email\": \"" + 
ALICE.asString() + "\"}]" +
+                "                    }" +
+                "                }" +
+                "            }" +
+                "        }, \"c3\"]" +
+                "    ]" +
+                "}";
+
         with()
-            .header("Authorization", bobAccessToken.asString())
-            .body(requestBody)
+            .auth().basic(bobCredential.username().asString(), 
bobCredential.password())
+            .header(ACCEPT_JMAP_RFC_HEADER)
+            .body(request)
             .post("/jmap")
         .then()
-            .extract()
-            .body()
-            .path(ARGUMENTS + ".created." + messageCreationId + ".id");
+            .statusCode(200)
+            .contentType(ContentType.JSON)
+            .body("methodResponses[0][1].created.e1526", 
Matchers.is(notNullValue()));
 
-        calmlyAwait.untilAsserted(() -> 
assertThat(listMessageIdsForAccount(aliceAccessToken))
-            .hasSize(1));
+        WAIT_THIRTY_SECONDS
+            .untilAsserted(() -> 
assertThat(listMessageIdsForAccount(aliceCredential)).hasSize(1));
     }
 
     private void aliceReadLastMessage() {
-        bodyOfMessage(aliceAccessToken, getLastMessageId(aliceAccessToken));
+        // read with fast view
+        with()
+            .auth().basic(aliceCredential.username().asString(), 
aliceCredential.password())
+            .header(ACCEPT_JMAP_RFC_HEADER)
+            .body("""
+                {
+                    "using": [ "urn:ietf:params:jmap:core", 
"urn:ietf:params:jmap:mail" ],
+                    "methodCalls": [
+                        [
+                            "Email/get",
+                            {
+                                "accountId": "%s",
+                                "ids": ["%s"],
+                                "properties": [ "preview", "hasAttachment" ]
+                            },
+                            "c1"
+                        ]
+                    ]
+                }
+                """.formatted(aliceCredential.accountId(), 
getLastMessageId(aliceCredential)))
+        .when()
+            .post("/jmap")
+        .then()
+            .statusCode(200)
+            .contentType(ContentType.JSON)
+            .extract()
+            .jsonPath();
     }
 }
diff --git 
a/server/protocols/webadmin-integration-test/webadmin-integration-test-common/src/main/java/org/apache/james/webadmin/integration/ForwardIntegrationTest.java
 
b/server/protocols/webadmin-integration-test/webadmin-integration-test-common/src/main/java/org/apache/james/webadmin/integration/ForwardIntegrationTest.java
index c3884586ad..2f7a22bd9b 100644
--- 
a/server/protocols/webadmin-integration-test/webadmin-integration-test-common/src/main/java/org/apache/james/webadmin/integration/ForwardIntegrationTest.java
+++ 
b/server/protocols/webadmin-integration-test/webadmin-integration-test-common/src/main/java/org/apache/james/webadmin/integration/ForwardIntegrationTest.java
@@ -19,34 +19,32 @@
 
 package org.apache.james.webadmin.integration;
 
-import static io.restassured.RestAssured.given;
 import static io.restassured.RestAssured.with;
-import static 
org.apache.james.jmap.HttpJmapAuthentication.authenticateJamesUser;
 import static org.apache.james.jmap.JMAPTestingConstants.ALICE;
 import static org.apache.james.jmap.JMAPTestingConstants.ALICE_PASSWORD;
-import static org.apache.james.jmap.JMAPTestingConstants.ARGUMENTS;
 import static org.apache.james.jmap.JMAPTestingConstants.BOB;
 import static org.apache.james.jmap.JMAPTestingConstants.BOB_PASSWORD;
 import static org.apache.james.jmap.JMAPTestingConstants.CEDRIC;
 import static org.apache.james.jmap.JMAPTestingConstants.CEDRIC_PASSWORD;
 import static org.apache.james.jmap.JMAPTestingConstants.DOMAIN;
-import static org.apache.james.jmap.JMAPTestingConstants.NAME;
-import static org.apache.james.jmap.JMAPTestingConstants.calmlyAwait;
 import static 
org.apache.james.jmap.JMAPTestingConstants.jmapRequestSpecBuilder;
-import static org.apache.james.jmap.JmapCommonRequests.getOutboxId;
-import static 
org.apache.james.jmap.JmapCommonRequests.isAnyMessageFoundInRecipientsMailboxes;
-import static org.apache.james.jmap.LocalHostURIBuilder.baseUri;
-import static org.hamcrest.Matchers.equalTo;
-import static org.hamcrest.Matchers.hasSize;
+import static 
org.apache.james.jmap.JmapRFCCommonRequests.ACCEPT_JMAP_RFC_HEADER;
+import static org.apache.james.jmap.JmapRFCCommonRequests.UserCredential;
+import static org.apache.james.jmap.JmapRFCCommonRequests.getUserCredential;
+import static 
org.apache.james.jmap.JmapRFCCommonRequests.listMessageIdsForAccount;
+import static 
org.apache.james.webadmin.integration.TestFixture.WAIT_THIRTY_SECONDS;
+import static org.assertj.core.api.AssertionsForInterfaceTypes.assertThat;
+import static org.hamcrest.Matchers.notNullValue;
 
 import java.io.IOException;
-import java.time.Duration;
-import java.util.concurrent.TimeUnit;
 
 import org.apache.james.GuiceJamesServer;
-import org.apache.james.jmap.AccessToken;
+import org.apache.james.jmap.JmapRFCCommonRequests;
 import org.apache.james.jmap.draft.JmapGuiceProbe;
 import org.apache.james.junit.categories.BasicFeature;
+import org.apache.james.mailbox.DefaultMailboxes;
+import org.apache.james.mailbox.probe.MailboxProbe;
+import org.apache.james.modules.MailboxProbeImpl;
 import org.apache.james.modules.protocols.SmtpGuiceProbe;
 import org.apache.james.probe.DataProbe;
 import org.apache.james.util.Port;
@@ -54,12 +52,14 @@ import org.apache.james.utils.DataProbeImpl;
 import org.apache.james.utils.SMTPMessageSender;
 import org.apache.james.utils.WebAdminGuiceProbe;
 import org.apache.james.webadmin.WebAdminUtils;
+import org.hamcrest.Matchers;
 import org.junit.jupiter.api.AfterEach;
 import org.junit.jupiter.api.BeforeEach;
 import org.junit.jupiter.api.Tag;
 import org.junit.jupiter.api.Test;
 
 import io.restassured.RestAssured;
+import io.restassured.http.ContentType;
 import io.restassured.specification.RequestSpecification;
 
 public abstract class ForwardIntegrationTest {
@@ -70,16 +70,21 @@ public abstract class ForwardIntegrationTest {
 
     @BeforeEach
     void setUp(GuiceJamesServer jmapServer) throws Exception {
+        MailboxProbe mailboxProbe = 
jmapServer.getProbe(MailboxProbeImpl.class);
+
         messageSender = new SMTPMessageSender(DOMAIN);
         DataProbe dataProbe = jmapServer.getProbe(DataProbeImpl.class);
         dataProbe.addDomain(DOMAIN);
         dataProbe.addUser(BOB.asString(), BOB_PASSWORD);
         dataProbe.addUser(ALICE.asString(), ALICE_PASSWORD);
         dataProbe.addUser(CEDRIC.asString(), CEDRIC_PASSWORD);
+        mailboxProbe.createMailbox("#private", ALICE.asString(), 
DefaultMailboxes.INBOX);
+        mailboxProbe.createMailbox("#private", CEDRIC.asString(), 
DefaultMailboxes.INBOX);
 
         jmapPort = jmapServer.getProbe(JmapGuiceProbe.class).getJmapPort();
         RestAssured.requestSpecification = jmapRequestSpecBuilder
             .setPort(jmapPort.getValue())
+            .addHeader(ACCEPT_JMAP_RFC_HEADER.getName(), 
ACCEPT_JMAP_RFC_HEADER.getValue())
             .build();
 
         webAdminApi = 
WebAdminUtils.spec(jmapServer.getProbe(WebAdminGuiceProbe.class).getWebAdminPort());
@@ -96,47 +101,11 @@ public abstract class ForwardIntegrationTest {
     void messageShouldBeForwardedWhenDefinedInRESTAPI() {
         webAdminApi.put(String.format("/address/forwards/%s/targets/%s", 
ALICE.asString(), BOB.asString()));
 
-        AccessToken cedricAccessToken = 
authenticateJamesUser(baseUri(jmapPort), CEDRIC, CEDRIC_PASSWORD);
-        String messageCreationId = "creationId1337";
-        String requestBody = "[" +
-            "  [" +
-            "    \"setMessages\"," +
-            "    {" +
-            "      \"create\": { \"" + messageCreationId  + "\" : {" +
-            "        \"from\": { \"name\": \"Me\", \"email\": \"" + 
CEDRIC.asString() + "\"}," +
-            "        \"to\": [{ \"name\": \"Alice\", \"email\": \"" + 
ALICE.asString() + "\"}]," +
-            "        \"subject\": \"subject\"," +
-            "        \"isUnread\": true," +
-            "        \"isFlagged\": true," +
-            "        \"isAnswered\": true," +
-            "        \"isDraft\": true," +
-            "        \"isForwarded\": true," +
-            "        \"mailboxIds\": [\"" + getOutboxId(cedricAccessToken) + 
"\"]" +
-            "      }}" +
-            "    }," +
-            "    \"#0\"" +
-            "  ]" +
-            "]";
+        cedricSendAnEmailToAlice();
 
-        with()
-            .header("Authorization", cedricAccessToken.asString())
-            .body(requestBody)
-        .post("/jmap");
-
-        AccessToken bobAccessToken = authenticateJamesUser(baseUri(jmapPort), 
BOB, BOB_PASSWORD);
-        calmlyAwait
-            .pollDelay(Duration.ofMillis(500))
-            .atMost(30, TimeUnit.SECONDS).until(() -> 
isAnyMessageFoundInRecipientsMailboxes(bobAccessToken));
-        given()
-            .header("Authorization", bobAccessToken.asString())
-            .body("[[\"getMessageList\", {}, \"#0\"]]")
-        .when()
-            .post("/jmap")
-        .then()
-            .log().ifValidationFails()
-            .statusCode(200)
-            .body(NAME, equalTo("messageList"))
-            .body(ARGUMENTS + ".messageIds", hasSize(1));
+        UserCredential bobCredential = getUserCredential(BOB, BOB_PASSWORD);
+        WAIT_THIRTY_SECONDS.untilAsserted(() -> 
assertThat(listMessageIdsForAccount(bobCredential))
+                .hasSize(1));
     }
 
     @Test
@@ -144,59 +113,15 @@ public abstract class ForwardIntegrationTest {
         webAdminApi.put(String.format("/address/forwards/%s/targets/%s", 
ALICE.asString(), BOB.asString()));
         webAdminApi.put(String.format("/address/forwards/%s/targets/%s", 
ALICE.asString(), ALICE.asString()));
 
-        AccessToken cedricAccessToken = 
authenticateJamesUser(baseUri(jmapPort), CEDRIC, CEDRIC_PASSWORD);
-        AccessToken aliceAccessToken = 
authenticateJamesUser(baseUri(jmapPort), ALICE, ALICE_PASSWORD);
-        String messageCreationId = "creationId1337";
-        String requestBody = "[" +
-            "  [" +
-            "    \"setMessages\"," +
-            "    {" +
-            "      \"create\": { \"" + messageCreationId  + "\" : {" +
-            "        \"from\": { \"name\": \"Me\", \"email\": \"" + 
CEDRIC.asString() + "\"}," +
-            "        \"to\": [{ \"name\": \"Alice\", \"email\": \"" + 
ALICE.asString() + "\"}]," +
-            "        \"subject\": \"subject\"," +
-            "        \"isUnread\": true," +
-            "        \"isFlagged\": true," +
-            "        \"isAnswered\": true," +
-            "        \"isDraft\": true," +
-            "        \"isForwarded\": true," +
-            "        \"mailboxIds\": [\"" + getOutboxId(cedricAccessToken) + 
"\"]" +
-            "      }}" +
-            "    }," +
-            "    \"#0\"" +
-            "  ]" +
-            "]";
+        cedricSendAnEmailToAlice();
 
-        with()
-            .header("Authorization", cedricAccessToken.asString())
-            .body(requestBody)
-        .post("/jmap");
-
-        AccessToken bobAccessToken = authenticateJamesUser(baseUri(jmapPort), 
BOB, BOB_PASSWORD);
-        calmlyAwait
-            .pollDelay(Duration.ofMillis(500))
-            .atMost(30, TimeUnit.SECONDS).until(() -> 
isAnyMessageFoundInRecipientsMailboxes(bobAccessToken));
-        given()
-            .header("Authorization", bobAccessToken.asString())
-            .body("[[\"getMessageList\", {}, \"#0\"]]")
-        .when()
-            .post("/jmap")
-        .then()
-            .log().ifValidationFails()
-            .statusCode(200)
-            .body(NAME, equalTo("messageList"))
-            .body(ARGUMENTS + ".messageIds", hasSize(1));
+        UserCredential bobCredential = getUserCredential(BOB, BOB_PASSWORD);
+        WAIT_THIRTY_SECONDS.untilAsserted(() -> 
assertThat(listMessageIdsForAccount(bobCredential))
+                .hasSize(1));
 
-        given()
-            .header("Authorization", aliceAccessToken.asString())
-            .body("[[\"getMessageList\", {}, \"#0\"]]")
-        .when()
-            .post("/jmap")
-        .then()
-            .log().ifValidationFails()
-            .statusCode(200)
-            .body(NAME, equalTo("messageList"))
-            .body(ARGUMENTS + ".messageIds", hasSize(1));
+        UserCredential aliceCredential = getUserCredential(BOB, BOB_PASSWORD);
+        WAIT_THIRTY_SECONDS.untilAsserted(() -> 
assertThat(listMessageIdsForAccount(aliceCredential))
+                .hasSize(1));
     }
 
     @Test
@@ -208,32 +133,13 @@ public abstract class ForwardIntegrationTest {
             .connect("127.0.0.1", 
jmapServer.getProbe(SmtpGuiceProbe.class).getSmtpPort())
             .sendMessage("[email protected]", ALICE.asString());
 
-        AccessToken bobAccessToken = authenticateJamesUser(baseUri(jmapPort), 
BOB, BOB_PASSWORD);
-        calmlyAwait
-            .pollDelay(Duration.ofMillis(500))
-            .atMost(30, TimeUnit.SECONDS).until(() -> 
isAnyMessageFoundInRecipientsMailboxes(bobAccessToken));
-        given()
-            .header("Authorization", bobAccessToken.asString())
-            .body("[[\"getMessageList\", {}, \"#0\"]]")
-        .when()
-            .post("/jmap")
-        .then()
-            .log().ifValidationFails()
-            .statusCode(200)
-            .body(NAME, equalTo("messageList"))
-            .body(ARGUMENTS + ".messageIds", hasSize(1));
-
-        AccessToken aliceAccessToken = 
authenticateJamesUser(baseUri(jmapPort), ALICE, ALICE_PASSWORD);
-        given()
-            .header("Authorization", aliceAccessToken.asString())
-            .body("[[\"getMessageList\", {}, \"#0\"]]")
-        .when()
-            .post("/jmap")
-        .then()
-            .log().ifValidationFails()
-            .statusCode(200)
-            .body(NAME, equalTo("messageList"))
-            .body(ARGUMENTS + ".messageIds", hasSize(1));
+        UserCredential bobCredential = getUserCredential(BOB, BOB_PASSWORD);
+        WAIT_THIRTY_SECONDS.untilAsserted(() -> 
assertThat(listMessageIdsForAccount(bobCredential))
+            .hasSize(1));
+
+        UserCredential aliceCredential = getUserCredential(BOB, BOB_PASSWORD);
+        WAIT_THIRTY_SECONDS.untilAsserted(() -> 
assertThat(listMessageIdsForAccount(aliceCredential))
+            .hasSize(1));
     }
 
     @Test
@@ -241,47 +147,11 @@ public abstract class ForwardIntegrationTest {
         webAdminApi.put(String.format("/address/forwards/%s/targets/%s", 
ALICE.asString(), CEDRIC.asString()));
         webAdminApi.put(String.format("/address/forwards/%s/targets/%s", 
CEDRIC.asString(), BOB.asString()));
 
-        AccessToken cedricAccessToken = 
authenticateJamesUser(baseUri(jmapPort), CEDRIC, CEDRIC_PASSWORD);
-        String messageCreationId = "creationId1337";
-        String requestBody = "[" +
-            "  [" +
-            "    \"setMessages\"," +
-            "    {" +
-            "      \"create\": { \"" + messageCreationId  + "\" : {" +
-            "        \"from\": { \"name\": \"Me\", \"email\": \"" + 
CEDRIC.asString() + "\"}," +
-            "        \"to\": [{ \"name\": \"Alice\", \"email\": \"" + 
ALICE.asString() + "\"}]," +
-            "        \"subject\": \"subject\"," +
-            "        \"isUnread\": true," +
-            "        \"isFlagged\": true," +
-            "        \"isAnswered\": true," +
-            "        \"isDraft\": true," +
-            "        \"isForwarded\": true," +
-            "        \"mailboxIds\": [\"" + getOutboxId(cedricAccessToken) + 
"\"]" +
-            "      }}" +
-            "    }," +
-            "    \"#0\"" +
-            "  ]" +
-            "]";
+        cedricSendAnEmailToAlice();
 
-        with()
-            .header("Authorization", cedricAccessToken.asString())
-            .body(requestBody)
-        .post("/jmap");
-
-        AccessToken bobAccessToken = authenticateJamesUser(baseUri(jmapPort), 
BOB, BOB_PASSWORD);
-        calmlyAwait
-            .pollDelay(Duration.ofMillis(500))
-            .atMost(30, TimeUnit.SECONDS).until(() -> 
isAnyMessageFoundInRecipientsMailboxes(bobAccessToken));
-        given()
-            .header("Authorization", bobAccessToken.asString())
-            .body("[[\"getMessageList\", {}, \"#0\"]]")
-        .when()
-            .post("/jmap")
-        .then()
-            .log().ifValidationFails()
-            .statusCode(200)
-            .body(NAME, equalTo("messageList"))
-            .body(ARGUMENTS + ".messageIds", hasSize(1));
+        UserCredential bobCredential = getUserCredential(BOB, BOB_PASSWORD);
+        WAIT_THIRTY_SECONDS.untilAsserted(() -> 
assertThat(listMessageIdsForAccount(bobCredential))
+            .hasSize(1));
     }
 
     @Test
@@ -290,96 +160,78 @@ public abstract class ForwardIntegrationTest {
         webAdminApi.put(String.format("/address/forwards/%s/targets/%s", 
ALICE.asString(), BOB.asString()));
         webAdminApi.put(String.format("/address/forwards/%s/targets/%s", 
BOB.asString(), CEDRIC.asString()));
 
-        AccessToken cedricAccessToken = 
authenticateJamesUser(baseUri(jmapPort), CEDRIC, CEDRIC_PASSWORD);
-        AccessToken aliceAccessToken = 
authenticateJamesUser(baseUri(jmapPort), ALICE, ALICE_PASSWORD);
-        String messageCreationId = "creationId1337";
-        String requestBody = "[" +
-            "  [" +
-            "    \"setMessages\"," +
-            "    {" +
-            "      \"create\": { \"" + messageCreationId  + "\" : {" +
-            "        \"from\": { \"name\": \"Me\", \"email\": \"" + 
CEDRIC.asString() + "\"}," +
-            "        \"to\": [{ \"name\": \"Alice\", \"email\": \"" + 
ALICE.asString() + "\"}]," +
-            "        \"subject\": \"subject\"," +
-            "        \"isUnread\": true," +
-            "        \"isFlagged\": true," +
-            "        \"isAnswered\": true," +
-            "        \"isDraft\": true," +
-            "        \"isForwarded\": true," +
-            "        \"mailboxIds\": [\"" + getOutboxId(cedricAccessToken) + 
"\"]" +
-            "      }}" +
-            "    }," +
-            "    \"#0\"" +
-            "  ]" +
-            "]";
+        cedricSendAnEmailToAlice();
 
-        with()
-            .header("Authorization", cedricAccessToken.asString())
-            .body(requestBody)
-        .post("/jmap");
-
-        calmlyAwait
-            .pollDelay(Duration.ofMillis(500))
-            .atMost(30, TimeUnit.SECONDS).until(() -> 
isAnyMessageFoundInRecipientsMailboxes(aliceAccessToken));
-        given()
-            .header("Authorization", aliceAccessToken.asString())
-            .body("[[\"getMessageList\", {}, \"#0\"]]")
-        .when()
-            .post("/jmap")
-        .then()
-            .log().ifValidationFails()
-            .statusCode(200)
-            .body(NAME, equalTo("messageList"))
-            .body(ARGUMENTS + ".messageIds", hasSize(1));
+        UserCredential aliceCredential = getUserCredential(ALICE, 
ALICE_PASSWORD);
+        WAIT_THIRTY_SECONDS.untilAsserted(() -> 
assertThat(listMessageIdsForAccount(aliceCredential))
+            .hasSize(1));
     }
 
     @Test
     void baseRecipientShouldNotReceiveEmailOnDefaultForward() {
         webAdminApi.put(String.format("/address/forwards/%s/targets/%s", 
ALICE.asString(), BOB.asString()));
 
-        AccessToken cedricAccessToken = 
authenticateJamesUser(baseUri(jmapPort), CEDRIC, CEDRIC_PASSWORD);
-        AccessToken aliceAccessToken = 
authenticateJamesUser(baseUri(jmapPort), ALICE, ALICE_PASSWORD);
-        String messageCreationId = "creationId1337";
-        String requestBody = "[" +
-            "  [" +
-            "    \"setMessages\"," +
-            "    {" +
-            "      \"create\": { \"" + messageCreationId  + "\" : {" +
-            "        \"from\": { \"name\": \"Me\", \"email\": \"" + 
CEDRIC.asString() + "\"}," +
-            "        \"to\": [{ \"name\": \"Alice\", \"email\": \"" + 
ALICE.asString() + "\"}]," +
-            "        \"subject\": \"subject\"," +
-            "        \"isUnread\": true," +
-            "        \"isFlagged\": true," +
-            "        \"isAnswered\": true," +
-            "        \"isDraft\": true," +
-            "        \"isForwarded\": true," +
-            "        \"mailboxIds\": [\"" + getOutboxId(cedricAccessToken) + 
"\"]" +
-            "      }}" +
-            "    }," +
-            "    \"#0\"" +
-            "  ]" +
-            "]";
+        cedricSendAnEmailToAlice();
+
+        UserCredential bobCredential = getUserCredential(BOB, BOB_PASSWORD);
+        WAIT_THIRTY_SECONDS.untilAsserted(() -> 
assertThat(listMessageIdsForAccount(bobCredential))
+            .hasSize(1));
+
+        UserCredential aliceCredential = getUserCredential(ALICE, 
ALICE_PASSWORD);
+        assertThat(listMessageIdsForAccount(aliceCredential))
+            .hasSize(0);
+    }
+
+    private void cedricSendAnEmailToAlice() {
+        UserCredential cedricCredential = getUserCredential(CEDRIC, 
CEDRIC_PASSWORD);
+        String cedricOutboxId = 
JmapRFCCommonRequests.getOutboxId(cedricCredential);
+        String request =
+            "{" +
+                "    \"using\": [\"urn:ietf:params:jmap:core\", 
\"urn:ietf:params:jmap:mail\", \"urn:ietf:params:jmap:submission\"]," +
+                "    \"methodCalls\": [" +
+                "        [\"Email/set\", {" +
+                "            \"accountId\": \"" + cedricCredential.accountId() 
+ "\"," +
+                "            \"create\": {" +
+                "                \"e1526\": {" +
+                "                    \"mailboxIds\": { \"" + cedricOutboxId + 
"\": true }," +
+                "                    \"subject\": \"subject\"," +
+                "                    \"htmlBody\": [{" +
+                "                        \"partId\": \"a49d\"," +
+                "                        \"type\": \"text/html\"" +
+                "                    }]," +
+                "                    \"bodyValues\": {" +
+                "                        \"a49d\": {" +
+                "                            \"value\": \"Test <b>body</b>, 
HTML version\"" +
+                "                        }" +
+                "                    }," +
+                "                    \"to\": [{\"email\": \"" + 
ALICE.asString() + "\"}]," +
+                "                    \"from\": [{\"email\": \"" + 
CEDRIC.asString() + "\"}]" +
+                "                }" +
+                "            }" +
+                "        }, \"c1\"]," +
+                "        [\"EmailSubmission/set\", {" +
+                "             \"accountId\": \"" + 
cedricCredential.accountId() + "\"," +
+                "             \"create\": {" +
+                "                 \"k1490\": {" +
+                "                     \"emailId\": \"#e1526\"," +
+                "                     \"envelope\": {" +
+                "                         \"mailFrom\": {\"email\": \"" + 
CEDRIC.asString() + "\"}," +
+                "                         \"rcptTo\": [{\"email\": \"" + 
ALICE.asString() + "\"}]" +
+                "                     }" +
+                "                 }" +
+                "             }" +
+                "         }, \"c3\"]" +
+                "    ]" +
+                "}";
 
         with()
-            .header("Authorization", cedricAccessToken.asString())
-            .body(requestBody)
-        .post("/jmap");
-
-        AccessToken bobAccessToken = authenticateJamesUser(baseUri(jmapPort), 
BOB, BOB_PASSWORD);
-        calmlyAwait
-            .pollDelay(Duration.ofMillis(500))
-            .atMost(30, TimeUnit.SECONDS).until(() -> 
isAnyMessageFoundInRecipientsMailboxes(bobAccessToken));
-
-        given()
-            .header("Authorization", aliceAccessToken.asString())
-            .body("[[\"getMessageList\", {}, \"#0\"]]")
-        .when()
+            .auth().basic(cedricCredential.username().asString(), 
cedricCredential.password())
+            .body(request)
             .post("/jmap")
         .then()
-            .log().ifValidationFails()
             .statusCode(200)
-            .body(NAME, equalTo("messageList"))
-            .body(ARGUMENTS + ".messageIds", hasSize(0));
+            .contentType(ContentType.JSON)
+            .body("methodResponses[0][1].created.e1526", 
Matchers.is(notNullValue()));
     }
 
 }
diff --git 
a/server/protocols/webadmin-integration-test/webadmin-integration-test-common/src/main/java/org/apache/james/webadmin/integration/TestFixture.java
 
b/server/protocols/webadmin-integration-test/webadmin-integration-test-common/src/main/java/org/apache/james/webadmin/integration/TestFixture.java
new file mode 100644
index 0000000000..1502974376
--- /dev/null
+++ 
b/server/protocols/webadmin-integration-test/webadmin-integration-test-common/src/main/java/org/apache/james/webadmin/integration/TestFixture.java
@@ -0,0 +1,34 @@
+/****************************************************************
+ * 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;
+
+import static org.apache.james.jmap.JMAPTestingConstants.calmlyAwait;
+
+import java.time.Duration;
+import java.util.concurrent.TimeUnit;
+
+import org.awaitility.core.ConditionFactory;
+
+public interface TestFixture {
+
+    ConditionFactory WAIT_THIRTY_SECONDS = calmlyAwait
+        .pollDelay(Duration.ofMillis(500))
+        .atMost(30, TimeUnit.SECONDS);
+}
diff --git 
a/server/protocols/webadmin-integration-test/webadmin-integration-test-common/src/main/java/org/apache/james/webadmin/integration/vault/DeletedMessageVaultIntegrationTest.java
 
b/server/protocols/webadmin-integration-test/webadmin-integration-test-common/src/main/java/org/apache/james/webadmin/integration/vault/DeletedMessageVaultIntegrationTest.java
index 89695a57d3..4d5d0c5afc 100644
--- 
a/server/protocols/webadmin-integration-test/webadmin-integration-test-common/src/main/java/org/apache/james/webadmin/integration/vault/DeletedMessageVaultIntegrationTest.java
+++ 
b/server/protocols/webadmin-integration-test/webadmin-integration-test-common/src/main/java/org/apache/james/webadmin/integration/vault/DeletedMessageVaultIntegrationTest.java
@@ -22,19 +22,21 @@ package org.apache.james.webadmin.integration.vault;
 import static io.restassured.RestAssured.given;
 import static io.restassured.RestAssured.with;
 import static io.restassured.config.ParamConfig.UpdateStrategy.REPLACE;
-import static 
org.apache.james.jmap.HttpJmapAuthentication.authenticateJamesUser;
-import static org.apache.james.jmap.JMAPTestingConstants.ARGUMENTS;
+import static io.restassured.http.ContentType.JSON;
 import static org.apache.james.jmap.JMAPTestingConstants.DOMAIN;
 import static org.apache.james.jmap.JMAPTestingConstants.LOCALHOST_IP;
 import static org.apache.james.jmap.JMAPTestingConstants.calmlyAwait;
 import static 
org.apache.james.jmap.JMAPTestingConstants.jmapRequestSpecBuilder;
-import static org.apache.james.jmap.JmapCommonRequests.deleteMessages;
-import static org.apache.james.jmap.JmapCommonRequests.getAllMailboxesIds;
-import static org.apache.james.jmap.JmapCommonRequests.getLatestMessageId;
-import static org.apache.james.jmap.JmapCommonRequests.getOutboxId;
-import static 
org.apache.james.jmap.JmapCommonRequests.listMessageIdsForAccount;
-import static org.apache.james.jmap.JmapCommonRequests.listMessageIdsInMailbox;
-import static org.apache.james.jmap.LocalHostURIBuilder.baseUri;
+import static 
org.apache.james.jmap.JmapRFCCommonRequests.ACCEPT_JMAP_RFC_HEADER;
+import static org.apache.james.jmap.JmapRFCCommonRequests.UserCredential;
+import static org.apache.james.jmap.JmapRFCCommonRequests.deleteMessages;
+import static org.apache.james.jmap.JmapRFCCommonRequests.getAllMailboxesIds;
+import static org.apache.james.jmap.JmapRFCCommonRequests.getLatestMessageId;
+import static org.apache.james.jmap.JmapRFCCommonRequests.getMessageContent;
+import static org.apache.james.jmap.JmapRFCCommonRequests.getOutboxId;
+import static org.apache.james.jmap.JmapRFCCommonRequests.getUserCredential;
+import static 
org.apache.james.jmap.JmapRFCCommonRequests.listMessageIdsForAccount;
+import static 
org.apache.james.jmap.JmapRFCCommonRequests.listMessageIdsInMailbox;
 import static org.apache.james.mailbox.backup.ZipAssert.EntryChecks.hasName;
 import static org.apache.james.mailbox.backup.ZipAssert.assertThatZip;
 import static 
org.apache.james.webadmin.integration.vault.DeletedMessagesVaultRequests.deleteFromVault;
@@ -44,18 +46,17 @@ import static 
org.apache.james.webadmin.integration.vault.DeletedMessagesVaultRe
 import static org.assertj.core.api.Assertions.assertThat;
 import static org.awaitility.Durations.FIVE_SECONDS;
 import static org.awaitility.Durations.TWO_MINUTES;
-import static org.hamcrest.Matchers.hasItem;
+import static org.hamcrest.Matchers.notNullValue;
 
 import java.io.FileInputStream;
 import java.io.IOException;
 import java.time.Clock;
 import java.time.ZonedDateTime;
 import java.util.List;
+import java.util.Map;
 
 import org.apache.james.GuiceJamesServer;
 import org.apache.james.GuiceModuleTestExtension;
-import org.apache.james.core.Username;
-import org.apache.james.jmap.AccessToken;
 import org.apache.james.jmap.draft.JmapGuiceProbe;
 import org.apache.james.junit.categories.BasicFeature;
 import org.apache.james.mailbox.DefaultMailboxes;
@@ -73,6 +74,7 @@ import org.apache.james.utils.UpdatableTickingClock;
 import org.apache.james.utils.WebAdminGuiceProbe;
 import org.apache.james.webadmin.WebAdminUtils;
 import org.awaitility.core.ConditionFactory;
+import org.hamcrest.Matchers;
 import org.junit.jupiter.api.AfterEach;
 import org.junit.jupiter.api.BeforeEach;
 import org.junit.jupiter.api.Tag;
@@ -81,7 +83,6 @@ import org.junit.jupiter.api.extension.ExtensionContext;
 import org.junit.jupiter.api.extension.ParameterContext;
 import org.junit.jupiter.api.extension.ParameterResolutionException;
 
-import com.google.common.base.Strings;
 import com.google.common.collect.ImmutableList;
 import com.google.inject.Module;
 
@@ -142,12 +143,13 @@ public abstract class DeletedMessageVaultIntegrationTest {
         .query(MATCH_ALL_QUERY);
 
     private TestIMAPClient testIMAPClient;
-    private AccessToken homerAccessToken;
-    private AccessToken bartAccessToken;
-    private AccessToken jackAccessToken;
     private RequestSpecification webAdminApi;
     private MailboxId otherMailboxId;
 
+    private UserCredential homerCredential;
+    private UserCredential bartCredential;
+    private UserCredential jackCredential;
+
     @BeforeEach
     void setup(GuiceJamesServer jmapServer) throws Throwable {
         MailboxProbe mailboxProbe = 
jmapServer.getProbe(MailboxProbeImpl.class);
@@ -156,6 +158,7 @@ public abstract class DeletedMessageVaultIntegrationTest {
         Port jmapPort = 
jmapServer.getProbe(JmapGuiceProbe.class).getJmapPort();
         RestAssured.requestSpecification = jmapRequestSpecBuilder
             .setPort(jmapPort.getValue())
+            .addHeader(ACCEPT_JMAP_RFC_HEADER.getName(), 
ACCEPT_JMAP_RFC_HEADER.getValue())
             .build();
         RestAssured.defaultParser = Parser.JSON;
 
@@ -165,9 +168,10 @@ public abstract class DeletedMessageVaultIntegrationTest {
         dataProbe.addUser(JACK, PASSWORD);
         mailboxProbe.createMailbox("#private", HOMER, DefaultMailboxes.INBOX);
         otherMailboxId = mailboxProbe.createMailbox("#private", HOMER, 
MAILBOX_NAME);
-        homerAccessToken = authenticateJamesUser(baseUri(jmapPort), 
Username.of(HOMER), PASSWORD);
-        bartAccessToken = authenticateJamesUser(baseUri(jmapPort), 
Username.of(BART), BOB_PASSWORD);
-        jackAccessToken = authenticateJamesUser(baseUri(jmapPort), 
Username.of(JACK), PASSWORD);
+
+        homerCredential = getUserCredential(HOMER, PASSWORD);
+        bartCredential = getUserCredential(BART, BOB_PASSWORD);
+        jackCredential = getUserCredential(JACK, PASSWORD);
 
         testIMAPClient = new TestIMAPClient();
 
@@ -188,31 +192,24 @@ public abstract class DeletedMessageVaultIntegrationTest {
     @Test
     void vaultEndpointShouldRestoreJmapDeletedEmail() {
         bartSendMessageToHomer();
-        WAIT_TWO_MINUTES.untilAsserted(() -> 
assertThat(listMessageIdsForAccount(homerAccessToken)).hasSize(1));
+        WAIT_TWO_MINUTES.untilAsserted(() -> 
assertThat(listMessageIdsForAccount(homerCredential)).hasSize(1));
 
-        homerDeletesMessages(listMessageIdsForAccount(homerAccessToken));
-        WAIT_TWO_MINUTES.untilAsserted(() -> 
assertThat(listMessageIdsForAccount(homerAccessToken)).hasSize(0));
+        homerDeletesMessages(listMessageIdsForAccount(homerCredential));
+        WAIT_TWO_MINUTES.untilAsserted(() -> 
assertThat(listMessageIdsForAccount(homerCredential)).hasSize(0));
 
         restoreAllMessagesOfHomer();
-        WAIT_TWO_MINUTES.untilAsserted(() -> 
assertThat(listMessageIdsForAccount(homerAccessToken)).hasSize(1));
+        WAIT_TWO_MINUTES.untilAsserted(() -> 
assertThat(listMessageIdsForAccount(homerCredential)).hasSize(1));
 
-        String messageId = listMessageIdsForAccount(homerAccessToken).get(0);
-        given()
-            .header("Authorization", homerAccessToken.asString())
-            .body("[[\"getMessages\", {\"ids\": [\"" + messageId + "\"]}, 
\"#0\"]]")
-        .when()
-            .post("/jmap")
-        .then()
-            .statusCode(200)
-            .log().ifValidationFails()
-            .body(ARGUMENTS + ".list.subject", hasItem(SUBJECT));
+        String messageId = listMessageIdsForAccount(homerCredential).get(0);
+        assertThat(getMessageContent(homerCredential, messageId)
+            
.getString("methodResponses[0][1].list[0].subject")).isEqualTo(SUBJECT);
     }
 
     @Tag(BasicFeature.TAG)
     @Test
     void vaultEndpointShouldRestoreImapDeletedEmail(GuiceJamesServer 
jmapServer) throws Exception {
         bartSendMessageToHomer();
-        WAIT_TWO_MINUTES.untilAsserted(() -> 
assertThat(listMessageIdsForAccount(homerAccessToken)).hasSize(1));
+        WAIT_TWO_MINUTES.untilAsserted(() -> 
assertThat(listMessageIdsForAccount(homerCredential)).hasSize(1));
 
         testIMAPClient.connect(LOCALHOST_IP, 
jmapServer.getProbe(ImapGuiceProbe.class).getImapPort())
             .login(HOMER, PASSWORD)
@@ -220,66 +217,52 @@ public abstract class DeletedMessageVaultIntegrationTest {
             .setFlagsForAllMessagesInMailbox("\\Deleted");
         testIMAPClient.expunge();
 
-        WAIT_TWO_MINUTES.untilAsserted(() -> 
assertThat(listMessageIdsForAccount(homerAccessToken)).hasSize(0));
+        WAIT_TWO_MINUTES.untilAsserted(() -> 
assertThat(listMessageIdsForAccount(homerCredential)).hasSize(0));
 
         restoreAllMessagesOfHomer();
-        WAIT_TWO_MINUTES.untilAsserted(() -> 
assertThat(listMessageIdsForAccount(homerAccessToken)).hasSize(1));
+        WAIT_TWO_MINUTES.untilAsserted(() -> 
assertThat(listMessageIdsForAccount(homerCredential)).hasSize(1));
 
-        String messageId = listMessageIdsForAccount(homerAccessToken).get(0);
-        given()
-            .header("Authorization", homerAccessToken.asString())
-            .body("[[\"getMessages\", {\"ids\": [\"" + messageId + "\"]}, 
\"#0\"]]")
-        .when()
-            .post("/jmap")
-        .then()
-            .statusCode(200)
-            .log().ifValidationFails()
-            .body(ARGUMENTS + ".list.subject", hasItem(SUBJECT));
+        String messageId = listMessageIdsForAccount(homerCredential).get(0);
+        assertThat(getMessageContent(homerCredential, messageId)
+            
.getString("methodResponses[0][1].list[0].subject")).isEqualTo(SUBJECT);
     }
 
     @Tag(BasicFeature.TAG)
     @Test
     void vaultEndpointShouldRestoreImapDeletedMailbox(GuiceJamesServer 
jmapServer) throws Exception {
         bartSendMessageToHomer();
-        WAIT_TWO_MINUTES.untilAsserted(() -> 
assertThat(listMessageIdsForAccount(homerAccessToken)).hasSize(1));
+        WAIT_TWO_MINUTES.untilAsserted(() -> 
assertThat(listMessageIdsForAccount(homerCredential)).hasSize(1));
 
         testIMAPClient.connect(LOCALHOST_IP, 
jmapServer.getProbe(ImapGuiceProbe.class).getImapPort())
             .login(HOMER, PASSWORD)
             .select(TestIMAPClient.INBOX);
 
         testIMAPClient.moveFirstMessage(MAILBOX_NAME);
-        WAIT_TWO_MINUTES.untilAsserted(() -> 
assertThat(listMessageIdsInMailbox(homerAccessToken, 
otherMailboxId.serialize())).hasSize(1));
+        WAIT_TWO_MINUTES.untilAsserted(() -> 
assertThat(listMessageIdsInMailbox(homerCredential, 
otherMailboxId.serialize())).hasSize(1));
 
         testIMAPClient.delete(MAILBOX_NAME);
 
-        WAIT_TWO_MINUTES.untilAsserted(() -> 
assertThat(listMessageIdsForAccount(homerAccessToken)).hasSize(0));
+        WAIT_TWO_MINUTES.untilAsserted(() -> 
assertThat(listMessageIdsForAccount(homerCredential)).hasSize(0));
         Thread.sleep(1000); // Wait for messages to be moved to the vault
 
         restoreAllMessagesOfHomer();
-        WAIT_TWO_MINUTES.untilAsserted(() -> 
assertThat(listMessageIdsForAccount(homerAccessToken)).hasSize(1));
+        WAIT_TWO_MINUTES.untilAsserted(() -> 
assertThat(listMessageIdsForAccount(homerCredential)).hasSize(1));
 
-        String messageId = listMessageIdsForAccount(homerAccessToken).get(0);
-        given()
-            .header("Authorization", homerAccessToken.asString())
-            .body("[[\"getMessages\", {\"ids\": [\"" + messageId + "\"]}, 
\"#0\"]]")
-        .when()
-            .post("/jmap")
-        .then()
-            .statusCode(200)
-            .log().ifValidationFails()
-            .body(ARGUMENTS + ".list.subject", hasItem(SUBJECT));
+        String messageId = listMessageIdsForAccount(homerCredential).get(0);
+        assertThat(getMessageContent(homerCredential, messageId)
+            
.getString("methodResponses[0][1].list[0].subject")).isEqualTo(SUBJECT);
     }
 
     @Test
     void restoreShouldCreateRestoreMessagesMailbox() {
         bartSendMessageToHomer();
-        WAIT_TWO_MINUTES.untilAsserted(() -> 
assertThat(listMessageIdsForAccount(homerAccessToken)).hasSize(1));
+        WAIT_TWO_MINUTES.untilAsserted(() -> 
assertThat(listMessageIdsForAccount(homerCredential)).hasSize(1));
 
-        homerDeletesMessages(listMessageIdsForAccount(homerAccessToken));
-        WAIT_TWO_MINUTES.untilAsserted(() -> 
assertThat(listMessageIdsForAccount(homerAccessToken)).hasSize(0));
+        homerDeletesMessages(listMessageIdsForAccount(homerCredential));
+        WAIT_TWO_MINUTES.untilAsserted(() -> 
assertThat(listMessageIdsForAccount(homerCredential)).hasSize(0));
 
         restoreAllMessagesOfHomer();
-        WAIT_TWO_MINUTES.untilAsserted(() -> 
assertThat(listMessageIdsForAccount(homerAccessToken)).hasSize(1));
+        WAIT_TWO_MINUTES.untilAsserted(() -> 
assertThat(listMessageIdsForAccount(homerCredential)).hasSize(1));
 
         assertThat(homerHasMailboxWithRole(Role.RESTORED_MESSAGES)).isTrue();
     }
@@ -288,11 +271,11 @@ public abstract class DeletedMessageVaultIntegrationTest {
     void postShouldRestoreMatchingMessages() {
         bartSendMessageToHomerWithSubject("aaaaa");
         bartSendMessageToHomerWithSubject("bbbbb");
-        WAIT_TWO_MINUTES.untilAsserted(() -> 
assertThat(listMessageIdsForAccount(homerAccessToken)).hasSize(2));
+        WAIT_TWO_MINUTES.untilAsserted(() -> 
assertThat(listMessageIdsForAccount(homerCredential)).hasSize(2));
 
-        homerDeletesMessages(listMessageIdsForAccount(homerAccessToken));
+        homerDeletesMessages(listMessageIdsForAccount(homerCredential));
 
-        WAIT_TWO_MINUTES.untilAsserted(() -> 
assertThat(listMessageIdsForAccount(homerAccessToken)).hasSize(0));
+        WAIT_TWO_MINUTES.untilAsserted(() -> 
assertThat(listMessageIdsForAccount(homerCredential)).hasSize(0));
 
         String query = "{" +
             "  \"combinator\": \"and\"," +
@@ -306,29 +289,22 @@ public abstract class DeletedMessageVaultIntegrationTest {
             "}";
         restoreMessagesForUserWithQuery(webAdminApi, HOMER, query);
 
-        WAIT_TWO_MINUTES.untilAsserted(() -> 
assertThat(listMessageIdsForAccount(homerAccessToken)).hasSize(1));
+        WAIT_TWO_MINUTES.untilAsserted(() -> 
assertThat(listMessageIdsForAccount(homerCredential)).hasSize(1));
 
-        String messageId = listMessageIdsForAccount(homerAccessToken).get(0);
-        given()
-            .header("Authorization", homerAccessToken.asString())
-            .body("[[\"getMessages\", {\"ids\": [\"" + messageId + "\"]}, 
\"#0\"]]")
-        .when()
-            .post("/jmap")
-            .then()
-            .statusCode(200)
-            .log().ifValidationFails()
-            .body(ARGUMENTS + ".list.subject", hasItem("aaaaa"));
+        String messageId = listMessageIdsForAccount(homerCredential).get(0);
+        assertThat(getMessageContent(homerCredential, messageId)
+            
.getString("methodResponses[0][1].list[0].subject")).isEqualTo("aaaaa");
     }
 
     @Test
     void postShouldNotRestoreWhenNoMatchingMessages() throws Exception {
         bartSendMessageToHomerWithSubject("aaaaa");
         bartSendMessageToHomerWithSubject("bbbbb");
-        WAIT_TWO_MINUTES.untilAsserted(() -> 
assertThat(listMessageIdsForAccount(homerAccessToken)).hasSize(2));
+        WAIT_TWO_MINUTES.untilAsserted(() -> 
assertThat(listMessageIdsForAccount(homerCredential)).hasSize(2));
 
-        homerDeletesMessages(listMessageIdsForAccount(homerAccessToken));
+        homerDeletesMessages(listMessageIdsForAccount(homerCredential));
 
-        WAIT_TWO_MINUTES.untilAsserted(() -> 
assertThat(listMessageIdsForAccount(homerAccessToken)).hasSize(0));
+        WAIT_TWO_MINUTES.untilAsserted(() -> 
assertThat(listMessageIdsForAccount(homerCredential)).hasSize(0));
 
         String query = "{" +
             "  \"combinator\": \"and\"," +
@@ -346,7 +322,7 @@ public abstract class DeletedMessageVaultIntegrationTest {
         Thread.sleep(FIVE_SECONDS.toMillis());
 
         // No additional had been restored for Bart as the vault is empty
-        assertThat(listMessageIdsForAccount(homerAccessToken).size())
+        assertThat(listMessageIdsForAccount(homerCredential).size())
             .isEqualTo(0);
     }
 
@@ -354,11 +330,11 @@ public abstract class DeletedMessageVaultIntegrationTest {
     void postShouldRestoreMatchingMessagesWhenQueryLimit() {
         bartSendMessageToHomerWithSubject("aaaa");
         bartSendMessageToHomerWithSubject("aaaa");
-        WAIT_TWO_MINUTES.untilAsserted(() -> 
assertThat(listMessageIdsForAccount(homerAccessToken)).hasSize(2));
+        WAIT_TWO_MINUTES.untilAsserted(() -> 
assertThat(listMessageIdsForAccount(homerCredential)).hasSize(2));
 
-        homerDeletesMessages(listMessageIdsForAccount(homerAccessToken));
+        homerDeletesMessages(listMessageIdsForAccount(homerCredential));
 
-        WAIT_TWO_MINUTES.untilAsserted(() -> 
assertThat(listMessageIdsForAccount(homerAccessToken)).hasSize(0));
+        WAIT_TWO_MINUTES.untilAsserted(() -> 
assertThat(listMessageIdsForAccount(homerCredential)).hasSize(0));
 
         String query = "{" +
             "  \"combinator\": \"and\"," +
@@ -373,13 +349,13 @@ public abstract class DeletedMessageVaultIntegrationTest {
             "}";
         restoreMessagesForUserWithQuery(webAdminApi, HOMER, query);
 
-        WAIT_TWO_MINUTES.untilAsserted(() -> 
assertThat(listMessageIdsForAccount(homerAccessToken)).hasSize(1));
+        WAIT_TWO_MINUTES.untilAsserted(() -> 
assertThat(listMessageIdsForAccount(homerCredential)).hasSize(1));
     }
 
     @Test
     void imapMovedMessageShouldNotEndUpInTheVault(GuiceJamesServer jmapServer) 
throws Exception {
         bartSendMessageToHomer();
-        WAIT_TWO_MINUTES.untilAsserted(() -> 
assertThat(listMessageIdsForAccount(homerAccessToken)).hasSize(1));
+        WAIT_TWO_MINUTES.untilAsserted(() -> 
assertThat(listMessageIdsForAccount(homerCredential)).hasSize(1));
 
         testIMAPClient.connect(LOCALHOST_IP, 
jmapServer.getProbe(ImapGuiceProbe.class).getImapPort())
             .login(HOMER, PASSWORD)
@@ -389,137 +365,131 @@ public abstract class 
DeletedMessageVaultIntegrationTest {
 
         //Moved messages should not be moved to the vault
         restoreAllMessagesOfHomer();
-        WAIT_TWO_MINUTES.untilAsserted(() -> 
assertThat(listMessageIdsForAccount(homerAccessToken)).hasSize(1));
+        WAIT_TWO_MINUTES.untilAsserted(() -> 
assertThat(listMessageIdsForAccount(homerCredential)).hasSize(1));
 
 
         // No messages restored for bart
-        
assertThat(listMessageIdsForAccount(bartAccessToken).size()).isEqualTo(1);
+        
assertThat(listMessageIdsForAccount(homerCredential).size()).isEqualTo(1);
     }
 
     @Test
     void jmapMovedMessageShouldNotEndUpInTheVault() {
         bartSendMessageToHomer();
-        WAIT_TWO_MINUTES.untilAsserted(() -> 
assertThat(listMessageIdsForAccount(homerAccessToken)).hasSize(1));
-        String messageId = listMessageIdsForAccount(homerAccessToken).get(0);
+        WAIT_TWO_MINUTES.untilAsserted(() -> 
assertThat(listMessageIdsForAccount(homerCredential)).hasSize(1));
+        String messageId = listMessageIdsForAccount(homerCredential).get(0);
 
         homerMovesTheMailInAnotherMailbox(messageId);
 
         //Moved messages should not be moved to the vault
         restoreAllMessagesOfHomer();
-        WAIT_TWO_MINUTES.untilAsserted(() -> 
assertThat(listMessageIdsForAccount(homerAccessToken)).hasSize(1));
+        WAIT_TWO_MINUTES.untilAsserted(() -> 
assertThat(listMessageIdsForAccount(homerCredential)).hasSize(1));
 
 
         // No messages restored for bart
-        
assertThat(listMessageIdsForAccount(bartAccessToken).size()).isEqualTo(1);
+        
assertThat(listMessageIdsForAccount(homerCredential).size()).isEqualTo(1);
     }
 
     @Test
     void restoreShouldNotImpactOtherUsers() {
         bartSendMessageToHomer();
-        WAIT_TWO_MINUTES.untilAsserted(() -> 
assertThat(listMessageIdsForAccount(homerAccessToken)).hasSize(1));
+        WAIT_TWO_MINUTES.untilAsserted(() -> 
assertThat(listMessageIdsForAccount(homerCredential)).hasSize(1));
 
-        homerDeletesMessages(listMessageIdsForAccount(homerAccessToken));
-        WAIT_TWO_MINUTES.untilAsserted(() -> 
assertThat(listMessageIdsForAccount(homerAccessToken)).hasSize(0));
+        homerDeletesMessages(listMessageIdsForAccount(homerCredential));
+        WAIT_TWO_MINUTES.untilAsserted(() -> 
assertThat(listMessageIdsForAccount(homerCredential)).hasSize(0));
 
-        bartDeletesMessages(listMessageIdsForAccount(bartAccessToken));
-        WAIT_TWO_MINUTES.untilAsserted(() -> 
assertThat(listMessageIdsForAccount(bartAccessToken)).hasSize(0));
+        bartDeletesMessages(listMessageIdsForAccount(bartCredential));
+        WAIT_TWO_MINUTES.untilAsserted(() -> 
assertThat(listMessageIdsForAccount(bartCredential)).hasSize(0));
 
         restoreAllMessagesOfHomer();
-        WAIT_TWO_MINUTES.untilAsserted(() -> 
assertThat(listMessageIdsForAccount(homerAccessToken)).hasSize(1));
+        WAIT_TWO_MINUTES.untilAsserted(() -> 
assertThat(listMessageIdsForAccount(homerCredential)).hasSize(1));
 
         // No messages restored for bart
-        
assertThat(listMessageIdsForAccount(bartAccessToken).size()).isEqualTo(0);
+        
assertThat(listMessageIdsForAccount(bartCredential).size()).isEqualTo(0);
     }
 
     @Test
     void restoredMessagesShouldNotBeRemovedFromTheVault() {
         bartSendMessageToHomer();
-        WAIT_TWO_MINUTES.untilAsserted(() -> 
assertThat(listMessageIdsForAccount(homerAccessToken)).hasSize(1));
+        WAIT_TWO_MINUTES.untilAsserted(() -> 
assertThat(listMessageIdsForAccount(homerCredential)).hasSize(1));
 
-        homerDeletesMessages(listMessageIdsForAccount(homerAccessToken));
-        WAIT_TWO_MINUTES.untilAsserted(() -> 
assertThat(listMessageIdsForAccount(homerAccessToken)).hasSize(0));
+        homerDeletesMessages(listMessageIdsForAccount(homerCredential));
+        WAIT_TWO_MINUTES.untilAsserted(() -> 
assertThat(listMessageIdsForAccount(homerCredential)).hasSize(0));
 
         restoreAllMessagesOfHomer();
-        WAIT_TWO_MINUTES.untilAsserted(() -> 
assertThat(listMessageIdsForAccount(homerAccessToken)).hasSize(1));
+        WAIT_TWO_MINUTES.untilAsserted(() -> 
assertThat(listMessageIdsForAccount(homerCredential)).hasSize(1));
 
         restoreAllMessagesOfHomer();
-        WAIT_TWO_MINUTES.untilAsserted(() -> 
assertThat(listMessageIdsForAccount(homerAccessToken)).hasSize(2));
+        WAIT_TWO_MINUTES.untilAsserted(() -> 
assertThat(listMessageIdsForAccount(homerCredential)).hasSize(2));
     }
 
     @Test
     void vaultEndpointShouldNotRestoreItemsWhenTheVaultIsEmpty() {
         bartSendMessageToHomer();
-        WAIT_TWO_MINUTES.untilAsserted(() -> 
assertThat(listMessageIdsForAccount(homerAccessToken)).hasSize(1));
+        WAIT_TWO_MINUTES.untilAsserted(() -> 
assertThat(listMessageIdsForAccount(homerCredential)).hasSize(1));
 
         restoreAllMessagesOfHomer();
         awaitSearchUpToDate();
 
         // No additional had been restored as the vault is empty
-        assertThat(listMessageIdsForAccount(homerAccessToken).size())
+        assertThat(listMessageIdsForAccount(homerCredential).size())
             .isEqualTo(1);
     }
 
     @Test
     void vaultEndpointShouldNotRestoreMessageForSharee() {
         bartSendMessageToHomer();
-        WAIT_TWO_MINUTES.untilAsserted(() -> 
assertThat(listMessageIdsForAccount(homerAccessToken)).hasSize(1));
-        WAIT_TWO_MINUTES.untilAsserted(() -> 
assertThat(listMessageIdsForAccount(bartAccessToken)).hasSize(1));
+        WAIT_TWO_MINUTES.untilAsserted(() -> 
assertThat(listMessageIdsForAccount(homerCredential)).hasSize(1));
+        WAIT_TWO_MINUTES.untilAsserted(() -> 
assertThat(listMessageIdsForAccount(bartCredential)).hasSize(1));
 
-        String messageId = listMessageIdsForAccount(homerAccessToken).get(0);
+        String messageId = listMessageIdsForAccount(homerCredential).get(0);
         homerMovesTheMailInAnotherMailbox(messageId);
 
         homerSharesHisMailboxWithBart();
 
         bartDeletesMessages(ImmutableList.of(messageId));
-        WAIT_TWO_MINUTES.untilAsserted(() -> 
assertThat(listMessageIdsForAccount(homerAccessToken)).hasSize(0));
+        WAIT_TWO_MINUTES.untilAsserted(() -> 
assertThat(listMessageIdsForAccount(homerCredential)).hasSize(0));
 
         restoreMessagesFor(BART);
         awaitSearchUpToDate();
 
         // No additional had been restored for Bart as the vault is empty
-        assertThat(listMessageIdsForAccount(bartAccessToken).size())
+        assertThat(listMessageIdsForAccount(bartCredential).size())
             .isEqualTo(1);
     }
 
     @Test
     void vaultEndpointShouldRestoreMessageForSharer() {
         bartSendMessageToHomer();
-        WAIT_TWO_MINUTES.untilAsserted(() -> 
assertThat(listMessageIdsForAccount(homerAccessToken)).hasSize(1));
+        WAIT_TWO_MINUTES.untilAsserted(() -> 
assertThat(listMessageIdsForAccount(homerCredential)).hasSize(1));
 
-        String messageId = listMessageIdsForAccount(homerAccessToken).get(0);
+        String messageId = listMessageIdsForAccount(homerCredential).get(0);
         homerMovesTheMailInAnotherMailbox(messageId);
 
         homerSharesHisMailboxWithBart();
 
         bartDeletesMessages(ImmutableList.of(messageId));
-        WAIT_TWO_MINUTES.untilAsserted(() -> 
assertThat(listMessageIdsForAccount(homerAccessToken)).hasSize(0));
+        WAIT_TWO_MINUTES.untilAsserted(() -> 
assertThat(listMessageIdsForAccount(homerCredential)).hasSize(0));
 
         restoreAllMessagesOfHomer();
-        WAIT_TWO_MINUTES.untilAsserted(() -> 
assertThat(listMessageIdsForAccount(homerAccessToken)).hasSize(1));
+        WAIT_TWO_MINUTES.untilAsserted(() -> 
assertThat(listMessageIdsForAccount(homerCredential)).hasSize(1));
 
-        String newMessageId = 
listMessageIdsForAccount(homerAccessToken).get(0);
-        given()
-            .header("Authorization", homerAccessToken.asString())
-            .body("[[\"getMessages\", {\"ids\": [\"" + newMessageId + "\"]}, 
\"#0\"]]")
-        .when()
-            .post("/jmap")
-            .then()
-            .statusCode(200)
-            .log().ifValidationFails()
-            .body(ARGUMENTS + ".list.subject", hasItem(SUBJECT));
+        String newMessageId = listMessageIdsForAccount(homerCredential).get(0);
+
+        assertThat(getMessageContent(homerCredential, newMessageId)
+            
.getString("methodResponses[0][1].list[0].subject")).isEqualTo(SUBJECT);
     }
 
     @Tag(BasicFeature.TAG)
     @Test
     void 
vaultExportShouldExportZipContainsVaultMessagesToShareeWhenJmapDeleteMessage() 
throws Exception {
         bartSendMessageToHomer();
-        WAIT_TWO_MINUTES.untilAsserted(() -> 
assertThat(listMessageIdsForAccount(homerAccessToken)).hasSize(1));
-        String messageIdOfHomer = 
listMessageIdsForAccount(homerAccessToken).get(0);
+        WAIT_TWO_MINUTES.untilAsserted(() -> 
assertThat(listMessageIdsForAccount(homerCredential)).hasSize(1));
+        String messageIdOfHomer = 
listMessageIdsForAccount(homerCredential).get(0);
 
-        homerDeletesMessages(listMessageIdsForAccount(homerAccessToken));
-        WAIT_TWO_MINUTES.untilAsserted(() -> 
assertThat(listMessageIdsForAccount(homerAccessToken)).hasSize(0));
+        homerDeletesMessages(listMessageIdsForAccount(homerCredential));
+        WAIT_TWO_MINUTES.untilAsserted(() -> 
assertThat(listMessageIdsForAccount(homerCredential)).hasSize(0));
 
-        String fileLocation = 
exportAndGetFileLocationFromLastMail(EXPORT_ALL_HOMER_MESSAGES_TO_BART, 
bartAccessToken);
+        String fileLocation = 
exportAndGetFileLocationFromLastMail(EXPORT_ALL_HOMER_MESSAGES_TO_BART, 
bartCredential);
 
         try (ZipAssert zipAssert = assertThatZip(new 
FileInputStream(fileLocation))) {
             zipAssert.hasEntriesSize(1)
@@ -531,8 +501,8 @@ public abstract class DeletedMessageVaultIntegrationTest {
     @Test
     void 
vaultExportShouldExportZipContainsVaultMessagesToShareeWhenImapDeleteMessage(GuiceJamesServer
 jmapServer) throws Exception {
         bartSendMessageToHomer();
-        WAIT_TWO_MINUTES.untilAsserted(() -> 
assertThat(listMessageIdsForAccount(homerAccessToken)).hasSize(1));
-        String messageIdOfHomer = 
listMessageIdsForAccount(homerAccessToken).get(0);
+        WAIT_TWO_MINUTES.untilAsserted(() -> 
assertThat(listMessageIdsForAccount(homerCredential)).hasSize(1));
+        String messageIdOfHomer = 
listMessageIdsForAccount(homerCredential).get(0);
 
         testIMAPClient.connect(LOCALHOST_IP, 
jmapServer.getProbe(ImapGuiceProbe.class).getImapPort())
             .login(HOMER, PASSWORD)
@@ -540,9 +510,9 @@ public abstract class DeletedMessageVaultIntegrationTest {
             .setFlagsForAllMessagesInMailbox("\\Deleted");
         testIMAPClient.expunge();
 
-        WAIT_TWO_MINUTES.untilAsserted(() -> 
assertThat(listMessageIdsForAccount(homerAccessToken)).hasSize(0));
+        WAIT_TWO_MINUTES.untilAsserted(() -> 
assertThat(listMessageIdsForAccount(homerCredential)).hasSize(0));
 
-        String fileLocation = 
exportAndGetFileLocationFromLastMail(EXPORT_ALL_HOMER_MESSAGES_TO_BART, 
bartAccessToken);
+        String fileLocation = 
exportAndGetFileLocationFromLastMail(EXPORT_ALL_HOMER_MESSAGES_TO_BART, 
bartCredential);
 
         try (ZipAssert zipAssert = assertThatZip(new 
FileInputStream(fileLocation))) {
             zipAssert.hasEntriesSize(1)
@@ -554,8 +524,8 @@ public abstract class DeletedMessageVaultIntegrationTest {
     @Test
     public void 
vaultExportShouldExportZipContainsVaultMessagesToShareeWhenImapDeletedMailbox(GuiceJamesServer
 jmapServer) throws Exception {
         bartSendMessageToHomer();
-        WAIT_TWO_MINUTES.untilAsserted(() -> 
assertThat(listMessageIdsForAccount(homerAccessToken)).hasSize(1));
-        String messageIdOfHomer = 
listMessageIdsForAccount(homerAccessToken).get(0);
+        WAIT_TWO_MINUTES.untilAsserted(() -> 
assertThat(listMessageIdsForAccount(homerCredential)).hasSize(1));
+        String messageIdOfHomer = 
listMessageIdsForAccount(homerCredential).get(0);
 
         testIMAPClient.connect(LOCALHOST_IP, 
jmapServer.getProbe(ImapGuiceProbe.class).getImapPort())
             .login(HOMER, PASSWORD)
@@ -565,9 +535,9 @@ public abstract class DeletedMessageVaultIntegrationTest {
 
         testIMAPClient.delete(MAILBOX_NAME);
 
-        WAIT_TWO_MINUTES.untilAsserted(() -> 
assertThat(listMessageIdsForAccount(homerAccessToken)).hasSize(0));
+        WAIT_TWO_MINUTES.untilAsserted(() -> 
assertThat(listMessageIdsForAccount(homerCredential)).hasSize(0));
 
-        String fileLocation = 
exportAndGetFileLocationFromLastMail(EXPORT_ALL_HOMER_MESSAGES_TO_BART, 
bartAccessToken);
+        String fileLocation = 
exportAndGetFileLocationFromLastMail(EXPORT_ALL_HOMER_MESSAGES_TO_BART, 
bartCredential);
 
         try (ZipAssert zipAssert = assertThatZip(new 
FileInputStream(fileLocation))) {
             zipAssert.hasEntriesSize(1)
@@ -578,24 +548,26 @@ public abstract class DeletedMessageVaultIntegrationTest {
     @Test
     void vaultExportShouldExportZipContainsOnlyMatchedMessages() throws 
Exception {
         bartSendMessageToHomerWithSubject(FIRST_SUBJECT);
-        WAIT_TWO_MINUTES.untilAsserted(() -> 
assertThat(listMessageIdsForAccount(homerAccessToken)).hasSize(1));
-        String firstMessageIdOfHomer = 
listMessageIdsForAccount(homerAccessToken).get(0);
+        WAIT_TWO_MINUTES.untilAsserted(() -> 
assertThat(listMessageIdsForAccount(homerCredential)).hasSize(1));
+        String firstMessageIdOfHomer = 
listMessageIdsForAccount(homerCredential).get(0);
 
         bartSendMessageToHomerWithSubject(SECOND_SUBJECT);
-        WAIT_TWO_MINUTES.untilAsserted(() -> 
assertThat(listMessageIdsForAccount(homerAccessToken)).hasSize(2));
+        WAIT_TWO_MINUTES.untilAsserted(() -> 
assertThat(listMessageIdsForAccount(homerCredential)).hasSize(2));
 
-        homerDeletesMessages(listMessageIdsForAccount(homerAccessToken));
-        WAIT_TWO_MINUTES.untilAsserted(() -> 
assertThat(listMessageIdsForAccount(homerAccessToken)).hasSize(0));
+        homerDeletesMessages(listMessageIdsForAccount(homerCredential));
+        WAIT_TWO_MINUTES.untilAsserted(() -> 
assertThat(listMessageIdsForAccount(homerCredential)).hasSize(0));
 
         ExportRequest exportRequest = ExportRequest
             .userExportFrom(HOMER)
             .exportTo(BART)
-            .query("{" +
-                "  \"fieldName\": \"subject\"," +
-                "  \"operator\": \"equals\"," +
-                "  \"value\": \"" + FIRST_SUBJECT + "\"" +
-                "}");
-        String fileLocation = 
exportAndGetFileLocationFromLastMail(exportRequest, bartAccessToken);
+            .query("""
+                {
+                    "fieldName": "subject",
+                    "operator": "equals",
+                    "value": "%s"
+                }
+                """.formatted(FIRST_SUBJECT));
+        String fileLocation = 
exportAndGetFileLocationFromLastMail(exportRequest, bartCredential);
 
         try (ZipAssert zipAssert = assertThatZip(new 
FileInputStream(fileLocation))) {
             
zipAssert.containsOnlyEntriesMatching(hasName(firstMessageIdOfHomer + ".eml"));
@@ -606,10 +578,10 @@ public abstract class DeletedMessageVaultIntegrationTest {
     void vaultExportShouldExportEmptyZipWhenQueryDoesntMatch() throws 
Exception {
         bartSendMessageToHomerWithSubject(FIRST_SUBJECT);
         bartSendMessageToHomerWithSubject(SECOND_SUBJECT);
-        WAIT_TWO_MINUTES.untilAsserted(() -> 
assertThat(listMessageIdsForAccount(homerAccessToken)).hasSize(2));
+        WAIT_TWO_MINUTES.untilAsserted(() -> 
assertThat(listMessageIdsForAccount(homerCredential)).hasSize(2));
 
-        homerDeletesMessages(listMessageIdsForAccount(homerAccessToken));
-        WAIT_TWO_MINUTES.untilAsserted(() -> 
assertThat(listMessageIdsForAccount(homerAccessToken)).hasSize(0));
+        homerDeletesMessages(listMessageIdsForAccount(homerCredential));
+        WAIT_TWO_MINUTES.untilAsserted(() -> 
assertThat(listMessageIdsForAccount(homerCredential)).hasSize(0));
 
         ExportRequest exportRequest = ExportRequest
             .userExportFrom(HOMER)
@@ -619,7 +591,7 @@ public abstract class DeletedMessageVaultIntegrationTest {
                 "  \"operator\": \"equals\"," +
                 "  \"value\": \"non matching\"" +
                 "}");
-        String fileLocation = 
exportAndGetFileLocationFromLastMail(exportRequest, bartAccessToken);
+        String fileLocation = 
exportAndGetFileLocationFromLastMail(exportRequest, bartCredential);
 
         try (ZipAssert zipAssert = assertThatZip(new 
FileInputStream(fileLocation))) {
             zipAssert.hasNoEntry();
@@ -628,7 +600,7 @@ public abstract class DeletedMessageVaultIntegrationTest {
 
     @Test
     void vaultExportShouldExportEmptyZipWhenVaultIsEmpty() throws Exception {
-        String fileLocation = 
exportAndGetFileLocationFromLastMail(EXPORT_ALL_HOMER_MESSAGES_TO_BART, 
bartAccessToken);
+        String fileLocation = 
exportAndGetFileLocationFromLastMail(EXPORT_ALL_HOMER_MESSAGES_TO_BART, 
bartCredential);
 
         try (ZipAssert zipAssert = assertThatZip(new 
FileInputStream(fileLocation))) {
             zipAssert.hasNoEntry();
@@ -638,13 +610,13 @@ public abstract class DeletedMessageVaultIntegrationTest {
     @Test
     void vaultExportShouldResponseIdempotentSideEffect() throws Exception {
         bartSendMessageToHomer();
-        WAIT_TWO_MINUTES.untilAsserted(() -> 
assertThat(listMessageIdsForAccount(homerAccessToken)).hasSize(1));
+        WAIT_TWO_MINUTES.untilAsserted(() -> 
assertThat(listMessageIdsForAccount(homerCredential)).hasSize(1));
 
-        homerDeletesMessages(listMessageIdsForAccount(homerAccessToken));
-        WAIT_TWO_MINUTES.untilAsserted(() -> 
assertThat(listMessageIdsForAccount(homerAccessToken)).hasSize(0));
+        homerDeletesMessages(listMessageIdsForAccount(homerCredential));
+        WAIT_TWO_MINUTES.untilAsserted(() -> 
assertThat(listMessageIdsForAccount(homerCredential)).hasSize(0));
 
-        String fileLocationFirstExport = 
exportAndGetFileLocationFromLastMail(EXPORT_ALL_HOMER_MESSAGES_TO_BART, 
bartAccessToken);
-        String fileLocationSecondExport = 
exportAndGetFileLocationFromLastMail(EXPORT_ALL_HOMER_MESSAGES_TO_BART, 
bartAccessToken);
+        String fileLocationFirstExport = 
exportAndGetFileLocationFromLastMail(EXPORT_ALL_HOMER_MESSAGES_TO_BART, 
bartCredential);
+        String fileLocationSecondExport = 
exportAndGetFileLocationFromLastMail(EXPORT_ALL_HOMER_MESSAGES_TO_BART, 
bartCredential);
 
         try (ZipAssert zipAssert = assertThatZip(new 
FileInputStream(fileLocationFirstExport))) {
             zipAssert.hasSameContentWith(new 
FileInputStream(fileLocationSecondExport));
@@ -656,15 +628,15 @@ public abstract class DeletedMessageVaultIntegrationTest {
         bartSendMessageToHomer();
         bartSendMessageToHomer();
         bartSendMessageToHomer();
-        WAIT_TWO_MINUTES.untilAsserted(() -> 
assertThat(listMessageIdsForAccount(homerAccessToken)).hasSize(3));
+        WAIT_TWO_MINUTES.untilAsserted(() -> 
assertThat(listMessageIdsForAccount(homerCredential)).hasSize(3));
 
-        homerDeletesMessages(listMessageIdsForAccount(homerAccessToken));
-        WAIT_TWO_MINUTES.untilAsserted(() -> 
assertThat(listMessageIdsForAccount(homerAccessToken)).hasSize(0));
+        homerDeletesMessages(listMessageIdsForAccount(homerCredential));
+        WAIT_TWO_MINUTES.untilAsserted(() -> 
assertThat(listMessageIdsForAccount(homerCredential)).hasSize(0));
 
         clock.setInstant(TWO_MONTH_AFTER_ONE_YEAR_EXPIRATION.toInstant());
         purgeVault(webAdminApi);
 
-        String fileLocation = 
exportAndGetFileLocationFromLastMail(EXPORT_ALL_HOMER_MESSAGES_TO_BART, 
bartAccessToken);
+        String fileLocation = 
exportAndGetFileLocationFromLastMail(EXPORT_ALL_HOMER_MESSAGES_TO_BART, 
bartCredential);
         try (ZipAssert zipAssert = assertThatZip(new 
FileInputStream(fileLocation))) {
             zipAssert.hasNoEntry();
         }
@@ -673,23 +645,23 @@ public abstract class DeletedMessageVaultIntegrationTest {
     @Test
     void 
vaultPurgeShouldMakeExportProduceAZipWhenOneMessageIsNotExpired(UpdatableTickingClock
 clock) throws Exception {
         bartSendMessageToHomer();
-        WAIT_TWO_MINUTES.untilAsserted(() -> 
assertThat(listMessageIdsForAccount(homerAccessToken)).hasSize(1));
+        WAIT_TWO_MINUTES.untilAsserted(() -> 
assertThat(listMessageIdsForAccount(homerCredential)).hasSize(1));
 
-        homerDeletesMessages(listMessageIdsForAccount(homerAccessToken));
-        WAIT_TWO_MINUTES.untilAsserted(() -> 
assertThat(listMessageIdsForAccount(homerAccessToken)).hasSize(0));
+        homerDeletesMessages(listMessageIdsForAccount(homerCredential));
+        WAIT_TWO_MINUTES.untilAsserted(() -> 
assertThat(listMessageIdsForAccount(homerCredential)).hasSize(0));
 
         bartSendMessageToHomer();
-        WAIT_TWO_MINUTES.untilAsserted(() -> 
assertThat(listMessageIdsForAccount(homerAccessToken)).hasSize(1));
+        WAIT_TWO_MINUTES.untilAsserted(() -> 
assertThat(listMessageIdsForAccount(homerCredential)).hasSize(1));
 
-        String messageIdOfNotExpiredMessage = 
listMessageIdsForAccount(homerAccessToken).get(0);
+        String messageIdOfNotExpiredMessage = 
listMessageIdsForAccount(homerCredential).get(0);
 
         clock.setInstant(TWO_MONTH_AFTER_ONE_YEAR_EXPIRATION.toInstant());
-        homerDeletesMessages(listMessageIdsForAccount(homerAccessToken));
-        WAIT_TWO_MINUTES.untilAsserted(() -> 
assertThat(listMessageIdsForAccount(homerAccessToken)).hasSize(0));
+        homerDeletesMessages(listMessageIdsForAccount(homerCredential));
+        WAIT_TWO_MINUTES.untilAsserted(() -> 
assertThat(listMessageIdsForAccount(homerCredential)).hasSize(0));
 
         purgeVault(webAdminApi);
 
-        String fileLocation = 
exportAndGetFileLocationFromLastMail(EXPORT_ALL_HOMER_MESSAGES_TO_BART, 
bartAccessToken);
+        String fileLocation = 
exportAndGetFileLocationFromLastMail(EXPORT_ALL_HOMER_MESSAGES_TO_BART, 
bartCredential);
         try (ZipAssert zipAssert = assertThatZip(new 
FileInputStream(fileLocation))) {
             zipAssert.hasEntriesSize(1)
                 .allSatisfies(entry -> hasName(messageIdOfNotExpiredMessage + 
".eml"));
@@ -701,14 +673,14 @@ public abstract class DeletedMessageVaultIntegrationTest {
         bartSendMessageToHomer();
         bartSendMessageToHomer();
         bartSendMessageToHomer();
-        WAIT_TWO_MINUTES.untilAsserted(() -> 
assertThat(listMessageIdsForAccount(homerAccessToken)).hasSize(3));
+        WAIT_TWO_MINUTES.untilAsserted(() -> 
assertThat(listMessageIdsForAccount(homerCredential)).hasSize(3));
 
-        homerDeletesMessages(listMessageIdsForAccount(homerAccessToken));
-        WAIT_TWO_MINUTES.untilAsserted(() -> 
assertThat(listMessageIdsForAccount(homerAccessToken)).hasSize(0));
+        homerDeletesMessages(listMessageIdsForAccount(homerCredential));
+        WAIT_TWO_MINUTES.untilAsserted(() -> 
assertThat(listMessageIdsForAccount(homerCredential)).hasSize(0));
 
         purgeVault(webAdminApi);
 
-        String fileLocation = 
exportAndGetFileLocationFromLastMail(EXPORT_ALL_HOMER_MESSAGES_TO_BART, 
bartAccessToken);
+        String fileLocation = 
exportAndGetFileLocationFromLastMail(EXPORT_ALL_HOMER_MESSAGES_TO_BART, 
bartCredential);
         try (ZipAssert zipAssert = assertThatZip(new 
FileInputStream(fileLocation))) {
             zipAssert.hasEntriesSize(3);
         }
@@ -717,31 +689,31 @@ public abstract class DeletedMessageVaultIntegrationTest {
     @Test
     void 
vaultPurgeShouldNotAppendMessageToTheUserMailbox(UpdatableTickingClock clock) {
         bartSendMessageToHomer();
-        WAIT_TWO_MINUTES.untilAsserted(() -> 
assertThat(listMessageIdsForAccount(homerAccessToken)).hasSize(1));
+        WAIT_TWO_MINUTES.untilAsserted(() -> 
assertThat(listMessageIdsForAccount(homerCredential)).hasSize(1));
 
-        homerDeletesMessages(listMessageIdsForAccount(homerAccessToken));
-        WAIT_TWO_MINUTES.untilAsserted(() -> 
assertThat(listMessageIdsForAccount(homerAccessToken)).hasSize(0));
+        homerDeletesMessages(listMessageIdsForAccount(homerCredential));
+        WAIT_TWO_MINUTES.untilAsserted(() -> 
assertThat(listMessageIdsForAccount(homerCredential)).hasSize(0));
 
         clock.setInstant(TWO_MONTH_AFTER_ONE_YEAR_EXPIRATION.toInstant());
         purgeVault(webAdminApi);
 
-        assertThat(listMessageIdsForAccount(homerAccessToken))
+        assertThat(listMessageIdsForAccount(homerCredential))
             .hasSize(0);
     }
 
     @Test
     void vaultDeleteShouldDeleteMessageThenExportWithNoEntry() throws 
Exception {
         bartSendMessageToHomer();
-        WAIT_TWO_MINUTES.untilAsserted(() -> 
assertThat(listMessageIdsForAccount(homerAccessToken)).hasSize(1));
+        WAIT_TWO_MINUTES.untilAsserted(() -> 
assertThat(listMessageIdsForAccount(homerCredential)).hasSize(1));
 
-        String messageIdOfHomer = 
listMessageIdsForAccount(homerAccessToken).get(0);
+        String messageIdOfHomer = 
listMessageIdsForAccount(homerCredential).get(0);
 
-        homerDeletesMessages(listMessageIdsForAccount(homerAccessToken));
-        WAIT_TWO_MINUTES.untilAsserted(() -> 
assertThat(listMessageIdsForAccount(homerAccessToken)).hasSize(0));
+        homerDeletesMessages(listMessageIdsForAccount(homerCredential));
+        WAIT_TWO_MINUTES.untilAsserted(() -> 
assertThat(listMessageIdsForAccount(homerCredential)).hasSize(0));
 
         deleteFromVault(webAdminApi, HOMER, messageIdOfHomer);
 
-        String fileLocation = 
exportAndGetFileLocationFromLastMail(EXPORT_ALL_HOMER_MESSAGES_TO_BART, 
bartAccessToken);
+        String fileLocation = 
exportAndGetFileLocationFromLastMail(EXPORT_ALL_HOMER_MESSAGES_TO_BART, 
bartCredential);
         try (ZipAssert zipAssert = assertThatZip(new 
FileInputStream(fileLocation))) {
             zipAssert.hasNoEntry();
         }
@@ -750,13 +722,13 @@ public abstract class DeletedMessageVaultIntegrationTest {
     @Test
     void vaultDeleteShouldNotDeleteEmptyVaultThenExportNoEntry() throws 
Exception {
         bartSendMessageToHomer();
-        WAIT_TWO_MINUTES.untilAsserted(() -> 
assertThat(listMessageIdsForAccount(homerAccessToken)).hasSize(1));
+        WAIT_TWO_MINUTES.untilAsserted(() -> 
assertThat(listMessageIdsForAccount(homerCredential)).hasSize(1));
 
-        String messageIdOfHomer = 
listMessageIdsForAccount(homerAccessToken).get(0);
+        String messageIdOfHomer = 
listMessageIdsForAccount(homerCredential).get(0);
 
         deleteFromVault(webAdminApi, HOMER, messageIdOfHomer);
 
-        String fileLocation = 
exportAndGetFileLocationFromLastMail(EXPORT_ALL_HOMER_MESSAGES_TO_BART, 
bartAccessToken);
+        String fileLocation = 
exportAndGetFileLocationFromLastMail(EXPORT_ALL_HOMER_MESSAGES_TO_BART, 
bartCredential);
         try (ZipAssert zipAssert = assertThatZip(new 
FileInputStream(fileLocation))) {
             zipAssert.hasNoEntry();
         }
@@ -765,18 +737,18 @@ public abstract class DeletedMessageVaultIntegrationTest {
     @Test
     void vaultDeleteShouldNotDeleteNotMatchedMessageInVaultThenExportAnEntry() 
throws Exception {
         bartSendMessageToHomer();
-        WAIT_TWO_MINUTES.untilAsserted(() -> 
assertThat(listMessageIdsForAccount(homerAccessToken)).hasSize(1));
-        String messageIdOfHomer = 
listMessageIdsForAccount(homerAccessToken).get(0);
+        WAIT_TWO_MINUTES.untilAsserted(() -> 
assertThat(listMessageIdsForAccount(homerCredential)).hasSize(1));
+        String messageIdOfHomer = 
listMessageIdsForAccount(homerCredential).get(0);
 
-        WAIT_TWO_MINUTES.untilAsserted(() -> 
assertThat(listMessageIdsForAccount(bartAccessToken)).hasSize(1));
-        String messageIdOfBart = 
listMessageIdsForAccount(bartAccessToken).get(0);
+        WAIT_TWO_MINUTES.untilAsserted(() -> 
assertThat(listMessageIdsForAccount(bartCredential)).hasSize(1));
+        String messageIdOfBart = 
listMessageIdsForAccount(bartCredential).get(0);
 
-        homerDeletesMessages(listMessageIdsForAccount(homerAccessToken));
-        WAIT_TWO_MINUTES.untilAsserted(() -> 
assertThat(listMessageIdsForAccount(homerAccessToken)).hasSize(0));
+        homerDeletesMessages(listMessageIdsForAccount(homerCredential));
+        WAIT_TWO_MINUTES.untilAsserted(() -> 
assertThat(listMessageIdsForAccount(homerCredential)).hasSize(0));
 
         deleteFromVault(webAdminApi, HOMER, messageIdOfBart);
 
-        String fileLocation = 
exportAndGetFileLocationFromLastMail(EXPORT_ALL_HOMER_MESSAGES_TO_BART, 
bartAccessToken);
+        String fileLocation = 
exportAndGetFileLocationFromLastMail(EXPORT_ALL_HOMER_MESSAGES_TO_BART, 
bartCredential);
         try (ZipAssert zipAssert = assertThatZip(new 
FileInputStream(fileLocation))) {
             zipAssert.hasEntriesSize(1)
                 .allSatisfies(entry -> hasName(messageIdOfHomer + ".eml"));
@@ -786,37 +758,37 @@ public abstract class DeletedMessageVaultIntegrationTest {
     @Test
     void vaultDeleteShouldNotAppendMessageToTheUserMailbox() {
         bartSendMessageToHomer();
-        WAIT_TWO_MINUTES.untilAsserted(() -> 
assertThat(listMessageIdsForAccount(homerAccessToken)).hasSize(1));
+        WAIT_TWO_MINUTES.untilAsserted(() -> 
assertThat(listMessageIdsForAccount(homerCredential)).hasSize(1));
 
-        String messageIdOfHomer = 
listMessageIdsForAccount(homerAccessToken).get(0);
+        String messageIdOfHomer = 
listMessageIdsForAccount(homerCredential).get(0);
 
-        homerDeletesMessages(listMessageIdsForAccount(homerAccessToken));
-        WAIT_TWO_MINUTES.untilAsserted(() -> 
assertThat(listMessageIdsForAccount(homerAccessToken)).hasSize(0));
+        homerDeletesMessages(listMessageIdsForAccount(homerCredential));
+        WAIT_TWO_MINUTES.untilAsserted(() -> 
assertThat(listMessageIdsForAccount(homerCredential)).hasSize(0));
 
         deleteFromVault(webAdminApi, HOMER, messageIdOfHomer);
 
-        assertThat(listMessageIdsForAccount(homerAccessToken))
+        assertThat(listMessageIdsForAccount(homerCredential))
             .hasSize(0);
     }
 
     @Test
     void vaultDeleteShouldDeleteAllMessagesHavingSameBlobContent() throws 
Exception {
         bartSendMessageToHomerAndJack();
-        WAIT_TWO_MINUTES.untilAsserted(() -> 
assertThat(listMessageIdsForAccount(homerAccessToken)).hasSize(1));
+        WAIT_TWO_MINUTES.untilAsserted(() -> 
assertThat(listMessageIdsForAccount(homerCredential)).hasSize(1));
 
-        String homerInboxMessageId = 
listMessageIdsForAccount(homerAccessToken).get(0);
+        String homerInboxMessageId = 
listMessageIdsForAccount(homerCredential).get(0);
         homerDeletesMessages(ImmutableList.of(homerInboxMessageId));
-        WAIT_TWO_MINUTES.untilAsserted(() -> 
assertThat(listMessageIdsForAccount(homerAccessToken)).hasSize(0));
+        WAIT_TWO_MINUTES.untilAsserted(() -> 
assertThat(listMessageIdsForAccount(homerCredential)).hasSize(0));
 
         // the message same with homer's one in inbox
-        String jackInboxMessageId = 
listMessageIdsForAccount(jackAccessToken).get(0);
+        String jackInboxMessageId = 
listMessageIdsForAccount(jackCredential).get(0);
         jackDeletesMessages(ImmutableList.of(jackInboxMessageId));
-        WAIT_TWO_MINUTES.untilAsserted(() -> 
assertThat(listMessageIdsForAccount(jackAccessToken)).hasSize(0));
+        WAIT_TWO_MINUTES.untilAsserted(() -> 
assertThat(listMessageIdsForAccount(jackCredential)).hasSize(0));
 
         // delete from homer's vault, expecting the message contains the same 
blob in jack's vault will be deleted
         deleteFromVault(webAdminApi, HOMER, homerInboxMessageId);
 
-        String fileLocationOfBartMessages = 
exportAndGetFileLocationFromLastMail(EXPORT_ALL_JACK_MESSAGES_TO_HOMER, 
homerAccessToken);
+        String fileLocationOfBartMessages = 
exportAndGetFileLocationFromLastMail(EXPORT_ALL_JACK_MESSAGES_TO_HOMER, 
homerCredential);
         try (ZipAssert zipAssert = assertThatZip(new 
FileInputStream(fileLocationOfBartMessages))) {
             zipAssert.hasNoEntry();
         }
@@ -825,64 +797,94 @@ public abstract class DeletedMessageVaultIntegrationTest {
     @Test
     void 
vaultDeleteShouldNotDeleteAllMessagesHavingSameBlobContentWhenMessageNotDeletedWithinTheSameMonth(UpdatableTickingClock
 clock) throws Exception {
         bartSendMessageToHomerAndJack();
-        WAIT_TWO_MINUTES.untilAsserted(() -> 
assertThat(listMessageIdsForAccount(homerAccessToken)).hasSize(1));
+        WAIT_TWO_MINUTES.untilAsserted(() -> 
assertThat(listMessageIdsForAccount(homerCredential)).hasSize(1));
 
-        String homerInboxMessageId = 
listMessageIdsForAccount(homerAccessToken).get(0);
+        String homerInboxMessageId = 
listMessageIdsForAccount(homerCredential).get(0);
         homerDeletesMessages(ImmutableList.of(homerInboxMessageId));
-        WAIT_TWO_MINUTES.untilAsserted(() -> 
assertThat(listMessageIdsForAccount(homerAccessToken)).hasSize(0));
+        WAIT_TWO_MINUTES.untilAsserted(() -> 
assertThat(listMessageIdsForAccount(homerCredential)).hasSize(0));
 
         // one year later, delete jack's message
         clock.setInstant(NOW.plusYears(1).toInstant());
         // the message same with homer's one in inbox
-        String jackInboxMessageId = 
listMessageIdsForAccount(jackAccessToken).get(0);
+        String jackInboxMessageId = 
listMessageIdsForAccount(jackCredential).get(0);
         jackDeletesMessages(ImmutableList.of(jackInboxMessageId));
-        WAIT_TWO_MINUTES.untilAsserted(() -> 
assertThat(listMessageIdsForAccount(jackAccessToken)).hasSize(0));
+        WAIT_TWO_MINUTES.untilAsserted(() -> 
assertThat(listMessageIdsForAccount(jackCredential)).hasSize(0));
 
         // delete from homer's vault, expecting jack's vault still be intact
         deleteFromVault(webAdminApi, HOMER, homerInboxMessageId);
 
-        String fileLocationOfBartMessages = 
exportAndGetFileLocationFromLastMail(EXPORT_ALL_JACK_MESSAGES_TO_HOMER, 
homerAccessToken);
+        String fileLocationOfBartMessages = 
exportAndGetFileLocationFromLastMail(EXPORT_ALL_JACK_MESSAGES_TO_HOMER, 
homerCredential);
         try (ZipAssert zipAssert = assertThatZip(new 
FileInputStream(fileLocationOfBartMessages))) {
             zipAssert.hasEntriesSize(1)
                 .allSatisfies(entry -> hasName(jackInboxMessageId + ".eml"));
         }
     }
 
-    private String exportAndGetFileLocationFromLastMail(ExportRequest 
exportRequest, AccessToken shareeAccessToken) {
-        int currentNumberOfMessages = 
listMessageIdsForAccount(shareeAccessToken).size();
+    private String exportAndGetFileLocationFromLastMail(ExportRequest 
exportRequest, UserCredential shareeCredential) {
+        int currentNumberOfMessages = 
listMessageIdsForAccount(shareeCredential).size();
         exportVaultContent(webAdminApi, exportRequest);
 
-        WAIT_TWO_MINUTES.untilAsserted(() -> 
assertThat(listMessageIdsForAccount(shareeAccessToken)).hasSize(currentNumberOfMessages
 + 1));
-        String exportingMessageId = getLatestMessageId(shareeAccessToken, 
Role.INBOX);
+        WAIT_TWO_MINUTES.untilAsserted(() -> 
assertThat(listMessageIdsForAccount(shareeCredential)).hasSize(currentNumberOfMessages
 + 1));
+        String exportingMessageId = getLatestMessageId(shareeCredential, 
Role.INBOX);
 
-        return exportedFileLocationFromMailHeader(exportingMessageId, 
shareeAccessToken);
+        return exportedFileLocationFromMailHeader(exportingMessageId, 
shareeCredential);
     }
 
-    private String exportedFileLocationFromMailHeader(String messageId, 
AccessToken accessToken) {
-        return with()
-                .header("Authorization", accessToken.asString())
-                .body("[[\"getMessages\", {\"ids\": [\"" + messageId + "\"]}, 
\"#0\"]]")
-                .post("/jmap")
-            .jsonPath()
-                .getList(ARGUMENTS + ".list.headers.corresponding-file", 
String.class)
-                .get(0);
+    private String exportedFileLocationFromMailHeader(String messageId, 
UserCredential userCredential) {
+        List<Map<String, String>> headers = with()
+            .auth().basic(userCredential.username().asString(), 
userCredential.password())
+            .body("""
+                {
+                    "using": ["urn:ietf:params:jmap:core", 
"urn:ietf:params:jmap:mail", "urn:ietf:params:jmap:submission"],
+                    "methodCalls": [
+                        ["Email/get", {
+                            "accountId": "%s",
+                            "ids": ["%s"],
+                            "properties":["bodyStructure"],
+                            "bodyProperties":["name", "type","headers"]
+                        }, "c2"]
+                    ]
+                }
+                """.formatted(userCredential.accountId(), messageId))
+            .post("/jmap")
+        .then()
+            .statusCode(200)
+            .contentType(JSON)
+            .extract()
+            .body()
+            .path("methodResponses[0][1].list[0].bodyStructure.headers");
+
+        return headers.stream()
+            .filter(header -> header.get("name").equals("corresponding-file"))
+            .findFirst()
+            .orElseThrow(() -> new RuntimeException("No corresponding-file 
header found"))
+            .get("value").trim();
     }
 
     private void homerSharesHisMailboxWithBart() {
         with()
-            .header("Authorization", homerAccessToken.asString())
-            .body("[" +
-                "  [ \"setMailboxes\"," +
-                "    {" +
-                "      \"update\": {" +
-                "        \"" + otherMailboxId.serialize() + "\" : {" +
-                "          \"sharedWith\" : {\"" + BART + "\": [\"l\", \"w\", 
\"t\", \"r\"]}" +
-                "        }" +
-                "      }" +
-                "    }," +
-                "    \"#0\"" +
-                "  ]" +
-                "]")
+            .auth().basic(homerCredential.username().asString(), 
homerCredential.password())
+            .body("""
+                    {
+                        "using": [ "urn:ietf:params:jmap:core", 
"urn:ietf:params:jmap:mail", "urn:apache:james:params:jmap:mail:shares" ],
+                        "methodCalls": [
+                            [
+                                "Mailbox/set",
+                                {
+                                    "accountId": "%s",
+                                    "update": {
+                                        "%s": {
+                                            "sharedWith": {
+                                                "%s":["r", "l", "w", "t"]
+                                            }
+                                        }
+                                    }
+                                },
+                                "c1"
+                            ]
+                        ]
+                    }
+                """.formatted(homerCredential.accountId(), 
otherMailboxId.serialize(), BART))
             .post("/jmap");
     }
 
@@ -891,71 +893,130 @@ public abstract class DeletedMessageVaultIntegrationTest 
{
     }
 
     private void bartSendMessageToHomerAndJack() {
-        String messageCreationId = "creationId";
-        String outboxId = getOutboxId(bartAccessToken);
-        String bigEnoughBody = Strings.repeat("123456789\n", 12 * 100);
-        String requestBody = "[" +
-            "  [" +
-            "    \"setMessages\"," +
-            "    {" +
-            "      \"create\": { \"" + messageCreationId  + "\" : {" +
-            "        \"headers\":{\"Disposition-Notification-To\":\"" + BART + 
"\"}," +
-            "        \"from\": { \"name\": \"Bob\", \"email\": \"" + BART + 
"\"}," +
-            "        \"to\": [{ \"name\": \"Homer\", \"email\": \"" + HOMER + 
"\"}, { \"name\": \"Jack\", \"email\": \"" + JACK + "\"}]," +
-            "        \"subject\": \"" + SUBJECT + "\"," +
-            "        \"textBody\": \"" + bigEnoughBody + "\"," +
-            "        \"htmlBody\": \"Test <b>body</b>, HTML version\"," +
-            "        \"mailboxIds\": [\"" + outboxId + "\"] " +
-            "      }}" +
-            "    }," +
-            "    \"#0\"" +
-            "  ]" +
-            "]";
+        String outboxId = getOutboxId(bartCredential);
+
+        String requestBody =
+            "{" +
+                "    \"using\": [\"urn:ietf:params:jmap:core\", 
\"urn:ietf:params:jmap:mail\", \"urn:ietf:params:jmap:submission\"]," +
+                "    \"methodCalls\": [" +
+                "        [\"Email/set\", {" +
+                "            \"accountId\": \"" + bartCredential.accountId() + 
"\"," +
+                "            \"create\": {" +
+                "                \"e1526\": {" +
+                "                    \"mailboxIds\": { \"" + outboxId + "\": 
true }," +
+                "                    \"subject\": \"" + SUBJECT + "\"," +
+                "                    \"htmlBody\": [{" +
+                "                        \"partId\": \"a49d\"," +
+                "                        \"type\": \"text/html\"" +
+                "                    }]," +
+                "                    \"bodyValues\": {" +
+                "                        \"a49d\": {" +
+                "                            \"value\": \"Test <b>body</b>, 
HTML version\"" +
+                "                        }" +
+                "                    }," +
+                "                    \"to\": [{" +
+                "                        \"email\": \"" + HOMER + "\"" +
+                "                    }, {" +
+                "                        \"email\": \"" + JACK + "\"" +
+                "                    }]," +
+                "                    \"from\": [{" +
+                "                        \"email\": \"" + BART + "\"" +
+                "                    }]" +
+                "                }" +
+                "            }" +
+                "        }, \"c1\"]," +
+                "        [\"Email/get\", {" +
+                "            \"accountId\": \"" + bartCredential.accountId() + 
"\"," +
+                "            \"ids\": [\"#e1526\"]," +
+                "            \"properties\": [\"sentAt\"]" +
+                "        }, \"c2\"]," +
+                "        [\"EmailSubmission/set\", {" +
+                "            \"accountId\": \"" + bartCredential.accountId() + 
"\"," +
+                "            \"create\": {" +
+                "                \"k1490\": {" +
+                "                    \"emailId\": \"#e1526\"," +
+                "                    \"envelope\": {" +
+                "                        \"mailFrom\": {\"email\": \"" + BART 
+ "\"}," +
+                "                        \"rcptTo\": [{" +
+                "                            \"email\": \"" + HOMER + "\"" +
+                "                        }, {" +
+                "                            \"email\": \"" + JACK + "\"" +
+                "                        }]" +
+                "                    }" +
+                "                }" +
+                "            }" +
+                "        }, \"c3\"]" +
+                "    ]" +
+                "}";
 
         with()
-            .header("Authorization", bartAccessToken.asString())
+            .auth().basic(bartCredential.username().asString(), 
bartCredential.password())
             .body(requestBody)
             .post("/jmap")
         .then()
-            .extract()
-            .body()
-            .path(ARGUMENTS + ".created." + messageCreationId + ".id");
+            .statusCode(200)
+            .contentType(JSON)
+            .body("methodResponses[2][1].created", 
Matchers.is(notNullValue()));
     }
 
     private void bartSendMessageToHomerWithSubject(String subject) {
-        String messageCreationId = "creationId";
-        String outboxId = getOutboxId(bartAccessToken);
-        String bigEnoughBody = Strings.repeat("123456789\n", 12 * 100);
-        String requestBody = "[" +
-            "  [" +
-            "    \"setMessages\"," +
-            "    {" +
-            "      \"create\": { \"" + messageCreationId  + "\" : {" +
-            "        \"headers\":{\"Disposition-Notification-To\":\"" + BART + 
"\"}," +
-            "        \"from\": { \"name\": \"Bob\", \"email\": \"" + BART + 
"\"}," +
-            "        \"to\": [{ \"name\": \"User\", \"email\": \"" + HOMER + 
"\"}]," +
-            "        \"subject\": \"" + subject + "\"," +
-            "        \"textBody\": \"" + bigEnoughBody + "\"," +
-            "        \"htmlBody\": \"Test <b>body</b>, HTML version\"," +
-            "        \"mailboxIds\": [\"" + outboxId + "\"] " +
-            "      }}" +
-            "    }," +
-            "    \"#0\"" +
-            "  ]" +
-            "]";
+        String outboxId = getOutboxId(bartCredential);
+        String requestBody =
+            "{" +
+                "    \"using\": [\"urn:ietf:params:jmap:core\", 
\"urn:ietf:params:jmap:mail\", \"urn:ietf:params:jmap:submission\"]," +
+                "    \"methodCalls\": [" +
+                "        [\"Email/set\", {" +
+                "            \"accountId\": \"" + bartCredential.accountId() + 
"\"," +
+                "            \"create\": {" +
+                "                \"e1526\": {" +
+                "                    \"mailboxIds\": { \"" + outboxId + "\": 
true }," +
+                "                    \"subject\": \"" + subject + "\"," +
+                "                    \"htmlBody\": [{" +
+                "                        \"partId\": \"a49d\"," +
+                "                        \"type\": \"text/html\"" +
+                "                    }]," +
+                "                    \"bodyValues\": {" +
+                "                        \"a49d\": {" +
+                "                            \"value\": \"Test <b>body</b>, 
HTML version\"" +
+                "                        }" +
+                "                    }," +
+                "                    \"to\": [{\"email\": \"" + HOMER + 
"\"}]," +
+                "                    \"from\": [{\"email\": \"" + BART + 
"\"}]" +
+                "                }" +
+                "            }" +
+                "        }, \"c1\"]," +
+                "        [\"Email/get\", {" +
+                "            \"accountId\": \"" + bartCredential.accountId() + 
"\"," +
+                "            \"ids\": [\"#e1526\"]," +
+                "            \"properties\": [\"sentAt\"]" +
+                "        }, \"c2\"]," +
+                "        [\"EmailSubmission/set\", {" +
+                "            \"accountId\": \"" + bartCredential.accountId() + 
"\"," +
+                "            \"create\": {" +
+                "                \"k1490\": {" +
+                "                    \"emailId\": \"#e1526\"," +
+                "                    \"envelope\": {" +
+                "                        \"mailFrom\": {\"email\": \"" + BART 
+ "\"}," +
+                "                        \"rcptTo\": [{\"email\": \"" + HOMER 
+ "\"}]" +
+                "                    }" +
+                "                }" +
+                "            }" +
+                "        }, \"c3\"]" +
+                "    ]" +
+                "}";
 
         with()
-            .header("Authorization", bartAccessToken.asString())
+            .auth().basic(bartCredential.username().asString(), 
bartCredential.password())
             .body(requestBody)
             .post("/jmap")
         .then()
-            .extract()
-            .body()
-            .path(ARGUMENTS + ".created." + messageCreationId + ".id");
+            .statusCode(200)
+            .contentType(JSON)
+            .body("methodResponses[2][1].created", 
Matchers.is(notNullValue()));
     }
 
     private void homerDeletesMessages(List<String> idsToDestroy) {
-        deleteMessages(homerAccessToken, idsToDestroy);
+        deleteMessages(homerCredential, idsToDestroy);
         // Grace period for the vault
         try {
             Thread.sleep(1000);
@@ -965,11 +1026,11 @@ public abstract class DeletedMessageVaultIntegrationTest 
{
     }
 
     private void bartDeletesMessages(List<String> idsToDestroy) {
-        deleteMessages(bartAccessToken, idsToDestroy);
+        deleteMessages(bartCredential, idsToDestroy);
     }
 
     private void jackDeletesMessages(List<String> idsToDestroy) {
-        deleteMessages(jackAccessToken, idsToDestroy);
+        deleteMessages(jackCredential, idsToDestroy);
     }
 
     private void restoreAllMessagesOfHomer() {
@@ -981,27 +1042,31 @@ public abstract class DeletedMessageVaultIntegrationTest 
{
     }
 
     private void homerMovesTheMailInAnotherMailbox(String messageId) {
-        String updateRequestBody = "[" +
-            "  [" +
-            "    \"setMessages\"," +
-            "    {" +
-            "      \"update\": { \"" + messageId  + "\" : {" +
-            "        \"mailboxIds\": [\"" + otherMailboxId.serialize() + "\"]" 
+
-            "      }}" +
-            "    }," +
-            "    \"#0\"" +
-            "  ]" +
-            "]";
-
         given()
-            .header("Authorization", homerAccessToken.asString())
-            .body(updateRequestBody)
+            .auth().basic(homerCredential.username().asString(), 
homerCredential.password())
+            .body("""
+                {
+                    "using": ["urn:ietf:params:jmap:core", 
"urn:ietf:params:jmap:mail"],
+                    "methodCalls": [
+                        ["Email/set", {
+                            "accountId": "%s",
+                            "update": {
+                                "%s":{
+                                    "mailboxIds": { "%s" : true}
+                                }
+                            }
+                        }, "c1"]]
+                }""".formatted(homerCredential.accountId(), messageId, 
otherMailboxId.serialize()))
             .when()
-            .post("/jmap");
+            .post("/jmap")
+        .then()
+            .statusCode(200)
+            .contentType(JSON);
     }
 
+
     private boolean homerHasMailboxWithRole(Role role) {
-        return getAllMailboxesIds(homerAccessToken).stream()
+        return getAllMailboxesIds(homerCredential).stream()
             .filter(mailbox -> mailbox.get("role") != null)
             .anyMatch(mailbox -> mailbox.get("role").equals(role.serialize())
                 && mailbox.get("name").equals(role.getDefaultMailbox()));
diff --git 
a/server/protocols/webadmin-integration-test/webadmin-integration-test-common/src/main/java/org/apache/james/webadmin/integration/vault/LinshareBlobExportMechanismIntegrationTest.java
 
b/server/protocols/webadmin-integration-test/webadmin-integration-test-common/src/main/java/org/apache/james/webadmin/integration/vault/LinshareBlobExportMechanismIntegrationTest.java
index 251967440a..d733ec5432 100644
--- 
a/server/protocols/webadmin-integration-test/webadmin-integration-test-common/src/main/java/org/apache/james/webadmin/integration/vault/LinshareBlobExportMechanismIntegrationTest.java
+++ 
b/server/protocols/webadmin-integration-test/webadmin-integration-test-common/src/main/java/org/apache/james/webadmin/integration/vault/LinshareBlobExportMechanismIntegrationTest.java
@@ -20,16 +20,15 @@
 package org.apache.james.webadmin.integration.vault;
 
 import static io.restassured.RestAssured.with;
-import static 
org.apache.james.jmap.HttpJmapAuthentication.authenticateJamesUser;
-import static org.apache.james.jmap.JMAPTestingConstants.ARGUMENTS;
+import static io.restassured.http.ContentType.JSON;
 import static org.apache.james.jmap.JMAPTestingConstants.DOMAIN;
 import static org.apache.james.jmap.JMAPTestingConstants.LOCALHOST_IP;
 import static org.apache.james.jmap.JMAPTestingConstants.calmlyAwait;
 import static 
org.apache.james.jmap.JMAPTestingConstants.jmapRequestSpecBuilder;
-import static org.apache.james.jmap.JmapCommonRequests.deleteMessages;
-import static org.apache.james.jmap.JmapCommonRequests.getOutboxId;
-import static 
org.apache.james.jmap.JmapCommonRequests.listMessageIdsForAccount;
-import static org.apache.james.jmap.LocalHostURIBuilder.baseUri;
+import static org.apache.james.jmap.JmapRFCCommonRequests.UserCredential;
+import static org.apache.james.jmap.JmapRFCCommonRequests.deleteMessages;
+import static org.apache.james.jmap.JmapRFCCommonRequests.getUserCredential;
+import static 
org.apache.james.jmap.JmapRFCCommonRequests.listMessageIdsForAccount;
 import static 
org.apache.james.linshare.LinshareExtension.LinshareAPIForTechnicalAccountTesting;
 import static 
org.apache.james.linshare.LinshareExtension.LinshareAPIForUserTesting;
 import static org.apache.james.linshare.LinshareFixture.MATCH_ALL_QUERY;
@@ -38,13 +37,14 @@ import static 
org.apache.james.mailbox.backup.ZipAssert.assertThatZip;
 import static 
org.apache.james.webadmin.integration.vault.DeletedMessagesVaultRequests.exportVaultContent;
 import static org.assertj.core.api.Assertions.assertThat;
 import static org.awaitility.Durations.TEN_SECONDS;
+import static org.hamcrest.Matchers.notNullValue;
 
 import java.io.ByteArrayInputStream;
 import java.util.List;
 
 import org.apache.james.GuiceJamesServer;
 import org.apache.james.core.Username;
-import org.apache.james.jmap.AccessToken;
+import org.apache.james.jmap.JmapRFCCommonRequests;
 import org.apache.james.jmap.draft.JmapGuiceProbe;
 import org.apache.james.linshare.client.Document;
 import org.apache.james.mailbox.DefaultMailboxes;
@@ -59,6 +59,7 @@ import org.apache.james.utils.TestIMAPClient;
 import org.apache.james.utils.WebAdminGuiceProbe;
 import org.apache.james.webadmin.WebAdminUtils;
 import org.awaitility.core.ConditionFactory;
+import org.hamcrest.Matchers;
 import org.junit.jupiter.api.BeforeEach;
 import org.junit.jupiter.api.Test;
 import org.junit.jupiter.api.extension.RegisterExtension;
@@ -83,8 +84,9 @@ public abstract class 
LinshareBlobExportMechanismIntegrationTest {
     @RegisterExtension
     TestIMAPClient testIMAPClient = new TestIMAPClient();
 
-    private AccessToken homerAccessToken;
-    private AccessToken bartAccessToken;
+    private UserCredential homerCredential;
+    private UserCredential bartCredential;
+
     private GuiceJamesServer jmapServer;
     private RequestSpecification webAdminApi;
     private LinshareAPIForUserTesting user1LinshareAPI;
@@ -110,8 +112,8 @@ public abstract class 
LinshareBlobExportMechanismIntegrationTest {
         MailboxProbe mailboxProbe = 
jmapServer.getProbe(MailboxProbeImpl.class);
         mailboxProbe.createMailbox(MailboxConstants.USER_NAMESPACE, HOMER, 
DefaultMailboxes.INBOX);
 
-        homerAccessToken = authenticateJamesUser(baseUri(jmapPort), 
Username.of(HOMER), HOMER_PASSWORD);
-        bartAccessToken = authenticateJamesUser(baseUri(jmapPort), 
Username.of(BART), BART_PASSWORD);
+        homerCredential = getUserCredential(Username.of(HOMER), 
HOMER_PASSWORD);
+        bartCredential = getUserCredential(Username.of(BART), BART_PASSWORD);
 
         user1LinshareAPI = LinshareAPIForUserTesting.from(USER_1);
     }
@@ -120,10 +122,10 @@ public abstract class 
LinshareBlobExportMechanismIntegrationTest {
     void exportShouldShareTheDocumentViaLinshareWhenJmapDelete() {
         bartSendMessageToHomer();
 
-        WAIT_TEN_SECONDS.until(() -> 
listMessageIdsForAccount(homerAccessToken).size() == 1);
+        WAIT_TEN_SECONDS.until(() -> 
listMessageIdsForAccount(homerCredential).size() == 1);
 
-        homerDeletesMessages(listMessageIdsForAccount(homerAccessToken));
-        WAIT_TEN_SECONDS.until(() -> 
listMessageIdsForAccount(homerAccessToken).isEmpty());
+        homerDeletesMessages(listMessageIdsForAccount(homerCredential));
+        WAIT_TEN_SECONDS.until(() -> 
listMessageIdsForAccount(homerCredential).isEmpty());
 
         exportVaultContent(webAdminApi, EXPORT_ALL_HOMER_MESSAGES_TO_USER_1);
 
@@ -136,7 +138,7 @@ public abstract class 
LinshareBlobExportMechanismIntegrationTest {
     void exportShouldShareTheDocumentViaLinshareWhenImapDelete() throws 
Exception {
         bartSendMessageToHomer();
 
-        WAIT_TEN_SECONDS.until(() -> 
listMessageIdsForAccount(homerAccessToken).size() == 1);
+        WAIT_TEN_SECONDS.until(() -> 
listMessageIdsForAccount(homerCredential).size() == 1);
 
         testIMAPClient.connect(LOCALHOST_IP, 
jmapServer.getProbe(ImapGuiceProbe.class).getImapPort())
             .login(HOMER, HOMER_PASSWORD)
@@ -144,7 +146,7 @@ public abstract class 
LinshareBlobExportMechanismIntegrationTest {
             .setFlagsForAllMessagesInMailbox("\\Deleted");
         testIMAPClient.expunge();
 
-        WAIT_TEN_SECONDS.until(() -> 
listMessageIdsForAccount(homerAccessToken).isEmpty());
+        WAIT_TEN_SECONDS.until(() -> 
listMessageIdsForAccount(homerCredential).isEmpty());
 
         exportVaultContent(webAdminApi, EXPORT_ALL_HOMER_MESSAGES_TO_USER_1);
 
@@ -157,10 +159,10 @@ public abstract class 
LinshareBlobExportMechanismIntegrationTest {
     void 
exportShouldShareNonEmptyZipViaLinshareWhenJmapDelete(LinshareAPIForTechnicalAccountTesting
 linshareAPIForTechnicalAccountTesting) throws Exception {
         bartSendMessageToHomer();
 
-        WAIT_TEN_SECONDS.until(() -> 
listMessageIdsForAccount(homerAccessToken).size() == 1);
+        WAIT_TEN_SECONDS.until(() -> 
listMessageIdsForAccount(homerCredential).size() == 1);
 
-        homerDeletesMessages(listMessageIdsForAccount(homerAccessToken));
-        WAIT_TEN_SECONDS.until(() -> 
listMessageIdsForAccount(homerAccessToken).isEmpty());
+        homerDeletesMessages(listMessageIdsForAccount(homerCredential));
+        WAIT_TEN_SECONDS.until(() -> 
listMessageIdsForAccount(homerCredential).isEmpty());
 
         exportVaultContent(webAdminApi, EXPORT_ALL_HOMER_MESSAGES_TO_USER_1);
 
@@ -177,7 +179,7 @@ public abstract class 
LinshareBlobExportMechanismIntegrationTest {
     void 
exportShouldShareNonEmptyZipViaLinshareWhenImapDelete(LinshareAPIForTechnicalAccountTesting
 linshareAPIForTechnicalAccountTesting) throws Exception {
         bartSendMessageToHomer();
 
-        WAIT_TEN_SECONDS.until(() -> 
listMessageIdsForAccount(homerAccessToken).size() == 1);
+        WAIT_TEN_SECONDS.until(() -> 
listMessageIdsForAccount(homerCredential).size() == 1);
 
         testIMAPClient.connect(LOCALHOST_IP, 
jmapServer.getProbe(ImapGuiceProbe.class).getImapPort())
             .login(HOMER, HOMER_PASSWORD)
@@ -185,7 +187,7 @@ public abstract class 
LinshareBlobExportMechanismIntegrationTest {
             .setFlagsForAllMessagesInMailbox("\\Deleted");
         testIMAPClient.expunge();
 
-        WAIT_TEN_SECONDS.until(() -> 
listMessageIdsForAccount(homerAccessToken).isEmpty());
+        WAIT_TEN_SECONDS.until(() -> 
listMessageIdsForAccount(homerCredential).isEmpty());
 
         exportVaultContent(webAdminApi, EXPORT_ALL_HOMER_MESSAGES_TO_USER_1);
 
@@ -199,37 +201,62 @@ public abstract class 
LinshareBlobExportMechanismIntegrationTest {
     }
 
     private void bartSendMessageToHomer() {
-        String messageCreationId = "creationId";
-        String outboxId = getOutboxId(bartAccessToken);
-        String textBody = "You got mail!";
-        String requestBody = "[" +
-            "  [" +
-            "    \"setMessages\"," +
-            "    {" +
-            "      \"create\": { \"" + messageCreationId + "\" : {" +
-            "        \"from\": { \"name\": \"user2\", \"email\": \"" + BART + 
"\"}," +
-            "        \"to\": [{ \"name\": \"user1\", \"email\": \"" + HOMER + 
"\"}]," +
-            "        \"subject\": \"" + SUBJECT + "\"," +
-            "        \"textBody\": \"" + textBody + "\"," +
-            "        \"htmlBody\": \"Test <b>body</b>, HTML version\"," +
-            "        \"mailboxIds\": [\"" + outboxId + "\"] " +
-            "      }}" +
-            "    }," +
-            "    \"#0\"" +
-            "  ]" +
-            "]";
+        String outboxId = JmapRFCCommonRequests.getOutboxId(bartCredential);
+        String requestBody =
+            "{" +
+                "    \"using\": [\"urn:ietf:params:jmap:core\", 
\"urn:ietf:params:jmap:mail\", \"urn:ietf:params:jmap:submission\"]," +
+                "    \"methodCalls\": [" +
+                "        [\"Email/set\", {" +
+                "            \"accountId\": \"" + bartCredential.accountId() + 
"\"," +
+                "            \"create\": {" +
+                "                \"e1526\": {" +
+                "                    \"mailboxIds\": { \"" + outboxId + "\": 
true }," +
+                "                    \"subject\": \"" + SUBJECT + "\"," +
+                "                    \"htmlBody\": [{" +
+                "                        \"partId\": \"a49d\"," +
+                "                        \"type\": \"text/html\"" +
+                "                    }]," +
+                "                    \"bodyValues\": {" +
+                "                        \"a49d\": {" +
+                "                            \"value\": \"Test <b>body</b>, 
HTML version\"" +
+                "                        }" +
+                "                    }," +
+                "                    \"to\": [{\"email\": \"" + HOMER + 
"\"}]," +
+                "                    \"from\": [{\"email\": \"" + BART + 
"\"}]" +
+                "                }" +
+                "            }" +
+                "        }, \"c1\"]," +
+                "        [\"Email/get\", {" +
+                "            \"accountId\": \"" + bartCredential.accountId() + 
"\"," +
+                "            \"ids\": [\"#e1526\"]," +
+                "            \"properties\": [\"sentAt\"]" +
+                "        }, \"c2\"]," +
+                "        [\"EmailSubmission/set\", {" +
+                "            \"accountId\": \"" + bartCredential.accountId() + 
"\"," +
+                "            \"create\": {" +
+                "                \"k1490\": {" +
+                "                    \"emailId\": \"#e1526\"," +
+                "                    \"envelope\": {" +
+                "                        \"mailFrom\": {\"email\": \"" + BART 
+ "\"}," +
+                "                        \"rcptTo\": [{\"email\": \"" + HOMER 
+ "\"}]" +
+                "                    }" +
+                "                }" +
+                "            }" +
+                "        }, \"c3\"]" +
+                "    ]" +
+                "}";
 
         with()
-            .header("Authorization", bartAccessToken.asString())
+            .auth().basic(bartCredential.username().asString(), 
bartCredential.password())
             .body(requestBody)
             .post("/jmap")
-        .then()
-            .extract()
-            .body()
-            .path(ARGUMENTS + ".created." + messageCreationId + ".id");
+            .then()
+            .statusCode(200)
+            .contentType(JSON)
+            .body("methodResponses[2][1].created", 
Matchers.is(notNullValue()));
     }
 
     private void homerDeletesMessages(List<String> idsToDestroy) {
-        deleteMessages(homerAccessToken, idsToDestroy);
+        deleteMessages(homerCredential, idsToDestroy);
     }
 }
diff --git 
a/server/testing/src/main/java/org/apache/james/jmap/JmapRFCCommonRequests.java 
b/server/testing/src/main/java/org/apache/james/jmap/JmapRFCCommonRequests.java
new file mode 100644
index 0000000000..6a1a54a24a
--- /dev/null
+++ 
b/server/testing/src/main/java/org/apache/james/jmap/JmapRFCCommonRequests.java
@@ -0,0 +1,314 @@
+/****************************************************************
+ * 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;
+
+import static io.restassured.RestAssured.with;
+import static io.restassured.http.ContentType.JSON;
+
+import java.util.List;
+import java.util.Map;
+import java.util.stream.Collectors;
+
+import org.apache.james.core.Username;
+import org.apache.james.mailbox.Role;
+import org.hamcrest.Matchers;
+
+import io.restassured.http.ContentType;
+import io.restassured.http.Header;
+import io.restassured.path.json.JsonPath;
+
+public class JmapRFCCommonRequests {
+    public record UserCredential(Username username, String password, String 
accountId) {
+    }
+    public static final Header ACCEPT_JMAP_RFC_HEADER = new Header("accept", 
"application/json; jmapVersion=rfc-8621");
+
+    public static String getOutboxId(UserCredential userCredential) {
+        return getMailboxId(userCredential, Role.OUTBOX);
+    }
+
+    public static String getSentId(UserCredential userCredential) {
+        return getMailboxId(userCredential, Role.SENT);
+    }
+
+    public static String getDraftId(UserCredential userCredential) {
+        return getMailboxId(userCredential, Role.DRAFTS);
+    }
+
+    public static String getMailboxId(UserCredential userCredential, Role 
role) {
+        return getAllMailboxesIds(userCredential).stream()
+            .filter(mailbox -> mailbox.get("role").equals(role.serialize()))
+            .map(mailbox -> mailbox.get("id"))
+            .findFirst().orElseThrow();
+    }
+
+    public static UserCredential getUserCredential(Username username, String 
password) {
+        return getUserCredential(username.asString(), password);
+    }
+
+    public static UserCredential getUserCredential(String username, String 
password) {
+        String accountId = with()
+            .auth().basic(username, password)
+            .header(ACCEPT_JMAP_RFC_HEADER)
+            .get("/jmap/session")
+        .then()
+            .statusCode(200)
+            .contentType(ContentType.JSON)
+            .extract()
+            .body()
+            .path("primaryAccounts[\"urn:ietf:params:jmap:core\"]");
+
+        return new UserCredential(Username.of(username), password, accountId);
+    }
+
+    public static List<Map<String, String>> getAllMailboxesIds(UserCredential 
userCredential) {
+        return with()
+            .auth().basic(userCredential.username().asString(), 
userCredential.password())
+            .header(ACCEPT_JMAP_RFC_HEADER)
+            .body("""
+                {
+                    "using": [
+                        "urn:ietf:params:jmap:core",
+                        "urn:ietf:params:jmap:mail",
+                        "urn:apache:james:params:jmap:mail:shares"
+                    ],
+                    "methodCalls": [
+                        [
+                            "Mailbox/get",
+                            {
+                                "accountId": "%s"
+                            },
+                            "c1"
+                        ]
+                    ]
+                }
+                """.formatted(userCredential.accountId()))
+            .post("/jmap")
+            .andReturn()
+            .body()
+            .jsonPath()
+            .getList("methodResponses[0][1].list");
+    }
+
+    public static List<String> listMessageIdsForAccount(UserCredential 
userCredential) {
+        return with()
+            .auth().basic(userCredential.username().asString(), 
userCredential.password())
+            .header(ACCEPT_JMAP_RFC_HEADER)
+            .body("""
+                {
+                    "using": [
+                        "urn:ietf:params:jmap:core",
+                        "urn:ietf:params:jmap:mail"
+                    ],
+                    "methodCalls": [
+                        [
+                            "Email/query",
+                            {
+                                "accountId": "%s",
+                                "sort": [
+                                    {
+                                        "isAscending": false,
+                                        "property": "receivedAt"
+                                    }
+                                ]
+                            },
+                            "c1"
+                        ]
+                    ]
+                }
+                """.formatted(userCredential.accountId()))
+            .post("/jmap")
+        .then()
+            .statusCode(200)
+            .contentType(JSON)
+            .extract()
+            .body()
+            .path("methodResponses[0][1].ids");
+    }
+
+    public static String getLastMessageId(UserCredential userCredential) {
+        return with()
+            .auth().basic(userCredential.username().asString(), 
userCredential.password())
+            .header(ACCEPT_JMAP_RFC_HEADER)
+            .body("""
+                    {
+                    "using": [ "urn:ietf:params:jmap:core", 
"urn:ietf:params:jmap:mail" ],
+                    "methodCalls": [
+                        [
+                            "Email/query",
+                            {
+                                "accountId": "%s",
+                                "sort": [ {
+                                        "isAscending": false,
+                                        "property": "receivedAt"
+                                    } ]
+                            },
+                            "c1"
+                        ]
+                    ]
+                }
+                """.formatted(userCredential.accountId()))
+            .post("/jmap")
+        .then()
+            .statusCode(200)
+            .contentType(JSON)
+            .extract()
+            .body()
+            .jsonPath()
+            .getString("methodResponses[0][1].ids[0]");
+    }
+
+    public static Object bodyOfMessage(UserCredential userCredential, String 
messageId) {
+        System.out.println("MessageId: " + messageId);
+        return getMessageContent(userCredential, messageId)
+            .get("methodResponses[0][1].list[0].textBody");
+    }
+
+    public static String getLatestMessageId(UserCredential userCredential, 
Role mailbox) {
+        String mailboxId = getMailboxId(userCredential, mailbox);
+        return with()
+            .auth().basic(userCredential.username().asString(), 
userCredential.password())
+            .header(ACCEPT_JMAP_RFC_HEADER)
+            .body("""
+                    {
+                    "using": [ "urn:ietf:params:jmap:core", 
"urn:ietf:params:jmap:mail" ],
+                    "methodCalls": [
+                        [
+                            "Email/query",
+                            {
+                                "accountId": "%s",
+                                "filter": {
+                                    "inMailbox": "%s"
+                                },
+                                "sort": [ {
+                                        "isAscending": false,
+                                        "property": "receivedAt"
+                                    } ]
+                            },
+                            "c1"
+                        ]
+                    ]
+                }
+                """.formatted(userCredential.accountId(), mailboxId))
+            .post("/jmap")
+        .then()
+            .statusCode(200)
+            .contentType(JSON)
+            .extract()
+            .body()
+            .jsonPath()
+            .getString("methodResponses[0][1].ids[0]");
+    }
+
+
+    public static JsonPath getMessageContent(UserCredential userCredential, 
String messageId) {
+        return with()
+            .auth().basic(userCredential.username().asString(), 
userCredential.password())
+            .header(ACCEPT_JMAP_RFC_HEADER)
+            .body("""
+                {
+                    "using": [ "urn:ietf:params:jmap:core", 
"urn:ietf:params:jmap:mail" ],
+                    "methodCalls": [
+                        [
+                            "Email/get",
+                            {
+                                "accountId": "%s",
+                                "ids": ["%s"]
+                            },
+                            "c1"
+                        ]
+                    ]
+                }
+                """.formatted(userCredential.accountId(), messageId))
+        .when()
+            .post("/jmap")
+        .then()
+            .statusCode(200)
+            .contentType(ContentType.JSON)
+            .extract()
+            .jsonPath();
+    }
+
+    public static List<String> listMessageIdsInMailbox(UserCredential 
userCredential, String mailboxId) {
+        return with()
+            .auth().basic(userCredential.username().asString(), 
userCredential.password())
+            .header(ACCEPT_JMAP_RFC_HEADER)
+            .body("""
+                {
+                    "using": [
+                        "urn:ietf:params:jmap:core",
+                        "urn:ietf:params:jmap:mail"
+                    ],
+                    "methodCalls": [
+                        [
+                            "Email/query",
+                            {
+                                "accountId": "%s",
+                                "filter": {
+                                    "inMailbox": "%s"
+                                },
+                                "sort": [
+                                    {
+                                        "isAscending": false,
+                                        "property": "receivedAt"
+                                    }
+                                ]
+                            },
+                            "c1"
+                        ]
+                    ]
+                }""".formatted(userCredential.accountId(), mailboxId))
+            .post("/jmap")
+        .then()
+            .statusCode(200)
+            .contentType(ContentType.JSON)
+            .extract()
+            .body()
+            .path("methodResponses[0][1].ids");
+    }
+
+    public static void deleteMessages(UserCredential userCredential, 
List<String> idsToDestroy) {
+        String idString = idsToDestroy.stream()
+            .map(id -> "\"" + id + "\"")
+            .collect(Collectors.joining(","));
+
+        with()
+            .auth().basic(userCredential.username().asString(), 
userCredential.password())
+            .header(ACCEPT_JMAP_RFC_HEADER)
+            .body("""
+                {
+                    "using": [ "urn:ietf:params:jmap:core", 
"urn:ietf:params:jmap:mail" ],
+                    "methodCalls": [
+                        [
+                            "Email/set",
+                            {
+                                "accountId": "%s",
+                                "destroy": [%s]
+                            },
+                            "c1"
+                        ]
+                    ]
+                }""".formatted(userCredential.accountId(), idString))
+            .post("/jmap")
+        .then()
+            .statusCode(200)
+            .contentType(JSON)
+            .body("methodResponses[0][1].destroyed", 
Matchers.is(Matchers.hasSize(idsToDestroy.size())));
+    }
+}


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

Reply via email to