You are viewing a plain text version of this content. The canonical link for it is here.
Posted to notifications@james.apache.org by bt...@apache.org on 2020/12/15 01:52:54 UTC

[james-project] branch master updated (4ae9454 -> 1c80dcc)

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

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


    from 4ae9454  JAMES-3467 Experimental cache for DomainList calls
     new 563883f  JAMES-3461 Add State class, replace literal values with fixture objects
     new e6053bd  JAMES-3461 Mailbox/changes method & contract
     new d38f8fe  JAMES-3461 MemoryMailboxChangeRepository should return state when no newer state
     new 5897af9  JAMES-3461 Dummy CassandraMailboxChangeRepo implementation
     new 1bfed8e  JAMES-3468 Webadmin Update User API should reject inserts of already existing users
     new e7f1c76  JAMES-3468 Update manage webadmin documents
     new 1c80dcc  JAMES-3468 Update Webadmin-cli user commands following Webadmin API change

The 7 revisions listed above as "new" are entirely new to this
repository and will be described in separate emails.  The revisions
listed as "add" were already present in the repository and have only
been added to this reference.


Summary of changes:
 .../pages/distributed/operate/webadmin.adoc        |  25 +-
 .../modules/mailbox/CassandraMailboxModule.java    |   3 +
 .../james/modules/mailbox/MemoryMailboxModule.java |   4 +
 .../apache/james/jmap/draft/JmapGuiceProbe.java    |  10 +-
 .../change/CassandraMailboxChangeRepository.java}  |  21 +-
 .../james/jmap/api/change/MailboxChanges.java      |  13 +-
 .../change/MemoryMailboxChangeRepository.java      |   2 +-
 .../change/MailboxChangeRepositoryContract.java    |  11 +
 .../rfc8621/contract/BackReferenceContract.scala   |  28 +-
 .../jmap/rfc8621/contract/EchoMethodContract.scala |   7 +-
 .../rfc8621/contract/EmailChangesContract.scala    |  22 +-
 .../rfc8621/contract/EmailGetMethodContract.scala  | 175 ++---
 .../contract/EmailQueryMethodContract.scala        |  89 +--
 .../rfc8621/contract/EmailSetMethodContract.scala  | 112 +--
 .../EmailSubmissionSetMethodContract.scala         |  18 +-
 .../james/jmap/rfc8621/contract/Fixture.scala      |   5 +-
 .../rfc8621/contract/IdentityGetContract.scala     |  30 +-
 .../rfc8621/contract/MailboxChangesContract.scala  | 172 ----
 .../contract/MailboxChangesMethodContract.scala    | 862 +++++++++++++++++++++
 .../contract/MailboxGetMethodContract.scala        |  60 +-
 .../contract/MailboxQueryMethodContract.scala      |  26 +-
 .../contract/MailboxSetMethodContract.scala        | 494 ++++++------
 .../rfc8621/contract/SessionRoutesContract.scala   |   2 +-
 .../rfc8621/contract/ThreadChangesContract.scala   |  22 +-
 .../jmap/rfc8621/contract/ThreadGetContract.scala  |  13 +-
 .../VacationResponseGetMethodContract.scala        |  60 +-
 .../VacationResponseSetMethodContract.scala        |  64 +-
 .../memory/MemoryMailboxChangesMethodTest.java     |   7 +-
 .../src/test/resources/listeners.xml               |   3 +
 .../jmap-rfc-8621/doc/specs/spec/jmap/api.mdown    |   2 +-
 .../doc/specs/spec/jmap/session.mdown              |   2 +-
 .../apache/james/jmap/core/ResponseObject.scala    |   3 +-
 .../scala/org/apache/james/jmap/core/Session.scala |  16 +-
 .../james/jmap/json/EmailGetSerializer.scala       |   5 +-
 .../james/jmap/json/EmailSetSerializer.scala       |   4 +-
 .../jmap/json/EmailSubmissionSetSerializer.scala   |   3 +-
 .../james/jmap/json/IdentitySerializer.scala       |   3 +-
 .../apache/james/jmap/json/MailboxSerializer.scala |  15 +-
 .../james/jmap/json/ResponseSerializer.scala       |   1 +
 .../apache/james/jmap/json/ThreadSerializer.scala  |   4 +-
 .../james/jmap/json/VacationSerializer.scala       |   3 +-
 .../scala/org/apache/james/jmap/json/package.scala |   4 +-
 .../org/apache/james/jmap/mail/EmailGet.scala      |   3 +-
 .../org/apache/james/jmap/mail/EmailSet.scala      |   3 +-
 .../james/jmap/mail/EmailSubmissionSet.scala       |   3 +-
 .../org/apache/james/jmap/mail/Identity.scala      |   3 +-
 .../org/apache/james/jmap/mail/MailboxGet.scala    |  23 +-
 .../org/apache/james/jmap/mail/MailboxSet.scala    |   3 +-
 .../scala/org/apache/james/jmap/mail/Thread.scala  |   5 +-
 .../james/jmap/method/MailboxChangesMethod.scala   |  41 +-
 .../org/apache/james/jmap/method/Method.scala      |   4 +-
 .../james/jmap/vacation/VacationResponseGet.scala  |   3 +-
 .../james/jmap/vacation/VacationResponseSet.scala  |   3 +-
 .../jmap/json/MailboxGetSerializationTest.scala    |   7 +-
 .../json/ResponseObjectSerializationTest.scala     |  22 +-
 .../james/jmap/json/SessionSerializationTest.scala |  10 +-
 .../VacationResponseGetSerializationTest.scala     |   9 +-
 .../james/jmap/routes/JMAPApiRoutesTest.scala      |  13 +-
 .../james/jmap/routes/SessionRoutesTest.scala      |   3 +-
 server/protocols/webadmin-cli/README.md            |  17 +-
 .../apache/james/cli/user/UserCreateCommand.java   |  37 +-
 .../org/apache/james/httpclient/UserClient.java    |   4 +
 .../java/org/apache/james/cli/UserManageTest.java  |  82 +-
 .../apache/james/webadmin/routes/UserRoutes.java   |  29 +-
 .../apache/james/webadmin/service/UserService.java |  15 +-
 .../james/webadmin/routes/UserRoutesTest.java      |  74 +-
 src/site/markdown/server/manage-webadmin.md        |  23 +-
 67 files changed, 1926 insertions(+), 938 deletions(-)
 copy server/data/{data-jmap/src/main/java/org/apache/james/jmap/api/vacation/NotificationRegistry.java => data-jmap-cassandra/src/main/java/org/apache/james/jmap/cassandra/change/CassandraMailboxChangeRepository.java} (68%)
 delete mode 100644 server/protocols/jmap-rfc-8621-integration-tests/jmap-rfc-8621-integration-tests-common/src/main/scala/org/apache/james/jmap/rfc8621/contract/MailboxChangesContract.scala
 create mode 100644 server/protocols/jmap-rfc-8621-integration-tests/jmap-rfc-8621-integration-tests-common/src/main/scala/org/apache/james/jmap/rfc8621/contract/MailboxChangesMethodContract.scala


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


[james-project] 04/07: JAMES-3461 Dummy CassandraMailboxChangeRepo implementation

Posted by bt...@apache.org.
This is an automated email from the ASF dual-hosted git repository.

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

commit 5897af9e2f5d6a27d955f058ce60d374fdd9f14f
Author: LanKhuat <dl...@linagora.com>
AuthorDate: Mon Dec 14 13:49:54 2020 +0700

    JAMES-3461 Dummy CassandraMailboxChangeRepo implementation
---
 .../modules/mailbox/CassandraMailboxModule.java    |  3 ++
 .../change/CassandraMailboxChangeRepository.java   | 42 ++++++++++++++++++++++
 2 files changed, 45 insertions(+)

diff --git a/server/container/guice/cassandra-guice/src/main/java/org/apache/james/modules/mailbox/CassandraMailboxModule.java b/server/container/guice/cassandra-guice/src/main/java/org/apache/james/modules/mailbox/CassandraMailboxModule.java
index 1ce6a3d..0e393d9 100644
--- a/server/container/guice/cassandra-guice/src/main/java/org/apache/james/modules/mailbox/CassandraMailboxModule.java
+++ b/server/container/guice/cassandra-guice/src/main/java/org/apache/james/modules/mailbox/CassandraMailboxModule.java
@@ -28,6 +28,8 @@ import org.apache.james.backends.cassandra.components.CassandraModule;
 import org.apache.james.eventsourcing.Event;
 import org.apache.james.eventsourcing.eventstore.cassandra.dto.EventDTO;
 import org.apache.james.eventsourcing.eventstore.cassandra.dto.EventDTOModule;
+import org.apache.james.jmap.api.change.MailboxChangeRepository;
+import org.apache.james.jmap.cassandra.change.CassandraMailboxChangeRepository;
 import org.apache.james.mailbox.AttachmentContentLoader;
 import org.apache.james.mailbox.AttachmentManager;
 import org.apache.james.mailbox.Authenticator;
@@ -178,6 +180,7 @@ public class CassandraMailboxModule extends AbstractModule {
         bind(Authorizator.class).to(UserRepositoryAuthorizator.class);
         bind(MailboxManager.class).to(CassandraMailboxManager.class);
         bind(StoreMailboxManager.class).to(CassandraMailboxManager.class);
+        bind(MailboxChangeRepository.class).to(CassandraMailboxChangeRepository.class);
         bind(MailboxId.Factory.class).to(CassandraId.Factory.class);
         bind(MessageId.Factory.class).to(CassandraMessageId.Factory.class);
         bind(MessageIdManager.class).to(StoreMessageIdManager.class);
diff --git a/server/data/data-jmap-cassandra/src/main/java/org/apache/james/jmap/cassandra/change/CassandraMailboxChangeRepository.java b/server/data/data-jmap-cassandra/src/main/java/org/apache/james/jmap/cassandra/change/CassandraMailboxChangeRepository.java
new file mode 100644
index 0000000..65b6d3f
--- /dev/null
+++ b/server/data/data-jmap-cassandra/src/main/java/org/apache/james/jmap/cassandra/change/CassandraMailboxChangeRepository.java
@@ -0,0 +1,42 @@
+/****************************************************************
+ * 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.cassandra.change;
+
+import java.util.Optional;
+
+import org.apache.james.jmap.api.change.MailboxChange;
+import org.apache.james.jmap.api.change.MailboxChangeRepository;
+import org.apache.james.jmap.api.change.MailboxChanges;
+import org.apache.james.jmap.api.model.AccountId;
+
+import reactor.core.publisher.Mono;
+
+public class CassandraMailboxChangeRepository implements MailboxChangeRepository {
+
+    @Override
+    public Mono<Void> save(MailboxChange change) {
+        return Mono.empty();
+    }
+
+    @Override
+    public Mono<MailboxChanges> getSinceState(AccountId accountId, MailboxChange.State state, Optional<MailboxChange.Limit> maxIdsToReturn) {
+        return Mono.empty();
+    }
+}


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


[james-project] 07/07: JAMES-3468 Update Webadmin-cli user commands following Webadmin API change

Posted by bt...@apache.org.
This is an automated email from the ASF dual-hosted git repository.

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

commit 1c80dccfa91a954652f1991ddee5862ceb84a1dc
Author: quanth <hq...@linagora.com>
AuthorDate: Mon Dec 14 10:47:57 2020 +0700

    JAMES-3468 Update Webadmin-cli user commands following Webadmin API change
---
 .../apache/james/cli/user/UserCreateCommand.java   | 37 +++++++++-
 .../org/apache/james/httpclient/UserClient.java    |  4 ++
 .../java/org/apache/james/cli/UserManageTest.java  | 82 +++++++++++++---------
 3 files changed, 88 insertions(+), 35 deletions(-)

diff --git a/server/protocols/webadmin-cli/src/main/java/org/apache/james/cli/user/UserCreateCommand.java b/server/protocols/webadmin-cli/src/main/java/org/apache/james/cli/user/UserCreateCommand.java
index f694ed3..47328a3 100644
--- a/server/protocols/webadmin-cli/src/main/java/org/apache/james/cli/user/UserCreateCommand.java
+++ b/server/protocols/webadmin-cli/src/main/java/org/apache/james/cli/user/UserCreateCommand.java
@@ -35,9 +35,13 @@ public class UserCreateCommand implements Callable<Integer> {
 
     public static final int CREATED_CODE = 204;
     public static final int BAD_REQUEST_CODE = 400;
+    public static final int CONFLICT_CODE = 409;
 
     @CommandLine.ParentCommand UserCommand userCommand;
 
+    @CommandLine.Option(names = "--force", description = "Update a user's password")
+    boolean force;
+
     @CommandLine.Parameters(description = "Username")
     String userName;
 
@@ -46,14 +50,25 @@ public class UserCreateCommand implements Callable<Integer> {
 
     @Override
     public Integer call() {
+        UserClient userClient = userCommand.fullyQualifiedURL("/users");
+        if (force) {
+            return updateAUserPassword(userClient);
+        } else {
+            return createAUser(userClient);
+        }
+    }
+
+    private Integer createAUser(UserClient userClient) {
         try {
-            UserClient userClient = userCommand.fullyQualifiedURL("/users");
             Response rs = userClient.createAUser(userName, new UserPassword(new String(password)));
             if (rs.status() == CREATED_CODE) {
                 userCommand.out.println("The user was created successfully");
                 return WebAdminCli.CLI_FINISHED_SUCCEED;
             } else if (rs.status() == BAD_REQUEST_CODE) {
-                userCommand.out.println("The user name or the payload is invalid");
+                userCommand.err.println("The user name or the payload is invalid");
+                return WebAdminCli.CLI_FINISHED_FAILED;
+            } else if (rs.status() == CONFLICT_CODE) {
+                userCommand.err.println("The user already exists");
                 return WebAdminCli.CLI_FINISHED_FAILED;
             }
             return WebAdminCli.CLI_FINISHED_FAILED;
@@ -62,4 +77,22 @@ public class UserCreateCommand implements Callable<Integer> {
             return WebAdminCli.CLI_FINISHED_FAILED;
         }
     }
+
+    private Integer updateAUserPassword(UserClient userClient) {
+        try {
+            Response rs = userClient.updateAUserPassword(userName, new UserPassword(new String(password)));
+            if (rs.status() == CREATED_CODE) {
+                userCommand.out.println("The user's password was successfully updated");
+                return WebAdminCli.CLI_FINISHED_SUCCEED;
+            } else if (rs.status() == BAD_REQUEST_CODE) {
+                userCommand.err.println("The user name or the payload is invalid");
+                return WebAdminCli.CLI_FINISHED_FAILED;
+            }
+            return WebAdminCli.CLI_FINISHED_FAILED;
+        } catch (Exception e) {
+            e.printStackTrace(userCommand.err);
+            return WebAdminCli.CLI_FINISHED_FAILED;
+        }
+    }
+
 }
diff --git a/server/protocols/webadmin-cli/src/main/java/org/apache/james/httpclient/UserClient.java b/server/protocols/webadmin-cli/src/main/java/org/apache/james/httpclient/UserClient.java
index 9e3a290..96b6924 100644
--- a/server/protocols/webadmin-cli/src/main/java/org/apache/james/httpclient/UserClient.java
+++ b/server/protocols/webadmin-cli/src/main/java/org/apache/james/httpclient/UserClient.java
@@ -38,6 +38,10 @@ public interface UserClient {
     @Headers("Content-Type: application/json")
     Response createAUser(@Param("userName") String userName, UserPassword password);
 
+    @RequestLine("PUT /{userName}?force")
+    @Headers("Content-Type: application/json")
+    Response updateAUserPassword(@Param("userName") String userName, UserPassword password);
+
     @RequestLine("DELETE /{userToBeDeleted}")
     Response deleteAUser(@Param("userToBeDeleted") String userName);
 
diff --git a/server/protocols/webadmin-cli/src/test/java/org/apache/james/cli/UserManageTest.java b/server/protocols/webadmin-cli/src/test/java/org/apache/james/cli/UserManageTest.java
index 6308bab..7fe002a 100644
--- a/server/protocols/webadmin-cli/src/test/java/org/apache/james/cli/UserManageTest.java
+++ b/server/protocols/webadmin-cli/src/test/java/org/apache/james/cli/UserManageTest.java
@@ -33,6 +33,7 @@ import org.apache.james.util.Port;
 import org.apache.james.utils.DataProbeImpl;
 import org.apache.james.utils.WebAdminGuiceProbe;
 import org.apache.james.webadmin.integration.WebadminIntegrationTestModule;
+import org.junit.jupiter.api.BeforeEach;
 import org.junit.jupiter.api.Test;
 import org.junit.jupiter.api.extension.RegisterExtension;
 
@@ -49,11 +50,16 @@ public class UserManageTest {
     private final ByteArrayOutputStream outputStreamCaptor = new ByteArrayOutputStream();
     private final ByteArrayOutputStream errorStreamCaptor = new ByteArrayOutputStream();
     private DataProbeImpl dataProbe;
+    private Port port;
 
-    @Test
-    void userListShouldBeEmptyWhenNoUsers(GuiceJamesServer server) {
-        Port port = server.getProbe(WebAdminGuiceProbe.class).getWebAdminPort();
+    @BeforeEach
+    void setUp(GuiceJamesServer server) {
+        port = server.getProbe(WebAdminGuiceProbe.class).getWebAdminPort();
+        dataProbe = server.getProbe(DataProbeImpl.class);
+    }
 
+    @Test
+    void userListShouldBeEmptyWhenNoUsers() {
         int exitCode = WebAdminCli.executeFluent(new PrintStream(outputStreamCaptor), new PrintStream(errorStreamCaptor),
             "--url", "http://127.0.0.1:" + port.getValue(), "user", "list");
 
@@ -62,9 +68,7 @@ public class UserManageTest {
     }
 
     @Test
-    void userListShouldShowTwoAddedUser(GuiceJamesServer server) throws Exception {
-        Port port = server.getProbe(WebAdminGuiceProbe.class).getWebAdminPort();
-        dataProbe = server.getProbe(DataProbeImpl.class);
+    void userListShouldShowTwoAddedUser() throws Exception {
         dataProbe.fluent().addDomain("linagora.com")
             .addUser("hqtran@linagora.com", "123456")
             .addUser("testing@linagora.com", "123456");
@@ -77,9 +81,7 @@ public class UserManageTest {
     }
 
     @Test
-    void userCreateShouldAddValidUserSucceed(GuiceJamesServer server) throws Exception {
-        Port port = server.getProbe(WebAdminGuiceProbe.class).getWebAdminPort();
-        dataProbe = server.getProbe(DataProbeImpl.class);
+    void userCreateWithoutForceShouldAddValidUserSucceed() throws Exception {
         dataProbe.fluent().addDomain("linagora.com");
 
         int exitCode = WebAdminCli.executeFluent(new PrintStream(outputStreamCaptor), new PrintStream(errorStreamCaptor),
@@ -91,27 +93,49 @@ public class UserManageTest {
     }
 
     @Test
-    void userCreateShouldFailWithInvalidUsername(GuiceJamesServer server) throws Exception {
-        Port port = server.getProbe(WebAdminGuiceProbe.class).getWebAdminPort();
-        dataProbe = server.getProbe(DataProbeImpl.class);
-        dataProbe.fluent().addDomain("linagora.com");
-
+    void userCreateShouldFailWithInvalidUsername() throws Exception {
         int exitCode = WebAdminCli.executeFluent(new PrintStream(outputStreamCaptor), new PrintStream(errorStreamCaptor),
-            "--url", "http://127.0.0.1:" + port.getValue(), "user", "create", "hq/tran@linagora.com", "--password", "123456");
+            "--url", "http://127.0.0.1:" + port.getValue(), "user", "create", "hqtran@linagora.com", "--password", "123456");
 
         int exitCode1 = WebAdminCli.executeFluent(new PrintStream(outputStreamCaptor), new PrintStream(errorStreamCaptor),
-            "--url", "http://127.0.0.1:" + port.getValue(), "user", "create", "hqtran@google.com", "--password", "123456");
+            "--url", "http://127.0.0.1:" + port.getValue(), "user", "create", "--force", "hqtran@linagora.com", "--password", "123456");
 
         assertThat(exitCode).isEqualTo(1);
         assertThat(exitCode1).isEqualTo(1);
-        assertThat(outputStreamCaptor.toString().trim()).isEqualTo("The user name or the payload is invalid");
+        assertThat(errorStreamCaptor.toString().trim()).isEqualTo("The user name or the payload is invalid\nThe user name or the payload is invalid");
         assertThat(dataProbe.listUsers()).isEmpty();
     }
 
     @Test
-    void userDeleteWithAddedUserShouldSucceed(GuiceJamesServer server) throws Exception {
-        Port port = server.getProbe(WebAdminGuiceProbe.class).getWebAdminPort();
-        dataProbe = server.getProbe(DataProbeImpl.class);
+    void userCreateWithoutForceShouldNotAllowUpdateAUserPassword() throws Exception {
+        dataProbe.fluent().addDomain("linagora.com");
+
+        WebAdminCli.executeFluent(new PrintStream(new ByteArrayOutputStream()), new PrintStream(new ByteArrayOutputStream()),
+            "--url", "http://127.0.0.1:" + port.getValue(), "user", "create", "hqtran@linagora.com", "--password", "123456");
+
+        int exitCode = WebAdminCli.executeFluent(new PrintStream(outputStreamCaptor), new PrintStream(errorStreamCaptor),
+            "--url", "http://127.0.0.1:" + port.getValue(), "user", "create", "hqtran@linagora.com", "--password", "123457");
+
+        assertThat(exitCode).isEqualTo(1);
+        assertThat(errorStreamCaptor.toString().trim()).isEqualTo("The user already exists");
+    }
+
+    @Test
+    void userCreateWithForceShouldAllowUpdateAUserPassword() throws Exception {
+        dataProbe.fluent().addDomain("linagora.com");
+
+        WebAdminCli.executeFluent(new PrintStream(new ByteArrayOutputStream()), new PrintStream(new ByteArrayOutputStream()),
+            "--url", "http://127.0.0.1:" + port.getValue(), "user", "create", "hqtran@linagora.com", "--password", "123456");
+
+        int exitCode = WebAdminCli.executeFluent(new PrintStream(outputStreamCaptor), new PrintStream(errorStreamCaptor),
+            "--url", "http://127.0.0.1:" + port.getValue(), "user", "create", "--force", "hqtran@linagora.com", "--password", "123457");
+
+        assertThat(exitCode).isEqualTo(0);
+        assertThat(outputStreamCaptor.toString().trim()).isEqualTo("The user's password was successfully updated");
+    }
+
+    @Test
+    void userDeleteWithAddedUserShouldSucceed() throws Exception {
         dataProbe.fluent().addDomain("linagora.com")
             .addUser("hqtran@linagora.com", "123456");
 
@@ -123,10 +147,7 @@ public class UserManageTest {
     }
 
     @Test
-    void userDeleteWithNonExistingUserShouldSucceed(GuiceJamesServer server) throws Exception {
-        Port port = server.getProbe(WebAdminGuiceProbe.class).getWebAdminPort();
-        dataProbe = server.getProbe(DataProbeImpl.class);
-
+    void userDeleteWithNonExistingUserShouldSucceed() throws Exception {
         int exitCode = WebAdminCli.executeFluent(new PrintStream(outputStreamCaptor), new PrintStream(errorStreamCaptor),
             "--url", "http://127.0.0.1:" + port.getValue(), "user", "delete", "hqtran@linagora.com");
 
@@ -135,9 +156,7 @@ public class UserManageTest {
     }
 
     @Test
-    void userExistCommandWithNonExistingUserShouldFail(GuiceJamesServer server) {
-        Port port = server.getProbe(WebAdminGuiceProbe.class).getWebAdminPort();
-
+    void userExistCommandWithNonExistingUserShouldFail() {
         int exitCode = WebAdminCli.executeFluent(new PrintStream(outputStreamCaptor), new PrintStream(errorStreamCaptor),
             "--url", "http://127.0.0.1:" + port.getValue(), "user", "exist", "hqtran@linagora.com");
 
@@ -146,9 +165,7 @@ public class UserManageTest {
     }
 
     @Test
-    void userExistCommandWithInvalidUserNameShouldFail(GuiceJamesServer server) {
-        Port port = server.getProbe(WebAdminGuiceProbe.class).getWebAdminPort();
-
+    void userExistCommandWithInvalidUserNameShouldFail() {
         int exitCode = WebAdminCli.executeFluent(new PrintStream(outputStreamCaptor), new PrintStream(errorStreamCaptor),
             "--url", "http://127.0.0.1:" + port.getValue(), "user", "exist", "hqtran@@linagora.com");
 
@@ -165,9 +182,7 @@ public class UserManageTest {
     }
 
     @Test
-    void userExistCommandWithAddedUserShouldSucceed(GuiceJamesServer server) throws Exception {
-        Port port = server.getProbe(WebAdminGuiceProbe.class).getWebAdminPort();
-        dataProbe = server.getProbe(DataProbeImpl.class);
+    void userExistCommandWithAddedUserShouldSucceed() throws Exception {
         dataProbe.fluent().addDomain("linagora.com")
             .addUser("hqtran@linagora.com", "123456");
 
@@ -177,4 +192,5 @@ public class UserManageTest {
         assertThat(exitCode).isEqualTo(0);
         assertThat(outputStreamCaptor.toString().trim()).isEqualTo("hqtran@linagora.com exists");
     }
+
 }
\ No newline at end of file


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


[james-project] 06/07: JAMES-3468 Update manage webadmin documents

Posted by bt...@apache.org.
This is an automated email from the ASF dual-hosted git repository.

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

commit e7f1c76ec3efbc3a13b00e3f39ef14318413cf63
Author: quanth <hq...@linagora.com>
AuthorDate: Fri Dec 11 16:01:40 2020 +0700

    JAMES-3468 Update manage webadmin documents
---
 .../pages/distributed/operate/webadmin.adoc        | 25 ++++++++++++++++------
 server/protocols/webadmin-cli/README.md            | 17 ++++++++++++++-
 src/site/markdown/server/manage-webadmin.md        | 23 +++++++++++++++++---
 3 files changed, 54 insertions(+), 11 deletions(-)

diff --git a/docs/modules/servers/pages/distributed/operate/webadmin.adoc b/docs/modules/servers/pages/distributed/operate/webadmin.adoc
index e7f79c1..c88a5e5 100644
--- a/docs/modules/servers/pages/distributed/operate/webadmin.adoc
+++ b/docs/modules/servers/pages/distributed/operate/webadmin.adoc
@@ -450,8 +450,25 @@ Response codes:
 
 * 204: The user was successfully created
 * 400: The user name or the payload is invalid
+* 409: The user name already exists
 
-Note: if the user exists already, its password will be updated.
+Note: If the user exists already, its password cannot be updated using this.
+If you want to update a user's password, please have a look at *Update a user password* below.
+
+=== Updating a user password
+
+....
+curl -XPUT http://ip:port/users/usernameToBeUsed?force \
+  -d '{"password":"passwordToBeUsed"}' \
+  -H "Content-Type: application/json"
+....
+
+Response codes:
+
+- 204: The user's password was successfully updated
+- 400: The user name or the payload is invalid
+
+This also can be used to create a new user.
 
 === Testing a user existence
 
@@ -468,12 +485,6 @@ Response codes:
 * 400: The user name is invalid
 * 404: The user does not exist
 
-=== Updating a user password
-
-Same than Create, but a user need to exist.
-
-If the user do not exist, then it will be created.
-
 === Deleting a user
 
 ....
diff --git a/server/protocols/webadmin-cli/README.md b/server/protocols/webadmin-cli/README.md
index 14a48b7..6ea0203 100644
--- a/server/protocols/webadmin-cli/README.md
+++ b/server/protocols/webadmin-cli/README.md
@@ -62,6 +62,7 @@ Note: the command line before ENTITY will be documented as {cli}.
    - [Get the list of domains](#get-the-list-of-domains)
 - [Manage Users](#manage-users) 
    - [Create a user](#create-a-user)
+   - [Update a user password](#update-a-user-password)  
    - [Test a user existence](#test-a-user-existence)
    - [Delete a user](#delete-a-user)
    - [Get users list](#get-users-list)
@@ -141,7 +142,21 @@ Enter value for --password (Password):
 ```
 Resource name <username> representing valid users, hence it should match the criteria at [User Repositories documentation](https://james.apache.org/server/config-users.html)
 
-Note: if the user exists already, its password will be updated.
+Note: If the user exists already, its password cannot be updated using this.
+If you want to update a user's password, please have a look at [Update a user password](#update-a-user-password).
+
+### Update a user password
+
+```
+{cli} user create --force <username> --password
+```
+Then the Command Line will prompt users to enter password (password will not be printed on the screen for security):
+```
+Enter value for --password (Password):
+```
+Resource name <username> representing valid users, hence it should match the criteria at [User Repositories documentation](https://james.apache.org/server/config-users.html)
+
+Note: This also can be used to create a new user.
 
 ### Test a user existence
 
diff --git a/src/site/markdown/server/manage-webadmin.md b/src/site/markdown/server/manage-webadmin.md
index 7a5e2d5..cb6c067 100644
--- a/src/site/markdown/server/manage-webadmin.md
+++ b/src/site/markdown/server/manage-webadmin.md
@@ -299,8 +299,8 @@ Response codes:
 ## Administrating users
 
    - [Create a user](#Create_a_user)
-   - [Testing a user existence](#Testing_a_user_existence)
    - [Updating a user password](#Updating_a_user_password)
+   - [Testing a user existence](#Testing_a_user_existence)
    - [Deleting a user](#Deleting_a_user)
    - [Retrieving the user list](#Retrieving_the_user_list)
    - [Retrieving the list of allowed `From` headers for a given user](Retrieving_the_list_of_allowed_From_headers_for_a_given_user)
@@ -320,10 +320,27 @@ Response codes:
 
  - 204: The user was successfully created
  - 400: The user name or the payload is invalid
+ - 409: The user name already exists
+
+Note: If the user exists already, its password cannot be updated using this. 
+If you want to update a user's password, please have a look at [Update a user password](#Updating_a_user_password).
+
+### Updating a user password
+
+```
+curl -XPUT http://ip:port/users/usernameToBeUsed?force \
+  -d '{"password":"passwordToBeUsed"}' \ 
+  -H "Content-Type: application/json"
+```
+
+Response codes:
+
+- 204: The user's password was successfully updated
+- 400: The user name or the payload is invalid
 
-Note: if the user exists already, its password will be updated.
+This also can be used to create a new user.
 
-###Testing a user existence
+### Testing a user existence
 
 ```
 curl -XHEAD http://ip:port/users/usernameToBeUsed


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


[james-project] 03/07: JAMES-3461 MemoryMailboxChangeRepository should return state when no newer state

Posted by bt...@apache.org.
This is an automated email from the ASF dual-hosted git repository.

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

commit d38f8fe7a179f22ec3a9ab48683c00b540b3a85f
Author: LanKhuat <dl...@linagora.com>
AuthorDate: Tue Dec 8 11:16:09 2020 +0700

    JAMES-3461 MemoryMailboxChangeRepository should return state when no newer state
---
 .../org/apache/james/jmap/api/change/MailboxChanges.java    | 13 ++++++-------
 .../jmap/memory/change/MemoryMailboxChangeRepository.java   |  2 +-
 .../jmap/api/change/MailboxChangeRepositoryContract.java    | 11 +++++++++++
 3 files changed, 18 insertions(+), 8 deletions(-)

diff --git a/server/data/data-jmap/src/main/java/org/apache/james/jmap/api/change/MailboxChanges.java b/server/data/data-jmap/src/main/java/org/apache/james/jmap/api/change/MailboxChanges.java
index 0dc1bc9..a3f9366 100644
--- a/server/data/data-jmap/src/main/java/org/apache/james/jmap/api/change/MailboxChanges.java
+++ b/server/data/data-jmap/src/main/java/org/apache/james/jmap/api/change/MailboxChanges.java
@@ -40,14 +40,16 @@ public class MailboxChanges {
 
         public static class MailboxChangeCollector implements Collector<MailboxChange, MailboxChangesBuilder, MailboxChanges> {
             private final MailboxChange.Limit limit;
+            private final MailboxChange.State state;
 
-            public MailboxChangeCollector(MailboxChange.Limit limit) {
+            public MailboxChangeCollector(MailboxChange.State state, MailboxChange.Limit limit) {
                 this.limit = limit;
+                this.state = state;
             }
 
             @Override
             public Supplier<MailboxChangesBuilder> supplier() {
-                return () -> new MailboxChangesBuilder(limit);
+                return () -> new MailboxChangesBuilder(state, limit);
             }
 
             public BiConsumer<MailboxChangesBuilder, MailboxChange> accumulator() {
@@ -78,8 +80,9 @@ public class MailboxChanges {
         private Set<MailboxId> updated;
         private Set<MailboxId> destroyed;
 
-        public MailboxChangesBuilder(MailboxChange.Limit limit) {
+        public MailboxChangesBuilder(MailboxChange.State state, MailboxChange.Limit limit) {
             this.limit = limit;
+            this.state = state;
             this.hasMoreChanges = false;
             this.canAddMoreItem = true;
             this.created = new HashSet<>();
@@ -132,10 +135,6 @@ public class MailboxChanges {
         this.destroyed = destroyed;
     }
 
-    public MailboxChangesBuilder build(MailboxChange.Limit limit) {
-        return new MailboxChangesBuilder(limit);
-    }
-
     public MailboxChange.State getNewState() {
         return newState;
     }
diff --git a/server/data/data-jmap/src/main/java/org/apache/james/jmap/memory/change/MemoryMailboxChangeRepository.java b/server/data/data-jmap/src/main/java/org/apache/james/jmap/memory/change/MemoryMailboxChangeRepository.java
index e920904..e9a2a79 100644
--- a/server/data/data-jmap/src/main/java/org/apache/james/jmap/memory/change/MemoryMailboxChangeRepository.java
+++ b/server/data/data-jmap/src/main/java/org/apache/james/jmap/memory/change/MemoryMailboxChangeRepository.java
@@ -65,7 +65,7 @@ public class MemoryMailboxChangeRepository implements MailboxChangeRepository {
             .flatMapMany(currentState -> Flux.fromIterable(mailboxChangeMap.get(accountId))
                 .filter(change -> change.getDate().isAfter(currentState.getDate()))
                 .sort(Comparator.comparing(MailboxChange::getDate)))
-            .collect(new MailboxChangeCollector(maxChanges.orElse(DEFAULT_NUMBER_OF_CHANGES)));
+            .collect(new MailboxChangeCollector(state, maxChanges.orElse(DEFAULT_NUMBER_OF_CHANGES)));
     }
 
     private Mono<MailboxChange> findByState(AccountId accountId, State state) {
diff --git a/server/data/data-jmap/src/test/java/org/apache/james/jmap/api/change/MailboxChangeRepositoryContract.java b/server/data/data-jmap/src/test/java/org/apache/james/jmap/api/change/MailboxChangeRepositoryContract.java
index 66f27e3..2f3209b 100644
--- a/server/data/data-jmap/src/test/java/org/apache/james/jmap/api/change/MailboxChangeRepositoryContract.java
+++ b/server/data/data-jmap/src/test/java/org/apache/james/jmap/api/change/MailboxChangeRepositoryContract.java
@@ -100,6 +100,17 @@ public interface MailboxChangeRepositoryContract {
     }
 
     @Test
+    default void getChangesShouldReturnCurrentStateWhenNoNewerState() {
+        MailboxChangeRepository repository = mailboxChangeRepository();
+
+        MailboxChange oldState = MailboxChange.of(ACCOUNT_ID, STATE_0, DATE, ImmutableList.of(TestId.of(1)), ImmutableList.of(), ImmutableList.of());
+        repository.save(oldState);
+
+        assertThat(repository.getSinceState(ACCOUNT_ID, STATE_0, Optional.empty()).block().getNewState())
+            .isEqualTo(oldState.getState());
+    }
+
+    @Test
     default void getChangesShouldLimitChanges() {
         MailboxChangeRepository repository = mailboxChangeRepository();
 


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


[james-project] 01/07: JAMES-3461 Add State class, replace literal values with fixture objects

Posted by bt...@apache.org.
This is an automated email from the ASF dual-hosted git repository.

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

commit 563883f66066762cd69c328eb29b90eccda54b4e
Author: LanKhuat <dl...@linagora.com>
AuthorDate: Fri Dec 4 17:21:00 2020 +0700

    JAMES-3461 Add State class, replace literal values with fixture objects
---
 .../rfc8621/contract/BackReferenceContract.scala   |  28 +-
 .../jmap/rfc8621/contract/EchoMethodContract.scala |   7 +-
 .../rfc8621/contract/EmailChangesContract.scala    |  22 +-
 .../rfc8621/contract/EmailGetMethodContract.scala  | 175 ++++----
 .../contract/EmailQueryMethodContract.scala        |  89 ++--
 .../rfc8621/contract/EmailSetMethodContract.scala  | 112 ++---
 .../EmailSubmissionSetMethodContract.scala         |  18 +-
 .../james/jmap/rfc8621/contract/Fixture.scala      |   5 +-
 .../rfc8621/contract/IdentityGetContract.scala     |  30 +-
 .../contract/MailboxGetMethodContract.scala        |  60 +--
 .../contract/MailboxQueryMethodContract.scala      |  26 +-
 .../contract/MailboxSetMethodContract.scala        | 494 +++++++++++----------
 .../rfc8621/contract/SessionRoutesContract.scala   |   2 +-
 .../rfc8621/contract/ThreadChangesContract.scala   |  22 +-
 .../jmap/rfc8621/contract/ThreadGetContract.scala  |  13 +-
 .../VacationResponseGetMethodContract.scala        |  60 +--
 .../VacationResponseSetMethodContract.scala        |  64 +--
 .../jmap-rfc-8621/doc/specs/spec/jmap/api.mdown    |   2 +-
 .../doc/specs/spec/jmap/session.mdown              |   2 +-
 .../apache/james/jmap/core/ResponseObject.scala    |   5 +-
 .../scala/org/apache/james/jmap/core/Session.scala |  12 +-
 .../james/jmap/json/EmailGetSerializer.scala       |   4 +-
 .../james/jmap/json/EmailSetSerializer.scala       |   4 +-
 .../jmap/json/EmailSubmissionSetSerializer.scala   |   3 +-
 .../james/jmap/json/IdentitySerializer.scala       |   3 +-
 .../apache/james/jmap/json/MailboxSerializer.scala |   9 +-
 .../james/jmap/json/ResponseSerializer.scala       |   7 +
 .../james/jmap/json/VacationSerializer.scala       |   3 +-
 .../org/apache/james/jmap/mail/EmailGet.scala      |   3 +-
 .../org/apache/james/jmap/mail/EmailSet.scala      |   3 +-
 .../james/jmap/mail/EmailSubmissionSet.scala       |   3 +-
 .../org/apache/james/jmap/mail/Identity.scala      |   3 +-
 .../org/apache/james/jmap/mail/MailboxGet.scala    |   3 +-
 .../org/apache/james/jmap/mail/MailboxSet.scala    |   3 +-
 .../james/jmap/vacation/VacationResponseGet.scala  |   3 +-
 .../james/jmap/vacation/VacationResponseSet.scala  |   3 +-
 .../jmap/json/MailboxGetSerializationTest.scala    |   7 +-
 .../json/ResponseObjectSerializationTest.scala     |  22 +-
 .../james/jmap/json/SessionSerializationTest.scala |  10 +-
 .../VacationResponseGetSerializationTest.scala     |   9 +-
 .../james/jmap/routes/JMAPApiRoutesTest.scala      |  13 +-
 .../james/jmap/routes/SessionRoutesTest.scala      |   3 +-
 42 files changed, 704 insertions(+), 665 deletions(-)

diff --git a/server/protocols/jmap-rfc-8621-integration-tests/jmap-rfc-8621-integration-tests-common/src/main/scala/org/apache/james/jmap/rfc8621/contract/BackReferenceContract.scala b/server/protocols/jmap-rfc-8621-integration-tests/jmap-rfc-8621-integration-tests-common/src/main/scala/org/apache/james/jmap/rfc8621/contract/BackReferenceContract.scala
index 5b23b53..27cc525 100644
--- a/server/protocols/jmap-rfc-8621-integration-tests/jmap-rfc-8621-integration-tests-common/src/main/scala/org/apache/james/jmap/rfc8621/contract/BackReferenceContract.scala
+++ b/server/protocols/jmap-rfc-8621-integration-tests/jmap-rfc-8621-integration-tests-common/src/main/scala/org/apache/james/jmap/rfc8621/contract/BackReferenceContract.scala
@@ -27,6 +27,8 @@ import net.javacrumbs.jsonunit.core.Option
 import net.javacrumbs.jsonunit.core.internal.Options
 import org.apache.http.HttpStatus.SC_OK
 import org.apache.james.GuiceJamesServer
+import org.apache.james.jmap.core.ResponseObject.SESSION_STATE
+import org.apache.james.jmap.core.State.INSTANCE
 import org.apache.james.jmap.http.UserCredential
 import org.apache.james.jmap.rfc8621.contract.Fixture._
 import org.apache.james.mailbox.MessageManager.AppendCommand
@@ -89,13 +91,13 @@ trait BackReferenceContract {
 
     assertThatJson(response).isEqualTo(
       s"""{
-         |    "sessionState": "75128aab4b1b",
+         |    "sessionState": "${SESSION_STATE.value}",
          |    "methodResponses": [
          |        [
          |            "Mailbox/get",
          |            {
          |                "accountId": "29883977c13473ae7cb7678ef767cbfbaffc8a44a6e463d971d23a65c1dc4af6",
-         |                "state": "000001",
+         |                "state": "${INSTANCE.value}",
          |                "list": [
          |                    {"id": "1"},
          |                    {"id": "5"},
@@ -112,7 +114,7 @@ trait BackReferenceContract {
          |            "Mailbox/get",
          |            {
          |                "accountId": "29883977c13473ae7cb7678ef767cbfbaffc8a44a6e463d971d23a65c1dc4af6",
-         |                "state": "000001",
+         |                "state": "${INSTANCE.value}",
          |                "list": [
          |                    {"id": "1"},
          |                    {"id": "5"},
@@ -168,13 +170,13 @@ trait BackReferenceContract {
 
     assertThatJson(response).isEqualTo(
       s"""{
-         |    "sessionState": "75128aab4b1b",
+         |    "sessionState": "${SESSION_STATE.value}",
          |    "methodResponses": [
          |        [
          |            "Mailbox/get",
          |            {
          |                "accountId": "29883977c13473ae7cb7678ef767cbfbaffc8a44a6e463d971d23a65c1dc4af6",
-         |                "state": "000001",
+         |                "state": "${INSTANCE.value}",
          |                "list": [
          |                    {"id": "1"},
          |                    {"id": "5"},
@@ -238,13 +240,13 @@ trait BackReferenceContract {
 
     assertThatJson(response).isEqualTo(
       s"""{
-         |    "sessionState": "75128aab4b1b",
+         |    "sessionState": "${SESSION_STATE.value}",
          |    "methodResponses": [
          |        [
          |            "Mailbox/get",
          |            {
          |                "accountId": "29883977c13473ae7cb7678ef767cbfbaffc8a44a6e463d971d23a65c1dc4af6",
-         |                "state": "000001",
+         |                "state": "${INSTANCE.value}",
          |                "list": [
          |                    {"id": "1"},
          |                    {"id": "5"},
@@ -308,13 +310,13 @@ trait BackReferenceContract {
 
     assertThatJson(response).isEqualTo(
       s"""{
-         |    "sessionState": "75128aab4b1b",
+         |    "sessionState": "${SESSION_STATE.value}",
          |    "methodResponses": [
          |        [
          |            "Mailbox/get",
          |            {
          |                "accountId": "29883977c13473ae7cb7678ef767cbfbaffc8a44a6e463d971d23a65c1dc4af6",
-         |                "state": "000001",
+         |                "state": "${INSTANCE.value}",
          |                "list": [
          |                    {"id": "1"},
          |                    {"id": "5"},
@@ -378,13 +380,13 @@ trait BackReferenceContract {
 
     assertThatJson(response).isEqualTo(
       s"""{
-         |    "sessionState": "75128aab4b1b",
+         |    "sessionState": "${SESSION_STATE.value}",
          |    "methodResponses": [
          |        [
          |            "Mailbox/get",
          |            {
          |                "accountId": "29883977c13473ae7cb7678ef767cbfbaffc8a44a6e463d971d23a65c1dc4af6",
-         |                "state": "000001",
+         |                "state": "${INSTANCE.value}",
          |                "list": [
          |                    {"id": "1"},
          |                    {"id": "5"},
@@ -487,7 +489,7 @@ trait BackReferenceContract {
       .withOptions(new Options(Option.IGNORING_ARRAY_ORDER))
       .isEqualTo(
       s"""{
-         |    "sessionState": "75128aab4b1b",
+         |    "sessionState": "${SESSION_STATE.value}",
          |    "methodResponses": [
          |        [
          |            "Mailbox/query",
@@ -517,7 +519,7 @@ trait BackReferenceContract {
          |            "Email/get",
          |            {
          |                "accountId": "29883977c13473ae7cb7678ef767cbfbaffc8a44a6e463d971d23a65c1dc4af6",
-         |                "state": "000001",
+         |                "state": "${INSTANCE.value}",
          |                "list": [
          |                    {"id": "${messageId3.serialize}", "subject": "message 3"},
          |                    {"id": "${messageId2.serialize}", "subject": "message 2"},
diff --git a/server/protocols/jmap-rfc-8621-integration-tests/jmap-rfc-8621-integration-tests-common/src/main/scala/org/apache/james/jmap/rfc8621/contract/EchoMethodContract.scala b/server/protocols/jmap-rfc-8621-integration-tests/jmap-rfc-8621-integration-tests-common/src/main/scala/org/apache/james/jmap/rfc8621/contract/EchoMethodContract.scala
index bf95d32..7b27d18 100644
--- a/server/protocols/jmap-rfc-8621-integration-tests/jmap-rfc-8621-integration-tests-common/src/main/scala/org/apache/james/jmap/rfc8621/contract/EchoMethodContract.scala
+++ b/server/protocols/jmap-rfc-8621-integration-tests/jmap-rfc-8621-integration-tests-common/src/main/scala/org/apache/james/jmap/rfc8621/contract/EchoMethodContract.scala
@@ -24,6 +24,7 @@ import io.restassured.http.ContentType.JSON
 import net.javacrumbs.jsonunit.assertj.JsonAssertions.assertThatJson
 import org.apache.http.HttpStatus.SC_OK
 import org.apache.james.GuiceJamesServer
+import org.apache.james.jmap.core.ResponseObject.SESSION_STATE
 import org.apache.james.jmap.http.UserCredential
 import org.apache.james.jmap.rfc8621.contract.EchoMethodContract._
 import org.apache.james.jmap.rfc8621.contract.Fixture._
@@ -57,8 +58,8 @@ object EchoMethodContract {
       |}""".stripMargin
 
   private val RESPONSE_OBJECT_WITH_UNSUPPORTED_METHOD: String =
-    """{
-      |  "sessionState": "75128aab4b1b",
+    s"""{
+      |  "sessionState": "${SESSION_STATE.value}",
       |  "methodResponses": [
       |    [
       |      "Core/echo",
@@ -145,7 +146,7 @@ trait EchoMethodContract {
 
     assertThatJson(response).isEqualTo(
       s"""{
-         |  "sessionState": "75128aab4b1b",
+         |  "sessionState": "${SESSION_STATE.value}",
          |  "methodResponses": [[
          |    "error",
          |    {
diff --git a/server/protocols/jmap-rfc-8621-integration-tests/jmap-rfc-8621-integration-tests-common/src/main/scala/org/apache/james/jmap/rfc8621/contract/EmailChangesContract.scala b/server/protocols/jmap-rfc-8621-integration-tests/jmap-rfc-8621-integration-tests-common/src/main/scala/org/apache/james/jmap/rfc8621/contract/EmailChangesContract.scala
index d5ea35b..d4d521b 100644
--- a/server/protocols/jmap-rfc-8621-integration-tests/jmap-rfc-8621-integration-tests-common/src/main/scala/org/apache/james/jmap/rfc8621/contract/EmailChangesContract.scala
+++ b/server/protocols/jmap-rfc-8621-integration-tests/jmap-rfc-8621-integration-tests-common/src/main/scala/org/apache/james/jmap/rfc8621/contract/EmailChangesContract.scala
@@ -25,6 +25,8 @@ import io.restassured.http.ContentType.JSON
 import net.javacrumbs.jsonunit.assertj.JsonAssertions.assertThatJson
 import org.apache.http.HttpStatus.SC_OK
 import org.apache.james.GuiceJamesServer
+import org.apache.james.jmap.core.ResponseObject.SESSION_STATE
+import org.apache.james.jmap.core.State.INSTANCE
 import org.apache.james.jmap.http.UserCredential
 import org.apache.james.jmap.rfc8621.contract.Fixture.{ACCEPT_RFC8621_VERSION_HEADER, BOB, BOB_PASSWORD, DOMAIN, authScheme, baseRequestSpecBuilder}
 import org.apache.james.utils.DataProbeImpl
@@ -53,7 +55,7 @@ trait EmailChangesContract {
          |    "Email/changes",
          |    {
          |      "accountId": "29883977c13473ae7cb7678ef767cbfbaffc8a44a6e463d971d23a65c1dc4af6",
-         |      "sinceState": "any-state"
+         |      "sinceState": "2c9f1b12-b35a-43e6-9af2-0106fb53a941"
          |    },
          |    "c1"]]
          |}""".stripMargin
@@ -72,8 +74,8 @@ trait EmailChangesContract {
 
     assertThatJson(response)
       .isEqualTo(
-        """{
-          |    "sessionState": "75128aab4b1b",
+        s"""{
+          |    "sessionState": "${SESSION_STATE.value}",
           |    "methodResponses": [
           |        [
           |            "error",
@@ -96,7 +98,7 @@ trait EmailChangesContract {
          |    "Email/changes",
          |    {
          |      "accountId": "bad",
-         |      "sinceState": "any-state"
+         |      "sinceState": "${INSTANCE.value}"
          |    },
          |    "c1"]]
          |}""".stripMargin
@@ -115,8 +117,8 @@ trait EmailChangesContract {
 
     assertThatJson(response)
       .isEqualTo(
-        """{
-          |    "sessionState": "75128aab4b1b",
+        s"""{
+          |    "sessionState": "${SESSION_STATE.value}",
           |    "methodResponses": [
           |        [
           |            "error",
@@ -138,7 +140,7 @@ trait EmailChangesContract {
          |    "Thread/changes",
          |    {
          |      "accountId": "29883977c13473ae7cb7678ef767cbfbaffc8a44a6e463d971d23a65c1dc4af6",
-         |      "sinceState": "000001"
+         |      "sinceState": "${INSTANCE.value}"
          |    },
          |    "c1"]]
          |}""".stripMargin
@@ -158,10 +160,10 @@ trait EmailChangesContract {
     assertThatJson(response)
       .inPath("methodResponses[0][1]")
       .isEqualTo(
-        """{
+        s"""{
           |  "accountId": "29883977c13473ae7cb7678ef767cbfbaffc8a44a6e463d971d23a65c1dc4af6",
-          |  "oldState": "000001",
-          |  "newState": "000001",
+          |  "oldState": "${INSTANCE.value}",
+          |  "newState": "${INSTANCE.value}",
           |  "hasMoreChanges": false,
           |  "created": [],
           |  "updated": [],
diff --git a/server/protocols/jmap-rfc-8621-integration-tests/jmap-rfc-8621-integration-tests-common/src/main/scala/org/apache/james/jmap/rfc8621/contract/EmailGetMethodContract.scala b/server/protocols/jmap-rfc-8621-integration-tests/jmap-rfc-8621-integration-tests-common/src/main/scala/org/apache/james/jmap/rfc8621/contract/EmailGetMethodContract.scala
index 2be3f41..41ca8ec 100644
--- a/server/protocols/jmap-rfc-8621-integration-tests/jmap-rfc-8621-integration-tests-common/src/main/scala/org/apache/james/jmap/rfc8621/contract/EmailGetMethodContract.scala
+++ b/server/protocols/jmap-rfc-8621-integration-tests/jmap-rfc-8621-integration-tests-common/src/main/scala/org/apache/james/jmap/rfc8621/contract/EmailGetMethodContract.scala
@@ -32,6 +32,8 @@ import net.javacrumbs.jsonunit.core.Option.IGNORING_ARRAY_ORDER
 import net.javacrumbs.jsonunit.core.internal.Options
 import org.apache.http.HttpStatus.SC_OK
 import org.apache.james.GuiceJamesServer
+import org.apache.james.jmap.core.ResponseObject.SESSION_STATE
+import org.apache.james.jmap.core.State.INSTANCE
 import org.apache.james.jmap.http.UserCredential
 import org.apache.james.jmap.rfc8621.contract.EmailGetMethodContract.createTestMessage
 import org.apache.james.jmap.rfc8621.contract.Fixture.{ACCEPT_RFC8621_VERSION_HEADER, ALICE, ANDRE, BOB, BOB_PASSWORD, DOMAIN, authScheme, baseRequestSpecBuilder}
@@ -100,7 +102,7 @@ trait EmailGetMethodContract {
 
     assertThatJson(response).isEqualTo(
       s"""{
-         |    "sessionState": "75128aab4b1b",
+         |    "sessionState": "${SESSION_STATE.value}",
          |    "methodResponses": [[
          |            "error",
          |            {
@@ -138,7 +140,7 @@ trait EmailGetMethodContract {
 
     assertThatJson(response).isEqualTo(
       s"""{
-         |    "sessionState": "75128aab4b1b",
+         |    "sessionState": "${SESSION_STATE.value}",
          |    "methodResponses": [[
          |            "error",
          |            {
@@ -177,12 +179,12 @@ trait EmailGetMethodContract {
 
     assertThatJson(response).isEqualTo(
       s"""{
-         |    "sessionState": "75128aab4b1b",
+         |    "sessionState": "${SESSION_STATE.value}",
          |    "methodResponses": [[
          |            "Email/get",
          |            {
          |                "accountId": "29883977c13473ae7cb7678ef767cbfbaffc8a44a6e463d971d23a65c1dc4af6",
-         |                "state": "000001",
+         |                "state": "${INSTANCE.value}",
          |                "list": [],
          |                "notFound": []
          |            },
@@ -218,12 +220,12 @@ trait EmailGetMethodContract {
 
     assertThatJson(response).isEqualTo(
       s"""{
-         |    "sessionState": "75128aab4b1b",
+         |    "sessionState": "${SESSION_STATE.value}",
          |    "methodResponses": [[
          |            "Email/get",
          |            {
          |                "accountId": "29883977c13473ae7cb7678ef767cbfbaffc8a44a6e463d971d23a65c1dc4af6",
-         |                "state": "000001",
+         |                "state": "${INSTANCE.value}",
          |                "list": [],
          |                "notFound": ["invalid"]
          |            },
@@ -262,12 +264,12 @@ trait EmailGetMethodContract {
 
     assertThatJson(response).isEqualTo(
       s"""{
-         |    "sessionState": "75128aab4b1b",
+         |    "sessionState": "${SESSION_STATE.value}",
          |    "methodResponses": [[
          |            "Email/get",
          |            {
          |                "accountId": "29883977c13473ae7cb7678ef767cbfbaffc8a44a6e463d971d23a65c1dc4af6",
-         |                "state": "000001",
+         |                "state": "${INSTANCE.value}",
          |                "list": [],
          |                "notFound": ["${messageId.serialize}"]
          |            },
@@ -316,12 +318,12 @@ trait EmailGetMethodContract {
 
     assertThatJson(response).isEqualTo(
       s"""{
-         |    "sessionState": "75128aab4b1b",
+         |    "sessionState": "${SESSION_STATE.value}",
          |    "methodResponses": [[
          |            "Email/get",
          |            {
          |                "accountId": "29883977c13473ae7cb7678ef767cbfbaffc8a44a6e463d971d23a65c1dc4af6",
-         |                "state": "000001",
+         |                "state": "${INSTANCE.value}",
          |                "list": [{
          |                        "id": "${messageId.serialize}",
          |                        "size": 85
@@ -2285,12 +2287,12 @@ trait EmailGetMethodContract {
       .withOptions(new Options(IGNORING_ARRAY_ORDER))
       .isEqualTo(
       s"""{
-         |    "sessionState": "75128aab4b1b",
+         |    "sessionState": "${SESSION_STATE.value}",
          |    "methodResponses": [[
          |            "Email/get",
          |            {
          |                "accountId": "29883977c13473ae7cb7678ef767cbfbaffc8a44a6e463d971d23a65c1dc4af6",
-         |                "state": "000001",
+         |                "state": "${SESSION_STATE.value}",
          |                "list": [ {
          |                        "id": "${messageId.serialize}",
          |                        "size": 85
@@ -2345,12 +2347,12 @@ trait EmailGetMethodContract {
 
     assertThatJson(response).isEqualTo(
       s"""{
-         |    "sessionState": "75128aab4b1b",
+         |    "sessionState": "${SESSION_STATE.value}",
          |    "methodResponses": [[
          |            "Email/get",
          |            {
          |                "accountId": "29883977c13473ae7cb7678ef767cbfbaffc8a44a6e463d971d23a65c1dc4af6",
-         |                "state": "000001",
+         |                "state": "${INSTANCE.value}",
          |                "list": [
          |                    {
          |                        "id": "${messageId1.serialize()}",
@@ -2405,13 +2407,13 @@ trait EmailGetMethodContract {
 
     assertThatJson(response).isEqualTo(
       s"""{
-         |    "sessionState": "75128aab4b1b",
+         |    "sessionState": "${SESSION_STATE.value}",
          |    "methodResponses": [
          |        [
          |            "Email/get",
          |            {
          |                "accountId": "29883977c13473ae7cb7678ef767cbfbaffc8a44a6e463d971d23a65c1dc4af6",
-         |                "state": "000001",
+         |                "state": "${INSTANCE.value}",
          |                "list": [
          |                    {
          |                        "threadId": "${messageId.serialize}",
@@ -2528,12 +2530,12 @@ trait EmailGetMethodContract {
 
     assertThatJson(response).isEqualTo(
       s"""{
-         |    "sessionState": "75128aab4b1b",
+         |    "sessionState": "${SESSION_STATE.value}",
          |    "methodResponses": [[
          |            "Email/get",
          |            {
          |                "accountId": "29883977c13473ae7cb7678ef767cbfbaffc8a44a6e463d971d23a65c1dc4af6",
-         |                "state": "000001",
+         |                "state": "${INSTANCE.value}",
          |                "list": [{
          |                        "id": "${messageId.serialize}",
          |                        "size": 85
@@ -2585,12 +2587,12 @@ trait EmailGetMethodContract {
 
     assertThatJson(response).isEqualTo(
       s"""{
-         |    "sessionState": "75128aab4b1b",
+         |    "sessionState": "${SESSION_STATE.value}",
          |    "methodResponses": [[
          |            "Email/get",
          |            {
          |                "accountId": "29883977c13473ae7cb7678ef767cbfbaffc8a44a6e463d971d23a65c1dc4af6",
-         |                "state": "000001",
+         |                "state": "${INSTANCE.value}",
          |                "list": [{
          |                        "id": "${messageId.serialize}"
          |                    }],
@@ -2641,12 +2643,12 @@ trait EmailGetMethodContract {
 
     assertThatJson(response).isEqualTo(
       s"""{
-         |    "sessionState": "75128aab4b1b",
+         |    "sessionState": "${SESSION_STATE.value}",
          |    "methodResponses": [[
          |            "Email/get",
          |            {
          |                "accountId": "29883977c13473ae7cb7678ef767cbfbaffc8a44a6e463d971d23a65c1dc4af6",
-         |                "state": "000001",
+         |                "state": "${INSTANCE.value}",
          |                "list": [{
          |                        "id": "${messageId.serialize}"
          |                    }],
@@ -2697,12 +2699,12 @@ trait EmailGetMethodContract {
 
     assertThatJson(response).isEqualTo(
       s"""{
-         |    "sessionState": "75128aab4b1b",
+         |    "sessionState": "${SESSION_STATE.value}",
          |    "methodResponses": [[
          |            "Email/get",
          |            {
          |                "accountId": "29883977c13473ae7cb7678ef767cbfbaffc8a44a6e463d971d23a65c1dc4af6",
-         |                "state": "000001",
+         |                "state": "${INSTANCE.value}",
          |                "list": [{
          |                        "id": "${messageId.serialize}",
          |                        "size": 85
@@ -2754,7 +2756,7 @@ trait EmailGetMethodContract {
 
     assertThatJson(response).isEqualTo(
       s"""{
-         |    "sessionState": "75128aab4b1b",
+         |    "sessionState": "${SESSION_STATE.value}",
          |    "methodResponses": [[
          |            "error",
          |            {
@@ -2796,12 +2798,12 @@ trait EmailGetMethodContract {
 
     assertThatJson(response).isEqualTo(
       s"""{
-         |    "sessionState": "75128aab4b1b",
+         |    "sessionState": "${SESSION_STATE.value}",
          |    "methodResponses": [[
          |            "Email/get",
          |            {
          |                "accountId": "29883977c13473ae7cb7678ef767cbfbaffc8a44a6e463d971d23a65c1dc4af6",
-         |                "state": "000001",
+         |                "state": "${INSTANCE.value}",
          |                "list": [],
          |                "notFound": ["${messageId.serialize}"]
          |            },
@@ -2851,12 +2853,12 @@ trait EmailGetMethodContract {
 
     assertThatJson(response).isEqualTo(
       s"""{
-         |    "sessionState": "75128aab4b1b",
+         |    "sessionState": "${SESSION_STATE.value}",
          |    "methodResponses": [[
          |            "Email/get",
          |            {
          |                "accountId": "29883977c13473ae7cb7678ef767cbfbaffc8a44a6e463d971d23a65c1dc4af6",
-         |                "state": "000001",
+         |                "state": "${INSTANCE.value}",
          |                "list": [],
          |                "notFound": ["${messageId.serialize}"]
          |            },
@@ -2909,12 +2911,12 @@ trait EmailGetMethodContract {
 
     assertThatJson(response).isEqualTo(
       s"""{
-         |    "sessionState": "75128aab4b1b",
+         |    "sessionState": "${SESSION_STATE.value}",
          |    "methodResponses": [[
          |            "Email/get",
          |            {
          |                "accountId": "29883977c13473ae7cb7678ef767cbfbaffc8a44a6e463d971d23a65c1dc4af6",
-         |                "state": "000001",
+         |                "state": "${INSTANCE.value}",
          |                "list": [{
          |                        "id": "${messageId.serialize}",
          |                        "size": 85
@@ -2969,12 +2971,12 @@ trait EmailGetMethodContract {
 
     assertThatJson(response).isEqualTo(
       s"""{
-         |    "sessionState": "75128aab4b1b",
+         |    "sessionState": "${SESSION_STATE.value}",
          |    "methodResponses": [[
          |            "Email/get",
          |            {
          |                "accountId": "29883977c13473ae7cb7678ef767cbfbaffc8a44a6e463d971d23a65c1dc4af6",
-         |                "state": "000001",
+         |                "state": "${INSTANCE.value}",
          |                "list": [],
          |                "notFound": ["${messageId.serialize}"]
          |            },
@@ -3009,7 +3011,7 @@ trait EmailGetMethodContract {
 
     assertThatJson(response).isEqualTo(
       s"""{
-         |  "sessionState": "75128aab4b1b",
+         |  "sessionState": "${SESSION_STATE.value}",
          |  "methodResponses": [[
          |    "error",
          |    {
@@ -3046,7 +3048,7 @@ trait EmailGetMethodContract {
 
     assertThatJson(response).isEqualTo(
       s"""{
-         |  "sessionState": "75128aab4b1b",
+         |  "sessionState": "${SESSION_STATE.value}",
          |  "methodResponses": [[
          |    "error",
          |    {
@@ -3099,12 +3101,12 @@ trait EmailGetMethodContract {
 
     assertThatJson(response).isEqualTo(
       s"""{
-         |    "sessionState": "75128aab4b1b",
+         |    "sessionState": "${SESSION_STATE.value}",
          |    "methodResponses": [[
          |            "Email/get",
          |            {
          |                "accountId": "29883977c13473ae7cb7678ef767cbfbaffc8a44a6e463d971d23a65c1dc4af6",
-         |                "state": "000001",
+         |                "state": "${INSTANCE.value}",
          |                "list": [
          |                    {
          |                        "id": "${messageId.serialize}",
@@ -3350,13 +3352,13 @@ trait EmailGetMethodContract {
 
     assertThatJson(response).isEqualTo(
       s"""{
-         |    "sessionState": "75128aab4b1b",
+         |    "sessionState": "${SESSION_STATE.value}",
          |    "methodResponses": [
          |        [
          |            "Email/get",
          |            {
          |                "accountId": "29883977c13473ae7cb7678ef767cbfbaffc8a44a6e463d971d23a65c1dc4af6",
-         |                "state": "000001",
+         |                "state": "${INSTANCE.value}",
          |                "list": [
          |                    {
          |                        "id": "${messageId.serialize}",
@@ -3421,12 +3423,12 @@ trait EmailGetMethodContract {
 
     assertThatJson(response).isEqualTo(
       s"""{
-         |    "sessionState": "75128aab4b1b",
+         |    "sessionState": "${SESSION_STATE.value}",
          |    "methodResponses": [[
          |            "Email/get",
          |            {
          |                "accountId": "29883977c13473ae7cb7678ef767cbfbaffc8a44a6e463d971d23a65c1dc4af6",
-         |                "state": "000001",
+         |                "state": "${INSTANCE.value}",
          |                "list": [
          |                    {
          |                        "id": "${messageId.serialize}",
@@ -3484,7 +3486,7 @@ trait EmailGetMethodContract {
 
     assertThatJson(response).isEqualTo(
       s"""{
-         |    "sessionState": "75128aab4b1b",
+         |    "sessionState": "${SESSION_STATE.value}",
          |    "methodResponses": [
          |        [
          |            "error",
@@ -3540,13 +3542,13 @@ trait EmailGetMethodContract {
 
     assertThatJson(response).isEqualTo(
       s"""{
-         |    "sessionState": "75128aab4b1b",
+         |    "sessionState": "${SESSION_STATE.value}",
          |    "methodResponses": [
          |        [
          |            "Email/get",
          |            {
          |                "accountId": "29883977c13473ae7cb7678ef767cbfbaffc8a44a6e463d971d23a65c1dc4af6",
-         |                "state": "000001",
+         |                "state": "${INSTANCE.value}",
          |                "list": [
          |                    {
          |                        "id": "${messageId.serialize}",
@@ -3622,13 +3624,13 @@ trait EmailGetMethodContract {
     val contentType = " multipart/mixed;\\r\\n boundary=\\\"------------64D8D789FC30153D6ED18258\\\""
     assertThatJson(response).isEqualTo(
       s"""{
-         |    "sessionState": "75128aab4b1b",
+         |    "sessionState": "${SESSION_STATE.value}",
          |    "methodResponses": [
          |        [
          |            "Email/get",
          |            {
          |                "accountId": "29883977c13473ae7cb7678ef767cbfbaffc8a44a6e463d971d23a65c1dc4af6",
-         |                "state": "000001",
+         |                "state": "${INSTANCE.value}",
          |                "list": [
          |                    {
          |                        "id": "${messageId.serialize}",
@@ -3812,13 +3814,13 @@ trait EmailGetMethodContract {
 
     assertThatJson(response).isEqualTo(
       s"""{
-         |    "sessionState": "75128aab4b1b",
+         |    "sessionState": "${SESSION_STATE.value}",
          |    "methodResponses": [
          |        [
          |            "Email/get",
          |            {
          |                "accountId": "29883977c13473ae7cb7678ef767cbfbaffc8a44a6e463d971d23a65c1dc4af6",
-         |                "state": "000001",
+         |                "state": "${INSTANCE.value}",
          |                "list": [
          |                    {
          |                        "id": "${messageId.serialize}",
@@ -3995,12 +3997,12 @@ trait EmailGetMethodContract {
 
     assertThatJson(response).isEqualTo(
       s"""{
-         |    "sessionState": "75128aab4b1b",
+         |    "sessionState": "${SESSION_STATE.value}",
          |    "methodResponses": [[
          |            "Email/get",
          |            {
          |                "accountId": "29883977c13473ae7cb7678ef767cbfbaffc8a44a6e463d971d23a65c1dc4af6",
-         |                "state": "000001",
+         |                "state": "${INSTANCE.value}",
          |                "list": [
          |                    {
          |                        "id": "${messageId.serialize}",
@@ -4059,12 +4061,12 @@ trait EmailGetMethodContract {
 
     assertThatJson(response).isEqualTo(
       s"""{
-         |    "sessionState": "75128aab4b1b",
+         |    "sessionState": "${SESSION_STATE.value}",
          |    "methodResponses": [[
          |            "Email/get",
          |            {
          |                "accountId": "29883977c13473ae7cb7678ef767cbfbaffc8a44a6e463d971d23a65c1dc4af6",
-         |                "state": "000001",
+         |                "state": "${INSTANCE.value}",
          |                "list": [
          |                    {
          |                        "id": "${messageId.serialize}",
@@ -4123,12 +4125,12 @@ trait EmailGetMethodContract {
 
     assertThatJson(response).isEqualTo(
       s"""{
-         |    "sessionState": "75128aab4b1b",
+         |    "sessionState": "${SESSION_STATE.value}",
          |    "methodResponses": [[
          |            "Email/get",
          |            {
          |                "accountId": "29883977c13473ae7cb7678ef767cbfbaffc8a44a6e463d971d23a65c1dc4af6",
-         |                "state": "000001",
+         |                "state": "${INSTANCE.value}",
          |                "list": [
          |                    {
          |                        "id": "${messageId.serialize}",
@@ -4188,12 +4190,12 @@ trait EmailGetMethodContract {
 
     assertThatJson(response).isEqualTo(
       s"""{
-         |    "sessionState": "75128aab4b1b",
+         |    "sessionState": "${SESSION_STATE.value}",
          |    "methodResponses": [[
          |            "Email/get",
          |            {
          |                "accountId": "29883977c13473ae7cb7678ef767cbfbaffc8a44a6e463d971d23a65c1dc4af6",
-         |                "state": "000001",
+         |                "state": "${INSTANCE.value}",
          |                "list": [
          |                    {
          |                        "id": "${messageId.serialize}",
@@ -4251,12 +4253,12 @@ trait EmailGetMethodContract {
 
     assertThatJson(response).isEqualTo(
       s"""{
-         |    "sessionState": "75128aab4b1b",
+         |    "sessionState": "${SESSION_STATE.value}",
          |    "methodResponses": [[
          |            "Email/get",
          |            {
          |                "accountId": "29883977c13473ae7cb7678ef767cbfbaffc8a44a6e463d971d23a65c1dc4af6",
-         |                "state": "000001",
+         |                "state": "${INSTANCE.value}",
          |                "list": [
          |                    {
          |                        "id": "${messageId.serialize}",
@@ -4314,7 +4316,7 @@ trait EmailGetMethodContract {
 
     assertThatJson(response).isEqualTo(
       s"""{
-         |    "sessionState": "75128aab4b1b",
+         |    "sessionState": "${SESSION_STATE.value}",
          |    "methodResponses": [
          |        [
          |            "Email/get",
@@ -4323,7 +4325,7 @@ trait EmailGetMethodContract {
          |                "notFound": [
          |
          |                ],
-         |                "state": "000001",
+         |                "state": "${INSTANCE.value}",
          |                "list": [
          |                    {
          |                        "id": "1",
@@ -4381,12 +4383,12 @@ trait EmailGetMethodContract {
 
     assertThatJson(response).isEqualTo(
       s"""{
-         |    "sessionState": "75128aab4b1b",
+         |    "sessionState": "${SESSION_STATE.value}",
          |    "methodResponses": [[
          |            "Email/get",
          |            {
          |                "accountId": "29883977c13473ae7cb7678ef767cbfbaffc8a44a6e463d971d23a65c1dc4af6",
-         |                "state": "000001",
+         |                "state": "${INSTANCE.value}",
          |                "list": [
          |                    {
          |                        "id": "${messageId.serialize}",
@@ -4444,12 +4446,12 @@ trait EmailGetMethodContract {
 
     assertThatJson(response).isEqualTo(
       s"""{
-         |    "sessionState": "75128aab4b1b",
+         |    "sessionState": "${SESSION_STATE.value}",
          |    "methodResponses": [[
          |            "Email/get",
          |            {
          |                "accountId": "29883977c13473ae7cb7678ef767cbfbaffc8a44a6e463d971d23a65c1dc4af6",
-         |                "state": "000001",
+         |                "state": "${INSTANCE.value}",
          |                "list": [
          |                    {
          |                        "id": "${messageId.serialize}",
@@ -4508,13 +4510,13 @@ trait EmailGetMethodContract {
 
     assertThatJson(response).isEqualTo(
       s"""{
-         |    "sessionState": "75128aab4b1b",
+         |    "sessionState": "${SESSION_STATE.value}",
          |    "methodResponses": [
          |        [
          |            "Email/get",
          |            {
          |                "accountId": "29883977c13473ae7cb7678ef767cbfbaffc8a44a6e463d971d23a65c1dc4af6",
-         |                "state": "000001",
+         |                "state": "${INSTANCE.value}",
          |                "list": [
          |                    {
          |                        "id": "${messageId.serialize}",
@@ -4579,12 +4581,12 @@ trait EmailGetMethodContract {
 
     assertThatJson(response).isEqualTo(
       s"""{
-         |    "sessionState": "75128aab4b1b",
+         |    "sessionState": "${SESSION_STATE.value}",
          |    "methodResponses": [[
          |            "Email/get",
          |            {
          |                "accountId": "29883977c13473ae7cb7678ef767cbfbaffc8a44a6e463d971d23a65c1dc4af6",
-         |                "state": "000001",
+         |                "state": "${INSTANCE.value}",
          |                "list": [
          |                    {
          |                        "id": "${messageId.serialize}",
@@ -4642,13 +4644,13 @@ trait EmailGetMethodContract {
 
     assertThatJson(response).isEqualTo(
       s"""{
-         |    "sessionState": "75128aab4b1b",
+         |    "sessionState": "${SESSION_STATE.value}",
          |    "methodResponses": [
          |        [
          |            "Email/get",
          |            {
          |                "accountId": "29883977c13473ae7cb7678ef767cbfbaffc8a44a6e463d971d23a65c1dc4af6",
-         |                "state": "000001",
+         |                "state": "${INSTANCE.value}",
          |                "list": [
          |                    {
          |                        "id": "${messageId.serialize}",
@@ -4716,12 +4718,12 @@ trait EmailGetMethodContract {
 
     assertThatJson(response).isEqualTo(
       s"""{
-         |    "sessionState": "75128aab4b1b",
+         |    "sessionState": "${SESSION_STATE.value}",
          |    "methodResponses": [[
          |            "Email/get",
          |            {
          |                "accountId": "29883977c13473ae7cb7678ef767cbfbaffc8a44a6e463d971d23a65c1dc4af6",
-         |                "state": "000001",
+         |                "state": "${INSTANCE.value}",
          |                "list": [
          |                    {
          |                        "id": "${messageId.serialize}",
@@ -4780,13 +4782,13 @@ trait EmailGetMethodContract {
 
     assertThatJson(response).isEqualTo(
       s"""{
-         |    "sessionState": "75128aab4b1b",
+         |    "sessionState": "${SESSION_STATE.value}",
          |    "methodResponses": [
          |        [
          |            "Email/get",
          |            {
          |                "accountId": "29883977c13473ae7cb7678ef767cbfbaffc8a44a6e463d971d23a65c1dc4af6",
-         |                "state": "000001",
+         |                "state": "${INSTANCE.value}",
          |                "list": [
          |                    {
          |                        "id": "${messageId.serialize}",
@@ -4854,12 +4856,12 @@ trait EmailGetMethodContract {
 
     assertThatJson(response).isEqualTo(
       s"""{
-         |    "sessionState": "75128aab4b1b",
+         |    "sessionState": "${SESSION_STATE.value}",
          |    "methodResponses": [[
          |            "Email/get",
          |            {
          |                "accountId": "29883977c13473ae7cb7678ef767cbfbaffc8a44a6e463d971d23a65c1dc4af6",
-         |                "state": "000001",
+         |                "state": "${INSTANCE.value}",
          |                "list": [
          |                    {
          |                        "id": "${messageId.serialize}",
@@ -4926,12 +4928,12 @@ trait EmailGetMethodContract {
 
     assertThatJson(response).isEqualTo(
       s"""{
-         |    "sessionState": "75128aab4b1b",
+         |    "sessionState": "${SESSION_STATE.value}",
          |    "methodResponses": [[
          |            "Email/get",
          |            {
          |                "accountId": "29883977c13473ae7cb7678ef767cbfbaffc8a44a6e463d971d23a65c1dc4af6",
-         |                "state": "000001",
+         |                "state": "${INSTANCE.value}",
          |                "list": [
          |                    {
          |                        "id": "${messageId.serialize}",
@@ -4945,7 +4947,6 @@ trait EmailGetMethodContract {
          |}""".stripMargin)
   }
 
-
   @Test
   def attachmentsForSimpleMultipart(server: GuiceJamesServer): Unit = {
     val path = MailboxPath.inbox(BOB)
@@ -4983,12 +4984,12 @@ trait EmailGetMethodContract {
 
     assertThatJson(response).isEqualTo(
       s"""{
-         |    "sessionState": "75128aab4b1b",
+         |    "sessionState": "${SESSION_STATE.value}",
          |    "methodResponses": [[
          |            "Email/get",
          |            {
          |                "accountId": "29883977c13473ae7cb7678ef767cbfbaffc8a44a6e463d971d23a65c1dc4af6",
-         |                "state": "000001",
+         |                "state": "${INSTANCE.value}",
          |                "list": [
          |                    {
          |                        "id": "${messageId.serialize}",
@@ -5067,12 +5068,12 @@ trait EmailGetMethodContract {
 
     assertThatJson(response).isEqualTo(
       s"""{
-         |    "sessionState": "75128aab4b1b",
+         |    "sessionState": "${SESSION_STATE.value}",
          |    "methodResponses": [[
          |            "Email/get",
          |            {
          |                "accountId": "29883977c13473ae7cb7678ef767cbfbaffc8a44a6e463d971d23a65c1dc4af6",
-         |                "state": "000001",
+         |                "state": "${INSTANCE.value}",
          |                "list": [
          |                    {
          |                        "id": "${messageId.serialize}",
@@ -5462,12 +5463,12 @@ trait EmailGetMethodContract {
 
     assertThatJson(response).isEqualTo(
       s"""{
-         |    "sessionState": "75128aab4b1b",
+         |    "sessionState": "${SESSION_STATE.value}",
          |    "methodResponses": [[
          |            "Email/get",
          |            {
          |                "accountId": "29883977c13473ae7cb7678ef767cbfbaffc8a44a6e463d971d23a65c1dc4af6",
-         |                "state": "000001",
+         |                "state": "${INSTANCE.value}",
          |                "list": [{
          |                    "id": "${messageId.serialize}",
          |                    "headers": [
@@ -5633,7 +5634,7 @@ trait EmailGetMethodContract {
 
     assertThatJson(response).isEqualTo(
       s"""{
-         |    "sessionState": "75128aab4b1b",
+         |    "sessionState": "${SESSION_STATE.value}",
          |    "methodResponses": [[
          |            "error",
          |            {
@@ -5740,7 +5741,7 @@ trait EmailGetMethodContract {
 
     assertThatJson(response).isEqualTo(
       s"""{
-         |    "sessionState": "75128aab4b1b",
+         |    "sessionState": "${SESSION_STATE.value}",
          |    "methodResponses": [[
          |            "error",
          |            {
diff --git a/server/protocols/jmap-rfc-8621-integration-tests/jmap-rfc-8621-integration-tests-common/src/main/scala/org/apache/james/jmap/rfc8621/contract/EmailQueryMethodContract.scala b/server/protocols/jmap-rfc-8621-integration-tests/jmap-rfc-8621-integration-tests-common/src/main/scala/org/apache/james/jmap/rfc8621/contract/EmailQueryMethodContract.scala
index 69297ed..182da77 100644
--- a/server/protocols/jmap-rfc-8621-integration-tests/jmap-rfc-8621-integration-tests-common/src/main/scala/org/apache/james/jmap/rfc8621/contract/EmailQueryMethodContract.scala
+++ b/server/protocols/jmap-rfc-8621-integration-tests/jmap-rfc-8621-integration-tests-common/src/main/scala/org/apache/james/jmap/rfc8621/contract/EmailQueryMethodContract.scala
@@ -37,6 +37,8 @@ import net.javacrumbs.jsonunit.core.Option.IGNORING_ARRAY_ORDER
 import net.javacrumbs.jsonunit.core.internal.Options
 import org.apache.http.HttpStatus.SC_OK
 import org.apache.james.GuiceJamesServer
+import org.apache.james.jmap.core.ResponseObject.SESSION_STATE
+import org.apache.james.jmap.core.State.INSTANCE
 import org.apache.james.jmap.core.UTCDate
 import org.apache.james.jmap.http.UserCredential
 import org.apache.james.jmap.rfc8621.contract.Fixture.{ACCEPT_RFC8621_VERSION_HEADER, ANDRE, ANDRE_PASSWORD, BOB, BOB_PASSWORD, DOMAIN, authScheme, baseRequestSpecBuilder}
@@ -123,7 +125,7 @@ trait EmailQueryMethodContract {
 
       assertThatJson(response).isEqualTo(
         s"""{
-           |    "sessionState": "75128aab4b1b",
+           |    "sessionState": "${SESSION_STATE.value}",
            |    "methodResponses": [[
            |            "error",
            |            {
@@ -187,7 +189,7 @@ trait EmailQueryMethodContract {
 
       assertThatJson(response).isEqualTo(
         s"""{
-           |    "sessionState": "75128aab4b1b",
+           |    "sessionState": "${SESSION_STATE.value}",
            |    "methodResponses": [[
            |            "Email/query",
            |            {
@@ -251,13 +253,13 @@ trait EmailQueryMethodContract {
 
     assertThatJson(response).isEqualTo(
       s"""{
-         |    "sessionState": "75128aab4b1b",
+         |    "sessionState": "${SESSION_STATE.value}",
          |    "methodResponses": [
          |        [
          |            "Mailbox/set",
          |            {
          |                "accountId": "29883977c13473ae7cb7678ef767cbfbaffc8a44a6e463d971d23a65c1dc4af6",
-         |                "newState": "000001",
+         |                "newState": "${INSTANCE.value}",
          |                "created": {
          |                    "C42": {
          |                        "id": "${mailboxId}",
@@ -348,13 +350,13 @@ trait EmailQueryMethodContract {
 
     assertThatJson(response).isEqualTo(
       s"""{
-         |    "sessionState": "75128aab4b1b",
+         |    "sessionState": "${SESSION_STATE.value}",
          |    "methodResponses": [
          |        [
          |            "Mailbox/set",
          |            {
          |                "accountId": "29883977c13473ae7cb7678ef767cbfbaffc8a44a6e463d971d23a65c1dc4af6",
-         |                "newState": "000001",
+         |                "newState": "${INSTANCE.value}",
          |                "created": {
          |                    "C42": {
          |                        "id": "${mailboxId}",
@@ -443,7 +445,7 @@ trait EmailQueryMethodContract {
 
       assertThatJson(response).isEqualTo(
         s"""{
-           |    "sessionState": "75128aab4b1b",
+           |    "sessionState": "${SESSION_STATE.value}",
            |    "methodResponses": [[
            |            "Email/query",
            |            {
@@ -506,7 +508,7 @@ trait EmailQueryMethodContract {
 
       assertThatJson(response).isEqualTo(
         s"""{
-           |    "sessionState": "75128aab4b1b",
+           |    "sessionState": "${SESSION_STATE.value}",
            |    "methodResponses": [[
            |            "Email/query",
            |            {
@@ -568,7 +570,7 @@ trait EmailQueryMethodContract {
 
       assertThatJson(response).isEqualTo(
         s"""{
-           |    "sessionState": "75128aab4b1b",
+           |    "sessionState": "${SESSION_STATE.value}",
            |    "methodResponses": [
            |        [
            |            "Email/query",
@@ -635,7 +637,7 @@ trait EmailQueryMethodContract {
 
       assertThatJson(response).isEqualTo(
         s"""{
-           |    "sessionState": "75128aab4b1b",
+           |    "sessionState": "${SESSION_STATE.value}",
            |    "methodResponses": [[
            |            "Email/query",
            |            {
@@ -697,7 +699,7 @@ trait EmailQueryMethodContract {
 
       assertThatJson(response).isEqualTo(
         s"""{
-           |    "sessionState": "75128aab4b1b",
+           |    "sessionState": "${SESSION_STATE.value}",
            |    "methodResponses": [[
            |            "Email/query",
            |            {
@@ -770,7 +772,7 @@ trait EmailQueryMethodContract {
 
       assertThatJson(response).isEqualTo(
         s"""{
-           |    "sessionState": "75128aab4b1b",
+           |    "sessionState": "${SESSION_STATE.value}",
            |    "methodResponses": [[
            |            "Email/query",
            |            {
@@ -982,7 +984,7 @@ trait EmailQueryMethodContract {
 
       assertThatJson(response).isEqualTo(
         s"""{
-           |    "sessionState": "75128aab4b1b",
+           |    "sessionState": "${SESSION_STATE.value}",
            |    "methodResponses": [[
            |            "Email/query",
            |            {
@@ -1053,7 +1055,7 @@ trait EmailQueryMethodContract {
 
       assertThatJson(response).isEqualTo(
         s"""{
-           |    "sessionState": "75128aab4b1b",
+           |    "sessionState": "${SESSION_STATE.value}",
            |    "methodResponses": [[
            |            "Email/query",
            |            {
@@ -1134,7 +1136,7 @@ trait EmailQueryMethodContract {
 
       assertThatJson(response).isEqualTo(
         s"""{
-           |    "sessionState": "75128aab4b1b",
+           |    "sessionState": "${SESSION_STATE.value}",
            |    "methodResponses": [[
            |            "Email/query",
            |            {
@@ -1215,7 +1217,7 @@ trait EmailQueryMethodContract {
 
       assertThatJson(response).isEqualTo(
         s"""{
-           |    "sessionState": "75128aab4b1b",
+           |    "sessionState": "${SESSION_STATE.value}",
            |    "methodResponses": [[
            |            "Email/query",
            |            {
@@ -1295,7 +1297,7 @@ trait EmailQueryMethodContract {
 
       assertThatJson(response)
         .isEqualTo(s"""{
-                      |    "sessionState": "75128aab4b1b",
+                      |    "sessionState": "${SESSION_STATE.value}",
                       |    "methodResponses": [
                       |        [
                       |            "error",
@@ -1353,7 +1355,7 @@ trait EmailQueryMethodContract {
 
       assertThatJson(response).isEqualTo(
         s"""{
-           |    "sessionState": "75128aab4b1b",
+           |    "sessionState": "${SESSION_STATE.value}",
            |    "methodResponses": [[
            |            "Email/query",
            |            {
@@ -1435,7 +1437,7 @@ trait EmailQueryMethodContract {
 
       assertThatJson(response).isEqualTo(
         s"""{
-           |    "sessionState": "75128aab4b1b",
+           |    "sessionState": "${SESSION_STATE.value}",
            |    "methodResponses": [[
            |            "Email/query",
            |            {
@@ -1540,7 +1542,7 @@ trait EmailQueryMethodContract {
 
       assertThatJson(response).isEqualTo(
         s"""{
-           |    "sessionState": "75128aab4b1b",
+           |    "sessionState": "${SESSION_STATE.value}",
            |    "methodResponses": [[
            |            "Email/query",
            |            {
@@ -2556,7 +2558,7 @@ trait EmailQueryMethodContract {
 
       assertThatJson(response).isEqualTo(
         s"""{
-           |    "sessionState": "75128aab4b1b",
+           |    "sessionState": "${SESSION_STATE.value}",
            |    "methodResponses": [
            |        [
            |            "error",
@@ -2718,7 +2720,7 @@ trait EmailQueryMethodContract {
       assertThatJson(response)
         .isEqualTo(
           s"""{
-             |    "sessionState": "75128aab4b1b",
+             |    "sessionState": "${SESSION_STATE.value}",
              |    "methodResponses": [
              |        [
              |            "error",
@@ -2767,7 +2769,7 @@ trait EmailQueryMethodContract {
       assertThatJson(response)
         .isEqualTo(
           s"""{
-             |    "sessionState": "75128aab4b1b",
+             |    "sessionState": "${SESSION_STATE.value}",
              |    "methodResponses": [
              |        [
              |            "error",
@@ -3231,7 +3233,7 @@ trait EmailQueryMethodContract {
 
       assertThatJson(response).isEqualTo(
         s"""{
-           |    "sessionState": "75128aab4b1b",
+           |    "sessionState": "${SESSION_STATE.value}",
            |    "methodResponses": [[
            |            "Email/query",
            |            {
@@ -3320,7 +3322,7 @@ trait EmailQueryMethodContract {
 
       assertThatJson(response).isEqualTo(
         s"""{
-           |    "sessionState": "75128aab4b1b",
+           |    "sessionState": "${SESSION_STATE.value}",
            |    "methodResponses": [[
            |            "Email/query",
            |            {
@@ -3386,7 +3388,7 @@ trait EmailQueryMethodContract {
 
       assertThatJson(response).isEqualTo(
         s"""{
-           |    "sessionState": "75128aab4b1b",
+           |    "sessionState": "${SESSION_STATE.value}",
            |    "methodResponses": [[
            |            "Email/query",
            |            {
@@ -3433,7 +3435,7 @@ trait EmailQueryMethodContract {
 
       assertThatJson(response).isEqualTo(
         s"""{
-           |    "sessionState": "75128aab4b1b",
+           |    "sessionState": "${SESSION_STATE.value}",
            |    "methodResponses": [
            |        [
            |            "error",
@@ -3605,7 +3607,7 @@ trait EmailQueryMethodContract {
 
       assertThatJson(response).isEqualTo(
         s"""{
-           |    "sessionState": "75128aab4b1b",
+           |    "sessionState": "${SESSION_STATE.value}",
            |    "methodResponses": [[
            |            "Email/query",
            |            {
@@ -3670,7 +3672,7 @@ trait EmailQueryMethodContract {
 
       assertThatJson(response).isEqualTo(
         s"""{
-           |    "sessionState": "75128aab4b1b",
+           |    "sessionState": "${SESSION_STATE.value}",
            |    "methodResponses": [[
            |            "Email/query",
            |            {
@@ -3729,7 +3731,7 @@ trait EmailQueryMethodContract {
 
       assertThatJson(response).isEqualTo(
         s"""{
-           |    "sessionState": "75128aab4b1b",
+           |    "sessionState": "${SESSION_STATE.value}",
            |    "methodResponses": [[
            |            "Email/query",
            |            {
@@ -3789,7 +3791,7 @@ trait EmailQueryMethodContract {
 
       assertThatJson(response).isEqualTo(
         s"""{
-           |    "sessionState": "75128aab4b1b",
+           |    "sessionState": "${SESSION_STATE.value}",
            |    "methodResponses": [
            |        [
            |            "error",
@@ -3883,8 +3885,8 @@ trait EmailQueryMethodContract {
 
     assertThatJson(response)
       .whenIgnoringPaths("methodResponses[0][1].description")
-      .isEqualTo("""{
-                    |    "sessionState": "75128aab4b1b",
+      .isEqualTo(s"""{
+                    |    "sessionState": "${SESSION_STATE.value}",
                     |    "methodResponses": [
                     |        [
                     |            "error",
@@ -3927,11 +3929,10 @@ trait EmailQueryMethodContract {
       .body
       .asString
 
-
     assertThatJson(response)
       .whenIgnoringPaths("methodResponses[0][1].description")
-      .isEqualTo("""{
-                   |    "sessionState": "75128aab4b1b",
+      .isEqualTo(s"""{
+                   |    "sessionState": "${SESSION_STATE.value}",
                    |    "methodResponses": [
                    |        [
                    |            "error",
@@ -3978,7 +3979,7 @@ trait EmailQueryMethodContract {
       .whenIgnoringPaths("methodResponses[0][1].description")
       .isEqualTo(
         s"""{
-           |    "sessionState": "75128aab4b1b",
+           |    "sessionState": "${SESSION_STATE.value}",
            |    "methodResponses": [
            |        [
            |            "error",
@@ -4025,7 +4026,7 @@ trait EmailQueryMethodContract {
       .whenIgnoringPaths("methodResponses[0][1].description")
       .isEqualTo(
         s"""{
-           |    "sessionState": "75128aab4b1b",
+           |    "sessionState": "${SESSION_STATE.value}",
            |    "methodResponses": [
            |        [
            |            "error",
@@ -4071,8 +4072,8 @@ trait EmailQueryMethodContract {
 
     assertThatJson(response)
       .whenIgnoringPaths("methodResponses[0][1].description")
-      .isEqualTo("""{
-                   |    "sessionState": "75128aab4b1b",
+      .isEqualTo(s"""{
+                   |    "sessionState": "${SESSION_STATE.value}",
                    |    "methodResponses": [
                    |        [
                    |            "error",
@@ -5535,7 +5536,7 @@ trait EmailQueryMethodContract {
 
     assertThatJson(response)
       .isEqualTo(s"""{
-                    |    "sessionState": "75128aab4b1b",
+                    |    "sessionState": "${SESSION_STATE.value}",
                     |    "methodResponses": [
                     |        [
                     |            "error",
@@ -5581,7 +5582,7 @@ trait EmailQueryMethodContract {
 
     assertThatJson(response)
       .isEqualTo(s"""{
-                    |    "sessionState": "75128aab4b1b",
+                    |    "sessionState": "${SESSION_STATE.value}",
                     |    "methodResponses": [
                     |        [
                     |            "error",
@@ -5644,7 +5645,7 @@ trait EmailQueryMethodContract {
 
     assertThatJson(response)
       .isEqualTo(s"""{
-                    |    "sessionState": "75128aab4b1b",
+                    |    "sessionState": "${SESSION_STATE.value}",
                     |    "methodResponses": [
                     |        [
                     |            "error",
@@ -5707,7 +5708,7 @@ trait EmailQueryMethodContract {
 
     assertThatJson(response)
       .isEqualTo(s"""{
-                    |    "sessionState": "75128aab4b1b",
+                    |    "sessionState": "${SESSION_STATE.value}",
                     |    "methodResponses": [
                     |        [
                     |            "error",
diff --git a/server/protocols/jmap-rfc-8621-integration-tests/jmap-rfc-8621-integration-tests-common/src/main/scala/org/apache/james/jmap/rfc8621/contract/EmailSetMethodContract.scala b/server/protocols/jmap-rfc-8621-integration-tests/jmap-rfc-8621-integration-tests-common/src/main/scala/org/apache/james/jmap/rfc8621/contract/EmailSetMethodContract.scala
index 724455a..ac44738 100644
--- a/server/protocols/jmap-rfc-8621-integration-tests/jmap-rfc-8621-integration-tests-common/src/main/scala/org/apache/james/jmap/rfc8621/contract/EmailSetMethodContract.scala
+++ b/server/protocols/jmap-rfc-8621-integration-tests/jmap-rfc-8621-integration-tests-common/src/main/scala/org/apache/james/jmap/rfc8621/contract/EmailSetMethodContract.scala
@@ -32,6 +32,8 @@ import javax.mail.Flags
 import net.javacrumbs.jsonunit.assertj.JsonAssertions.assertThatJson
 import org.apache.http.HttpStatus.{SC_CREATED, SC_OK}
 import org.apache.james.GuiceJamesServer
+import org.apache.james.jmap.core.ResponseObject.SESSION_STATE
+import org.apache.james.jmap.core.State.INSTANCE
 import org.apache.james.jmap.core.UTCDate
 import org.apache.james.jmap.draft.{JmapGuiceProbe, MessageIdProbe}
 import org.apache.james.jmap.http.UserCredential
@@ -3021,11 +3023,11 @@ trait EmailSetMethodContract {
     assertThatJson(response)
       .isEqualTo(
         s"""{
-           |  "sessionState": "75128aab4b1b",
+           |  "sessionState": "${SESSION_STATE.value}",
            |  "methodResponses": [
            |    ["Email/set", {
            |      "accountId": "29883977c13473ae7cb7678ef767cbfbaffc8a44a6e463d971d23a65c1dc4af6",
-           |      "newState": "000001",
+           |      "newState": "${INSTANCE.value}",
            |      "created": {
            |        "aaaaaa": {
            |          "id": "$messageId",
@@ -3037,7 +3039,7 @@ trait EmailSetMethodContract {
            |    }, "c1"],
            |    ["Email/get", {
            |      "accountId": "29883977c13473ae7cb7678ef767cbfbaffc8a44a6e463d971d23a65c1dc4af6",
-           |      "state": "000001",
+           |      "state": "${INSTANCE.value}",
            |      "list": [
            |        {
            |          "id": "$messageId",
@@ -3133,11 +3135,11 @@ trait EmailSetMethodContract {
     assertThatJson(response)
       .isEqualTo(
         s"""{
-           |  "sessionState": "75128aab4b1b",
+           |  "sessionState": "${SESSION_STATE.value}",
            |  "methodResponses": [
            |    ["Email/set", {
            |      "accountId": "29883977c13473ae7cb7678ef767cbfbaffc8a44a6e463d971d23a65c1dc4af6",
-           |      "newState": "000001",
+           |      "newState": "${INSTANCE.value}",
            |      "created": {
            |        "aaaaaa": {
            |          "id": "$messageId",
@@ -3149,7 +3151,7 @@ trait EmailSetMethodContract {
            |    }, "c1"],
            |    ["Email/get", {
            |      "accountId": "29883977c13473ae7cb7678ef767cbfbaffc8a44a6e463d971d23a65c1dc4af6",
-           |      "state": "000001",
+           |      "state": "${INSTANCE.value}",
            |      "list": [
            |        {
            |          "id": "$messageId",
@@ -4647,16 +4649,16 @@ trait EmailSetMethodContract {
 
     assertThatJson(response).isEqualTo(
       s"""{
-         |    "sessionState": "75128aab4b1b",
+         |    "sessionState": "${SESSION_STATE.value}",
          |    "methodResponses": [
          |      ["Email/set", {
          |        "accountId": "29883977c13473ae7cb7678ef767cbfbaffc8a44a6e463d971d23a65c1dc4af6",
-         |        "newState": "000001",
+         |        "newState": "${INSTANCE.value}",
          |        "destroyed": ["${messageId.serialize}"]
          |      }, "c1"],
          |      ["Email/get", {
          |        "accountId": "29883977c13473ae7cb7678ef767cbfbaffc8a44a6e463d971d23a65c1dc4af6",
-         |        "state": "000001",
+         |        "state": "${INSTANCE.value}",
          |        "list": [],
          |        "notFound": ["${messageId.serialize}"]
          |      }, "c2"]
@@ -4692,11 +4694,11 @@ trait EmailSetMethodContract {
 
     assertThatJson(response).isEqualTo(
       s"""{
-         |    "sessionState": "75128aab4b1b",
+         |    "sessionState": "${SESSION_STATE.value}",
          |    "methodResponses": [
          |      ["Email/set", {
          |        "accountId": "29883977c13473ae7cb7678ef767cbfbaffc8a44a6e463d971d23a65c1dc4af6",
-         |        "newState": "000001",
+         |        "newState": "${INSTANCE.value}",
          |        "notDestroyed": {
          |          "invalid": {
          |            "type": "invalidArguments",
@@ -4737,11 +4739,11 @@ trait EmailSetMethodContract {
 
     assertThatJson(response).isEqualTo(
       s"""{
-         |    "sessionState": "75128aab4b1b",
+         |    "sessionState": "${SESSION_STATE.value}",
          |    "methodResponses": [
          |      ["Email/set", {
          |        "accountId": "29883977c13473ae7cb7678ef767cbfbaffc8a44a6e463d971d23a65c1dc4af6",
-         |        "newState": "000001",
+         |        "newState": "${INSTANCE.value}",
          |        "notDestroyed": {
          |          "${messageId.serialize}": {
          |            "type": "notFound",
@@ -4789,11 +4791,11 @@ trait EmailSetMethodContract {
 
     assertThatJson(response).isEqualTo(
       s"""{
-         |    "sessionState": "75128aab4b1b",
+         |    "sessionState": "${SESSION_STATE.value}",
          |    "methodResponses": [
          |      ["Email/set", {
          |        "accountId": "29883977c13473ae7cb7678ef767cbfbaffc8a44a6e463d971d23a65c1dc4af6",
-         |        "newState": "000001",
+         |        "newState": "${INSTANCE.value}",
          |        "notDestroyed": {
          |          "${messageId.serialize}": {
          |            "type": "notFound",
@@ -4848,11 +4850,11 @@ trait EmailSetMethodContract {
 
     assertThatJson(response).isEqualTo(
       s"""{
-         |    "sessionState": "75128aab4b1b",
+         |    "sessionState": "${SESSION_STATE.value}",
          |    "methodResponses": [
          |      ["Email/set", {
          |        "accountId": "29883977c13473ae7cb7678ef767cbfbaffc8a44a6e463d971d23a65c1dc4af6",
-         |        "newState": "000001",
+         |        "newState": "${INSTANCE.value}",
          |        "notDestroyed": {
          |          "${messageId.serialize}": {
          |            "type": "notFound",
@@ -4912,16 +4914,16 @@ trait EmailSetMethodContract {
 
     assertThatJson(response).isEqualTo(
       s"""{
-         |    "sessionState": "75128aab4b1b",
+         |    "sessionState": "${SESSION_STATE.value}",
          |    "methodResponses": [
          |      ["Email/set", {
          |        "accountId": "29883977c13473ae7cb7678ef767cbfbaffc8a44a6e463d971d23a65c1dc4af6",
-         |        "newState": "000001",
+         |        "newState": "${INSTANCE.value}",
          |        "destroyed": ["${messageId.serialize}"]
          |      }, "c1"],
          |      ["Email/get", {
          |        "accountId": "29883977c13473ae7cb7678ef767cbfbaffc8a44a6e463d971d23a65c1dc4af6",
-         |        "state": "000001",
+         |        "state": "${INSTANCE.value}",
          |        "list": [],
          |        "notFound": ["${messageId.serialize}"]
          |      }, "c2"]
@@ -4982,16 +4984,16 @@ trait EmailSetMethodContract {
 
     assertThatJson(response).isEqualTo(
       s"""{
-         |    "sessionState": "75128aab4b1b",
+         |    "sessionState": "${SESSION_STATE.value}",
          |    "methodResponses": [
          |      ["Email/set", {
          |        "accountId": "29883977c13473ae7cb7678ef767cbfbaffc8a44a6e463d971d23a65c1dc4af6",
-         |        "newState": "000001",
+         |        "newState": "${INSTANCE.value}",
          |        "destroyed": ["${messageId.serialize}"]
          |      }, "c1"],
          |      ["Email/get", {
          |        "accountId": "29883977c13473ae7cb7678ef767cbfbaffc8a44a6e463d971d23a65c1dc4af6",
-         |        "state": "000001",
+         |        "state": "${INSTANCE.value}",
          |        "list": [],
          |        "notFound": ["${messageId.serialize}"]
          |      }, "c2"]
@@ -5305,11 +5307,11 @@ trait EmailSetMethodContract {
 
     assertThatJson(response).isEqualTo(
       s"""{
-         |    "sessionState": "75128aab4b1b",
+         |    "sessionState": "${SESSION_STATE.value}",
          |    "methodResponses": [
          |      ["Email/set", {
          |        "accountId": "29883977c13473ae7cb7678ef767cbfbaffc8a44a6e463d971d23a65c1dc4af6",
-         |        "newState": "000001",
+         |        "newState": "${INSTANCE.value}",
          |        "destroyed": ["${messageId.serialize}"],
          |        "notDestroyed": {
          |          "invalid": {
@@ -5374,18 +5376,18 @@ trait EmailSetMethodContract {
 
     assertThatJson(response).isEqualTo(
       s"""{
-         |    "sessionState": "75128aab4b1b",
+         |    "sessionState": "${SESSION_STATE.value}",
          |    "methodResponses": [
          |      ["Email/set", {
          |        "accountId": "29883977c13473ae7cb7678ef767cbfbaffc8a44a6e463d971d23a65c1dc4af6",
-         |        "newState": "000001",
+         |        "newState": "${INSTANCE.value}",
          |        "updated": {
          |          "${messageId.serialize}": null
          |        }
          |      }, "c1"],
          |      ["Email/get",{
          |        "accountId":"29883977c13473ae7cb7678ef767cbfbaffc8a44a6e463d971d23a65c1dc4af6",
-         |        "state":"000001",
+         |        "state":"${INSTANCE.value}",
          |        "list":[
          |          {
          |            "id":"${messageId.serialize}",
@@ -5463,11 +5465,11 @@ trait EmailSetMethodContract {
     assertThatJson(response)
       .isEqualTo(
       s"""{
-         |    "sessionState": "75128aab4b1b",
+         |    "sessionState": "${SESSION_STATE.value}",
          |    "methodResponses": [
          |      ["Email/set", {
          |        "accountId": "29883977c13473ae7cb7678ef767cbfbaffc8a44a6e463d971d23a65c1dc4af6",
-         |        "newState": "000001",
+         |        "newState": "${INSTANCE.value}",
          |        "updated": {
          |          "${messageId1.serialize}": null,
          |          "${messageId2.serialize}": null
@@ -5475,7 +5477,7 @@ trait EmailSetMethodContract {
          |      }, "c1"],
          |      ["Email/get", {
          |        "accountId":"29883977c13473ae7cb7678ef767cbfbaffc8a44a6e463d971d23a65c1dc4af6",
-         |        "state":"000001",
+         |        "state":"${INSTANCE.value}",
          |        "list":[
          |          {
          |            "id":"${messageId1.serialize}",
@@ -5543,11 +5545,11 @@ trait EmailSetMethodContract {
     assertThatJson(response)
       .isEqualTo(
         s"""{
-           |    "sessionState": "75128aab4b1b",
+           |    "sessionState": "${SESSION_STATE.value}",
            |    "methodResponses": [
            |        ["Email/set", {
            |          "accountId": "29883977c13473ae7cb7678ef767cbfbaffc8a44a6e463d971d23a65c1dc4af6",
-           |          "newState": "000001",
+           |          "newState": "${INSTANCE.value}",
            |          "notUpdated": {
            |            "${messageId.serialize}": {
            |              "type": "notFound",
@@ -5615,11 +5617,11 @@ trait EmailSetMethodContract {
     assertThatJson(response)
       .isEqualTo(
         s"""{
-           |    "sessionState": "75128aab4b1b",
+           |    "sessionState": "${SESSION_STATE.value}",
            |    "methodResponses": [
            |      ["Email/set", {
            |        "accountId": "29883977c13473ae7cb7678ef767cbfbaffc8a44a6e463d971d23a65c1dc4af6",
-           |        "newState": "000001",
+           |        "newState": "${INSTANCE.value}",
            |        "notUpdated": {
            |          "${messageId.serialize}": {
            |            "type": "notFound",
@@ -5629,7 +5631,7 @@ trait EmailSetMethodContract {
            |      }, "c1"],
            |      ["Email/get", {
            |        "accountId":"29883977c13473ae7cb7678ef767cbfbaffc8a44a6e463d971d23a65c1dc4af6",
-           |        "state":"000001",
+           |        "state":"${INSTANCE.value}",
            |        "list":[
            |          {
            |            "id":"${messageId.serialize}",
@@ -5700,11 +5702,11 @@ trait EmailSetMethodContract {
     assertThatJson(response)
       .isEqualTo(
         s"""{
-           |    "sessionState": "75128aab4b1b",
+           |    "sessionState": "${SESSION_STATE.value}",
            |    "methodResponses": [
            |      ["Email/set", {
            |        "accountId": "29883977c13473ae7cb7678ef767cbfbaffc8a44a6e463d971d23a65c1dc4af6",
-           |        "newState": "000001",
+           |        "newState": "${INSTANCE.value}",
            |        "notUpdated": {
            |          "${messageId.serialize}": {
            |            "type": "notFound",
@@ -5714,7 +5716,7 @@ trait EmailSetMethodContract {
            |      }, "c1"],
            |      ["Email/get", {
            |        "accountId":"29883977c13473ae7cb7678ef767cbfbaffc8a44a6e463d971d23a65c1dc4af6",
-           |        "state":"000001",
+           |        "state":"${INSTANCE.value}",
            |        "list":[
            |          {
            |            "id":"${messageId.serialize}",
@@ -5786,18 +5788,18 @@ trait EmailSetMethodContract {
     assertThatJson(response)
       .isEqualTo(
         s"""{
-           |    "sessionState": "75128aab4b1b",
+           |    "sessionState": "${SESSION_STATE.value}",
            |    "methodResponses": [
            |      ["Email/set", {
            |        "accountId": "29883977c13473ae7cb7678ef767cbfbaffc8a44a6e463d971d23a65c1dc4af6",
-           |        "newState": "000001",
+           |        "newState": "${INSTANCE.value}",
            |        "updated": {
            |          "${messageId.serialize}": null
            |        }
            |      }, "c1"],
            |      ["Email/get", {
            |        "accountId":"29883977c13473ae7cb7678ef767cbfbaffc8a44a6e463d971d23a65c1dc4af6",
-           |        "state":"000001",
+           |        "state":"${INSTANCE.value}",
            |        "list":[
            |          {
            |            "id":"${messageId.serialize}",
@@ -5869,18 +5871,18 @@ trait EmailSetMethodContract {
     assertThatJson(response)
       .isEqualTo(
         s"""{
-           |    "sessionState": "75128aab4b1b",
+           |    "sessionState": "${SESSION_STATE.value}",
            |    "methodResponses": [
            |      ["Email/set", {
            |        "accountId": "29883977c13473ae7cb7678ef767cbfbaffc8a44a6e463d971d23a65c1dc4af6",
-           |        "newState": "000001",
+           |        "newState": "${INSTANCE.value}",
            |        "updated": {
            |          "${messageId.serialize}": null
            |        }
            |      }, "c1"],
            |      ["Email/get", {
            |        "accountId":"29883977c13473ae7cb7678ef767cbfbaffc8a44a6e463d971d23a65c1dc4af6",
-           |        "state":"000001",
+           |        "state":"${INSTANCE.value}",
            |        "list":[
            |          {
            |            "id":"${messageId.serialize}",
@@ -5946,11 +5948,11 @@ trait EmailSetMethodContract {
     assertThatJson(response)
       .isEqualTo(
         s"""{
-           |    "sessionState": "75128aab4b1b",
+           |    "sessionState": "${SESSION_STATE.value}",
            |    "methodResponses": [
            |      ["Email/set", {
            |        "accountId": "29883977c13473ae7cb7678ef767cbfbaffc8a44a6e463d971d23a65c1dc4af6",
-           |        "newState": "000001",
+           |        "newState": "${INSTANCE.value}",
            |        "updated": {
            |          "${messageId.serialize}": null
            |        }
@@ -6009,11 +6011,11 @@ trait EmailSetMethodContract {
     assertThatJson(response)
       .isEqualTo(
         s"""{
-           |    "sessionState": "75128aab4b1b",
+           |    "sessionState": "${SESSION_STATE.value}",
            |    "methodResponses": [
            |      ["Email/set", {
            |        "accountId": "29883977c13473ae7cb7678ef767cbfbaffc8a44a6e463d971d23a65c1dc4af6",
-           |        "newState": "000001",
+           |        "newState": "${INSTANCE.value}",
            |        "notUpdated": {
            |          "${messageId.serialize}": {
            |            "type": "invalidPatch",
@@ -6070,11 +6072,11 @@ trait EmailSetMethodContract {
     assertThatJson(response)
       .isEqualTo(
         s"""{
-           |    "sessionState": "75128aab4b1b",
+           |    "sessionState": "${SESSION_STATE.value}",
            |    "methodResponses": [
            |      ["Email/set", {
            |        "accountId": "29883977c13473ae7cb7678ef767cbfbaffc8a44a6e463d971d23a65c1dc4af6",
-           |        "newState": "000001",
+           |        "newState": "${INSTANCE.value}",
            |        "notUpdated": {
            |          "${messageId.serialize}": {
            |            "type": "invalidPatch",
@@ -6131,11 +6133,11 @@ trait EmailSetMethodContract {
     assertThatJson(response)
       .isEqualTo(
         s"""{
-           |    "sessionState": "75128aab4b1b",
+           |    "sessionState": "${SESSION_STATE.value}",
            |    "methodResponses": [
            |      ["Email/set", {
            |        "accountId": "29883977c13473ae7cb7678ef767cbfbaffc8a44a6e463d971d23a65c1dc4af6",
-           |        "newState": "000001",
+           |        "newState": "${INSTANCE.value}",
            |        "notUpdated": {
            |          "${messageId.serialize}": {
            |            "type": "invalidPatch",
@@ -6209,11 +6211,11 @@ trait EmailSetMethodContract {
     assertThatJson(response)
       .isEqualTo(
         s"""{
-           |    "sessionState": "75128aab4b1b",
+           |    "sessionState": "${SESSION_STATE.value}",
            |    "methodResponses": [
            |      ["Email/set", {
            |        "accountId": "29883977c13473ae7cb7678ef767cbfbaffc8a44a6e463d971d23a65c1dc4af6",
-           |        "newState": "000001",
+           |        "newState": "${INSTANCE.value}",
            |        "updated": {
            |          "${messageId1.serialize}": null
            |        },
diff --git a/server/protocols/jmap-rfc-8621-integration-tests/jmap-rfc-8621-integration-tests-common/src/main/scala/org/apache/james/jmap/rfc8621/contract/EmailSubmissionSetMethodContract.scala b/server/protocols/jmap-rfc-8621-integration-tests/jmap-rfc-8621-integration-tests-common/src/main/scala/org/apache/james/jmap/rfc8621/contract/EmailSubmissionSetMethodContract.scala
index 108c5d7..ddbb3bb 100644
--- a/server/protocols/jmap-rfc-8621-integration-tests/jmap-rfc-8621-integration-tests-common/src/main/scala/org/apache/james/jmap/rfc8621/contract/EmailSubmissionSetMethodContract.scala
+++ b/server/protocols/jmap-rfc-8621-integration-tests/jmap-rfc-8621-integration-tests-common/src/main/scala/org/apache/james/jmap/rfc8621/contract/EmailSubmissionSetMethodContract.scala
@@ -29,6 +29,8 @@ import io.restassured.http.ContentType.JSON
 import net.javacrumbs.jsonunit.assertj.JsonAssertions.assertThatJson
 import org.apache.http.HttpStatus.SC_OK
 import org.apache.james.GuiceJamesServer
+import org.apache.james.jmap.core.ResponseObject.SESSION_STATE
+import org.apache.james.jmap.core.State.INSTANCE
 import org.apache.james.jmap.http.UserCredential
 import org.apache.james.jmap.rfc8621.contract.Fixture.{ACCEPT_RFC8621_VERSION_HEADER, ACCOUNT_ID, ANDRE, ANDRE_ACCOUNT_ID, ANDRE_PASSWORD, BOB, BOB_PASSWORD, DOMAIN, authScheme, baseRequestSpecBuilder}
 import org.apache.james.mailbox.DefaultMailboxes
@@ -885,13 +887,13 @@ trait EmailSubmissionSetMethodContract {
       // Ids are randomly generated, and not stored, let's ignore it
       .whenIgnoringPaths("methodResponses[0][1].created.k1490")
       .isEqualTo(s"""{
-                   |    "sessionState": "75128aab4b1b",
+                   |    "sessionState": "${SESSION_STATE.value}",
                    |    "methodResponses": [
                    |        [
                    |            "EmailSubmission/set",
                    |            {
                    |                "accountId": "29883977c13473ae7cb7678ef767cbfbaffc8a44a6e463d971d23a65c1dc4af6",
-                   |                "newState": "000001",
+                   |                "newState": "${INSTANCE.value}",
                    |                "created": {
                    |                    "k1490": "f0850507-bb63-4675-b14f-d560f8dca21f"
                    |                }
@@ -902,7 +904,7 @@ trait EmailSubmissionSetMethodContract {
                    |            "Email/set",
                    |            {
                    |                "accountId": "29883977c13473ae7cb7678ef767cbfbaffc8a44a6e463d971d23a65c1dc4af6",
-                   |                "newState": "000001",
+                   |                "newState": "${INSTANCE.value}",
                    |                "updated": {
                    |                    "${messageId.serialize}": null
                    |                }
@@ -913,7 +915,7 @@ trait EmailSubmissionSetMethodContract {
                    |            "Email/get",
                    |            {
                    |                "accountId": "29883977c13473ae7cb7678ef767cbfbaffc8a44a6e463d971d23a65c1dc4af6",
-                   |                "state": "000001",
+                   |                "state": "${INSTANCE.value}",
                    |                "list": [
                    |                    {
                    |                        "keywords": {"$$sent": true},
@@ -987,13 +989,13 @@ trait EmailSubmissionSetMethodContract {
       // Ids are randomly generated, and not stored, let's ignore it
       .whenIgnoringPaths("methodResponses[0][1].created.k1490")
       .isEqualTo(s"""{
-                   |    "sessionState": "75128aab4b1b",
+                   |    "sessionState": "${SESSION_STATE.value}",
                    |    "methodResponses": [
                    |        [
                    |            "EmailSubmission/set",
                    |            {
                    |                "accountId": "29883977c13473ae7cb7678ef767cbfbaffc8a44a6e463d971d23a65c1dc4af6",
-                   |                "newState": "000001",
+                   |                "newState": "${INSTANCE.value}",
                    |                "created": {
                    |                    "k1490": "f0850507-bb63-4675-b14f-d560f8dca21f"
                    |                }
@@ -1004,7 +1006,7 @@ trait EmailSubmissionSetMethodContract {
                    |            "Email/set",
                    |            {
                    |                "accountId": "29883977c13473ae7cb7678ef767cbfbaffc8a44a6e463d971d23a65c1dc4af6",
-                   |                "newState": "000001",
+                   |                "newState": "${INSTANCE.value}",
                    |                "destroyed": ["${messageId.serialize}"]
                    |            },
                    |            "c1"
@@ -1013,7 +1015,7 @@ trait EmailSubmissionSetMethodContract {
                    |            "Email/get",
                    |            {
                    |                "accountId": "29883977c13473ae7cb7678ef767cbfbaffc8a44a6e463d971d23a65c1dc4af6",
-                   |                "state": "000001",
+                   |                "state": "${INSTANCE.value}",
                    |                "list":[],
                    |                "notFound": ["${messageId.serialize}"]
                    |            },
diff --git a/server/protocols/jmap-rfc-8621-integration-tests/jmap-rfc-8621-integration-tests-common/src/main/scala/org/apache/james/jmap/rfc8621/contract/Fixture.scala b/server/protocols/jmap-rfc-8621-integration-tests/jmap-rfc-8621-integration-tests-common/src/main/scala/org/apache/james/jmap/rfc8621/contract/Fixture.scala
index d2b2528..73bb287 100644
--- a/server/protocols/jmap-rfc-8621-integration-tests/jmap-rfc-8621-integration-tests-common/src/main/scala/org/apache/james/jmap/rfc8621/contract/Fixture.scala
+++ b/server/protocols/jmap-rfc-8621-integration-tests/jmap-rfc-8621-integration-tests-common/src/main/scala/org/apache/james/jmap/rfc8621/contract/Fixture.scala
@@ -32,6 +32,7 @@ import io.restassured.http.{ContentType, Header, Headers}
 import org.apache.james.GuiceJamesServer
 import org.apache.james.core.{Domain, Username}
 import org.apache.james.jmap.JMAPUrls.JMAP
+import org.apache.james.jmap.core.ResponseObject.SESSION_STATE
 import org.apache.james.jmap.draft.JmapGuiceProbe
 import org.apache.james.jmap.http.UserCredential
 import org.apache.james.mime4j.dom.Message
@@ -127,8 +128,8 @@ object Fixture {
       |}""".stripMargin
 
   val ECHO_RESPONSE_OBJECT: String =
-    """{
-      |  "sessionState": "75128aab4b1b",
+    s"""{
+      |  "sessionState": "${SESSION_STATE.value}",
       |  "methodResponses": [
       |    [
       |      "Core/echo",
diff --git a/server/protocols/jmap-rfc-8621-integration-tests/jmap-rfc-8621-integration-tests-common/src/main/scala/org/apache/james/jmap/rfc8621/contract/IdentityGetContract.scala b/server/protocols/jmap-rfc-8621-integration-tests/jmap-rfc-8621-integration-tests-common/src/main/scala/org/apache/james/jmap/rfc8621/contract/IdentityGetContract.scala
index 8f84f84..f452c69 100644
--- a/server/protocols/jmap-rfc-8621-integration-tests/jmap-rfc-8621-integration-tests-common/src/main/scala/org/apache/james/jmap/rfc8621/contract/IdentityGetContract.scala
+++ b/server/protocols/jmap-rfc-8621-integration-tests/jmap-rfc-8621-integration-tests-common/src/main/scala/org/apache/james/jmap/rfc8621/contract/IdentityGetContract.scala
@@ -25,6 +25,8 @@ import io.restassured.http.ContentType.JSON
 import net.javacrumbs.jsonunit.assertj.JsonAssertions.assertThatJson
 import org.apache.http.HttpStatus.SC_OK
 import org.apache.james.GuiceJamesServer
+import org.apache.james.jmap.core.ResponseObject.SESSION_STATE
+import org.apache.james.jmap.core.State.INSTANCE
 import org.apache.james.jmap.http.UserCredential
 import org.apache.james.jmap.rfc8621.contract.Fixture._
 import org.apache.james.utils.DataProbeImpl
@@ -73,9 +75,9 @@ trait IdentityGetContract {
     assertThatJson(response)
       .inPath("methodResponses[0][1]")
       .isEqualTo(
-      """{
+      s"""{
         |  "accountId": "29883977c13473ae7cb7678ef767cbfbaffc8a44a6e463d971d23a65c1dc4af6",
-        |  "state": "000001",
+        |  "state": "${INSTANCE.value}",
         |  "list": [
         |      {
         |          "id": "29883977c13473ae7cb7678ef767cbfbaffc8a44a6e463d971d23a65c1dc4af6",
@@ -117,9 +119,9 @@ trait IdentityGetContract {
     assertThatJson(response)
       .inPath("methodResponses[0][1]")
       .isEqualTo(
-      """{
+      s"""{
         |    "accountId": "29883977c13473ae7cb7678ef767cbfbaffc8a44a6e463d971d23a65c1dc4af6",
-        |    "state": "000001",
+        |    "state": "${INSTANCE.value}",
         |    "list": [
         |        {
         |            "id": "29883977c13473ae7cb7678ef767cbfbaffc8a44a6e463d971d23a65c1dc4af6",
@@ -168,9 +170,9 @@ trait IdentityGetContract {
     assertThatJson(response)
       .inPath("methodResponses[0][1]")
       .isEqualTo(
-      """{
+      s"""{
         |    "accountId": "29883977c13473ae7cb7678ef767cbfbaffc8a44a6e463d971d23a65c1dc4af6",
-        |    "state": "000001",
+        |    "state": "${INSTANCE.value}",
         |    "list": [
         |        {
         |            "id": "29883977c13473ae7cb7678ef767cbfbaffc8a44a6e463d971d23a65c1dc4af6",
@@ -231,9 +233,9 @@ trait IdentityGetContract {
     assertThatJson(response)
       .inPath("methodResponses[0][1]")
       .isEqualTo(
-        """{
+        s"""{
           |  "accountId": "29883977c13473ae7cb7678ef767cbfbaffc8a44a6e463d971d23a65c1dc4af6",
-          |  "state": "000001",
+          |  "state": "${INSTANCE.value}",
           |  "list": [
           |      {
           |          "id": "29883977c13473ae7cb7678ef767cbfbaffc8a44a6e463d971d23a65c1dc4af6",
@@ -276,9 +278,9 @@ trait IdentityGetContract {
     assertThatJson(response)
       .inPath("methodResponses[0][1]")
       .isEqualTo(
-        """{
+        s"""{
           |  "accountId": "29883977c13473ae7cb7678ef767cbfbaffc8a44a6e463d971d23a65c1dc4af6",
-          |  "state": "000001",
+          |  "state": "${INSTANCE.value}",
           |  "list": [
           |      {
           |          "id": "29883977c13473ae7cb7678ef767cbfbaffc8a44a6e463d971d23a65c1dc4af6",
@@ -318,8 +320,8 @@ trait IdentityGetContract {
 
     assertThatJson(response)
       .isEqualTo(
-        """{
-          |    "sessionState": "75128aab4b1b",
+        s"""{
+          |    "sessionState": "${SESSION_STATE.value}",
           |    "methodResponses": [
           |        [
           |            "error",
@@ -361,8 +363,8 @@ trait IdentityGetContract {
 
     assertThatJson(response)
       .isEqualTo(
-        """{
-          |    "sessionState": "75128aab4b1b",
+        s"""{
+          |    "sessionState": "${SESSION_STATE.value}",
           |    "methodResponses": [
           |        [
           |            "error",
diff --git a/server/protocols/jmap-rfc-8621-integration-tests/jmap-rfc-8621-integration-tests-common/src/main/scala/org/apache/james/jmap/rfc8621/contract/MailboxGetMethodContract.scala b/server/protocols/jmap-rfc-8621-integration-tests/jmap-rfc-8621-integration-tests-common/src/main/scala/org/apache/james/jmap/rfc8621/contract/MailboxGetMethodContract.scala
index 843460f..82f18c4 100644
--- a/server/protocols/jmap-rfc-8621-integration-tests/jmap-rfc-8621-integration-tests-common/src/main/scala/org/apache/james/jmap/rfc8621/contract/MailboxGetMethodContract.scala
+++ b/server/protocols/jmap-rfc-8621-integration-tests/jmap-rfc-8621-integration-tests-common/src/main/scala/org/apache/james/jmap/rfc8621/contract/MailboxGetMethodContract.scala
@@ -30,6 +30,8 @@ import net.javacrumbs.jsonunit.assertj.JsonAssertions.assertThatJson
 import org.apache.http.HttpStatus.SC_OK
 import org.apache.james.GuiceJamesServer
 import org.apache.james.core.quota.{QuotaCountLimit, QuotaSizeLimit}
+import org.apache.james.jmap.core.ResponseObject.SESSION_STATE
+import org.apache.james.jmap.core.State.INSTANCE
 import org.apache.james.jmap.http.UserCredential
 import org.apache.james.jmap.rfc8621.contract.Fixture._
 import org.apache.james.jmap.rfc8621.contract.tags.CategoryTags
@@ -104,8 +106,8 @@ trait MailboxGetMethodContract {
       .asString
 
     assertThatJson(response).isEqualTo(
-      """{
-        |  "sessionState": "75128aab4b1b",
+      s"""{
+        |  "sessionState": "${SESSION_STATE.value}",
         |  "methodResponses": [
         |    ["error", {
         |      "type": "accountNotFound"
@@ -146,12 +148,12 @@ trait MailboxGetMethodContract {
 
     assertThatJson(response).isEqualTo(
       s"""{
-         |  "sessionState": "75128aab4b1b",
+         |  "sessionState": "${SESSION_STATE.value}",
          |  "methodResponses": [[
          |    "Mailbox/get",
          |    {
          |      "accountId": "29883977c13473ae7cb7678ef767cbfbaffc8a44a6e463d971d23a65c1dc4af6",
-         |      "state": "000001",
+         |      "state": "${INSTANCE.value}",
          |      "list": [
          |        {
          |          "id": "${mailboxId}",
@@ -215,12 +217,12 @@ trait MailboxGetMethodContract {
 
     assertThatJson(response).isEqualTo(
       s"""{
-         |  "sessionState": "75128aab4b1b",
+         |  "sessionState": "${SESSION_STATE.value}",
          |  "methodResponses": [[
          |    "Mailbox/get",
          |    {
          |      "accountId": "29883977c13473ae7cb7678ef767cbfbaffc8a44a6e463d971d23a65c1dc4af6",
-         |      "state": "000001",
+         |      "state": "${INSTANCE.value}",
          |      "list": [
          |        {
          |          "id": "${mailboxId}",
@@ -289,12 +291,12 @@ trait MailboxGetMethodContract {
 
     assertThatJson(response).isEqualTo(
       s"""{
-         |  "sessionState": "75128aab4b1b",
+         |  "sessionState": "${SESSION_STATE.value}",
          |  "methodResponses": [[
          |    "Mailbox/get",
          |    {
          |      "accountId": "29883977c13473ae7cb7678ef767cbfbaffc8a44a6e463d971d23a65c1dc4af6",
-         |      "state": "000001",
+         |      "state": "${INSTANCE.value}",
          |      "list": [
          |        {
          |          "id": "${mailboxId}",
@@ -364,12 +366,12 @@ trait MailboxGetMethodContract {
 
     assertThatJson(response).isEqualTo(
       s"""{
-         |  "sessionState": "75128aab4b1b",
+         |  "sessionState": "${SESSION_STATE.value}",
          |  "methodResponses": [[
          |    "Mailbox/get",
          |    {
          |      "accountId": "29883977c13473ae7cb7678ef767cbfbaffc8a44a6e463d971d23a65c1dc4af6",
-         |      "state": "000001",
+         |      "state": "${INSTANCE.value}",
          |      "list": [
          |        {
          |          "id": "${mailboxId}",
@@ -431,12 +433,12 @@ trait MailboxGetMethodContract {
 
     assertThatJson(response).isEqualTo(
       s"""{
-         |  "sessionState": "75128aab4b1b",
+         |  "sessionState": "${SESSION_STATE.value}",
          |  "methodResponses": [[
          |    "Mailbox/get",
          |    {
          |      "accountId": "29883977c13473ae7cb7678ef767cbfbaffc8a44a6e463d971d23a65c1dc4af6",
-         |      "state": "000001",
+         |      "state": "${INSTANCE.value}",
          |      "list": [
          |        {
          |          "id": "${mailboxId}"
@@ -480,12 +482,12 @@ trait MailboxGetMethodContract {
 
     assertThatJson(response).isEqualTo(
       s"""{
-         |  "sessionState": "75128aab4b1b",
+         |  "sessionState": "${SESSION_STATE.value}",
          |  "methodResponses": [[
          |    "Mailbox/get",
          |    {
          |      "accountId": "29883977c13473ae7cb7678ef767cbfbaffc8a44a6e463d971d23a65c1dc4af6",
-         |      "state": "000001",
+         |      "state": "${INSTANCE.value}",
          |      "list": [
          |        {
          |          "id": "${mailboxId}",
@@ -530,12 +532,12 @@ trait MailboxGetMethodContract {
 
     assertThatJson(response).isEqualTo(
       s"""{
-         |  "sessionState": "75128aab4b1b",
+         |  "sessionState": "${SESSION_STATE.value}",
          |  "methodResponses": [[
          |    "Mailbox/get",
          |    {
          |      "accountId": "29883977c13473ae7cb7678ef767cbfbaffc8a44a6e463d971d23a65c1dc4af6",
-         |      "state": "000001",
+         |      "state": "${INSTANCE.value}",
          |      "list": [
          |        {
          |          "id": "${mailboxId}",
@@ -581,12 +583,12 @@ trait MailboxGetMethodContract {
 
     assertThatJson(response).isEqualTo(
       s"""{
-         |  "sessionState": "75128aab4b1b",
+         |  "sessionState": "${SESSION_STATE.value}",
          |  "methodResponses": [[
          |    "Mailbox/get",
          |    {
          |      "accountId": "29883977c13473ae7cb7678ef767cbfbaffc8a44a6e463d971d23a65c1dc4af6",
-         |      "state": "000001",
+         |      "state": "${INSTANCE.value}",
          |      "list": [
          |        {
          |          "id": "${mailboxId}",
@@ -627,12 +629,12 @@ trait MailboxGetMethodContract {
 
     assertThatJson(response).isEqualTo(
       s"""{
-         |  "sessionState": "75128aab4b1b",
+         |  "sessionState": "${SESSION_STATE.value}",
          |  "methodResponses": [[
          |    "Mailbox/get",
          |    {
          |      "accountId": "29883977c13473ae7cb7678ef767cbfbaffc8a44a6e463d971d23a65c1dc4af6",
-         |      "state": "000001",
+         |      "state": "${INSTANCE.value}",
          |      "list": [],
          |      "notFound": ["invalid"]
          |    },
@@ -667,12 +669,12 @@ trait MailboxGetMethodContract {
 
     assertThatJson(response).isEqualTo(
       s"""{
-         |  "sessionState": "75128aab4b1b",
+         |  "sessionState": "${SESSION_STATE.value}",
          |  "methodResponses": [[
          |    "Mailbox/get",
          |    {
          |      "accountId": "29883977c13473ae7cb7678ef767cbfbaffc8a44a6e463d971d23a65c1dc4af6",
-         |      "state": "000001",
+         |      "state": "${INSTANCE.value}",
          |      "list": [],
          |      "notFound": ["#C42"]
          |    },
@@ -712,7 +714,7 @@ trait MailboxGetMethodContract {
 
     assertThatJson(response).isEqualTo(
       s"""{
-         |  "sessionState": "75128aab4b1b",
+         |  "sessionState": "${SESSION_STATE.value}",
          |  "methodResponses": [[
          |   "error", {
          |     "type": "invalidArguments",
@@ -1208,12 +1210,12 @@ trait MailboxGetMethodContract {
 
     assertThatJson(response).isEqualTo(
       s"""{
-         |  "sessionState": "75128aab4b1b",
+         |  "sessionState": "${SESSION_STATE.value}",
          |  "methodResponses": [[
          |    "Mailbox/get",
          |      {
          |        "accountId": "29883977c13473ae7cb7678ef767cbfbaffc8a44a6e463d971d23a65c1dc4af6",
-         |        "state": "000001",
+         |        "state": "${INSTANCE.value}",
          |        "list": [
          |          {
          |            "id": "${mailboxId}",
@@ -1282,12 +1284,12 @@ trait MailboxGetMethodContract {
 
     assertThatJson(response).isEqualTo(
       s"""{
-         |  "sessionState": "75128aab4b1b",
+         |  "sessionState": "${SESSION_STATE.value}",
          |  "methodResponses": [[
          |    "Mailbox/get",
          |      {
          |        "accountId": "29883977c13473ae7cb7678ef767cbfbaffc8a44a6e463d971d23a65c1dc4af6",
-         |        "state": "000001",
+         |        "state": "${INSTANCE.value}",
          |        "list": [
          |          {
          |            "id": "${mailboxId}",
@@ -1475,7 +1477,7 @@ trait MailboxGetMethodContract {
 
     assertThatJson(response).isEqualTo(
       s"""{
-         |  "sessionState": "75128aab4b1b",
+         |  "sessionState": "${SESSION_STATE.value}",
          |  "methodResponses": [[
          |    "error",
          |    {
@@ -1513,7 +1515,7 @@ trait MailboxGetMethodContract {
 
     assertThatJson(response).isEqualTo(
       s"""{
-         |  "sessionState": "75128aab4b1b",
+         |  "sessionState": "${SESSION_STATE.value}",
          |  "methodResponses": [[
          |    "error",
          |    {
diff --git a/server/protocols/jmap-rfc-8621-integration-tests/jmap-rfc-8621-integration-tests-common/src/main/scala/org/apache/james/jmap/rfc8621/contract/MailboxQueryMethodContract.scala b/server/protocols/jmap-rfc-8621-integration-tests/jmap-rfc-8621-integration-tests-common/src/main/scala/org/apache/james/jmap/rfc8621/contract/MailboxQueryMethodContract.scala
index 68e07f9..6cec1c3 100644
--- a/server/protocols/jmap-rfc-8621-integration-tests/jmap-rfc-8621-integration-tests-common/src/main/scala/org/apache/james/jmap/rfc8621/contract/MailboxQueryMethodContract.scala
+++ b/server/protocols/jmap-rfc-8621-integration-tests/jmap-rfc-8621-integration-tests-common/src/main/scala/org/apache/james/jmap/rfc8621/contract/MailboxQueryMethodContract.scala
@@ -26,6 +26,8 @@ import io.restassured.http.ContentType.JSON
 import net.javacrumbs.jsonunit.assertj.JsonAssertions.assertThatJson
 import org.apache.http.HttpStatus.SC_OK
 import org.apache.james.GuiceJamesServer
+import org.apache.james.jmap.core.ResponseObject.SESSION_STATE
+import org.apache.james.jmap.core.State.INSTANCE
 import org.apache.james.jmap.http.UserCredential
 import org.apache.james.jmap.rfc8621.contract.Fixture.{ACCEPT_RFC8621_VERSION_HEADER, ANDRE, ANDRE_PASSWORD, BOB, BOB_PASSWORD, DOMAIN, authScheme, baseRequestSpecBuilder}
 import org.apache.james.mailbox.model.{MailboxACL, MailboxId, MailboxPath}
@@ -77,8 +79,8 @@ trait MailboxQueryMethodContract {
       .asString
 
     assertThatJson(response).isEqualTo(
-      """{
-        |  "sessionState": "75128aab4b1b",
+      s"""{
+        |  "sessionState": "${SESSION_STATE.value}",
         |  "methodResponses": [
         |    ["error", {
         |      "type": "accountNotFound"
@@ -121,7 +123,7 @@ trait MailboxQueryMethodContract {
       assertThatJson(response)
         .isEqualTo(
         s"""{
-           |    "sessionState": "75128aab4b1b",
+           |    "sessionState": "${INSTANCE.value}",
            |    "methodResponses": [
            |        [
            |            "Mailbox/query",
@@ -220,7 +222,7 @@ trait MailboxQueryMethodContract {
       assertThatJson(response)
         .isEqualTo(
         s"""{
-           |    "sessionState": "75128aab4b1b",
+           |    "sessionState": "${SESSION_STATE.value}",
            |    "methodResponses": [
            |        [
            |            "Mailbox/query",
@@ -281,7 +283,7 @@ trait MailboxQueryMethodContract {
       assertThatJson(response)
         .isEqualTo(
         s"""{
-           |    "sessionState": "75128aab4b1b",
+           |    "sessionState": "${SESSION_STATE.value}",
            |    "methodResponses": [
            |        [
            |            "Mailbox/query",
@@ -332,7 +334,7 @@ trait MailboxQueryMethodContract {
       assertThatJson(response)
         .isEqualTo(
         s"""{
-           |    "sessionState": "75128aab4b1b",
+           |    "sessionState": "${SESSION_STATE.value}",
            |    "methodResponses": [
            |        [
            |            "error",
@@ -377,7 +379,7 @@ trait MailboxQueryMethodContract {
       assertThatJson(response)
         .isEqualTo(
         s"""{
-           |    "sessionState": "75128aab4b1b",
+           |    "sessionState": "${SESSION_STATE.value}",
            |    "methodResponses": [
            |        [
            |            "error",
@@ -423,7 +425,7 @@ trait MailboxQueryMethodContract {
       assertThatJson(response)
         .isEqualTo(
         s"""{
-           |    "sessionState": "75128aab4b1b",
+           |    "sessionState": "${SESSION_STATE.value}",
            |    "methodResponses": [
            |        [
            |            "error",
@@ -470,14 +472,14 @@ trait MailboxQueryMethodContract {
 
     assertThatJson(response)
       .isEqualTo(
-        """{
-           |    "sessionState": "75128aab4b1b",
+        s"""{
+           |    "sessionState": "${SESSION_STATE.value}",
            |    "methodResponses": [
            |        [
            |            "error",
            |            {
            |                "type": "invalidArguments",
-           |                "description": "{\"errors\":[{\"path\":\"obj.filter\",\"messages\":[\"These '[unsupported_option]' was unsupported filter options\"]}]}"
+           |                "description": "{\\"errors\\":[{\\"path\\":\\"obj.filter\\",\\"messages\\":[\\"These '[unsupported_option]' was unsupported filter options\\"]}]}"
            |            },
            |            "c1"
            |        ]
@@ -515,7 +517,7 @@ trait MailboxQueryMethodContract {
       assertThatJson(response)
         .isEqualTo(
         s"""{
-           |    "sessionState": "75128aab4b1b",
+           |    "sessionState": "${SESSION_STATE.value}",
            |    "methodResponses": [
            |        [
            |            "error",
diff --git a/server/protocols/jmap-rfc-8621-integration-tests/jmap-rfc-8621-integration-tests-common/src/main/scala/org/apache/james/jmap/rfc8621/contract/MailboxSetMethodContract.scala b/server/protocols/jmap-rfc-8621-integration-tests/jmap-rfc-8621-integration-tests-common/src/main/scala/org/apache/james/jmap/rfc8621/contract/MailboxSetMethodContract.scala
index d13058c..7b1a213 100644
--- a/server/protocols/jmap-rfc-8621-integration-tests/jmap-rfc-8621-integration-tests-common/src/main/scala/org/apache/james/jmap/rfc8621/contract/MailboxSetMethodContract.scala
+++ b/server/protocols/jmap-rfc-8621-integration-tests/jmap-rfc-8621-integration-tests-common/src/main/scala/org/apache/james/jmap/rfc8621/contract/MailboxSetMethodContract.scala
@@ -30,6 +30,8 @@ import net.javacrumbs.jsonunit.core.Option
 import net.javacrumbs.jsonunit.core.internal.Options
 import org.apache.http.HttpStatus.SC_OK
 import org.apache.james.GuiceJamesServer
+import org.apache.james.jmap.core.ResponseObject.SESSION_STATE
+import org.apache.james.jmap.core.State.INSTANCE
 import org.apache.james.jmap.draft.MessageIdProbe
 import org.apache.james.jmap.http.UserCredential
 import org.apache.james.jmap.rfc8621.contract.Fixture.{ACCEPT_RFC8621_VERSION_HEADER, ANDRE, BOB, BOB_PASSWORD, CEDRIC, DAVID, DOMAIN, authScheme, baseRequestSpecBuilder}
@@ -100,8 +102,8 @@ trait MailboxSetMethodContract {
       .asString
 
     assertThatJson(response).isEqualTo(
-      """{
-        |  "sessionState": "75128aab4b1b",
+      s"""{
+        |  "sessionState": "${SESSION_STATE.value}",
         |  "methodResponses": [
         |    ["error", {
         |      "type": "accountNotFound"
@@ -147,11 +149,11 @@ trait MailboxSetMethodContract {
 
     assertThatJson(response).isEqualTo(
       s"""{
-         |  "sessionState": "75128aab4b1b",
+         |  "sessionState": "${SESSION_STATE.value}",
          |  "methodResponses": [
          |    ["Mailbox/set", {
          |      "accountId": "29883977c13473ae7cb7678ef767cbfbaffc8a44a6e463d971d23a65c1dc4af6",
-         |      "newState": "000001",
+         |      "newState": "${INSTANCE.value}",
          |      "notUpdated": {
          |        "${mailboxId.serialize}": {
          |          "type": "invalidArguments",
@@ -201,11 +203,11 @@ trait MailboxSetMethodContract {
 
     assertThatJson(response).isEqualTo(
       s"""{
-         |  "sessionState": "75128aab4b1b",
+         |  "sessionState": "${SESSION_STATE.value}",
          |  "methodResponses": [
          |    ["Mailbox/set", {
          |      "accountId": "29883977c13473ae7cb7678ef767cbfbaffc8a44a6e463d971d23a65c1dc4af6",
-         |      "newState": "000001",
+         |      "newState": "${INSTANCE.value}",
          |      "notUpdated": {
          |        "${mailboxId.serialize}": {
          |          "type": "invalidArguments",
@@ -255,11 +257,11 @@ trait MailboxSetMethodContract {
 
     assertThatJson(response).isEqualTo(
       s"""{
-         |  "sessionState": "75128aab4b1b",
+         |  "sessionState": "${SESSION_STATE.value}",
          |  "methodResponses": [
          |    ["Mailbox/set", {
          |      "accountId": "29883977c13473ae7cb7678ef767cbfbaffc8a44a6e463d971d23a65c1dc4af6",
-         |      "newState": "000001",
+         |      "newState": "${INSTANCE.value}",
          |      "notUpdated": {
          |        "${mailboxId.serialize}": {
          |          "type": "invalidArguments",
@@ -309,11 +311,11 @@ trait MailboxSetMethodContract {
 
     assertThatJson(response).isEqualTo(
       s"""{
-         |  "sessionState": "75128aab4b1b",
+         |  "sessionState": "${SESSION_STATE.value}",
          |  "methodResponses": [
          |    ["Mailbox/set", {
          |      "accountId": "29883977c13473ae7cb7678ef767cbfbaffc8a44a6e463d971d23a65c1dc4af6",
-         |      "newState": "000001",
+         |      "newState": "${INSTANCE.value}",
          |      "notUpdated": {
          |        "${mailboxId.serialize}": {
          |          "type": "invalidArguments",
@@ -363,11 +365,11 @@ trait MailboxSetMethodContract {
 
     assertThatJson(response).isEqualTo(
       s"""{
-         |  "sessionState": "75128aab4b1b",
+         |  "sessionState": "${SESSION_STATE.value}",
          |  "methodResponses": [
          |    ["Mailbox/set", {
          |      "accountId": "29883977c13473ae7cb7678ef767cbfbaffc8a44a6e463d971d23a65c1dc4af6",
-         |      "newState": "000001",
+         |      "newState": "${INSTANCE.value}",
          |      "notUpdated": {
          |        "${mailboxId.serialize}": {
          |          "type": "invalidArguments",
@@ -417,11 +419,11 @@ trait MailboxSetMethodContract {
 
     assertThatJson(response).isEqualTo(
       s"""{
-         |  "sessionState": "75128aab4b1b",
+         |  "sessionState": "${SESSION_STATE.value}",
          |  "methodResponses": [
          |    ["Mailbox/set", {
          |      "accountId": "29883977c13473ae7cb7678ef767cbfbaffc8a44a6e463d971d23a65c1dc4af6",
-         |      "newState": "000001",
+         |      "newState": "${INSTANCE.value}",
          |      "notUpdated": {
          |        "${mailboxId.serialize()}": {
          |          "type": "invalidArguments",
@@ -472,11 +474,11 @@ trait MailboxSetMethodContract {
 
     assertThatJson(response).isEqualTo(
       s"""{
-         |  "sessionState": "75128aab4b1b",
+         |  "sessionState": "${SESSION_STATE.value}",
          |  "methodResponses": [
          |    ["Mailbox/set", {
          |      "accountId": "29883977c13473ae7cb7678ef767cbfbaffc8a44a6e463d971d23a65c1dc4af6",
-         |      "newState": "000001",
+         |      "newState": "${INSTANCE.value}",
          |      "notCreated": {
          |        "C42": {
          |          "type": "invalidArguments",
@@ -526,11 +528,11 @@ trait MailboxSetMethodContract {
 
     assertThatJson(response).isEqualTo(
       s"""{
-         |  "sessionState": "75128aab4b1b",
+         |  "sessionState": "${SESSION_STATE.value}",
          |  "methodResponses": [
          |    ["Mailbox/set", {
          |      "accountId": "29883977c13473ae7cb7678ef767cbfbaffc8a44a6e463d971d23a65c1dc4af6",
-         |      "newState": "000001",
+         |      "newState": "${INSTANCE.value}",
          |      "notUpdated": {
          |        "${mailboxId.serialize}": {
          |          "type": "invalidArguments",
@@ -580,11 +582,11 @@ trait MailboxSetMethodContract {
 
     assertThatJson(response).isEqualTo(
       s"""{
-         |  "sessionState": "75128aab4b1b",
+         |  "sessionState": "${SESSION_STATE.value}",
          |  "methodResponses": [
          |    ["Mailbox/set", {
          |      "accountId": "29883977c13473ae7cb7678ef767cbfbaffc8a44a6e463d971d23a65c1dc4af6",
-         |      "newState": "000001",
+         |      "newState": "${INSTANCE.value}",
          |      "notUpdated": {
          |        "${mailboxId.serialize}": {
          |          "type": "invalidArguments",
@@ -634,11 +636,11 @@ trait MailboxSetMethodContract {
 
     assertThatJson(response).isEqualTo(
       s"""{
-         |  "sessionState": "75128aab4b1b",
+         |  "sessionState": "${SESSION_STATE.value}",
          |  "methodResponses": [
          |    ["Mailbox/set", {
          |      "accountId": "29883977c13473ae7cb7678ef767cbfbaffc8a44a6e463d971d23a65c1dc4af6",
-         |      "newState": "000001",
+         |      "newState": "${INSTANCE.value}",
          |      "notUpdated": {
          |        "${mailboxId.serialize}": {
          |          "type": "invalidArguments",
@@ -688,11 +690,11 @@ trait MailboxSetMethodContract {
 
     assertThatJson(response).isEqualTo(
       s"""{
-         |  "sessionState": "75128aab4b1b",
+         |  "sessionState": "${SESSION_STATE.value}",
          |  "methodResponses": [
          |    ["Mailbox/set", {
          |      "accountId": "29883977c13473ae7cb7678ef767cbfbaffc8a44a6e463d971d23a65c1dc4af6",
-         |      "newState": "000001",
+         |      "newState": "${INSTANCE.value}",
          |      "notUpdated": {
          |        "${mailboxId.serialize}": {
          |          "type": "invalidArguments",
@@ -743,12 +745,12 @@ trait MailboxSetMethodContract {
 
     assertThatJson(response).isEqualTo(
       s"""{
-         |  "sessionState": "75128aab4b1b",
+         |  "sessionState": "${SESSION_STATE.value}",
          |  "methodResponses": [[
          |    "Mailbox/set",
          |    {
          |      "accountId": "29883977c13473ae7cb7678ef767cbfbaffc8a44a6e463d971d23a65c1dc4af6",
-         |      "newState": "000001",
+         |      "newState": "${INSTANCE.value}",
          |      "notCreated": {
          |        "C42": {
          |          "type": "invalidArguments",
@@ -799,12 +801,12 @@ trait MailboxSetMethodContract {
 
     assertThatJson(response).isEqualTo(
       s"""{
-         |  "sessionState": "75128aab4b1b",
+         |  "sessionState": "${SESSION_STATE.value}",
          |  "methodResponses": [[
          |    "Mailbox/set",
          |    {
          |      "accountId": "29883977c13473ae7cb7678ef767cbfbaffc8a44a6e463d971d23a65c1dc4af6",
-         |      "newState": "000001",
+         |      "newState": "${INSTANCE.value}",
          |      "notCreated": {
          |        "C42": {
          |          "type": "invalidArguments",
@@ -855,12 +857,12 @@ trait MailboxSetMethodContract {
 
     assertThatJson(response).isEqualTo(
       s"""{
-         |  "sessionState": "75128aab4b1b",
+         |  "sessionState": "${SESSION_STATE.value}",
          |  "methodResponses": [[
          |    "Mailbox/set",
          |    {
          |      "accountId": "29883977c13473ae7cb7678ef767cbfbaffc8a44a6e463d971d23a65c1dc4af6",
-         |      "newState": "000001",
+         |      "newState": "${INSTANCE.value}",
          |      "notCreated": {
          |        "C42": {
          |          "type": "invalidArguments",
@@ -913,12 +915,12 @@ trait MailboxSetMethodContract {
 
     assertThatJson(response).isEqualTo(
       s"""{
-         |  "sessionState": "75128aab4b1b",
+         |  "sessionState": "${SESSION_STATE.value}",
          |  "methodResponses": [[
          |    "Mailbox/set",
          |    {
          |      "accountId": "29883977c13473ae7cb7678ef767cbfbaffc8a44a6e463d971d23a65c1dc4af6",
-         |      "newState": "000001",
+         |      "newState": "${INSTANCE.value}",
          |      "notCreated": {
          |        "C42": {
          |          "type": "invalidArguments",
@@ -971,12 +973,12 @@ trait MailboxSetMethodContract {
 
     assertThatJson(response).isEqualTo(
       s"""{
-         |  "sessionState": "75128aab4b1b",
+         |  "sessionState": "${SESSION_STATE.value}",
          |  "methodResponses": [[
          |    "Mailbox/set",
          |    {
          |      "accountId": "29883977c13473ae7cb7678ef767cbfbaffc8a44a6e463d971d23a65c1dc4af6",
-         |      "newState": "000001",
+         |      "newState": "${INSTANCE.value}",
          |      "notCreated": {
          |        "C42": {
          |          "type": "invalidArguments",
@@ -1029,12 +1031,12 @@ trait MailboxSetMethodContract {
 
     assertThatJson(response).isEqualTo(
       s"""{
-         |  "sessionState": "75128aab4b1b",
+         |  "sessionState": "${SESSION_STATE.value}",
          |  "methodResponses": [[
          |    "Mailbox/set",
          |    {
          |      "accountId": "29883977c13473ae7cb7678ef767cbfbaffc8a44a6e463d971d23a65c1dc4af6",
-         |      "newState": "000001",
+         |      "newState": "${INSTANCE.value}",
          |      "notCreated": {
          |        "C42": {
          |          "type": "invalidArguments",
@@ -1171,11 +1173,11 @@ trait MailboxSetMethodContract {
 
     assertThatJson(response).isEqualTo(
       s"""{
-         |	"sessionState": "75128aab4b1b",
+         |	"sessionState": "${SESSION_STATE.value}",
          |	"methodResponses": [
          |		["Mailbox/set", {
          |			"accountId": "29883977c13473ae7cb7678ef767cbfbaffc8a44a6e463d971d23a65c1dc4af6",
-         |			"newState": "000001",
+         |			"newState": "${INSTANCE.value}",
          |			"created": {
          |				"C42": {
          |					"id": "${mailboxId}",
@@ -1336,11 +1338,11 @@ trait MailboxSetMethodContract {
 
     assertThatJson(response).isEqualTo(
       s"""{
-         |	"sessionState": "75128aab4b1b",
+         |	"sessionState": "${SESSION_STATE.value}",
          |	"methodResponses": [
          |		["Mailbox/set", {
          |			"accountId": "29883977c13473ae7cb7678ef767cbfbaffc8a44a6e463d971d23a65c1dc4af6",
-         |			"newState": "000001",
+         |			"newState": "${INSTANCE.value}",
          |			"created": {
          |				"C42": {
          |					"id": "$mailboxId",
@@ -1366,7 +1368,7 @@ trait MailboxSetMethodContract {
          |		}, "c1"],
          |		["Mailbox/get", {
          |			"accountId": "29883977c13473ae7cb7678ef767cbfbaffc8a44a6e463d971d23a65c1dc4af6",
-         |			"state": "000001",
+         |			"state": "${INSTANCE.value}",
          |			"list": [{
          |				"id": "$mailboxId",
          |				"name": "myMailbox",
@@ -1421,11 +1423,11 @@ trait MailboxSetMethodContract {
 
     assertThatJson(response).isEqualTo(
       s"""{
-         |	"sessionState": "75128aab4b1b",
+         |	"sessionState": "${SESSION_STATE.value}",
          |	"methodResponses": [
          |		["Mailbox/set", {
          |			"accountId": "29883977c13473ae7cb7678ef767cbfbaffc8a44a6e463d971d23a65c1dc4af6",
-         |			"newState": "000001",
+         |			"newState": "${INSTANCE.value}",
          |			"notCreated": {
          |				"C42": {
          |					"type": "invalidArguments",
@@ -1478,11 +1480,11 @@ trait MailboxSetMethodContract {
 
     assertThatJson(response).isEqualTo(
       s"""{
-         |	"sessionState": "75128aab4b1b",
+         |	"sessionState": "${SESSION_STATE.value}",
          |	"methodResponses": [
          |		["Mailbox/set", {
          |			"accountId": "29883977c13473ae7cb7678ef767cbfbaffc8a44a6e463d971d23a65c1dc4af6",
-         |			"newState": "000001",
+         |			"newState": "${INSTANCE.value}",
          |			"notCreated": {
          |				"C42": {
          |					"type": "invalidArguments",
@@ -1543,11 +1545,11 @@ trait MailboxSetMethodContract {
 
     assertThatJson(response).isEqualTo(
       s"""{
-         |  "sessionState": "75128aab4b1b",
+         |  "sessionState": "${SESSION_STATE.value}",
          |  "methodResponses": [
          |    ["Mailbox/set", {
          |      "accountId": "29883977c13473ae7cb7678ef767cbfbaffc8a44a6e463d971d23a65c1dc4af6",
-         |      "newState": "000001",
+         |      "newState": "${INSTANCE.value}",
          |      "created": {
          |        "C42": {
          |          "id": "$mailboxId",
@@ -1573,7 +1575,7 @@ trait MailboxSetMethodContract {
          |    }, "c1"],
          |    ["Mailbox/get", {
          |      "accountId": "29883977c13473ae7cb7678ef767cbfbaffc8a44a6e463d971d23a65c1dc4af6",
-         |      "state": "000001",
+         |      "state": "${INSTANCE.value}",
          |      "list": [{
          |        "id": "$mailboxId",
          |        "name": "myMailbox"
@@ -1673,12 +1675,12 @@ trait MailboxSetMethodContract {
 
     assertThatJson(response).isEqualTo(
       s"""{
-         |  "sessionState": "75128aab4b1b",
+         |  "sessionState": "${SESSION_STATE.value}",
          |  "methodResponses": [[
          |    "Mailbox/set",
          |    {
          |      "accountId": "29883977c13473ae7cb7678ef767cbfbaffc8a44a6e463d971d23a65c1dc4af6",
-         |      "newState": "000001",
+         |      "newState": "${INSTANCE.value}",
          |      "created": {
          |        "C42": {
          |          "id": "$mailboxId",
@@ -1741,12 +1743,12 @@ trait MailboxSetMethodContract {
 
     assertThatJson(response).isEqualTo(
       s"""{
-         |  "sessionState": "75128aab4b1b",
+         |  "sessionState": "${SESSION_STATE.value}",
          |  "methodResponses": [[
          |    "Mailbox/set",
          |    {
          |      "accountId": "29883977c13473ae7cb7678ef767cbfbaffc8a44a6e463d971d23a65c1dc4af6",
-         |      "newState": "000001",
+         |      "newState": "${INSTANCE.value}",
          |      "created": {
          |        "C42": {
          |          "id": "$mailboxId",
@@ -1813,12 +1815,12 @@ trait MailboxSetMethodContract {
 
     assertThatJson(response).isEqualTo(
       s"""{
-         |  "sessionState": "75128aab4b1b",
+         |  "sessionState": "${SESSION_STATE.value}",
          |  "methodResponses": [[
          |    "Mailbox/set",
          |    {
          |      "accountId": "29883977c13473ae7cb7678ef767cbfbaffc8a44a6e463d971d23a65c1dc4af6",
-         |      "newState": "000001",
+         |      "newState": "${INSTANCE.value}",
          |      "created": {
          |        "C42": {
          |          "id": "$mailboxId",
@@ -1925,12 +1927,12 @@ trait MailboxSetMethodContract {
 
     assertThatJson(response).isEqualTo(
       s"""{
-         |  "sessionState": "75128aab4b1b",
+         |  "sessionState": "${SESSION_STATE.value}",
          |  "methodResponses": [[
          |    "Mailbox/set",
          |    {
          |      "accountId": "29883977c13473ae7cb7678ef767cbfbaffc8a44a6e463d971d23a65c1dc4af6",
-         |      "newState": "000001",
+         |      "newState": "${INSTANCE.value}",
          |      "notCreated": {
          |        "C42": {
          |          "type": "invalidArguments",
@@ -1982,12 +1984,12 @@ trait MailboxSetMethodContract {
 
     assertThatJson(response).isEqualTo(
       s"""{
-         |  "sessionState": "75128aab4b1b",
+         |  "sessionState": "${SESSION_STATE.value}",
          |  "methodResponses": [[
          |    "Mailbox/set",
          |    {
          |      "accountId": "29883977c13473ae7cb7678ef767cbfbaffc8a44a6e463d971d23a65c1dc4af6",
-         |      "newState": "000001",
+         |      "newState": "${INSTANCE.value}",
          |      "notCreated": {
          |        "C42": {
          |          "type": "invalidArguments",
@@ -2038,12 +2040,12 @@ trait MailboxSetMethodContract {
 
     assertThatJson(response).isEqualTo(
       s"""{
-         |  "sessionState": "75128aab4b1b",
+         |  "sessionState": "${SESSION_STATE.value}",
          |  "methodResponses": [[
          |    "Mailbox/set",
          |    {
          |      "accountId": "29883977c13473ae7cb7678ef767cbfbaffc8a44a6e463d971d23a65c1dc4af6",
-         |      "newState": "000001",
+         |      "newState": "${INSTANCE.value}",
          |      "notCreated": {
          |        "C42": {
          |          "type": "invalidArguments",
@@ -2100,12 +2102,12 @@ trait MailboxSetMethodContract {
 
     assertThatJson(response).isEqualTo(
       s"""{
-         |  "sessionState": "75128aab4b1b",
+         |  "sessionState": "${SESSION_STATE.value}",
          |  "methodResponses": [[
          |    "Mailbox/set",
          |    {
          |      "accountId": "29883977c13473ae7cb7678ef767cbfbaffc8a44a6e463d971d23a65c1dc4af6",
-         |      "newState": "000001",
+         |      "newState": "${INSTANCE.value}",
          |      "notCreated": {
          |        "C42": {
          |          "type": "forbidden",
@@ -2155,12 +2157,12 @@ trait MailboxSetMethodContract {
 
     assertThatJson(response).isEqualTo(
       s"""{
-         |  "sessionState": "75128aab4b1b",
+         |  "sessionState": "${SESSION_STATE.value}",
          |  "methodResponses": [[
          |    "Mailbox/set",
          |    {
          |      "accountId": "29883977c13473ae7cb7678ef767cbfbaffc8a44a6e463d971d23a65c1dc4af6",
-         |      "newState": "000001",
+         |      "newState": "${INSTANCE.value}",
          |      "destroyed": ["${mailboxId.serialize}"]
          |    },
          |    "c1"]]
@@ -2222,13 +2224,13 @@ trait MailboxSetMethodContract {
 
     assertThatJson(response).isEqualTo(
       s"""{
-         |    "sessionState": "75128aab4b1b",
+         |    "sessionState": "${SESSION_STATE.value}",
          |    "methodResponses": [
          |        [
          |            "Mailbox/get",
          |            {
          |                "accountId": "29883977c13473ae7cb7678ef767cbfbaffc8a44a6e463d971d23a65c1dc4af6",
-         |                "state": "000001",
+         |                "state": "${INSTANCE.value}",
          |                "list": [
          |
          |                ],
@@ -2300,13 +2302,13 @@ trait MailboxSetMethodContract {
       .withOptions(new Options(Option.IGNORING_ARRAY_ORDER))
       .isEqualTo(
       s"""{
-         |    "sessionState": "75128aab4b1b",
+         |    "sessionState": "${SESSION_STATE.value}",
          |    "methodResponses": [
          |        [
          |            "Mailbox/get",
          |            {
          |                "accountId": "29883977c13473ae7cb7678ef767cbfbaffc8a44a6e463d971d23a65c1dc4af6",
-         |                "state": "000001",
+         |                "state": "${INSTANCE.value}",
          |                "list": [
          |
          |                ],
@@ -2355,12 +2357,12 @@ trait MailboxSetMethodContract {
 
     assertThatJson(response).isEqualTo(
       s"""{
-         |  "sessionState": "75128aab4b1b",
+         |  "sessionState": "${SESSION_STATE.value}",
          |  "methodResponses": [[
          |    "Mailbox/set",
          |    {
          |      "accountId": "29883977c13473ae7cb7678ef767cbfbaffc8a44a6e463d971d23a65c1dc4af6",
-         |      "newState": "000001",
+         |      "newState": "${INSTANCE.value}",
          |      "notDestroyed": {
          |        "${mailboxId.serialize}": {
          |          "type": "notFound",
@@ -2416,12 +2418,12 @@ trait MailboxSetMethodContract {
 
     assertThatJson(response).isEqualTo(
       s"""{
-         |  "sessionState": "75128aab4b1b",
+         |  "sessionState": "${SESSION_STATE.value}",
          |  "methodResponses": [[
          |    "Mailbox/set",
          |    {
          |      "accountId": "29883977c13473ae7cb7678ef767cbfbaffc8a44a6e463d971d23a65c1dc4af6",
-         |      "newState": "000001",
+         |      "newState": "${INSTANCE.value}",
          |      "notDestroyed": {
          |        "${mailboxId.serialize}": {
          |          "type": "mailboxHasEmail",
@@ -2470,12 +2472,12 @@ trait MailboxSetMethodContract {
 
     assertThatJson(response).isEqualTo(
       s"""{
-         |  "sessionState": "75128aab4b1b",
+         |  "sessionState": "${SESSION_STATE.value}",
          |  "methodResponses": [[
          |    "Mailbox/set",
          |    {
          |      "accountId": "29883977c13473ae7cb7678ef767cbfbaffc8a44a6e463d971d23a65c1dc4af6",
-         |      "newState": "000001",
+         |      "newState": "${INSTANCE.value}",
          |      "notDestroyed": {
          |        "${mailboxId.serialize}": {
          |          "type": "mailboxHasChild",
@@ -2526,12 +2528,12 @@ trait MailboxSetMethodContract {
 
     assertThatJson(response).isEqualTo(
       s"""{
-         |  "sessionState": "75128aab4b1b",
+         |  "sessionState": "${SESSION_STATE.value}",
          |  "methodResponses": [[
          |    "Mailbox/set",
          |    {
          |      "accountId": "29883977c13473ae7cb7678ef767cbfbaffc8a44a6e463d971d23a65c1dc4af6",
-         |      "newState": "000001",
+         |      "newState": "${INSTANCE.value}",
          |      "notDestroyed": {
          |        "${mailboxId.serialize}": {
          |          "type": "notFound",
@@ -2577,12 +2579,12 @@ trait MailboxSetMethodContract {
 
     assertThatJson(response).isEqualTo(
       s"""{
-         |  "sessionState": "75128aab4b1b",
+         |  "sessionState": "${SESSION_STATE.value}",
          |  "methodResponses": [[
          |    "Mailbox/set",
          |    {
          |      "accountId": "29883977c13473ae7cb7678ef767cbfbaffc8a44a6e463d971d23a65c1dc4af6",
-         |      "newState": "000001",
+         |      "newState": "${INSTANCE.value}",
          |      "notDestroyed": {
          |        "invalid": {
          |          "type": "invalidArguments",
@@ -2689,13 +2691,13 @@ trait MailboxSetMethodContract {
 
     assertThatJson(response).isEqualTo(
       s"""{
-         |    "sessionState": "75128aab4b1b",
+         |    "sessionState": "${SESSION_STATE.value}",
          |    "methodResponses": [
          |        [
          |            "Mailbox/set",
          |            {
          |                "accountId": "29883977c13473ae7cb7678ef767cbfbaffc8a44a6e463d971d23a65c1dc4af6",
-         |                "newState": "000001",
+         |                "newState": "${INSTANCE.value}",
          |                "created": {
          |                    "C42": {
          |                        "id": "$parentId",
@@ -2725,7 +2727,7 @@ trait MailboxSetMethodContract {
          |            "Mailbox/set",
          |            {
          |                "accountId": "29883977c13473ae7cb7678ef767cbfbaffc8a44a6e463d971d23a65c1dc4af6",
-         |                "newState": "000001",
+         |                "newState": "${INSTANCE.value}",
          |                "created": {
          |                    "C43": {
          |                        "id": "$childId",
@@ -2801,11 +2803,11 @@ trait MailboxSetMethodContract {
 
     assertThatJson(response).isEqualTo(
       s"""{
-         |  "sessionState": "75128aab4b1b",
+         |  "sessionState": "${SESSION_STATE.value}",
          |  "methodResponses": [
          |    ["Mailbox/set", {
          |      "accountId": "29883977c13473ae7cb7678ef767cbfbaffc8a44a6e463d971d23a65c1dc4af6",
-         |      "newState": "000001",
+         |      "newState": "${INSTANCE.value}",
          |      "notDestroyed": {
          |        "#C42": {
          |          "type": "invalidArguments",
@@ -2815,7 +2817,7 @@ trait MailboxSetMethodContract {
          |    }, "c2"],
          |    ["Mailbox/set", {
          |      "accountId": "29883977c13473ae7cb7678ef767cbfbaffc8a44a6e463d971d23a65c1dc4af6",
-         |      "newState": "000001",
+         |      "newState": "${INSTANCE.value}",
          |      "created": {
          |        "C42": {
          |          "id": "$mailboxId",
@@ -2875,11 +2877,11 @@ trait MailboxSetMethodContract {
 
     assertThatJson(response).isEqualTo(
       s"""{
-         |  "sessionState": "75128aab4b1b",
+         |  "sessionState": "${SESSION_STATE.value}",
          |  "methodResponses": [
          |    ["Mailbox/set", {
          |      "accountId": "29883977c13473ae7cb7678ef767cbfbaffc8a44a6e463d971d23a65c1dc4af6",
-         |      "newState": "000001",
+         |      "newState": "${INSTANCE.value}",
          |      "notDestroyed": {
          |        "#C42": {
          |          "type": "invalidArguments",
@@ -2924,11 +2926,11 @@ trait MailboxSetMethodContract {
     val message = "# is not a mailboxId: # was not used in previously defined creationIds"
     assertThatJson(response).isEqualTo(
       s"""{
-         |  "sessionState": "75128aab4b1b",
+         |  "sessionState": "${SESSION_STATE.value}",
          |  "methodResponses": [
          |    ["Mailbox/set", {
          |      "accountId": "29883977c13473ae7cb7678ef767cbfbaffc8a44a6e463d971d23a65c1dc4af6",
-         |      "newState": "000001",
+         |      "newState": "${INSTANCE.value}",
          |      "notDestroyed": {
          |        "#": {
          |          "type": "invalidArguments",
@@ -2986,18 +2988,18 @@ trait MailboxSetMethodContract {
 
     assertThatJson(response).isEqualTo(
       s"""{
-         |  "sessionState": "75128aab4b1b",
+         |  "sessionState": "${SESSION_STATE.value}",
          |  "methodResponses": [
          |    ["Mailbox/set", {
          |      "accountId": "29883977c13473ae7cb7678ef767cbfbaffc8a44a6e463d971d23a65c1dc4af6",
-         |      "newState": "000001",
+         |      "newState": "${INSTANCE.value}",
          |      "updated": {
          |        "${mailboxId.serialize}": {}
          |      }
          |    }, "c2"],
          |    ["Mailbox/get", {
          |      "accountId": "29883977c13473ae7cb7678ef767cbfbaffc8a44a6e463d971d23a65c1dc4af6",
-         |      "state": "000001",
+         |      "state": "${INSTANCE.value}",
          |      "list": [{
          |        "id": "${mailboxId.serialize}",
          |        "name": "newName"
@@ -3058,11 +3060,11 @@ trait MailboxSetMethodContract {
 
     assertThatJson(response).isEqualTo(
       s"""{
-         |  "sessionState": "75128aab4b1b",
+         |  "sessionState": "${SESSION_STATE.value}",
          |  "methodResponses": [
          |    ["Mailbox/set", {
          |      "accountId": "29883977c13473ae7cb7678ef767cbfbaffc8a44a6e463d971d23a65c1dc4af6",
-         |      "newState": "000001",
+         |      "newState": "${INSTANCE.value}",
          |      "created": {
          |        "C43": {
          |          "id": "$mailboxId",
@@ -3088,7 +3090,7 @@ trait MailboxSetMethodContract {
          |    }, "c1"],
          |    ["Mailbox/set", {
          |      "accountId": "29883977c13473ae7cb7678ef767cbfbaffc8a44a6e463d971d23a65c1dc4af6",
-         |      "newState": "000001",
+         |      "newState": "${INSTANCE.value}",
          |      "updated": {
          |        "$mailboxId": {}
          |      }
@@ -3176,11 +3178,11 @@ trait MailboxSetMethodContract {
 
     assertThatJson(response).isEqualTo(
       s"""{
-         |  "sessionState": "75128aab4b1b",
+         |  "sessionState": "${SESSION_STATE.value}",
          |  "methodResponses": [
          |    ["Mailbox/set", {
          |      "accountId": "29883977c13473ae7cb7678ef767cbfbaffc8a44a6e463d971d23a65c1dc4af6",
-         |      "newState": "000001",
+         |      "newState": "${INSTANCE.value}",
          |      "notUpdated": {
          |        "${mailboxId1.serialize}": {
          |          "type": "invalidArguments",
@@ -3229,11 +3231,11 @@ trait MailboxSetMethodContract {
 
     assertThatJson(response).isEqualTo(
       s"""{
-         |  "sessionState": "75128aab4b1b",
+         |  "sessionState": "${SESSION_STATE.value}",
          |  "methodResponses": [
          |    ["Mailbox/set", {
          |      "accountId": "29883977c13473ae7cb7678ef767cbfbaffc8a44a6e463d971d23a65c1dc4af6",
-         |      "newState": "000001",
+         |      "newState": "${INSTANCE.value}",
          |      "notUpdated": {
          |        "${mailboxId1.serialize}": {
          |          "type": "invalidArguments",
@@ -3282,11 +3284,11 @@ trait MailboxSetMethodContract {
 
     assertThatJson(response).isEqualTo(
       s"""{
-         |  "sessionState": "75128aab4b1b",
+         |  "sessionState": "${SESSION_STATE.value}",
          |  "methodResponses": [
          |    ["Mailbox/set", {
          |      "accountId": "29883977c13473ae7cb7678ef767cbfbaffc8a44a6e463d971d23a65c1dc4af6",
-         |      "newState": "000001",
+         |      "newState": "${INSTANCE.value}",
          |      "notUpdated": {
          |        "${mailboxId1.serialize}": {
          |          "type": "invalidArguments",
@@ -3335,11 +3337,11 @@ trait MailboxSetMethodContract {
 
     assertThatJson(response).isEqualTo(
       s"""{
-         |  "sessionState": "75128aab4b1b",
+         |  "sessionState": "${SESSION_STATE.value}",
          |  "methodResponses": [
          |    ["Mailbox/set", {
          |      "accountId": "29883977c13473ae7cb7678ef767cbfbaffc8a44a6e463d971d23a65c1dc4af6",
-         |      "newState": "000001",
+         |      "newState": "${INSTANCE.value}",
          |      "notUpdated": {
          |        "${mailboxId1.serialize}": {
          |          "type": "invalidArguments",
@@ -3389,11 +3391,11 @@ trait MailboxSetMethodContract {
     val message = "Invalid property specified in a patch object: Predicate isEmpty() did not fail."
     assertThatJson(response).isEqualTo(
       s"""{
-         |  "sessionState": "75128aab4b1b",
+         |  "sessionState": "${SESSION_STATE.value}",
          |  "methodResponses": [
          |    ["Mailbox/set", {
          |      "accountId": "29883977c13473ae7cb7678ef767cbfbaffc8a44a6e463d971d23a65c1dc4af6",
-         |      "newState": "000001",
+         |      "newState": "${INSTANCE.value}",
          |      "notUpdated": {
          |        "${mailboxId1.serialize}": {
          |          "type": "invalidPatch",
@@ -3441,11 +3443,11 @@ trait MailboxSetMethodContract {
 
     assertThatJson(response).isEqualTo(
       s"""{
-         |  "sessionState": "75128aab4b1b",
+         |  "sessionState": "${SESSION_STATE.value}",
          |  "methodResponses": [
          |    ["Mailbox/set", {
          |      "accountId": "29883977c13473ae7cb7678ef767cbfbaffc8a44a6e463d971d23a65c1dc4af6",
-         |      "newState": "000001",
+         |      "newState": "${INSTANCE.value}",
          |      "notUpdated": {
          |        "${mailboxId1.serialize}": {
          |          "type": "invalidArguments",
@@ -3494,11 +3496,11 @@ trait MailboxSetMethodContract {
 
     assertThatJson(response).isEqualTo(
       s"""{
-         |  "sessionState": "75128aab4b1b",
+         |  "sessionState": "${SESSION_STATE.value}",
          |  "methodResponses": [
          |    ["Mailbox/set", {
          |      "accountId": "29883977c13473ae7cb7678ef767cbfbaffc8a44a6e463d971d23a65c1dc4af6",
-         |      "newState": "000001",
+         |      "newState": "${INSTANCE.value}",
          |      "notUpdated": {
          |        "${mailboxId1.serialize}": {
          |          "type": "notFound",
@@ -3549,11 +3551,11 @@ trait MailboxSetMethodContract {
 
     assertThatJson(response).isEqualTo(
       s"""{
-         |  "sessionState": "75128aab4b1b",
+         |  "sessionState": "${SESSION_STATE.value}",
          |  "methodResponses": [
          |    ["Mailbox/set", {
          |      "accountId": "29883977c13473ae7cb7678ef767cbfbaffc8a44a6e463d971d23a65c1dc4af6",
-         |      "newState": "000001",
+         |      "newState": "${INSTANCE.value}",
          |      "notUpdated": {
          |        "${mailboxId1.serialize}": {
          |          "type": "notFound",
@@ -3602,11 +3604,11 @@ trait MailboxSetMethodContract {
 
     assertThatJson(response).isEqualTo(
       s"""{
-         |  "sessionState": "75128aab4b1b",
+         |  "sessionState": "${SESSION_STATE.value}",
          |  "methodResponses": [
          |    ["Mailbox/set", {
          |      "accountId": "29883977c13473ae7cb7678ef767cbfbaffc8a44a6e463d971d23a65c1dc4af6",
-         |      "newState": "000001",
+         |      "newState": "${INSTANCE.value}",
          |      "notUpdated": {
          |        "${mailboxId.serialize}": {
          |          "type": "invalidArguments",
@@ -3652,11 +3654,11 @@ trait MailboxSetMethodContract {
 
     assertThatJson(response).isEqualTo(
       s"""{
-         |  "sessionState": "75128aab4b1b",
+         |  "sessionState": "${SESSION_STATE.value}",
          |  "methodResponses": [
          |    ["Mailbox/set", {
          |      "accountId": "29883977c13473ae7cb7678ef767cbfbaffc8a44a6e463d971d23a65c1dc4af6",
-         |      "newState": "000001",
+         |      "newState": "${INSTANCE.value}",
          |      "notDestroyed": {
          |        "${mailboxId.serialize}": {
          |          "type": "invalidArguments",
@@ -3717,18 +3719,18 @@ trait MailboxSetMethodContract {
 
     assertThatJson(response).isEqualTo(
       s"""{
-         |  "sessionState": "75128aab4b1b",
+         |  "sessionState": "${SESSION_STATE.value}",
          |  "methodResponses": [
          |    ["Mailbox/set", {
          |      "accountId": "29883977c13473ae7cb7678ef767cbfbaffc8a44a6e463d971d23a65c1dc4af6",
-         |      "newState": "000001",
+         |      "newState": "${INSTANCE.value}",
          |      "updated": {
          |        "${childId.serialize}": {}
          |      }
          |    }, "c1"],
          |    ["Mailbox/get", {
          |      "accountId": "29883977c13473ae7cb7678ef767cbfbaffc8a44a6e463d971d23a65c1dc4af6",
-         |      "state": "000001",
+         |      "state": "${INSTANCE.value}",
          |      "list": [{
          |        "id": "${childId.serialize}",
          |        "name": "newChild",
@@ -3789,18 +3791,18 @@ trait MailboxSetMethodContract {
 
     assertThatJson(response).isEqualTo(
       s"""{
-         |  "sessionState": "75128aab4b1b",
+         |  "sessionState": "${SESSION_STATE.value}",
          |  "methodResponses": [
          |    ["Mailbox/set", {
          |      "accountId": "29883977c13473ae7cb7678ef767cbfbaffc8a44a6e463d971d23a65c1dc4af6",
-         |      "newState": "000001",
+         |      "newState": "${INSTANCE.value}",
          |      "updated": {
          |        "${parentId.serialize}": {}
          |      }
          |    }, "c1"],
          |    ["Mailbox/get", {
          |      "accountId": "29883977c13473ae7cb7678ef767cbfbaffc8a44a6e463d971d23a65c1dc4af6",
-         |      "state": "000001",
+         |      "state": "${INSTANCE.value}",
          |      "list": [{
          |        "id": "${childId.serialize}",
          |        "name": "child",
@@ -3857,12 +3859,12 @@ trait MailboxSetMethodContract {
 
     assertThatJson(response).isEqualTo(
       s"""{
-         |  "sessionState": "75128aab4b1b",
+         |  "sessionState": "${SESSION_STATE.value}",
          |  "methodResponses": [[
          |    "Mailbox/set",
          |    {
          |      "accountId": "29883977c13473ae7cb7678ef767cbfbaffc8a44a6e463d971d23a65c1dc4af6",
-         |      "newState": "000001",
+         |      "newState": "${INSTANCE.value}",
          |      "destroyed": ["${mailboxId.serialize}"]
          |    },
          |    "c1"]]
@@ -3931,13 +3933,13 @@ trait MailboxSetMethodContract {
 
     assertThatJson(response).isEqualTo(
       s"""{
-         |    "sessionState": "75128aab4b1b",
+         |    "sessionState": "${SESSION_STATE.value}",
          |    "methodResponses": [
          |        [
          |            "Mailbox/get",
          |            {
          |                "accountId": "29883977c13473ae7cb7678ef767cbfbaffc8a44a6e463d971d23a65c1dc4af6",
-         |                "state": "000001",
+         |                "state": "${INSTANCE.value}",
          |                "list": [
          |
          |                ],
@@ -4051,12 +4053,12 @@ trait MailboxSetMethodContract {
 
     assertThatJson(response).isEqualTo(
       s"""{
-         |  "sessionState": "75128aab4b1b",
+         |  "sessionState": "${SESSION_STATE.value}",
          |  "methodResponses": [[
          |    "Mailbox/set",
          |    {
          |      "accountId": "29883977c13473ae7cb7678ef767cbfbaffc8a44a6e463d971d23a65c1dc4af6",
-         |      "newState": "000001",
+         |      "newState": "${INSTANCE.value}",
          |      "notDestroyed": {
          |        "${mailboxId.serialize}": {
          |          "type": "mailboxHasEmail",
@@ -4114,18 +4116,18 @@ trait MailboxSetMethodContract {
 
     assertThatJson(response).isEqualTo(
       s"""{
-         |  "sessionState": "75128aab4b1b",
+         |  "sessionState": "${SESSION_STATE.value}",
          |  "methodResponses": [
          |    ["Mailbox/set", {
          |      "accountId": "29883977c13473ae7cb7678ef767cbfbaffc8a44a6e463d971d23a65c1dc4af6",
-         |      "newState": "000001",
+         |      "newState": "${INSTANCE.value}",
          |      "updated": {
          |        "${mailboxId.serialize}": {}
          |      }
          |    }, "c2"],
          |    ["Mailbox/get", {
          |      "accountId": "29883977c13473ae7cb7678ef767cbfbaffc8a44a6e463d971d23a65c1dc4af6",
-         |      "state": "000001",
+         |      "state": "${INSTANCE.value}",
          |      "list": [{
          |        "id": "${mailboxId.serialize}",
          |        "isSubscribed": true
@@ -4191,25 +4193,25 @@ trait MailboxSetMethodContract {
 
     assertThatJson(response).isEqualTo(
       s"""{
-         |  "sessionState": "75128aab4b1b",
+         |  "sessionState": "${SESSION_STATE.value}",
          |  "methodResponses": [
          |    ["Mailbox/set", {
          |      "accountId": "29883977c13473ae7cb7678ef767cbfbaffc8a44a6e463d971d23a65c1dc4af6",
-         |      "newState": "000001",
+         |      "newState": "${INSTANCE.value}",
          |      "updated": {
          |        "${mailboxId.serialize}": {}
          |      }
          |    }, "c2"],
          |    ["Mailbox/set", {
          |      "accountId": "29883977c13473ae7cb7678ef767cbfbaffc8a44a6e463d971d23a65c1dc4af6",
-         |      "newState": "000001",
+         |      "newState": "${INSTANCE.value}",
          |      "updated": {
          |        "${mailboxId.serialize}": {}
          |      }
          |    }, "c3"],
          |    ["Mailbox/get", {
          |      "accountId": "29883977c13473ae7cb7678ef767cbfbaffc8a44a6e463d971d23a65c1dc4af6",
-         |      "state": "000001",
+         |      "state": "${INSTANCE.value}",
          |      "list": [{
          |        "id": "${mailboxId.serialize}",
          |        "isSubscribed": false
@@ -4265,18 +4267,18 @@ trait MailboxSetMethodContract {
 
     assertThatJson(response).isEqualTo(
       s"""{
-         |  "sessionState": "75128aab4b1b",
+         |  "sessionState": "${SESSION_STATE.value}",
          |  "methodResponses": [
          |    ["Mailbox/set", {
          |      "accountId": "29883977c13473ae7cb7678ef767cbfbaffc8a44a6e463d971d23a65c1dc4af6",
-         |      "newState": "000001",
+         |      "newState": "${INSTANCE.value}",
          |      "updated": {
          |        "${mailboxId.serialize}": {}
          |      }
          |    }, "c3"],
          |    ["Mailbox/get", {
          |      "accountId": "29883977c13473ae7cb7678ef767cbfbaffc8a44a6e463d971d23a65c1dc4af6",
-         |      "state": "000001",
+         |      "state": "${INSTANCE.value}",
          |      "list": [{
          |        "id": "${mailboxId.serialize}",
          |        "isSubscribed": true
@@ -4337,18 +4339,18 @@ trait MailboxSetMethodContract {
 
     assertThatJson(response).isEqualTo(
       s"""{
-         |  "sessionState": "75128aab4b1b",
+         |  "sessionState": "${SESSION_STATE.value}",
          |  "methodResponses": [
          |    ["Mailbox/set", {
          |      "accountId": "29883977c13473ae7cb7678ef767cbfbaffc8a44a6e463d971d23a65c1dc4af6",
-         |      "newState": "000001",
+         |      "newState": "${INSTANCE.value}",
          |      "updated": {
          |        "${mailboxId.serialize}": {}
          |      }
          |    }, "c3"],
          |    ["Mailbox/get", {
          |      "accountId": "29883977c13473ae7cb7678ef767cbfbaffc8a44a6e463d971d23a65c1dc4af6",
-         |      "state": "000001",
+         |      "state": "${INSTANCE.value}",
          |      "list": [{
          |        "id": "${mailboxId.serialize}",
          |        "isSubscribed": true,
@@ -4419,25 +4421,25 @@ trait MailboxSetMethodContract {
 
     assertThatJson(response).isEqualTo(
       s"""{
-         |  "sessionState": "75128aab4b1b",
+         |  "sessionState": "${SESSION_STATE.value}",
          |  "methodResponses": [
          |    ["Mailbox/set", {
          |      "accountId": "29883977c13473ae7cb7678ef767cbfbaffc8a44a6e463d971d23a65c1dc4af6",
-         |      "newState": "000001",
+         |      "newState": "${INSTANCE.value}",
          |      "updated": {
          |        "${mailboxId.serialize}": {}
          |      }
          |    }, "c2"],
          |    ["Mailbox/set", {
          |      "accountId": "29883977c13473ae7cb7678ef767cbfbaffc8a44a6e463d971d23a65c1dc4af6",
-         |      "newState": "000001",
+         |      "newState": "${INSTANCE.value}",
          |      "updated": {
          |        "${mailboxId.serialize}": {}
          |      }
          |    }, "c3"],
          |    ["Mailbox/get", {
          |      "accountId": "29883977c13473ae7cb7678ef767cbfbaffc8a44a6e463d971d23a65c1dc4af6",
-         |      "state": "000001",
+         |      "state": "${INSTANCE.value}",
          |      "list": [{
          |        "id": "${mailboxId.serialize}",
          |        "isSubscribed": false,
@@ -4485,11 +4487,11 @@ trait MailboxSetMethodContract {
 
     assertThatJson(response).isEqualTo(
       s"""{
-         |  "sessionState": "75128aab4b1b",
+         |  "sessionState": "${SESSION_STATE.value}",
          |  "methodResponses": [
          |    ["Mailbox/set", {
          |      "accountId": "29883977c13473ae7cb7678ef767cbfbaffc8a44a6e463d971d23a65c1dc4af6",
-         |      "newState": "000001",
+         |      "newState": "${INSTANCE.value}",
          |      "notUpdated": {
          |        "${mailboxId1.serialize}": {
          |          "type": "invalidArguments",
@@ -4555,11 +4557,11 @@ trait MailboxSetMethodContract {
 
     assertThatJson(response).isEqualTo(
       s"""{
-         |  "sessionState": "75128aab4b1b",
+         |  "sessionState": "${SESSION_STATE.value}",
          |  "methodResponses": [
          |    ["Mailbox/set", {
          |      "accountId": "29883977c13473ae7cb7678ef767cbfbaffc8a44a6e463d971d23a65c1dc4af6",
-         |      "newState": "000001",
+         |      "newState": "${INSTANCE.value}",
          |      "updated": {
          |        "${andreId.serialize}": {},
          |        "${bobId.serialize}": {}
@@ -4567,7 +4569,7 @@ trait MailboxSetMethodContract {
          |    }, "c2"],
          |    ["Mailbox/get", {
          |      "accountId": "29883977c13473ae7cb7678ef767cbfbaffc8a44a6e463d971d23a65c1dc4af6",
-         |      "state": "000001",
+         |      "state": "${INSTANCE.value}",
          |      "list": [{
          |        "id": "${andreId.serialize}",
          |        "isSubscribed": true
@@ -4640,25 +4642,25 @@ trait MailboxSetMethodContract {
 
     assertThatJson(response).isEqualTo(
       s"""{
-         |  "sessionState": "75128aab4b1b",
+         |  "sessionState": "${SESSION_STATE.value}",
          |  "methodResponses": [
          |    ["Mailbox/set", {
          |      "accountId": "29883977c13473ae7cb7678ef767cbfbaffc8a44a6e463d971d23a65c1dc4af6",
-         |      "newState": "000001",
+         |      "newState": "${INSTANCE.value}",
          |      "updated": {
          |        "${mailboxId.serialize}": {}
          |      }
          |    }, "c2"],
          |    ["Mailbox/set", {
          |      "accountId": "29883977c13473ae7cb7678ef767cbfbaffc8a44a6e463d971d23a65c1dc4af6",
-         |      "newState": "000001",
+         |      "newState": "${INSTANCE.value}",
          |      "updated": {
          |        "${mailboxId.serialize}": {}
          |      }
          |    }, "c3"],
          |    ["Mailbox/get", {
          |      "accountId": "29883977c13473ae7cb7678ef767cbfbaffc8a44a6e463d971d23a65c1dc4af6",
-         |      "state": "000001",
+         |      "state": "${INSTANCE.value}",
          |      "list": [{
          |        "id": "${mailboxId.serialize}",
          |        "isSubscribed": false,
@@ -4749,11 +4751,11 @@ trait MailboxSetMethodContract {
 
     assertThatJson(response).isEqualTo(
       s"""{
-         |  "sessionState": "75128aab4b1b",
+         |  "sessionState": "${SESSION_STATE.value}",
          |  "methodResponses": [
          |    ["Mailbox/set", {
          |      "accountId": "29883977c13473ae7cb7678ef767cbfbaffc8a44a6e463d971d23a65c1dc4af6",
-         |      "newState": "000001",
+         |      "newState": "${INSTANCE.value}",
          |      "notUpdated": {
          |        "${mailboxId.serialize}": {
          |          "type": "invalidArguments",
@@ -4851,13 +4853,13 @@ trait MailboxSetMethodContract {
 
     assertThatJson(response).isEqualTo(
       s"""{
-         |    "sessionState": "75128aab4b1b",
+         |    "sessionState": "${SESSION_STATE.value}",
          |    "methodResponses": [
          |        [
          |            "Mailbox/set",
          |            {
          |                "accountId": "29883977c13473ae7cb7678ef767cbfbaffc8a44a6e463d971d23a65c1dc4af6",
-         |                "newState": "000001",
+         |                "newState": "${INSTANCE.value}",
          |                "notUpdated": {
          |                    "${mailboxId.serialize}": {
          |                        "type": "invalidArguments",
@@ -4911,13 +4913,13 @@ trait MailboxSetMethodContract {
 
     assertThatJson(response).isEqualTo(
       s"""{
-         |    "sessionState": "75128aab4b1b",
+         |    "sessionState": "${SESSION_STATE.value}",
          |    "methodResponses": [
          |        [
          |            "Mailbox/set",
          |            {
          |                "accountId": "29883977c13473ae7cb7678ef767cbfbaffc8a44a6e463d971d23a65c1dc4af6",
-         |                "newState": "000001",
+         |                "newState": "${INSTANCE.value}",
          |                "notUpdated": {
          |                    "${mailboxId.serialize}": {
          |                        "type": "invalidArguments",
@@ -4971,13 +4973,13 @@ trait MailboxSetMethodContract {
 
     assertThatJson(response).isEqualTo(
       s"""{
-         |    "sessionState": "75128aab4b1b",
+         |    "sessionState": "${SESSION_STATE.value}",
          |    "methodResponses": [
          |        [
          |            "Mailbox/set",
          |            {
          |                "accountId": "29883977c13473ae7cb7678ef767cbfbaffc8a44a6e463d971d23a65c1dc4af6",
-         |                "newState": "000001",
+         |                "newState": "${INSTANCE.value}",
          |                "notUpdated": {
          |                    "${mailboxId.serialize}": {
          |                        "type": "invalidArguments",
@@ -5041,18 +5043,18 @@ trait MailboxSetMethodContract {
 
     assertThatJson(response).isEqualTo(
       s"""{
-         |  "sessionState": "75128aab4b1b",
+         |  "sessionState": "${SESSION_STATE.value}",
          |  "methodResponses": [
          |    ["Mailbox/set", {
          |      "accountId": "29883977c13473ae7cb7678ef767cbfbaffc8a44a6e463d971d23a65c1dc4af6",
-         |      "newState": "000001",
+         |      "newState": "${INSTANCE.value}",
          |      "updated": {
          |        "${mailboxId.serialize}": {}
          |      }
          |    }, "c1"],
          |    ["Mailbox/get", {
          |      "accountId": "29883977c13473ae7cb7678ef767cbfbaffc8a44a6e463d971d23a65c1dc4af6",
-         |      "state": "000001",
+         |      "state": "${INSTANCE.value}",
          |      "list": [{
          |        "id": "${mailboxId.serialize}",
          |        "rights": {
@@ -5122,18 +5124,18 @@ trait MailboxSetMethodContract {
 
     assertThatJson(response).isEqualTo(
       s"""{
-         |  "sessionState": "75128aab4b1b",
+         |  "sessionState": "${SESSION_STATE.value}",
          |  "methodResponses": [
          |    ["Mailbox/set", {
          |      "accountId": "29883977c13473ae7cb7678ef767cbfbaffc8a44a6e463d971d23a65c1dc4af6",
-         |      "newState": "000001",
+         |      "newState": "${INSTANCE.value}",
          |      "updated": {
          |        "${mailboxId.serialize}": {}
          |      }
          |    }, "c1"],
          |    ["Mailbox/get", {
          |      "accountId": "29883977c13473ae7cb7678ef767cbfbaffc8a44a6e463d971d23a65c1dc4af6",
-         |      "state": "000001",
+         |      "state": "${INSTANCE.value}",
          |      "list": [{
          |        "id": "${mailboxId.serialize}",
          |        "rights": {
@@ -5201,11 +5203,11 @@ trait MailboxSetMethodContract {
 
     assertThatJson(response).isEqualTo(
       s"""{
-         |  "sessionState": "75128aab4b1b",
+         |  "sessionState": "${SESSION_STATE.value}",
          |  "methodResponses": [
          |    ["Mailbox/set", {
          |      "accountId": "29883977c13473ae7cb7678ef767cbfbaffc8a44a6e463d971d23a65c1dc4af6",
-         |      "newState": "000001",
+         |      "newState": "${INSTANCE.value}",
          |      "notUpdated": {
          |        "${mailboxId.serialize}": {
          |          "type": "invalidArguments",
@@ -5215,7 +5217,7 @@ trait MailboxSetMethodContract {
          |    }, "c1"],
          |    ["Mailbox/get", {
          |      "accountId": "29883977c13473ae7cb7678ef767cbfbaffc8a44a6e463d971d23a65c1dc4af6",
-         |      "state": "000001",
+         |      "state": "${INSTANCE.value}",
          |      "list": [{
          |        "id": "${mailboxId.serialize}",
          |        "namespace": "Delegated[andre@domain.tld]",
@@ -5277,11 +5279,11 @@ trait MailboxSetMethodContract {
 
     assertThatJson(response).isEqualTo(
       s"""{
-         |  "sessionState": "75128aab4b1b",
+         |  "sessionState": "${SESSION_STATE.value}",
          |  "methodResponses": [
          |    ["Mailbox/set", {
          |      "accountId": "29883977c13473ae7cb7678ef767cbfbaffc8a44a6e463d971d23a65c1dc4af6",
-         |      "newState": "000001",
+         |      "newState": "${INSTANCE.value}",
          |      "notUpdated": {
          |        "${mailboxId.serialize}": {
          |          "type": "notFound",
@@ -5337,11 +5339,11 @@ trait MailboxSetMethodContract {
 
     assertThatJson(response).isEqualTo(
       s"""{
-         |  "sessionState": "75128aab4b1b",
+         |  "sessionState": "${SESSION_STATE.value}",
          |  "methodResponses": [
          |    ["Mailbox/set", {
          |      "accountId": "29883977c13473ae7cb7678ef767cbfbaffc8a44a6e463d971d23a65c1dc4af6",
-         |      "newState": "000001",
+         |      "newState": "${INSTANCE.value}",
          |      "notUpdated": {
          |        "${mailboxId.serialize}": {
          |          "type": "invalidArguments",
@@ -5405,18 +5407,18 @@ trait MailboxSetMethodContract {
 
     assertThatJson(response).isEqualTo(
       s"""{
-         |  "sessionState": "75128aab4b1b",
+         |  "sessionState": "${SESSION_STATE.value}",
          |  "methodResponses": [
          |    ["Mailbox/set", {
          |      "accountId": "29883977c13473ae7cb7678ef767cbfbaffc8a44a6e463d971d23a65c1dc4af6",
-         |      "newState": "000001",
+         |      "newState": "${INSTANCE.value}",
          |      "updated": {
          |        "${mailboxId.serialize}": {}
          |      }
          |    }, "c1"],
          |    ["Mailbox/get", {
          |      "accountId": "29883977c13473ae7cb7678ef767cbfbaffc8a44a6e463d971d23a65c1dc4af6",
-         |      "state": "000001",
+         |      "state": "${INSTANCE.value}",
          |      "list": [{
          |        "id": "${mailboxId.serialize}",
          |        "rights": {
@@ -5471,11 +5473,11 @@ trait MailboxSetMethodContract {
 
     assertThatJson(response).isEqualTo(
       s"""{
-         |  "sessionState": "75128aab4b1b",
+         |  "sessionState": "${SESSION_STATE.value}",
          |  "methodResponses": [
          |    ["Mailbox/set", {
          |      "accountId": "29883977c13473ae7cb7678ef767cbfbaffc8a44a6e463d971d23a65c1dc4af6",
-         |      "newState": "000001",
+         |      "newState": "${INSTANCE.value}",
          |      "notUpdated": {
          |        "${mailboxId.serialize}": {
          |          "type": "invalidPatch",
@@ -5528,13 +5530,13 @@ trait MailboxSetMethodContract {
 
     assertThatJson(response).isEqualTo(
       s"""{
-         |    "sessionState": "75128aab4b1b",
+         |    "sessionState": "${SESSION_STATE.value}",
          |    "methodResponses": [
          |        [
          |            "Mailbox/set",
          |            {
          |                "accountId": "29883977c13473ae7cb7678ef767cbfbaffc8a44a6e463d971d23a65c1dc4af6",
-         |                "newState": "000001",
+         |                "newState": "${INSTANCE.value}",
          |                "notUpdated": {
          |                    "${mailboxId.serialize}": {
          |                        "type": "invalidArguments",
@@ -5595,13 +5597,13 @@ trait MailboxSetMethodContract {
 
     assertThatJson(response).isEqualTo(
       s"""{
-         |    "sessionState": "75128aab4b1b",
+         |    "sessionState": "${SESSION_STATE.value}",
          |    "methodResponses": [
          |        [
          |            "Mailbox/set",
          |            {
          |                "accountId": "29883977c13473ae7cb7678ef767cbfbaffc8a44a6e463d971d23a65c1dc4af6",
-         |                "newState": "000001",
+         |                "newState": "${INSTANCE.value}",
          |                "notUpdated": {
          |                    "${mailboxId.serialize}": {
          |                        "type": "invalidPatch",
@@ -5657,11 +5659,11 @@ trait MailboxSetMethodContract {
 
     assertThatJson(response).isEqualTo(
       s"""{
-         |  "sessionState": "75128aab4b1b",
+         |  "sessionState": "${SESSION_STATE.value}",
          |  "methodResponses": [
          |    ["Mailbox/set", {
          |      "accountId": "29883977c13473ae7cb7678ef767cbfbaffc8a44a6e463d971d23a65c1dc4af6",
-         |      "newState": "000001",
+         |      "newState": "${INSTANCE.value}",
          |      "notUpdated": {
          |        "${mailboxId.serialize}": {
          |          "type": "notFound",
@@ -5722,11 +5724,11 @@ trait MailboxSetMethodContract {
 
     assertThatJson(response).isEqualTo(
       s"""{
-         |  "sessionState": "75128aab4b1b",
+         |  "sessionState": "${SESSION_STATE.value}",
          |  "methodResponses": [
          |    ["Mailbox/set", {
          |      "accountId": "29883977c13473ae7cb7678ef767cbfbaffc8a44a6e463d971d23a65c1dc4af6",
-         |      "newState": "000001",
+         |      "newState": "${INSTANCE.value}",
          |      "notUpdated": {
          |        "${mailboxId.serialize}": {
          |          "type": "invalidArguments",
@@ -5792,18 +5794,18 @@ trait MailboxSetMethodContract {
 
     assertThatJson(response).isEqualTo(
       s"""{
-         |  "sessionState": "75128aab4b1b",
+         |  "sessionState": "${SESSION_STATE.value}",
          |  "methodResponses": [
          |    ["Mailbox/set", {
          |      "accountId": "29883977c13473ae7cb7678ef767cbfbaffc8a44a6e463d971d23a65c1dc4af6",
-         |      "newState": "000001",
+         |      "newState": "${INSTANCE.value}",
          |      "updated": {
          |        "${mailboxId.serialize}": {}
          |      }
          |    }, "c1"],
          |    ["Mailbox/get", {
          |      "accountId": "29883977c13473ae7cb7678ef767cbfbaffc8a44a6e463d971d23a65c1dc4af6",
-         |      "state": "000001",
+         |      "state": "${INSTANCE.value}",
          |      "list": [{
          |        "id": "${mailboxId.serialize}",
          |        "name": "mailbox",
@@ -5855,13 +5857,13 @@ trait MailboxSetMethodContract {
 
     assertThatJson(response).isEqualTo(
       s"""{
-         |    "sessionState": "75128aab4b1b",
+         |    "sessionState": "${SESSION_STATE.value}",
          |    "methodResponses": [
          |        [
          |            "Mailbox/set",
          |            {
          |                "accountId": "29883977c13473ae7cb7678ef767cbfbaffc8a44a6e463d971d23a65c1dc4af6",
-         |                "newState": "000001",
+         |                "newState": "${INSTANCE.value}",
          |                "notUpdated": {
          |                    "${mailboxId.serialize}": {
          |                        "type": "invalidArguments",
@@ -5920,13 +5922,13 @@ trait MailboxSetMethodContract {
 
     assertThatJson(response).isEqualTo(
       s"""{
-         |    "sessionState": "75128aab4b1b",
+         |    "sessionState": "${SESSION_STATE.value}",
          |    "methodResponses": [
          |        [
          |            "Mailbox/set",
          |            {
          |                "accountId": "29883977c13473ae7cb7678ef767cbfbaffc8a44a6e463d971d23a65c1dc4af6",
-         |                "newState": "000001",
+         |                "newState": "${INSTANCE.value}",
          |                "notUpdated": {
          |                    "${mailboxId.serialize}": {
          |                        "type": "invalidArguments",
@@ -6145,18 +6147,18 @@ trait MailboxSetMethodContract {
 
     assertThatJson(response).isEqualTo(
       s"""{
-         |  "sessionState": "75128aab4b1b",
+         |  "sessionState": "${SESSION_STATE.value}",
          |  "methodResponses": [
          |    ["Mailbox/set", {
          |      "accountId": "29883977c13473ae7cb7678ef767cbfbaffc8a44a6e463d971d23a65c1dc4af6",
-         |      "newState": "000001",
+         |      "newState": "${INSTANCE.value}",
          |      "updated": {
          |        "${mailboxId.serialize}": {}
          |      }
          |    }, "c1"],
          |    ["Mailbox/get", {
          |      "accountId": "29883977c13473ae7cb7678ef767cbfbaffc8a44a6e463d971d23a65c1dc4af6",
-         |      "state": "000001",
+         |      "state": "${INSTANCE.value}",
          |      "list": [{
          |        "id": "${mailboxId.serialize}",
          |        "name": "mailbox",
@@ -6217,18 +6219,18 @@ trait MailboxSetMethodContract {
 
     assertThatJson(response).isEqualTo(
       s"""{
-         |  "sessionState": "75128aab4b1b",
+         |  "sessionState": "${SESSION_STATE.value}",
          |  "methodResponses": [
          |    ["Mailbox/set", {
          |      "accountId": "29883977c13473ae7cb7678ef767cbfbaffc8a44a6e463d971d23a65c1dc4af6",
-         |      "newState": "000001",
+         |      "newState": "${INSTANCE.value}",
          |      "updated": {
          |        "${mailboxId.serialize}": {}
          |      }
          |    }, "c1"],
          |    ["Mailbox/get", {
          |      "accountId": "29883977c13473ae7cb7678ef767cbfbaffc8a44a6e463d971d23a65c1dc4af6",
-         |      "state": "000001",
+         |      "state": "${INSTANCE.value}",
          |      "list": [{
          |        "id": "${mailboxId.serialize}",
          |        "name": "newName",
@@ -6290,18 +6292,18 @@ trait MailboxSetMethodContract {
 
     assertThatJson(response).isEqualTo(
       s"""{
-         |  "sessionState": "75128aab4b1b",
+         |  "sessionState": "${SESSION_STATE.value}",
          |  "methodResponses": [
          |    ["Mailbox/set", {
          |      "accountId": "29883977c13473ae7cb7678ef767cbfbaffc8a44a6e463d971d23a65c1dc4af6",
-         |      "newState": "000001",
+         |      "newState": "${INSTANCE.value}",
          |      "updated": {
          |        "${mailboxId.serialize}": {}
          |      }
          |    }, "c1"],
          |    ["Mailbox/get", {
          |      "accountId": "29883977c13473ae7cb7678ef767cbfbaffc8a44a6e463d971d23a65c1dc4af6",
-         |      "state": "000001",
+         |      "state": "${INSTANCE.value}",
          |      "list": [{
          |        "id": "${mailboxId.serialize}",
          |        "name": "newName",
@@ -6362,18 +6364,18 @@ trait MailboxSetMethodContract {
 
     assertThatJson(response).isEqualTo(
       s"""{
-         |  "sessionState": "75128aab4b1b",
+         |  "sessionState": "${SESSION_STATE.value}",
          |  "methodResponses": [
          |    ["Mailbox/set", {
          |      "accountId": "29883977c13473ae7cb7678ef767cbfbaffc8a44a6e463d971d23a65c1dc4af6",
-         |      "newState": "000001",
+         |      "newState": "${INSTANCE.value}",
          |      "updated": {
          |        "${mailboxId.serialize}": {}
          |      }
          |    }, "c1"],
          |    ["Mailbox/get", {
          |      "accountId": "29883977c13473ae7cb7678ef767cbfbaffc8a44a6e463d971d23a65c1dc4af6",
-         |      "state": "000001",
+         |      "state": "${INSTANCE.value}",
          |      "list": [{
          |        "id": "${mailboxId.serialize}",
          |        "name": "mailbox"
@@ -6433,18 +6435,18 @@ trait MailboxSetMethodContract {
 
     assertThatJson(response).isEqualTo(
       s"""{
-         |  "sessionState": "75128aab4b1b",
+         |  "sessionState": "${SESSION_STATE.value}",
          |  "methodResponses": [
          |    ["Mailbox/set", {
          |      "accountId": "29883977c13473ae7cb7678ef767cbfbaffc8a44a6e463d971d23a65c1dc4af6",
-         |      "newState": "000001",
+         |      "newState": "${INSTANCE.value}",
          |      "updated": {
          |        "${mailboxId.serialize}": {}
          |      }
          |    }, "c1"],
          |    ["Mailbox/get", {
          |      "accountId": "29883977c13473ae7cb7678ef767cbfbaffc8a44a6e463d971d23a65c1dc4af6",
-         |      "state": "000001",
+         |      "state": "${INSTANCE.value}",
          |      "list": [{
          |        "id": "${mailboxId.serialize}",
          |        "name": "newName"
@@ -6505,18 +6507,18 @@ trait MailboxSetMethodContract {
 
     assertThatJson(response).isEqualTo(
       s"""{
-         |  "sessionState": "75128aab4b1b",
+         |  "sessionState": "${SESSION_STATE.value}",
          |  "methodResponses": [
          |    ["Mailbox/set", {
          |      "accountId": "29883977c13473ae7cb7678ef767cbfbaffc8a44a6e463d971d23a65c1dc4af6",
-         |      "newState": "000001",
+         |      "newState": "${INSTANCE.value}",
          |      "updated": {
          |        "${mailboxId.serialize}": {}
          |      }
          |    }, "c1"],
          |    ["Mailbox/get", {
          |      "accountId": "29883977c13473ae7cb7678ef767cbfbaffc8a44a6e463d971d23a65c1dc4af6",
-         |      "state": "000001",
+         |      "state": "${INSTANCE.value}",
          |      "list": [{
          |        "id": "${mailboxId.serialize}",
          |        "name": "newName"
@@ -6574,18 +6576,18 @@ trait MailboxSetMethodContract {
 
     assertThatJson(response).isEqualTo(
       s"""{
-         |  "sessionState": "75128aab4b1b",
+         |  "sessionState": "${SESSION_STATE.value}",
          |  "methodResponses": [
          |    ["Mailbox/set", {
          |      "accountId": "29883977c13473ae7cb7678ef767cbfbaffc8a44a6e463d971d23a65c1dc4af6",
-         |      "newState": "000001",
+         |      "newState": "${INSTANCE.value}",
          |      "updated": {
          |        "${mailboxId.serialize}": {}
          |      }
          |    }, "c1"],
          |    ["Mailbox/get", {
          |      "accountId": "29883977c13473ae7cb7678ef767cbfbaffc8a44a6e463d971d23a65c1dc4af6",
-         |      "state": "000001",
+         |      "state": "${INSTANCE.value}",
          |      "list": [{
          |        "id": "${mailboxId.serialize}",
          |        "name": "mailbox"
@@ -6645,18 +6647,18 @@ trait MailboxSetMethodContract {
 
     assertThatJson(response).isEqualTo(
       s"""{
-         |  "sessionState": "75128aab4b1b",
+         |  "sessionState": "${SESSION_STATE.value}",
          |  "methodResponses": [
          |    ["Mailbox/set", {
          |      "accountId": "29883977c13473ae7cb7678ef767cbfbaffc8a44a6e463d971d23a65c1dc4af6",
-         |      "newState": "000001",
+         |      "newState": "${INSTANCE.value}",
          |      "updated": {
          |        "${mailboxId.serialize}": {}
          |      }
          |    }, "c1"],
          |    ["Mailbox/get", {
          |      "accountId": "29883977c13473ae7cb7678ef767cbfbaffc8a44a6e463d971d23a65c1dc4af6",
-         |      "state": "000001",
+         |      "state": "${INSTANCE.value}",
          |      "list": [{
          |        "id": "${mailboxId.serialize}",
          |        "parentId": "${parentId.serialize}",
@@ -6731,11 +6733,11 @@ trait MailboxSetMethodContract {
 
     assertThatJson(response).isEqualTo(
       s"""{
-         |  "sessionState": "75128aab4b1b",
+         |  "sessionState": "${SESSION_STATE.value}",
          |  "methodResponses": [
          |    ["Mailbox/set", {
          |      "accountId": "29883977c13473ae7cb7678ef767cbfbaffc8a44a6e463d971d23a65c1dc4af6",
-         |      "newState": "000001",
+         |      "newState": "${INSTANCE.value}",
          |      "created": {
          |        "C42": {
          |          "id": "$parentId",
@@ -6761,14 +6763,14 @@ trait MailboxSetMethodContract {
          |    }, "c1"],
          |    ["Mailbox/set", {
          |      "accountId": "29883977c13473ae7cb7678ef767cbfbaffc8a44a6e463d971d23a65c1dc4af6",
-         |      "newState": "000001",
+         |      "newState": "${INSTANCE.value}",
          |      "updated": {
          |        "${mailboxId.serialize}": {}
          |      }
          |    }, "c2"],
          |    ["Mailbox/get", {
          |      "accountId": "29883977c13473ae7cb7678ef767cbfbaffc8a44a6e463d971d23a65c1dc4af6",
-         |      "state": "000001",
+         |      "state": "${INSTANCE.value}",
          |      "list": [{
          |        "id": "${mailboxId.serialize}",
          |        "name": "mailbox",
@@ -6819,11 +6821,11 @@ trait MailboxSetMethodContract {
 
     assertThatJson(response).isEqualTo(
       s"""{
-         |  "sessionState": "75128aab4b1b",
+         |  "sessionState": "${SESSION_STATE.value}",
          |  "methodResponses": [
          |    ["Mailbox/set", {
          |      "accountId": "29883977c13473ae7cb7678ef767cbfbaffc8a44a6e463d971d23a65c1dc4af6",
-         |      "newState": "000001",
+         |      "newState": "${INSTANCE.value}",
          |      "notUpdated": {
          |        "${mailboxId.serialize}": {
          |          "type": "invalidArguments",
@@ -6875,11 +6877,11 @@ trait MailboxSetMethodContract {
 
     assertThatJson(response).isEqualTo(
       s"""{
-         |  "sessionState": "75128aab4b1b",
+         |  "sessionState": "${SESSION_STATE.value}",
          |  "methodResponses": [
          |    ["Mailbox/set", {
          |      "accountId": "29883977c13473ae7cb7678ef767cbfbaffc8a44a6e463d971d23a65c1dc4af6",
-         |      "newState": "000001",
+         |      "newState": "${INSTANCE.value}",
          |      "notUpdated": {
          |        "${mailboxId.serialize}": {
          |          "type": "invalidArguments",
@@ -6932,11 +6934,11 @@ trait MailboxSetMethodContract {
 
     assertThatJson(response).isEqualTo(
       s"""{
-         |  "sessionState": "75128aab4b1b",
+         |  "sessionState": "${SESSION_STATE.value}",
          |  "methodResponses": [
          |    ["Mailbox/set", {
          |      "accountId": "29883977c13473ae7cb7678ef767cbfbaffc8a44a6e463d971d23a65c1dc4af6",
-         |      "newState": "000001",
+         |      "newState": "${INSTANCE.value}",
          |      "notUpdated": {
          |        "${mailboxId.serialize}": {
          |          "type": "notFound",
@@ -6989,11 +6991,11 @@ trait MailboxSetMethodContract {
 
     assertThatJson(response).isEqualTo(
       s"""{
-         |  "sessionState": "75128aab4b1b",
+         |  "sessionState": "${SESSION_STATE.value}",
          |  "methodResponses": [
          |    ["Mailbox/set", {
          |      "accountId": "29883977c13473ae7cb7678ef767cbfbaffc8a44a6e463d971d23a65c1dc4af6",
-         |      "newState": "000001",
+         |      "newState": "${INSTANCE.value}",
          |      "notUpdated": {
          |        "${mailboxId.serialize}": {
          |          "type": "invalidArguments",
@@ -7048,11 +7050,11 @@ trait MailboxSetMethodContract {
 
     assertThatJson(response).isEqualTo(
       s"""{
-         |  "sessionState": "75128aab4b1b",
+         |  "sessionState": "${SESSION_STATE.value}",
          |  "methodResponses": [
          |    ["Mailbox/set", {
          |      "accountId": "29883977c13473ae7cb7678ef767cbfbaffc8a44a6e463d971d23a65c1dc4af6",
-         |      "newState": "000001",
+         |      "newState": "${INSTANCE.value}",
          |      "notUpdated": {
          |        "${mailboxId.serialize}": {
          |          "type": "invalidArguments",
@@ -7112,11 +7114,11 @@ trait MailboxSetMethodContract {
 
     assertThatJson(response).isEqualTo(
       s"""{
-         |  "sessionState": "75128aab4b1b",
+         |  "sessionState": "${SESSION_STATE.value}",
          |  "methodResponses": [
          |    ["Mailbox/set", {
          |      "accountId": "29883977c13473ae7cb7678ef767cbfbaffc8a44a6e463d971d23a65c1dc4af6",
-         |      "newState": "000001",
+         |      "newState": "${INSTANCE.value}",
          |      "notUpdated": {
          |        "${mailboxId.serialize}": {
          |          "type": "notFound",
@@ -7174,11 +7176,11 @@ trait MailboxSetMethodContract {
 
     assertThatJson(response).isEqualTo(
       s"""{
-         |  "sessionState": "75128aab4b1b",
+         |  "sessionState": "${SESSION_STATE.value}",
          |  "methodResponses": [
          |    ["Mailbox/set", {
          |      "accountId": "29883977c13473ae7cb7678ef767cbfbaffc8a44a6e463d971d23a65c1dc4af6",
-         |      "newState": "000001",
+         |      "newState": "${INSTANCE.value}",
          |      "notUpdated": {
          |        "${mailboxId.serialize}": {
          |          "type": "notFound",
@@ -7236,11 +7238,11 @@ trait MailboxSetMethodContract {
 
     assertThatJson(response).isEqualTo(
       s"""{
-         |  "sessionState": "75128aab4b1b",
+         |  "sessionState": "${SESSION_STATE.value}",
          |  "methodResponses": [
          |    ["Mailbox/set", {
          |      "accountId": "29883977c13473ae7cb7678ef767cbfbaffc8a44a6e463d971d23a65c1dc4af6",
-         |      "newState": "000001",
+         |      "newState": "${INSTANCE.value}",
          |      "notUpdated": {
          |        "${mailboxId.serialize}": {
          |          "type": "notFound",
@@ -7305,18 +7307,18 @@ trait MailboxSetMethodContract {
 
     assertThatJson(response).isEqualTo(
       s"""{
-         |  "sessionState": "75128aab4b1b",
+         |  "sessionState": "${SESSION_STATE.value}",
          |  "methodResponses": [
          |    ["Mailbox/set", {
          |      "accountId": "29883977c13473ae7cb7678ef767cbfbaffc8a44a6e463d971d23a65c1dc4af6",
-         |      "newState": "000001",
+         |      "newState": "${INSTANCE.value}",
          |      "updated": {
          |        "${mailboxId.serialize}": {}
          |      }
          |    }, "c1"],
          |    ["Mailbox/get", {
          |      "accountId": "29883977c13473ae7cb7678ef767cbfbaffc8a44a6e463d971d23a65c1dc4af6",
-         |      "state": "000001",
+         |      "state": "${INSTANCE.value}",
          |      "list": [{
          |        "id": "${parentId.serialize}",
          |        "name": "parent",
@@ -7372,13 +7374,13 @@ trait MailboxSetMethodContract {
 
     assertThatJson(response).isEqualTo(
       s"""{
-         |    "sessionState": "75128aab4b1b",
+         |    "sessionState": "${SESSION_STATE.value}",
          |    "methodResponses": [
          |        [
          |            "Mailbox/set",
          |            {
          |                "accountId": "29883977c13473ae7cb7678ef767cbfbaffc8a44a6e463d971d23a65c1dc4af6",
-         |                "newState": "000001",
+         |                "newState": "${INSTANCE.value}",
          |                "updated": {
          |                    "${mailboxId.serialize}": {
          |
@@ -7420,7 +7422,7 @@ trait MailboxSetMethodContract {
 
     assertThatJson(response).isEqualTo(
       s"""{
-         |  "sessionState": "75128aab4b1b",
+         |  "sessionState": "${SESSION_STATE.value}",
          |  "methodResponses": [[
          |    "error",
          |    {
@@ -7460,7 +7462,7 @@ trait MailboxSetMethodContract {
 
     assertThatJson(response).isEqualTo(
       s"""{
-         |  "sessionState": "75128aab4b1b",
+         |  "sessionState": "${SESSION_STATE.value}",
          |  "methodResponses": [[
          |    "error",
          |    {
@@ -7504,13 +7506,13 @@ trait MailboxSetMethodContract {
 
     assertThatJson(response).isEqualTo(
       s"""{
-         |    "sessionState": "75128aab4b1b",
+         |    "sessionState": "${SESSION_STATE.value}",
          |    "methodResponses": [
          |        [
          |            "Mailbox/set",
          |            {
          |                "accountId": "29883977c13473ae7cb7678ef767cbfbaffc8a44a6e463d971d23a65c1dc4af6",
-         |                "newState": "000001",
+         |                "newState": "${INSTANCE.value}",
          |                "notUpdated": {
          |                    "#invalid": {
          |                        "type": "invalidArguments",
diff --git a/server/protocols/jmap-rfc-8621-integration-tests/jmap-rfc-8621-integration-tests-common/src/main/scala/org/apache/james/jmap/rfc8621/contract/SessionRoutesContract.scala b/server/protocols/jmap-rfc-8621-integration-tests/jmap-rfc-8621-integration-tests-common/src/main/scala/org/apache/james/jmap/rfc8621/contract/SessionRoutesContract.scala
index b33c01e..b6a1d50 100644
--- a/server/protocols/jmap-rfc-8621-integration-tests/jmap-rfc-8621-integration-tests-common/src/main/scala/org/apache/james/jmap/rfc8621/contract/SessionRoutesContract.scala
+++ b/server/protocols/jmap-rfc-8621-integration-tests/jmap-rfc-8621-integration-tests-common/src/main/scala/org/apache/james/jmap/rfc8621/contract/SessionRoutesContract.scala
@@ -114,7 +114,7 @@ object SessionRoutesContract {
                          |  "downloadUrl" : "http://domain.com/download/{accountId}/{blobId}/?type={type}&name={name}",
                          |  "uploadUrl" : "http://domain.com/upload/{accountId}",
                          |  "eventSourceUrl" : "http://domain.com/eventSource",
-                         |  "state" : "000001"
+                         |  "state" : "2c9f1b12-b35a-43e6-9af2-0106fb53a943"
                          |}""".stripMargin
   private val EXPECTED_BASE_PATH: String = "/jmap"
 }
diff --git a/server/protocols/jmap-rfc-8621-integration-tests/jmap-rfc-8621-integration-tests-common/src/main/scala/org/apache/james/jmap/rfc8621/contract/ThreadChangesContract.scala b/server/protocols/jmap-rfc-8621-integration-tests/jmap-rfc-8621-integration-tests-common/src/main/scala/org/apache/james/jmap/rfc8621/contract/ThreadChangesContract.scala
index 6695084..4b7c384 100644
--- a/server/protocols/jmap-rfc-8621-integration-tests/jmap-rfc-8621-integration-tests-common/src/main/scala/org/apache/james/jmap/rfc8621/contract/ThreadChangesContract.scala
+++ b/server/protocols/jmap-rfc-8621-integration-tests/jmap-rfc-8621-integration-tests-common/src/main/scala/org/apache/james/jmap/rfc8621/contract/ThreadChangesContract.scala
@@ -25,6 +25,8 @@ import io.restassured.http.ContentType.JSON
 import net.javacrumbs.jsonunit.assertj.JsonAssertions.assertThatJson
 import org.apache.http.HttpStatus.SC_OK
 import org.apache.james.GuiceJamesServer
+import org.apache.james.jmap.core.ResponseObject.SESSION_STATE
+import org.apache.james.jmap.core.State.INSTANCE
 import org.apache.james.jmap.http.UserCredential
 import org.apache.james.jmap.rfc8621.contract.Fixture.{ACCEPT_RFC8621_VERSION_HEADER, BOB, BOB_PASSWORD, DOMAIN, authScheme, baseRequestSpecBuilder}
 import org.apache.james.utils.DataProbeImpl
@@ -53,7 +55,7 @@ trait ThreadChangesContract {
          |    "Thread/changes",
          |    {
          |      "accountId": "29883977c13473ae7cb7678ef767cbfbaffc8a44a6e463d971d23a65c1dc4af6",
-         |      "sinceState": "any-state"
+         |      "sinceState": "2c9f1b12-b35a-43e6-9af2-0106fb53a941"
          |    },
          |    "c1"]]
          |}""".stripMargin
@@ -72,8 +74,8 @@ trait ThreadChangesContract {
 
     assertThatJson(response)
       .isEqualTo(
-        """{
-          |    "sessionState": "75128aab4b1b",
+        s"""{
+          |    "sessionState": "${SESSION_STATE.value}",
           |    "methodResponses": [
           |        [
           |            "error",
@@ -96,7 +98,7 @@ trait ThreadChangesContract {
          |    "Thread/changes",
          |    {
          |      "accountId": "29883977c13473ae7cb7678ef767cbfbaffc8a44a6e463d971d23a65c1dc4af6",
-         |      "sinceState": "000001"
+         |      "sinceState": "${INSTANCE.value}"
          |    },
          |    "c1"]]
          |}""".stripMargin
@@ -116,10 +118,10 @@ trait ThreadChangesContract {
     assertThatJson(response)
       .inPath("methodResponses[0][1]")
       .isEqualTo(
-        """{
+        s"""{
           |  "accountId": "29883977c13473ae7cb7678ef767cbfbaffc8a44a6e463d971d23a65c1dc4af6",
-          |  "oldState": "000001",
-          |  "newState": "000001",
+          |  "oldState": "${INSTANCE.value}",
+          |  "newState": "${INSTANCE.value}",
           |  "hasMoreChanges": false,
           |  "created": [],
           |  "updated": [],
@@ -136,7 +138,7 @@ trait ThreadChangesContract {
          |    "Thread/changes",
          |    {
          |      "accountId": "bad",
-         |      "sinceState": "any-state"
+         |      "sinceState": "${INSTANCE.value}"
          |    },
          |    "c1"]]
          |}""".stripMargin
@@ -155,8 +157,8 @@ trait ThreadChangesContract {
 
     assertThatJson(response)
       .isEqualTo(
-        """{
-          |    "sessionState": "75128aab4b1b",
+        s"""{
+          |    "sessionState": "${SESSION_STATE.value}",
           |    "methodResponses": [
           |        [
           |            "error",
diff --git a/server/protocols/jmap-rfc-8621-integration-tests/jmap-rfc-8621-integration-tests-common/src/main/scala/org/apache/james/jmap/rfc8621/contract/ThreadGetContract.scala b/server/protocols/jmap-rfc-8621-integration-tests/jmap-rfc-8621-integration-tests-common/src/main/scala/org/apache/james/jmap/rfc8621/contract/ThreadGetContract.scala
index 29cf5ed..04cfdd8 100644
--- a/server/protocols/jmap-rfc-8621-integration-tests/jmap-rfc-8621-integration-tests-common/src/main/scala/org/apache/james/jmap/rfc8621/contract/ThreadGetContract.scala
+++ b/server/protocols/jmap-rfc-8621-integration-tests/jmap-rfc-8621-integration-tests-common/src/main/scala/org/apache/james/jmap/rfc8621/contract/ThreadGetContract.scala
@@ -25,6 +25,7 @@ import io.restassured.http.ContentType.JSON
 import net.javacrumbs.jsonunit.assertj.JsonAssertions.assertThatJson
 import org.apache.http.HttpStatus.SC_OK
 import org.apache.james.GuiceJamesServer
+import org.apache.james.jmap.core.ResponseObject.SESSION_STATE
 import org.apache.james.jmap.http.UserCredential
 import org.apache.james.jmap.rfc8621.contract.Fixture.{ACCEPT_RFC8621_VERSION_HEADER, BOB, BOB_PASSWORD, DOMAIN, authScheme, baseRequestSpecBuilder}
 import org.apache.james.utils.DataProbeImpl
@@ -73,9 +74,9 @@ trait ThreadGetContract {
     assertThatJson(response)
       .inPath("methodResponses[0][1]")
       .isEqualTo(
-        """{
+        s"""{
           |  "accountId": "29883977c13473ae7cb7678ef767cbfbaffc8a44a6e463d971d23a65c1dc4af6",
-          |  "state": "000001",
+          |  "state": "${SESSION_STATE.value}",
           |  "list": [
           |      {
           |          "id": "123456",
@@ -114,9 +115,9 @@ trait ThreadGetContract {
     assertThatJson(response)
       .inPath("methodResponses[0][1]")
       .isEqualTo(
-        """{
+        s"""{
           |  "accountId": "29883977c13473ae7cb7678ef767cbfbaffc8a44a6e463d971d23a65c1dc4af6",
-          |  "state": "000001",
+          |  "state": "${SESSION_STATE.value}",
           |  "list": [
           |      {
           |          "id": "123456",
@@ -158,8 +159,8 @@ trait ThreadGetContract {
 
     assertThatJson(response)
       .isEqualTo(
-        """{
-          |    "sessionState": "75128aab4b1b",
+        s"""{
+          |    "sessionState": "${SESSION_STATE.value}",
           |    "methodResponses": [
           |        [
           |            "error",
diff --git a/server/protocols/jmap-rfc-8621-integration-tests/jmap-rfc-8621-integration-tests-common/src/main/scala/org/apache/james/jmap/rfc8621/contract/VacationResponseGetMethodContract.scala b/server/protocols/jmap-rfc-8621-integration-tests/jmap-rfc-8621-integration-tests-common/src/main/scala/org/apache/james/jmap/rfc8621/contract/VacationResponseGetMethodContract.scala
index cf547d1..38a2def 100644
--- a/server/protocols/jmap-rfc-8621-integration-tests/jmap-rfc-8621-integration-tests-common/src/main/scala/org/apache/james/jmap/rfc8621/contract/VacationResponseGetMethodContract.scala
+++ b/server/protocols/jmap-rfc-8621-integration-tests/jmap-rfc-8621-integration-tests-common/src/main/scala/org/apache/james/jmap/rfc8621/contract/VacationResponseGetMethodContract.scala
@@ -29,6 +29,8 @@ import org.apache.http.HttpStatus.SC_OK
 import org.apache.james.GuiceJamesServer
 import org.apache.james.jmap.api.model.AccountId
 import org.apache.james.jmap.api.vacation.VacationPatch
+import org.apache.james.jmap.core.ResponseObject.SESSION_STATE
+import org.apache.james.jmap.core.State.INSTANCE
 import org.apache.james.jmap.draft.JmapGuiceProbe
 import org.apache.james.jmap.http.UserCredential
 import org.apache.james.jmap.rfc8621.contract.Fixture.{ACCEPT_RFC8621_VERSION_HEADER, BOB, BOB_PASSWORD, DOMAIN, authScheme, baseRequestSpecBuilder}
@@ -93,8 +95,8 @@ trait VacationResponseGetMethodContract {
       .asString
 
     assertThatJson(response).isEqualTo(
-      """{
-        |  "sessionState": "75128aab4b1b",
+      s"""{
+        |  "sessionState": "${SESSION_STATE.value}",
         |  "methodResponses": [
         |    ["error", {
         |      "type": "accountNotFound"
@@ -132,12 +134,12 @@ trait VacationResponseGetMethodContract {
 
     assertThatJson(response).isEqualTo(
       s"""{
-         |  "sessionState": "75128aab4b1b",
+         |  "sessionState": "${SESSION_STATE.value}",
          |  "methodResponses": [[
          |    "VacationResponse/get",
          |    {
          |      "accountId": "29883977c13473ae7cb7678ef767cbfbaffc8a44a6e463d971d23a65c1dc4af6",
-         |      "state": "000001",
+         |      "state": "${INSTANCE.value}",
          |      "list": [
          |        {
          |          "id":"singleton",
@@ -182,12 +184,12 @@ trait VacationResponseGetMethodContract {
 
     assertThatJson(response).isEqualTo(
       s"""{
-         |  "sessionState": "75128aab4b1b",
+         |  "sessionState": "${SESSION_STATE.value}",
          |  "methodResponses": [[
          |    "VacationResponse/get",
          |    {
          |      "accountId": "29883977c13473ae7cb7678ef767cbfbaffc8a44a6e463d971d23a65c1dc4af6",
-         |      "state": "000001",
+         |      "state": "${INSTANCE.value}",
          |      "list": [
          |        {
          |          "id":"singleton",
@@ -232,7 +234,7 @@ trait VacationResponseGetMethodContract {
 
     assertThatJson(response).isEqualTo(
       s"""{
-         |  "sessionState": "75128aab4b1b",
+         |  "sessionState": "${SESSION_STATE.value}",
          |  "methodResponses": [[
          |    "error",
          |    {
@@ -268,7 +270,7 @@ trait VacationResponseGetMethodContract {
 
     assertThatJson(response).isEqualTo(
       s"""{
-         |  "sessionState": "75128aab4b1b",
+         |  "sessionState": "${SESSION_STATE.value}",
          |  "methodResponses": [[
          |    "error",
          |    {
@@ -307,12 +309,12 @@ trait VacationResponseGetMethodContract {
 
     assertThatJson(response).isEqualTo(
       s"""{
-         |  "sessionState": "75128aab4b1b",
+         |  "sessionState": "${SESSION_STATE.value}",
          |  "methodResponses": [[
          |    "VacationResponse/get",
          |    {
          |      "accountId": "29883977c13473ae7cb7678ef767cbfbaffc8a44a6e463d971d23a65c1dc4af6",
-         |      "state": "000001",
+         |      "state": "${INSTANCE.value}",
          |      "list": [
          |        {
          |          "id":"singleton",
@@ -353,12 +355,12 @@ trait VacationResponseGetMethodContract {
 
     assertThatJson(response).isEqualTo(
       s"""{
-         |  "sessionState": "75128aab4b1b",
+         |  "sessionState": "${SESSION_STATE.value}",
          |  "methodResponses": [[
          |    "VacationResponse/get",
          |    {
          |      "accountId": "29883977c13473ae7cb7678ef767cbfbaffc8a44a6e463d971d23a65c1dc4af6",
-         |      "state": "000001",
+         |      "state": "${INSTANCE.value}",
          |      "list": [],
          |      "notFound": ["random"]
          |    },
@@ -394,12 +396,12 @@ trait VacationResponseGetMethodContract {
 
     assertThatJson(response).isEqualTo(
       s"""{
-         |  "sessionState": "75128aab4b1b",
+         |  "sessionState": "${SESSION_STATE.value}",
          |  "methodResponses": [[
          |    "VacationResponse/get",
          |    {
          |      "accountId": "29883977c13473ae7cb7678ef767cbfbaffc8a44a6e463d971d23a65c1dc4af6",
-         |      "state": "000001",
+         |      "state": "${INSTANCE.value}",
          |      "list": [
          |        {
          |          "id":"singleton",
@@ -440,12 +442,12 @@ trait VacationResponseGetMethodContract {
 
     assertThatJson(response).isEqualTo(
       s"""{
-         |  "sessionState": "75128aab4b1b",
+         |  "sessionState": "${SESSION_STATE.value}",
          |  "methodResponses": [[
          |    "VacationResponse/get",
          |    {
          |      "accountId": "29883977c13473ae7cb7678ef767cbfbaffc8a44a6e463d971d23a65c1dc4af6",
-         |      "state": "000001",
+         |      "state": "${INSTANCE.value}",
          |      "list": [],
          |      "notFound": []
          |    },
@@ -481,13 +483,13 @@ trait VacationResponseGetMethodContract {
       .stripMargin
 
     assertThatJson(response).isEqualTo(
-      """{
-         |  "sessionState": "75128aab4b1b",
+      s"""{
+         |  "sessionState": "${SESSION_STATE.value}",
          |  "methodResponses": [[
          |    "error",
          |      {
          |        "type": "invalidArguments",
-         |        "description": "{\"errors\":[{\"path\":\"obj.ids[0]\",\"messages\":[\"Predicate isEmpty() did not fail.\"]}]}"
+         |        "description": "{\\"errors\\":[{\\"path\\":\\"obj.ids[0]\\",\\"messages\\":[\\"Predicate isEmpty() did not fail.\\"]}]}"
          |      },
          |    "c1"]]
          |}""".stripMargin)
@@ -525,12 +527,12 @@ trait VacationResponseGetMethodContract {
 
     assertThatJson(response).isEqualTo(
       s"""{
-         |  "sessionState": "75128aab4b1b",
+         |  "sessionState": "${SESSION_STATE.value}",
          |  "methodResponses": [[
          |    "VacationResponse/get",
          |    {
          |      "accountId": "29883977c13473ae7cb7678ef767cbfbaffc8a44a6e463d971d23a65c1dc4af6",
-         |      "state": "000001",
+         |      "state": "${INSTANCE.value}",
          |      "list": [
          |        {
          |          "id":"singleton",
@@ -580,12 +582,12 @@ trait VacationResponseGetMethodContract {
 
     assertThatJson(response).isEqualTo(
       s"""{
-         |  "sessionState": "75128aab4b1b",
+         |  "sessionState": "${SESSION_STATE.value}",
          |  "methodResponses": [[
          |    "VacationResponse/get",
          |    {
          |      "accountId": "29883977c13473ae7cb7678ef767cbfbaffc8a44a6e463d971d23a65c1dc4af6",
-         |      "state": "000001",
+         |      "state": "${INSTANCE.value}",
          |      "list": [
          |        {
          |          "id":"singleton"
@@ -629,12 +631,12 @@ trait VacationResponseGetMethodContract {
 
     assertThatJson(response).isEqualTo(
       s"""{
-         |  "sessionState": "75128aab4b1b",
+         |  "sessionState": "${SESSION_STATE.value}",
          |  "methodResponses": [[
          |    "VacationResponse/get",
          |    {
          |      "accountId": "29883977c13473ae7cb7678ef767cbfbaffc8a44a6e463d971d23a65c1dc4af6",
-         |      "state": "000001",
+         |      "state": "${INSTANCE.value}",
          |      "list": [
          |        {
          |          "id":"singleton",
@@ -679,12 +681,12 @@ trait VacationResponseGetMethodContract {
 
     assertThatJson(response).isEqualTo(
       s"""{
-         |  "sessionState": "75128aab4b1b",
+         |  "sessionState": "${SESSION_STATE.value}",
          |  "methodResponses": [[
          |    "VacationResponse/get",
          |    {
          |      "accountId": "29883977c13473ae7cb7678ef767cbfbaffc8a44a6e463d971d23a65c1dc4af6",
-         |      "state": "000001",
+         |      "state": "${INSTANCE.value}",
          |      "list": [
          |        {
          |          "id":"singleton",
@@ -726,8 +728,8 @@ trait VacationResponseGetMethodContract {
       .stripMargin
 
     assertThatJson(response).isEqualTo(
-      """{
-        |  "sessionState": "75128aab4b1b",
+      s"""{
+        |  "sessionState": "${SESSION_STATE.value}",
         |  "methodResponses": [[
         |    "error",
         |    {
diff --git a/server/protocols/jmap-rfc-8621-integration-tests/jmap-rfc-8621-integration-tests-common/src/main/scala/org/apache/james/jmap/rfc8621/contract/VacationResponseSetMethodContract.scala b/server/protocols/jmap-rfc-8621-integration-tests/jmap-rfc-8621-integration-tests-common/src/main/scala/org/apache/james/jmap/rfc8621/contract/VacationResponseSetMethodContract.scala
index 0b96bf6..a111fee 100644
--- a/server/protocols/jmap-rfc-8621-integration-tests/jmap-rfc-8621-integration-tests-common/src/main/scala/org/apache/james/jmap/rfc8621/contract/VacationResponseSetMethodContract.scala
+++ b/server/protocols/jmap-rfc-8621-integration-tests/jmap-rfc-8621-integration-tests-common/src/main/scala/org/apache/james/jmap/rfc8621/contract/VacationResponseSetMethodContract.scala
@@ -25,6 +25,8 @@ import io.restassured.http.ContentType.JSON
 import net.javacrumbs.jsonunit.assertj.JsonAssertions.assertThatJson
 import org.apache.http.HttpStatus.SC_OK
 import org.apache.james.GuiceJamesServer
+import org.apache.james.jmap.core.ResponseObject.SESSION_STATE
+import org.apache.james.jmap.core.State.INSTANCE
 import org.apache.james.jmap.http.UserCredential
 import org.apache.james.jmap.rfc8621.contract.Fixture._
 import org.apache.james.jmap.rfc8621.contract.tags.CategoryTags
@@ -84,8 +86,8 @@ trait VacationResponseSetMethodContract {
       .asString
 
     assertThatJson(response).isEqualTo(
-      """{
-        |  "sessionState": "75128aab4b1b",
+      s"""{
+        |  "sessionState": "${SESSION_STATE.value}",
         |  "methodResponses": [
         |    ["error", {
         |      "type": "accountNotFound"
@@ -140,18 +142,18 @@ trait VacationResponseSetMethodContract {
 
     assertThatJson(response).isEqualTo(
       s"""{
-         |"sessionState": "75128aab4b1b",
+         |"sessionState": "${SESSION_STATE.value}",
          |  "methodResponses": [
          |    ["VacationResponse/set", {
          |      "accountId": "29883977c13473ae7cb7678ef767cbfbaffc8a44a6e463d971d23a65c1dc4af6",
-         |      "newState": "000001",
+         |      "newState": "${INSTANCE.value}",
          |      "updated": {
          |        "singleton": {}
          |      }
          |    }, "c1"],
          |    ["VacationResponse/get", {
          |      "accountId": "29883977c13473ae7cb7678ef767cbfbaffc8a44a6e463d971d23a65c1dc4af6",
-         |      "state": "000001",
+         |      "state": "${INSTANCE.value}",
          |      "list": [
          |        {
          |          "id": "singleton",
@@ -240,18 +242,18 @@ trait VacationResponseSetMethodContract {
 
     assertThatJson(response).isEqualTo(
       s"""{
-         |"sessionState": "75128aab4b1b",
+         |"sessionState": "${SESSION_STATE.value}",
          |  "methodResponses": [
          |    ["VacationResponse/set", {
          |      "accountId": "29883977c13473ae7cb7678ef767cbfbaffc8a44a6e463d971d23a65c1dc4af6",
-         |      "newState": "000001",
+         |      "newState": "${INSTANCE.value}",
          |      "updated": {
          |        "singleton": {}
          |      }
          |    }, "c1"],
          |    ["VacationResponse/get", {
          |      "accountId": "29883977c13473ae7cb7678ef767cbfbaffc8a44a6e463d971d23a65c1dc4af6",
-         |      "state": "000001",
+         |      "state": "${INSTANCE.value}",
          |      "list": [
          |        {
          |          "id": "singleton",
@@ -305,11 +307,11 @@ trait VacationResponseSetMethodContract {
 
     assertThatJson(response).isEqualTo(
       s"""{
-         |"sessionState": "75128aab4b1b",
+         |"sessionState": "${SESSION_STATE.value}",
          |  "methodResponses": [
          |    ["VacationResponse/set", {
          |      "accountId": "29883977c13473ae7cb7678ef767cbfbaffc8a44a6e463d971d23a65c1dc4af6",
-         |      "newState": "000001",
+         |      "newState": "${INSTANCE.value}",
          |      "updated": {
          |        "singleton": {}
          |      }
@@ -392,18 +394,18 @@ trait VacationResponseSetMethodContract {
 
     assertThatJson(response).isEqualTo(
       s"""{
-         |"sessionState": "75128aab4b1b",
+         |"sessionState": "${SESSION_STATE.value}",
          |  "methodResponses": [
          |    ["VacationResponse/set", {
          |      "accountId": "29883977c13473ae7cb7678ef767cbfbaffc8a44a6e463d971d23a65c1dc4af6",
-         |      "newState": "000001",
+         |      "newState": "${INSTANCE.value}",
          |      "updated": {
          |        "singleton": {}
          |      }
          |    }, "c1"],
          |    ["VacationResponse/get", {
          |      "accountId": "29883977c13473ae7cb7678ef767cbfbaffc8a44a6e463d971d23a65c1dc4af6",
-         |      "state": "000001",
+         |      "state": "${INSTANCE.value}",
          |      "list": [
          |        {
          |          "id": "singleton",
@@ -457,11 +459,11 @@ trait VacationResponseSetMethodContract {
 
     assertThatJson(response).isEqualTo(
       s"""{
-         |  "sessionState": "75128aab4b1b",
+         |  "sessionState": "${SESSION_STATE.value}",
          |  "methodResponses": [
          |    ["VacationResponse/set", {
          |      "accountId": "29883977c13473ae7cb7678ef767cbfbaffc8a44a6e463d971d23a65c1dc4af6",
-         |      "newState": "000001",
+         |      "newState": "${INSTANCE.value}",
          |      "notUpdated": {
          |        "invalid": {
          |          "type": "invalidArguments",
@@ -510,11 +512,11 @@ trait VacationResponseSetMethodContract {
 
     assertThatJson(response).isEqualTo(
       s"""{
-         |  "sessionState": "75128aab4b1b",
+         |  "sessionState": "${SESSION_STATE.value}",
          |  "methodResponses": [
          |    ["VacationResponse/set", {
          |      "accountId": "29883977c13473ae7cb7678ef767cbfbaffc8a44a6e463d971d23a65c1dc4af6",
-         |      "newState": "000001",
+         |      "newState": "${INSTANCE.value}",
          |      "notUpdated": {
          |        "singleton": {
          |          "type": "invalidArguments",
@@ -562,11 +564,11 @@ trait VacationResponseSetMethodContract {
 
     assertThatJson(response).isEqualTo(
       s"""{
-         |  "sessionState": "75128aab4b1b",
+         |  "sessionState": "${SESSION_STATE.value}",
          |  "methodResponses": [
          |    ["VacationResponse/set", {
          |      "accountId": "29883977c13473ae7cb7678ef767cbfbaffc8a44a6e463d971d23a65c1dc4af6",
-         |      "newState": "000001",
+         |      "newState": "${INSTANCE.value}",
          |      "notUpdated": {
          |        "singleton": {
          |          "type": "invalidArguments",
@@ -615,11 +617,11 @@ trait VacationResponseSetMethodContract {
 
     assertThatJson(response).isEqualTo(
       s"""{
-         |  "sessionState": "75128aab4b1b",
+         |  "sessionState": "${SESSION_STATE.value}",
          |  "methodResponses": [
          |    ["VacationResponse/set", {
          |      "accountId": "29883977c13473ae7cb7678ef767cbfbaffc8a44a6e463d971d23a65c1dc4af6",
-         |      "newState": "000001",
+         |      "newState": "${INSTANCE.value}",
          |      "notUpdated": {
          |        "singleton": {
          |          "type": "invalidArguments",
@@ -664,11 +666,11 @@ trait VacationResponseSetMethodContract {
 
     assertThatJson(response).isEqualTo(
       s"""{
-         |  "sessionState": "75128aab4b1b",
+         |  "sessionState": "${SESSION_STATE.value}",
          |  "methodResponses": [
          |    ["VacationResponse/set", {
          |      "accountId": "29883977c13473ae7cb7678ef767cbfbaffc8a44a6e463d971d23a65c1dc4af6",
-         |      "newState": "000001"
+         |      "newState": "${INSTANCE.value}"
          |    }, "c1"]
          |  ]
          |}""".stripMargin)
@@ -713,11 +715,11 @@ trait VacationResponseSetMethodContract {
 
     assertThatJson(response).isEqualTo(
       s"""{
-         |  "sessionState": "75128aab4b1b",
+         |  "sessionState": "${SESSION_STATE.value}",
          |  "methodResponses": [
          |    ["VacationResponse/set", {
          |      "accountId": "29883977c13473ae7cb7678ef767cbfbaffc8a44a6e463d971d23a65c1dc4af6",
-         |      "newState": "000001",
+         |      "newState": "${INSTANCE.value}",
          |      "updated": {
          |        "singleton": {}
          |      },
@@ -768,11 +770,11 @@ trait VacationResponseSetMethodContract {
 
     assertThatJson(response).isEqualTo(
       s"""{
-         |  "sessionState": "75128aab4b1b",
+         |  "sessionState": "${SESSION_STATE.value}",
          |  "methodResponses": [
          |    ["VacationResponse/set", {
          |      "accountId": "29883977c13473ae7cb7678ef767cbfbaffc8a44a6e463d971d23a65c1dc4af6",
-         |      "newState": "000001",
+         |      "newState": "${INSTANCE.value}",
          |      "notCreated": {
          |        "singleton": {
          |          "type": "invalidArguments",
@@ -816,11 +818,11 @@ trait VacationResponseSetMethodContract {
 
     assertThatJson(response).isEqualTo(
       s"""{
-         |  "sessionState": "75128aab4b1b",
+         |  "sessionState": "${SESSION_STATE.value}",
          |  "methodResponses": [
          |    ["VacationResponse/set", {
          |      "accountId": "29883977c13473ae7cb7678ef767cbfbaffc8a44a6e463d971d23a65c1dc4af6",
-         |      "newState": "000001",
+         |      "newState": "${INSTANCE.value}",
          |      "notDestroyed": {
          |        "singleton": {
          |          "type": "invalidArguments",
@@ -860,7 +862,7 @@ trait VacationResponseSetMethodContract {
 
     assertThatJson(response).isEqualTo(
       s"""{
-         |  "sessionState": "75128aab4b1b",
+         |  "sessionState": "${SESSION_STATE.value}",
          |  "methodResponses": [[
          |    "error",
          |    {
@@ -898,7 +900,7 @@ trait VacationResponseSetMethodContract {
 
     assertThatJson(response).isEqualTo(
       s"""{
-         |  "sessionState": "75128aab4b1b",
+         |  "sessionState": "${SESSION_STATE.value}",
          |  "methodResponses": [[
          |    "error",
          |    {
diff --git a/server/protocols/jmap-rfc-8621/doc/specs/spec/jmap/api.mdown b/server/protocols/jmap-rfc-8621/doc/specs/spec/jmap/api.mdown
index 209c4ab..34648e0 100644
--- a/server/protocols/jmap-rfc-8621/doc/specs/spec/jmap/api.mdown
+++ b/server/protocols/jmap-rfc-8621/doc/specs/spec/jmap/api.mdown
@@ -104,7 +104,7 @@ Unless otherwise specified, if the method call completed successfully, its respo
           "type":"unknownMethod"
         }, "c3" ]
       ],
-      "sessionState": "75128aab4b1b"
+      "sessionState": "2c9f1b12-b35a-43e6-9af2-0106fb53a943"
     }
 
 ## Omitting Arguments
diff --git a/server/protocols/jmap-rfc-8621/doc/specs/spec/jmap/session.mdown b/server/protocols/jmap-rfc-8621/doc/specs/spec/jmap/session.mdown
index 22cf51f..2216ed9 100644
--- a/server/protocols/jmap-rfc-8621/doc/specs/spec/jmap/session.mdown
+++ b/server/protocols/jmap-rfc-8621/doc/specs/spec/jmap/session.mdown
@@ -188,7 +188,7 @@ In the following example Session object, the user has access to their own mail a
       "uploadUrl": "https://jmap.example.com/upload/{accountId}/",
       "eventSourceUrl": "https://jmap.example.com
         /eventsource/?types={types}&closeafter={closeafter}&ping={ping}",
-      "state": "75128aab4b1b"
+      "state": "2c9f1b12-b35a-43e6-9af2-0106fb53a943"
     }
 
 ## Service Autodiscovery
diff --git a/server/protocols/jmap-rfc-8621/src/main/scala/org/apache/james/jmap/core/ResponseObject.scala b/server/protocols/jmap-rfc-8621/src/main/scala/org/apache/james/jmap/core/ResponseObject.scala
index 349e692..ec05f82 100644
--- a/server/protocols/jmap-rfc-8621/src/main/scala/org/apache/james/jmap/core/ResponseObject.scala
+++ b/server/protocols/jmap-rfc-8621/src/main/scala/org/apache/james/jmap/core/ResponseObject.scala
@@ -19,11 +19,8 @@
 
 package org.apache.james.jmap.core
 
-import eu.timepit.refined.auto._
-import org.apache.james.jmap.core.State.State
-
 case class ResponseObject(sessionState: State, methodResponses: Seq[Invocation])
 
 object ResponseObject {
-  val SESSION_STATE: State = "75128aab4b1b"
+  val SESSION_STATE: State = State.fromString("2c9f1b12-b35a-43e6-9af2-0106fb53a943")
 }
diff --git a/server/protocols/jmap-rfc-8621/src/main/scala/org/apache/james/jmap/core/Session.scala b/server/protocols/jmap-rfc-8621/src/main/scala/org/apache/james/jmap/core/Session.scala
index 1e86baf..2189de3 100644
--- a/server/protocols/jmap-rfc-8621/src/main/scala/org/apache/james/jmap/core/Session.scala
+++ b/server/protocols/jmap-rfc-8621/src/main/scala/org/apache/james/jmap/core/Session.scala
@@ -21,16 +21,14 @@ package org.apache.james.jmap.core
 
 import java.net.URL
 import java.nio.charset.StandardCharsets
+import java.util.UUID
 
 import com.google.common.hash.Hashing
-import eu.timepit.refined.api.Refined
-import eu.timepit.refined.auto._
-import eu.timepit.refined.collection.NonEmpty
 import eu.timepit.refined.refineV
 import org.apache.james.core.Username
 import org.apache.james.jmap.core.CapabilityIdentifier.CapabilityIdentifier
 import org.apache.james.jmap.core.Id.Id
-import org.apache.james.jmap.core.State.{INSTANCE, State}
+import org.apache.james.jmap.core.State.INSTANCE
 
 case class IsPersonal(value: Boolean) extends AnyVal
 case class IsReadOnly(value: Boolean) extends AnyVal
@@ -75,11 +73,13 @@ final case class Account private(accountId: AccountId,
                                  accountCapabilities: Set[_ <: Capability])
 
 object State {
-  val INSTANCE: State = "000001"
+  val INSTANCE: State = fromString("2c9f1b12-b35a-43e6-9af2-0106fb53a943")
 
-  type State = String Refined NonEmpty
+  def fromString(value: String): State = State(UUID.fromString(value))
 }
 
+case class State(value: UUID)
+
 final case class Session(capabilities: Capabilities,
                          accounts: List[Account],
                          primaryAccounts: Map[CapabilityIdentifier, AccountId],
diff --git a/server/protocols/jmap-rfc-8621/src/main/scala/org/apache/james/jmap/json/EmailGetSerializer.scala b/server/protocols/jmap-rfc-8621/src/main/scala/org/apache/james/jmap/json/EmailGetSerializer.scala
index dba6258..a0062a1 100644
--- a/server/protocols/jmap-rfc-8621/src/main/scala/org/apache/james/jmap/json/EmailGetSerializer.scala
+++ b/server/protocols/jmap-rfc-8621/src/main/scala/org/apache/james/jmap/json/EmailGetSerializer.scala
@@ -20,7 +20,7 @@
 package org.apache.james.jmap.json
 
 import org.apache.james.jmap.api.model.Preview
-import org.apache.james.jmap.core.Properties
+import org.apache.james.jmap.core.{Properties, State}
 import org.apache.james.jmap.mail.Email.Size
 import org.apache.james.jmap.mail.{AddressesHeaderValue, BlobId, Charset, DateHeaderValue, Disposition, EmailAddress, EmailAddressGroup, EmailBody, EmailBodyMetadata, EmailBodyPart, EmailBodyValue, EmailChangesRequest, EmailChangesResponse, EmailFastView, EmailFullView, EmailGetRequest, EmailGetResponse, EmailHeader, EmailHeaderName, EmailHeaderValue, EmailHeaderView, EmailHeaders, EmailIds, EmailMetadata, EmailMetadataView, EmailNotFound, EmailView, EmailerName, FetchAllBodyValues, Fetc [...]
 import org.apache.james.mailbox.model.{Cid, MailboxId, MessageId}
@@ -163,6 +163,8 @@ object EmailGetSerializer {
     case view: EmailFastView => emailFastViewWrites.writes(view)
     case view: EmailFullView => emailFullViewWrites.writes(view)
   }
+
+  private implicit val stateWrites: Writes[State] = Json.valueWrites[State]
   private implicit val emailGetResponseWrites: Writes[EmailGetResponse] = Json.writes[EmailGetResponse]
   private implicit val changesResponseWrites: OWrites[EmailChangesResponse] = Json.writes[EmailChangesResponse]
 
diff --git a/server/protocols/jmap-rfc-8621/src/main/scala/org/apache/james/jmap/json/EmailSetSerializer.scala b/server/protocols/jmap-rfc-8621/src/main/scala/org/apache/james/jmap/json/EmailSetSerializer.scala
index 12baa8d..0ad72f6 100644
--- a/server/protocols/jmap-rfc-8621/src/main/scala/org/apache/james/jmap/json/EmailSetSerializer.scala
+++ b/server/protocols/jmap-rfc-8621/src/main/scala/org/apache/james/jmap/json/EmailSetSerializer.scala
@@ -25,7 +25,7 @@ import eu.timepit.refined.refineV
 import eu.timepit.refined.types.string.NonEmptyString
 import javax.inject.Inject
 import org.apache.james.jmap.core.Id.IdConstraint
-import org.apache.james.jmap.core.{Id, SetError, UTCDate}
+import org.apache.james.jmap.core.{Id, SetError, State, UTCDate}
 import org.apache.james.jmap.mail.EmailSet.{EmailCreationId, UnparsedMessageId, UnparsedMessageIdConstraint}
 import org.apache.james.jmap.mail.KeywordsFactory.STRICT_KEYWORDS_FACTORY
 import org.apache.james.jmap.mail.{AddressesHeaderValue, AsAddresses, AsDate, AsGroupedAddresses, AsMessageIds, AsRaw, AsText, AsURLs, Attachment, BlobId, Charset, ClientBody, ClientCid, ClientEmailBodyValue, ClientPartId, DateHeaderValue, DestroyIds, Disposition, EmailAddress, EmailAddressGroup, EmailCreationRequest, EmailCreationResponse, EmailHeader, EmailHeaderName, EmailHeaderValue, EmailSetRequest, EmailSetResponse, EmailSetUpdate, EmailerName, GroupName, GroupedAddressesHeaderValu [...]
@@ -214,6 +214,8 @@ class EmailSetSerializer @Inject()(messageIdFactory: MessageId.Factory, mailboxI
     mapWrites[EmailCreationId, EmailCreationResponse](_.value, emailCreationResponseWrites)
   private implicit val notCreatedMapWrites: Writes[Map[EmailCreationId, SetError]] =
     mapWrites[EmailCreationId, SetError](_.value, setErrorWrites)
+
+  private implicit val stateWrites: Writes[State] = Json.valueWrites[State]
   private implicit val emailResponseSetWrites: OWrites[EmailSetResponse] = Json.writes[EmailSetResponse]
 
   private implicit val subjectReads: Reads[Subject] = Json.valueReads[Subject]
diff --git a/server/protocols/jmap-rfc-8621/src/main/scala/org/apache/james/jmap/json/EmailSubmissionSetSerializer.scala b/server/protocols/jmap-rfc-8621/src/main/scala/org/apache/james/jmap/json/EmailSubmissionSetSerializer.scala
index 2d5460a..3f3c911 100644
--- a/server/protocols/jmap-rfc-8621/src/main/scala/org/apache/james/jmap/json/EmailSubmissionSetSerializer.scala
+++ b/server/protocols/jmap-rfc-8621/src/main/scala/org/apache/james/jmap/json/EmailSubmissionSetSerializer.scala
@@ -23,7 +23,7 @@ import eu.timepit.refined.refineV
 import javax.inject.Inject
 import org.apache.james.core.MailAddress
 import org.apache.james.jmap.core.Id.IdConstraint
-import org.apache.james.jmap.core.SetError
+import org.apache.james.jmap.core.{SetError, State}
 import org.apache.james.jmap.mail.EmailSet.{UnparsedMessageId, UnparsedMessageIdConstraint}
 import org.apache.james.jmap.mail.EmailSubmissionSet.EmailSubmissionCreationId
 import org.apache.james.jmap.mail.{DestroyIds, EmailSubmissionAddress, EmailSubmissionCreationRequest, EmailSubmissionCreationResponse, EmailSubmissionId, EmailSubmissionSetRequest, EmailSubmissionSetResponse, Envelope}
@@ -64,6 +64,7 @@ class EmailSubmissionSetSerializer @Inject()(messageIdFactory: MessageId.Factory
 
   private implicit val emailSubmissionCreationResponseWrites: Writes[EmailSubmissionCreationResponse] = Json.valueWrites[EmailSubmissionCreationResponse]
 
+  private implicit val stateWrites: Writes[State] = Json.valueWrites[State]
   private implicit def emailSubmissionSetResponseWrites(implicit emailSubmissionCreationResponseWrites: Writes[EmailSubmissionCreationResponse]): Writes[EmailSubmissionSetResponse] = Json.writes[EmailSubmissionSetResponse]
 
   private implicit def emailSubmissionMapCreationResponseWrites(implicit emailSubmissionSetCreationResponseWrites: Writes[EmailSubmissionCreationResponse]): Writes[Map[EmailSubmissionCreationId, EmailSubmissionCreationResponse]] =
diff --git a/server/protocols/jmap-rfc-8621/src/main/scala/org/apache/james/jmap/json/IdentitySerializer.scala b/server/protocols/jmap-rfc-8621/src/main/scala/org/apache/james/jmap/json/IdentitySerializer.scala
index bca92b2..cb8fc0a 100644
--- a/server/protocols/jmap-rfc-8621/src/main/scala/org/apache/james/jmap/json/IdentitySerializer.scala
+++ b/server/protocols/jmap-rfc-8621/src/main/scala/org/apache/james/jmap/json/IdentitySerializer.scala
@@ -19,7 +19,7 @@
 
 package org.apache.james.jmap.json
 
-import org.apache.james.jmap.core.Properties
+import org.apache.james.jmap.core.{Properties, State}
 import org.apache.james.jmap.mail._
 import play.api.libs.json.{JsArray, JsObject, JsResult, JsSuccess, JsValue, Json, OWrites, Reads, Writes, __}
 
@@ -32,6 +32,7 @@ object IdentitySerializer {
   private implicit val mayDeleteWrites: Writes[MayDeleteIdentity] = Json.valueWrites[MayDeleteIdentity]
   private implicit val identityWrites: Writes[Identity] = Json.writes[Identity]
   private implicit val identityGetRequestReads: Reads[IdentityGetRequest] = Json.reads[IdentityGetRequest]
+  private implicit val stateWrites: Writes[State] = Json.valueWrites[State]
   private implicit val identityGetResponseWrites: OWrites[IdentityGetResponse] = Json.writes[IdentityGetResponse]
 
   def serialize(response: IdentityGetResponse, properties: Properties): JsObject = Json.toJsObject(response)
diff --git a/server/protocols/jmap-rfc-8621/src/main/scala/org/apache/james/jmap/json/MailboxSerializer.scala b/server/protocols/jmap-rfc-8621/src/main/scala/org/apache/james/jmap/json/MailboxSerializer.scala
index fdc1ea5..0064179 100644
--- a/server/protocols/jmap-rfc-8621/src/main/scala/org/apache/james/jmap/json/MailboxSerializer.scala
+++ b/server/protocols/jmap-rfc-8621/src/main/scala/org/apache/james/jmap/json/MailboxSerializer.scala
@@ -19,12 +19,14 @@
 
 package org.apache.james.jmap.json
 
+import java.util.UUID
+
 import eu.timepit.refined._
 import eu.timepit.refined.collection.NonEmpty
 import javax.inject.Inject
 import org.apache.james.core.{Domain, Username}
 import org.apache.james.jmap.core.CapabilityIdentifier.CapabilityIdentifier
-import org.apache.james.jmap.core.{ClientId, Properties, SetError}
+import org.apache.james.jmap.core.{ClientId, Properties, SetError, State}
 import org.apache.james.jmap.mail.MailboxGet.{UnparsedMailboxId, UnparsedMailboxIdConstraint}
 import org.apache.james.jmap.mail.MailboxSetRequest.MailboxCreationId
 import org.apache.james.jmap.mail.{DelegatedNamespace, Ids, IsSubscribed, Mailbox, MailboxChangesRequest, MailboxChangesResponse, MailboxCreationRequest, MailboxCreationResponse, MailboxGetRequest, MailboxGetResponse, MailboxNamespace, MailboxPatchObject, MailboxRights, MailboxSetRequest, MailboxSetResponse, MailboxUpdateResponse, MayAddItems, MayCreateChild, MayDelete, MayReadItems, MayRemoveItems, MayRename, MaySetKeywords, MaySetSeen, MaySubmit, NotFound, PersonalNamespace, Quota, Quo [...]
@@ -124,10 +126,15 @@ class MailboxSerializer @Inject()(mailboxIdFactory: MailboxId.Factory) {
   private implicit val mapCreationRequestByMailBoxCreationId: Reads[Map[MailboxCreationId, JsObject]] =
     Reads.mapReads[MailboxCreationId, JsObject] {string => refineV[NonEmpty](string).fold(JsError(_), id => JsSuccess(id)) }
 
+  private implicit val stateReads: Reads[State] = {
+    case JsString(underlying) => Try(UUID.fromString(underlying))
+      .fold(e => JsError(e.getMessage), value => JsSuccess(State(value)))
+  }
   private implicit val mailboxSetRequestReads: Reads[MailboxSetRequest] = Json.reads[MailboxSetRequest]
 
   private implicit val notFoundWrites: Writes[NotFound] = Json.valueWrites[NotFound]
 
+  private implicit val stateWrites: Writes[State] = Json.valueWrites[State]
   private implicit val mailboxGetResponseWrites: Writes[MailboxGetResponse] = Json.writes[MailboxGetResponse]
 
 
diff --git a/server/protocols/jmap-rfc-8621/src/main/scala/org/apache/james/jmap/json/ResponseSerializer.scala b/server/protocols/jmap-rfc-8621/src/main/scala/org/apache/james/jmap/json/ResponseSerializer.scala
index 24eefc8..b75aca5 100644
--- a/server/protocols/jmap-rfc-8621/src/main/scala/org/apache/james/jmap/json/ResponseSerializer.scala
+++ b/server/protocols/jmap-rfc-8621/src/main/scala/org/apache/james/jmap/json/ResponseSerializer.scala
@@ -21,6 +21,7 @@ package org.apache.james.jmap.json
 
 import java.io.InputStream
 import java.net.URL
+import java.util.UUID
 
 import eu.timepit.refined.refineV
 import io.netty.handler.codec.http.HttpResponseStatus
@@ -36,6 +37,7 @@ import play.api.libs.json._
 
 import scala.collection.{Seq => LegacySeq}
 import scala.language.implicitConversions
+import scala.util.Try
 
 object ResponseSerializer {
   // CreateIds
@@ -66,6 +68,11 @@ object ResponseSerializer {
   // RequestObject
   private implicit val requestObjectRead: Format[RequestObject] = Json.format[RequestObject]
 
+  private implicit val stateReads: Reads[State] = {
+    case JsString(underlying) => Try(UUID.fromString(underlying))
+      .fold(e => JsError(e.getMessage), value => JsSuccess(State(value)))
+  }
+  private implicit val stateWrites: Writes[State] = Json.valueWrites[State]
   // ResponseObject
   private implicit val responseObjectFormat: Format[ResponseObject] = Json.format[ResponseObject]
 
diff --git a/server/protocols/jmap-rfc-8621/src/main/scala/org/apache/james/jmap/json/VacationSerializer.scala b/server/protocols/jmap-rfc-8621/src/main/scala/org/apache/james/jmap/json/VacationSerializer.scala
index 102e16a..4219bc2 100644
--- a/server/protocols/jmap-rfc-8621/src/main/scala/org/apache/james/jmap/json/VacationSerializer.scala
+++ b/server/protocols/jmap-rfc-8621/src/main/scala/org/apache/james/jmap/json/VacationSerializer.scala
@@ -19,7 +19,7 @@
 
 package org.apache.james.jmap.json
 
-import org.apache.james.jmap.core.Properties
+import org.apache.james.jmap.core.{Properties, State}
 import org.apache.james.jmap.mail.Subject
 import org.apache.james.jmap.vacation.VacationResponse.VACATION_RESPONSE_ID
 import org.apache.james.jmap.vacation.{FromDate, HtmlBody, IsEnabled, TextBody, ToDate, VacationResponse, VacationResponseGetRequest, VacationResponseGetResponse, VacationResponseId, VacationResponseIds, VacationResponseNotFound, VacationResponsePatchObject, VacationResponseSetError, VacationResponseSetRequest, VacationResponseSetResponse, VacationResponseUpdateResponse}
@@ -39,6 +39,7 @@ object VacationSerializer {
 
   private implicit val vacationResponseSetErrorWrites: Writes[VacationResponseSetError] = Json.writes[VacationResponseSetError]
 
+  private implicit val stateWrites: Writes[State] = Json.valueWrites[State]
   private implicit val vacationResponseSetResponseWrites: Writes[VacationResponseSetResponse] = Json.writes[VacationResponseSetResponse]
 
   private implicit val vacationResponseIdWrites: Writes[VacationResponseId] = _ => JsString(VACATION_RESPONSE_ID.value)
diff --git a/server/protocols/jmap-rfc-8621/src/main/scala/org/apache/james/jmap/mail/EmailGet.scala b/server/protocols/jmap-rfc-8621/src/main/scala/org/apache/james/jmap/mail/EmailGet.scala
index 0582a08..a9ff048 100644
--- a/server/protocols/jmap-rfc-8621/src/main/scala/org/apache/james/jmap/mail/EmailGet.scala
+++ b/server/protocols/jmap-rfc-8621/src/main/scala/org/apache/james/jmap/mail/EmailGet.scala
@@ -26,9 +26,8 @@ import eu.timepit.refined.auto._
 import eu.timepit.refined.numeric.NonNegative
 import eu.timepit.refined.types.string.NonEmptyString
 import org.apache.james.jmap.core.Id.Id
-import org.apache.james.jmap.core.State.State
 import org.apache.james.jmap.core.UnsignedInt.UnsignedInt
-import org.apache.james.jmap.core.{AccountId, Properties}
+import org.apache.james.jmap.core.{AccountId, Properties, State}
 import org.apache.james.jmap.mail.Email.UnparsedEmailId
 import org.apache.james.jmap.mail.EmailGetRequest.MaxBodyValueBytes
 import org.apache.james.jmap.mail.EmailHeaders.SPECIFIC_HEADER_PREFIX
diff --git a/server/protocols/jmap-rfc-8621/src/main/scala/org/apache/james/jmap/mail/EmailSet.scala b/server/protocols/jmap-rfc-8621/src/main/scala/org/apache/james/jmap/mail/EmailSet.scala
index 91a2fda..f56f5ba 100644
--- a/server/protocols/jmap-rfc-8621/src/main/scala/org/apache/james/jmap/mail/EmailSet.scala
+++ b/server/protocols/jmap-rfc-8621/src/main/scala/org/apache/james/jmap/mail/EmailSet.scala
@@ -29,8 +29,7 @@ import eu.timepit.refined
 import eu.timepit.refined.api.Refined
 import eu.timepit.refined.collection.NonEmpty
 import org.apache.james.jmap.core.Id.Id
-import org.apache.james.jmap.core.State.State
-import org.apache.james.jmap.core.{AccountId, SetError, UTCDate}
+import org.apache.james.jmap.core.{AccountId, SetError, State, UTCDate}
 import org.apache.james.jmap.mail.Disposition.INLINE
 import org.apache.james.jmap.mail.Email.Size
 import org.apache.james.jmap.mail.EmailSet.{EmailCreationId, UnparsedMessageId}
diff --git a/server/protocols/jmap-rfc-8621/src/main/scala/org/apache/james/jmap/mail/EmailSubmissionSet.scala b/server/protocols/jmap-rfc-8621/src/main/scala/org/apache/james/jmap/mail/EmailSubmissionSet.scala
index 55fea6b..e0944fc 100644
--- a/server/protocols/jmap-rfc-8621/src/main/scala/org/apache/james/jmap/mail/EmailSubmissionSet.scala
+++ b/server/protocols/jmap-rfc-8621/src/main/scala/org/apache/james/jmap/mail/EmailSubmissionSet.scala
@@ -27,8 +27,7 @@ import eu.timepit.refined.types.string.NonEmptyString
 import org.apache.james.core.MailAddress
 import org.apache.james.jmap.core.Id.Id
 import org.apache.james.jmap.core.SetError.SetErrorDescription
-import org.apache.james.jmap.core.State.State
-import org.apache.james.jmap.core.{AccountId, Id, Properties, SetError}
+import org.apache.james.jmap.core.{AccountId, Id, Properties, SetError, State}
 import org.apache.james.jmap.mail.EmailSet.UnparsedMessageId
 import org.apache.james.jmap.mail.EmailSubmissionSet.EmailSubmissionCreationId
 import org.apache.james.jmap.method.{EmailSubmissionCreationParseException, WithAccountId}
diff --git a/server/protocols/jmap-rfc-8621/src/main/scala/org/apache/james/jmap/mail/Identity.scala b/server/protocols/jmap-rfc-8621/src/main/scala/org/apache/james/jmap/mail/Identity.scala
index 9702f98..a05a7a3 100644
--- a/server/protocols/jmap-rfc-8621/src/main/scala/org/apache/james/jmap/mail/Identity.scala
+++ b/server/protocols/jmap-rfc-8621/src/main/scala/org/apache/james/jmap/mail/Identity.scala
@@ -28,8 +28,7 @@ import eu.timepit.refined.refineV
 import javax.inject.Inject
 import org.apache.james.core.MailAddress
 import org.apache.james.jmap.core.Id.Id
-import org.apache.james.jmap.core.State.State
-import org.apache.james.jmap.core.{AccountId, Properties}
+import org.apache.james.jmap.core.{AccountId, Properties, State}
 import org.apache.james.jmap.method.WithAccountId
 import org.apache.james.mailbox.MailboxSession
 import org.apache.james.rrt.api.CanSendFrom
diff --git a/server/protocols/jmap-rfc-8621/src/main/scala/org/apache/james/jmap/mail/MailboxGet.scala b/server/protocols/jmap-rfc-8621/src/main/scala/org/apache/james/jmap/mail/MailboxGet.scala
index 509b2c4..3e10abe 100644
--- a/server/protocols/jmap-rfc-8621/src/main/scala/org/apache/james/jmap/mail/MailboxGet.scala
+++ b/server/protocols/jmap-rfc-8621/src/main/scala/org/apache/james/jmap/mail/MailboxGet.scala
@@ -23,9 +23,8 @@ import eu.timepit.refined
 import eu.timepit.refined.api.Refined
 import eu.timepit.refined.collection.NonEmpty
 import org.apache.james.jmap.core.Id.Id
-import org.apache.james.jmap.core.State.State
 import org.apache.james.jmap.core.UnsignedInt.UnsignedInt
-import org.apache.james.jmap.core.{AccountId, Properties}
+import org.apache.james.jmap.core.{AccountId, Properties, State}
 import org.apache.james.jmap.mail.MailboxGet.UnparsedMailboxId
 import org.apache.james.jmap.method.WithAccountId
 import org.apache.james.mailbox.model.MailboxId
diff --git a/server/protocols/jmap-rfc-8621/src/main/scala/org/apache/james/jmap/mail/MailboxSet.scala b/server/protocols/jmap-rfc-8621/src/main/scala/org/apache/james/jmap/mail/MailboxSet.scala
index 021139d..5d73bdc 100644
--- a/server/protocols/jmap-rfc-8621/src/main/scala/org/apache/james/jmap/mail/MailboxSet.scala
+++ b/server/protocols/jmap-rfc-8621/src/main/scala/org/apache/james/jmap/mail/MailboxSet.scala
@@ -27,8 +27,7 @@ import eu.timepit.refined.types.string.NonEmptyString
 import org.apache.james.core.Username
 import org.apache.james.jmap.core.CapabilityIdentifier.CapabilityIdentifier
 import org.apache.james.jmap.core.SetError.{SetErrorDescription, SetErrorType}
-import org.apache.james.jmap.core.State.State
-import org.apache.james.jmap.core.{AccountId, CapabilityIdentifier, Properties, SetError}
+import org.apache.james.jmap.core.{AccountId, CapabilityIdentifier, Properties, SetError, State}
 import org.apache.james.jmap.json.MailboxSerializer
 import org.apache.james.jmap.mail.MailboxGet.UnparsedMailboxId
 import org.apache.james.jmap.mail.MailboxName.MailboxName
diff --git a/server/protocols/jmap-rfc-8621/src/main/scala/org/apache/james/jmap/vacation/VacationResponseGet.scala b/server/protocols/jmap-rfc-8621/src/main/scala/org/apache/james/jmap/vacation/VacationResponseGet.scala
index 6b9f6e7..8d07bef 100644
--- a/server/protocols/jmap-rfc-8621/src/main/scala/org/apache/james/jmap/vacation/VacationResponseGet.scala
+++ b/server/protocols/jmap-rfc-8621/src/main/scala/org/apache/james/jmap/vacation/VacationResponseGet.scala
@@ -19,8 +19,7 @@
 
 package org.apache.james.jmap.vacation
 
-import org.apache.james.jmap.core.State.State
-import org.apache.james.jmap.core.{AccountId, Properties}
+import org.apache.james.jmap.core.{AccountId, Properties, State}
 import org.apache.james.jmap.method.WithAccountId
 import org.apache.james.jmap.vacation.VacationResponse.UnparsedVacationResponseId
 
diff --git a/server/protocols/jmap-rfc-8621/src/main/scala/org/apache/james/jmap/vacation/VacationResponseSet.scala b/server/protocols/jmap-rfc-8621/src/main/scala/org/apache/james/jmap/vacation/VacationResponseSet.scala
index 6cfe717..89abd4e 100644
--- a/server/protocols/jmap-rfc-8621/src/main/scala/org/apache/james/jmap/vacation/VacationResponseSet.scala
+++ b/server/protocols/jmap-rfc-8621/src/main/scala/org/apache/james/jmap/vacation/VacationResponseSet.scala
@@ -24,9 +24,8 @@ import java.time.format.DateTimeFormatter
 
 import org.apache.james.jmap.api.vacation.Vacation.ID
 import org.apache.james.jmap.api.vacation.VacationPatch
-import org.apache.james.jmap.core.AccountId
 import org.apache.james.jmap.core.SetError.{SetErrorDescription, SetErrorType, invalidArgumentValue, serverFailValue}
-import org.apache.james.jmap.core.State.State
+import org.apache.james.jmap.core.{AccountId, State}
 import org.apache.james.jmap.method.WithAccountId
 import org.apache.james.util.ValuePatch
 import play.api.libs.json.{JsBoolean, JsNull, JsObject, JsString, JsValue}
diff --git a/server/protocols/jmap-rfc-8621/src/test/scala/org/apache/james/jmap/json/MailboxGetSerializationTest.scala b/server/protocols/jmap-rfc-8621/src/test/scala/org/apache/james/jmap/json/MailboxGetSerializationTest.scala
index 55a4a7b..5eb339a 100644
--- a/server/protocols/jmap-rfc-8621/src/test/scala/org/apache/james/jmap/json/MailboxGetSerializationTest.scala
+++ b/server/protocols/jmap-rfc-8621/src/test/scala/org/apache/james/jmap/json/MailboxGetSerializationTest.scala
@@ -21,6 +21,7 @@ package org.apache.james.jmap.json
 
 import eu.timepit.refined.auto._
 import net.javacrumbs.jsonunit.assertj.JsonAssertions.assertThatJson
+import org.apache.james.jmap.core.State.INSTANCE
 import org.apache.james.jmap.core.{AccountId, DefaultCapabilities, Properties}
 import org.apache.james.jmap.json.Fixture._
 import org.apache.james.jmap.json.MailboxGetSerializationTest._
@@ -145,15 +146,15 @@ class MailboxGetSerializationTest extends AnyWordSpec with Matchers {
     "succeed" in {
       val actualValue: MailboxGetResponse = MailboxGetResponse(
         accountId = ACCOUNT_ID,
-        state = "75128aab4b1b",
+        state = INSTANCE,
         list = List(MAILBOX),
         notFound = NotFound(Set(MAILBOX_ID_1, MAILBOX_ID_2)))
 
       val expectedJson: String =
-        """
+        s"""
           |{
           |  "accountId": "aHR0cHM6Ly93d3cuYmFzZTY0ZW5jb2RlLm9yZy8",
-          |  "state": "75128aab4b1b",
+          |  "state": "${INSTANCE.value}",
           |  "list": [{
           |    "id":"2",
           |    "name":"inbox",
diff --git a/server/protocols/jmap-rfc-8621/src/test/scala/org/apache/james/jmap/json/ResponseObjectSerializationTest.scala b/server/protocols/jmap-rfc-8621/src/test/scala/org/apache/james/jmap/json/ResponseObjectSerializationTest.scala
index 3a4a532..6f522ef 100644
--- a/server/protocols/jmap-rfc-8621/src/test/scala/org/apache/james/jmap/json/ResponseObjectSerializationTest.scala
+++ b/server/protocols/jmap-rfc-8621/src/test/scala/org/apache/james/jmap/json/ResponseObjectSerializationTest.scala
@@ -19,8 +19,8 @@
 
 package org.apache.james.jmap.json
 
-import eu.timepit.refined.auto._
-import org.apache.james.jmap.core.ResponseObject
+import org.apache.james.jmap.core.ResponseObject.SESSION_STATE
+import org.apache.james.jmap.core.{ResponseObject, State}
 import org.apache.james.jmap.json.Fixture._
 import org.scalatest.matchers.should.Matchers
 import org.scalatest.wordspec.AnyWordSpec
@@ -30,11 +30,11 @@ class ResponseObjectSerializationTest extends AnyWordSpec with Matchers {
   "Deserialize ResponseObject" should {
     "succeed " in {
       val expectedResponseObject = ResponseObject(
-        sessionState = "75128aab4b1b",
+        sessionState = SESSION_STATE,
         methodResponses = Seq(invocation1))
 
       ResponseSerializer.deserializeResponseObject(
-        """
+        s"""
           |{
           |  "methodResponses": [
           |    [ "Core/echo", {
@@ -42,20 +42,20 @@ class ResponseObjectSerializationTest extends AnyWordSpec with Matchers {
           |      "arg2": "arg2data"
           |    }, "c1" ]
           |  ],
-          |  "sessionState": "75128aab4b1b"
+          |  "sessionState": "${SESSION_STATE.value}"
           |}
           |""".stripMargin) should be(JsSuccess(expectedResponseObject))
     }
 
     "succeed with many Capability, methodCalls" in {
       val expectedResponseObject = ResponseObject(
-        sessionState = "75128aab4b1b",
+        sessionState = State.INSTANCE,
         methodResponses = Seq(invocation1, invocation2))
 
       ResponseSerializer.deserializeResponseObject(
-        """
+        s"""
           |{
-          |  "sessionState": "75128aab4b1b",
+          |  "sessionState": "${SESSION_STATE.value}",
           |  "methodResponses": [
           |    [ "Core/echo", {
           |      "arg1": "arg1data",
@@ -74,13 +74,13 @@ class ResponseObjectSerializationTest extends AnyWordSpec with Matchers {
   "Serialize ResponseObject" should {
     "succeed " in {
       val responseObject: ResponseObject = ResponseObject(
-        sessionState = "75128aab4b1b",
+        sessionState = State.INSTANCE,
         methodResponses = Seq(invocation1))
 
       val expectedJson = Json.prettyPrint(Json.parse(
-        """
+        s"""
           |{
-          |  "sessionState": "75128aab4b1b",
+          |  "sessionState": "${SESSION_STATE.value}",
           |  "methodResponses": [
           |    [ "Core/echo", {
           |      "arg1": "arg1data",
diff --git a/server/protocols/jmap-rfc-8621/src/test/scala/org/apache/james/jmap/json/SessionSerializationTest.scala b/server/protocols/jmap-rfc-8621/src/test/scala/org/apache/james/jmap/json/SessionSerializationTest.scala
index 6d9931e..861ce63 100644
--- a/server/protocols/jmap-rfc-8621/src/test/scala/org/apache/james/jmap/json/SessionSerializationTest.scala
+++ b/server/protocols/jmap-rfc-8621/src/test/scala/org/apache/james/jmap/json/SessionSerializationTest.scala
@@ -26,8 +26,7 @@ import org.apache.james.core.Username
 import org.apache.james.jmap.core.CapabilityIdentifier.CapabilityIdentifier
 import org.apache.james.jmap.core.CoreCapabilityProperties.CollationAlgorithm
 import org.apache.james.jmap.core.MailCapability.EmailQuerySortOption
-import org.apache.james.jmap.core.State.State
-import org.apache.james.jmap.core.{Account, Capabilities, CoreCapability, CoreCapabilityProperties, IsPersonal, IsReadOnly, MailCapability, MailCapabilityProperties, MaxCallsInRequest, MaxConcurrentRequests, MaxConcurrentUpload, MaxMailboxDepth, MaxMailboxesPerEmail, MaxObjectsInGet, MaxObjectsInSet, MaxSizeAttachmentsPerEmail, MaxSizeMailboxName, MaxSizeRequest, MaxSizeUpload, MayCreateTopLevelMailbox, QuotaCapability, Session, SharesCapability, VacationResponseCapability}
+import org.apache.james.jmap.core.{Account, Capabilities, CoreCapability, CoreCapabilityProperties, IsPersonal, IsReadOnly, MailCapability, MailCapabilityProperties, MaxCallsInRequest, MaxConcurrentRequests, MaxConcurrentUpload, MaxMailboxDepth, MaxMailboxesPerEmail, MaxObjectsInGet, MaxObjectsInSet, MaxSizeAttachmentsPerEmail, MaxSizeMailboxName, MaxSizeRequest, MaxSizeUpload, MayCreateTopLevelMailbox, QuotaCapability, Session, SharesCapability, State, VacationResponseCapability}
 import org.apache.james.jmap.json.SessionSerializationTest.SESSION
 import org.scalatest.matchers.should.Matchers
 import org.scalatest.wordspec.AnyWordSpec
@@ -51,7 +50,6 @@ object SessionSerializationTest {
   private val USER_1 = Username.of("user1@james.org")
   private val USER_2 = Username.of("user2@james.org")
   private val URL = new URL("http://james.org")
-  private val STATE : State = "fda9342jcm"
 
   private val MAIL_IDENTIFIER: CapabilityIdentifier = "urn:ietf:params:jmap:mail"
   private val CONTACT_IDENTIFIER: CapabilityIdentifier = "urn:ietf:params:jmap:contact"
@@ -110,7 +108,7 @@ object SessionSerializationTest {
     downloadUrl = URL,
     uploadUrl = URL,
     eventSourceUrl = URL,
-    state = STATE)
+    state = State.INSTANCE)
 
   def readResource(resourceFileName: String): String = {
     Using(Source.fromURL(getClass.getResource(resourceFileName), "UTF-8")) { source =>
@@ -124,7 +122,7 @@ class SessionSerializationTest extends AnyWordSpec with Matchers {
   "sessionWrites" should {
     "serialize session" in {
       val json = Json.parse(
-        """{
+        s"""{
           |  "capabilities": {
           |    "urn:ietf:params:jmap:core": {
           |      "maxSizeUpload": 50000000,
@@ -205,7 +203,7 @@ class SessionSerializationTest extends AnyWordSpec with Matchers {
           |  "downloadUrl": "http://james.org",
           |  "uploadUrl": "http://james.org",
           |  "eventSourceUrl": "http://james.org",
-          |  "state": "fda9342jcm"
+          |  "state": "${State.INSTANCE.value}"
           |}""".stripMargin)
       ResponseSerializer.serialize(SESSION) should equal(json)
     }
diff --git a/server/protocols/jmap-rfc-8621/src/test/scala/org/apache/james/jmap/json/VacationResponseGetSerializationTest.scala b/server/protocols/jmap-rfc-8621/src/test/scala/org/apache/james/jmap/json/VacationResponseGetSerializationTest.scala
index dda1b9a..b374d94 100644
--- a/server/protocols/jmap-rfc-8621/src/test/scala/org/apache/james/jmap/json/VacationResponseGetSerializationTest.scala
+++ b/server/protocols/jmap-rfc-8621/src/test/scala/org/apache/james/jmap/json/VacationResponseGetSerializationTest.scala
@@ -21,7 +21,8 @@ package org.apache.james.jmap.json
 
 import eu.timepit.refined.auto._
 import net.javacrumbs.jsonunit.assertj.JsonAssertions.assertThatJson
-import org.apache.james.jmap.core.{AccountId, Properties}
+import org.apache.james.jmap.core.ResponseObject.SESSION_STATE
+import org.apache.james.jmap.core.{AccountId, Properties, State}
 import org.apache.james.jmap.json.Fixture.id
 import org.apache.james.jmap.json.VacationResponseGetSerializationTest.{ACCOUNT_ID, PROPERTIES, SINGLETON_ID}
 import org.apache.james.jmap.json.VacationResponseSerializationTest.VACATION_RESPONSE
@@ -153,15 +154,15 @@ class VacationResponseGetSerializationTest extends AnyWordSpec with Matchers {
     "succeed" in {
       val actualValue: VacationResponseGetResponse = VacationResponseGetResponse(
         accountId = ACCOUNT_ID,
-        state = "75128aab4b1b",
+        state = State.INSTANCE,
         list = List(VACATION_RESPONSE),
         notFound = VacationResponseNotFound(Set("randomId1", "randomId2")))
 
       val expectedJson: String =
-        """
+        s"""
           |{
           |  "accountId": "aHR0cHM6Ly93d3cuYmFzZTY0ZW5jb2RlLm9yZy8",
-          |  "state": "75128aab4b1b",
+          |  "state": "${SESSION_STATE.value}",
           |  "list": [{
           |    "id":"singleton",
           |    "isEnabled":true,
diff --git a/server/protocols/jmap-rfc-8621/src/test/scala/org/apache/james/jmap/routes/JMAPApiRoutesTest.scala b/server/protocols/jmap-rfc-8621/src/test/scala/org/apache/james/jmap/routes/JMAPApiRoutesTest.scala
index b8bb281..1ea3a45 100644
--- a/server/protocols/jmap-rfc-8621/src/test/scala/org/apache/james/jmap/routes/JMAPApiRoutesTest.scala
+++ b/server/protocols/jmap-rfc-8621/src/test/scala/org/apache/james/jmap/routes/JMAPApiRoutesTest.scala
@@ -39,6 +39,7 @@ import org.apache.james.jmap.JMAPUrls.JMAP
 import org.apache.james.jmap.core.CapabilityIdentifier.{CapabilityIdentifier, JMAP_CORE}
 import org.apache.james.jmap.core.Invocation.MethodName
 import org.apache.james.jmap.core.RequestLevelErrorType
+import org.apache.james.jmap.core.ResponseObject.SESSION_STATE
 import org.apache.james.jmap.http.{Authenticator, BasicAuthenticationStrategy, UserProvisioning}
 import org.apache.james.jmap.method.{CoreEchoMethod, Method}
 import org.apache.james.jmap.routes.JMAPApiRoutesTest._
@@ -149,8 +150,8 @@ object JMAPApiRoutesTest {
       |}""".stripMargin
 
   private val RESPONSE_OBJECT: String =
-    """{
-      |  "sessionState": "75128aab4b1b",
+    s"""{
+      |  "sessionState": "${SESSION_STATE.value}",
       |  "methodResponses": [
       |    [
       |      "Core/echo",
@@ -164,8 +165,8 @@ object JMAPApiRoutesTest {
       |}""".stripMargin
 
   private val SERVER_FAIL_RESPONSE_OBJECT: String =
-    """{
-      |  "sessionState": "75128aab4b1b",
+    s"""{
+      |  "sessionState": "${SESSION_STATE.value}",
       |  "methodResponses": [
       |    [
       |      "error",
@@ -187,8 +188,8 @@ object JMAPApiRoutesTest {
       |}""".stripMargin
 
   private val RESPONSE_OBJECT_WITH_UNSUPPORTED_METHOD: String =
-    """{
-      |  "sessionState": "75128aab4b1b",
+    s"""{
+      |  "sessionState": "${SESSION_STATE.value}",
       |  "methodResponses": [
       |    [
       |      "Core/echo",
diff --git a/server/protocols/jmap-rfc-8621/src/test/scala/org/apache/james/jmap/routes/SessionRoutesTest.scala b/server/protocols/jmap-rfc-8621/src/test/scala/org/apache/james/jmap/routes/SessionRoutesTest.scala
index 8a3bb45..2f21d81 100644
--- a/server/protocols/jmap-rfc-8621/src/test/scala/org/apache/james/jmap/routes/SessionRoutesTest.scala
+++ b/server/protocols/jmap-rfc-8621/src/test/scala/org/apache/james/jmap/routes/SessionRoutesTest.scala
@@ -32,6 +32,7 @@ import org.apache.http.HttpStatus
 import org.apache.james.core.Username
 import org.apache.james.jmap.core.JmapRfc8621Configuration
 import org.apache.james.jmap.core.JmapRfc8621Configuration.LOCALHOST_URL_PREFIX
+import org.apache.james.jmap.core.State.INSTANCE
 import org.apache.james.jmap.http.Authenticator
 import org.apache.james.jmap.routes.SessionRoutesTest.{BOB, TEST_CONFIGURATION}
 import org.apache.james.jmap.{JMAPConfiguration, JMAPRoutesHandler, JMAPServer, Version, VersionParser}
@@ -192,7 +193,7 @@ class SessionRoutesTest extends AnyFlatSpec with BeforeAndAfter with Matchers {
                          |  "downloadUrl" : "$LOCALHOST_URL_PREFIX/$downloadPath",
                          |  "uploadUrl" : "$LOCALHOST_URL_PREFIX/upload/{accountId}",
                          |  "eventSourceUrl" : "$LOCALHOST_URL_PREFIX/eventSource",
-                         |  "state" : "000001"
+                         |  "state" : "${INSTANCE.value}"
                          |}""".stripMargin
 
     assertThatJson(sessionJson).isEqualTo(expectedJson)


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


[james-project] 05/07: JAMES-3468 Webadmin Update User API should reject inserts of already existing users

Posted by bt...@apache.org.
This is an automated email from the ASF dual-hosted git repository.

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

commit 1bfed8eeb9840dd8e43760892312cef651f437f2
Author: quanth <hq...@linagora.com>
AuthorDate: Wed Dec 9 17:09:46 2020 +0700

    JAMES-3468 Webadmin Update User API should reject inserts of already existing users
---
 .../apache/james/webadmin/routes/UserRoutes.java   | 29 +++++++--
 .../apache/james/webadmin/service/UserService.java | 15 +++--
 .../james/webadmin/routes/UserRoutesTest.java      | 74 ++++++++++++++++++++--
 3 files changed, 106 insertions(+), 12 deletions(-)

diff --git a/server/protocols/webadmin/webadmin-data/src/main/java/org/apache/james/webadmin/routes/UserRoutes.java b/server/protocols/webadmin/webadmin-data/src/main/java/org/apache/james/webadmin/routes/UserRoutes.java
index 6cfcbc8..9e5b2d0 100644
--- a/server/protocols/webadmin/webadmin-data/src/main/java/org/apache/james/webadmin/routes/UserRoutes.java
+++ b/server/protocols/webadmin/webadmin-data/src/main/java/org/apache/james/webadmin/routes/UserRoutes.java
@@ -37,6 +37,7 @@ import org.apache.james.core.Username;
 import org.apache.james.rrt.api.CanSendFrom;
 import org.apache.james.rrt.api.RecipientRewriteTable;
 import org.apache.james.rrt.api.RecipientRewriteTableException;
+import org.apache.james.user.api.AlreadyExistInUsersRepositoryException;
 import org.apache.james.user.api.InvalidUsernameException;
 import org.apache.james.user.api.UsersRepositoryException;
 import org.apache.james.webadmin.Constants;
@@ -76,6 +77,7 @@ public class UserRoutes implements Routes {
     private static final Logger LOGGER = LoggerFactory.getLogger(UserRoutes.class);
 
     public static final String USERS = "/users";
+    private static final String FORCE_PARAM = "force";
 
     private final UserService userService;
     private final JsonTransformer jsonTransformer;
@@ -150,11 +152,18 @@ public class UserRoutes implements Routes {
     @ApiOperation(value = "Creating an user")
     @ApiImplicitParams({
             @ApiImplicitParam(required = true, dataType = "string", name = "username", paramType = "path"),
-            @ApiImplicitParam(required = true, dataTypeClass = AddUserRequest.class, paramType = "body")
+            @ApiImplicitParam(required = true, dataTypeClass = AddUserRequest.class, paramType = "body"),
+            @ApiImplicitParam(
+                    paramType = "query parameter",
+                    dataType = "String",
+                    allowEmptyValue = true,
+                    example = "?force",
+                    value = "If present, it allows to overwrite a user password. Otherwise modification of already existing users are rejected.")
     })
     @ApiResponses(value = {
             @ApiResponse(code = HttpStatus.NO_CONTENT_204, message = "OK. New user is added."),
             @ApiResponse(code = HttpStatus.BAD_REQUEST_400, message = "Invalid input user."),
+            @ApiResponse(code = HttpStatus.CONFLICT_409, message = "User already exist."),
             @ApiResponse(code = HttpStatus.INTERNAL_SERVER_ERROR_500,
                 message = "Internal server error - Something went bad on the server side.")
     })
@@ -222,9 +231,12 @@ public class UserRoutes implements Routes {
     private HaltException upsertUser(Request request, Response response) throws JsonExtractException {
         Username username = extractUsername(request);
         try {
-            userService.upsertUser(username,
-                jsonExtractor.parse(request.body()).getPassword());
-
+            boolean isForced = request.queryParams().contains(FORCE_PARAM);
+            if (isForced) {
+                userService.upsertUser(username, jsonExtractor.parse(request.body()).getPassword());
+            } else {
+                userService.insertUser(username, jsonExtractor.parse(request.body()).getPassword());
+            }
             return halt(HttpStatus.NO_CONTENT_204);
         } catch (InvalidUsernameException e) {
             LOGGER.info("Invalid username", e);
@@ -234,6 +246,14 @@ public class UserRoutes implements Routes {
                 .message("Username supplied is invalid")
                 .cause(e)
                 .haltError();
+        } catch (AlreadyExistInUsersRepositoryException e) {
+            LOGGER.info(e.getMessage());
+            throw ErrorResponder.builder()
+                    .statusCode(HttpStatus.CONFLICT_409)
+                    .type(ErrorType.INVALID_ARGUMENT)
+                    .message("User already exists")
+                    .cause(e)
+                    .haltError();
         } catch (UsersRepositoryException e) {
             String errorMessage = String.format("Error while upserting user '%s'", username);
             LOGGER.info(errorMessage, e);
@@ -278,4 +298,5 @@ public class UserRoutes implements Routes {
     private Username extractUsername(Request request) {
         return Username.of(request.params(USER_NAME));
     }
+
 }
\ No newline at end of file
diff --git a/server/protocols/webadmin/webadmin-data/src/main/java/org/apache/james/webadmin/service/UserService.java b/server/protocols/webadmin/webadmin-data/src/main/java/org/apache/james/webadmin/service/UserService.java
index 35e5cb6..89c8a9b 100644
--- a/server/protocols/webadmin/webadmin-data/src/main/java/org/apache/james/webadmin/service/UserService.java
+++ b/server/protocols/webadmin/webadmin-data/src/main/java/org/apache/james/webadmin/service/UserService.java
@@ -26,6 +26,7 @@ import java.util.stream.Stream;
 import javax.inject.Inject;
 
 import org.apache.james.core.Username;
+import org.apache.james.user.api.AlreadyExistInUsersRepositoryException;
 import org.apache.james.user.api.UsersRepository;
 import org.apache.james.user.api.UsersRepositoryException;
 import org.apache.james.user.api.model.User;
@@ -62,19 +63,25 @@ public class UserService {
 
     public void upsertUser(Username username, char[] password) throws UsersRepositoryException {
         User user = usersRepository.getUserByName(username);
-        upsert(user, username, password);
+        if (user == null) {
+            usersRepository.addUser(username, new String(password));
+        } else {
+            user.setPassword(new String(password));
+            usersRepository.updateUser(user);
+        }
     }
 
     public boolean userExists(Username username) throws UsersRepositoryException {
         return usersRepository.contains(username);
     }
 
-    private void upsert(User user, Username username, char[] password) throws UsersRepositoryException {
+    public void insertUser(Username username, char[] password) throws UsersRepositoryException, AlreadyExistInUsersRepositoryException {
+        User user = usersRepository.getUserByName(username);
         if (user == null) {
             usersRepository.addUser(username, new String(password));
         } else {
-            user.setPassword(new String(password));
-            usersRepository.updateUser(user);
+            throw new AlreadyExistInUsersRepositoryException("User " + username + " already exists.");
         }
     }
+
 }
diff --git a/server/protocols/webadmin/webadmin-data/src/test/java/org/apache/james/webadmin/routes/UserRoutesTest.java b/server/protocols/webadmin/webadmin-data/src/test/java/org/apache/james/webadmin/routes/UserRoutesTest.java
index 99bc9f8..a5fe202 100644
--- a/server/protocols/webadmin/webadmin-data/src/test/java/org/apache/james/webadmin/routes/UserRoutesTest.java
+++ b/server/protocols/webadmin/webadmin-data/src/test/java/org/apache/james/webadmin/routes/UserRoutesTest.java
@@ -438,6 +438,7 @@ class UserRoutesTest {
                 doThrow(new UsersRepositoryException("message")).when(usersRepository).updateUser(any());
 
                 given()
+                    .queryParam("force")
                     .body("{\"password\":\"password\"}")
                 .when()
                     .put(USERNAME_WITH_DOMAIN.asString())
@@ -497,6 +498,7 @@ class UserRoutesTest {
                 doThrow(new RuntimeException()).when(usersRepository).updateUser(any());
 
                 given()
+                    .queryParam("force")
                     .body("{\"password\":\"password\"}")
                 .when()
                     .put(USERNAME_WITH_DOMAIN.asString())
@@ -542,7 +544,7 @@ class UserRoutesTest {
         }
 
         @Test
-        void puttingWithDomainPartInUsernameTwoTimesShouldBeAllowed() {
+        void puttingWithDomainPartInUsernameTwoTimesShouldNotBeAllowed() {
             // Given
             with()
                 .body("{\"password\":\"password\"}")
@@ -554,7 +556,7 @@ class UserRoutesTest {
             .when()
                 .put(USERNAME_WITH_DOMAIN.asString())
             .then()
-                .statusCode(HttpStatus.NO_CONTENT_204);
+                .statusCode(HttpStatus.CONFLICT_409);
 
             // Then
             List<Map<String, String>> users =
@@ -617,6 +619,38 @@ class UserRoutesTest {
         }
 
         @Test
+        void putWithDomainPartInUsernameWithExistingUsernameAndNonForceParamShouldNotBeAllowed() {
+            given()
+                .body("{\"password\":\"password\"}")
+                .put(USERNAME_WITH_DOMAIN.asString());
+
+            given()
+                .body("{\"password\":\"password\"}")
+            .when()
+                .put(USERNAME_WITH_DOMAIN.asString())
+            .then()
+                .statusCode(HttpStatus.CONFLICT_409)
+                .body("statusCode", is(HttpStatus.CONFLICT_409))
+                .body("type", is(ErrorResponder.ErrorType.INVALID_ARGUMENT.getType()))
+                .body("message", is("User already exists"));
+        }
+
+        @Test
+        void putWithDomainPartInUsernameWithExistingUsernameAndForceParamShouldBeAllowed() {
+            given()
+                .body("{\"password\":\"password\"}")
+                .put(USERNAME_WITH_DOMAIN.asString());
+
+            given()
+                .body("{\"password\":\"password\"}")
+                .queryParam("force")
+            .when()
+                .put(USERNAME_WITH_DOMAIN.asString())
+            .then()
+                .statusCode(HttpStatus.NO_CONTENT_204);
+        }
+
+        @Test
         void putWithDomainPartInUsernameShouldReturnOkWhenValidJsonBody() {
             given()
                 .body("{\"password\":\"password\"}")
@@ -731,7 +765,7 @@ class UserRoutesTest {
         }
 
         @Test
-        void puttingWithoutDomainPartInUsernameTwoTimesShouldBeAllowed() {
+        void puttingWithoutDomainPartInUsernameTwoTimesShouldNotBeAllowed() {
             // Given
             with()
                 .body("{\"password\":\"password\"}")
@@ -743,7 +777,7 @@ class UserRoutesTest {
             .when()
                 .put(USERNAME_WITHOUT_DOMAIN.asString())
             .then()
-                .statusCode(HttpStatus.NO_CONTENT_204);
+                .statusCode(HttpStatus.CONFLICT_409);
 
             // Then
             List<Map<String, String>> users =
@@ -792,6 +826,38 @@ class UserRoutesTest {
         }
 
         @Test
+        void putWithoutDomainPartInUsernameWithExistingUsernameAndNonForceParamShouldNotBeAllowed() {
+            given()
+                .body("{\"password\":\"password\"}")
+                .put(USERNAME_WITHOUT_DOMAIN.asString());
+
+            given()
+                .body("{\"password\":\"password\"}")
+            .when()
+                .put(USERNAME_WITHOUT_DOMAIN.asString())
+            .then()
+                .statusCode(HttpStatus.CONFLICT_409)
+                .body("statusCode", is(HttpStatus.CONFLICT_409))
+                .body("type", is(ErrorResponder.ErrorType.INVALID_ARGUMENT.getType()))
+                .body("message", is("User already exists"));
+        }
+
+        @Test
+        void putWithoutDomainPartInUsernameWithExistingUsernameAndForceParamShouldBeAllowed() {
+            given()
+                .body("{\"password\":\"password\"}")
+                .put(USERNAME_WITHOUT_DOMAIN.asString());
+
+            given()
+                .body("{\"password\":\"password\"}")
+                .queryParam("force")
+            .when()
+                .put(USERNAME_WITHOUT_DOMAIN.asString())
+            .then()
+                .statusCode(HttpStatus.NO_CONTENT_204);
+        }
+
+        @Test
         void putShouldReturnBadRequestWhenUsernameHasDomainPart() {
             given()
                 .body("{\"password\":\"password\"}")


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


[james-project] 02/07: JAMES-3461 Mailbox/changes method & contract

Posted by bt...@apache.org.
This is an automated email from the ASF dual-hosted git repository.

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

commit e6053bd935ba8ac26494f199ebaf02974338945c
Author: LanKhuat <dl...@linagora.com>
AuthorDate: Fri Dec 4 18:05:41 2020 +0700

    JAMES-3461 Mailbox/changes method & contract
---
 .../james/modules/mailbox/MemoryMailboxModule.java |   4 +
 .../apache/james/jmap/draft/JmapGuiceProbe.java    |  10 +-
 .../rfc8621/contract/MailboxChangesContract.scala  | 172 ----
 .../contract/MailboxChangesMethodContract.scala    | 862 +++++++++++++++++++++
 .../memory/MemoryMailboxChangesMethodTest.java     |   7 +-
 .../src/test/resources/listeners.xml               |   3 +
 .../apache/james/jmap/core/ResponseObject.scala    |   2 +
 .../scala/org/apache/james/jmap/core/Session.scala |  10 +-
 .../james/jmap/json/EmailGetSerializer.scala       |   1 +
 .../apache/james/jmap/json/MailboxSerializer.scala |  18 +-
 .../james/jmap/json/ResponseSerializer.scala       |   6 -
 .../apache/james/jmap/json/ThreadSerializer.scala  |   4 +-
 .../scala/org/apache/james/jmap/json/package.scala |   4 +-
 .../org/apache/james/jmap/mail/MailboxGet.scala    |  20 +-
 .../scala/org/apache/james/jmap/mail/Thread.scala  |   5 +-
 .../james/jmap/method/MailboxChangesMethod.scala   |  41 +-
 .../org/apache/james/jmap/method/Method.scala      |   4 +-
 17 files changed, 957 insertions(+), 216 deletions(-)

diff --git a/server/container/guice/memory-guice/src/main/java/org/apache/james/modules/mailbox/MemoryMailboxModule.java b/server/container/guice/memory-guice/src/main/java/org/apache/james/modules/mailbox/MemoryMailboxModule.java
index 6f42336..211efe6 100644
--- a/server/container/guice/memory-guice/src/main/java/org/apache/james/modules/mailbox/MemoryMailboxModule.java
+++ b/server/container/guice/memory-guice/src/main/java/org/apache/james/modules/mailbox/MemoryMailboxModule.java
@@ -25,6 +25,8 @@ import javax.inject.Singleton;
 
 import org.apache.james.adapter.mailbox.UserRepositoryAuthenticator;
 import org.apache.james.adapter.mailbox.UserRepositoryAuthorizator;
+import org.apache.james.jmap.api.change.MailboxChangeRepository;
+import org.apache.james.jmap.memory.change.MemoryMailboxChangeRepository;
 import org.apache.james.mailbox.AttachmentContentLoader;
 import org.apache.james.mailbox.AttachmentManager;
 import org.apache.james.mailbox.Authenticator;
@@ -103,6 +105,7 @@ public class MemoryMailboxModule extends AbstractModule {
         bind(Authorizator.class).to(UserRepositoryAuthorizator.class);
         bind(MailboxManager.class).to(InMemoryMailboxManager.class);
         bind(StoreMailboxManager.class).to(InMemoryMailboxManager.class);
+        bind(MailboxChangeRepository.class).to(MemoryMailboxChangeRepository.class);
         bind(MessageIdManager.class).to(StoreMessageIdManager.class);
         bind(AttachmentManager.class).to(StoreAttachmentManager.class);
         bind(SessionProvider.class).to(SessionProviderImpl.class);
@@ -123,6 +126,7 @@ public class MemoryMailboxModule extends AbstractModule {
         bind(UserRepositoryAuthenticator.class).in(Scopes.SINGLETON);
         bind(UserRepositoryAuthorizator.class).in(Scopes.SINGLETON);
         bind(InMemoryMailboxManager.class).in(Scopes.SINGLETON);
+        bind(MemoryMailboxChangeRepository.class).in(Scopes.SINGLETON);
         bind(InMemoryMessageId.Factory.class).in(Scopes.SINGLETON);
         bind(StoreMessageIdManager.class).in(Scopes.SINGLETON);
         bind(StoreAttachmentManager.class).in(Scopes.SINGLETON);
diff --git a/server/container/guice/protocols/jmap/src/main/java/org/apache/james/jmap/draft/JmapGuiceProbe.java b/server/container/guice/protocols/jmap/src/main/java/org/apache/james/jmap/draft/JmapGuiceProbe.java
index 6347e36..c6d19fb 100644
--- a/server/container/guice/protocols/jmap/src/main/java/org/apache/james/jmap/draft/JmapGuiceProbe.java
+++ b/server/container/guice/protocols/jmap/src/main/java/org/apache/james/jmap/draft/JmapGuiceProbe.java
@@ -25,6 +25,8 @@ import javax.inject.Inject;
 
 import org.apache.james.core.Username;
 import org.apache.james.jmap.JMAPServer;
+import org.apache.james.jmap.api.change.MailboxChange;
+import org.apache.james.jmap.api.change.MailboxChangeRepository;
 import org.apache.james.jmap.api.model.AccountId;
 import org.apache.james.jmap.api.projections.MessageFastViewProjection;
 import org.apache.james.jmap.api.vacation.Vacation;
@@ -46,6 +48,7 @@ import reactor.core.publisher.Mono;
 public class JmapGuiceProbe implements GuiceProbe {
 
     private final VacationRepository vacationRepository;
+    private final MailboxChangeRepository mailboxChangeRepository;
     private final JMAPServer jmapServer;
     private final MessageIdManager messageIdManager;
     private final MailboxManager mailboxManager;
@@ -53,8 +56,9 @@ public class JmapGuiceProbe implements GuiceProbe {
     private final MessageFastViewProjection messageFastViewProjection;
 
     @Inject
-    private JmapGuiceProbe(VacationRepository vacationRepository, JMAPServer jmapServer, MessageIdManager messageIdManager, MailboxManager mailboxManager, EventBus eventBus, MessageFastViewProjection messageFastViewProjection) {
+    private JmapGuiceProbe(VacationRepository vacationRepository, MailboxChangeRepository mailboxChangeRepository, JMAPServer jmapServer, MessageIdManager messageIdManager, MailboxManager mailboxManager, EventBus eventBus, MessageFastViewProjection messageFastViewProjection) {
         this.vacationRepository = vacationRepository;
+        this.mailboxChangeRepository = mailboxChangeRepository;
         this.jmapServer = jmapServer;
         this.messageIdManager = messageIdManager;
         this.mailboxManager = mailboxManager;
@@ -86,4 +90,8 @@ public class JmapGuiceProbe implements GuiceProbe {
     public void clearMessageFastViewProjection() {
         Mono.from(messageFastViewProjection.clear()).block();
     }
+
+    public void saveMailboxChange(MailboxChange change) {
+        mailboxChangeRepository.save(change).block();
+    }
 }
diff --git a/server/protocols/jmap-rfc-8621-integration-tests/jmap-rfc-8621-integration-tests-common/src/main/scala/org/apache/james/jmap/rfc8621/contract/MailboxChangesContract.scala b/server/protocols/jmap-rfc-8621-integration-tests/jmap-rfc-8621-integration-tests-common/src/main/scala/org/apache/james/jmap/rfc8621/contract/MailboxChangesContract.scala
deleted file mode 100644
index b38a3ce..0000000
--- a/server/protocols/jmap-rfc-8621-integration-tests/jmap-rfc-8621-integration-tests-common/src/main/scala/org/apache/james/jmap/rfc8621/contract/MailboxChangesContract.scala
+++ /dev/null
@@ -1,172 +0,0 @@
-/****************************************************************
- * Licensed to the Apache Software Foundation (ASF) under one   *
- * or more contributor license agreements.  See the NOTICE file *
- * distributed with this work for additional information        *
- * regarding copyright ownership.  The ASF licenses this file   *
- * to you under the Apache License, Version 2.0 (the            *
- * "License"); you may not use this file except in compliance   *
- * with the License.  You may obtain a copy of the License at   *
- *                                                              *
- *   http://www.apache.org/licenses/LICENSE-2.0                 *
- *                                                              *
- * Unless required by applicable law or agreed to in writing,   *
- * software distributed under the License is distributed on an  *
- * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY       *
- * KIND, either express or implied.  See the License for the    *
- * specific language governing permissions and limitations      *
- * under the License.                                           *
- ****************************************************************/
-
-package org.apache.james.jmap.rfc8621.contract
-
-import io.netty.handler.codec.http.HttpHeaderNames.ACCEPT
-import io.restassured.RestAssured.{`given`, requestSpecification}
-import io.restassured.http.ContentType.JSON
-import net.javacrumbs.jsonunit.assertj.JsonAssertions.assertThatJson
-import org.apache.http.HttpStatus.SC_OK
-import org.apache.james.GuiceJamesServer
-import org.apache.james.jmap.http.UserCredential
-import org.apache.james.jmap.rfc8621.contract.Fixture.{ACCEPT_RFC8621_VERSION_HEADER, BOB, BOB_PASSWORD, DOMAIN, authScheme, baseRequestSpecBuilder}
-import org.apache.james.utils.DataProbeImpl
-import org.junit.jupiter.api.{BeforeEach, Test}
-
-trait MailboxChangesContract {
-  @BeforeEach
-  def setUp(server: GuiceJamesServer): Unit = {
-    server.getProbe(classOf[DataProbeImpl])
-      .fluent
-      .addDomain(DOMAIN.asString)
-      .addDomain("domain-alias.tld")
-      .addUser(BOB.asString, BOB_PASSWORD)
-
-    requestSpecification = baseRequestSpecBuilder(server)
-      .setAuth(authScheme(UserCredential(BOB, BOB_PASSWORD)))
-      .build
-  }
-
-  @Test
-  def shouldReturnCannotCalculateChanges(): Unit = {
-    val request =
-      s"""{
-         |  "using": ["urn:ietf:params:jmap:core", "urn:ietf:params:jmap:mail"],
-         |  "methodCalls": [[
-         |    "Mailbox/changes",
-         |    {
-         |      "accountId": "29883977c13473ae7cb7678ef767cbfbaffc8a44a6e463d971d23a65c1dc4af6",
-         |      "sinceState": "any-state"
-         |    },
-         |    "c1"]]
-         |}""".stripMargin
-
-    val response =  `given`
-      .header(ACCEPT.toString, ACCEPT_RFC8621_VERSION_HEADER)
-      .body(request)
-    .when
-      .post
-    .`then`
-      .statusCode(SC_OK)
-      .contentType(JSON)
-      .extract
-      .body
-      .asString
-
-    assertThatJson(response)
-      .isEqualTo(
-        """{
-          |    "sessionState": "75128aab4b1b",
-          |    "methodResponses": [
-          |        [
-          |            "error",
-          |            {
-          |                "type": "cannotCalculateChanges",
-          |                "description": "Naive implementation for Mailbox/changes"
-          |            },
-          |            "c1"
-          |        ]
-          |    ]
-          |}""".stripMargin)
-  }
-
-  @Test
-  def badAccountIdShouldBeRejected(): Unit = {
-    val request =
-      s"""{
-         |  "using": ["urn:ietf:params:jmap:core", "urn:ietf:params:jmap:mail"],
-         |  "methodCalls": [[
-         |    "Mailbox/changes",
-         |    {
-         |      "accountId": "bad",
-         |      "sinceState": "any-state"
-         |    },
-         |    "c1"]]
-         |}""".stripMargin
-
-    val response =  `given`
-      .header(ACCEPT.toString, ACCEPT_RFC8621_VERSION_HEADER)
-      .body(request)
-    .when
-      .post
-    .`then`
-      .statusCode(SC_OK)
-      .contentType(JSON)
-      .extract
-      .body
-      .asString
-
-    assertThatJson(response)
-      .isEqualTo(
-        """{
-          |    "sessionState": "75128aab4b1b",
-          |    "methodResponses": [
-          |        [
-          |            "error",
-          |            {
-          |                "type": "accountNotFound"
-          |            },
-          |            "c1"
-          |        ]
-          |    ]
-          |}""".stripMargin)
-  }
-
-  @Test
-  def shouldReturnEmptyWhenKnownState(): Unit = {
-    val request =
-      s"""{
-         |  "using": ["urn:ietf:params:jmap:core", "urn:ietf:params:jmap:mail"],
-         |  "methodCalls": [[
-         |    "Mailbox/changes",
-         |    {
-         |      "accountId": "29883977c13473ae7cb7678ef767cbfbaffc8a44a6e463d971d23a65c1dc4af6",
-         |      "sinceState": "000001"
-         |    },
-         |    "c1"]]
-         |}""".stripMargin
-
-    val response =  `given`
-      .header(ACCEPT.toString, ACCEPT_RFC8621_VERSION_HEADER)
-      .body(request)
-    .when
-      .post
-    .`then`
-      .statusCode(SC_OK)
-      .contentType(JSON)
-      .extract
-      .body
-      .asString
-
-    assertThatJson(response)
-      .inPath("methodResponses[0][1]")
-      .isEqualTo(
-        """{
-          |  "accountId": "29883977c13473ae7cb7678ef767cbfbaffc8a44a6e463d971d23a65c1dc4af6",
-          |  "oldState": "000001",
-          |  "newState": "000001",
-          |  "hasMoreChanges": false,
-          |  "updatedProperties": [],
-          |  "created": [],
-          |  "updated": [],
-          |  "destroyed": []
-          |}""".stripMargin)
-  }
-}
diff --git a/server/protocols/jmap-rfc-8621-integration-tests/jmap-rfc-8621-integration-tests-common/src/main/scala/org/apache/james/jmap/rfc8621/contract/MailboxChangesMethodContract.scala b/server/protocols/jmap-rfc-8621-integration-tests/jmap-rfc-8621-integration-tests-common/src/main/scala/org/apache/james/jmap/rfc8621/contract/MailboxChangesMethodContract.scala
new file mode 100644
index 0000000..e7de455
--- /dev/null
+++ b/server/protocols/jmap-rfc-8621-integration-tests/jmap-rfc-8621-integration-tests-common/src/main/scala/org/apache/james/jmap/rfc8621/contract/MailboxChangesMethodContract.scala
@@ -0,0 +1,862 @@
+/****************************************************************
+ * 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.rfc8621.contract
+
+import java.nio.charset.StandardCharsets
+import java.time.ZonedDateTime
+import java.util.UUID
+
+import io.netty.handler.codec.http.HttpHeaderNames.ACCEPT
+import io.restassured.RestAssured.{`given`, requestSpecification}
+import io.restassured.builder.ResponseSpecBuilder
+import io.restassured.http.ContentType.JSON
+import net.javacrumbs.jsonunit.assertj.JsonAssertions.assertThatJson
+import net.javacrumbs.jsonunit.core.Option.IGNORING_ARRAY_ORDER
+import net.javacrumbs.jsonunit.core.internal.Options
+import org.apache.http.HttpStatus.SC_OK
+import org.apache.james.GuiceJamesServer
+import org.apache.james.jmap.api.change.MailboxChange
+import org.apache.james.jmap.api.change.MailboxChange.State
+import org.apache.james.jmap.api.model.AccountId
+import org.apache.james.jmap.core.ResponseObject.SESSION_STATE
+import org.apache.james.jmap.draft.JmapGuiceProbe
+import org.apache.james.jmap.http.UserCredential
+import org.apache.james.jmap.rfc8621.contract.Fixture.{ACCEPT_RFC8621_VERSION_HEADER, ANDRE, ANDRE_ACCOUNT_ID, ANDRE_PASSWORD, BOB, BOB_PASSWORD, DOMAIN, authScheme, baseRequestSpecBuilder}
+import org.apache.james.mailbox.MessageManager.AppendCommand
+import org.apache.james.mailbox.model.MailboxACL.Right
+import org.apache.james.mailbox.model.{MailboxACL, MailboxId, MailboxPath}
+import org.apache.james.mime4j.dom.Message
+import org.apache.james.modules.{ACLProbeImpl, MailboxProbeImpl}
+import org.apache.james.utils.DataProbeImpl
+import org.assertj.core.api.Assertions.assertThat
+import org.junit.jupiter.api.{BeforeEach, Disabled, Test}
+import play.api.libs.json.{JsString, Json}
+
+import scala.jdk.CollectionConverters._
+
+object TestId {
+  def of(value: Long): MailboxId = TestId(value)
+}
+
+case class TestId(value: Long) extends MailboxId {
+  override def serialize(): String = String.valueOf(value)
+}
+
+trait MailboxChangesMethodContract {
+
+  @BeforeEach
+  def setUp(server: GuiceJamesServer): Unit = {
+    server.getProbe(classOf[DataProbeImpl])
+      .fluent
+      .addDomain(DOMAIN.asString)
+      .addDomain("domain-alias.tld")
+      .addUser(BOB.asString, BOB_PASSWORD)
+      .addUser(ANDRE.asString, ANDRE_PASSWORD)
+
+    requestSpecification = baseRequestSpecBuilder(server)
+      .setAuth(authScheme(UserCredential(BOB, BOB_PASSWORD)))
+      .build
+  }
+
+  @Test
+  def mailboxChangesShouldReturnCreatedChanges(server: GuiceJamesServer): Unit = {
+    val mailboxProbe: MailboxProbeImpl = server.getProbe(classOf[MailboxProbeImpl])
+    provisionSystemMailboxes(server)
+
+    val oldState: State = storeReferenceState(server)
+
+    val mailboxId1: String = mailboxProbe
+      .createMailbox(MailboxPath.forUser(BOB, "mailbox1"))
+      .serialize
+
+    val mailboxId2: String = mailboxProbe
+      .createMailbox(MailboxPath.forUser(BOB, "mailbox2"))
+      .serialize
+
+    val mailboxId3: String = mailboxProbe
+      .createMailbox(MailboxPath.forUser(BOB, "mailbox3"))
+      .serialize
+
+    val request =
+      s"""{
+         |  "using": ["urn:ietf:params:jmap:core", "urn:ietf:params:jmap:mail"],
+         |  "methodCalls": [[
+         |    "Mailbox/changes",
+         |    {
+         |      "accountId": "29883977c13473ae7cb7678ef767cbfbaffc8a44a6e463d971d23a65c1dc4af6",
+         |      "sinceState": "${oldState.getValue}"
+         |    },
+         |    "c1"]]
+         |}""".stripMargin
+
+      val response = `given`
+        .header(ACCEPT.toString, ACCEPT_RFC8621_VERSION_HEADER)
+        .body(request)
+      .when
+        .post
+      .`then`
+        .statusCode(SC_OK)
+        .contentType(JSON)
+        .extract
+        .body
+        .asString
+
+      assertThatJson(response)
+        .whenIgnoringPaths("methodResponses[0][1].newState")
+        .withOptions(new Options(IGNORING_ARRAY_ORDER))
+        .isEqualTo(
+          s"""{
+            |    "sessionState": "${SESSION_STATE.value}",
+            |    "methodResponses": [
+            |      [ "Mailbox/changes", {
+            |        "accountId": "29883977c13473ae7cb7678ef767cbfbaffc8a44a6e463d971d23a65c1dc4af6",
+            |        "oldState": "${oldState.getValue}",
+            |        "hasMoreChanges": false,
+            |        "updatedProperties": [],
+            |        "created": ["$mailboxId1", "$mailboxId2", "$mailboxId3"],
+            |        "updated": [],
+            |        "destroyed": []
+            |      }, "c1"]
+            |    ]
+            |}""".stripMargin)
+  }
+
+  @Test
+  def mailboxChangesShouldReturnUpdatedChangesWhenRenameMailbox(server: GuiceJamesServer): Unit = {
+    val mailboxProbe: MailboxProbeImpl = server.getProbe(classOf[MailboxProbeImpl])
+
+    provisionSystemMailboxes(server)
+    val path = MailboxPath.forUser(BOB, "mailbox1")
+    val mailboxId: String = mailboxProbe
+      .createMailbox(path)
+      .serialize
+
+    val oldState: State = storeReferenceState(server)
+
+    renameMailbox(mailboxId, "mailbox11")
+
+    val request =
+      s"""{
+         |  "using": ["urn:ietf:params:jmap:core", "urn:ietf:params:jmap:mail"],
+         |  "methodCalls": [[
+         |    "Mailbox/changes",
+         |    {
+         |      "accountId": "29883977c13473ae7cb7678ef767cbfbaffc8a44a6e463d971d23a65c1dc4af6",
+         |      "sinceState": "${oldState.getValue}"
+         |    },
+         |    "c1"]]
+         |}""".stripMargin
+
+    val response = `given`
+      .header(ACCEPT.toString, ACCEPT_RFC8621_VERSION_HEADER)
+      .body(request)
+    .when
+      .post
+    .`then`
+      .statusCode(SC_OK)
+      .contentType(JSON)
+      .extract
+      .body
+      .asString
+
+    assertThatJson(response)
+      .whenIgnoringPaths("methodResponses[0][1].newState")
+      .withOptions(new Options(IGNORING_ARRAY_ORDER))
+      .isEqualTo(
+        s"""{
+           |    "sessionState": "${SESSION_STATE.value}",
+           |    "methodResponses": [
+           |      [ "Mailbox/changes", {
+           |        "accountId": "29883977c13473ae7cb7678ef767cbfbaffc8a44a6e463d971d23a65c1dc4af6",
+           |        "oldState": "${oldState.getValue}",
+           |        "hasMoreChanges": false,
+           |        "updatedProperties": [],
+           |        "created": [],
+           |        "updated": ["$mailboxId"],
+           |        "destroyed": []
+           |      }, "c1"]
+           |    ]
+           |}""".stripMargin)
+  }
+
+  @Test
+  def mailboxChangesShouldReturnUpdatedChangesWhenAppendMessageToMailbox(server: GuiceJamesServer): Unit = {
+    val mailboxProbe: MailboxProbeImpl = server.getProbe(classOf[MailboxProbeImpl])
+
+    provisionSystemMailboxes(server)
+
+    val path = MailboxPath.forUser(BOB, "mailbox1")
+    val mailboxId: String = mailboxProbe
+      .createMailbox(path)
+      .serialize
+
+    val oldState: State = storeReferenceState(server)
+
+    val message: Message = Message.Builder
+      .of
+      .setSubject("test")
+      .setBody("testmail", StandardCharsets.UTF_8)
+      .build
+    mailboxProbe.appendMessage(BOB.asString(), path, AppendCommand.from(message))
+
+    val request =
+      s"""{
+         |  "using": ["urn:ietf:params:jmap:core", "urn:ietf:params:jmap:mail"],
+         |  "methodCalls": [[
+         |    "Mailbox/changes",
+         |    {
+         |      "accountId": "29883977c13473ae7cb7678ef767cbfbaffc8a44a6e463d971d23a65c1dc4af6",
+         |      "sinceState": "${oldState.getValue}"
+         |    },
+         |    "c1"]]
+         |}""".stripMargin
+
+    val response = `given`
+      .header(ACCEPT.toString, ACCEPT_RFC8621_VERSION_HEADER)
+      .body(request)
+    .when
+      .post
+    .`then`
+      .statusCode(SC_OK)
+      .contentType(JSON)
+      .extract
+      .body
+      .asString
+
+    assertThatJson(response)
+      .whenIgnoringPaths("methodResponses[0][1].newState")
+      .withOptions(new Options(IGNORING_ARRAY_ORDER))
+      .isEqualTo(
+        s"""{
+           |    "sessionState": "${SESSION_STATE.value}",
+           |    "methodResponses": [
+           |      [ "Mailbox/changes", {
+           |        "accountId": "29883977c13473ae7cb7678ef767cbfbaffc8a44a6e463d971d23a65c1dc4af6",
+           |        "oldState": "${oldState.getValue}",
+           |        "hasMoreChanges": false,
+           |        "updatedProperties": [],
+           |        "created": [],
+           |        "updated": ["$mailboxId"],
+           |        "destroyed": []
+           |      }, "c1"]
+           |    ]
+           |}""".stripMargin)
+  }
+
+  @Test
+  @Disabled("Not implemented yet")
+  def mailboxChangesShouldReturnUpdatedChangesWhenAppendMessageToDelegatedMailbox(server: GuiceJamesServer): Unit = {
+    val mailboxProbe: MailboxProbeImpl = server.getProbe(classOf[MailboxProbeImpl])
+
+    provisionSystemMailboxes(server)
+
+    val oldState: State = storeReferenceState(server)
+
+    val path = MailboxPath.forUser(BOB, "mailbox1")
+    val mailboxId: String = mailboxProbe
+      .createMailbox(path)
+      .serialize
+
+    server.getProbe(classOf[ACLProbeImpl])
+      .replaceRights(path, ANDRE.asString, new MailboxACL.Rfc4314Rights(Right.Lookup, Right.Read))
+
+    val message: Message = Message.Builder
+      .of
+      .setSubject("test")
+      .setBody("testmail", StandardCharsets.UTF_8)
+      .build
+    mailboxProbe.appendMessage(BOB.asString(), path, AppendCommand.from(message))
+
+    val request =
+      s"""{
+         |  "using": ["urn:ietf:params:jmap:core", "urn:ietf:params:jmap:mail"],
+         |  "methodCalls": [[
+         |    "Mailbox/changes",
+         |    {
+         |      "accountId": "$ANDRE_ACCOUNT_ID",
+         |      "sinceState": "${oldState.getValue}"
+         |    },
+         |    "c1"]]
+         |}""".stripMargin
+
+    val response = `given`(
+      baseRequestSpecBuilder(server)
+        .setAuth(authScheme(UserCredential(ANDRE, ANDRE_PASSWORD)))
+        .addHeader(ACCEPT.toString, ACCEPT_RFC8621_VERSION_HEADER)
+        .setBody(request)
+        .build, new ResponseSpecBuilder().build)
+      .post
+      .`then`
+        .statusCode(SC_OK)
+        .contentType(JSON)
+        .extract
+        .body
+        .asString
+
+    assertThatJson(response)
+      .whenIgnoringPaths("methodResponses[0][1].newState")
+      .withOptions(new Options(IGNORING_ARRAY_ORDER))
+      .isEqualTo(
+        s"""{
+           |    "sessionState": "${SESSION_STATE.value}",
+           |    "methodResponses": [
+           |      [ "Mailbox/changes", {
+           |        "accountId": "$ANDRE_ACCOUNT_ID",
+           |        "oldState": "${oldState.getValue}",
+           |        "hasMoreChanges": false,
+           |        "updatedProperties": [],
+           |        "created": [],
+           |        "updated": ["$mailboxId"],
+           |        "destroyed": []
+           |      }, "c1"]
+           |    ]
+           |}""".stripMargin)
+  }
+
+  @Test
+  def mailboxChangesShouldReturnDestroyedChanges(server: GuiceJamesServer): Unit = {
+    val mailboxProbe: MailboxProbeImpl = server.getProbe(classOf[MailboxProbeImpl])
+
+    provisionSystemMailboxes(server)
+
+    val path = MailboxPath.forUser(BOB, "mailbox1")
+    val mailboxId: String = mailboxProbe
+      .createMailbox(path)
+      .serialize
+
+    val oldState: State = storeReferenceState(server)
+
+    mailboxProbe
+      .deleteMailbox(path.getNamespace, BOB.asString(), path.getName)
+
+    val request =
+      s"""{
+         |  "using": ["urn:ietf:params:jmap:core", "urn:ietf:params:jmap:mail"],
+         |  "methodCalls": [[
+         |    "Mailbox/changes",
+         |    {
+         |      "accountId": "29883977c13473ae7cb7678ef767cbfbaffc8a44a6e463d971d23a65c1dc4af6",
+         |      "sinceState": "${oldState.getValue}"
+         |    },
+         |    "c1"]]
+         |}""".stripMargin
+
+    val response = `given`
+      .header(ACCEPT.toString, ACCEPT_RFC8621_VERSION_HEADER)
+      .body(request)
+    .when
+      .post
+    .`then`
+      .statusCode(SC_OK)
+      .contentType(JSON)
+      .extract
+      .body
+      .asString
+
+    assertThatJson(response)
+      .whenIgnoringPaths("methodResponses[0][1].newState")
+      .withOptions(new Options(IGNORING_ARRAY_ORDER))
+      .isEqualTo(
+        s"""{
+           |    "sessionState": "${SESSION_STATE.value}",
+           |    "methodResponses": [
+           |      [ "Mailbox/changes", {
+           |        "accountId": "29883977c13473ae7cb7678ef767cbfbaffc8a44a6e463d971d23a65c1dc4af6",
+           |        "oldState": "${oldState.getValue}",
+           |        "hasMoreChanges": false,
+           |        "updatedProperties": [],
+           |        "created": [],
+           |        "updated": [],
+           |        "destroyed": ["$mailboxId"]
+           |      }, "c1"]
+           |    ]
+           |}""".stripMargin)
+  }
+
+  @Test
+  def mailboxChangesShouldReturnAllTypeOfChanges(server: GuiceJamesServer): Unit = {
+    val mailboxProbe: MailboxProbeImpl = server.getProbe(classOf[MailboxProbeImpl])
+
+    provisionSystemMailboxes(server)
+
+    val oldState: State = storeReferenceState(server)
+
+    val path1 = MailboxPath.forUser(BOB, "mailbox1")
+    val mailboxId1: String = mailboxProbe
+      .createMailbox(path1)
+      .serialize
+
+    val message: Message = Message.Builder
+      .of
+      .setSubject("test")
+      .setBody("testmail", StandardCharsets.UTF_8)
+      .build
+    mailboxProbe.appendMessage(BOB.asString(), path1, AppendCommand.from(message))
+
+    val path2 = MailboxPath.forUser(BOB, "mailbox2")
+    val mailboxId2: String = mailboxProbe
+      .createMailbox(path2)
+      .serialize
+    renameMailbox(mailboxId2, "mailbox22")
+
+    server.getProbe(classOf[MailboxProbeImpl])
+      .deleteMailbox(path1.getNamespace, BOB.asString(), path1.getName)
+
+    val request =
+      s"""{
+         |  "using": ["urn:ietf:params:jmap:core", "urn:ietf:params:jmap:mail"],
+         |  "methodCalls": [[
+         |    "Mailbox/changes",
+         |    {
+         |      "accountId": "29883977c13473ae7cb7678ef767cbfbaffc8a44a6e463d971d23a65c1dc4af6",
+         |      "sinceState": "${oldState.getValue}"
+         |    },
+         |    "c1"]]
+         |}""".stripMargin
+
+    val response = `given`
+      .header(ACCEPT.toString, ACCEPT_RFC8621_VERSION_HEADER)
+      .body(request)
+    .when
+      .post
+    .`then`
+      .statusCode(SC_OK)
+      .contentType(JSON)
+      .extract
+      .body
+      .asString
+
+    assertThatJson(response)
+      .whenIgnoringPaths("methodResponses[0][1].newState")
+      .withOptions(new Options(IGNORING_ARRAY_ORDER))
+      .isEqualTo(
+        s"""{
+           |    "sessionState": "${SESSION_STATE.value}",
+           |    "methodResponses": [
+           |      [ "Mailbox/changes", {
+           |        "accountId": "29883977c13473ae7cb7678ef767cbfbaffc8a44a6e463d971d23a65c1dc4af6",
+           |        "oldState": "${oldState.getValue}",
+           |        "hasMoreChanges": false,
+           |        "updatedProperties": [],
+           |        "created": ["$mailboxId1", "$mailboxId2"],
+           |        "updated": ["$mailboxId1", "$mailboxId2"],
+           |        "destroyed": ["$mailboxId1"]
+           |      }, "c1"]
+           |    ]
+           |}""".stripMargin)
+  }
+
+  @Test
+  def mailboxChangesShouldReturnHasMoreChangesWhenTrue(server: GuiceJamesServer): Unit = {
+    val mailboxProbe: MailboxProbeImpl = server.getProbe(classOf[MailboxProbeImpl])
+    provisionSystemMailboxes(server)
+
+    val oldState: State = storeReferenceState(server)
+
+    val mailboxId1: String = mailboxProbe
+      .createMailbox(MailboxPath.forUser(BOB, "mailbox1"))
+      .serialize
+
+    val mailboxId2: String = mailboxProbe
+      .createMailbox(MailboxPath.forUser(BOB, "mailbox2"))
+      .serialize
+
+    val mailboxId3: String = mailboxProbe
+      .createMailbox(MailboxPath.forUser(BOB, "mailbox3"))
+      .serialize
+
+    val mailboxId4: String = mailboxProbe
+      .createMailbox(MailboxPath.forUser(BOB, "mailbox4"))
+      .serialize
+
+    val mailboxId5: String = mailboxProbe
+      .createMailbox(MailboxPath.forUser(BOB, "mailbox5"))
+      .serialize
+
+    val mailboxId6: String = mailboxProbe
+      .createMailbox(MailboxPath.forUser(BOB, "mailbox6"))
+      .serialize
+
+    val request =
+      s"""{
+         |  "using": ["urn:ietf:params:jmap:core", "urn:ietf:params:jmap:mail"],
+         |  "methodCalls": [[
+         |    "Mailbox/changes",
+         |    {
+         |      "accountId": "29883977c13473ae7cb7678ef767cbfbaffc8a44a6e463d971d23a65c1dc4af6",
+         |      "sinceState": "${oldState.getValue}"
+         |    },
+         |    "c1"]]
+         |}""".stripMargin
+
+    val response = `given`
+      .header(ACCEPT.toString, ACCEPT_RFC8621_VERSION_HEADER)
+      .body(request)
+    .when
+      .post
+    .`then`
+      .statusCode(SC_OK)
+      .contentType(JSON)
+      .extract
+      .body
+      .asString
+
+    assertThatJson(response)
+      .whenIgnoringPaths("methodResponses[0][1].newState")
+      .withOptions(new Options(IGNORING_ARRAY_ORDER))
+      .isEqualTo(
+        s"""{
+           |    "sessionState": "${SESSION_STATE.value}",
+           |    "methodResponses": [
+           |      [ "Mailbox/changes", {
+           |        "accountId": "29883977c13473ae7cb7678ef767cbfbaffc8a44a6e463d971d23a65c1dc4af6",
+           |        "oldState": "${oldState.getValue}",
+           |        "hasMoreChanges": true,
+           |        "updatedProperties": [],
+           |        "created": ["$mailboxId1", "$mailboxId2", "$mailboxId3", "$mailboxId4", "$mailboxId5"],
+           |        "updated": [],
+           |        "destroyed": []
+           |      }, "c1"]
+           |    ]
+           |}""".stripMargin)
+  }
+
+  @Test
+  def mailboxChangesShouldFailWhenAccountIdNotFound(server: GuiceJamesServer): Unit = {
+    val oldState: State = storeReferenceState(server)
+
+    val request =
+      s"""{
+         |  "using": ["urn:ietf:params:jmap:core", "urn:ietf:params:jmap:mail"],
+         |  "methodCalls": [[
+         |    "Mailbox/changes",
+         |    {
+         |      "accountId": "bad",
+         |      "sinceState": "${oldState.getValue}"
+         |    },
+         |    "c1"]]
+         |}""".stripMargin
+
+    val response =  `given`
+      .header(ACCEPT.toString, ACCEPT_RFC8621_VERSION_HEADER)
+      .body(request)
+    .when
+      .post
+    .`then`
+      .statusCode(SC_OK)
+      .contentType(JSON)
+      .extract
+      .body
+      .asString
+
+    assertThatJson(response)
+      .isEqualTo(
+        s"""{
+          |   "sessionState": "${SESSION_STATE.value}",
+          |   "methodResponses": [[
+          |     "error", {
+          |       "type": "accountNotFound"
+          |     }, "c1"]
+          |   ]
+          |}""".stripMargin)
+  }
+
+  @Test
+  def mailboxChangesShouldFailWhenStateNotFound(server: GuiceJamesServer): Unit = {
+    provisionSystemMailboxes(server)
+
+    val state: String = UUID.randomUUID().toString
+
+    val request =
+      s"""{
+         |  "using": ["urn:ietf:params:jmap:core", "urn:ietf:params:jmap:mail"],
+         |  "methodCalls": [[
+         |    "Mailbox/changes",
+         |    {
+         |      "accountId": "29883977c13473ae7cb7678ef767cbfbaffc8a44a6e463d971d23a65c1dc4af6",
+         |      "sinceState": "$state"
+         |    },
+         |    "c1"]]
+         |}""".stripMargin
+
+    val response = `given`
+      .header(ACCEPT.toString, ACCEPT_RFC8621_VERSION_HEADER)
+      .body(request)
+    .when
+      .post
+    .`then`
+      .statusCode(SC_OK)
+      .contentType(JSON)
+      .extract
+      .body
+      .asString
+
+    assertThatJson(response)
+      .whenIgnoringPaths("methodResponses[0][1].newState")
+      .withOptions(new Options(IGNORING_ARRAY_ORDER))
+      .isEqualTo(
+        s"""{
+           |  "sessionState": "${SESSION_STATE.value}",
+           |  "methodResponses": [[
+           |    "error", {
+           |      "type": "cannotCalculateChanges",
+           |      "description": "State '$state' could not be found"
+           |    }, "c1"]
+           |  ]
+           |}""".stripMargin)
+  }
+
+  @Test
+  def mailboxChangesShouldReturnNoChangesWhenNoNewerState(server: GuiceJamesServer): Unit = {
+    provisionSystemMailboxes(server)
+
+    val oldState: State = storeReferenceState(server)
+
+    val request =
+      s"""{
+         |  "using": ["urn:ietf:params:jmap:core", "urn:ietf:params:jmap:mail"],
+         |  "methodCalls": [[
+         |    "Mailbox/changes",
+         |    {
+         |      "accountId": "29883977c13473ae7cb7678ef767cbfbaffc8a44a6e463d971d23a65c1dc4af6",
+         |      "sinceState": "${oldState.getValue}"
+         |    },
+         |    "c1"]]
+         |}""".stripMargin
+
+    val response = `given`
+      .header(ACCEPT.toString, ACCEPT_RFC8621_VERSION_HEADER)
+      .body(request)
+    .when
+      .post
+    .`then`
+      .statusCode(SC_OK)
+      .contentType(JSON)
+      .extract
+      .body
+      .asString
+
+    assertThatJson(response)
+      .withOptions(new Options(IGNORING_ARRAY_ORDER))
+      .isEqualTo(
+        s"""{
+           |    "sessionState": "${SESSION_STATE.value}",
+           |    "methodResponses": [
+           |      [ "Mailbox/changes", {
+           |        "accountId": "29883977c13473ae7cb7678ef767cbfbaffc8a44a6e463d971d23a65c1dc4af6",
+           |        "oldState": "${oldState.getValue}",
+           |        "newState": "${oldState.getValue}",
+           |        "hasMoreChanges": false,
+           |        "updatedProperties": [],
+           |        "created": [],
+           |        "updated": [],
+           |        "destroyed": []
+           |      }, "c1"]
+           |    ]
+           |}""".stripMargin)
+  }
+
+  @Test
+  def mailboxChangesShouldReturnDifferentStateThanOldState(server: GuiceJamesServer): Unit = {
+    val mailboxProbe: MailboxProbeImpl = server.getProbe(classOf[MailboxProbeImpl])
+    provisionSystemMailboxes(server)
+
+    val oldState: State = storeReferenceState(server)
+    mailboxProbe.createMailbox(MailboxPath.forUser(BOB, "mailbox1"))
+    mailboxProbe.createMailbox(MailboxPath.forUser(BOB, "mailbox2"))
+
+    val request =
+      s"""{
+         |  "using": ["urn:ietf:params:jmap:core", "urn:ietf:params:jmap:mail"],
+         |  "methodCalls": [[
+         |    "Mailbox/changes",
+         |    {
+         |      "accountId": "29883977c13473ae7cb7678ef767cbfbaffc8a44a6e463d971d23a65c1dc4af6",
+         |      "sinceState": "${oldState.getValue}"
+         |    },
+         |    "c1"]]
+         |}""".stripMargin
+
+    val response = `given`
+      .header(ACCEPT.toString, ACCEPT_RFC8621_VERSION_HEADER)
+      .body(request)
+    .when
+      .post
+    .`then`
+      .statusCode(SC_OK)
+      .contentType(JSON)
+      .extract
+      .body
+      .asString
+
+    val newState = Json.parse(response)
+      .\("methodResponses")
+      .\(0).\(1)
+      .\("newState")
+      .get.asInstanceOf[JsString].value
+
+    assertThat(oldState.getValue.toString).isNotEqualTo(newState)
+  }
+
+  @Test
+  def mailboxChangesShouldEventuallyReturnNoChanges(server: GuiceJamesServer): Unit = {
+    val mailboxProbe: MailboxProbeImpl = server.getProbe(classOf[MailboxProbeImpl])
+    provisionSystemMailboxes(server)
+
+    val oldState: State = storeReferenceState(server)
+    mailboxProbe.createMailbox(MailboxPath.forUser(BOB, "mailbox1"))
+    mailboxProbe.createMailbox(MailboxPath.forUser(BOB, "mailbox2"))
+
+    val request1 =
+      s"""{
+         |  "using": ["urn:ietf:params:jmap:core", "urn:ietf:params:jmap:mail"],
+         |  "methodCalls": [[
+         |    "Mailbox/changes",
+         |    {
+         |      "accountId": "29883977c13473ae7cb7678ef767cbfbaffc8a44a6e463d971d23a65c1dc4af6",
+         |      "sinceState": "${oldState.getValue}"
+         |    },
+         |    "c1"]]
+         |}""".stripMargin
+
+    val response1 = `given`
+      .header(ACCEPT.toString, ACCEPT_RFC8621_VERSION_HEADER)
+      .body(request1)
+    .when
+      .post
+    .`then`
+      .statusCode(SC_OK)
+      .contentType(JSON)
+      .extract
+      .body
+      .asString
+
+    val newState = Json.parse(response1)
+      .\("methodResponses")
+      .\(0).\(1)
+      .\("newState")
+      .get.asInstanceOf[JsString].value
+
+    val request2 =
+      s"""{
+         |  "using": ["urn:ietf:params:jmap:core", "urn:ietf:params:jmap:mail"],
+         |  "methodCalls": [[
+         |    "Mailbox/changes",
+         |    {
+         |      "accountId": "29883977c13473ae7cb7678ef767cbfbaffc8a44a6e463d971d23a65c1dc4af6",
+         |      "sinceState": "$newState"
+         |    },
+         |    "c1"]]
+         |}""".stripMargin
+
+    val response2 = `given`
+      .header(ACCEPT.toString, ACCEPT_RFC8621_VERSION_HEADER)
+      .body(request2)
+    .when
+      .post
+    .`then`
+      .statusCode(SC_OK)
+      .contentType(JSON)
+      .extract
+      .body
+      .asString
+
+    assertThatJson(response2)
+      .withOptions(new Options(IGNORING_ARRAY_ORDER))
+      .isEqualTo(
+        s"""{
+           |    "sessionState": "${SESSION_STATE.value}",
+           |    "methodResponses": [
+           |      [ "Mailbox/changes", {
+           |        "accountId": "29883977c13473ae7cb7678ef767cbfbaffc8a44a6e463d971d23a65c1dc4af6",
+           |        "oldState": "$newState",
+           |        "newState": "$newState",
+           |        "hasMoreChanges": false,
+           |        "updatedProperties": [],
+           |        "created": [],
+           |        "updated": [],
+           |        "destroyed": []
+           |      }, "c1"]
+           |    ]
+           |}""".stripMargin)
+  }
+
+  private def renameMailbox(mailboxId: String, name: String): Unit = {
+    val request =
+      s"""
+         |{
+         |  "using": [ "urn:ietf:params:jmap:core", "urn:ietf:params:jmap:mail" ],
+         |  "methodCalls": [[
+         |    "Mailbox/set", {
+         |      "accountId": "29883977c13473ae7cb7678ef767cbfbaffc8a44a6e463d971d23a65c1dc4af6",
+         |      "update": {
+         |        "$mailboxId": {
+         |          "name": "$name"
+         |        }
+         |      }
+         |    }, "c1"]
+         |  ]
+         |}
+         |""".stripMargin
+
+    `given`
+      .header(ACCEPT.toString, ACCEPT_RFC8621_VERSION_HEADER)
+      .body(request)
+    .when
+      .post
+    .`then`
+      .log().ifValidationFails()
+      .statusCode(SC_OK)
+      .contentType(JSON)
+  }
+
+  private def storeReferenceState(server: GuiceJamesServer): State = {
+    val state: State = State.of(UUID.randomUUID())
+    val jmapGuiceProbe: JmapGuiceProbe = server.getProbe(classOf[JmapGuiceProbe])
+    jmapGuiceProbe.saveMailboxChange(MailboxChange.of(AccountId.fromUsername(BOB), state, ZonedDateTime.now(), List().asJava, List(TestId.of(0)).asJava, List().asJava))
+
+    state
+  }
+
+  private def provisionSystemMailboxes(server: GuiceJamesServer): Unit = {
+    val mailboxId: MailboxId = server.getProbe(classOf[MailboxProbeImpl]).createMailbox(MailboxPath.inbox(BOB))
+
+    val request =
+      s"""{
+         |  "using": ["urn:ietf:params:jmap:core", "urn:ietf:params:jmap:mail"],
+         |  "methodCalls": [[
+         |    "Mailbox/get",
+         |    {
+         |      "accountId": "29883977c13473ae7cb7678ef767cbfbaffc8a44a6e463d971d23a65c1dc4af6",
+         |      "ids": ["$mailboxId"]
+         |    },
+         |    "c1"]]
+         |}""".stripMargin
+
+    `given`
+      .header(ACCEPT.toString, ACCEPT_RFC8621_VERSION_HEADER)
+      .body(request)
+    .when
+      .post
+    .`then`
+      .statusCode(SC_OK)
+      .contentType(JSON)
+  }
+}
diff --git a/server/protocols/jmap-rfc-8621-integration-tests/memory-jmap-rfc-8621-integration-tests/src/test/java/org/apache/james/jmap/rfc8621/memory/MemoryMailboxChangesMethodTest.java b/server/protocols/jmap-rfc-8621-integration-tests/memory-jmap-rfc-8621-integration-tests/src/test/java/org/apache/james/jmap/rfc8621/memory/MemoryMailboxChangesMethodTest.java
index 9b8cd71..eadfa66 100644
--- a/server/protocols/jmap-rfc-8621-integration-tests/memory-jmap-rfc-8621-integration-tests/src/test/java/org/apache/james/jmap/rfc8621/memory/MemoryMailboxChangesMethodTest.java
+++ b/server/protocols/jmap-rfc-8621-integration-tests/memory-jmap-rfc-8621-integration-tests/src/test/java/org/apache/james/jmap/rfc8621/memory/MemoryMailboxChangesMethodTest.java
@@ -24,16 +24,15 @@ import static org.apache.james.MemoryJamesServerMain.IN_MEMORY_SERVER_AGGREGATE_
 import org.apache.james.GuiceJamesServer;
 import org.apache.james.JamesServerBuilder;
 import org.apache.james.JamesServerExtension;
-import org.apache.james.jmap.rfc8621.contract.EmailChangesContract;
-import org.apache.james.jmap.rfc8621.contract.MailboxChangesContract;
+import org.apache.james.jmap.rfc8621.contract.MailboxChangesMethodContract;
 import org.apache.james.modules.TestJMAPServerModule;
 import org.junit.jupiter.api.extension.RegisterExtension;
 
-public class MemoryMailboxChangesMethodTest implements MailboxChangesContract {
+public class MemoryMailboxChangesMethodTest implements MailboxChangesMethodContract {
     @RegisterExtension
     static JamesServerExtension testExtension = new JamesServerBuilder<>(JamesServerBuilder.defaultConfigurationProvider())
         .server(configuration -> GuiceJamesServer.forConfiguration(configuration)
             .combineWith(IN_MEMORY_SERVER_AGGREGATE_MODULE)
             .overrideWith(new TestJMAPServerModule()))
         .build();
-}
+}
\ No newline at end of file
diff --git a/server/protocols/jmap-rfc-8621-integration-tests/memory-jmap-rfc-8621-integration-tests/src/test/resources/listeners.xml b/server/protocols/jmap-rfc-8621-integration-tests/memory-jmap-rfc-8621-integration-tests/src/test/resources/listeners.xml
index a1a139d..af44f35 100644
--- a/server/protocols/jmap-rfc-8621-integration-tests/memory-jmap-rfc-8621-integration-tests/src/test/resources/listeners.xml
+++ b/server/protocols/jmap-rfc-8621-integration-tests/memory-jmap-rfc-8621-integration-tests/src/test/resources/listeners.xml
@@ -47,4 +47,7 @@
     <class>org.apache.james.jmap.event.PopulateEmailQueryViewListener</class>
     <async>true</async>
   </listener>
+  <listener>
+    <class>org.apache.james.jmap.change.MailboxChangeListener</class>
+  </listener>
 </listeners>
\ No newline at end of file
diff --git a/server/protocols/jmap-rfc-8621/src/main/scala/org/apache/james/jmap/core/ResponseObject.scala b/server/protocols/jmap-rfc-8621/src/main/scala/org/apache/james/jmap/core/ResponseObject.scala
index ec05f82..634594a 100644
--- a/server/protocols/jmap-rfc-8621/src/main/scala/org/apache/james/jmap/core/ResponseObject.scala
+++ b/server/protocols/jmap-rfc-8621/src/main/scala/org/apache/james/jmap/core/ResponseObject.scala
@@ -19,6 +19,8 @@
 
 package org.apache.james.jmap.core
 
+import eu.timepit.refined.auto._
+
 case class ResponseObject(sessionState: State, methodResponses: Seq[Invocation])
 
 object ResponseObject {
diff --git a/server/protocols/jmap-rfc-8621/src/main/scala/org/apache/james/jmap/core/Session.scala b/server/protocols/jmap-rfc-8621/src/main/scala/org/apache/james/jmap/core/Session.scala
index 2189de3..123aa3d 100644
--- a/server/protocols/jmap-rfc-8621/src/main/scala/org/apache/james/jmap/core/Session.scala
+++ b/server/protocols/jmap-rfc-8621/src/main/scala/org/apache/james/jmap/core/Session.scala
@@ -24,8 +24,12 @@ import java.nio.charset.StandardCharsets
 import java.util.UUID
 
 import com.google.common.hash.Hashing
+import eu.timepit.refined.api.Refined
+import eu.timepit.refined.auto._
 import eu.timepit.refined.refineV
+import eu.timepit.refined.string.Uuid
 import org.apache.james.core.Username
+import org.apache.james.jmap.api.change.MailboxChanges
 import org.apache.james.jmap.core.CapabilityIdentifier.CapabilityIdentifier
 import org.apache.james.jmap.core.Id.Id
 import org.apache.james.jmap.core.State.INSTANCE
@@ -73,9 +77,13 @@ final case class Account private(accountId: AccountId,
                                  accountCapabilities: Set[_ <: Capability])
 
 object State {
+  type UUIDString = String Refined Uuid
+
   val INSTANCE: State = fromString("2c9f1b12-b35a-43e6-9af2-0106fb53a943")
 
-  def fromString(value: String): State = State(UUID.fromString(value))
+  def fromString(value: UUIDString): State = State(UUID.fromString(value.value))
+
+  def fromMailboxChanges(mailboxChanges: MailboxChanges): State = State(mailboxChanges.getNewState.getValue)
 }
 
 case class State(value: UUID)
diff --git a/server/protocols/jmap-rfc-8621/src/main/scala/org/apache/james/jmap/json/EmailGetSerializer.scala b/server/protocols/jmap-rfc-8621/src/main/scala/org/apache/james/jmap/json/EmailGetSerializer.scala
index a0062a1..edc3392 100644
--- a/server/protocols/jmap-rfc-8621/src/main/scala/org/apache/james/jmap/json/EmailGetSerializer.scala
+++ b/server/protocols/jmap-rfc-8621/src/main/scala/org/apache/james/jmap/json/EmailGetSerializer.scala
@@ -110,6 +110,7 @@ object EmailGetSerializer {
   private implicit val bodyValueWrites: Writes[EmailBodyValue] = Json.writes[EmailBodyValue]
   private implicit val emailIdsReads: Reads[EmailIds] = Json.valueReads[EmailIds]
   private implicit val emailGetRequestReads: Reads[EmailGetRequest] = Json.reads[EmailGetRequest]
+
   private implicit val emailChangesRequestReads: Reads[EmailChangesRequest] = Json.reads[EmailChangesRequest]
   private implicit val subjectWrites: Writes[Subject] = Json.valueWrites[Subject]
   private implicit val emailNotFoundWrites: Writes[EmailNotFound] = Json.valueWrites[EmailNotFound]
diff --git a/server/protocols/jmap-rfc-8621/src/main/scala/org/apache/james/jmap/json/MailboxSerializer.scala b/server/protocols/jmap-rfc-8621/src/main/scala/org/apache/james/jmap/json/MailboxSerializer.scala
index 0064179..f85c08e 100644
--- a/server/protocols/jmap-rfc-8621/src/main/scala/org/apache/james/jmap/json/MailboxSerializer.scala
+++ b/server/protocols/jmap-rfc-8621/src/main/scala/org/apache/james/jmap/json/MailboxSerializer.scala
@@ -19,12 +19,11 @@
 
 package org.apache.james.jmap.json
 
-import java.util.UUID
-
 import eu.timepit.refined._
 import eu.timepit.refined.collection.NonEmpty
 import javax.inject.Inject
 import org.apache.james.core.{Domain, Username}
+import org.apache.james.jmap.api.change.MailboxChange.Limit
 import org.apache.james.jmap.core.CapabilityIdentifier.CapabilityIdentifier
 import org.apache.james.jmap.core.{ClientId, Properties, SetError, State}
 import org.apache.james.jmap.mail.MailboxGet.{UnparsedMailboxId, UnparsedMailboxIdConstraint}
@@ -114,6 +113,13 @@ class MailboxSerializer @Inject()(mailboxIdFactory: MailboxId.Factory) {
   private implicit val idsRead: Reads[Ids] = Json.valueReads[Ids]
 
   private implicit val mailboxGetRequest: Reads[MailboxGetRequest] = Json.reads[MailboxGetRequest]
+
+  private implicit val limitReads: Reads[Limit] = {
+    case JsNumber(underlying) if underlying > 0 => JsSuccess(Limit.of(underlying.intValue))
+    case JsNumber(underlying) if underlying <= 0 => JsError("Expecting a positive integer as Limit")
+    case _ => JsError("Expecting a number as Limit")
+  }
+
   private implicit val mailboxChangesRequest: Reads[MailboxChangesRequest] = Json.reads[MailboxChangesRequest]
 
   private implicit val mailboxRemoveEmailsOnDestroy: Reads[RemoveEmailsOnDestroy] = Json.valueFormat[RemoveEmailsOnDestroy]
@@ -126,10 +132,6 @@ class MailboxSerializer @Inject()(mailboxIdFactory: MailboxId.Factory) {
   private implicit val mapCreationRequestByMailBoxCreationId: Reads[Map[MailboxCreationId, JsObject]] =
     Reads.mapReads[MailboxCreationId, JsObject] {string => refineV[NonEmpty](string).fold(JsError(_), id => JsSuccess(id)) }
 
-  private implicit val stateReads: Reads[State] = {
-    case JsString(underlying) => Try(UUID.fromString(underlying))
-      .fold(e => JsError(e.getMessage), value => JsSuccess(State(value)))
-  }
   private implicit val mailboxSetRequestReads: Reads[MailboxSetRequest] = Json.reads[MailboxSetRequest]
 
   private implicit val notFoundWrites: Writes[NotFound] = Json.valueWrites[NotFound]
@@ -188,10 +190,10 @@ class MailboxSerializer @Inject()(mailboxIdFactory: MailboxId.Factory) {
 
   def deserializeMailboxGetRequest(input: String): JsResult[MailboxGetRequest] = Json.parse(input).validate[MailboxGetRequest]
 
-  def deserializeMailboxGetRequest(input: JsValue): JsResult[MailboxGetRequest] = Json.fromJson[MailboxGetRequest](input)
-
   def deserializeMailboxChangesRequest(input: JsValue): JsResult[MailboxChangesRequest] = Json.fromJson[MailboxChangesRequest](input)
 
+  def deserializeMailboxGetRequest(input: JsValue): JsResult[MailboxGetRequest] = Json.fromJson[MailboxGetRequest](input)
+
   def deserializeMailboxSetRequest(input: JsValue): JsResult[MailboxSetRequest] = Json.fromJson[MailboxSetRequest](input)
 
   def deserializeRights(input: JsValue): JsResult[Rights] = Json.fromJson[Rights](input)
diff --git a/server/protocols/jmap-rfc-8621/src/main/scala/org/apache/james/jmap/json/ResponseSerializer.scala b/server/protocols/jmap-rfc-8621/src/main/scala/org/apache/james/jmap/json/ResponseSerializer.scala
index b75aca5..8bdbe4a 100644
--- a/server/protocols/jmap-rfc-8621/src/main/scala/org/apache/james/jmap/json/ResponseSerializer.scala
+++ b/server/protocols/jmap-rfc-8621/src/main/scala/org/apache/james/jmap/json/ResponseSerializer.scala
@@ -21,7 +21,6 @@ package org.apache.james.jmap.json
 
 import java.io.InputStream
 import java.net.URL
-import java.util.UUID
 
 import eu.timepit.refined.refineV
 import io.netty.handler.codec.http.HttpResponseStatus
@@ -37,7 +36,6 @@ import play.api.libs.json._
 
 import scala.collection.{Seq => LegacySeq}
 import scala.language.implicitConversions
-import scala.util.Try
 
 object ResponseSerializer {
   // CreateIds
@@ -68,10 +66,6 @@ object ResponseSerializer {
   // RequestObject
   private implicit val requestObjectRead: Format[RequestObject] = Json.format[RequestObject]
 
-  private implicit val stateReads: Reads[State] = {
-    case JsString(underlying) => Try(UUID.fromString(underlying))
-      .fold(e => JsError(e.getMessage), value => JsSuccess(State(value)))
-  }
   private implicit val stateWrites: Writes[State] = Json.valueWrites[State]
   // ResponseObject
   private implicit val responseObjectFormat: Format[ResponseObject] = Json.format[ResponseObject]
diff --git a/server/protocols/jmap-rfc-8621/src/main/scala/org/apache/james/jmap/json/ThreadSerializer.scala b/server/protocols/jmap-rfc-8621/src/main/scala/org/apache/james/jmap/json/ThreadSerializer.scala
index 235a817..4e4622d 100644
--- a/server/protocols/jmap-rfc-8621/src/main/scala/org/apache/james/jmap/json/ThreadSerializer.scala
+++ b/server/protocols/jmap-rfc-8621/src/main/scala/org/apache/james/jmap/json/ThreadSerializer.scala
@@ -19,8 +19,9 @@
 
 package org.apache.james.jmap.json
 
+import org.apache.james.jmap.core.State
 import org.apache.james.jmap.mail.{Thread, ThreadChangesRequest, ThreadChangesResponse, ThreadGetRequest, ThreadGetResponse}
-import play.api.libs.json.{JsObject, JsResult, JsValue, Json, OWrites, Reads}
+import play.api.libs.json.{JsObject, JsResult, JsValue, Json, OWrites, Reads, Writes}
 
 import scala.language.implicitConversions
 
@@ -28,6 +29,7 @@ object ThreadSerializer {
   private implicit val threadGetReads: Reads[ThreadGetRequest] = Json.reads[ThreadGetRequest]
   private implicit val threadChangesReads: Reads[ThreadChangesRequest] = Json.reads[ThreadChangesRequest]
   private implicit val threadWrites: OWrites[Thread] = Json.writes[Thread]
+  private implicit val stateWrites: Writes[State] = Json.valueWrites[State]
   private implicit val threadGetWrites: OWrites[ThreadGetResponse] = Json.writes[ThreadGetResponse]
   private implicit val changesResponseWrites: OWrites[ThreadChangesResponse] = Json.writes[ThreadChangesResponse]
 
diff --git a/server/protocols/jmap-rfc-8621/src/main/scala/org/apache/james/jmap/json/package.scala b/server/protocols/jmap-rfc-8621/src/main/scala/org/apache/james/jmap/json/package.scala
index 3a8d44f..e3160cf 100644
--- a/server/protocols/jmap-rfc-8621/src/main/scala/org/apache/james/jmap/json/package.scala
+++ b/server/protocols/jmap-rfc-8621/src/main/scala/org/apache/james/jmap/json/package.scala
@@ -25,7 +25,7 @@ import java.time.format.DateTimeFormatter
 import eu.timepit.refined.api.{RefType, Validate}
 import org.apache.james.core.MailAddress
 import org.apache.james.jmap.core.SetError.SetErrorDescription
-import org.apache.james.jmap.core.{AccountId, Properties, SetError, UTCDate}
+import org.apache.james.jmap.core.{AccountId, Properties, SetError, State, UTCDate}
 import org.apache.james.jmap.mail.HasMoreChanges
 import play.api.libs.json._
 
@@ -79,6 +79,8 @@ package object json {
       }
     case _ => JsError("Expecting js string to represent UTC Date")
   }
+
+  private[json] implicit val stateReads: Reads[State] = Json.valueReads[State]
   private[json] implicit val accountIdWrites: Format[AccountId] = Json.valueFormat[AccountId]
   private[json] implicit val propertiesFormat: Format[Properties] = Json.valueFormat[Properties]
   private[json] implicit val setErrorDescriptionWrites: Writes[SetErrorDescription] = Json.valueWrites[SetErrorDescription]
diff --git a/server/protocols/jmap-rfc-8621/src/main/scala/org/apache/james/jmap/mail/MailboxGet.scala b/server/protocols/jmap-rfc-8621/src/main/scala/org/apache/james/jmap/mail/MailboxGet.scala
index 3e10abe..add1c6e 100644
--- a/server/protocols/jmap-rfc-8621/src/main/scala/org/apache/james/jmap/mail/MailboxGet.scala
+++ b/server/protocols/jmap-rfc-8621/src/main/scala/org/apache/james/jmap/mail/MailboxGet.scala
@@ -22,8 +22,8 @@ package org.apache.james.jmap.mail
 import eu.timepit.refined
 import eu.timepit.refined.api.Refined
 import eu.timepit.refined.collection.NonEmpty
-import org.apache.james.jmap.core.Id.Id
-import org.apache.james.jmap.core.UnsignedInt.UnsignedInt
+import org.apache.james.jmap.api.change.MailboxChange.Limit
+import org.apache.james.jmap.api.change.MailboxChanges
 import org.apache.james.jmap.core.{AccountId, Properties, State}
 import org.apache.james.jmap.mail.MailboxGet.UnparsedMailboxId
 import org.apache.james.jmap.method.WithAccountId
@@ -66,15 +66,21 @@ case class MailboxGetResponse(accountId: AccountId,
                               list: List[Mailbox],
                               notFound: NotFound)
 
+object HasMoreChanges {
+  def fromMailboxChanges(mailboxChanges: MailboxChanges): HasMoreChanges = HasMoreChanges(mailboxChanges.hasMoreChanges)
+}
+
+case class HasMoreChanges(value: Boolean) extends AnyVal
+
 case class MailboxChangesRequest(accountId: AccountId,
-                                sinceState: State,
-                                maxChanged: Option[UnsignedInt]) extends WithAccountId
+                                 sinceState: State,
+                                 maxChanged: Option[Limit]) extends WithAccountId
 
 case class MailboxChangesResponse(accountId: AccountId,
                                   oldState: State,
                                   newState: State,
                                   hasMoreChanges: HasMoreChanges,
                                   updatedProperties: Option[Properties],
-                                  created: List[Id],
-                                  updated: List[Id],
-                                  destroyed: List[Id])
\ No newline at end of file
+                                  created: Set[MailboxId],
+                                  updated: Set[MailboxId],
+                                  destroyed: Set[MailboxId])
diff --git a/server/protocols/jmap-rfc-8621/src/main/scala/org/apache/james/jmap/mail/Thread.scala b/server/protocols/jmap-rfc-8621/src/main/scala/org/apache/james/jmap/mail/Thread.scala
index b85954c..a51e16c 100644
--- a/server/protocols/jmap-rfc-8621/src/main/scala/org/apache/james/jmap/mail/Thread.scala
+++ b/server/protocols/jmap-rfc-8621/src/main/scala/org/apache/james/jmap/mail/Thread.scala
@@ -19,10 +19,9 @@
 
 package org.apache.james.jmap.mail
 
-import org.apache.james.jmap.core.AccountId
 import org.apache.james.jmap.core.Id.Id
-import org.apache.james.jmap.core.State.State
 import org.apache.james.jmap.core.UnsignedInt.UnsignedInt
+import org.apache.james.jmap.core.{AccountId, State}
 import org.apache.james.jmap.method.WithAccountId
 
 case class Thread(id: Id, emailIds: List[Id])
@@ -38,8 +37,6 @@ case class ThreadChangesRequest(accountId: AccountId,
                                 sinceState: State,
                                 maxChanged: Option[UnsignedInt]) extends WithAccountId
 
-case class HasMoreChanges(value: Boolean) extends AnyVal
-
 case class ThreadChangesResponse(accountId: AccountId,
                                  oldState: State,
                                  newState: State,
diff --git a/server/protocols/jmap-rfc-8621/src/main/scala/org/apache/james/jmap/method/MailboxChangesMethod.scala b/server/protocols/jmap-rfc-8621/src/main/scala/org/apache/james/jmap/method/MailboxChangesMethod.scala
index 09b5ccb..438704e 100644
--- a/server/protocols/jmap-rfc-8621/src/main/scala/org/apache/james/jmap/method/MailboxChangesMethod.scala
+++ b/server/protocols/jmap-rfc-8621/src/main/scala/org/apache/james/jmap/method/MailboxChangesMethod.scala
@@ -21,9 +21,12 @@ package org.apache.james.jmap.method
 
 import eu.timepit.refined.auto._
 import javax.inject.Inject
+import org.apache.james.jmap.api.change.MailboxChange.{State => JavaState}
+import org.apache.james.jmap.api.change.MailboxChangeRepository
+import org.apache.james.jmap.api.model.{AccountId => JavaAccountId}
 import org.apache.james.jmap.core.CapabilityIdentifier.{CapabilityIdentifier, JMAP_MAIL}
 import org.apache.james.jmap.core.Invocation.{Arguments, MethodName}
-import org.apache.james.jmap.core.{ErrorCode, Invocation, Properties, State}
+import org.apache.james.jmap.core.{Invocation, Properties, State}
 import org.apache.james.jmap.json.{MailboxSerializer, ResponseSerializer}
 import org.apache.james.jmap.mail.{HasMoreChanges, MailboxChangesRequest, MailboxChangesResponse}
 import org.apache.james.jmap.routes.SessionSupplier
@@ -32,13 +35,19 @@ import org.apache.james.metrics.api.MetricFactory
 import play.api.libs.json.{JsError, JsSuccess}
 import reactor.core.scala.publisher.SMono
 
+import scala.jdk.CollectionConverters._
+import scala.jdk.OptionConverters._
+
 class MailboxChangesMethod @Inject()(mailboxSerializer: MailboxSerializer,
-                                   val metricFactory: MetricFactory,
-                                   val sessionSupplier: SessionSupplier) extends MethodRequiringAccountId[MailboxChangesRequest] {
+                                     val metricFactory: MetricFactory,
+                                     val sessionSupplier: SessionSupplier,
+                                     val mailboxChangeRepository: MailboxChangeRepository) extends MethodRequiringAccountId[MailboxChangesRequest] {
   override val methodName: MethodName = MethodName("Mailbox/changes")
   override val requiredCapabilities: Set[CapabilityIdentifier] = Set(JMAP_MAIL)
 
   override def doProcess(capabilities: Set[CapabilityIdentifier], invocation: InvocationWithContext, mailboxSession: MailboxSession, request: MailboxChangesRequest): SMono[InvocationWithContext] =
+
+    // Support for LTT.RS. This should be removed as soon as Mailbox/get returns the correct state
     if (request.sinceState.equals(State.INSTANCE)) {
       val response: MailboxChangesResponse = MailboxChangesResponse(
         accountId = request.accountId,
@@ -46,19 +55,31 @@ class MailboxChangesMethod @Inject()(mailboxSerializer: MailboxSerializer,
         newState = State.INSTANCE,
         hasMoreChanges = HasMoreChanges(false),
         updatedProperties = Some(Properties()),
-        created = List(),
-        updated = List(),
-        destroyed = List())
+        created = Set(),
+        updated = Set(),
+        destroyed = Set())
       SMono.just(InvocationWithContext(invocation = Invocation(
         methodName = methodName,
         arguments = Arguments(mailboxSerializer.serializeChanges(response)),
         methodCallId = invocation.invocation.methodCallId
       ), processingContext = invocation.processingContext))
     } else {
-      SMono.just(InvocationWithContext(invocation = Invocation.error(ErrorCode.CannotCalculateChanges,
-        "Naive implementation for Mailbox/changes",
-        invocation.invocation.methodCallId),
-        processingContext = invocation.processingContext))
+      SMono.fromPublisher(mailboxChangeRepository.getSinceState(JavaAccountId.fromUsername(mailboxSession.getUser), JavaState.of(request.sinceState.value), request.maxChanged.toJava))
+        .map(mailboxChanges => MailboxChangesResponse(
+          accountId = request.accountId,
+          oldState = request.sinceState,
+          newState = State.fromMailboxChanges(mailboxChanges),
+          hasMoreChanges = HasMoreChanges.fromMailboxChanges(mailboxChanges),
+          updatedProperties = Some(Properties()),
+          created = mailboxChanges.getCreated.asScala.toSet,
+          updated = mailboxChanges.getUpdated.asScala.toSet,
+          destroyed = mailboxChanges.getDestroyed.asScala.toSet))
+        .map(response => InvocationWithContext(
+          invocation = Invocation(
+            methodName = methodName,
+            arguments = Arguments(mailboxSerializer.serializeChanges(response)),
+            methodCallId = invocation.invocation.methodCallId),
+          processingContext = invocation.processingContext))
     }
 
   override def getRequest(mailboxSession: MailboxSession, invocation: Invocation): Either[IllegalArgumentException, MailboxChangesRequest] =
diff --git a/server/protocols/jmap-rfc-8621/src/main/scala/org/apache/james/jmap/method/Method.scala b/server/protocols/jmap-rfc-8621/src/main/scala/org/apache/james/jmap/method/Method.scala
index c2663a4..a4acfe1 100644
--- a/server/protocols/jmap-rfc-8621/src/main/scala/org/apache/james/jmap/method/Method.scala
+++ b/server/protocols/jmap-rfc-8621/src/main/scala/org/apache/james/jmap/method/Method.scala
@@ -18,6 +18,7 @@
  ****************************************************************/
 package org.apache.james.jmap.method
 
+import org.apache.james.jmap.api.exception.ChangeNotFoundException
 import org.apache.james.jmap.core.CapabilityIdentifier.CapabilityIdentifier
 import org.apache.james.jmap.core.Invocation.MethodName
 import org.apache.james.jmap.core.{AccountId, ErrorCode, Invocation, Session}
@@ -27,7 +28,7 @@ import org.apache.james.mailbox.MailboxSession
 import org.apache.james.mailbox.exception.MailboxNotFoundException
 import org.apache.james.metrics.api.MetricFactory
 import org.reactivestreams.Publisher
-import reactor.core.scala.publisher.{SFlux, SMono}
+import reactor.core.scala.publisher.SFlux
 
 case class AccountNotFoundException(invocation: Invocation) extends IllegalArgumentException
 
@@ -81,6 +82,7 @@ trait MethodRequiringAccountId[REQUEST <: WithAccountId] extends Method {
           invocation.invocation.methodCallId), invocation.processingContext))
         case e: IllegalArgumentException => SFlux.just[InvocationWithContext] (InvocationWithContext(Invocation.error(ErrorCode.InvalidArguments, e.getMessage, invocation.invocation.methodCallId), invocation.processingContext))
         case e: MailboxNotFoundException => SFlux.just[InvocationWithContext] (InvocationWithContext(Invocation.error(ErrorCode.InvalidArguments, e.getMessage, invocation.invocation.methodCallId), invocation.processingContext))
+        case e: ChangeNotFoundException => SFlux.just[InvocationWithContext] (InvocationWithContext(Invocation.error(ErrorCode.CannotCalculateChanges, e.getMessage, invocation.invocation.methodCallId), invocation.processingContext))
         case e: Throwable => SFlux.raiseError[InvocationWithContext] (e)
       }
 


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