You are viewing a plain text version of this content. The canonical link for it is here.
Posted to server-dev@james.apache.org by bt...@apache.org on 2019/05/23 03:37:49 UTC

[james-project] 01/14: JAMES-2764 Copy of mailbox-elasticsearch module to a new mailbox-elasticsearch-v6 module

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 861b27ee70b0d79ccdcb8415dcc9715d1d60ba27
Author: Rene Cordier <rc...@linagora.com>
AuthorDate: Thu May 16 15:45:03 2019 +0700

    JAMES-2764 Copy of mailbox-elasticsearch module to a new mailbox-elasticsearch-v6 module
---
 mailbox/elasticsearch-v6/pom.xml                   |  203 ++++
 .../v6/ElasticSearchMailboxConfiguration.java      |  213 ++++
 .../mailbox/elasticsearch/v6/IndexAttachments.java |   24 +
 .../v6/MailboxElasticSearchConstants.java          |   37 +
 .../elasticsearch/v6/MailboxIndexCreationUtil.java |   56 +
 .../elasticsearch/v6/MailboxMappingFactory.java    |  365 ++++++
 .../ElasticSearchListeningMessageSearchIndex.java  |  196 +++
 .../mailbox/elasticsearch/v6/json/EMailer.java     |   75 ++
 .../mailbox/elasticsearch/v6/json/EMailers.java    |   52 +
 .../elasticsearch/v6/json/HeaderCollection.java    |  224 ++++
 .../elasticsearch/v6/json/IndexableMessage.java    |  471 ++++++++
 .../v6/json/JsonMessageConstants.java              |   83 ++
 .../v6/json/MessageToElasticSearchJson.java        |   86 ++
 .../elasticsearch/v6/json/MessageUpdateJson.java   |   79 ++
 .../mailbox/elasticsearch/v6/json/MimePart.java    |  303 +++++
 .../v6/json/MimePartContainerBuilder.java          |   50 +
 .../elasticsearch/v6/json/MimePartParser.java      |  129 ++
 .../v6/json/RootMimePartContainerBuilder.java      |   96 ++
 .../elasticsearch/v6/json/Serializable.java        |   25 +
 .../mailbox/elasticsearch/v6/json/Subjects.java    |   50 +
 .../elasticsearch/v6/query/CriterionConverter.java |  310 +++++
 .../v6/query/DateResolutionFormater.java           |   73 ++
 .../elasticsearch/v6/query/QueryConverter.java     |   79 ++
 .../elasticsearch/v6/query/SortConverter.java      |   81 ++
 .../v6/search/ElasticSearchSearcher.java           |  138 +++
 .../elasticsearch-v6/src/reporting-site/site.xml   |   29 +
 .../v6/ElasticSearchIntegrationTest.java           |  223 ++++
 .../v6/ElasticSearchMailboxConfigurationTest.java  |  219 ++++
 ...asticSearchListeningMessageSearchIndexTest.java |  269 +++++
 .../elasticsearch/v6/json/EMailersTest.java        |   66 +
 .../mailbox/elasticsearch/v6/json/FieldImpl.java   |   65 +
 .../v6/json/HeaderCollectionTest.java              |  334 +++++
 .../v6/json/IndexableMessageTest.java              |  578 +++++++++
 .../v6/json/MessageToElasticSearchJsonTest.java    |  388 ++++++
 .../elasticsearch/v6/json/MimePartTest.java        |   50 +
 .../elasticsearch/v6/json/SubjectsTest.java        |   66 +
 .../v6/query/DateResolutionFormaterTest.java       |   99 ++
 .../elasticsearch/v6/query/SearchQueryTest.java    |   77 ++
 .../src/test/resources/eml/bodyMakeTikaToFail.eml  | 1272 ++++++++++++++++++++
 .../test/resources/eml/emailWith3Attachments.eml   |   50 +
 .../src/test/resources/eml/mailWithHeaders.eml     |   14 +
 .../src/test/resources/logback-test.xml            |   24 +
 mailbox/pom.xml                                    |    1 +
 43 files changed, 7322 insertions(+)

diff --git a/mailbox/elasticsearch-v6/pom.xml b/mailbox/elasticsearch-v6/pom.xml
new file mode 100644
index 0000000..6bf0500
--- /dev/null
+++ b/mailbox/elasticsearch-v6/pom.xml
@@ -0,0 +1,203 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!--
+    Licensed to the Apache Software Foundation (ASF) under one
+    or more contributor license agreements. See the NOTICE file
+    distributed with this work for additional information
+    regarding copyright ownership. The ASF licenses this file
+    to you under the Apache License, Version 2.0 (the
+    "License"); you may not use this file except in compliance
+    with the License. You may obtain a copy of the License at
+
+    http://www.apache.org/licenses/LICENSE-2.0
+
+    Unless required by applicable law or agreed to in writing,
+    software distributed under the License is distributed on an
+    "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+    KIND, either express or implied. See the License for the
+    specific language governing permissions and limitations
+    under the License.
+-->
+<project xmlns="http://maven.apache.org/POM/4.0.0"
+         xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
+         xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
+    <modelVersion>4.0.0</modelVersion>
+
+    <parent>
+        <groupId>org.apache.james</groupId>
+        <artifactId>apache-james-mailbox</artifactId>
+        <version>3.4.0-SNAPSHOT</version>
+        <relativePath>../pom.xml</relativePath>
+    </parent>
+
+    <artifactId>apache-james-mailbox-elasticsearch-v6</artifactId>
+    <name>Apache James :: Mailbox :: ElasticSearch :: v6</name>
+    <description>Apache James Mailbox IMAP search implementation using ElasticSearch v6</description>
+
+    <dependencies>
+        <dependency>
+            <groupId>${james.groupId}</groupId>
+            <artifactId>apache-james-backends-es</artifactId>
+        </dependency>
+        <dependency>
+            <groupId>${james.groupId}</groupId>
+            <artifactId>apache-james-backends-es</artifactId>
+            <type>test-jar</type>
+            <scope>test</scope>
+        </dependency>
+        <dependency>
+            <groupId>${james.groupId}</groupId>
+            <artifactId>apache-james-mailbox-api</artifactId>
+        </dependency>
+        <dependency>
+            <groupId>${james.groupId}</groupId>
+            <artifactId>apache-james-mailbox-api</artifactId>
+            <type>test-jar</type>
+            <scope>test</scope>
+        </dependency>
+        <dependency>
+            <groupId>${james.groupId}</groupId>
+            <artifactId>apache-james-mailbox-event-memory</artifactId>
+            <scope>test</scope>
+        </dependency>
+        <dependency>
+            <groupId>${james.groupId}</groupId>
+            <artifactId>apache-james-mailbox-memory</artifactId>
+            <scope>test</scope>
+        </dependency>
+        <dependency>
+            <groupId>${james.groupId}</groupId>
+            <artifactId>apache-james-mailbox-memory</artifactId>
+            <scope>test</scope>
+            <type>test-jar</type>
+        </dependency>
+        <dependency>
+            <groupId>${james.groupId}</groupId>
+            <artifactId>apache-james-mailbox-store</artifactId>
+        </dependency>
+        <dependency>
+            <groupId>${james.groupId}</groupId>
+            <artifactId>apache-james-mailbox-store</artifactId>
+            <type>test-jar</type>
+            <scope>test</scope>
+        </dependency>
+        <dependency>
+            <groupId>${james.groupId}</groupId>
+            <artifactId>apache-james-mailbox-tika</artifactId>
+            <scope>test</scope>
+        </dependency>
+        <dependency>
+            <groupId>${james.groupId}</groupId>
+            <artifactId>apache-james-mailbox-tika</artifactId>
+            <type>test-jar</type>
+            <scope>test</scope>
+        </dependency>
+        <dependency>
+            <groupId>${james.groupId}</groupId>
+            <artifactId>james-server-util</artifactId>
+            <type>test-jar</type>
+            <scope>test</scope>
+        </dependency>
+        <dependency>
+            <groupId>org.apache.james</groupId>
+            <artifactId>james-server-testing</artifactId>
+            <scope>test</scope>
+        </dependency>
+        <dependency>
+            <groupId>ch.qos.logback</groupId>
+            <artifactId>logback-classic</artifactId>
+            <scope>test</scope>
+        </dependency>
+        <dependency>
+            <groupId>com.fasterxml.jackson.core</groupId>
+            <artifactId>jackson-databind</artifactId>
+        </dependency>
+        <dependency>
+            <groupId>com.fasterxml.jackson.datatype</groupId>
+            <artifactId>jackson-datatype-guava</artifactId>
+        </dependency>
+        <dependency>
+            <groupId>com.fasterxml.jackson.datatype</groupId>
+            <artifactId>jackson-datatype-jdk8</artifactId>
+        </dependency>
+        <dependency>
+            <groupId>com.github.steveash.guavate</groupId>
+            <artifactId>guavate</artifactId>
+        </dependency>
+        <dependency>
+            <groupId>com.google.guava</groupId>
+            <artifactId>guava</artifactId>
+        </dependency>
+        <dependency>
+            <groupId>com.jayway.awaitility</groupId>
+            <artifactId>awaitility</artifactId>
+            <scope>test</scope>
+        </dependency>
+        <dependency>
+            <groupId>com.sun.mail</groupId>
+            <artifactId>javax.mail</artifactId>
+        </dependency>
+        <dependency>
+            <groupId>javax.inject</groupId>
+            <artifactId>javax.inject</artifactId>
+        </dependency>
+        <dependency>
+            <groupId>junit</groupId>
+            <artifactId>junit</artifactId>
+            <scope>test</scope>
+        </dependency>
+        <dependency>
+            <groupId>net.javacrumbs.json-unit</groupId>
+            <artifactId>json-unit-assertj</artifactId>
+            <scope>test</scope>
+        </dependency>
+        <dependency>
+            <groupId>org.assertj</groupId>
+            <artifactId>assertj-core</artifactId>
+            <scope>test</scope>
+        </dependency>
+        <dependency>
+            <groupId>org.elasticsearch</groupId>
+            <artifactId>elasticsearch</artifactId>
+            <version>2.2.1</version>
+        </dependency>
+        <dependency>
+            <groupId>org.elasticsearch</groupId>
+            <artifactId>elasticsearch</artifactId>
+            <version>2.2.1</version>
+            <type>test-jar</type>
+            <scope>test</scope>
+        </dependency>
+        <dependency>
+            <groupId>org.junit.jupiter</groupId>
+            <artifactId>junit-jupiter-params</artifactId>
+            <scope>test</scope>
+        </dependency>
+        <dependency>
+            <groupId>org.mockito</groupId>
+            <artifactId>mockito-core</artifactId>
+            <scope>test</scope>
+        </dependency>
+        <dependency>
+            <groupId>org.slf4j</groupId>
+            <artifactId>slf4j-api</artifactId>
+        </dependency>
+        <dependency>
+            <groupId>org.testcontainers</groupId>
+            <artifactId>testcontainers</artifactId>
+            <scope>test</scope>
+        </dependency>
+    </dependencies>
+
+    <build>
+        <plugins>
+            <plugin>
+                <groupId>org.apache.maven.plugins</groupId>
+                <artifactId>maven-surefire-plugin</artifactId>
+                <configuration>
+                    <reuseForks>true</reuseForks>
+                </configuration>
+            </plugin>
+        </plugins>
+    </build>
+
+</project>
\ No newline at end of file
diff --git a/mailbox/elasticsearch-v6/src/main/java/org/apache/james/mailbox/elasticsearch/v6/ElasticSearchMailboxConfiguration.java b/mailbox/elasticsearch-v6/src/main/java/org/apache/james/mailbox/elasticsearch/v6/ElasticSearchMailboxConfiguration.java
new file mode 100644
index 0000000..6ff086c
--- /dev/null
+++ b/mailbox/elasticsearch-v6/src/main/java/org/apache/james/mailbox/elasticsearch/v6/ElasticSearchMailboxConfiguration.java
@@ -0,0 +1,213 @@
+/****************************************************************
+ * 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.mailbox.elasticsearch.v6;
+
+import java.util.Objects;
+import java.util.Optional;
+
+import org.apache.commons.configuration.Configuration;
+import org.apache.james.backends.es.IndexName;
+import org.apache.james.backends.es.ReadAliasName;
+import org.apache.james.backends.es.WriteAliasName;
+import org.apache.james.util.OptionalUtils;
+
+public class ElasticSearchMailboxConfiguration {
+
+    public static class Builder {
+        private Optional<IndexName> indexMailboxName;
+        private Optional<ReadAliasName> readAliasMailboxName;
+        private Optional<WriteAliasName> writeAliasMailboxName;
+        private Optional<IndexAttachments> indexAttachment;
+
+        public Builder() {
+            indexMailboxName = Optional.empty();
+            readAliasMailboxName = Optional.empty();
+            writeAliasMailboxName = Optional.empty();
+            indexAttachment = Optional.empty();
+        }
+
+        public Builder indexMailboxName(IndexName indexMailboxName) {
+            return indexMailboxName(Optional.of(indexMailboxName));
+        }
+
+        public Builder indexMailboxName(Optional<IndexName> indexMailboxName) {
+            this.indexMailboxName = indexMailboxName;
+            return this;
+        }
+
+        public Builder readAliasMailboxName(ReadAliasName readAliasMailboxName) {
+            return readAliasMailboxName(Optional.of(readAliasMailboxName));
+        }
+
+        public Builder readAliasMailboxName(Optional<ReadAliasName> readAliasMailboxName) {
+            this.readAliasMailboxName = readAliasMailboxName;
+            return this;
+        }
+
+        public Builder writeAliasMailboxName(WriteAliasName writeAliasMailboxName) {
+            return writeAliasMailboxName(Optional.of(writeAliasMailboxName));
+        }
+
+        public Builder writeAliasMailboxName(Optional<WriteAliasName> writeAliasMailboxName) {
+            this.writeAliasMailboxName = writeAliasMailboxName;
+            return this;
+        }
+
+
+        public Builder indexAttachment(IndexAttachments indexAttachment) {
+            this.indexAttachment = Optional.of(indexAttachment);
+            return this;
+        }
+
+
+
+        public ElasticSearchMailboxConfiguration build() {
+            return new ElasticSearchMailboxConfiguration(
+                indexMailboxName.orElse(MailboxElasticSearchConstants.DEFAULT_MAILBOX_INDEX),
+                readAliasMailboxName.orElse(MailboxElasticSearchConstants.DEFAULT_MAILBOX_READ_ALIAS),
+                writeAliasMailboxName.orElse(MailboxElasticSearchConstants.DEFAULT_MAILBOX_WRITE_ALIAS),
+                indexAttachment.orElse(IndexAttachments.YES));
+        }
+    }
+
+    public static Builder builder() {
+        return new Builder();
+    }
+
+    public static final String ELASTICSEARCH_HOSTS = "elasticsearch.hosts";
+    public static final String ELASTICSEARCH_MASTER_HOST = "elasticsearch.masterHost";
+    public static final String ELASTICSEARCH_PORT = "elasticsearch.port";
+    public static final String ELASTICSEARCH_INDEX_NAME = "elasticsearch.index.name";
+    public static final String ELASTICSEARCH_INDEX_MAILBOX_NAME = "elasticsearch.index.mailbox.name";
+    public static final String ELASTICSEARCH_NB_REPLICA = "elasticsearch.nb.replica";
+    public static final String ELASTICSEARCH_NB_SHARDS = "elasticsearch.nb.shards";
+    public static final String ELASTICSEARCH_ALIAS_READ_NAME = "elasticsearch.alias.read.name";
+    public static final String ELASTICSEARCH_ALIAS_WRITE_NAME = "elasticsearch.alias.write.name";
+    public static final String ELASTICSEARCH_ALIAS_READ_MAILBOX_NAME = "elasticsearch.alias.read.mailbox.name";
+    public static final String ELASTICSEARCH_ALIAS_WRITE_MAILBOX_NAME = "elasticsearch.alias.write.mailbox.name";
+    public static final String ELASTICSEARCH_INDEX_QUOTA_RATIO_NAME = "elasticsearch.index.quota.ratio.name";
+    public static final String ELASTICSEARCH_ALIAS_READ_QUOTA_RATIO_NAME = "elasticsearch.alias.read.quota.ratio.name";
+    public static final String ELASTICSEARCH_ALIAS_WRITE_QUOTA_RATIO_NAME = "elasticsearch.alias.write.quota.ratio.name";
+    public static final String ELASTICSEARCH_RETRY_CONNECTION_MIN_DELAY = "elasticsearch.retryConnection.minDelay";
+    public static final String ELASTICSEARCH_RETRY_CONNECTION_MAX_RETRIES = "elasticsearch.retryConnection.maxRetries";
+    public static final String ELASTICSEARCH_INDEX_ATTACHMENTS = "elasticsearch.indexAttachments";
+
+    public static final int DEFAULT_CONNECTION_MAX_RETRIES = 7;
+    public static final int DEFAULT_CONNECTION_MIN_DELAY = 3000;
+    public static final boolean DEFAULT_INDEX_ATTACHMENTS = true;
+    public static final int DEFAULT_NB_SHARDS = 5;
+    public static final int DEFAULT_NB_REPLICA = 1;
+    public static final int DEFAULT_PORT = 9300;
+    public static final Optional<Integer> DEFAULT_PORT_AS_OPTIONAL = Optional.of(DEFAULT_PORT);
+
+    public static final ElasticSearchMailboxConfiguration DEFAULT_CONFIGURATION = builder().build();
+
+    public static ElasticSearchMailboxConfiguration fromProperties(Configuration configuration) {
+        return builder()
+            .indexMailboxName(computeMailboxIndexName(configuration))
+            .readAliasMailboxName(computeMailboxReadAlias(configuration))
+            .writeAliasMailboxName(computeMailboxWriteAlias(configuration))
+            .indexAttachment(provideIndexAttachments(configuration))
+            .build();
+    }
+
+    public static Optional<IndexName> computeMailboxIndexName(Configuration configuration) {
+        return OptionalUtils.or(
+            Optional.ofNullable(configuration.getString(ELASTICSEARCH_INDEX_MAILBOX_NAME))
+                .map(IndexName::new),
+            Optional.ofNullable(configuration.getString(ELASTICSEARCH_INDEX_NAME))
+                .map(IndexName::new));
+    }
+
+    public static Optional<WriteAliasName> computeMailboxWriteAlias(Configuration configuration) {
+        return OptionalUtils.or(
+            Optional.ofNullable(configuration.getString(ELASTICSEARCH_ALIAS_WRITE_MAILBOX_NAME))
+                .map(WriteAliasName::new),
+            Optional.ofNullable(configuration.getString(ELASTICSEARCH_ALIAS_WRITE_NAME))
+                .map(WriteAliasName::new));
+    }
+
+    public static Optional<ReadAliasName> computeMailboxReadAlias(Configuration configuration) {
+        return OptionalUtils.or(
+            Optional.ofNullable(configuration.getString(ELASTICSEARCH_ALIAS_READ_MAILBOX_NAME))
+                .map(ReadAliasName::new),
+            Optional.ofNullable(configuration.getString(ELASTICSEARCH_ALIAS_READ_NAME))
+                .map(ReadAliasName::new));
+    }
+
+
+    private static IndexAttachments provideIndexAttachments(Configuration configuration) {
+        if (configuration.getBoolean(ELASTICSEARCH_INDEX_ATTACHMENTS, DEFAULT_INDEX_ATTACHMENTS)) {
+            return IndexAttachments.YES;
+        }
+        return IndexAttachments.NO;
+    }
+
+
+
+
+    private final IndexName indexMailboxName;
+    private final ReadAliasName readAliasMailboxName;
+    private final WriteAliasName writeAliasMailboxName;
+    private final IndexAttachments indexAttachment;
+
+    private ElasticSearchMailboxConfiguration(IndexName indexMailboxName, ReadAliasName readAliasMailboxName,
+                                              WriteAliasName writeAliasMailboxName, IndexAttachments indexAttachment) {
+        this.indexMailboxName = indexMailboxName;
+        this.readAliasMailboxName = readAliasMailboxName;
+        this.writeAliasMailboxName = writeAliasMailboxName;
+        this.indexAttachment = indexAttachment;
+    }
+
+
+    public IndexName getIndexMailboxName() {
+        return indexMailboxName;
+    }
+
+    public ReadAliasName getReadAliasMailboxName() {
+        return readAliasMailboxName;
+    }
+
+    public WriteAliasName getWriteAliasMailboxName() {
+        return writeAliasMailboxName;
+    }
+
+    public IndexAttachments getIndexAttachment() {
+        return indexAttachment;
+    }
+
+    @Override
+    public final boolean equals(Object o) {
+        if (o instanceof ElasticSearchMailboxConfiguration) {
+            ElasticSearchMailboxConfiguration that = (ElasticSearchMailboxConfiguration) o;
+
+            return Objects.equals(this.indexAttachment, that.indexAttachment)
+                && Objects.equals(this.indexMailboxName, that.indexMailboxName)
+                && Objects.equals(this.readAliasMailboxName, that.readAliasMailboxName)
+                && Objects.equals(this.writeAliasMailboxName, that.writeAliasMailboxName);
+        }
+        return false;
+    }
+
+    @Override
+    public final int hashCode() {
+        return Objects.hash(indexMailboxName, readAliasMailboxName, writeAliasMailboxName, indexAttachment, writeAliasMailboxName);
+    }
+}
diff --git a/mailbox/elasticsearch-v6/src/main/java/org/apache/james/mailbox/elasticsearch/v6/IndexAttachments.java b/mailbox/elasticsearch-v6/src/main/java/org/apache/james/mailbox/elasticsearch/v6/IndexAttachments.java
new file mode 100644
index 0000000..f827bd8
--- /dev/null
+++ b/mailbox/elasticsearch-v6/src/main/java/org/apache/james/mailbox/elasticsearch/v6/IndexAttachments.java
@@ -0,0 +1,24 @@
+/****************************************************************
+ * 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.mailbox.elasticsearch.v6;
+
+public enum IndexAttachments {
+    NO, YES
+}
diff --git a/mailbox/elasticsearch-v6/src/main/java/org/apache/james/mailbox/elasticsearch/v6/MailboxElasticSearchConstants.java b/mailbox/elasticsearch-v6/src/main/java/org/apache/james/mailbox/elasticsearch/v6/MailboxElasticSearchConstants.java
new file mode 100644
index 0000000..301127e
--- /dev/null
+++ b/mailbox/elasticsearch-v6/src/main/java/org/apache/james/mailbox/elasticsearch/v6/MailboxElasticSearchConstants.java
@@ -0,0 +1,37 @@
+/****************************************************************
+ * 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.mailbox.elasticsearch.v6;
+
+import org.apache.james.backends.es.IndexName;
+import org.apache.james.backends.es.ReadAliasName;
+import org.apache.james.backends.es.TypeName;
+import org.apache.james.backends.es.WriteAliasName;
+
+public interface MailboxElasticSearchConstants {
+
+    interface InjectionNames {
+        String MAILBOX = "mailbox";
+    }
+
+    WriteAliasName DEFAULT_MAILBOX_WRITE_ALIAS = new WriteAliasName("mailboxWriteAlias");
+    ReadAliasName DEFAULT_MAILBOX_READ_ALIAS = new ReadAliasName("mailboxReadAlias");
+    IndexName DEFAULT_MAILBOX_INDEX = new IndexName("mailbox_v1");
+    TypeName MESSAGE_TYPE = new TypeName("message");
+}
diff --git a/mailbox/elasticsearch-v6/src/main/java/org/apache/james/mailbox/elasticsearch/v6/MailboxIndexCreationUtil.java b/mailbox/elasticsearch-v6/src/main/java/org/apache/james/mailbox/elasticsearch/v6/MailboxIndexCreationUtil.java
new file mode 100644
index 0000000..4d320e4
--- /dev/null
+++ b/mailbox/elasticsearch-v6/src/main/java/org/apache/james/mailbox/elasticsearch/v6/MailboxIndexCreationUtil.java
@@ -0,0 +1,56 @@
+/****************************************************************
+ * 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.mailbox.elasticsearch.v6;
+
+import org.apache.james.backends.es.ElasticSearchConfiguration;
+import org.apache.james.backends.es.IndexCreationFactory;
+import org.apache.james.backends.es.IndexName;
+import org.apache.james.backends.es.NodeMappingFactory;
+import org.apache.james.backends.es.ReadAliasName;
+import org.apache.james.backends.es.WriteAliasName;
+import org.elasticsearch.client.Client;
+
+public class MailboxIndexCreationUtil {
+
+    public static Client prepareClient(Client client,
+                                       ReadAliasName readAlias,
+                                       WriteAliasName writeAlias,
+                                       IndexName indexName,
+                                       ElasticSearchConfiguration configuration) {
+
+        return NodeMappingFactory.applyMapping(
+            new IndexCreationFactory(configuration)
+                .useIndex(indexName)
+                .addAlias(readAlias)
+                .addAlias(writeAlias)
+                .createIndexAndAliases(client),
+            indexName,
+            MailboxElasticSearchConstants.MESSAGE_TYPE,
+            MailboxMappingFactory.getMappingContent());
+    }
+
+    public static Client prepareDefaultClient(Client client, ElasticSearchConfiguration configuration) {
+        return prepareClient(client,
+            MailboxElasticSearchConstants.DEFAULT_MAILBOX_READ_ALIAS,
+            MailboxElasticSearchConstants.DEFAULT_MAILBOX_WRITE_ALIAS,
+            MailboxElasticSearchConstants.DEFAULT_MAILBOX_INDEX,
+                configuration);
+    }
+}
diff --git a/mailbox/elasticsearch-v6/src/main/java/org/apache/james/mailbox/elasticsearch/v6/MailboxMappingFactory.java b/mailbox/elasticsearch-v6/src/main/java/org/apache/james/mailbox/elasticsearch/v6/MailboxMappingFactory.java
new file mode 100644
index 0000000..2ecd6d3
--- /dev/null
+++ b/mailbox/elasticsearch-v6/src/main/java/org/apache/james/mailbox/elasticsearch/v6/MailboxMappingFactory.java
@@ -0,0 +1,365 @@
+/****************************************************************
+ * 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.mailbox.elasticsearch.v6;
+
+import static org.apache.james.backends.es.IndexCreationFactory.CASE_INSENSITIVE;
+import static org.apache.james.backends.es.IndexCreationFactory.KEEP_MAIL_AND_URL;
+import static org.apache.james.backends.es.IndexCreationFactory.SNOWBALL_KEEP_MAIL_AND_URL;
+import static org.apache.james.backends.es.NodeMappingFactory.ANALYZER;
+import static org.apache.james.backends.es.NodeMappingFactory.BOOLEAN;
+import static org.apache.james.backends.es.NodeMappingFactory.FIELDS;
+import static org.apache.james.backends.es.NodeMappingFactory.FORMAT;
+import static org.apache.james.backends.es.NodeMappingFactory.IGNORE_ABOVE;
+import static org.apache.james.backends.es.NodeMappingFactory.INDEX;
+import static org.apache.james.backends.es.NodeMappingFactory.LONG;
+import static org.apache.james.backends.es.NodeMappingFactory.NESTED;
+import static org.apache.james.backends.es.NodeMappingFactory.NOT_ANALYZED;
+import static org.apache.james.backends.es.NodeMappingFactory.PROPERTIES;
+import static org.apache.james.backends.es.NodeMappingFactory.RAW;
+import static org.apache.james.backends.es.NodeMappingFactory.SEARCH_ANALYZER;
+import static org.apache.james.backends.es.NodeMappingFactory.SNOWBALL;
+import static org.apache.james.backends.es.NodeMappingFactory.SPLIT_EMAIL;
+import static org.apache.james.backends.es.NodeMappingFactory.STRING;
+import static org.apache.james.backends.es.NodeMappingFactory.TYPE;
+import static org.apache.james.mailbox.elasticsearch.v6.json.JsonMessageConstants.BCC;
+import static org.apache.james.mailbox.elasticsearch.v6.json.JsonMessageConstants.CC;
+import static org.apache.james.mailbox.elasticsearch.v6.json.JsonMessageConstants.DATE;
+import static org.apache.james.mailbox.elasticsearch.v6.json.JsonMessageConstants.FROM;
+import static org.apache.james.mailbox.elasticsearch.v6.json.JsonMessageConstants.HAS_ATTACHMENT;
+import static org.apache.james.mailbox.elasticsearch.v6.json.JsonMessageConstants.HTML_BODY;
+import static org.apache.james.mailbox.elasticsearch.v6.json.JsonMessageConstants.IS_ANSWERED;
+import static org.apache.james.mailbox.elasticsearch.v6.json.JsonMessageConstants.IS_DELETED;
+import static org.apache.james.mailbox.elasticsearch.v6.json.JsonMessageConstants.IS_DRAFT;
+import static org.apache.james.mailbox.elasticsearch.v6.json.JsonMessageConstants.IS_FLAGGED;
+import static org.apache.james.mailbox.elasticsearch.v6.json.JsonMessageConstants.IS_RECENT;
+import static org.apache.james.mailbox.elasticsearch.v6.json.JsonMessageConstants.IS_UNREAD;
+import static org.apache.james.mailbox.elasticsearch.v6.json.JsonMessageConstants.MAILBOX_ID;
+import static org.apache.james.mailbox.elasticsearch.v6.json.JsonMessageConstants.MEDIA_TYPE;
+import static org.apache.james.mailbox.elasticsearch.v6.json.JsonMessageConstants.MESSAGE_ID;
+import static org.apache.james.mailbox.elasticsearch.v6.json.JsonMessageConstants.MIME_MESSAGE_ID;
+import static org.apache.james.mailbox.elasticsearch.v6.json.JsonMessageConstants.MODSEQ;
+import static org.apache.james.mailbox.elasticsearch.v6.json.JsonMessageConstants.SENT_DATE;
+import static org.apache.james.mailbox.elasticsearch.v6.json.JsonMessageConstants.SIZE;
+import static org.apache.james.mailbox.elasticsearch.v6.json.JsonMessageConstants.SUBJECT;
+import static org.apache.james.mailbox.elasticsearch.v6.json.JsonMessageConstants.SUBTYPE;
+import static org.apache.james.mailbox.elasticsearch.v6.json.JsonMessageConstants.TEXT;
+import static org.apache.james.mailbox.elasticsearch.v6.json.JsonMessageConstants.TEXT_BODY;
+import static org.apache.james.mailbox.elasticsearch.v6.json.JsonMessageConstants.TO;
+import static org.apache.james.mailbox.elasticsearch.v6.json.JsonMessageConstants.UID;
+import static org.apache.james.mailbox.elasticsearch.v6.json.JsonMessageConstants.USERS;
+import static org.apache.james.mailbox.elasticsearch.v6.json.JsonMessageConstants.USER_FLAGS;
+import static org.elasticsearch.common.xcontent.XContentFactory.jsonBuilder;
+
+import java.io.IOException;
+
+import org.apache.james.backends.es.NodeMappingFactory;
+import org.apache.james.mailbox.elasticsearch.v6.json.JsonMessageConstants.EMailer;
+import org.apache.james.mailbox.elasticsearch.v6.json.JsonMessageConstants.Property;
+import org.elasticsearch.common.xcontent.XContentBuilder;
+
+public class MailboxMappingFactory {
+
+    private static final int MAXIMUM_TERM_LENGTH = 4096;
+    private static final String STANDARD = "standard";
+
+    public static XContentBuilder getMappingContent() {
+        try {
+            return jsonBuilder()
+                .startObject()
+
+                    .startObject(MailboxElasticSearchConstants.MESSAGE_TYPE.getValue())
+                        .startObject(PROPERTIES)
+
+                            .startObject(MESSAGE_ID)
+                                .field(TYPE, STRING)
+                                .field(INDEX, NOT_ANALYZED)
+                            .endObject()
+
+                            .startObject(UID)
+                                .field(TYPE, LONG)
+                            .endObject()
+
+                            .startObject(MODSEQ)
+                                .field(TYPE, LONG)
+                            .endObject()
+
+                            .startObject(SIZE)
+                                .field(TYPE, LONG)
+                            .endObject()
+
+                            .startObject(IS_ANSWERED)
+                                .field(TYPE, BOOLEAN)
+                            .endObject()
+
+                            .startObject(IS_DELETED)
+                                .field(TYPE, BOOLEAN)
+                            .endObject()
+
+                            .startObject(IS_DRAFT)
+                                .field(TYPE, BOOLEAN)
+                            .endObject()
+
+                            .startObject(IS_FLAGGED)
+                                .field(TYPE, BOOLEAN)
+                            .endObject()
+
+                            .startObject(IS_RECENT)
+                                .field(TYPE, BOOLEAN)
+                            .endObject()
+
+                            .startObject(IS_UNREAD)
+                                .field(TYPE, BOOLEAN)
+                            .endObject()
+
+                            .startObject(DATE)
+                                .field(TYPE, NodeMappingFactory.DATE)
+                                .field(FORMAT, "yyyy-MM-dd'T'HH:mm:ssZ")
+                            .endObject()
+
+                            .startObject(SENT_DATE)
+                                .field(TYPE, NodeMappingFactory.DATE)
+                                .field(FORMAT, "yyyy-MM-dd'T'HH:mm:ssZ")
+                            .endObject()
+
+                            .startObject(MEDIA_TYPE)
+                                .field(TYPE, STRING)
+                                .field(INDEX, NOT_ANALYZED)
+                            .endObject()
+
+                            .startObject(SUBTYPE)
+                                .field(TYPE, STRING)
+                                .field(INDEX, NOT_ANALYZED)
+                            .endObject()
+
+                            .startObject(USER_FLAGS)
+                                .field(TYPE, STRING)
+                                .field(INDEX, NOT_ANALYZED)
+                            .endObject()
+
+                            .startObject(FROM)
+                                .field(TYPE, NESTED)
+                                .startObject(PROPERTIES)
+                                    .startObject(EMailer.NAME)
+                                        .field(TYPE, STRING)
+                                        .field(ANALYZER, KEEP_MAIL_AND_URL)
+                                        .startObject(FIELDS)
+                                            .startObject(RAW)
+                                                .field(TYPE, STRING)
+                                                .field(ANALYZER, CASE_INSENSITIVE)
+                                            .endObject()
+                                        .endObject()
+                                    .endObject()
+                                    .startObject(EMailer.ADDRESS)
+                                        .field(TYPE, STRING)
+                                        .field(ANALYZER, STANDARD)
+                                        .field(SEARCH_ANALYZER, KEEP_MAIL_AND_URL)
+                                        .startObject(FIELDS)
+                                            .startObject(RAW)
+                                                .field(TYPE, STRING)
+                                                .field(ANALYZER, CASE_INSENSITIVE)
+                                            .endObject()
+                                        .endObject()
+                                    .endObject()
+                                .endObject()
+                            .endObject()
+
+                            .startObject(SUBJECT)
+                                .field(TYPE, STRING)
+                                .field(ANALYZER, KEEP_MAIL_AND_URL)
+                                .startObject(FIELDS)
+                                    .startObject(RAW)
+                                        .field(TYPE, STRING)
+                                        .field(ANALYZER, CASE_INSENSITIVE)
+                                    .endObject()
+                                .endObject()
+                            .endObject()
+
+                            .startObject(TO)
+                                .field(TYPE, NESTED)
+                                .startObject(PROPERTIES)
+                                    .startObject(EMailer.NAME)
+                                        .field(TYPE, STRING)
+                                        .field(ANALYZER, KEEP_MAIL_AND_URL)
+                                        .startObject(FIELDS)
+                                            .startObject(RAW)
+                                                .field(TYPE, STRING)
+                                                .field(ANALYZER, CASE_INSENSITIVE)
+                                            .endObject()
+                                        .endObject()
+                                    .endObject()
+                                    .startObject(EMailer.ADDRESS)
+                                        .field(TYPE, STRING)
+                                        .field(ANALYZER, STANDARD)
+                                        .field(SEARCH_ANALYZER, KEEP_MAIL_AND_URL)
+                                        .startObject(FIELDS)
+                                            .startObject(RAW)
+                                                .field(TYPE, STRING)
+                                                .field(ANALYZER, CASE_INSENSITIVE)
+                                            .endObject()
+                                        .endObject()
+                                    .endObject()
+                                .endObject()
+                            .endObject()
+
+                            .startObject(CC)
+                                .field(TYPE, NESTED)
+                                .startObject(PROPERTIES)
+                                    .startObject(EMailer.NAME)
+                                        .field(TYPE, STRING)
+                                        .field(ANALYZER, KEEP_MAIL_AND_URL)
+                                        .startObject(FIELDS)
+                                            .startObject(RAW)
+                                                .field(TYPE, STRING)
+                                                .field(ANALYZER, CASE_INSENSITIVE)
+                                            .endObject()
+                                        .endObject()
+                                    .endObject()
+                                    .startObject(EMailer.ADDRESS)
+                                        .field(TYPE, STRING)
+                                        .field(ANALYZER, STANDARD)
+                                        .field(SEARCH_ANALYZER, KEEP_MAIL_AND_URL)
+                                        .startObject(FIELDS)
+                                            .startObject(RAW)
+                                            .field(TYPE, STRING)
+                                            .field(ANALYZER, CASE_INSENSITIVE)
+                                            .endObject()
+                                        .endObject()
+                                    .endObject()
+                                .endObject()
+                            .endObject()
+
+                            .startObject(BCC)
+                                .field(TYPE, NESTED)
+                                .startObject(PROPERTIES)
+                                    .startObject(EMailer.NAME)
+                                        .field(TYPE, STRING)
+                                        .field(ANALYZER, KEEP_MAIL_AND_URL)
+                                        .startObject(FIELDS)
+                                            .startObject(RAW)
+                                                .field(TYPE, STRING)
+                                                .field(ANALYZER, CASE_INSENSITIVE)
+                                            .endObject()
+                                        .endObject()
+                                    .endObject()
+                                    .startObject(EMailer.ADDRESS)
+                                        .field(TYPE, STRING)
+                                        .field(ANALYZER, STANDARD)
+                                        .field(SEARCH_ANALYZER, KEEP_MAIL_AND_URL)
+                                        .startObject(FIELDS)
+                                            .startObject(RAW)
+                                                .field(TYPE, STRING)
+                                                .field(ANALYZER, CASE_INSENSITIVE)
+                                            .endObject()
+                                        .endObject()
+                                    .endObject()
+                                .endObject()
+                            .endObject()
+
+                            .startObject(MAILBOX_ID)
+                                .field(TYPE, STRING)
+                                .field(INDEX, NOT_ANALYZED)
+                            .endObject()
+
+                            .startObject(MIME_MESSAGE_ID)
+                                .field(TYPE, STRING)
+                                .field(INDEX, NOT_ANALYZED)
+                            .endObject()
+
+                            .startObject(USERS)
+                                .field(TYPE, STRING)
+                                .field(INDEX, NOT_ANALYZED)
+                            .endObject()
+
+                            .startObject(PROPERTIES)
+                                .field(TYPE, NESTED)
+                                .startObject(PROPERTIES)
+                                    .startObject(Property.NAMESPACE)
+                                        .field(TYPE, STRING)
+                                        .field(INDEX, NOT_ANALYZED)
+                                    .endObject()
+                                    .startObject(Property.NAME)
+                                        .field(TYPE, STRING)
+                                        .field(INDEX, NOT_ANALYZED)
+                                    .endObject()
+                                    .startObject(Property.VALUE)
+                                        .field(TYPE, STRING)
+                                        .field(INDEX, NOT_ANALYZED)
+                                    .endObject()
+                                .endObject()
+                            .endObject()
+
+                            .startObject(TEXT_BODY)
+                                .field(TYPE, STRING)
+                                .field(ANALYZER, KEEP_MAIL_AND_URL)
+                                .startObject(FIELDS)
+                                    .startObject(SPLIT_EMAIL)
+                                        .field(TYPE, STRING)
+                                        .field(ANALYZER, STANDARD)
+                                        .field(SEARCH_ANALYZER, KEEP_MAIL_AND_URL)
+                                    .endObject()
+                                    .startObject(RAW)
+                                        .field(TYPE, STRING)
+                                        .field(ANALYZER, CASE_INSENSITIVE)
+                                        .field(IGNORE_ABOVE, MAXIMUM_TERM_LENGTH)
+                                    .endObject()
+                                .endObject()
+                            .endObject()
+
+                            .startObject(HTML_BODY)
+                                .field(TYPE, STRING)
+                                .field(ANALYZER, KEEP_MAIL_AND_URL)
+                                .startObject(FIELDS)
+                                    .startObject(SPLIT_EMAIL)
+                                        .field(TYPE, STRING)
+                                        .field(ANALYZER, STANDARD)
+                                        .field(SEARCH_ANALYZER, KEEP_MAIL_AND_URL)
+                                    .endObject()
+                                    .startObject(RAW)
+                                        .field(TYPE, STRING)
+                                        .field(ANALYZER, CASE_INSENSITIVE)
+                                        .field(IGNORE_ABOVE, MAXIMUM_TERM_LENGTH)
+                                    .endObject()
+                                .endObject()
+                            .endObject()
+
+                            .startObject(HAS_ATTACHMENT)
+                                .field(TYPE, BOOLEAN)
+                            .endObject()
+
+                            .startObject(TEXT)
+                                .field(TYPE, STRING)
+                                .field(ANALYZER, SNOWBALL_KEEP_MAIL_AND_URL)
+                                .field(IGNORE_ABOVE, MAXIMUM_TERM_LENGTH)
+                                .startObject(FIELDS)
+                                    .startObject(SPLIT_EMAIL)
+                                        .field(TYPE, STRING)
+                                        .field(ANALYZER, SNOWBALL)
+                                        .field(SEARCH_ANALYZER, SNOWBALL_KEEP_MAIL_AND_URL)
+                                    .endObject()
+                                .endObject()
+                            .endObject()
+                        .endObject()
+                    .endObject()
+                .endObject();
+        } catch (IOException e) {
+            throw new RuntimeException(e);
+        }
+    }
+}
diff --git a/mailbox/elasticsearch-v6/src/main/java/org/apache/james/mailbox/elasticsearch/v6/events/ElasticSearchListeningMessageSearchIndex.java b/mailbox/elasticsearch-v6/src/main/java/org/apache/james/mailbox/elasticsearch/v6/events/ElasticSearchListeningMessageSearchIndex.java
new file mode 100644
index 0000000..8ee2204
--- /dev/null
+++ b/mailbox/elasticsearch-v6/src/main/java/org/apache/james/mailbox/elasticsearch/v6/events/ElasticSearchListeningMessageSearchIndex.java
@@ -0,0 +1,196 @@
+/****************************************************************
+ * 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.mailbox.elasticsearch.v6.events;
+
+import static org.elasticsearch.index.query.QueryBuilders.termQuery;
+
+import java.util.Collection;
+import java.util.EnumSet;
+import java.util.Iterator;
+import java.util.List;
+import java.util.Optional;
+
+import javax.inject.Inject;
+import javax.inject.Named;
+
+import org.apache.james.backends.es.ElasticSearchIndexer;
+import org.apache.james.backends.es.UpdatedRepresentation;
+import org.apache.james.mailbox.MailboxManager.MessageCapabilities;
+import org.apache.james.mailbox.MailboxManager.SearchCapabilities;
+import org.apache.james.mailbox.MailboxSession;
+import org.apache.james.mailbox.MessageUid;
+import org.apache.james.mailbox.elasticsearch.v6.MailboxElasticSearchConstants;
+import org.apache.james.mailbox.elasticsearch.v6.json.JsonMessageConstants;
+import org.apache.james.mailbox.elasticsearch.v6.json.MessageToElasticSearchJson;
+import org.apache.james.mailbox.elasticsearch.v6.search.ElasticSearchSearcher;
+import org.apache.james.mailbox.events.Group;
+import org.apache.james.mailbox.exception.MailboxException;
+import org.apache.james.mailbox.model.Mailbox;
+import org.apache.james.mailbox.model.MailboxId;
+import org.apache.james.mailbox.model.MessageId;
+import org.apache.james.mailbox.model.SearchQuery;
+import org.apache.james.mailbox.model.UpdatedFlags;
+import org.apache.james.mailbox.store.MailboxSessionMapperFactory;
+import org.apache.james.mailbox.store.SessionProvider;
+import org.apache.james.mailbox.store.mail.model.MailboxMessage;
+import org.apache.james.mailbox.store.search.ListeningMessageSearchIndex;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+import com.fasterxml.jackson.core.JsonProcessingException;
+import com.github.fge.lambdas.Throwing;
+import com.github.steveash.guavate.Guavate;
+import com.google.common.base.Preconditions;
+import com.google.common.collect.ImmutableList;
+
+public class ElasticSearchListeningMessageSearchIndex extends ListeningMessageSearchIndex {
+    public static class ElasticSearchListeningMessageSearchIndexGroup extends Group {}
+
+    private static final Logger LOGGER = LoggerFactory.getLogger(ElasticSearchListeningMessageSearchIndex.class);
+    private static final String ID_SEPARATOR = ":";
+    private static final Group GROUP = new ElasticSearchListeningMessageSearchIndexGroup();
+
+    private final ElasticSearchIndexer elasticSearchIndexer;
+    private final ElasticSearchSearcher searcher;
+    private final MessageToElasticSearchJson messageToElasticSearchJson;
+
+    @Inject
+    public ElasticSearchListeningMessageSearchIndex(MailboxSessionMapperFactory factory,
+                                                    @Named(MailboxElasticSearchConstants.InjectionNames.MAILBOX) ElasticSearchIndexer indexer,
+                                                    ElasticSearchSearcher searcher, MessageToElasticSearchJson messageToElasticSearchJson,
+                                                    SessionProvider sessionProvider) {
+        super(factory, sessionProvider);
+        this.elasticSearchIndexer = indexer;
+        this.messageToElasticSearchJson = messageToElasticSearchJson;
+        this.searcher = searcher;
+    }
+
+    @Override
+    public Group getDefaultGroup() {
+        return GROUP;
+    }
+
+    @Override
+    public EnumSet<SearchCapabilities> getSupportedCapabilities(EnumSet<MessageCapabilities> messageCapabilities) {
+        return EnumSet.of(
+            SearchCapabilities.MultimailboxSearch,
+            SearchCapabilities.Text,
+            SearchCapabilities.FullText,
+            SearchCapabilities.Attachment,
+            SearchCapabilities.AttachmentFileName,
+            SearchCapabilities.PartialEmailMatch);
+    }
+    
+    @Override
+    public Iterator<MessageUid> search(MailboxSession session, Mailbox mailbox, SearchQuery searchQuery) throws MailboxException {
+        Preconditions.checkArgument(session != null, "'session' is mandatory");
+        Optional<Long> noLimit = Optional.empty();
+        return searcher
+                .search(ImmutableList.of(mailbox.getMailboxId()), searchQuery, noLimit)
+                .map(SearchResult::getMessageUid)
+                .iterator();
+    }
+    
+    @Override
+    public List<MessageId> search(MailboxSession session, Collection<MailboxId> mailboxIds, SearchQuery searchQuery, long limit)
+            throws MailboxException {
+        Preconditions.checkArgument(session != null, "'session' is mandatory");
+
+        if (mailboxIds.isEmpty()) {
+            return ImmutableList.of();
+        }
+
+        return searcher.search(mailboxIds, searchQuery, Optional.empty())
+            .peek(this::logIfNoMessageId)
+            .map(SearchResult::getMessageId)
+            .map(Optional::get)
+            .distinct()
+            .limit(limit)
+            .collect(Guavate.toImmutableList());
+    }
+
+    @Override
+    public void add(MailboxSession session, Mailbox mailbox, MailboxMessage message) throws JsonProcessingException {
+        LOGGER.info("Indexing mailbox {}-{} of user {} on message {}",
+            mailbox.getName(),
+            mailbox.getMailboxId(),
+            session.getUser().asString(),
+            message.getUid());
+
+        String jsonContent = generateIndexedJson(mailbox, message, session);
+        elasticSearchIndexer.index(indexIdFor(mailbox, message.getUid()), jsonContent);
+    }
+
+    private String generateIndexedJson(Mailbox mailbox, MailboxMessage message, MailboxSession session) throws JsonProcessingException {
+        try {
+            return messageToElasticSearchJson.convertToJson(message, ImmutableList.of(session.getUser()));
+        } catch (Exception e) {
+            LOGGER.warn("Indexing mailbox {}-{} of user {} on message {} without attachments ",
+                mailbox.getName(),
+                mailbox.getMailboxId().serialize(),
+                session.getUser().asString(),
+                message.getUid(),
+                e);
+            return messageToElasticSearchJson.convertToJsonWithoutAttachment(message, ImmutableList.of(session.getUser()));
+        }
+    }
+
+    @Override
+    public void delete(MailboxSession session, Mailbox mailbox, Collection<MessageUid> expungedUids) {
+            elasticSearchIndexer.delete(expungedUids.stream()
+                .map(uid ->  indexIdFor(mailbox, uid))
+                .collect(Guavate.toImmutableList()));
+    }
+
+    @Override
+    public void deleteAll(MailboxSession session, Mailbox mailbox) {
+            elasticSearchIndexer.deleteAllMatchingQuery(
+                termQuery(
+                    JsonMessageConstants.MAILBOX_ID,
+                    mailbox.getMailboxId().serialize()));
+    }
+
+    @Override
+    public void update(MailboxSession session, Mailbox mailbox, List<UpdatedFlags> updatedFlagsList) {
+            elasticSearchIndexer.update(updatedFlagsList.stream()
+                .map(Throwing.<UpdatedFlags, UpdatedRepresentation>function(
+                    updatedFlags -> createUpdatedDocumentPartFromUpdatedFlags(mailbox, updatedFlags))
+                    .sneakyThrow())
+                .collect(Guavate.toImmutableList()));
+    }
+
+    private UpdatedRepresentation createUpdatedDocumentPartFromUpdatedFlags(Mailbox mailbox, UpdatedFlags updatedFlags) throws JsonProcessingException {
+            return new UpdatedRepresentation(
+                indexIdFor(mailbox, updatedFlags.getUid()),
+                    messageToElasticSearchJson.getUpdatedJsonMessagePart(
+                        updatedFlags.getNewFlags(),
+                        updatedFlags.getModSeq()));
+    }
+
+    private String indexIdFor(Mailbox mailbox, MessageUid uid) {
+        return String.join(ID_SEPARATOR, mailbox.getMailboxId().serialize(), String.valueOf(uid.asLong()));
+    }
+
+    private void logIfNoMessageId(SearchResult searchResult) {
+        if (!searchResult.getMessageId().isPresent()) {
+            LOGGER.error("No messageUid for {} in mailbox {}", searchResult.getMessageUid(), searchResult.getMailboxId());
+        }
+    }
+
+}
diff --git a/mailbox/elasticsearch-v6/src/main/java/org/apache/james/mailbox/elasticsearch/v6/json/EMailer.java b/mailbox/elasticsearch-v6/src/main/java/org/apache/james/mailbox/elasticsearch/v6/json/EMailer.java
new file mode 100644
index 0000000..83ff556
--- /dev/null
+++ b/mailbox/elasticsearch-v6/src/main/java/org/apache/james/mailbox/elasticsearch/v6/json/EMailer.java
@@ -0,0 +1,75 @@
+/****************************************************************
+ * 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.mailbox.elasticsearch.v6.json;
+
+import java.util.Objects;
+
+import com.fasterxml.jackson.annotation.JsonProperty;
+import com.google.common.base.Joiner;
+import com.google.common.base.MoreObjects;
+
+public class EMailer implements Serializable {
+
+    private final String name;
+    private final String address;
+
+    public EMailer(String name, String address) {
+        this.name = name;
+        this.address = address;
+    }
+
+    @JsonProperty(JsonMessageConstants.EMailer.NAME)
+    public String getName() {
+        return name;
+    }
+
+    @JsonProperty(JsonMessageConstants.EMailer.ADDRESS)
+    public String getAddress() {
+        return address;
+    }
+
+    @Override
+    public String serialize() {
+        return Joiner.on(" ").join(name, address);
+    }
+
+    @Override
+    public boolean equals(Object o) {
+        if (o instanceof EMailer) {
+            EMailer otherEMailer = (EMailer) o;
+            return Objects.equals(name, otherEMailer.name)
+                && Objects.equals(address, otherEMailer.address);
+        }
+        return false;
+    }
+
+    @Override
+    public int hashCode() {
+        return Objects.hash(name, address);
+    }
+
+    @Override
+    public String toString() {
+        return MoreObjects.toStringHelper(this)
+            .add("name", name)
+            .add("address", address)
+            .toString();
+    }
+}
diff --git a/mailbox/elasticsearch-v6/src/main/java/org/apache/james/mailbox/elasticsearch/v6/json/EMailers.java b/mailbox/elasticsearch-v6/src/main/java/org/apache/james/mailbox/elasticsearch/v6/json/EMailers.java
new file mode 100644
index 0000000..e5e8e65
--- /dev/null
+++ b/mailbox/elasticsearch-v6/src/main/java/org/apache/james/mailbox/elasticsearch/v6/json/EMailers.java
@@ -0,0 +1,52 @@
+/****************************************************************
+ * 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.mailbox.elasticsearch.v6.json;
+
+import java.util.Set;
+import java.util.stream.Collectors;
+
+import com.fasterxml.jackson.annotation.JsonValue;
+import com.google.common.base.Preconditions;
+
+public class EMailers implements Serializable {
+
+    public static EMailers from(Set<EMailer> emailers) {
+        Preconditions.checkNotNull(emailers, "'emailers' is mandatory");
+        return new EMailers(emailers);
+    }
+
+    private final Set<EMailer> emailers;
+
+    private EMailers(Set<EMailer> emailers) {
+        this.emailers = emailers;
+    }
+
+    @JsonValue
+    public Set<EMailer> getEmailers() {
+        return emailers;
+    }
+
+    @Override
+    public String serialize() {
+        return emailers.stream()
+            .map(EMailer::serialize)
+            .collect(Collectors.joining(" "));
+    }
+}
diff --git a/mailbox/elasticsearch-v6/src/main/java/org/apache/james/mailbox/elasticsearch/v6/json/HeaderCollection.java b/mailbox/elasticsearch-v6/src/main/java/org/apache/james/mailbox/elasticsearch/v6/json/HeaderCollection.java
new file mode 100644
index 0000000..83f2b52
--- /dev/null
+++ b/mailbox/elasticsearch-v6/src/main/java/org/apache/james/mailbox/elasticsearch/v6/json/HeaderCollection.java
@@ -0,0 +1,224 @@
+/****************************************************************
+ * 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.mailbox.elasticsearch.v6.json;
+
+import java.time.ZonedDateTime;
+import java.util.HashSet;
+import java.util.Locale;
+import java.util.Optional;
+import java.util.Set;
+import java.util.stream.Collectors;
+import java.util.stream.Stream;
+
+import org.apache.james.mailbox.store.search.SearchUtil;
+import org.apache.james.mailbox.store.search.comparator.SentDateComparator;
+import org.apache.james.mime4j.dom.address.Address;
+import org.apache.james.mime4j.dom.address.Group;
+import org.apache.james.mime4j.dom.address.Mailbox;
+import org.apache.james.mime4j.field.address.LenientAddressParser;
+import org.apache.james.mime4j.stream.Field;
+import org.apache.james.mime4j.util.MimeUtil;
+
+import com.google.common.base.Preconditions;
+import com.google.common.collect.ArrayListMultimap;
+import com.google.common.collect.ImmutableMultimap;
+import com.google.common.collect.ImmutableSet;
+import com.google.common.collect.Multimap;
+
+public class HeaderCollection {
+
+    public static class Builder {
+
+        private final Set<EMailer> toAddressSet;
+        private final Set<EMailer> fromAddressSet;
+        private final Set<EMailer> ccAddressSet;
+        private final Set<EMailer> bccAddressSet;
+        private final Set<EMailer> replyToAddressSet;
+        private final Set<String> subjectSet;
+        private final Multimap<String, String> headers;
+        private Optional<ZonedDateTime> sentDate;
+        private Optional<String> messageID;
+
+        private Builder() {
+            toAddressSet = new HashSet<>();
+            fromAddressSet = new HashSet<>();
+            ccAddressSet = new HashSet<>();
+            bccAddressSet = new HashSet<>();
+            replyToAddressSet = new HashSet<>();
+            subjectSet = new HashSet<>();
+            headers = ArrayListMultimap.create();
+            sentDate = Optional.empty();
+            messageID = Optional.empty();
+        }
+
+        public Builder add(Field field) {
+            Preconditions.checkNotNull(field);
+            String headerName = field.getName().toLowerCase(Locale.US);
+            String rawHeaderValue = field.getBody();
+            String sanitizedValue = MimeUtil.unscrambleHeaderValue(rawHeaderValue);
+
+            if (!headerName.contains(".")) {
+                headers.put(headerName, sanitizedValue);
+            }
+            handleSpecificHeader(headerName, sanitizedValue, rawHeaderValue);
+            return this;
+        }
+
+        public HeaderCollection build() {
+            return new HeaderCollection(
+                ImmutableSet.copyOf(toAddressSet),
+                ImmutableSet.copyOf(fromAddressSet),
+                ImmutableSet.copyOf(ccAddressSet),
+                ImmutableSet.copyOf(bccAddressSet),
+                ImmutableSet.copyOf(replyToAddressSet),
+                ImmutableSet.copyOf(subjectSet),
+                ImmutableMultimap.copyOf(headers),
+                sentDate, messageID);
+        }
+
+        private void handleSpecificHeader(String headerName, String headerValue, String rawHeaderValue) {
+            switch (headerName) {
+                case TO:
+                case FROM:
+                case CC:
+                case BCC:
+                case REPLY_TO:
+                    manageAddressField(headerName, rawHeaderValue);
+                    break;
+                case SUBJECT:
+                    subjectSet.add(headerValue);
+                    break;
+                case DATE:
+                    sentDate = SentDateComparator.toISODate(headerValue);
+                    break;
+                case MESSAGE_ID:
+                    messageID = Optional.ofNullable(headerValue);
+                    break;
+            }
+        }
+
+        private void manageAddressField(String headerName, String rawHeaderValue) {
+            LenientAddressParser.DEFAULT
+                .parseAddressList(rawHeaderValue)
+                .stream()
+                .flatMap(this::convertAddressToMailboxStream)
+                .map((mailbox) -> new EMailer(SearchUtil.getDisplayAddress(mailbox), mailbox.getAddress()))
+                .collect(Collectors.toCollection(() -> getAddressSet(headerName)));
+        }
+
+        private Stream<Mailbox> convertAddressToMailboxStream(Address address) {
+            if (address instanceof Mailbox) {
+                return Stream.of((Mailbox) address);
+            } else if (address instanceof Group) {
+                return ((Group) address).getMailboxes().stream();
+            }
+            return Stream.empty();
+        }
+
+        private Set<EMailer> getAddressSet(String headerName) {
+            switch (headerName) {
+                case TO:
+                    return toAddressSet;
+                case FROM:
+                    return fromAddressSet;
+                case CC:
+                    return ccAddressSet;
+                case BCC:
+                    return bccAddressSet;
+                case REPLY_TO:
+                    return replyToAddressSet;
+            }
+            throw new RuntimeException(headerName + " is not a address header name");
+        }
+    }
+
+    public static final String TO = "to";
+    public static final String FROM = "from";
+    public static final String CC = "cc";
+    public static final String BCC = "bcc";
+    public static final String REPLY_TO = "reply-to";
+    public static final String SUBJECT = "subject";
+    public static final String DATE = "date";
+    public static final String MESSAGE_ID = "message-id";
+
+    public static Builder builder() {
+        return new Builder();
+    }
+
+    private final ImmutableSet<EMailer> toAddressSet;
+    private final ImmutableSet<EMailer> fromAddressSet;
+    private final ImmutableSet<EMailer> ccAddressSet;
+    private final ImmutableSet<EMailer> bccAddressSet;
+    private final ImmutableSet<EMailer> replyToAddressSet;
+    private final ImmutableSet<String> subjectSet;
+    private final ImmutableMultimap<String, String> headers;
+    private final Optional<ZonedDateTime> sentDate;
+    private final Optional<String> messageID;
+
+    private HeaderCollection(ImmutableSet<EMailer> toAddressSet, ImmutableSet<EMailer> fromAddressSet,
+                             ImmutableSet<EMailer> ccAddressSet, ImmutableSet<EMailer> bccAddressSet, ImmutableSet<EMailer> replyToAddressSet, ImmutableSet<String> subjectSet,
+                             ImmutableMultimap<String, String> headers, Optional<ZonedDateTime> sentDate, Optional<String> messageID) {
+        this.toAddressSet = toAddressSet;
+        this.fromAddressSet = fromAddressSet;
+        this.ccAddressSet = ccAddressSet;
+        this.bccAddressSet = bccAddressSet;
+        this.replyToAddressSet = replyToAddressSet;
+        this.subjectSet = subjectSet;
+        this.headers = headers;
+        this.sentDate = sentDate;
+        this.messageID = messageID;
+    }
+
+    public Set<EMailer> getToAddressSet() {
+        return toAddressSet;
+    }
+
+    public Set<EMailer> getFromAddressSet() {
+        return fromAddressSet;
+    }
+
+    public Set<EMailer> getCcAddressSet() {
+        return ccAddressSet;
+    }
+
+    public Set<EMailer> getBccAddressSet() {
+        return bccAddressSet;
+    }
+
+    public Set<EMailer> getReplyToAddressSet() {
+        return replyToAddressSet;
+    }
+
+    public Set<String> getSubjectSet() {
+        return subjectSet;
+    }
+
+    public Optional<ZonedDateTime> getSentDate() {
+        return sentDate;
+    }
+
+    public Multimap<String, String> getHeaders() {
+        return headers;
+    }
+
+    public Optional<String> getMessageID() {
+        return messageID;
+    }
+}
diff --git a/mailbox/elasticsearch-v6/src/main/java/org/apache/james/mailbox/elasticsearch/v6/json/IndexableMessage.java b/mailbox/elasticsearch-v6/src/main/java/org/apache/james/mailbox/elasticsearch/v6/json/IndexableMessage.java
new file mode 100644
index 0000000..221aa91
--- /dev/null
+++ b/mailbox/elasticsearch-v6/src/main/java/org/apache/james/mailbox/elasticsearch/v6/json/IndexableMessage.java
@@ -0,0 +1,471 @@
+/****************************************************************
+ * 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.mailbox.elasticsearch.v6.json;
+
+import java.io.IOException;
+import java.time.Instant;
+import java.time.ZoneId;
+import java.time.ZonedDateTime;
+import java.util.List;
+import java.util.Optional;
+import java.util.stream.Collectors;
+import java.util.stream.Stream;
+
+import org.apache.james.core.User;
+import org.apache.james.mailbox.elasticsearch.v6.IndexAttachments;
+import org.apache.james.mailbox.elasticsearch.v6.query.DateResolutionFormater;
+import org.apache.james.mailbox.extractor.TextExtractor;
+import org.apache.james.mailbox.store.mail.model.MailboxMessage;
+import org.apache.james.mailbox.store.mail.model.Property;
+import org.apache.james.mailbox.store.mail.model.impl.PropertyBuilder;
+import org.apache.james.mailbox.store.mail.model.impl.SimpleProperty;
+import org.apache.james.mailbox.store.search.SearchUtil;
+import org.apache.james.mime4j.MimeException;
+
+import com.fasterxml.jackson.annotation.JsonProperty;
+import com.github.steveash.guavate.Guavate;
+import com.google.common.base.Preconditions;
+import com.google.common.base.Strings;
+import com.google.common.collect.ImmutableList;
+import com.google.common.collect.Multimap;
+
+public class IndexableMessage {
+
+    public static class Builder {
+        private static ZonedDateTime getSanitizedInternalDate(MailboxMessage message, ZoneId zoneId) {
+            if (message.getInternalDate() == null) {
+                return ZonedDateTime.now();
+            }
+            return ZonedDateTime.ofInstant(
+                    Instant.ofEpochMilli(message.getInternalDate().getTime()),
+                    zoneId);
+        }
+        
+        private IndexAttachments indexAttachments;
+        private MailboxMessage message;
+        private TextExtractor textExtractor;
+        private List<User> users;
+
+        private ZoneId zoneId;
+
+        private Builder() {
+        }
+
+        public IndexableMessage build() {
+            Preconditions.checkNotNull(message.getMailboxId());
+            Preconditions.checkNotNull(users);
+            Preconditions.checkNotNull(textExtractor);
+            Preconditions.checkNotNull(indexAttachments);
+            Preconditions.checkNotNull(zoneId);
+            Preconditions.checkState(!users.isEmpty());
+
+            try {
+                return instanciateIndexedMessage();
+            } catch (IOException | MimeException e) {
+                throw new RuntimeException(e);
+            }
+        }
+
+        public Builder extractor(TextExtractor textExtractor) {
+            this.textExtractor = textExtractor;
+            return this;
+        }
+
+        public Builder indexAttachments(IndexAttachments indexAttachments) {
+            this.indexAttachments = indexAttachments;
+            return this;
+        }
+
+        public Builder message(MailboxMessage message) {
+            this.message = message;
+            return this;
+        }
+
+        public Builder users(List<User> users) {
+            this.users = users;
+            return this;
+        }
+
+        public Builder zoneId(ZoneId zoneId) {
+            this.zoneId = zoneId;
+            return this;
+        }
+
+        private boolean computeHasAttachment(MailboxMessage message) {
+            return message.getProperties()
+                    .stream()
+                    .anyMatch(property -> property.equals(HAS_ATTACHMENT_PROPERTY));
+        }
+
+        private IndexableMessage instanciateIndexedMessage() throws IOException, MimeException {
+            String messageId = SearchUtil.getSerializedMessageIdIfSupportedByUnderlyingStorageOrNull(message);
+            MimePart parsingResult = new MimePartParser(message, textExtractor).parse();
+
+            List<String> stringifiedUsers = users.stream()
+                    .map(User::asString)
+                    .collect(Guavate.toImmutableList());
+
+            Optional<String> bodyText = parsingResult.locateFirstTextBody();
+            Optional<String> bodyHtml = parsingResult.locateFirstHtmlBody();
+
+            boolean hasAttachment = computeHasAttachment(message);
+            List<MimePart> attachments = setFlattenedAttachments(parsingResult, indexAttachments);
+
+            HeaderCollection headerCollection = parsingResult.getHeaderCollection();
+            ZonedDateTime internalDate = getSanitizedInternalDate(message, zoneId);
+
+            Multimap<String, String> headers = headerCollection.getHeaders();
+            Subjects subjects = Subjects.from(headerCollection.getSubjectSet());
+            EMailers from = EMailers.from(headerCollection.getFromAddressSet());
+            EMailers to = EMailers.from(headerCollection.getToAddressSet());
+            EMailers replyTo = EMailers.from(headerCollection.getReplyToAddressSet());
+            EMailers cc = EMailers.from(headerCollection.getCcAddressSet());
+            EMailers bcc = EMailers.from(headerCollection.getBccAddressSet());
+            String sentDate = DateResolutionFormater.DATE_TIME_FOMATTER.format(headerCollection.getSentDate().orElse(internalDate));
+            Optional<String> mimeMessageID = headerCollection.getMessageID();
+
+            String text = Stream.of(from.serialize(),
+                        to.serialize(),
+                        cc.serialize(),
+                        bcc.serialize(),
+                        subjects.serialize(),
+                        bodyText.orElse(null),
+                        bodyHtml.orElse(null))
+                    .filter(str -> !Strings.isNullOrEmpty(str))
+                    .collect(Collectors.joining(" "));
+
+            long uid = message.getUid().asLong();
+            String mailboxId = message.getMailboxId().serialize();
+            long modSeq = message.getModSeq();
+            long size = message.getFullContentOctets();
+            String date = DateResolutionFormater.DATE_TIME_FOMATTER.format(getSanitizedInternalDate(message, zoneId));
+            String mediaType = message.getMediaType();
+            String subType = message.getSubType();
+            boolean isAnswered = message.isAnswered();
+            boolean isDeleted = message.isDeleted();
+            boolean isDraft = message.isDraft();
+            boolean isFlagged = message.isFlagged();
+            boolean isRecent = message.isRecent();
+            boolean isUnRead = !message.isSeen();
+            String[] userFlags = message.createFlags().getUserFlags();
+            List<Property> properties = message.getProperties();
+
+            return new IndexableMessage(
+                    attachments,
+                    bcc,
+                    bodyHtml,
+                    bodyText,
+                    cc,
+                    date,
+                    from,
+                    hasAttachment,
+                    headers,
+                    isAnswered,
+                    isDeleted,
+                    isDraft,
+                    isFlagged,
+                    isRecent,
+                    isUnRead,
+                    mailboxId,
+                    mediaType,
+                    messageId,
+                    modSeq,
+                    properties,
+                    replyTo,
+                    sentDate,
+                    size,
+                    subjects,
+                    subType,
+                    text,
+                    to,
+                    uid,
+                    userFlags,
+                    stringifiedUsers,
+                    mimeMessageID);
+        }
+
+        private List<MimePart> setFlattenedAttachments(MimePart parsingResult, IndexAttachments indexAttachments) {
+            if (IndexAttachments.YES.equals(indexAttachments)) {
+                return parsingResult.getAttachmentsStream()
+                    .collect(Guavate.toImmutableList());
+            } else {
+                return ImmutableList.of();
+            }
+        }
+    }
+
+    public static final SimpleProperty HAS_ATTACHMENT_PROPERTY = new SimpleProperty(PropertyBuilder.JAMES_INTERNALS, PropertyBuilder.HAS_ATTACHMENT, "true");
+
+    public static Builder builder() {
+        return new Builder();
+    }
+
+    private final List<MimePart> attachments;
+    private final EMailers bcc;
+    private final Optional<String> bodyHtml;
+    private final Optional<String> bodyText;
+    private final EMailers cc;
+    private final String date;
+    private final EMailers from;
+    private final boolean hasAttachment;
+    private final Multimap<String, String> headers;
+    private final boolean isAnswered;
+    private final boolean isDeleted;
+    private final boolean isDraft;
+    private final boolean isFlagged;
+    private final boolean isRecent;
+    private final boolean isUnRead;
+    private final String mailboxId;
+    private final String mediaType;
+    private final String messageId;
+    private final long modSeq;
+    private final List<Property> properties;
+    private final EMailers replyTo;
+    private final String sentDate;
+    private final long size;
+    private final Subjects subjects;
+    private final String subType;
+    private final String text;
+    private final EMailers to;
+    private final long uid;
+    private final String[] userFlags;
+    private final List<String> users;
+    private final Optional<String> mimeMessageID;
+
+    private IndexableMessage(
+            List<MimePart> attachments,
+            EMailers bcc,
+            Optional<String> bodyHtml,
+            Optional<String> bodyText,
+            EMailers cc,
+            String date,
+            EMailers from,
+            boolean hasAttachment,
+            Multimap<String, String> headers,
+            boolean isAnswered,
+            boolean isDeleted,
+            boolean isDraft,
+            boolean isFlagged,
+            boolean isRecent,
+            boolean isUnRead,
+            String mailboxId,
+            String mediaType,
+            String messageId,
+            long modSeq,
+            List<Property> properties,
+            EMailers replyTo,
+            String sentDate,
+            long size,
+            Subjects subjects,
+            String subType,
+            String text,
+            EMailers to,
+            long uid,
+            String[] userFlags,
+            List<String> users,
+            Optional<String> mimeMessageID) {
+        this.attachments = attachments;
+        this.bcc = bcc;
+        this.bodyHtml = bodyHtml;
+        this.bodyText = bodyText;
+        this.cc = cc;
+        this.date = date;
+        this.from = from;
+        this.hasAttachment = hasAttachment;
+        this.headers = headers;
+        this.isAnswered = isAnswered;
+        this.isDeleted = isDeleted;
+        this.isDraft = isDraft;
+        this.isFlagged = isFlagged;
+        this.isRecent = isRecent;
+        this.isUnRead = isUnRead;
+        this.mailboxId = mailboxId;
+        this.mediaType = mediaType;
+        this.messageId = messageId;
+        this.modSeq = modSeq;
+        this.properties = properties;
+        this.replyTo = replyTo;
+        this.sentDate = sentDate;
+        this.size = size;
+        this.subjects = subjects;
+        this.subType = subType;
+        this.text = text;
+        this.to = to;
+        this.uid = uid;
+        this.userFlags = userFlags;
+        this.users = users;
+        this.mimeMessageID = mimeMessageID;
+    }
+
+    @JsonProperty(JsonMessageConstants.ATTACHMENTS)
+    public List<MimePart> getAttachments() {
+        return attachments;
+    }
+    
+    @JsonProperty(JsonMessageConstants.BCC)
+    public EMailers getBcc() {
+        return bcc;
+    }
+    
+    @JsonProperty(JsonMessageConstants.HTML_BODY)
+    public Optional<String> getBodyHtml() {
+        return bodyHtml;
+    }
+
+    @JsonProperty(JsonMessageConstants.TEXT_BODY)
+    public Optional<String> getBodyText() {
+        return bodyText;
+    }
+
+    @JsonProperty(JsonMessageConstants.CC)
+    public EMailers getCc() {
+        return cc;
+    }
+
+    @JsonProperty(JsonMessageConstants.DATE)
+    public String getDate() {
+        return date;
+    }
+
+    @JsonProperty(JsonMessageConstants.FROM)
+    public EMailers getFrom() {
+        return from;
+    }
+
+    @JsonProperty(JsonMessageConstants.HAS_ATTACHMENT)
+    public boolean getHasAttachment() {
+        return hasAttachment;
+    }
+
+    @JsonProperty(JsonMessageConstants.HEADERS)
+    public Multimap<String, String> getHeaders() {
+        return headers;
+    }
+
+    @JsonProperty(JsonMessageConstants.MAILBOX_ID)
+    public String getMailboxId() {
+        return mailboxId;
+    }
+
+    @JsonProperty(JsonMessageConstants.MEDIA_TYPE)
+    public String getMediaType() {
+        return mediaType;
+    }
+
+    @JsonProperty(JsonMessageConstants.MESSAGE_ID)
+    public String getMessageId() {
+        return messageId;
+    }
+
+    @JsonProperty(JsonMessageConstants.MODSEQ)
+    public long getModSeq() {
+        return modSeq;
+    }
+
+    @JsonProperty(JsonMessageConstants.PROPERTIES)
+    public List<Property> getProperties() {
+        return properties;
+    }
+
+    @JsonProperty(JsonMessageConstants.REPLY_TO)
+    public EMailers getReplyTo() {
+        return replyTo;
+    }
+
+    @JsonProperty(JsonMessageConstants.SENT_DATE)
+    public String getSentDate() {
+        return sentDate;
+    }
+
+    @JsonProperty(JsonMessageConstants.SIZE)
+    public long getSize() {
+        return size;
+    }
+
+    @JsonProperty(JsonMessageConstants.SUBJECT)
+    public Subjects getSubjects() {
+        return subjects;
+    }
+
+    @JsonProperty(JsonMessageConstants.SUBTYPE)
+    public String getSubType() {
+        return subType;
+    }
+
+    @JsonProperty(JsonMessageConstants.TEXT)
+    public String getText() {
+        return text;
+    }
+
+    @JsonProperty(JsonMessageConstants.TO)
+    public EMailers getTo() {
+        return to;
+    }
+
+    @JsonProperty(JsonMessageConstants.UID)
+    public Long getUid() {
+        return uid;
+    }
+
+    @JsonProperty(JsonMessageConstants.USER_FLAGS)
+    public String[] getUserFlags() {
+        return userFlags;
+    }
+
+    @JsonProperty(JsonMessageConstants.USERS)
+    public List<String> getUsers() {
+        return users;
+    }
+
+    @JsonProperty(JsonMessageConstants.IS_ANSWERED)
+    public boolean isAnswered() {
+        return isAnswered;
+    }
+
+    @JsonProperty(JsonMessageConstants.IS_DELETED)
+    public boolean isDeleted() {
+        return isDeleted;
+    }
+
+    @JsonProperty(JsonMessageConstants.IS_DRAFT)
+    public boolean isDraft() {
+        return isDraft;
+    }
+
+    @JsonProperty(JsonMessageConstants.IS_FLAGGED)
+    public boolean isFlagged() {
+        return isFlagged;
+    }
+
+    @JsonProperty(JsonMessageConstants.IS_RECENT)
+    public boolean isRecent() {
+        return isRecent;
+    }
+
+    @JsonProperty(JsonMessageConstants.IS_UNREAD)
+    public boolean isUnRead() {
+        return isUnRead;
+    }
+
+    @JsonProperty(JsonMessageConstants.MIME_MESSAGE_ID)
+    public Optional<String> getMimeMessageID() {
+        return mimeMessageID;
+    }
+}
diff --git a/mailbox/elasticsearch-v6/src/main/java/org/apache/james/mailbox/elasticsearch/v6/json/JsonMessageConstants.java b/mailbox/elasticsearch-v6/src/main/java/org/apache/james/mailbox/elasticsearch/v6/json/JsonMessageConstants.java
new file mode 100644
index 0000000..e747c9f
--- /dev/null
+++ b/mailbox/elasticsearch-v6/src/main/java/org/apache/james/mailbox/elasticsearch/v6/json/JsonMessageConstants.java
@@ -0,0 +1,83 @@
+/****************************************************************
+ * Licensed to the Apache Software Foundation (ASF) under one   *
+ * or more contributor license agreements.  See the NOTICE file *
+ * distributed with this work for additional information        *
+ * regarding copyright ownership.  The ASF licenses this file   *
+ * to you under the Apache License, Version 2.0 (the            *
+ * "License"); you may not use this file except in compliance   *
+ * with the License.  You may obtain a copy of the License at   *
+ *                                                              *
+ *   http://www.apache.org/licenses/LICENSE-2.0                 *
+ *                                                              *
+ * Unless required by applicable law or agreed to in writing,   *
+ * software distributed under the License is distributed on an  *
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY       *
+ * KIND, either express or implied.  See the License for the    *
+ * specific language governing permissions and limitations      *
+ * under the License.                                           *
+ ****************************************************************/
+
+package org.apache.james.mailbox.elasticsearch.v6.json;
+
+public interface JsonMessageConstants {
+
+    /*
+    Properties defined by JMAP
+     */
+    String MESSAGE_ID = "messageId";
+    String UID = "uid";
+    String MAILBOX_ID = "mailboxId";
+    String USERS = "users";
+    String IS_UNREAD = "isUnread";
+    String IS_FLAGGED = "isFlagged";
+    String IS_ANSWERED = "isAnswered";
+    String IS_DRAFT = "isDraft";
+    String HEADERS = "headers";
+    String FROM = "from";
+    String TO = "to";
+    String CC = "cc";
+    String BCC = "bcc";
+    String REPLY_TO = "replyTo";
+    String SUBJECT = "subject";
+    String DATE = "date";
+    String SIZE = "size";
+    String TEXT_BODY = "textBody";
+    String HTML_BODY = "htmlBody";
+    String SENT_DATE = "sentDate";
+    String ATTACHMENTS = "attachments";
+    String TEXT = "text";
+    String MIME_MESSAGE_ID = "mimeMessageID";
+
+    /*
+    James properties we can easily get
+     */
+    String PROPERTIES = "properties";
+    String MODSEQ = "modSeq";
+    String USER_FLAGS = "userFlags";
+    String IS_RECENT = "isRecent";
+    String IS_DELETED = "isDeleted";
+    String MEDIA_TYPE = "mediaType";
+    String SUBTYPE = "subtype";
+    String HAS_ATTACHMENT = "hasAttachment";
+
+    interface EMailer {
+        String NAME = "name";
+        String ADDRESS = "address";
+    }
+
+    interface Attachment {
+        String TEXT_CONTENT = "textContent";
+        String MEDIA_TYPE = "mediaType";
+        String SUBTYPE = "subtype";
+        String CONTENT_DISPOSITION = "contentDisposition";
+        String FILENAME = "fileName";
+        String FILE_EXTENSION = "fileExtension";
+    }
+
+    interface Property {
+        String NAMESPACE = "namespace";
+        String NAME = "name";
+        String VALUE = "value";
+    }
+
+}
diff --git a/mailbox/elasticsearch-v6/src/main/java/org/apache/james/mailbox/elasticsearch/v6/json/MessageToElasticSearchJson.java b/mailbox/elasticsearch-v6/src/main/java/org/apache/james/mailbox/elasticsearch/v6/json/MessageToElasticSearchJson.java
new file mode 100644
index 0000000..95d9c5d
--- /dev/null
+++ b/mailbox/elasticsearch-v6/src/main/java/org/apache/james/mailbox/elasticsearch/v6/json/MessageToElasticSearchJson.java
@@ -0,0 +1,86 @@
+/****************************************************************
+ * 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.mailbox.elasticsearch.v6.json;
+
+import java.time.ZoneId;
+import java.util.List;
+
+import javax.inject.Inject;
+import javax.mail.Flags;
+
+import org.apache.james.core.User;
+import org.apache.james.mailbox.elasticsearch.v6.IndexAttachments;
+import org.apache.james.mailbox.extractor.TextExtractor;
+import org.apache.james.mailbox.store.mail.model.MailboxMessage;
+
+import com.fasterxml.jackson.core.JsonProcessingException;
+import com.fasterxml.jackson.databind.ObjectMapper;
+import com.fasterxml.jackson.datatype.guava.GuavaModule;
+import com.fasterxml.jackson.datatype.jdk8.Jdk8Module;
+import com.google.common.base.Preconditions;
+
+public class MessageToElasticSearchJson {
+
+    private final ObjectMapper mapper;
+    private final TextExtractor textExtractor;
+    private final ZoneId zoneId;
+    private final IndexAttachments indexAttachments;
+
+    public MessageToElasticSearchJson(TextExtractor textExtractor, ZoneId zoneId, IndexAttachments indexAttachments) {
+        this.textExtractor = textExtractor;
+        this.zoneId = zoneId;
+        this.indexAttachments = indexAttachments;
+        this.mapper = new ObjectMapper();
+        this.mapper.registerModule(new GuavaModule());
+        this.mapper.registerModule(new Jdk8Module());
+    }
+
+    @Inject
+    public MessageToElasticSearchJson(TextExtractor textExtractor, IndexAttachments indexAttachments) {
+        this(textExtractor, ZoneId.systemDefault(), indexAttachments);
+    }
+
+    public String convertToJson(MailboxMessage message, List<User> users) throws JsonProcessingException {
+        Preconditions.checkNotNull(message);
+
+        return mapper.writeValueAsString(IndexableMessage.builder()
+                .message(message)
+                .users(users)
+                .extractor(textExtractor)
+                .zoneId(zoneId)
+                .indexAttachments(indexAttachments)
+                .build());
+    }
+
+    public String convertToJsonWithoutAttachment(MailboxMessage message, List<User> users) throws JsonProcessingException {
+        return mapper.writeValueAsString(IndexableMessage.builder()
+                .message(message)
+                .users(users)
+                .extractor(textExtractor)
+                .zoneId(zoneId)
+                .indexAttachments(IndexAttachments.NO)
+                .build());
+    }
+
+    public String getUpdatedJsonMessagePart(Flags flags, long modSeq) throws JsonProcessingException {
+        Preconditions.checkNotNull(flags);
+        return mapper.writeValueAsString(new MessageUpdateJson(flags, modSeq));
+    }
+}
diff --git a/mailbox/elasticsearch-v6/src/main/java/org/apache/james/mailbox/elasticsearch/v6/json/MessageUpdateJson.java b/mailbox/elasticsearch-v6/src/main/java/org/apache/james/mailbox/elasticsearch/v6/json/MessageUpdateJson.java
new file mode 100644
index 0000000..f8b2510
--- /dev/null
+++ b/mailbox/elasticsearch-v6/src/main/java/org/apache/james/mailbox/elasticsearch/v6/json/MessageUpdateJson.java
@@ -0,0 +1,79 @@
+
+
+/****************************************************************
+ * 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.mailbox.elasticsearch.v6.json;
+
+import javax.mail.Flags;
+
+import com.fasterxml.jackson.annotation.JsonProperty;
+
+public class MessageUpdateJson {
+
+    private final Flags flags;
+    private final long modSeq;
+
+    public MessageUpdateJson(Flags flags, long modSeq) {
+        this.flags = flags;
+        this.modSeq = modSeq;
+    }
+
+    @JsonProperty(JsonMessageConstants.IS_ANSWERED)
+    public boolean isAnswered() {
+        return flags.contains(Flags.Flag.ANSWERED);
+    }
+
+    @JsonProperty(JsonMessageConstants.IS_DELETED)
+    public boolean isDeleted() {
+        return flags.contains(Flags.Flag.DELETED);
+    }
+
+    @JsonProperty(JsonMessageConstants.IS_DRAFT)
+    public boolean isDraft() {
+        return flags.contains(Flags.Flag.DRAFT);
+    }
+
+    @JsonProperty(JsonMessageConstants.IS_FLAGGED)
+    public boolean isFlagged() {
+        return flags.contains(Flags.Flag.FLAGGED);
+    }
+
+    @JsonProperty(JsonMessageConstants.IS_RECENT)
+    public boolean isRecent() {
+        return flags.contains(Flags.Flag.RECENT);
+    }
+
+    @JsonProperty(JsonMessageConstants.IS_UNREAD)
+    public boolean isUnRead() {
+        return ! flags.contains(Flags.Flag.SEEN);
+    }
+
+
+    @JsonProperty(JsonMessageConstants.USER_FLAGS)
+    public String[] getUserFlags() {
+        return flags.getUserFlags();
+    }
+
+    @JsonProperty(JsonMessageConstants.MODSEQ)
+    public long getModSeq() {
+        return modSeq;
+    }
+
+}
diff --git a/mailbox/elasticsearch-v6/src/main/java/org/apache/james/mailbox/elasticsearch/v6/json/MimePart.java b/mailbox/elasticsearch-v6/src/main/java/org/apache/james/mailbox/elasticsearch/v6/json/MimePart.java
new file mode 100644
index 0000000..3d700cb
--- /dev/null
+++ b/mailbox/elasticsearch-v6/src/main/java/org/apache/james/mailbox/elasticsearch/v6/json/MimePart.java
@@ -0,0 +1,303 @@
+/****************************************************************
+ * 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.mailbox.elasticsearch.v6.json;
+
+import java.io.InputStream;
+import java.nio.charset.Charset;
+import java.nio.charset.StandardCharsets;
+import java.util.List;
+import java.util.Optional;
+import java.util.stream.Stream;
+
+import org.apache.commons.io.FilenameUtils;
+import org.apache.commons.io.IOUtils;
+import org.apache.james.mailbox.extractor.ParsedContent;
+import org.apache.james.mailbox.extractor.TextExtractor;
+import org.apache.james.mailbox.store.extractor.DefaultTextExtractor;
+import org.apache.james.mime4j.stream.Field;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+import com.fasterxml.jackson.annotation.JsonIgnore;
+import com.fasterxml.jackson.annotation.JsonProperty;
+import com.google.common.base.Preconditions;
+import com.google.common.collect.ImmutableMap;
+import com.google.common.collect.Lists;
+import com.google.common.collect.Multimap;
+
+public class MimePart {
+
+    public static class Builder implements MimePartContainerBuilder {
+
+        private final HeaderCollection.Builder headerCollectionBuilder;
+        private Optional<InputStream> bodyContent;
+        private final List<MimePart> children;
+        private Optional<String> mediaType;
+        private Optional<String> subType;
+        private Optional<String> fileName;
+        private Optional<String> fileExtension;
+        private Optional<String> contentDisposition;
+        private Optional<Charset> charset;
+        private TextExtractor textExtractor;
+
+        private Builder() {
+            children = Lists.newArrayList();
+            headerCollectionBuilder = HeaderCollection.builder();
+            this.bodyContent = Optional.empty();
+            this.mediaType = Optional.empty();
+            this.subType = Optional.empty();
+            this.fileName = Optional.empty();
+            this.fileExtension = Optional.empty();
+            this.contentDisposition = Optional.empty();
+            this.charset = Optional.empty();
+            this.textExtractor = new DefaultTextExtractor();
+        }
+
+        @Override
+        public Builder addToHeaders(Field field) {
+            headerCollectionBuilder.add(field);
+            return this;
+        }
+
+        @Override
+        public Builder addBodyContent(InputStream bodyContent) {
+            this.bodyContent = Optional.of(bodyContent);
+            return this;
+        }
+
+        @Override
+        public Builder addChild(MimePart mimePart) {
+            children.add(mimePart);
+            return this;
+        }
+
+        @Override
+        public Builder addFileName(String fileName) {
+            this.fileName = Optional.ofNullable(fileName);
+            this.fileExtension = this.fileName.map(FilenameUtils::getExtension);
+            return this;
+        }
+
+        @Override
+        public Builder addMediaType(String mediaType) {
+            this.mediaType = Optional.ofNullable(mediaType);
+            return this;
+        }
+
+        @Override
+        public Builder addSubType(String subType) {
+            this.subType = Optional.ofNullable(subType);
+            return this;
+        }
+
+        @Override
+        public Builder addContentDisposition(String contentDisposition) {
+            this.contentDisposition = Optional.ofNullable(contentDisposition);
+            return this;
+        }
+
+        @Override
+        public MimePartContainerBuilder using(TextExtractor textExtractor) {
+            Preconditions.checkArgument(textExtractor != null, "Provided text extractor should not be null");
+            this.textExtractor = textExtractor;
+            return this;
+        }
+
+        @Override
+        public MimePartContainerBuilder charset(Charset charset) {
+            this.charset = Optional.of(charset);
+            return this;
+        }
+
+        @Override
+        public MimePart build() {
+            Optional<ParsedContent> parsedContent = parseContent(textExtractor);
+            return new MimePart(
+                headerCollectionBuilder.build(),
+                parsedContent.flatMap(ParsedContent::getTextualContent),
+                mediaType,
+                subType,
+                fileName,
+                fileExtension,
+                contentDisposition,
+                children);
+        }
+
+        private Optional<ParsedContent> parseContent(TextExtractor textExtractor) {
+            if (bodyContent.isPresent()) {
+                try {
+                    return Optional.of(extractText(textExtractor, bodyContent.get()));
+                } catch (Throwable e) {
+                    LOGGER.warn("Failed parsing attachment", e);
+                }
+            }
+            return Optional.empty();
+        }
+
+        private ParsedContent extractText(TextExtractor textExtractor, InputStream bodyContent) throws Exception {
+            if (isTextBody()) {
+                return new ParsedContent(
+                        Optional.ofNullable(IOUtils.toString(bodyContent, charset.orElse(StandardCharsets.UTF_8))),
+                        ImmutableMap.of());
+            }
+            return textExtractor.extractContent(
+                bodyContent,
+                computeContentType().orElse(null));
+        }
+
+        private Boolean isTextBody() {
+            return mediaType.map("text"::equals).orElse(false);
+        }
+
+        private Optional<String> computeContentType() {
+            if (mediaType.isPresent() && subType.isPresent()) {
+                return Optional.of(mediaType.get() + "/" + subType.get());
+            } else {
+                return Optional.empty();
+            }
+        }
+
+    }
+    
+    public static Builder builder() {
+        return new Builder();
+    }
+
+    private static final Logger LOGGER = LoggerFactory.getLogger(MimePart.class);
+
+    private final HeaderCollection headerCollection;
+    private final Optional<String> bodyTextContent;
+    private final Optional<String> mediaType;
+    private final Optional<String> subType;
+    private final Optional<String> fileName;
+    private final Optional<String> fileExtension;
+    private final Optional<String> contentDisposition;
+    private final List<MimePart> attachments;
+
+    private MimePart(HeaderCollection headerCollection, Optional<String> bodyTextContent, Optional<String> mediaType,
+                    Optional<String> subType, Optional<String> fileName, Optional<String> fileExtension,
+                    Optional<String> contentDisposition, List<MimePart> attachments) {
+        this.headerCollection = headerCollection;
+        this.mediaType = mediaType;
+        this.subType = subType;
+        this.fileName = fileName;
+        this.fileExtension = fileExtension;
+        this.contentDisposition = contentDisposition;
+        this.attachments = attachments;
+        this.bodyTextContent = bodyTextContent;
+    }
+
+    @JsonIgnore
+    public List<MimePart> getAttachments() {
+        return attachments;
+    }
+
+    @JsonIgnore
+    public HeaderCollection getHeaderCollection() {
+        return headerCollection;
+    }
+
+    @JsonProperty(JsonMessageConstants.HEADERS)
+    public Multimap<String, String> getHeaders() {
+        return headerCollection.getHeaders();
+    }
+
+    @JsonProperty(JsonMessageConstants.Attachment.FILENAME)
+    public Optional<String> getFileName() {
+        return fileName;
+    }
+
+    @JsonProperty(JsonMessageConstants.Attachment.FILE_EXTENSION)
+    public Optional<String> getFileExtension() {
+        return fileExtension;
+    }
+
+    @JsonProperty(JsonMessageConstants.Attachment.MEDIA_TYPE)
+    public Optional<String> getMediaType() {
+        return mediaType;
+    }
+
+    @JsonProperty(JsonMessageConstants.Attachment.SUBTYPE)
+    public Optional<String> getSubType() {
+        return subType;
+    }
+
+    @JsonProperty(JsonMessageConstants.Attachment.CONTENT_DISPOSITION)
+    public Optional<String> getContentDisposition() {
+        return contentDisposition;
+    }
+
+    @JsonProperty(JsonMessageConstants.Attachment.TEXT_CONTENT)
+    public Optional<String> getTextualBody() {
+        return bodyTextContent;
+    }
+
+    @JsonIgnore
+    public Optional<String> locateFirstTextBody() {
+        return firstBody(textAttachments()
+                .filter(this::isPlainSubType));
+    }
+
+    @JsonIgnore
+    public Optional<String> locateFirstHtmlBody() {
+        return firstBody(textAttachments()
+                .filter(this::isHtmlSubType));
+    }
+
+    private Optional<String> firstBody(Stream<MimePart> mimeParts) {
+        return mimeParts
+                .map((mimePart) -> mimePart.bodyTextContent)
+                .filter(Optional::isPresent)
+                .map(Optional::get)
+                .findFirst();
+    }
+
+    private Stream<MimePart> textAttachments() {
+        return Stream.concat(
+                    Stream.of(this),
+                    attachments.stream())
+                .filter(this::isTextMediaType);
+    }
+
+    private boolean isTextMediaType(MimePart mimePart) {
+        return mimePart.getMediaType()
+                .filter("text"::equals)
+                .isPresent();
+    }
+
+    private boolean isPlainSubType(MimePart mimePart) {
+        return mimePart.getSubType()
+                .filter("plain"::equals)
+                .isPresent();
+    }
+
+    private boolean isHtmlSubType(MimePart mimePart) {
+        return mimePart.getSubType()
+                .filter("html"::equals)
+                .isPresent();
+    }
+
+    @JsonIgnore
+    public Stream<MimePart> getAttachmentsStream() {
+        return attachments.stream()
+                .flatMap((mimePart) -> Stream.concat(Stream.of(mimePart), mimePart.getAttachmentsStream()));
+    }
+
+}
diff --git a/mailbox/elasticsearch-v6/src/main/java/org/apache/james/mailbox/elasticsearch/v6/json/MimePartContainerBuilder.java b/mailbox/elasticsearch-v6/src/main/java/org/apache/james/mailbox/elasticsearch/v6/json/MimePartContainerBuilder.java
new file mode 100644
index 0000000..5a12008
--- /dev/null
+++ b/mailbox/elasticsearch-v6/src/main/java/org/apache/james/mailbox/elasticsearch/v6/json/MimePartContainerBuilder.java
@@ -0,0 +1,50 @@
+/****************************************************************
+ * 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.mailbox.elasticsearch.v6.json;
+
+import java.io.InputStream;
+import java.nio.charset.Charset;
+
+import org.apache.james.mailbox.extractor.TextExtractor;
+import org.apache.james.mime4j.stream.Field;
+
+public interface MimePartContainerBuilder {
+
+    MimePart build();
+
+    MimePartContainerBuilder using(TextExtractor textExtractor);
+
+    MimePartContainerBuilder addToHeaders(Field field);
+
+    MimePartContainerBuilder addBodyContent(InputStream bodyContent);
+
+    MimePartContainerBuilder addChild(MimePart mimePart);
+
+    MimePartContainerBuilder addFileName(String fileName);
+
+    MimePartContainerBuilder charset(Charset charset);
+
+    MimePartContainerBuilder addMediaType(String mediaType);
+
+    MimePartContainerBuilder addSubType(String subType);
+
+    MimePartContainerBuilder addContentDisposition(String contentDisposition);
+
+}
diff --git a/mailbox/elasticsearch-v6/src/main/java/org/apache/james/mailbox/elasticsearch/v6/json/MimePartParser.java b/mailbox/elasticsearch-v6/src/main/java/org/apache/james/mailbox/elasticsearch/v6/json/MimePartParser.java
new file mode 100644
index 0000000..0f2a8ff
--- /dev/null
+++ b/mailbox/elasticsearch-v6/src/main/java/org/apache/james/mailbox/elasticsearch/v6/json/MimePartParser.java
@@ -0,0 +1,129 @@
+/****************************************************************
+ * 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.mailbox.elasticsearch.v6.json;
+
+import java.io.IOException;
+import java.nio.charset.Charset;
+import java.util.Deque;
+import java.util.LinkedList;
+import java.util.Optional;
+
+import org.apache.james.mailbox.extractor.TextExtractor;
+import org.apache.james.mailbox.store.mail.model.Message;
+import org.apache.james.mime4j.MimeException;
+import org.apache.james.mime4j.message.DefaultBodyDescriptorBuilder;
+import org.apache.james.mime4j.message.MaximalBodyDescriptor;
+import org.apache.james.mime4j.stream.EntityState;
+import org.apache.james.mime4j.stream.MimeConfig;
+import org.apache.james.mime4j.stream.MimeTokenStream;
+
+import com.google.common.base.Preconditions;
+
+public class MimePartParser {
+
+    private final Message message;
+    private final TextExtractor textExtractor;
+    private final MimeTokenStream stream;
+    private final Deque<MimePartContainerBuilder> builderStack;
+    private MimePart result;
+    private MimePartContainerBuilder currentlyBuildMimePart;
+
+    public MimePartParser(Message message, TextExtractor textExtractor) {
+        this.message = message;
+        this.textExtractor = textExtractor;
+        this.builderStack = new LinkedList<>();
+        this.currentlyBuildMimePart = new RootMimePartContainerBuilder();
+        this.stream = new MimeTokenStream(
+            MimeConfig.PERMISSIVE,
+            new DefaultBodyDescriptorBuilder());
+    }
+
+    public MimePart parse() throws IOException, MimeException {
+        stream.parse(message.getFullContent());
+        for (EntityState state = stream.getState(); state != EntityState.T_END_OF_STREAM; state = stream.next()) {
+            processMimePart(stream, state);
+        }
+        return result;
+    }
+
+    private void processMimePart(MimeTokenStream stream, EntityState state) {
+        switch (state) {
+            case T_START_MULTIPART:
+            case T_START_MESSAGE:
+                stackCurrent();
+                break;
+            case T_START_HEADER:
+                currentlyBuildMimePart = MimePart.builder();
+                break;
+            case T_FIELD:
+                currentlyBuildMimePart.addToHeaders(stream.getField());
+                break;
+            case T_BODY:
+                manageBodyExtraction(stream);
+                closeMimePart();
+                break;
+            case T_END_MULTIPART:
+            case T_END_MESSAGE:
+                unstackToCurrent();
+                closeMimePart();
+                break;
+            default:
+                break;
+        }
+    }
+
+    private void stackCurrent() {
+        builderStack.push(currentlyBuildMimePart);
+        currentlyBuildMimePart = null;
+    }
+
+    private void unstackToCurrent() {
+        currentlyBuildMimePart = builderStack.pop();
+    }
+    
+    private void closeMimePart() {
+        MimePart bodyMimePart = currentlyBuildMimePart.using(textExtractor).build();
+        if (!builderStack.isEmpty()) {
+            builderStack.peek().addChild(bodyMimePart);
+        } else {
+            Preconditions.checkState(result == null);
+            result = bodyMimePart;
+        }
+    }
+
+    private void manageBodyExtraction(MimeTokenStream stream) {
+        extractMimePartBodyDescription(stream);
+        currentlyBuildMimePart.addBodyContent(stream.getDecodedInputStream());
+    }
+
+    private void extractMimePartBodyDescription(MimeTokenStream stream) {
+        MaximalBodyDescriptor descriptor = (MaximalBodyDescriptor) stream.getBodyDescriptor();
+
+        currentlyBuildMimePart.addMediaType(descriptor.getMediaType())
+            .addSubType(descriptor.getSubType())
+            .addContentDisposition(descriptor.getContentDispositionType())
+            .addFileName(descriptor.getContentDispositionFilename());
+
+        Optional.ofNullable(descriptor.getCharset())
+            .map(Charset::forName)
+            .ifPresent(currentlyBuildMimePart::charset);
+    }
+
+}
diff --git a/mailbox/elasticsearch-v6/src/main/java/org/apache/james/mailbox/elasticsearch/v6/json/RootMimePartContainerBuilder.java b/mailbox/elasticsearch-v6/src/main/java/org/apache/james/mailbox/elasticsearch/v6/json/RootMimePartContainerBuilder.java
new file mode 100644
index 0000000..415d96f
--- /dev/null
+++ b/mailbox/elasticsearch-v6/src/main/java/org/apache/james/mailbox/elasticsearch/v6/json/RootMimePartContainerBuilder.java
@@ -0,0 +1,96 @@
+/****************************************************************
+ * 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.mailbox.elasticsearch.v6.json;
+
+import java.io.InputStream;
+import java.nio.charset.Charset;
+
+import org.apache.james.mailbox.extractor.TextExtractor;
+import org.apache.james.mime4j.stream.Field;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+public class RootMimePartContainerBuilder implements MimePartContainerBuilder {
+
+    private static final Logger LOGGER = LoggerFactory.getLogger(RootMimePartContainerBuilder.class);
+
+    private MimePart rootMimePart;
+
+    @Override
+    public MimePart build() {
+        return rootMimePart;
+    }
+
+    @Override public MimePartContainerBuilder using(TextExtractor textExtractor) {
+        return this;
+    }
+
+    @Override
+    public MimePartContainerBuilder addToHeaders(Field field) {
+        LOGGER.warn("Trying to add headers to the Root MimePart container");
+        return this;
+    }
+
+    @Override
+    public MimePartContainerBuilder addBodyContent(InputStream bodyContent) {
+        LOGGER.warn("Trying to add body content to the Root MimePart container");
+        return this;
+    }
+
+    @Override
+    public MimePartContainerBuilder addChild(MimePart mimePart) {
+        if (rootMimePart == null) {
+            rootMimePart = mimePart;
+        } else {
+            LOGGER.warn("Trying to add several children to the Root MimePart container");
+        }
+        return this;
+    }
+
+    @Override
+    public MimePartContainerBuilder addFileName(String fileName) {
+        LOGGER.warn("Trying to add fineName to the Root MimePart container");
+        return this;
+    }
+
+    @Override
+    public MimePartContainerBuilder addMediaType(String mediaType) {
+        LOGGER.warn("Trying to add media type to the Root MimePart container");
+        return this;
+    }
+
+    @Override
+    public MimePartContainerBuilder addSubType(String subType) {
+        LOGGER.warn("Trying to add sub type to the Root MimePart container");
+        return this;
+    }
+
+    @Override
+    public MimePartContainerBuilder addContentDisposition(String contentDisposition) {
+        LOGGER.warn("Trying to add content disposition to the Root MimePart container");
+        return this;
+    }
+
+    @Override
+    public MimePartContainerBuilder charset(Charset charset) {
+        LOGGER.warn("Trying to add content charset to the Root MimePart container");
+        return this;
+    }
+}
diff --git a/mailbox/elasticsearch-v6/src/main/java/org/apache/james/mailbox/elasticsearch/v6/json/Serializable.java b/mailbox/elasticsearch-v6/src/main/java/org/apache/james/mailbox/elasticsearch/v6/json/Serializable.java
new file mode 100644
index 0000000..5ad6334
--- /dev/null
+++ b/mailbox/elasticsearch-v6/src/main/java/org/apache/james/mailbox/elasticsearch/v6/json/Serializable.java
@@ -0,0 +1,25 @@
+/****************************************************************
+ * 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.mailbox.elasticsearch.v6.json;
+
+public interface Serializable {
+
+    String serialize();
+}
diff --git a/mailbox/elasticsearch-v6/src/main/java/org/apache/james/mailbox/elasticsearch/v6/json/Subjects.java b/mailbox/elasticsearch-v6/src/main/java/org/apache/james/mailbox/elasticsearch/v6/json/Subjects.java
new file mode 100644
index 0000000..d962932
--- /dev/null
+++ b/mailbox/elasticsearch-v6/src/main/java/org/apache/james/mailbox/elasticsearch/v6/json/Subjects.java
@@ -0,0 +1,50 @@
+/****************************************************************
+ * 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.mailbox.elasticsearch.v6.json;
+
+import java.util.Set;
+
+import com.fasterxml.jackson.annotation.JsonValue;
+import com.google.common.base.Joiner;
+import com.google.common.base.Preconditions;
+
+public class Subjects implements Serializable {
+
+    public static Subjects from(Set<String> subjects) {
+        Preconditions.checkNotNull(subjects, "'subjects' is mandatory");
+        return new Subjects(subjects);
+    }
+
+    private final Set<String> subjects;
+
+    private Subjects(Set<String> subjects) {
+        this.subjects = subjects;
+    }
+
+    @JsonValue
+    public Set<String> getSubjects() {
+        return subjects;
+    }
+
+    @Override
+    public String serialize() {
+        return Joiner.on(" ").join(subjects);
+    }
+}
diff --git a/mailbox/elasticsearch-v6/src/main/java/org/apache/james/mailbox/elasticsearch/v6/query/CriterionConverter.java b/mailbox/elasticsearch-v6/src/main/java/org/apache/james/mailbox/elasticsearch/v6/query/CriterionConverter.java
new file mode 100644
index 0000000..19612cc
--- /dev/null
+++ b/mailbox/elasticsearch-v6/src/main/java/org/apache/james/mailbox/elasticsearch/v6/query/CriterionConverter.java
@@ -0,0 +1,310 @@
+/****************************************************************
+ * 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.mailbox.elasticsearch.v6.query;
+
+import static org.apache.james.backends.es.NodeMappingFactory.RAW;
+import static org.apache.james.backends.es.NodeMappingFactory.SPLIT_EMAIL;
+import static org.elasticsearch.index.query.QueryBuilders.boolQuery;
+import static org.elasticsearch.index.query.QueryBuilders.existsQuery;
+import static org.elasticsearch.index.query.QueryBuilders.matchAllQuery;
+import static org.elasticsearch.index.query.QueryBuilders.matchQuery;
+import static org.elasticsearch.index.query.QueryBuilders.nestedQuery;
+import static org.elasticsearch.index.query.QueryBuilders.rangeQuery;
+import static org.elasticsearch.index.query.QueryBuilders.termQuery;
+
+import java.util.Arrays;
+import java.util.HashMap;
+import java.util.Locale;
+import java.util.Map;
+import java.util.function.BiFunction;
+import java.util.function.Function;
+import java.util.stream.Collector;
+import java.util.stream.Stream;
+
+import javax.mail.Flags;
+
+import org.apache.james.mailbox.elasticsearch.v6.json.HeaderCollection;
+import org.apache.james.mailbox.elasticsearch.v6.json.JsonMessageConstants;
+import org.apache.james.mailbox.model.SearchQuery;
+import org.apache.james.mailbox.model.SearchQuery.Criterion;
+import org.apache.james.mailbox.model.SearchQuery.HeaderOperator;
+import org.elasticsearch.index.query.BoolQueryBuilder;
+import org.elasticsearch.index.query.QueryBuilder;
+import org.elasticsearch.index.query.QueryBuilders;
+
+public class CriterionConverter {
+
+    private final Map<Class<?>, Function<SearchQuery.Criterion, QueryBuilder>> criterionConverterMap;
+    private final Map<Class<?>, BiFunction<String, SearchQuery.HeaderOperator, QueryBuilder>> headerOperatorConverterMap;
+
+    public CriterionConverter() {
+        criterionConverterMap = new HashMap<>();
+        headerOperatorConverterMap = new HashMap<>();
+        
+        registerCriterionConverters();
+        registerHeaderOperatorConverters();
+    }
+
+    private void registerCriterionConverters() {
+        registerCriterionConverter(SearchQuery.FlagCriterion.class, this::convertFlag);
+        registerCriterionConverter(SearchQuery.UidCriterion.class, this::convertUid);
+        registerCriterionConverter(SearchQuery.ConjunctionCriterion.class, this::convertConjunction);
+        registerCriterionConverter(SearchQuery.HeaderCriterion.class, this::convertHeader);
+        registerCriterionConverter(SearchQuery.TextCriterion.class, this::convertTextCriterion);
+        registerCriterionConverter(SearchQuery.CustomFlagCriterion.class, this::convertCustomFlagCriterion);
+        
+        registerCriterionConverter(SearchQuery.AllCriterion.class,
+            criterion -> matchAllQuery());
+        
+        registerCriterionConverter(SearchQuery.ModSeqCriterion.class,
+            criterion -> createNumericFilter(JsonMessageConstants.MODSEQ, criterion.getOperator()));
+        
+        registerCriterionConverter(SearchQuery.SizeCriterion.class,
+            criterion -> createNumericFilter(JsonMessageConstants.SIZE, criterion.getOperator()));
+
+        registerCriterionConverter(SearchQuery.InternalDateCriterion.class,
+            criterion -> dateRangeFilter(JsonMessageConstants.DATE, criterion.getOperator()));
+
+        registerCriterionConverter(SearchQuery.AttachmentCriterion.class, this::convertAttachmentCriterion);
+        registerCriterionConverter(SearchQuery.MimeMessageIDCriterion.class, this::convertMimeMessageIDCriterion);
+    }
+    
+    @SuppressWarnings("unchecked")
+    private <T extends Criterion> void registerCriterionConverter(Class<T> type, Function<T, QueryBuilder> f) {
+        criterionConverterMap.put(type, (Function<Criterion, QueryBuilder>) f);
+    }
+    
+    private void registerHeaderOperatorConverters() {
+
+        registerHeaderOperatorConverter(
+            SearchQuery.ExistsOperator.class,
+            (headerName, operator) ->
+                existsQuery(JsonMessageConstants.HEADERS + "." + headerName));
+        
+        registerHeaderOperatorConverter(
+            SearchQuery.AddressOperator.class,
+            (headerName, operator) -> manageAddressFields(headerName, operator.getAddress()));
+        
+        registerHeaderOperatorConverter(
+            SearchQuery.DateOperator.class,
+            (headerName, operator) -> dateRangeFilter(JsonMessageConstants.SENT_DATE, operator));
+        
+        registerHeaderOperatorConverter(
+            SearchQuery.ContainsOperator.class,
+            (headerName, operator) -> matchQuery(JsonMessageConstants.HEADERS + "." + headerName,
+                    operator.getValue()));
+    }
+
+    @SuppressWarnings("unchecked")
+    private <T extends HeaderOperator> void registerHeaderOperatorConverter(Class<T> type, BiFunction<String, T, QueryBuilder> f) {
+        headerOperatorConverterMap.put(type, (BiFunction<String, HeaderOperator, QueryBuilder>) f);
+    }
+
+    public QueryBuilder convertCriterion(SearchQuery.Criterion criterion) {
+        return criterionConverterMap.get(criterion.getClass()).apply(criterion);
+    }
+
+    private QueryBuilder convertAttachmentCriterion(SearchQuery.AttachmentCriterion criterion) {
+        return termQuery(JsonMessageConstants.HAS_ATTACHMENT, criterion.getOperator().isSet());
+    }
+
+    private QueryBuilder convertMimeMessageIDCriterion(SearchQuery.MimeMessageIDCriterion criterion) {
+        return termQuery(JsonMessageConstants.MIME_MESSAGE_ID, criterion.getMessageID());
+    }
+
+    private QueryBuilder convertCustomFlagCriterion(SearchQuery.CustomFlagCriterion criterion) {
+        QueryBuilder termQueryBuilder = termQuery(JsonMessageConstants.USER_FLAGS, criterion.getFlag());
+        if (criterion.getOperator().isSet()) {
+            return termQueryBuilder;
+        } else {
+            return boolQuery().mustNot(termQueryBuilder);
+        }
+    }
+
+    private QueryBuilder convertTextCriterion(SearchQuery.TextCriterion textCriterion) {
+        switch (textCriterion.getType()) {
+        case BODY:
+            return boolQuery()
+                    .should(matchQuery(JsonMessageConstants.TEXT_BODY, textCriterion.getOperator().getValue()))
+                    .should(matchQuery(JsonMessageConstants.TEXT_BODY + "." + SPLIT_EMAIL,
+                        textCriterion.getOperator().getValue()))
+                    .should(matchQuery(JsonMessageConstants.HTML_BODY + "." + SPLIT_EMAIL,
+                        textCriterion.getOperator().getValue()))
+                    .should(matchQuery(JsonMessageConstants.HTML_BODY, textCriterion.getOperator().getValue()));
+        case TEXT:
+            return boolQuery()
+                    .should(matchQuery(JsonMessageConstants.TEXT, textCriterion.getOperator().getValue()))
+                    .should(matchQuery(JsonMessageConstants.TEXT + "." + SPLIT_EMAIL,
+                        textCriterion.getOperator().getValue()));
+        case FULL:
+            return boolQuery()
+                    .should(matchQuery(JsonMessageConstants.TEXT_BODY, textCriterion.getOperator().getValue()))
+                    .should(matchQuery(JsonMessageConstants.TEXT_BODY + "." + SPLIT_EMAIL,
+                        textCriterion.getOperator().getValue()))
+                    .should(matchQuery(JsonMessageConstants.HTML_BODY + "." + SPLIT_EMAIL,
+                        textCriterion.getOperator().getValue()))
+                    .should(matchQuery(JsonMessageConstants.HTML_BODY, textCriterion.getOperator().getValue()))
+                    .should(matchQuery(JsonMessageConstants.HTML_BODY, textCriterion.getOperator().getValue()))
+                    .should(matchQuery(JsonMessageConstants.ATTACHMENTS + "." + JsonMessageConstants.Attachment.TEXT_CONTENT,
+                        textCriterion.getOperator().getValue()));
+        case ATTACHMENTS:
+            return boolQuery()
+                    .should(matchQuery(JsonMessageConstants.ATTACHMENTS + "." + JsonMessageConstants.Attachment.TEXT_CONTENT,
+                        textCriterion.getOperator().getValue()));
+        case ATTACHMENT_FILE_NAME:
+            return boolQuery()
+                .should(termQuery(JsonMessageConstants.ATTACHMENTS + "." + JsonMessageConstants.Attachment.FILENAME,
+                    textCriterion.getOperator().getValue()));
+        }
+        throw new RuntimeException("Unknown SCOPE for text criterion");
+    }
+
+    private QueryBuilder dateRangeFilter(String field, SearchQuery.DateOperator dateOperator) {
+        return boolQuery().filter(
+            convertDateOperator(field,
+                dateOperator.getType(),
+                DateResolutionFormater.DATE_TIME_FOMATTER.format(
+                    DateResolutionFormater.computeLowerDate(
+                        DateResolutionFormater.convertDateToZonedDateTime(dateOperator.getDate()),
+                        dateOperator.getDateResultion())),
+                DateResolutionFormater.DATE_TIME_FOMATTER.format(
+                    DateResolutionFormater.computeUpperDate(
+                        DateResolutionFormater.convertDateToZonedDateTime(dateOperator.getDate()),
+                        dateOperator.getDateResultion()))));
+    }
+
+    private BoolQueryBuilder convertConjunction(SearchQuery.ConjunctionCriterion criterion) {
+        return convertToBoolQuery(criterion.getCriteria().stream().map(this::convertCriterion),
+            convertConjunctionType(criterion.getType()));
+    }
+
+    private BiFunction<BoolQueryBuilder, QueryBuilder, BoolQueryBuilder> convertConjunctionType(SearchQuery.Conjunction type) {
+        switch (type) {
+            case AND:
+                return BoolQueryBuilder::must;
+            case OR:
+                return BoolQueryBuilder::should;
+            case NOR:
+                return BoolQueryBuilder::mustNot;
+            default:
+                throw new RuntimeException("Unexpected conjunction criteria " + type);
+        }
+    }
+
+    private BoolQueryBuilder convertToBoolQuery(Stream<QueryBuilder> stream, BiFunction<BoolQueryBuilder, QueryBuilder, BoolQueryBuilder> addCriterionToBoolQuery) {
+        return stream.collect(Collector.of(QueryBuilders::boolQuery,
+                addCriterionToBoolQuery::apply,
+                addCriterionToBoolQuery::apply));
+    }
+
+    private QueryBuilder convertFlag(SearchQuery.FlagCriterion flagCriterion) {
+        SearchQuery.BooleanOperator operator = flagCriterion.getOperator();
+        Flags.Flag flag = flagCriterion.getFlag();
+        if (flag.equals(Flags.Flag.DELETED)) {
+            return boolQuery().filter(termQuery(JsonMessageConstants.IS_DELETED, operator.isSet()));
+        }
+        if (flag.equals(Flags.Flag.ANSWERED)) {
+            return boolQuery().filter(termQuery(JsonMessageConstants.IS_ANSWERED, operator.isSet()));
+        }
+        if (flag.equals(Flags.Flag.DRAFT)) {
+            return boolQuery().filter(termQuery(JsonMessageConstants.IS_DRAFT, operator.isSet()));
+        }
+        if (flag.equals(Flags.Flag.SEEN)) {
+            return boolQuery().filter(termQuery(JsonMessageConstants.IS_UNREAD, !operator.isSet()));
+        }
+        if (flag.equals(Flags.Flag.RECENT)) {
+            return boolQuery().filter(termQuery(JsonMessageConstants.IS_RECENT, operator.isSet()));
+        }
+        if (flag.equals(Flags.Flag.FLAGGED)) {
+            return boolQuery().filter(termQuery(JsonMessageConstants.IS_FLAGGED, operator.isSet()));
+        }
+        throw new RuntimeException("Unknown flag used in Flag search criterion");
+    }
+
+    private QueryBuilder createNumericFilter(String fieldName, SearchQuery.NumericOperator operator) {
+        switch (operator.getType()) {
+        case EQUALS:
+            return boolQuery().filter(rangeQuery(fieldName).gte(operator.getValue()).lte(operator.getValue()));
+        case GREATER_THAN:
+            return boolQuery().filter(rangeQuery(fieldName).gte(operator.getValue()));
+        case LESS_THAN:
+            return boolQuery().filter(rangeQuery(fieldName).lte(operator.getValue()));
+        default:
+            throw new RuntimeException("A non existing numeric operator was triggered");
+        }
+    }
+
+    private BoolQueryBuilder convertUid(SearchQuery.UidCriterion uidCriterion) {
+        if (uidCriterion.getOperator().getRange().length == 0) {
+            return boolQuery();
+        }
+        return boolQuery().filter(
+            convertToBoolQuery(
+                Arrays.stream(uidCriterion.getOperator().getRange())
+                    .map(this::uidRangeFilter), BoolQueryBuilder::should));
+    }
+
+    private QueryBuilder uidRangeFilter(SearchQuery.UidRange numericRange) {
+        return rangeQuery(JsonMessageConstants.UID)
+                .lte(numericRange.getHighValue().asLong())
+                .gte(numericRange.getLowValue().asLong());
+    }
+
+    private QueryBuilder convertHeader(SearchQuery.HeaderCriterion headerCriterion) {
+        return headerOperatorConverterMap.get(headerCriterion.getOperator().getClass())
+            .apply(
+                headerCriterion.getHeaderName().toLowerCase(Locale.US),
+                headerCriterion.getOperator());
+    }
+
+    private QueryBuilder manageAddressFields(String headerName, String value) {
+        return nestedQuery(getFieldNameFromHeaderName(headerName), boolQuery()
+            .should(matchQuery(getFieldNameFromHeaderName(headerName) + "." + JsonMessageConstants.EMailer.NAME, value))
+            .should(matchQuery(getFieldNameFromHeaderName(headerName) + "." + JsonMessageConstants.EMailer.ADDRESS, value))
+            .should(matchQuery(getFieldNameFromHeaderName(headerName) + "." + JsonMessageConstants.EMailer.ADDRESS + "." + RAW, value)));
+    }
+
+    private String getFieldNameFromHeaderName(String headerName) {
+        switch (headerName.toLowerCase(Locale.US)) {
+        case HeaderCollection.TO:
+            return JsonMessageConstants.TO;
+        case HeaderCollection.CC:
+            return JsonMessageConstants.CC;
+        case HeaderCollection.BCC:
+            return JsonMessageConstants.BCC;
+        case HeaderCollection.FROM:
+            return JsonMessageConstants.FROM;
+        }
+        throw new RuntimeException("Header not recognized as Addess Header : " + headerName);
+    }
+
+    private QueryBuilder convertDateOperator(String field, SearchQuery.DateComparator dateComparator, String lowDateString, String upDateString) {
+        switch (dateComparator) {
+        case BEFORE:
+            return rangeQuery(field).lte(upDateString);
+        case AFTER:
+            return rangeQuery(field).gte(lowDateString);
+        case ON:
+            return rangeQuery(field).lte(upDateString).gte(lowDateString);
+        }
+        throw new RuntimeException("Unknown date operator");
+    }
+
+}
diff --git a/mailbox/elasticsearch-v6/src/main/java/org/apache/james/mailbox/elasticsearch/v6/query/DateResolutionFormater.java b/mailbox/elasticsearch-v6/src/main/java/org/apache/james/mailbox/elasticsearch/v6/query/DateResolutionFormater.java
new file mode 100644
index 0000000..731b564
--- /dev/null
+++ b/mailbox/elasticsearch-v6/src/main/java/org/apache/james/mailbox/elasticsearch/v6/query/DateResolutionFormater.java
@@ -0,0 +1,73 @@
+/****************************************************************
+ * 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.mailbox.elasticsearch.v6.query;
+
+import java.time.Instant;
+import java.time.ZoneId;
+import java.time.ZonedDateTime;
+import java.time.format.DateTimeFormatter;
+import java.time.temporal.ChronoUnit;
+import java.time.temporal.TemporalUnit;
+import java.util.Date;
+
+import org.apache.james.mailbox.model.SearchQuery;
+
+public class DateResolutionFormater {
+
+    public static DateTimeFormatter DATE_TIME_FOMATTER = DateTimeFormatter.ofPattern("yyyy-MM-dd'T'HH:mm:ssZ");
+
+    public static ZonedDateTime computeUpperDate(ZonedDateTime date, SearchQuery.DateResolution resolution) {
+        return computeLowerDate(date, resolution).plus(1, convertDateResolutionField(resolution));
+    }
+
+    public static ZonedDateTime computeLowerDate(ZonedDateTime date, SearchQuery.DateResolution resolution) {
+        switch (resolution) {
+            case Year:
+                return date.truncatedTo(ChronoUnit.DAYS).withDayOfYear(1);
+            case Month:
+                return date.truncatedTo(ChronoUnit.DAYS).withDayOfMonth(1);
+            default:
+                return date.truncatedTo(convertDateResolutionField(resolution));
+        }
+    }
+
+    private static TemporalUnit convertDateResolutionField(SearchQuery.DateResolution resolution) {
+        switch (resolution) {
+            case Year:
+                return ChronoUnit.YEARS;
+            case Month:
+                return ChronoUnit.MONTHS;
+            case Day:
+                return ChronoUnit.DAYS;
+            case Hour:
+                return ChronoUnit.HOURS;
+            case Minute:
+                return ChronoUnit.MINUTES;
+            case Second:
+                return ChronoUnit.SECONDS;
+            default:
+                throw new RuntimeException("Unknown Date resolution used");
+        }
+    }
+
+    public static ZonedDateTime convertDateToZonedDateTime(Date date) {
+        return ZonedDateTime.ofInstant(Instant.ofEpochMilli(date.getTime()), ZoneId.systemDefault());
+    }
+}
\ No newline at end of file
diff --git a/mailbox/elasticsearch-v6/src/main/java/org/apache/james/mailbox/elasticsearch/v6/query/QueryConverter.java b/mailbox/elasticsearch-v6/src/main/java/org/apache/james/mailbox/elasticsearch/v6/query/QueryConverter.java
new file mode 100644
index 0000000..c06239b
--- /dev/null
+++ b/mailbox/elasticsearch-v6/src/main/java/org/apache/james/mailbox/elasticsearch/v6/query/QueryConverter.java
@@ -0,0 +1,79 @@
+/****************************************************************
+ * 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.mailbox.elasticsearch.v6.query;
+
+import static org.elasticsearch.index.query.QueryBuilders.boolQuery;
+import static org.elasticsearch.index.query.QueryBuilders.termsQuery;
+
+import java.util.Collection;
+import java.util.List;
+import java.util.Optional;
+
+import javax.inject.Inject;
+
+import org.apache.james.mailbox.elasticsearch.v6.json.JsonMessageConstants;
+import org.apache.james.mailbox.model.MailboxId;
+import org.apache.james.mailbox.model.SearchQuery;
+import org.elasticsearch.index.query.BoolQueryBuilder;
+import org.elasticsearch.index.query.QueryBuilder;
+
+import com.github.steveash.guavate.Guavate;
+import com.google.common.collect.ImmutableList;
+
+public class QueryConverter {
+
+
+    private final CriterionConverter criterionConverter;
+
+    @Inject
+    public QueryConverter(CriterionConverter criterionConverter) {
+        this.criterionConverter = criterionConverter;
+    }
+
+    public QueryBuilder from(Collection<MailboxId> mailboxIds, SearchQuery query) {
+        BoolQueryBuilder boolQueryBuilder = boolQuery()
+            .must(generateQueryBuilder(query));
+
+        mailboxesQuery(mailboxIds).map(boolQueryBuilder::filter);
+        return boolQueryBuilder;
+    }
+
+    private QueryBuilder generateQueryBuilder(SearchQuery searchQuery) {
+        List<SearchQuery.Criterion> criteria = searchQuery.getCriterias();
+        if (criteria.isEmpty()) {
+            return criterionConverter.convertCriterion(SearchQuery.all());
+        } else if (criteria.size() == 1) {
+            return criterionConverter.convertCriterion(criteria.get(0));
+        } else {
+            return criterionConverter.convertCriterion(new SearchQuery.ConjunctionCriterion(SearchQuery.Conjunction.AND, criteria));
+        }
+    }
+
+    private Optional<QueryBuilder> mailboxesQuery(Collection<MailboxId> mailboxIds) {
+        if (mailboxIds.isEmpty()) {
+            return Optional.empty();
+        }
+        ImmutableList<String> ids = mailboxIds.stream()
+                .map(MailboxId::serialize)
+                .collect(Guavate.toImmutableList());
+        return Optional.of(termsQuery(JsonMessageConstants.MAILBOX_ID, ids));
+    }
+
+}
diff --git a/mailbox/elasticsearch-v6/src/main/java/org/apache/james/mailbox/elasticsearch/v6/query/SortConverter.java b/mailbox/elasticsearch-v6/src/main/java/org/apache/james/mailbox/elasticsearch/v6/query/SortConverter.java
new file mode 100644
index 0000000..52a2624
--- /dev/null
+++ b/mailbox/elasticsearch-v6/src/main/java/org/apache/james/mailbox/elasticsearch/v6/query/SortConverter.java
@@ -0,0 +1,81 @@
+/****************************************************************
+ * 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.mailbox.elasticsearch.v6.query;
+
+import org.apache.james.backends.es.NodeMappingFactory;
+import org.apache.james.mailbox.elasticsearch.v6.json.JsonMessageConstants;
+import org.apache.james.mailbox.model.SearchQuery;
+import org.elasticsearch.search.sort.FieldSortBuilder;
+import org.elasticsearch.search.sort.SortBuilders;
+import org.elasticsearch.search.sort.SortOrder;
+
+public class SortConverter {
+
+    private static final String MIN = "min";
+    private static final String PATH_SEPARATOR = ".";
+
+    public static FieldSortBuilder convertSort(SearchQuery.Sort sort) {
+        return getSortClause(sort.getSortClause())
+            .order(getOrder(sort))
+            .sortMode(MIN);
+    }
+
+    private static FieldSortBuilder getSortClause(SearchQuery.Sort.SortClause clause) {
+        switch (clause) {
+            case Arrival :
+                return SortBuilders.fieldSort(JsonMessageConstants.DATE);
+            case MailboxCc :
+                return SortBuilders.fieldSort(JsonMessageConstants.CC + PATH_SEPARATOR + JsonMessageConstants.EMailer.ADDRESS)
+                    .setNestedPath(JsonMessageConstants.CC);
+            case MailboxFrom :
+                return SortBuilders.fieldSort(JsonMessageConstants.FROM + PATH_SEPARATOR + JsonMessageConstants.EMailer.ADDRESS)
+                    .setNestedPath(JsonMessageConstants.FROM);
+            case MailboxTo :
+                return SortBuilders.fieldSort(JsonMessageConstants.TO + PATH_SEPARATOR + JsonMessageConstants.EMailer.ADDRESS)
+                    .setNestedPath(JsonMessageConstants.TO);
+            case BaseSubject :
+                return SortBuilders.fieldSort(JsonMessageConstants.SUBJECT + PATH_SEPARATOR + NodeMappingFactory.RAW);
+            case Size :
+                return SortBuilders.fieldSort(JsonMessageConstants.SIZE);
+            case SentDate :
+                return SortBuilders.fieldSort(JsonMessageConstants.SENT_DATE);
+            case Uid :
+                return SortBuilders.fieldSort(JsonMessageConstants.UID);
+            case DisplayFrom:
+                return SortBuilders.fieldSort(JsonMessageConstants.FROM + PATH_SEPARATOR + JsonMessageConstants.EMailer.NAME + PATH_SEPARATOR + NodeMappingFactory.RAW)
+                    .setNestedPath(JsonMessageConstants.FROM);
+            case DisplayTo:
+                return SortBuilders.fieldSort(JsonMessageConstants.TO + PATH_SEPARATOR + JsonMessageConstants.EMailer.NAME + PATH_SEPARATOR + NodeMappingFactory.RAW)
+                    .setNestedPath(JsonMessageConstants.TO);
+            case Id:
+                return SortBuilders.fieldSort(JsonMessageConstants.MESSAGE_ID);
+            default:
+                throw new RuntimeException("Sort is not implemented");
+        }
+    }
+
+    private static SortOrder getOrder(SearchQuery.Sort sort) {
+        if (sort.isReverse()) {
+            return SortOrder.DESC;
+        } else {
+            return SortOrder.ASC;
+        }
+    }
+}
diff --git a/mailbox/elasticsearch-v6/src/main/java/org/apache/james/mailbox/elasticsearch/v6/search/ElasticSearchSearcher.java b/mailbox/elasticsearch-v6/src/main/java/org/apache/james/mailbox/elasticsearch/v6/search/ElasticSearchSearcher.java
new file mode 100644
index 0000000..195326e
--- /dev/null
+++ b/mailbox/elasticsearch-v6/src/main/java/org/apache/james/mailbox/elasticsearch/v6/search/ElasticSearchSearcher.java
@@ -0,0 +1,138 @@
+/****************************************************************
+ * 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.mailbox.elasticsearch.v6.search;
+
+import java.util.Collection;
+import java.util.Optional;
+import java.util.stream.Stream;
+
+import org.apache.james.backends.es.AliasName;
+import org.apache.james.backends.es.ReadAliasName;
+import org.apache.james.backends.es.TypeName;
+import org.apache.james.backends.es.search.ScrollIterable;
+import org.apache.james.mailbox.MessageUid;
+import org.apache.james.mailbox.elasticsearch.v6.json.JsonMessageConstants;
+import org.apache.james.mailbox.elasticsearch.v6.query.QueryConverter;
+import org.apache.james.mailbox.elasticsearch.v6.query.SortConverter;
+import org.apache.james.mailbox.exception.MailboxException;
+import org.apache.james.mailbox.model.MailboxId;
+import org.apache.james.mailbox.model.MessageId;
+import org.apache.james.mailbox.model.SearchQuery;
+import org.apache.james.mailbox.store.search.MessageSearchIndex;
+import org.apache.james.util.streams.Iterators;
+import org.elasticsearch.action.search.SearchRequestBuilder;
+import org.elasticsearch.action.search.SearchResponse;
+import org.elasticsearch.client.Client;
+import org.elasticsearch.common.unit.TimeValue;
+import org.elasticsearch.search.SearchHit;
+import org.elasticsearch.search.SearchHitField;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+public class ElasticSearchSearcher {
+
+    public static final int DEFAULT_SEARCH_SIZE = 100;
+
+    private static final Logger LOGGER = LoggerFactory.getLogger(ElasticSearchSearcher.class);
+    private static final TimeValue TIMEOUT = new TimeValue(60000);
+
+    private final Client client;
+    private final QueryConverter queryConverter;
+    private final int size;
+    private final MailboxId.Factory mailboxIdFactory;
+    private final MessageId.Factory messageIdFactory;
+    private final AliasName aliasName;
+    private final TypeName typeName;
+
+    public ElasticSearchSearcher(Client client, QueryConverter queryConverter, int size,
+                                 MailboxId.Factory mailboxIdFactory, MessageId.Factory messageIdFactory,
+                                 ReadAliasName aliasName, TypeName typeName) {
+        this.client = client;
+        this.queryConverter = queryConverter;
+        this.size = size;
+        this.mailboxIdFactory = mailboxIdFactory;
+        this.messageIdFactory = messageIdFactory;
+        this.aliasName = aliasName;
+        this.typeName = typeName;
+    }
+
+    public Stream<MessageSearchIndex.SearchResult> search(Collection<MailboxId> mailboxIds, SearchQuery query,
+                                                          Optional<Long> limit) throws MailboxException {
+        SearchRequestBuilder searchRequestBuilder = getSearchRequestBuilder(client, mailboxIds, query, limit);
+        Stream<MessageSearchIndex.SearchResult> pairStream = new ScrollIterable(client, searchRequestBuilder).stream()
+            .flatMap(this::transformResponseToUidStream);
+
+        return limit.map(pairStream::limit)
+            .orElse(pairStream);
+    }
+
+    private SearchRequestBuilder getSearchRequestBuilder(Client client, Collection<MailboxId> users,
+                                                         SearchQuery query, Optional<Long> limit) {
+        return query.getSorts()
+            .stream()
+            .reduce(
+                client.prepareSearch(aliasName.getValue())
+                    .setTypes(typeName.getValue())
+                    .setScroll(TIMEOUT)
+                    .addFields(JsonMessageConstants.UID, JsonMessageConstants.MAILBOX_ID, JsonMessageConstants.MESSAGE_ID)
+                    .setQuery(queryConverter.from(users, query))
+                    .setSize(computeRequiredSize(limit)),
+                (searchBuilder, sort) -> searchBuilder.addSort(SortConverter.convertSort(sort)),
+                (partialResult1, partialResult2) -> partialResult1);
+    }
+
+    private int computeRequiredSize(Optional<Long> limit) {
+        return limit.map(value -> Math.min(value.intValue(), size))
+            .orElse(size);
+    }
+
+    private Stream<MessageSearchIndex.SearchResult> transformResponseToUidStream(SearchResponse searchResponse) {
+        return Iterators.toStream(searchResponse.getHits().iterator())
+            .map(this::extractContentFromHit)
+            .filter(Optional::isPresent)
+            .map(Optional::get);
+    }
+
+    private Optional<MessageSearchIndex.SearchResult> extractContentFromHit(SearchHit hit) {
+        SearchHitField mailboxId = hit.field(JsonMessageConstants.MAILBOX_ID);
+        SearchHitField uid = hit.field(JsonMessageConstants.UID);
+        Optional<SearchHitField> id = retrieveMessageIdField(hit);
+        if (mailboxId != null && uid != null) {
+            Number uidAsNumber = uid.getValue();
+            return Optional.of(
+                new MessageSearchIndex.SearchResult(
+                    id.map(field -> messageIdFactory.fromString(field.getValue())),
+                    mailboxIdFactory.fromString(mailboxId.getValue()),
+                    MessageUid.of(uidAsNumber.longValue())));
+        } else {
+            LOGGER.warn("Can not extract UID, MessageID and/or MailboxId for search result {}", hit.getId());
+            return Optional.empty();
+        }
+    }
+
+    private Optional<SearchHitField> retrieveMessageIdField(SearchHit hit) {
+        if (hit.fields().keySet().contains(JsonMessageConstants.MESSAGE_ID)) {
+            return Optional.ofNullable(hit.field(JsonMessageConstants.MESSAGE_ID));
+        } else {
+            return Optional.empty();
+        }
+    }
+
+}
diff --git a/mailbox/elasticsearch-v6/src/reporting-site/site.xml b/mailbox/elasticsearch-v6/src/reporting-site/site.xml
new file mode 100644
index 0000000..d919164
--- /dev/null
+++ b/mailbox/elasticsearch-v6/src/reporting-site/site.xml
@@ -0,0 +1,29 @@
+<?xml version="1.0" encoding="ISO-8859-1"?>
+<!--
+    Licensed to the Apache Software Foundation (ASF) under one
+    or more contributor license agreements.  See the NOTICE file
+    distributed with this work for additional information
+    regarding copyright ownership.  The ASF licenses this file
+    to you under the Apache License, Version 2.0 (the
+    "License"); you may not use this file except in compliance
+    with the License.  You may obtain a copy of the License at
+    
+    http://www.apache.org/licenses/LICENSE-2.0
+    
+    Unless required by applicable law or agreed to in writing,
+    software distributed under the License is distributed on an
+    "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+    KIND, either express or implied.  See the License for the
+    specific language governing permissions and limitations
+    under the License.    
+-->
+<project name="${project.name}">
+
+    <body>
+
+        <menu ref="parent" />
+        <menu ref="reports" />
+
+    </body>
+
+</project>
diff --git a/mailbox/elasticsearch-v6/src/test/java/org/apache/james/mailbox/elasticsearch/v6/ElasticSearchIntegrationTest.java b/mailbox/elasticsearch-v6/src/test/java/org/apache/james/mailbox/elasticsearch/v6/ElasticSearchIntegrationTest.java
new file mode 100644
index 0000000..81a4293
--- /dev/null
+++ b/mailbox/elasticsearch-v6/src/test/java/org/apache/james/mailbox/elasticsearch/v6/ElasticSearchIntegrationTest.java
@@ -0,0 +1,223 @@
+/****************************************************************
+ * 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.mailbox.elasticsearch.v6;
+
+import static org.assertj.core.api.Assertions.assertThat;
+
+import java.nio.charset.StandardCharsets;
+import java.time.ZoneId;
+import java.util.concurrent.Executors;
+import java.util.concurrent.ThreadFactory;
+
+import org.apache.james.backends.es.DockerElasticSearchRule;
+import org.apache.james.backends.es.ElasticSearchConfiguration;
+import org.apache.james.backends.es.ElasticSearchIndexer;
+import org.apache.james.mailbox.MailboxSession;
+import org.apache.james.mailbox.MailboxSessionUtil;
+import org.apache.james.mailbox.MessageManager;
+import org.apache.james.mailbox.elasticsearch.v6.events.ElasticSearchListeningMessageSearchIndex;
+import org.apache.james.mailbox.elasticsearch.v6.json.MessageToElasticSearchJson;
+import org.apache.james.mailbox.elasticsearch.v6.query.CriterionConverter;
+import org.apache.james.mailbox.elasticsearch.v6.query.QueryConverter;
+import org.apache.james.mailbox.elasticsearch.v6.search.ElasticSearchSearcher;
+import org.apache.james.mailbox.inmemory.InMemoryId;
+import org.apache.james.mailbox.inmemory.InMemoryMessageId;
+import org.apache.james.mailbox.inmemory.manager.InMemoryIntegrationResources;
+import org.apache.james.mailbox.model.ComposedMessageId;
+import org.apache.james.mailbox.model.MailboxPath;
+import org.apache.james.mailbox.model.SearchQuery;
+import org.apache.james.mailbox.store.search.AbstractMessageSearchIndexTest;
+import org.apache.james.mailbox.tika.TikaConfiguration;
+import org.apache.james.mailbox.tika.TikaContainerSingletonRule;
+import org.apache.james.mailbox.tika.TikaHttpClientImpl;
+import org.apache.james.mailbox.tika.TikaTextExtractor;
+import org.apache.james.metrics.api.NoopMetricFactory;
+import org.apache.james.mime4j.dom.Message;
+import org.apache.james.util.concurrent.NamedThreadFactory;
+import org.elasticsearch.client.Client;
+import org.junit.ClassRule;
+import org.junit.Rule;
+import org.junit.Test;
+
+import com.google.common.base.Strings;
+
+public class ElasticSearchIntegrationTest extends AbstractMessageSearchIndexTest {
+
+    private static final int BATCH_SIZE = 1;
+    private static final int SEARCH_SIZE = 1;
+
+    @ClassRule
+    public static TikaContainerSingletonRule tika = TikaContainerSingletonRule.rule;
+
+    @Rule
+    public DockerElasticSearchRule elasticSearch = new DockerElasticSearchRule();
+    private TikaTextExtractor textExtractor;
+
+    @Override
+    public void setUp() throws Exception {
+        textExtractor = new TikaTextExtractor(new NoopMetricFactory(),
+            new TikaHttpClientImpl(TikaConfiguration.builder()
+                .host(tika.getIp())
+                .port(tika.getPort())
+                .timeoutInMillis(tika.getTimeoutInMillis())
+                .build()));
+        super.setUp();
+    }
+
+    @Override
+    protected void await() {
+        elasticSearch.awaitForElasticSearch();
+    }
+
+    @Override
+    protected void initializeMailboxManager() {
+        Client client = MailboxIndexCreationUtil.prepareDefaultClient(
+            elasticSearch.clientProvider().get(),
+            ElasticSearchConfiguration.builder()
+                .addHost(elasticSearch.getTcpHost())
+                .build());
+
+        InMemoryMessageId.Factory messageIdFactory = new InMemoryMessageId.Factory();
+        ThreadFactory threadFactory = NamedThreadFactory.withClassName(getClass());
+
+        InMemoryIntegrationResources resources = InMemoryIntegrationResources.builder()
+            .preProvisionnedFakeAuthenticator()
+            .fakeAuthorizator()
+            .inVmEventBus()
+            .defaultAnnotationLimits()
+            .defaultMessageParser()
+            .listeningSearchIndex(preInstanciationStage -> new ElasticSearchListeningMessageSearchIndex(
+                preInstanciationStage.getMapperFactory(),
+                new ElasticSearchIndexer(client,
+                    Executors.newSingleThreadExecutor(threadFactory),
+                    MailboxElasticSearchConstants.DEFAULT_MAILBOX_WRITE_ALIAS,
+                    MailboxElasticSearchConstants.MESSAGE_TYPE,
+                    BATCH_SIZE),
+                new ElasticSearchSearcher(client, new QueryConverter(new CriterionConverter()), SEARCH_SIZE,
+                    new InMemoryId.Factory(), messageIdFactory,
+                    MailboxElasticSearchConstants.DEFAULT_MAILBOX_READ_ALIAS,
+                    MailboxElasticSearchConstants.MESSAGE_TYPE),
+                new MessageToElasticSearchJson(textExtractor, ZoneId.of("Europe/Paris"), IndexAttachments.YES),
+                preInstanciationStage.getSessionProvider()))
+            .noPreDeletionHooks()
+            .storeQuotaManager()
+            .build();
+
+        storeMailboxManager = resources.getMailboxManager();
+        messageIdManager = resources.getMessageIdManager();
+        messageSearchIndex = resources.getSearchIndex();
+    }
+
+    @Test
+    public void termsBetweenElasticSearchAndLuceneLimitDueTuNonAsciiCharsShouldBeTruncated() throws Exception {
+        MailboxPath mailboxPath = MailboxPath.forUser(USERNAME, INBOX);
+        MailboxSession session = MailboxSessionUtil.create(USERNAME);
+        MessageManager messageManager = storeMailboxManager.getMailbox(mailboxPath, session);
+
+        String recipient = "benwa@linagora.com";
+        ComposedMessageId composedMessageId = messageManager.appendMessage(MessageManager.AppendCommand.from(
+            Message.Builder.of()
+                .setTo(recipient)
+                .setBody(Strings.repeat("0à2345678é", 3200), StandardCharsets.UTF_8)),
+            session);
+
+        elasticSearch.awaitForElasticSearch();
+
+        assertThat(messageManager.search(new SearchQuery(SearchQuery.address(SearchQuery.AddressType.To, recipient)), session))
+            .containsExactly(composedMessageId.getUid());
+    }
+
+    @Test
+    public void tooLongTermsShouldNotMakeIndexingFail() throws Exception {
+        MailboxPath mailboxPath = MailboxPath.forUser(USERNAME, INBOX);
+        MailboxSession session = MailboxSessionUtil.create(USERNAME);
+        MessageManager messageManager = storeMailboxManager.getMailbox(mailboxPath, session);
+
+        String recipient = "benwa@linagora.com";
+        ComposedMessageId composedMessageId = messageManager.appendMessage(MessageManager.AppendCommand.from(
+            Message.Builder.of()
+                .setTo(recipient)
+                .setBody(Strings.repeat("0123456789", 3300), StandardCharsets.UTF_8)),
+            session);
+
+        elasticSearch.awaitForElasticSearch();
+
+        assertThat(messageManager.search(new SearchQuery(SearchQuery.address(SearchQuery.AddressType.To, recipient)), session))
+            .containsExactly(composedMessageId.getUid());
+    }
+
+    @Test
+    public void fieldsExceedingLuceneLimitShouldNotBeIgnored() throws Exception {
+        MailboxPath mailboxPath = MailboxPath.forUser(USERNAME, INBOX);
+        MailboxSession session = MailboxSessionUtil.create(USERNAME);
+        MessageManager messageManager = storeMailboxManager.getMailbox(mailboxPath, session);
+
+        String recipient = "benwa@linagora.com";
+        ComposedMessageId composedMessageId = messageManager.appendMessage(MessageManager.AppendCommand.from(
+            Message.Builder.of()
+                .setTo(recipient)
+                .setBody(Strings.repeat("0123456789 ", 5000), StandardCharsets.UTF_8)),
+            session);
+
+        elasticSearch.awaitForElasticSearch();
+
+        assertThat(messageManager.search(new SearchQuery(SearchQuery.bodyContains("0123456789")), session))
+            .containsExactly(composedMessageId.getUid());
+    }
+
+    @Test
+    public void fieldsWithTooLongTermShouldStillBeIndexed() throws Exception {
+        MailboxPath mailboxPath = MailboxPath.forUser(USERNAME, INBOX);
+        MailboxSession session = MailboxSessionUtil.create(USERNAME);
+        MessageManager messageManager = storeMailboxManager.getMailbox(mailboxPath, session);
+
+        String recipient = "benwa@linagora.com";
+        ComposedMessageId composedMessageId = messageManager.appendMessage(MessageManager.AppendCommand.from(
+            Message.Builder.of()
+                .setTo(recipient)
+                .setBody(Strings.repeat("0123456789 ", 5000) + " matchMe", StandardCharsets.UTF_8)),
+            session);
+
+        elasticSearch.awaitForElasticSearch();
+
+        assertThat(messageManager.search(new SearchQuery(SearchQuery.bodyContains("matchMe")), session))
+            .containsExactly(composedMessageId.getUid());
+    }
+
+    @Test
+    public void reasonableLongTermShouldNotBeIgnored() throws Exception {
+        MailboxPath mailboxPath = MailboxPath.forUser(USERNAME, INBOX);
+        MailboxSession session = MailboxSessionUtil.create(USERNAME);
+        MessageManager messageManager = storeMailboxManager.getMailbox(mailboxPath, session);
+
+        String recipient = "benwa@linagora.com";
+        String reasonableLongTerm = "dichlorodiphényltrichloroéthane";
+        ComposedMessageId composedMessageId = messageManager.appendMessage(MessageManager.AppendCommand.from(
+            Message.Builder.of()
+                .setTo(recipient)
+                .setBody(reasonableLongTerm, StandardCharsets.UTF_8)),
+            session);
+
+        elasticSearch.awaitForElasticSearch();
+
+        assertThat(messageManager.search(new SearchQuery(SearchQuery.bodyContains(reasonableLongTerm)), session))
+            .containsExactly(composedMessageId.getUid());
+    }
+}
\ No newline at end of file
diff --git a/mailbox/elasticsearch-v6/src/test/java/org/apache/james/mailbox/elasticsearch/v6/ElasticSearchMailboxConfigurationTest.java b/mailbox/elasticsearch-v6/src/test/java/org/apache/james/mailbox/elasticsearch/v6/ElasticSearchMailboxConfigurationTest.java
new file mode 100644
index 0000000..64a1cd0
--- /dev/null
+++ b/mailbox/elasticsearch-v6/src/test/java/org/apache/james/mailbox/elasticsearch/v6/ElasticSearchMailboxConfigurationTest.java
@@ -0,0 +1,219 @@
+/****************************************************************
+ * 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.mailbox.elasticsearch.v6;
+
+import static org.assertj.core.api.Assertions.assertThat;
+
+import org.apache.commons.configuration.PropertiesConfiguration;
+import org.apache.james.backends.es.IndexName;
+import org.apache.james.backends.es.ReadAliasName;
+import org.apache.james.backends.es.WriteAliasName;
+import org.junit.Test;
+
+public class ElasticSearchMailboxConfigurationTest {
+    @Test
+    public void getIndexMailboxNameShouldReturnOldConfiguredValue() {
+        PropertiesConfiguration configuration = new PropertiesConfiguration();
+        String name = "name";
+        configuration.addProperty("elasticsearch.index.name", name);
+        configuration.addProperty("elasticsearch.hosts", "127.0.0.1");
+
+        ElasticSearchMailboxConfiguration elasticSearchConfiguration = ElasticSearchMailboxConfiguration.fromProperties(configuration);
+
+        assertThat(elasticSearchConfiguration.getIndexMailboxName())
+            .isEqualTo(new IndexName(name));
+    }
+
+    @Test
+    public void getIndexMailboxNameShouldReturnNewConfiguredValueWhenBoth() {
+        PropertiesConfiguration configuration = new PropertiesConfiguration();
+        String name = "name";
+        configuration.addProperty("elasticsearch.index.name", "other");
+        configuration.addProperty("elasticsearch.index.mailbox.name", name);
+        configuration.addProperty("elasticsearch.hosts", "127.0.0.1");
+
+        ElasticSearchMailboxConfiguration elasticSearchConfiguration = ElasticSearchMailboxConfiguration.fromProperties(configuration);
+
+        assertThat(elasticSearchConfiguration.getIndexMailboxName())
+            .isEqualTo(new IndexName(name));
+    }
+
+    @Test
+    public void getIndexMailboxNameShouldReturnConfiguredValue() {
+        PropertiesConfiguration configuration = new PropertiesConfiguration();
+        String name = "name";
+        configuration.addProperty("elasticsearch.index.mailbox.name", name);
+        configuration.addProperty("elasticsearch.hosts", "127.0.0.1");
+
+        ElasticSearchMailboxConfiguration elasticSearchConfiguration = ElasticSearchMailboxConfiguration.fromProperties(configuration);
+
+        assertThat(elasticSearchConfiguration.getIndexMailboxName())
+            .isEqualTo(new IndexName(name));
+    }
+
+    @Test
+    public void getIndexMailboxNameShouldReturnDefaultValueWhenMissing() {
+        PropertiesConfiguration configuration = new PropertiesConfiguration();
+        configuration.addProperty("elasticsearch.hosts", "127.0.0.1");
+
+        ElasticSearchMailboxConfiguration elasticSearchConfiguration = ElasticSearchMailboxConfiguration.fromProperties(configuration);
+
+        assertThat(elasticSearchConfiguration.getIndexMailboxName())
+            .isEqualTo(MailboxElasticSearchConstants.DEFAULT_MAILBOX_INDEX);
+    }
+
+    @Test
+    public void getReadAliasMailboxNameShouldReturnOldConfiguredValue() {
+        PropertiesConfiguration configuration = new PropertiesConfiguration();
+        String name = "name";
+        configuration.addProperty("elasticsearch.alias.read.name", name);
+        configuration.addProperty("elasticsearch.hosts", "127.0.0.1");
+
+        ElasticSearchMailboxConfiguration elasticSearchConfiguration = ElasticSearchMailboxConfiguration.fromProperties(configuration);
+
+        assertThat(elasticSearchConfiguration.getReadAliasMailboxName())
+            .isEqualTo(new ReadAliasName(name));
+    }
+
+    @Test
+    public void getReadAliasMailboxNameShouldReturnConfiguredValue() {
+        PropertiesConfiguration configuration = new PropertiesConfiguration();
+        String name = "name";
+        configuration.addProperty("elasticsearch.alias.read.mailbox.name", name);
+        configuration.addProperty("elasticsearch.hosts", "127.0.0.1");
+
+        ElasticSearchMailboxConfiguration elasticSearchConfiguration = ElasticSearchMailboxConfiguration.fromProperties(configuration);
+
+        assertThat(elasticSearchConfiguration.getReadAliasMailboxName())
+            .isEqualTo(new ReadAliasName(name));
+    }
+
+    @Test
+    public void getReadAliasMailboxNameShouldReturnNewConfiguredValueWhenBoth() {
+        PropertiesConfiguration configuration = new PropertiesConfiguration();
+        String name = "name";
+        configuration.addProperty("elasticsearch.alias.read.mailbox.name", name);
+        configuration.addProperty("elasticsearch.alias.read.name", "other");
+        configuration.addProperty("elasticsearch.hosts", "127.0.0.1");
+
+        ElasticSearchMailboxConfiguration elasticSearchConfiguration = ElasticSearchMailboxConfiguration.fromProperties(configuration);
+
+        assertThat(elasticSearchConfiguration.getReadAliasMailboxName())
+            .isEqualTo(new ReadAliasName(name));
+    }
+
+    @Test
+    public void getReadAliasMailboxNameShouldReturnDefaultValueWhenMissing() {
+        PropertiesConfiguration configuration = new PropertiesConfiguration();
+        configuration.addProperty("elasticsearch.hosts", "127.0.0.1");
+
+        ElasticSearchMailboxConfiguration elasticSearchConfiguration = ElasticSearchMailboxConfiguration.fromProperties(configuration);
+
+        assertThat(elasticSearchConfiguration.getReadAliasMailboxName())
+            .isEqualTo(MailboxElasticSearchConstants.DEFAULT_MAILBOX_READ_ALIAS);
+    }
+
+    @Test
+    public void getWriteAliasMailboxNameShouldReturnOldConfiguredValue() {
+        PropertiesConfiguration configuration = new PropertiesConfiguration();
+        String name = "name";
+        configuration.addProperty("elasticsearch.alias.write.name", name);
+        configuration.addProperty("elasticsearch.hosts", "127.0.0.1");
+
+        ElasticSearchMailboxConfiguration elasticSearchConfiguration = ElasticSearchMailboxConfiguration.fromProperties(configuration);
+
+        assertThat(elasticSearchConfiguration.getWriteAliasMailboxName())
+            .isEqualTo(new WriteAliasName(name));
+    }
+
+    @Test
+    public void getWriteAliasMailboxNameShouldReturnConfiguredValue() {
+        PropertiesConfiguration configuration = new PropertiesConfiguration();
+        String name = "name";
+        configuration.addProperty("elasticsearch.alias.write.mailbox.name", name);
+        configuration.addProperty("elasticsearch.hosts", "127.0.0.1");
+
+        ElasticSearchMailboxConfiguration elasticSearchConfiguration = ElasticSearchMailboxConfiguration.fromProperties(configuration);
+
+        assertThat(elasticSearchConfiguration.getWriteAliasMailboxName())
+            .isEqualTo(new WriteAliasName(name));
+    }
+
+    @Test
+    public void getWriteAliasMailboxNameShouldReturnNewConfiguredValueWhenBoth() {
+        PropertiesConfiguration configuration = new PropertiesConfiguration();
+        String name = "name";
+        configuration.addProperty("elasticsearch.alias.write.mailbox.name", name);
+        configuration.addProperty("elasticsearch.alias.write.name", "other");
+        configuration.addProperty("elasticsearch.hosts", "127.0.0.1");
+
+        ElasticSearchMailboxConfiguration elasticSearchConfiguration = ElasticSearchMailboxConfiguration.fromProperties(configuration);
+
+        assertThat(elasticSearchConfiguration.getWriteAliasMailboxName())
+            .isEqualTo(new WriteAliasName(name));
+    }
+
+    @Test
+    public void getWriteAliasMailboxNameShouldReturnDefaultValueWhenMissing() {
+        PropertiesConfiguration configuration = new PropertiesConfiguration();
+        configuration.addProperty("elasticsearch.hosts", "127.0.0.1");
+
+        ElasticSearchMailboxConfiguration elasticSearchConfiguration = ElasticSearchMailboxConfiguration.fromProperties(configuration);
+
+        assertThat(elasticSearchConfiguration.getWriteAliasMailboxName())
+            .isEqualTo(MailboxElasticSearchConstants.DEFAULT_MAILBOX_WRITE_ALIAS);
+    }
+
+    @Test
+    public void getIndexAttachmentShouldReturnConfiguredValueWhenTrue() {
+        PropertiesConfiguration configuration = new PropertiesConfiguration();
+        configuration.addProperty("elasticsearch.indexAttachments", true);
+        configuration.addProperty("elasticsearch.hosts", "127.0.0.1");
+
+        ElasticSearchMailboxConfiguration elasticSearchConfiguration = ElasticSearchMailboxConfiguration.fromProperties(configuration);
+
+        assertThat(elasticSearchConfiguration.getIndexAttachment())
+            .isEqualTo(IndexAttachments.YES);
+    }
+
+    @Test
+    public void getIndexAttachmentShouldReturnConfiguredValueWhenFalse() {
+        PropertiesConfiguration configuration = new PropertiesConfiguration();
+        configuration.addProperty("elasticsearch.indexAttachments", false);
+        configuration.addProperty("elasticsearch.hosts", "127.0.0.1");
+
+        ElasticSearchMailboxConfiguration elasticSearchConfiguration = ElasticSearchMailboxConfiguration.fromProperties(configuration);
+
+        assertThat(elasticSearchConfiguration.getIndexAttachment())
+            .isEqualTo(IndexAttachments.NO);
+    }
+
+    @Test
+    public void getIndexAttachmentShouldReturnDefaultValueWhenMissing() {
+        PropertiesConfiguration configuration = new PropertiesConfiguration();
+        configuration.addProperty("elasticsearch.hosts", "127.0.0.1");
+
+        ElasticSearchMailboxConfiguration elasticSearchConfiguration = ElasticSearchMailboxConfiguration.fromProperties(configuration);
+
+        assertThat(elasticSearchConfiguration.getIndexAttachment())
+            .isEqualTo(IndexAttachments.YES);
+    }
+
+}
\ No newline at end of file
diff --git a/mailbox/elasticsearch-v6/src/test/java/org/apache/james/mailbox/elasticsearch/v6/events/ElasticSearchListeningMessageSearchIndexTest.java b/mailbox/elasticsearch-v6/src/test/java/org/apache/james/mailbox/elasticsearch/v6/events/ElasticSearchListeningMessageSearchIndexTest.java
new file mode 100644
index 0000000..e17f6ca
--- /dev/null
+++ b/mailbox/elasticsearch-v6/src/test/java/org/apache/james/mailbox/elasticsearch/v6/events/ElasticSearchListeningMessageSearchIndexTest.java
@@ -0,0 +1,269 @@
+/****************************************************************
+ * 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.mailbox.elasticsearch.v6.events;
+
+import static org.assertj.core.api.Assertions.assertThat;
+import static org.assertj.core.api.Assertions.assertThatThrownBy;
+import static org.mockito.ArgumentMatchers.any;
+import static org.mockito.ArgumentMatchers.anyLong;
+import static org.mockito.ArgumentMatchers.eq;
+import static org.mockito.ArgumentMatchers.refEq;
+import static org.mockito.Mockito.doThrow;
+import static org.mockito.Mockito.mock;
+import static org.mockito.Mockito.verify;
+import static org.mockito.Mockito.when;
+
+import java.util.List;
+import java.util.Optional;
+
+import javax.mail.Flags;
+
+import org.apache.james.backends.es.ElasticSearchIndexer;
+import org.apache.james.backends.es.UpdatedRepresentation;
+import org.apache.james.core.User;
+import org.apache.james.mailbox.MailboxSession;
+import org.apache.james.mailbox.MailboxSessionUtil;
+import org.apache.james.mailbox.MessageUid;
+import org.apache.james.mailbox.elasticsearch.v6.json.MessageToElasticSearchJson;
+import org.apache.james.mailbox.elasticsearch.v6.search.ElasticSearchSearcher;
+import org.apache.james.mailbox.events.Group;
+import org.apache.james.mailbox.model.Mailbox;
+import org.apache.james.mailbox.model.TestId;
+import org.apache.james.mailbox.model.UpdatedFlags;
+import org.apache.james.mailbox.store.MailboxSessionMapperFactory;
+import org.apache.james.mailbox.store.SessionProvider;
+import org.apache.james.mailbox.store.mail.model.MailboxMessage;
+import org.elasticsearch.ElasticsearchException;
+import org.elasticsearch.action.bulk.BulkResponse;
+import org.elasticsearch.index.query.QueryBuilder;
+import org.elasticsearch.index.query.QueryBuilders;
+import org.junit.Before;
+import org.junit.Test;
+
+import com.fasterxml.jackson.core.JsonGenerationException;
+import com.fasterxml.jackson.core.JsonGenerator;
+import com.fasterxml.jackson.core.JsonProcessingException;
+import com.google.common.collect.ImmutableList;
+import com.google.common.collect.Lists;
+
+public class ElasticSearchListeningMessageSearchIndexTest {
+    private static final long MODSEQ = 18L;
+    private static final MessageUid MESSAGE_UID = MessageUid.of(1);
+    private static final TestId MAILBOX_ID = TestId.of(12);
+    private static final String ELASTIC_SEARCH_ID = "12:1";
+    private static final String EXPECTED_JSON_CONTENT = "json content";
+    private static final String USERNAME = "username";
+
+    private ElasticSearchIndexer elasticSearchIndexer;
+    private MessageToElasticSearchJson messageToElasticSearchJson;
+    private ElasticSearchListeningMessageSearchIndex testee;
+    private MailboxSession session;
+    private List<User> users;
+    private Mailbox mailbox;
+
+    @Before
+    public void setup() {
+        MailboxSessionMapperFactory mapperFactory = mock(MailboxSessionMapperFactory.class);
+        messageToElasticSearchJson = mock(MessageToElasticSearchJson.class);
+        ElasticSearchSearcher elasticSearchSearcher = mock(ElasticSearchSearcher.class);
+        SessionProvider mockSessionProvider = mock(SessionProvider.class);
+
+        elasticSearchIndexer = mock(ElasticSearchIndexer.class);
+        
+        testee = new ElasticSearchListeningMessageSearchIndex(mapperFactory, elasticSearchIndexer, elasticSearchSearcher,
+            messageToElasticSearchJson, mockSessionProvider);
+        session = MailboxSessionUtil.create(USERNAME);
+        users = ImmutableList.of(User.fromUsername(USERNAME));
+
+        mailbox = mock(Mailbox.class);
+        when(mailbox.getMailboxId()).thenReturn(MAILBOX_ID);
+    }
+
+    @Test
+    public void deserializeElasticSearchListeningMessageSearchIndexGroup() throws Exception {
+        assertThat(Group.deserialize("org.apache.james.mailbox.elasticsearch.v6.events.ElasticSearchListeningMessageSearchIndex$ElasticSearchListeningMessageSearchIndexGroup"))
+            .isEqualTo(new ElasticSearchListeningMessageSearchIndex.ElasticSearchListeningMessageSearchIndexGroup());
+    }
+    
+    @Test
+    public void addShouldIndex() throws Exception {
+        //Given
+        MailboxMessage message = mockedMessage(MESSAGE_UID);
+        
+        when(messageToElasticSearchJson.convertToJson(eq(message), eq(users)))
+            .thenReturn(EXPECTED_JSON_CONTENT);
+        
+        //When
+        testee.add(session, mailbox, message);
+        
+        //Then
+        verify(elasticSearchIndexer).index(eq(ELASTIC_SEARCH_ID), eq(EXPECTED_JSON_CONTENT));
+    }
+
+    @Test
+    public void addShouldIndexEmailBodyWhenNotIndexableAttachment() throws Exception {
+        //Given
+        MailboxMessage message = mockedMessage(MESSAGE_UID);
+        
+        when(messageToElasticSearchJson.convertToJson(eq(message), eq(users)))
+            .thenThrow(JsonProcessingException.class);
+        
+        when(messageToElasticSearchJson.convertToJsonWithoutAttachment(eq(message), eq(users)))
+            .thenReturn(EXPECTED_JSON_CONTENT);
+        
+        //When
+        testee.add(session, mailbox, message);
+        
+        //Then
+        verify(elasticSearchIndexer).index(eq(ELASTIC_SEARCH_ID), eq(EXPECTED_JSON_CONTENT));
+    }
+
+    private MailboxMessage mockedMessage(MessageUid uid) {
+        MailboxMessage message = mock(MailboxMessage.class);
+        when(message.getUid()).thenReturn(uid);
+        return message;
+    }
+
+    @Test
+    public void addShouldPropagateExceptionWhenExceptionOccurs() throws Exception {
+        //Given
+        MailboxMessage message = mockedMessage(MESSAGE_UID);
+        
+        when(messageToElasticSearchJson.convertToJson(eq(message), eq(users)))
+            .thenThrow(JsonProcessingException.class);
+
+        // When
+        JsonGenerator jsonGenerator = null;
+        when(messageToElasticSearchJson.convertToJsonWithoutAttachment(eq(message), eq(users)))
+            .thenThrow(new JsonGenerationException("expected error", jsonGenerator));
+        
+        //Then
+        assertThatThrownBy(() -> testee.add(session, mailbox, message)).isInstanceOf(JsonGenerationException.class);
+    }
+
+    @Test
+    @SuppressWarnings("unchecked")
+    public void deleteShouldWork() {
+        //Given
+        BulkResponse expectedBulkResponse = mock(BulkResponse.class);
+        when(elasticSearchIndexer.delete(any(List.class)))
+            .thenReturn(Optional.of(expectedBulkResponse));
+
+        //When
+        testee.delete(session, mailbox, Lists.newArrayList(MESSAGE_UID));
+
+        //Then
+        verify(elasticSearchIndexer).delete(eq(Lists.newArrayList(ELASTIC_SEARCH_ID)));
+    }
+
+    @Test
+    @SuppressWarnings("unchecked")
+    public void deleteShouldWorkWhenMultipleMessageIds() {
+        //Given
+        MessageUid messageId2 = MessageUid.of(2);
+        MessageUid messageId3 = MessageUid.of(3);
+        MessageUid messageId4 = MessageUid.of(4);
+        MessageUid messageId5 = MessageUid.of(5);
+
+        BulkResponse expectedBulkResponse = mock(BulkResponse.class);
+        when(elasticSearchIndexer.delete(any(List.class)))
+            .thenReturn(Optional.of(expectedBulkResponse));
+        
+        //When
+        testee.delete(session, mailbox, Lists.newArrayList(MESSAGE_UID, messageId2, messageId3, messageId4, messageId5));
+        
+        //Then
+        verify(elasticSearchIndexer).delete(eq(Lists.newArrayList(ELASTIC_SEARCH_ID, "12:2", "12:3", "12:4", "12:5")));
+    }
+
+    @Test
+    @SuppressWarnings("unchecked")
+    public void deleteShouldPropagateExceptionWhenExceptionOccurs() {
+        //Given
+        when(elasticSearchIndexer.delete(any(List.class)))
+            .thenThrow(new ElasticsearchException(""));
+
+        // Then
+        assertThatThrownBy(() -> testee.delete(session, mailbox, Lists.newArrayList(MESSAGE_UID)))
+            .isInstanceOf(ElasticsearchException.class);
+    }
+
+    @Test
+    public void updateShouldWork() throws Exception {
+        //Given
+        Flags flags = new Flags();
+
+        UpdatedFlags updatedFlags = UpdatedFlags.builder()
+            .uid(MESSAGE_UID)
+            .modSeq(MODSEQ)
+            .oldFlags(flags)
+            .newFlags(flags)
+            .build();
+
+        when(messageToElasticSearchJson.getUpdatedJsonMessagePart(any(Flags.class), any(Long.class)))
+            .thenReturn("json updated content");
+        
+        //When
+        testee.update(session, mailbox, Lists.newArrayList(updatedFlags));
+        
+        //Then
+        ImmutableList<UpdatedRepresentation> expectedUpdatedRepresentations = ImmutableList.of(new UpdatedRepresentation(ELASTIC_SEARCH_ID, "json updated content"));
+        verify(elasticSearchIndexer).update(expectedUpdatedRepresentations);
+    }
+
+    @Test
+    public void updateShouldPropagateExceptionWhenExceptionOccurs() throws Exception {
+        //Given
+        Flags flags = new Flags();
+        UpdatedFlags updatedFlags = UpdatedFlags.builder()
+            .uid(MESSAGE_UID)
+            .modSeq(MODSEQ)
+            .oldFlags(flags)
+            .newFlags(flags)
+            .build();
+        when(messageToElasticSearchJson.getUpdatedJsonMessagePart(any(), anyLong())).thenReturn("update doc");
+
+        //When
+        when(elasticSearchIndexer.update(any())).thenThrow(new ElasticsearchException(""));
+        
+        //Then
+        assertThatThrownBy(() -> testee.update(session, mailbox, Lists.newArrayList(updatedFlags))).isInstanceOf(ElasticsearchException.class);
+    }
+
+    @Test
+    public void deleteAllShouldWork() {
+        //Given
+        testee.deleteAll(session, mailbox);
+        
+        //Then
+        QueryBuilder expectedQueryBuilder = QueryBuilders.termQuery("mailboxId", "12");
+        verify(elasticSearchIndexer).deleteAllMatchingQuery(refEq(expectedQueryBuilder));
+    }
+
+    @Test
+    public void deleteAllShouldNotPropagateExceptionWhenExceptionOccurs() {
+        //Given
+        doThrow(RuntimeException.class)
+            .when(elasticSearchIndexer).deleteAllMatchingQuery(any());
+
+        //Then
+        assertThatThrownBy(() -> testee.deleteAll(session, mailbox)).isInstanceOf(RuntimeException.class);
+    }
+
+}
\ No newline at end of file
diff --git a/mailbox/elasticsearch-v6/src/test/java/org/apache/james/mailbox/elasticsearch/v6/json/EMailersTest.java b/mailbox/elasticsearch-v6/src/test/java/org/apache/james/mailbox/elasticsearch/v6/json/EMailersTest.java
new file mode 100644
index 0000000..c89a0ed
--- /dev/null
+++ b/mailbox/elasticsearch-v6/src/test/java/org/apache/james/mailbox/elasticsearch/v6/json/EMailersTest.java
@@ -0,0 +1,66 @@
+/****************************************************************
+ * Licensed to the Apache Software Foundation (ASF) under one   *
+ * or more contributor license agreements.  See the NOTICE file *
+ * distributed with this work for additional information        *
+ * regarding copyright ownership.  The ASF licenses this file   *
+ * to you under the Apache License, Version 2.0 (the            *
+ * "License"); you may not use this file except in compliance   *
+ * with the License.  You may obtain a copy of the License at   *
+ *                                                              *
+ *   http://www.apache.org/licenses/LICENSE-2.0                 *
+ *                                                              *
+ * Unless required by applicable law or agreed to in writing,   *
+ * software distributed under the License is distributed on an  *
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY       *
+ * KIND, either express or implied.  See the License for the    *
+ * specific language governing permissions and limitations      *
+ * under the License.                                           *
+ ****************************************************************/
+
+package org.apache.james.mailbox.elasticsearch.v6.json;
+
+import static org.assertj.core.api.Assertions.assertThat;
+import static org.assertj.core.api.Assertions.assertThatThrownBy;
+
+import org.junit.Test;
+
+import com.google.common.base.Joiner;
+import com.google.common.collect.ImmutableSet;
+
+public class EMailersTest {
+
+    @Test
+    public void fromShouldThrowWhenSetIsNull() {
+        assertThatThrownBy(() -> EMailers.from(null))
+            .isInstanceOf(NullPointerException.class)
+            .hasMessage("'emailers' is mandatory");
+    }
+
+    @Test
+    public void serializeShouldReturnEmptyWhenEmptySet() {
+        EMailers eMailers = EMailers.from(ImmutableSet.of());
+
+        assertThat(eMailers.serialize()).isEmpty();
+    }
+
+    @Test
+    public void serializeShouldNotJoinWhenOneElement() {
+        EMailer emailer = new EMailer("name", "address");
+        EMailers eMailers = EMailers.from(ImmutableSet.of(emailer));
+
+        assertThat(eMailers.serialize()).isEqualTo(emailer.serialize());
+    }
+
+    @Test
+    public void serializeShouldJoinWhenMultipleElements() {
+        EMailer emailer = new EMailer("name", "address");
+        EMailer emailer2 = new EMailer("name2", "address2");
+        EMailer emailer3 = new EMailer("name3", "address3");
+
+        String expected = Joiner.on(" ").join(emailer.serialize(), emailer2.serialize(), emailer3.serialize());
+
+        EMailers eMailers = EMailers.from(ImmutableSet.of(emailer, emailer2, emailer3));
+
+        assertThat(eMailers.serialize()).isEqualTo(expected);
+    }
+}
diff --git a/mailbox/elasticsearch-v6/src/test/java/org/apache/james/mailbox/elasticsearch/v6/json/FieldImpl.java b/mailbox/elasticsearch-v6/src/test/java/org/apache/james/mailbox/elasticsearch/v6/json/FieldImpl.java
new file mode 100644
index 0000000..0525330
--- /dev/null
+++ b/mailbox/elasticsearch-v6/src/test/java/org/apache/james/mailbox/elasticsearch/v6/json/FieldImpl.java
@@ -0,0 +1,65 @@
+/****************************************************************
+ * 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.mailbox.elasticsearch.v6.json;
+
+import java.util.Objects;
+
+import org.apache.james.mime4j.stream.Field;
+import org.apache.james.mime4j.util.ByteSequence;
+
+public class FieldImpl implements Field {
+    private final String name;
+    private final String body;
+
+    public FieldImpl(String name, String body) {
+        this.name = name;
+        this.body = body;
+    }
+
+    @Override
+    public String getName() {
+        return name;
+    }
+
+    @Override
+    public String getBody() {
+        return body;
+    }
+
+    @Override
+    public ByteSequence getRaw() {
+        return null;
+    }
+
+    @Override
+    public int hashCode() {
+        return Objects.hash(name, body);
+    }
+
+    @Override
+    public boolean equals(Object o) {
+        if (o instanceof  FieldImpl) {
+            FieldImpl otherField = (FieldImpl) o;
+            return Objects.equals(name, otherField.name)
+                && Objects.equals(body, otherField.body);
+        }
+        return false;
+    }
+}
diff --git a/mailbox/elasticsearch-v6/src/test/java/org/apache/james/mailbox/elasticsearch/v6/json/HeaderCollectionTest.java b/mailbox/elasticsearch-v6/src/test/java/org/apache/james/mailbox/elasticsearch/v6/json/HeaderCollectionTest.java
new file mode 100644
index 0000000..649c61c
--- /dev/null
+++ b/mailbox/elasticsearch-v6/src/test/java/org/apache/james/mailbox/elasticsearch/v6/json/HeaderCollectionTest.java
@@ -0,0 +1,334 @@
+/****************************************************************
+ * 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.mailbox.elasticsearch.v6.json;
+
+import static org.assertj.core.api.Assertions.assertThat;
+import static org.assertj.core.api.Assertions.assertThatThrownBy;
+
+import java.time.format.DateTimeFormatter;
+import java.util.stream.Stream;
+
+import org.junit.jupiter.api.Test;
+import org.junit.jupiter.api.extension.ExtensionContext;
+import org.junit.jupiter.params.ParameterizedTest;
+import org.junit.jupiter.params.provider.Arguments;
+import org.junit.jupiter.params.provider.ArgumentsProvider;
+import org.junit.jupiter.params.provider.ArgumentsSource;
+
+class HeaderCollectionTest {
+
+    static class UTF8FromHeaderTestSource implements ArgumentsProvider {
+
+        @Override
+        public Stream<? extends Arguments> provideArguments(ExtensionContext context) throws Exception {
+            return Stream.of(
+                Arguments.of("=?UTF-8?B?RnLDqWTDqXJpYyBNQVJUSU4=?= <fm...@linagora.com>, Graham CROSMARIE <gc...@linagora.com>", "Frédéric MARTIN"),
+                Arguments.of("=?UTF-8?Q?=C3=9Csteli=C4=9Fhan_Ma=C5=9Frapa?= <us...@domain.tld>", "ÃœsteliÄŸhan MaÅŸrapa"),
+                Arguments.of("=?UTF-8?Q?Ke=C5=9Ffet_Turizm?= <ke...@domain.tld>", "KeÅŸfet Turizm"),
+                Arguments.of("=?UTF-8?Q?MODAL=C4=B0F?= <mo...@domain.tld>", "MODALÄ°F"));
+        }
+    }
+
+    private static final DateTimeFormatter DATE_TIME_FORMATTER = DateTimeFormatter.ofPattern("yyyy/MM/dd HH:mm:ss");
+
+    @Test
+    void simpleValueAddressHeaderShouldBeAddedToTheAddressSet() {
+        HeaderCollection headerCollection = HeaderCollection.builder()
+            .add(new FieldImpl("To", "ben.tellier@linagora.com"))
+            .build();
+
+        assertThat(headerCollection.getToAddressSet())
+            .containsOnly(new EMailer("ben.tellier@linagora.com", "ben.tellier@linagora.com"));
+    }
+
+    @Test
+    void comaSeparatedAddressShouldBeBothAddedToTheAddressSet() {
+        HeaderCollection headerCollection = HeaderCollection.builder()
+            .add(new FieldImpl("To", "ben.tellier@linagora.com, btellier@minet.net"))
+            .build();
+
+        assertThat(headerCollection.getToAddressSet())
+            .containsOnly(
+                new EMailer("ben.tellier@linagora.com", "ben.tellier@linagora.com"),
+                new EMailer("btellier@minet.net", "btellier@minet.net"));
+    }
+
+    @Test
+    void addressesOfTwoFieldsHavingTheSameNameShouldBeMerged() {
+        HeaderCollection headerCollection = HeaderCollection.builder()
+            .add(new FieldImpl("To", "ben.tellier@linagora.com"))
+            .add(new FieldImpl("To", "ben.tellier@linagora.com, btellier@minet.net"))
+            .build();
+
+        assertThat(headerCollection.getToAddressSet())
+            .containsOnly(
+                new EMailer("ben.tellier@linagora.com", "ben.tellier@linagora.com"),
+                new EMailer("btellier@minet.net", "btellier@minet.net"));
+    }
+
+    @Test
+    void displayNamesShouldBeRetreived() {
+        HeaderCollection headerCollection = HeaderCollection.builder()
+            .add(new FieldImpl("To", "Christophe Hamerling <ch...@linagora.com>"))
+            .build();
+
+        assertThat(headerCollection.getToAddressSet())
+            .containsOnly(new EMailer("Christophe Hamerling", "chri.hamerling@linagora.com"));
+    }
+
+    @ParameterizedTest
+    @ArgumentsSource(UTF8FromHeaderTestSource.class)
+    void displayNamesShouldBeRetrievedWhenEncodedWord(String encodedFromHeader, String nameOfFromAddress) {
+        HeaderCollection headerCollection = HeaderCollection.builder()
+            .add(new FieldImpl("From", encodedFromHeader))
+            .build();
+
+        assertThat(headerCollection.getFromAddressSet())
+            .extracting(EMailer::getName)
+            .contains(nameOfFromAddress);
+    }
+
+    @Test
+    void getHeadersShouldDecodeValues() {
+        HeaderCollection headerCollection = HeaderCollection.builder()
+            .add(new FieldImpl("From", "=?UTF-8?B?RnLDqWTDqXJpYyBNQVJUSU4=?= <fm...@linagora.com>, Graham CROSMARIE <gc...@linagora.com>"))
+            .build();
+
+        assertThat(headerCollection.getHeaders().get("from"))
+            .containsExactly("Frédéric MARTIN <fm...@linagora.com>, Graham CROSMARIE <gc...@linagora.com>");
+    }
+
+    @Test
+    void getHeadersShouldIgnoreHeadersWithDots() {
+        HeaderCollection headerCollection = HeaderCollection.builder()
+            .add(new FieldImpl("a.b.c", "value"))
+            .build();
+
+        assertThat(headerCollection.getHeaders().get("a.b.c"))
+            .isEmpty();
+    }
+
+    @Test
+    void addressWithTwoDisplayNamesOnTheSameFieldShouldBeRetrieved() {
+        HeaderCollection headerCollection = HeaderCollection.builder()
+            .add(new FieldImpl("From", "Christophe Hamerling <ch...@linagora.com>, Graham CROSMARIE <gr...@linagora.com>"))
+            .build();
+
+        assertThat(headerCollection.getFromAddressSet())
+            .containsOnly(new EMailer("Christophe Hamerling", "chri.hamerling@linagora.com"),
+                new EMailer("Graham CROSMARIE", "grah.crosmarie@linagora.com"));
+    }
+
+    @Test
+    void foldedFromHeaderShouldBeSupported() {
+        HeaderCollection headerCollection = HeaderCollection.builder()
+            .add(new FieldImpl("From", "Christophe Hamerling <ch...@linagora.com>,\r\n" +
+                " Graham CROSMARIE <gr...@linagora.com>"))
+            .build();
+
+        assertThat(headerCollection.getFromAddressSet())
+            .containsOnly(new EMailer("Christophe Hamerling", "chri.hamerling@linagora.com"),
+                new EMailer("Graham CROSMARIE", "grah.crosmarie@linagora.com"));
+    }
+
+    @Test
+    void foldedHeaderShouldBeSupported() {
+        HeaderCollection headerCollection = HeaderCollection.builder()
+            .add(new FieldImpl("From", "Christophe Hamerling <ch...@linagora.com>,\r\n" +
+                " Graham CROSMARIE <gr...@linagora.com>"))
+            .build();
+
+        assertThat(headerCollection.getHeaders().get("from"))
+            .containsOnly("Christophe Hamerling <ch...@linagora.com>, Graham CROSMARIE <gr...@linagora.com>");
+    }
+
+    @Test
+    void mixingAddressWithDisplayNamesWithOthersShouldBeAllowed() {
+        HeaderCollection headerCollection = HeaderCollection.builder()
+            .add(new FieldImpl("To", "Christophe Hamerling <ch...@linagora.com>, grah.crosmarie@linagora.com"))
+            .build();
+
+        assertThat(headerCollection.getToAddressSet())
+            .containsOnly(new EMailer("Christophe Hamerling", "chri.hamerling@linagora.com"),
+                new EMailer("grah.crosmarie@linagora.com", "grah.crosmarie@linagora.com"));
+    }
+
+    @Test
+    void displayNamesShouldBeRetreivedOnCc() {
+        HeaderCollection headerCollection = HeaderCollection.builder()
+            .add(new FieldImpl("Cc", "Christophe Hamerling <ch...@linagora.com>"))
+            .build();
+
+        assertThat(headerCollection.getCcAddressSet())
+            .containsOnly(new EMailer("Christophe Hamerling", "chri.hamerling@linagora.com"));
+    }
+
+    @Test
+    void displayNamesShouldBeRetreivedOnReplyTo() {
+        HeaderCollection headerCollection = HeaderCollection.builder()
+            .add(new FieldImpl("Reply-To", "Christophe Hamerling <ch...@linagora.com>"))
+            .build();
+
+        assertThat(headerCollection.getReplyToAddressSet())
+            .containsOnly(new EMailer("Christophe Hamerling", "chri.hamerling@linagora.com"));
+    }
+
+    @Test
+    void displayNamesShouldBeRetreivedOnBcc() {
+        HeaderCollection headerCollection = HeaderCollection.builder()
+            .add(new FieldImpl("Bcc", "Christophe Hamerling <ch...@linagora.com>"))
+            .build();
+
+        assertThat(headerCollection.getBccAddressSet())
+            .containsOnly(new EMailer("Christophe Hamerling", "chri.hamerling@linagora.com"));
+    }
+
+    @Test
+    void headerContaingNoAddressShouldBeConsideredBothAsNameAndAddress() {
+        HeaderCollection headerCollection = HeaderCollection.builder()
+            .add(new FieldImpl("Bcc", "Not an address"))
+            .build();
+
+        assertThat(headerCollection.getBccAddressSet())
+            .containsOnly(new EMailer("Not an address", "Not an address"));
+    }
+
+    @Test
+    void unclosedAddressSubpartShouldBeWellHandled() {
+        HeaderCollection headerCollection = HeaderCollection.builder()
+            .add(new FieldImpl("Bcc", "Mickey <tricky@mouse.com"))
+            .build();
+
+        assertThat(headerCollection.getBccAddressSet())
+            .containsOnly(new EMailer("Mickey", "tricky@mouse.com"));
+    }
+
+    @Test
+    void notComaSeparatedAddressSubpartShouldBeWellHandled() {
+        HeaderCollection headerCollection = HeaderCollection.builder()
+            .add(new FieldImpl("Bcc", "Mickey <tr...@mouse.com> Miny<he...@polo.com>"))
+            .build();
+
+        assertThat(headerCollection.getBccAddressSet())
+            .containsOnly(new EMailer("Mickey", "tricky@mouse.com"),
+                new EMailer("Miny", "hello@polo.com"));
+    }
+
+    @Test
+    void notSeparatedAddressSubpartShouldBeWellHandled() {
+        HeaderCollection headerCollection = HeaderCollection.builder()
+            .add(new FieldImpl("Bcc", "Mickey <tr...@polo.com>"))
+            .build();
+
+        assertThat(headerCollection.getBccAddressSet())
+            .containsOnly(new EMailer("Mickey", "tricky@mouse.com"),
+                new EMailer("Miny", "hello@polo.com"));
+    }
+
+    @Test
+    void dateShouldBeRetreived() {
+        HeaderCollection headerCollection = HeaderCollection.builder()
+            .add(new FieldImpl("Date", "Thu, 4 Jun 2015 06:08:41 +0200"))
+            .build();
+
+        assertThat(DATE_TIME_FORMATTER.format(headerCollection.getSentDate().get()))
+            .isEqualTo("2015/06/04 06:08:41");
+    }
+
+    @Test
+    void partialYearShouldBeCompleted() {
+        HeaderCollection headerCollection = HeaderCollection.builder()
+            .add(new FieldImpl("Date", "Thu, 4 Jun 15 06:08:41 +0200"))
+            .build();
+
+        assertThat(DATE_TIME_FORMATTER.format(headerCollection.getSentDate().get()))
+            .isEqualTo("2015/06/04 06:08:41");
+    }
+
+    @Test
+    void nonStandardDatesShouldBeRetreived() {
+        HeaderCollection headerCollection = HeaderCollection.builder()
+            .add(new FieldImpl("Date", "Thu, 4 Jun 2015 06:08:41 +0200 (UTC)"))
+            .build();
+
+        assertThat(DATE_TIME_FORMATTER.format(headerCollection.getSentDate().get()))
+            .isEqualTo("2015/06/04 06:08:41");
+    }
+
+    @Test
+    void dateShouldBeAbsentOnInvalidHeader() {
+        HeaderCollection headerCollection = HeaderCollection.builder()
+            .add(new FieldImpl("Date", "Not a date"))
+            .build();
+
+        assertThat(headerCollection.getSentDate().isPresent())
+            .isFalse();
+    }
+
+    @Test
+    void subjectsShouldBeWellRetrieved() {
+        String subject = "A fantastic ElasticSearch module will be available soon for JAMES";
+        HeaderCollection headerCollection = HeaderCollection.builder()
+            .add(new FieldImpl("Subject", subject))
+            .build();
+
+        assertThat(headerCollection.getSubjectSet()).containsOnly("A fantastic ElasticSearch module will be available soon for JAMES");
+    }
+
+    @Test
+    void getMessageIDShouldReturnMessageIdValue() {
+        String messageID = "<ab...@123>";
+        HeaderCollection headerCollection = HeaderCollection.builder()
+            .add(new FieldImpl("Message-ID", messageID))
+            .build();
+
+        assertThat(headerCollection.getMessageID())
+            .contains(messageID);
+    }
+
+    @Test
+    void getMessageIDShouldReturnLatestEncounteredMessageIdValue() {
+        String messageID = "<ab...@123>";
+        HeaderCollection headerCollection = HeaderCollection.builder()
+            .add(new FieldImpl("Message-ID", "<ot...@toto.com>"))
+            .add(new FieldImpl("Message-ID", messageID))
+            .build();
+
+        assertThat(headerCollection.getMessageID())
+            .contains(messageID);
+    }
+
+    @Test
+    void getMessageIDShouldReturnEmptyWhenNoMessageId() {
+        HeaderCollection headerCollection = HeaderCollection.builder()
+            .add(new FieldImpl("Other", "value"))
+            .build();
+
+        assertThat(headerCollection.getMessageID())
+            .isEmpty();
+    }
+
+    @Test
+    void nullFieldShouldThrow() {
+        assertThatThrownBy(() -> HeaderCollection.builder().add(null).build())
+            .isInstanceOf(NullPointerException.class);
+    }
+
+}
diff --git a/mailbox/elasticsearch-v6/src/test/java/org/apache/james/mailbox/elasticsearch/v6/json/IndexableMessageTest.java b/mailbox/elasticsearch-v6/src/test/java/org/apache/james/mailbox/elasticsearch/v6/json/IndexableMessageTest.java
new file mode 100644
index 0000000..c9e2e19
--- /dev/null
+++ b/mailbox/elasticsearch-v6/src/test/java/org/apache/james/mailbox/elasticsearch/v6/json/IndexableMessageTest.java
@@ -0,0 +1,578 @@
+/****************************************************************
+ * 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.mailbox.elasticsearch.v6.json;
+
+import static org.assertj.core.api.Assertions.assertThat;
+import static org.mockito.ArgumentMatchers.any;
+import static org.mockito.Mockito.mock;
+import static org.mockito.Mockito.when;
+
+import java.io.ByteArrayInputStream;
+import java.io.IOException;
+import java.time.ZoneId;
+import java.util.Optional;
+
+import javax.mail.Flags;
+
+import org.apache.james.core.User;
+import org.apache.james.mailbox.MessageUid;
+import org.apache.james.mailbox.elasticsearch.v6.IndexAttachments;
+import org.apache.james.mailbox.extractor.ParsedContent;
+import org.apache.james.mailbox.extractor.TextExtractor;
+import org.apache.james.mailbox.inmemory.InMemoryMessageId;
+import org.apache.james.mailbox.model.MessageId;
+import org.apache.james.mailbox.model.TestId;
+import org.apache.james.mailbox.store.extractor.DefaultTextExtractor;
+import org.apache.james.mailbox.store.mail.model.MailboxMessage;
+import org.apache.james.mailbox.store.mail.model.impl.PropertyBuilder;
+import org.apache.james.mailbox.store.mail.model.impl.SimpleProperty;
+import org.apache.james.mailbox.tika.TikaConfiguration;
+import org.apache.james.mailbox.tika.TikaContainerSingletonRule;
+import org.apache.james.mailbox.tika.TikaHttpClientImpl;
+import org.apache.james.mailbox.tika.TikaTextExtractor;
+import org.apache.james.metrics.api.NoopMetricFactory;
+import org.assertj.core.api.iterable.Extractor;
+import org.junit.Before;
+import org.junit.ClassRule;
+import org.junit.Test;
+
+import com.google.common.collect.ImmutableList;
+import com.google.common.collect.ImmutableMap;
+
+public class IndexableMessageTest {
+    private static final MessageUid MESSAGE_UID = MessageUid.of(154);
+
+    @ClassRule
+    public static TikaContainerSingletonRule tika = TikaContainerSingletonRule.rule;
+
+    private TikaTextExtractor textExtractor;
+
+    @Before
+    public void setUp() throws Exception {
+        textExtractor = new TikaTextExtractor(new NoopMetricFactory(), new TikaHttpClientImpl(TikaConfiguration.builder()
+                .host(tika.getIp())
+                .port(tika.getPort())
+                .timeoutInMillis(tika.getTimeoutInMillis())
+                .build()));
+    }
+
+    @Test
+    public void textShouldBeEmptyWhenNoMatchingHeaders() throws Exception {
+        MailboxMessage mailboxMessage = mock(MailboxMessage.class);
+        TestId mailboxId = TestId.of(1);
+        when(mailboxMessage.getMailboxId())
+            .thenReturn(mailboxId);
+        when(mailboxMessage.getMessageId())
+            .thenReturn(InMemoryMessageId.of(42));
+        when(mailboxMessage.getFullContent())
+            .thenReturn(new ByteArrayInputStream("".getBytes()));
+        when(mailboxMessage.createFlags())
+            .thenReturn(new Flags());
+        when(mailboxMessage.getUid())
+            .thenReturn(MESSAGE_UID);
+
+        IndexableMessage indexableMessage = IndexableMessage.builder()
+                .message(mailboxMessage)
+                .users(ImmutableList.of(User.fromUsername("username")))
+                .extractor(new DefaultTextExtractor())
+                .zoneId(ZoneId.of("Europe/Paris"))
+                .indexAttachments(IndexAttachments.NO)
+                .build();
+
+        assertThat(indexableMessage.getText()).isEmpty();
+    }
+
+    @Test
+    public void textShouldContainsFromWhenFrom() throws Exception {
+        MailboxMessage mailboxMessage = mock(MailboxMessage.class);
+        TestId mailboxId = TestId.of(1);
+        when(mailboxMessage.getMailboxId())
+            .thenReturn(mailboxId);
+        when(mailboxMessage.getMessageId())
+            .thenReturn(InMemoryMessageId.of(42));
+        when(mailboxMessage.getFullContent())
+            .thenReturn(new ByteArrayInputStream("From: First user <us...@james.org>\nFrom: Second user <us...@james.org>".getBytes()));
+        when(mailboxMessage.createFlags())
+            .thenReturn(new Flags());
+        when(mailboxMessage.getUid())
+            .thenReturn(MESSAGE_UID);
+
+        IndexableMessage indexableMessage = IndexableMessage.builder()
+                .message(mailboxMessage)
+                .users(ImmutableList.of(User.fromUsername("username")))
+                .extractor(new DefaultTextExtractor())
+                .zoneId(ZoneId.of("Europe/Paris"))
+                .indexAttachments(IndexAttachments.NO)
+                .build();
+
+        assertThat(indexableMessage.getText()).isEqualTo("Second user user2@james.org First user user@james.org");
+    }
+
+    @Test
+    public void textShouldContainsToWhenTo() throws Exception {
+        MailboxMessage mailboxMessage = mock(MailboxMessage.class);
+        TestId mailboxId = TestId.of(1);
+        when(mailboxMessage.getMailboxId())
+            .thenReturn(mailboxId);
+        when(mailboxMessage.getMessageId())
+            .thenReturn(InMemoryMessageId.of(42));
+        when(mailboxMessage.getFullContent())
+            .thenReturn(new ByteArrayInputStream("To: First to <us...@james.org>\nTo: Second to <us...@james.org>".getBytes()));
+        when(mailboxMessage.createFlags())
+            .thenReturn(new Flags());
+        when(mailboxMessage.getUid())
+            .thenReturn(MESSAGE_UID);
+
+        IndexableMessage indexableMessage = IndexableMessage.builder()
+                .message(mailboxMessage)
+                .users(ImmutableList.of(User.fromUsername("username")))
+                .extractor(new DefaultTextExtractor())
+                .zoneId(ZoneId.of("Europe/Paris"))
+                .indexAttachments(IndexAttachments.NO)
+                .build();
+
+        assertThat(indexableMessage.getText()).isEqualTo("First to user@james.org Second to user2@james.org");
+    }
+
+    @Test
+    public void textShouldContainsCcWhenCc() throws Exception {
+        MailboxMessage mailboxMessage = mock(MailboxMessage.class);
+        TestId mailboxId = TestId.of(1);
+        when(mailboxMessage.getMailboxId())
+            .thenReturn(mailboxId);
+        when(mailboxMessage.getMessageId())
+            .thenReturn(InMemoryMessageId.of(42));
+        when(mailboxMessage.getFullContent())
+            .thenReturn(new ByteArrayInputStream("Cc: First cc <us...@james.org>\nCc: Second cc <us...@james.org>".getBytes()));
+        when(mailboxMessage.createFlags())
+            .thenReturn(new Flags());
+        when(mailboxMessage.getUid())
+            .thenReturn(MESSAGE_UID);
+
+        IndexableMessage indexableMessage = IndexableMessage.builder()
+                .message(mailboxMessage)
+                .users(ImmutableList.of(User.fromUsername("username")))
+                .extractor(new DefaultTextExtractor())
+                .zoneId(ZoneId.of("Europe/Paris"))
+                .indexAttachments(IndexAttachments.NO)
+                .build();
+
+        assertThat(indexableMessage.getText()).isEqualTo("First cc user@james.org Second cc user2@james.org");
+    }
+
+    @Test
+    public void textShouldContainsBccWhenBcc() throws Exception {
+        MailboxMessage mailboxMessage = mock(MailboxMessage.class);
+        TestId mailboxId = TestId.of(1);
+        when(mailboxMessage.getMailboxId())
+            .thenReturn(mailboxId);
+        when(mailboxMessage.getMessageId())
+            .thenReturn(InMemoryMessageId.of(42));
+        when(mailboxMessage.getUid())
+            .thenReturn(MESSAGE_UID);
+        when(mailboxMessage.getFullContent())
+            .thenReturn(new ByteArrayInputStream("Bcc: First bcc <us...@james.org>\nBcc: Second bcc <us...@james.org>".getBytes()));
+        when(mailboxMessage.createFlags())
+            .thenReturn(new Flags());
+
+        IndexableMessage indexableMessage = IndexableMessage.builder()
+                .message(mailboxMessage)
+                .users(ImmutableList.of(User.fromUsername("username")))
+                .extractor(new DefaultTextExtractor())
+                .zoneId(ZoneId.of("Europe/Paris"))
+                .indexAttachments(IndexAttachments.NO)
+                .build();
+
+        assertThat(indexableMessage.getText()).isEqualTo("Second bcc user2@james.org First bcc user@james.org");
+    }
+
+    @Test
+    public void textShouldContainsSubjectsWhenSubjects() throws Exception {
+        MailboxMessage mailboxMessage = mock(MailboxMessage.class);
+        TestId mailboxId = TestId.of(1);
+        when(mailboxMessage.getMailboxId())
+            .thenReturn(mailboxId);
+        when(mailboxMessage.getMessageId())
+            .thenReturn(InMemoryMessageId.of(42));
+        when(mailboxMessage.getFullContent())
+            .thenReturn(new ByteArrayInputStream("Subject: subject1\nSubject: subject2".getBytes()));
+        when(mailboxMessage.createFlags())
+            .thenReturn(new Flags());
+        when(mailboxMessage.getUid())
+            .thenReturn(MESSAGE_UID);
+
+        IndexableMessage indexableMessage = IndexableMessage.builder()
+                .message(mailboxMessage)
+                .users(ImmutableList.of(User.fromUsername("username")))
+                .extractor(new DefaultTextExtractor())
+                .zoneId(ZoneId.of("Europe/Paris"))
+                .indexAttachments(IndexAttachments.NO)
+                .build();
+
+        assertThat(indexableMessage.getText()).isEqualTo("subject1 subject2");
+    }
+
+    @Test
+    public void textShouldContainsBodyWhenBody() throws Exception {
+        MailboxMessage mailboxMessage = mock(MailboxMessage.class);
+        TestId mailboxId = TestId.of(1);
+        when(mailboxMessage.getMailboxId())
+            .thenReturn(mailboxId);
+        when(mailboxMessage.getMessageId())
+            .thenReturn(InMemoryMessageId.of(42));
+        when(mailboxMessage.getFullContent())
+            .thenReturn(new ByteArrayInputStream("\nMy body".getBytes()));
+        when(mailboxMessage.createFlags())
+            .thenReturn(new Flags());
+        when(mailboxMessage.getUid())
+            .thenReturn(MESSAGE_UID);
+
+        IndexableMessage indexableMessage = IndexableMessage.builder()
+                .message(mailboxMessage)
+                .users(ImmutableList.of(User.fromUsername("username")))
+                .extractor(new DefaultTextExtractor())
+                .zoneId(ZoneId.of("Europe/Paris"))
+                .indexAttachments(IndexAttachments.NO)
+                .build();
+
+        assertThat(indexableMessage.getText()).isEqualTo("My body");
+    }
+
+    @Test
+    public void textShouldContainsAllFieldsWhenAllSet() throws Exception {
+        MailboxMessage mailboxMessage = mock(MailboxMessage.class);
+        TestId mailboxId = TestId.of(1);
+        when(mailboxMessage.getMailboxId())
+            .thenReturn(mailboxId);
+        when(mailboxMessage.getMessageId())
+            .thenReturn(InMemoryMessageId.of(42));
+        when(mailboxMessage.getFullContent())
+            .thenReturn(ClassLoader.getSystemResourceAsStream("eml/mailWithHeaders.eml"));
+        when(mailboxMessage.createFlags())
+            .thenReturn(new Flags());
+        when(mailboxMessage.getUid())
+            .thenReturn(MESSAGE_UID);
+
+        IndexableMessage indexableMessage = IndexableMessage.builder()
+                .message(mailboxMessage)
+                .users(ImmutableList.of(User.fromUsername("username")))
+                .extractor(new DefaultTextExtractor())
+                .zoneId(ZoneId.of("Europe/Paris"))
+                .indexAttachments(IndexAttachments.NO)
+                .build();
+
+        assertThat(indexableMessage.getText()).isEqualTo("Ad Min admin@opush.test " +
+                "a@test a@test B b@test " + 
+                "c@test c@test " +
+                "dD d@test " + 
+                "my subject " + 
+                "Mail content\n" +
+                "\n" +
+                "-- \n" + 
+                "Ad Min\n");
+    }
+
+    @Test
+    public void hasAttachmentsShouldReturnTrueWhenPropertyIsPresentAndTrue() throws IOException {
+        //Given
+        MailboxMessage  mailboxMessage = mock(MailboxMessage.class);
+        TestId mailboxId = TestId.of(1);
+        when(mailboxMessage.getMailboxId())
+            .thenReturn(mailboxId);
+        when(mailboxMessage.getMessageId())
+            .thenReturn(InMemoryMessageId.of(42));
+        when(mailboxMessage.getFullContent())
+            .thenReturn(ClassLoader.getSystemResourceAsStream("eml/mailWithHeaders.eml"));
+        when(mailboxMessage.createFlags())
+            .thenReturn(new Flags());
+        when(mailboxMessage.getUid())
+            .thenReturn(MESSAGE_UID);
+        when(mailboxMessage.getProperties()).thenReturn(ImmutableList.of(IndexableMessage.HAS_ATTACHMENT_PROPERTY));
+
+        // When
+        IndexableMessage indexableMessage = IndexableMessage.builder()
+                .message(mailboxMessage)
+                .users(ImmutableList.of(User.fromUsername("username")))
+                .extractor(new DefaultTextExtractor())
+                .zoneId(ZoneId.of("Europe/Paris"))
+                .indexAttachments(IndexAttachments.YES)
+                .build();
+
+        // Then
+        assertThat(indexableMessage.getHasAttachment()).isTrue();
+    }
+
+    @Test
+    public void hasAttachmentsShouldReturnFalseWhenPropertyIsPresentButFalse() throws IOException {
+        //Given
+        MailboxMessage  mailboxMessage = mock(MailboxMessage.class);
+        TestId mailboxId = TestId.of(1);
+        when(mailboxMessage.getMailboxId())
+            .thenReturn(mailboxId);
+        when(mailboxMessage.getMessageId())
+            .thenReturn(InMemoryMessageId.of(42));
+        when(mailboxMessage.getFullContent())
+            .thenReturn(ClassLoader.getSystemResourceAsStream("eml/mailWithHeaders.eml"));
+        when(mailboxMessage.createFlags())
+            .thenReturn(new Flags());
+        when(mailboxMessage.getUid())
+            .thenReturn(MESSAGE_UID);
+        when(mailboxMessage.getProperties())
+            .thenReturn(ImmutableList.of(new SimpleProperty(PropertyBuilder.JAMES_INTERNALS, PropertyBuilder.HAS_ATTACHMENT, "false")));
+
+        // When
+        IndexableMessage indexableMessage = IndexableMessage.builder()
+                .message(mailboxMessage)
+                .users(ImmutableList.of(User.fromUsername("username")))
+                .extractor(new DefaultTextExtractor())
+                .zoneId(ZoneId.of("Europe/Paris"))
+                .indexAttachments(IndexAttachments.NO)
+                .build();
+
+        // Then
+        assertThat(indexableMessage.getHasAttachment()).isFalse();
+    }
+
+    @Test
+    public void hasAttachmentsShouldReturnFalseWhenPropertyIsAbsent() throws IOException {
+        //Given
+        MailboxMessage  mailboxMessage = mock(MailboxMessage.class);
+        TestId mailboxId = TestId.of(1);
+        when(mailboxMessage.getMailboxId())
+            .thenReturn(mailboxId);
+        when(mailboxMessage.getMessageId())
+            .thenReturn(InMemoryMessageId.of(42));
+        when(mailboxMessage.getFullContent())
+            .thenReturn(ClassLoader.getSystemResourceAsStream("eml/mailWithHeaders.eml"));
+        when(mailboxMessage.createFlags())
+            .thenReturn(new Flags());
+        when(mailboxMessage.getUid())
+            .thenReturn(MESSAGE_UID);
+        when(mailboxMessage.getProperties())
+            .thenReturn(ImmutableList.of());
+
+        // When
+        IndexableMessage indexableMessage = IndexableMessage.builder()
+                .message(mailboxMessage)
+                .users(ImmutableList.of(User.fromUsername("username")))
+                .extractor(new DefaultTextExtractor())
+                .zoneId(ZoneId.of("Europe/Paris"))
+                .indexAttachments(IndexAttachments.NO)
+                .build();
+
+        // Then
+        assertThat(indexableMessage.getHasAttachment()).isFalse();
+    }
+
+    @Test
+    public void attachmentsShouldNotBeenIndexedWhenAsked() throws Exception {
+        //Given
+        MailboxMessage mailboxMessage = mock(MailboxMessage.class);
+        TestId mailboxId = TestId.of(1);
+        when(mailboxMessage.getMailboxId())
+            .thenReturn(mailboxId);
+        when(mailboxMessage.getMessageId())
+            .thenReturn(InMemoryMessageId.of(42));
+        when(mailboxMessage.getFullContent())
+            .thenReturn(ClassLoader.getSystemResourceAsStream("eml/mailWithHeaders.eml"));
+        when(mailboxMessage.createFlags())
+            .thenReturn(new Flags());
+        when(mailboxMessage.getUid())
+            .thenReturn(MESSAGE_UID);
+
+        // When
+        IndexableMessage indexableMessage = IndexableMessage.builder()
+                .message(mailboxMessage)
+                .users(ImmutableList.of(User.fromUsername("username")))
+                .extractor(new DefaultTextExtractor())
+                .zoneId(ZoneId.of("Europe/Paris"))
+                .indexAttachments(IndexAttachments.NO)
+                .build();
+
+        // Then
+        assertThat(indexableMessage.getAttachments()).isEmpty();
+    }
+
+    @Test
+    public void attachmentsShouldBeenIndexedWhenAsked() throws Exception {
+        //Given
+        MailboxMessage mailboxMessage = mock(MailboxMessage.class);
+        TestId mailboxId = TestId.of(1);
+        when(mailboxMessage.getMailboxId())
+            .thenReturn(mailboxId);
+        when(mailboxMessage.getMessageId())
+            .thenReturn(InMemoryMessageId.of(42));
+        when(mailboxMessage.getFullContent())
+            .thenReturn(ClassLoader.getSystemResourceAsStream("eml/emailWith3Attachments.eml"));
+        when(mailboxMessage.createFlags())
+            .thenReturn(new Flags());
+        when(mailboxMessage.getUid())
+            .thenReturn(MESSAGE_UID);
+
+        // When
+        IndexableMessage indexableMessage = IndexableMessage.builder()
+                .message(mailboxMessage)
+                .users(ImmutableList.of(User.fromUsername("username")))
+                .extractor(new DefaultTextExtractor())
+                .zoneId(ZoneId.of("Europe/Paris"))
+                .indexAttachments(IndexAttachments.YES)
+                .build();
+
+        // Then
+        assertThat(indexableMessage.getAttachments()).isNotEmpty();
+    }
+
+    @Test
+    public void otherAttachmentsShouldBeenIndexedWhenOneOfThemCannotBeParsed() throws Exception {
+        //Given
+        MailboxMessage mailboxMessage = mock(MailboxMessage.class);
+        TestId mailboxId = TestId.of(1);
+        when(mailboxMessage.getMailboxId())
+            .thenReturn(mailboxId);
+        when(mailboxMessage.getMessageId())
+            .thenReturn(InMemoryMessageId.of(42));
+        when(mailboxMessage.getFullContent())
+            .thenReturn(ClassLoader.getSystemResourceAsStream("eml/emailWith3Attachments.eml"));
+        when(mailboxMessage.createFlags())
+            .thenReturn(new Flags());
+        when(mailboxMessage.getUid())
+            .thenReturn(MESSAGE_UID);
+
+        TextExtractor textExtractor = mock(TextExtractor.class);
+        when(textExtractor.extractContent(any(), any()))
+            .thenReturn(new ParsedContent(Optional.of("first attachment content"), ImmutableMap.of()))
+            .thenThrow(new RuntimeException("second cannot be parsed"))
+            .thenReturn(new ParsedContent(Optional.of("third attachment content"), ImmutableMap.of()));
+
+        // When
+        IndexableMessage indexableMessage = IndexableMessage.builder()
+                .message(mailboxMessage)
+                .users(ImmutableList.of(User.fromUsername("username")))
+                .extractor(textExtractor)
+                .zoneId(ZoneId.of("Europe/Paris"))
+                .indexAttachments(IndexAttachments.YES)
+                .build();
+
+        // Then
+        assertThat(indexableMessage.getAttachments())
+            .extracting(new TextualBodyExtractor())
+            .contains("first attachment content", TextualBodyExtractor.NO_TEXTUAL_BODY, "third attachment content");
+    }
+
+    private static class TextualBodyExtractor implements Extractor<MimePart, String> {
+
+        public static final String NO_TEXTUAL_BODY = "The textual body is not present";
+
+        @Override
+        public String extract(MimePart input) {
+            return input.getTextualBody().orElse(NO_TEXTUAL_BODY);
+        }
+    }
+
+    @Test
+    public void messageShouldBeIndexedEvenIfTikaParserThrowsAnError() throws Exception {
+        //Given
+        MailboxMessage mailboxMessage = mock(MailboxMessage.class);
+        TestId mailboxId = TestId.of(1);
+        when(mailboxMessage.getMailboxId())
+            .thenReturn(mailboxId);
+        when(mailboxMessage.getMessageId())
+            .thenReturn(InMemoryMessageId.of(42));
+        when(mailboxMessage.getFullContent())
+            .thenReturn(ClassLoader.getSystemResourceAsStream("eml/bodyMakeTikaToFail.eml"));
+        when(mailboxMessage.createFlags())
+            .thenReturn(new Flags());
+        when(mailboxMessage.getUid())
+            .thenReturn(MESSAGE_UID);
+
+        // When
+        IndexableMessage indexableMessage = IndexableMessage.builder()
+                .message(mailboxMessage)
+                .users(ImmutableList.of(User.fromUsername("username")))
+                .extractor(textExtractor)
+                .zoneId(ZoneId.of("Europe/Paris"))
+                .indexAttachments(IndexAttachments.YES)
+                .build();
+
+        // Then
+        assertThat(indexableMessage.getText()).contains("subject should be parsed");
+    }
+
+    @Test
+    public void shouldHandleCorrectlyMessageIdHavingSerializeMethodThatReturnNull() throws Exception {
+       MessageId invalidMessageIdThatReturnNull = mock(MessageId.class);
+       when(invalidMessageIdThatReturnNull.serialize())
+           .thenReturn(null);
+       
+        // When
+        MailboxMessage mailboxMessage = mock(MailboxMessage.class);
+        TestId mailboxId = TestId.of(1);
+        when(mailboxMessage.getMailboxId())
+            .thenReturn(mailboxId);
+        when(mailboxMessage.getMessageId())
+            .thenReturn(invalidMessageIdThatReturnNull);
+        when(mailboxMessage.getFullContent())
+            .thenReturn(ClassLoader.getSystemResourceAsStream("eml/bodyMakeTikaToFail.eml"));
+        when(mailboxMessage.createFlags())
+            .thenReturn(new Flags());
+        when(mailboxMessage.getUid())
+            .thenReturn(MESSAGE_UID);
+
+        IndexableMessage indexableMessage = IndexableMessage.builder()
+                .message(mailboxMessage)
+                .users(ImmutableList.of(User.fromUsername("username")))
+                .extractor(textExtractor)
+                .zoneId(ZoneId.of("Europe/Paris"))
+                .indexAttachments(IndexAttachments.YES)
+                .build();
+
+        // Then
+        assertThat(indexableMessage.getMessageId()).isNull();
+    }
+
+    @Test
+    public void shouldHandleCorrectlyNullMessageId() throws Exception {
+       
+        // When
+        MailboxMessage mailboxMessage = mock(MailboxMessage.class);
+        TestId mailboxId = TestId.of(1);
+        when(mailboxMessage.getMailboxId())
+            .thenReturn(mailboxId);
+        when(mailboxMessage.getMessageId())
+            .thenReturn(null);
+        when(mailboxMessage.getFullContent())
+            .thenReturn(ClassLoader.getSystemResourceAsStream("eml/bodyMakeTikaToFail.eml"));
+        when(mailboxMessage.createFlags())
+            .thenReturn(new Flags());
+        when(mailboxMessage.getUid())
+            .thenReturn(MESSAGE_UID);
+
+        IndexableMessage indexableMessage = IndexableMessage.builder()
+                .message(mailboxMessage)
+                .users(ImmutableList.of(User.fromUsername("username")))
+                .extractor(textExtractor)
+                .zoneId(ZoneId.of("Europe/Paris"))
+                .indexAttachments(IndexAttachments.YES)
+                .build();
+
+        // Then
+        assertThat(indexableMessage.getMessageId()).isNull();
+    }
+}
diff --git a/mailbox/elasticsearch-v6/src/test/java/org/apache/james/mailbox/elasticsearch/v6/json/MessageToElasticSearchJsonTest.java b/mailbox/elasticsearch-v6/src/test/java/org/apache/james/mailbox/elasticsearch/v6/json/MessageToElasticSearchJsonTest.java
new file mode 100644
index 0000000..9c840be
--- /dev/null
+++ b/mailbox/elasticsearch-v6/src/test/java/org/apache/james/mailbox/elasticsearch/v6/json/MessageToElasticSearchJsonTest.java
@@ -0,0 +1,388 @@
+/****************************************************************
+ * 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.mailbox.elasticsearch.v6.json;
+
+import static net.javacrumbs.jsonunit.assertj.JsonAssertions.assertThatJson;
+import static net.javacrumbs.jsonunit.core.Option.IGNORING_ARRAY_ORDER;
+import static net.javacrumbs.jsonunit.core.Option.IGNORING_VALUES;
+import static org.assertj.core.api.Assertions.assertThatThrownBy;
+
+import java.io.IOException;
+import java.nio.charset.StandardCharsets;
+import java.time.ZoneId;
+import java.util.Date;
+
+import javax.mail.Flags;
+import javax.mail.util.SharedByteArrayInputStream;
+
+import org.apache.james.core.User;
+import org.apache.james.mailbox.FlagsBuilder;
+import org.apache.james.mailbox.MessageUid;
+import org.apache.james.mailbox.elasticsearch.v6.IndexAttachments;
+import org.apache.james.mailbox.extractor.TextExtractor;
+import org.apache.james.mailbox.model.MessageId;
+import org.apache.james.mailbox.model.TestId;
+import org.apache.james.mailbox.model.TestMessageId;
+import org.apache.james.mailbox.store.extractor.DefaultTextExtractor;
+import org.apache.james.mailbox.store.mail.model.MailboxMessage;
+import org.apache.james.mailbox.store.mail.model.impl.PropertyBuilder;
+import org.apache.james.mailbox.store.mail.model.impl.SimpleMailboxMessage;
+import org.apache.james.mailbox.tika.TikaConfiguration;
+import org.apache.james.mailbox.tika.TikaContainerSingletonRule;
+import org.apache.james.mailbox.tika.TikaHttpClientImpl;
+import org.apache.james.mailbox.tika.TikaTextExtractor;
+import org.apache.james.metrics.api.NoopMetricFactory;
+import org.apache.james.util.ClassLoaderUtils;
+import org.junit.Before;
+import org.junit.ClassRule;
+import org.junit.Test;
+
+import com.google.common.collect.ImmutableList;
+
+public class MessageToElasticSearchJsonTest {
+    private static final int SIZE = 25;
+    private static final int BODY_START_OCTET = 100;
+    private static final TestId MAILBOX_ID = TestId.of(18L);
+    private static final MessageId MESSAGE_ID = TestMessageId.of(184L);
+    private static final long MOD_SEQ = 42L;
+    private static final MessageUid UID = MessageUid.of(25);
+    private static final String USERNAME = "username";
+    private static final User USER = User.fromUsername(USERNAME);
+
+    private TextExtractor textExtractor;
+
+    private Date date;
+    private PropertyBuilder propertyBuilder;
+
+    @ClassRule
+    public static TikaContainerSingletonRule tika = TikaContainerSingletonRule.rule;
+
+    @Before
+    public void setUp() throws Exception {
+        textExtractor = new TikaTextExtractor(new NoopMetricFactory(), new TikaHttpClientImpl(TikaConfiguration.builder()
+                .host(tika.getIp())
+                .port(tika.getPort())
+                .timeoutInMillis(tika.getTimeoutInMillis())
+                .build()));
+        // 2015/06/07 00:00:00 0200 (Paris time zone)
+        date = new Date(1433628000000L);
+        propertyBuilder = new PropertyBuilder();
+        propertyBuilder.setMediaType("plain");
+        propertyBuilder.setSubType("text");
+        propertyBuilder.setTextualLineCount(18L);
+        propertyBuilder.setContentDescription("An e-mail");
+    }
+
+    @Test
+    public void convertToJsonShouldThrowWhenNoUser() {
+        MessageToElasticSearchJson messageToElasticSearchJson = new MessageToElasticSearchJson(
+                new DefaultTextExtractor(),
+                ZoneId.of("Europe/Paris"), IndexAttachments.YES);
+        MailboxMessage spamMail = new SimpleMailboxMessage(MESSAGE_ID,
+                date,
+                SIZE,
+                BODY_START_OCTET,
+                new SharedByteArrayInputStream("message".getBytes(StandardCharsets.UTF_8)),
+                new Flags(),
+                propertyBuilder,
+                MAILBOX_ID);
+        ImmutableList<User> users = ImmutableList.of();
+
+        assertThatThrownBy(() -> messageToElasticSearchJson.convertToJson(spamMail, users))
+            .isInstanceOf(IllegalStateException.class);
+    }
+
+    @Test
+    public void spamEmailShouldBeWellConvertedToJson() throws IOException {
+        MessageToElasticSearchJson messageToElasticSearchJson = new MessageToElasticSearchJson(
+            new DefaultTextExtractor(),
+            ZoneId.of("Europe/Paris"), IndexAttachments.YES);
+        MailboxMessage spamMail = new SimpleMailboxMessage(MESSAGE_ID,
+                date,
+                SIZE,
+                BODY_START_OCTET,
+                ClassLoaderUtils.getSystemResourceAsSharedStream("eml/spamMail.eml"),
+                new Flags(),
+                propertyBuilder,
+                MAILBOX_ID);
+        spamMail.setUid(UID);
+        spamMail.setModSeq(MOD_SEQ);
+        assertThatJson(messageToElasticSearchJson.convertToJson(spamMail, ImmutableList.of(USER)))
+            .when(IGNORING_ARRAY_ORDER)
+            .isEqualTo(ClassLoaderUtils.getSystemResourceAsString("eml/spamMail.json"));
+    }
+
+    @Test
+    public void htmlEmailShouldBeWellConvertedToJson() throws IOException {
+        MessageToElasticSearchJson messageToElasticSearchJson = new MessageToElasticSearchJson(
+            new DefaultTextExtractor(),
+            ZoneId.of("Europe/Paris"), IndexAttachments.YES);
+        MailboxMessage htmlMail = new SimpleMailboxMessage(MESSAGE_ID,
+                date,
+                SIZE,
+                BODY_START_OCTET,
+                ClassLoaderUtils.getSystemResourceAsSharedStream("eml/htmlMail.eml"),
+                new FlagsBuilder().add(Flags.Flag.DELETED, Flags.Flag.SEEN).add("social", "pocket-money").build(),
+                propertyBuilder,
+                MAILBOX_ID);
+        htmlMail.setModSeq(MOD_SEQ);
+        htmlMail.setUid(UID);
+        assertThatJson(messageToElasticSearchJson.convertToJson(htmlMail, ImmutableList.of(USER)))
+            .when(IGNORING_ARRAY_ORDER)
+            .isEqualTo(ClassLoaderUtils.getSystemResourceAsString("eml/htmlMail.json"));
+    }
+
+    @Test
+    public void pgpSignedEmailShouldBeWellConvertedToJson() throws IOException {
+        MessageToElasticSearchJson messageToElasticSearchJson = new MessageToElasticSearchJson(
+            new DefaultTextExtractor(),
+            ZoneId.of("Europe/Paris"), IndexAttachments.YES);
+        MailboxMessage pgpSignedMail = new SimpleMailboxMessage(MESSAGE_ID,
+                date,
+                SIZE,
+                BODY_START_OCTET,
+                ClassLoaderUtils.getSystemResourceAsSharedStream("eml/pgpSignedMail.eml"),
+                new FlagsBuilder().add(Flags.Flag.DELETED, Flags.Flag.SEEN).add("debian", "security").build(),
+                propertyBuilder,
+                MAILBOX_ID);
+        pgpSignedMail.setModSeq(MOD_SEQ);
+        pgpSignedMail.setUid(UID);
+        assertThatJson(messageToElasticSearchJson.convertToJson(pgpSignedMail, ImmutableList.of(USER)))
+            .when(IGNORING_ARRAY_ORDER)
+            .isEqualTo(ClassLoaderUtils.getSystemResourceAsString("eml/pgpSignedMail.json"));
+    }
+
+    @Test
+    public void simpleEmailShouldBeWellConvertedToJson() throws IOException {
+        MessageToElasticSearchJson messageToElasticSearchJson = new MessageToElasticSearchJson(
+            new DefaultTextExtractor(),
+            ZoneId.of("Europe/Paris"), IndexAttachments.YES);
+        MailboxMessage mail = new SimpleMailboxMessage(MESSAGE_ID,
+                date,
+                SIZE,
+                BODY_START_OCTET,
+                ClassLoaderUtils.getSystemResourceAsSharedStream("eml/mail.eml"),
+                new FlagsBuilder().add(Flags.Flag.DELETED, Flags.Flag.SEEN).add("debian", "security").build(),
+                propertyBuilder,
+                MAILBOX_ID);
+        mail.setModSeq(MOD_SEQ);
+        mail.setUid(UID);
+        assertThatJson(messageToElasticSearchJson.convertToJson(mail,
+                ImmutableList.of(User.fromUsername("user1"), User.fromUsername("user2"))))
+            .when(IGNORING_ARRAY_ORDER).when(IGNORING_VALUES)
+            .isEqualTo(ClassLoaderUtils.getSystemResourceAsString("eml/mail.json"));
+    }
+
+    @Test
+    public void recursiveEmailShouldBeWellConvertedToJson() throws IOException {
+        MessageToElasticSearchJson messageToElasticSearchJson = new MessageToElasticSearchJson(
+            new DefaultTextExtractor(),
+            ZoneId.of("Europe/Paris"), IndexAttachments.YES);
+        MailboxMessage recursiveMail = new SimpleMailboxMessage(MESSAGE_ID, 
+                date,
+                SIZE,
+                BODY_START_OCTET,
+                ClassLoaderUtils.getSystemResourceAsSharedStream("eml/recursiveMail.eml"),
+                new FlagsBuilder().add(Flags.Flag.DELETED, Flags.Flag.SEEN).add("debian", "security").build(),
+                propertyBuilder,
+                MAILBOX_ID);
+        recursiveMail.setModSeq(MOD_SEQ);
+        recursiveMail.setUid(UID);
+        assertThatJson(messageToElasticSearchJson.convertToJson(recursiveMail, ImmutableList.of(USER)))
+            .when(IGNORING_ARRAY_ORDER).when(IGNORING_VALUES)
+            .isEqualTo(ClassLoaderUtils.getSystemResourceAsString("eml/recursiveMail.json"));
+    }
+
+    @Test
+    public void emailWithNoInternalDateShouldUseNowDate() throws IOException {
+        MessageToElasticSearchJson messageToElasticSearchJson = new MessageToElasticSearchJson(
+            new DefaultTextExtractor(),
+            ZoneId.of("Europe/Paris"), IndexAttachments.YES);
+        MailboxMessage mailWithNoInternalDate = new SimpleMailboxMessage(MESSAGE_ID,
+                null,
+                SIZE,
+                BODY_START_OCTET,
+                ClassLoaderUtils.getSystemResourceAsSharedStream("eml/recursiveMail.eml"),
+                new FlagsBuilder().add(Flags.Flag.DELETED, Flags.Flag.SEEN).add("debian", "security").build(),
+                propertyBuilder,
+                MAILBOX_ID);
+        mailWithNoInternalDate.setModSeq(MOD_SEQ);
+        mailWithNoInternalDate.setUid(UID);
+        assertThatJson(messageToElasticSearchJson.convertToJson(mailWithNoInternalDate, ImmutableList.of(USER)))
+            .when(IGNORING_ARRAY_ORDER)
+            .when(IGNORING_VALUES)
+            .isEqualTo(ClassLoaderUtils.getSystemResourceAsString("eml/recursiveMail.json"));
+    }
+
+    @Test
+    public void emailWithAttachmentsShouldConvertAttachmentsWhenIndexAttachmentsIsTrue() throws IOException {
+        // Given
+        MailboxMessage mailWithNoInternalDate = new SimpleMailboxMessage(MESSAGE_ID,
+                null,
+                SIZE,
+                BODY_START_OCTET,
+                ClassLoaderUtils.getSystemResourceAsSharedStream("eml/recursiveMail.eml"),
+                new FlagsBuilder().add(Flags.Flag.DELETED, Flags.Flag.SEEN).add("debian", "security").build(),
+                propertyBuilder,
+                MAILBOX_ID);
+        mailWithNoInternalDate.setModSeq(MOD_SEQ);
+        mailWithNoInternalDate.setUid(UID);
+
+        // When
+        MessageToElasticSearchJson messageToElasticSearchJson = new MessageToElasticSearchJson(
+            new DefaultTextExtractor(),
+            ZoneId.of("Europe/Paris"),
+            IndexAttachments.YES);
+        String convertToJson = messageToElasticSearchJson.convertToJson(mailWithNoInternalDate, ImmutableList.of(USER));
+
+        // Then
+        assertThatJson(convertToJson)
+            .when(IGNORING_ARRAY_ORDER)
+            .when(IGNORING_VALUES)
+            .isEqualTo(ClassLoaderUtils.getSystemResourceAsString("eml/recursiveMail.json"));
+    }
+
+    @Test
+    public void emailWithAttachmentsShouldNotConvertAttachmentsWhenIndexAttachmentsIsFalse() throws IOException {
+        // Given
+        MailboxMessage mailWithNoInternalDate = new SimpleMailboxMessage(MESSAGE_ID,
+                null,
+                SIZE,
+                BODY_START_OCTET,
+                ClassLoaderUtils.getSystemResourceAsSharedStream("eml/recursiveMail.eml"),
+                new FlagsBuilder().add(Flags.Flag.DELETED, Flags.Flag.SEEN).add("debian", "security").build(),
+                propertyBuilder,
+                MAILBOX_ID);
+        mailWithNoInternalDate.setModSeq(MOD_SEQ);
+        mailWithNoInternalDate.setUid(UID);
+
+        // When
+        MessageToElasticSearchJson messageToElasticSearchJson = new MessageToElasticSearchJson(
+            new DefaultTextExtractor(),
+            ZoneId.of("Europe/Paris"),
+            IndexAttachments.NO);
+        String convertToJson = messageToElasticSearchJson.convertToJson(mailWithNoInternalDate, ImmutableList.of(USER));
+
+        // Then
+        assertThatJson(convertToJson)
+            .when(IGNORING_ARRAY_ORDER)
+            .when(IGNORING_VALUES)
+            .isEqualTo(ClassLoaderUtils.getSystemResourceAsString("eml/recursiveMailWithoutAttachments.json"));
+    }
+
+    @Test
+    public void emailWithNoMailboxIdShouldThrow() {
+        MessageToElasticSearchJson messageToElasticSearchJson = new MessageToElasticSearchJson(
+            new DefaultTextExtractor(),
+            ZoneId.of("Europe/Paris"), IndexAttachments.YES);
+        MailboxMessage mailWithNoMailboxId = new SimpleMailboxMessage(MESSAGE_ID, date,
+            SIZE,
+            BODY_START_OCTET,
+            ClassLoaderUtils.getSystemResourceAsSharedStream("eml/recursiveMail.eml"),
+            new FlagsBuilder().add(Flags.Flag.DELETED, Flags.Flag.SEEN).add("debian", "security").build(),
+            propertyBuilder,
+            null);
+        mailWithNoMailboxId.setModSeq(MOD_SEQ);
+        mailWithNoMailboxId.setUid(UID);
+
+        assertThatThrownBy(() ->
+            messageToElasticSearchJson.convertToJson(mailWithNoMailboxId, ImmutableList.of(USER)))
+            .isInstanceOf(NullPointerException.class);
+    }
+
+    @Test
+    public void getUpdatedJsonMessagePartShouldBehaveWellOnEmptyFlags() throws Exception {
+        MessageToElasticSearchJson messageToElasticSearchJson = new MessageToElasticSearchJson(
+            new DefaultTextExtractor(),
+            ZoneId.of("Europe/Paris"),
+            IndexAttachments.YES);
+        assertThatJson(messageToElasticSearchJson.getUpdatedJsonMessagePart(new Flags(), MOD_SEQ))
+            .isEqualTo("{\"modSeq\":42,\"isAnswered\":false,\"isDeleted\":false,\"isDraft\":false,\"isFlagged\":false,\"isRecent\":false,\"userFlags\":[],\"isUnread\":true}");
+    }
+
+    @Test
+    public void getUpdatedJsonMessagePartShouldBehaveWellOnNonEmptyFlags() throws Exception {
+        MessageToElasticSearchJson messageToElasticSearchJson = new MessageToElasticSearchJson(
+            new DefaultTextExtractor(),
+            ZoneId.of("Europe/Paris"),
+            IndexAttachments.YES);
+        assertThatJson(messageToElasticSearchJson.getUpdatedJsonMessagePart(new FlagsBuilder().add(Flags.Flag.DELETED, Flags.Flag.FLAGGED).add("user").build(), MOD_SEQ))
+            .isEqualTo("{\"modSeq\":42,\"isAnswered\":false,\"isDeleted\":true,\"isDraft\":false,\"isFlagged\":true,\"isRecent\":false,\"userFlags\":[\"user\"],\"isUnread\":true}");
+    }
+
+    @Test(expected = NullPointerException.class)
+    public void getUpdatedJsonMessagePartShouldThrowIfFlagsIsNull() throws Exception {
+        MessageToElasticSearchJson messageToElasticSearchJson = new MessageToElasticSearchJson(
+            new DefaultTextExtractor(),
+            ZoneId.of("Europe/Paris"),
+            IndexAttachments.YES);
+        messageToElasticSearchJson.getUpdatedJsonMessagePart(null, MOD_SEQ);
+    }
+
+    @Test
+    public void spamEmailShouldBeWellConvertedToJsonWithApacheTika() throws IOException {
+        MessageToElasticSearchJson messageToElasticSearchJson = new MessageToElasticSearchJson(
+            textExtractor,
+            ZoneId.of("Europe/Paris"),
+            IndexAttachments.YES);
+        MailboxMessage spamMail = new SimpleMailboxMessage(MESSAGE_ID, date,
+            SIZE,
+            BODY_START_OCTET,
+            ClassLoaderUtils.getSystemResourceAsSharedStream("eml/nonTextual.eml"),
+            new Flags(),
+            propertyBuilder,
+            MAILBOX_ID);
+        spamMail.setUid(UID);
+        spamMail.setModSeq(MOD_SEQ);
+
+        assertThatJson(messageToElasticSearchJson.convertToJson(spamMail, ImmutableList.of(USER)))
+            .when(IGNORING_ARRAY_ORDER)
+            .isEqualTo(
+                ClassLoaderUtils.getSystemResourceAsString("eml/nonTextual.json", StandardCharsets.UTF_8));
+    }
+
+    @Test
+    public void convertToJsonWithoutAttachmentShouldConvertEmailBoby() throws IOException {
+        // Given
+        MailboxMessage message = new SimpleMailboxMessage(MESSAGE_ID,
+            null,
+            SIZE,
+            BODY_START_OCTET,
+            ClassLoaderUtils.getSystemResourceAsSharedStream("eml/emailWithNonIndexableAttachment.eml"),
+            new FlagsBuilder().add(Flags.Flag.DELETED, Flags.Flag.SEEN).add("debian", "security").build(),
+            propertyBuilder,
+            MAILBOX_ID);
+        message.setModSeq(MOD_SEQ);
+        message.setUid(UID);
+
+        // When
+        MessageToElasticSearchJson messageToElasticSearchJson = new MessageToElasticSearchJson(
+                new DefaultTextExtractor(),
+                ZoneId.of("Europe/Paris"),
+                IndexAttachments.NO);
+        String convertToJsonWithoutAttachment = messageToElasticSearchJson.convertToJsonWithoutAttachment(message, ImmutableList.of(USER));
+
+        // Then
+        assertThatJson(convertToJsonWithoutAttachment)
+            .when(IGNORING_ARRAY_ORDER)
+            .when(IGNORING_VALUES)
+            .isEqualTo(ClassLoaderUtils.getSystemResourceAsString("eml/emailWithNonIndexableAttachmentWithoutAttachment.json"));
+    }
+}
diff --git a/mailbox/elasticsearch-v6/src/test/java/org/apache/james/mailbox/elasticsearch/v6/json/MimePartTest.java b/mailbox/elasticsearch-v6/src/test/java/org/apache/james/mailbox/elasticsearch/v6/json/MimePartTest.java
new file mode 100644
index 0000000..89daa82
--- /dev/null
+++ b/mailbox/elasticsearch-v6/src/test/java/org/apache/james/mailbox/elasticsearch/v6/json/MimePartTest.java
@@ -0,0 +1,50 @@
+/****************************************************************
+ * 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.mailbox.elasticsearch.v6.json;
+
+import static org.assertj.core.api.Assertions.assertThat;
+
+import java.io.ByteArrayInputStream;
+import java.nio.charset.StandardCharsets;
+
+import org.junit.Test;
+
+public class MimePartTest {
+
+    @Test
+    public void buildShouldWorkWhenTextualContentFromParserIsEmpty() {
+        MimePart.builder()
+            .addBodyContent(new ByteArrayInputStream(new byte[] {}))
+            .addMediaType("text")
+            .addSubType("plain")
+            .build();
+    }
+
+    @Test
+    public void buildShouldWorkWhenTextualContentFromParserIsNonEmpty() {
+        String body = "text";
+        MimePart mimePart = MimePart.builder()
+            .addBodyContent(new ByteArrayInputStream(body.getBytes(StandardCharsets.UTF_8)))
+            .addMediaType("text")
+            .addSubType("plain")
+            .build();
+        
+        assertThat(mimePart.getTextualBody()).contains(body);
+    }
+}
diff --git a/mailbox/elasticsearch-v6/src/test/java/org/apache/james/mailbox/elasticsearch/v6/json/SubjectsTest.java b/mailbox/elasticsearch-v6/src/test/java/org/apache/james/mailbox/elasticsearch/v6/json/SubjectsTest.java
new file mode 100644
index 0000000..38f6581
--- /dev/null
+++ b/mailbox/elasticsearch-v6/src/test/java/org/apache/james/mailbox/elasticsearch/v6/json/SubjectsTest.java
@@ -0,0 +1,66 @@
+/****************************************************************
+ * Licensed to the Apache Software Foundation (ASF) under one   *
+ * or more contributor license agreements.  See the NOTICE file *
+ * distributed with this work for additional information        *
+ * regarding copyright ownership.  The ASF licenses this file   *
+ * to you under the Apache License, Version 2.0 (the            *
+ * "License"); you may not use this file except in compliance   *
+ * with the License.  You may obtain a copy of the License at   *
+ *                                                              *
+ *   http://www.apache.org/licenses/LICENSE-2.0                 *
+ *                                                              *
+ * Unless required by applicable law or agreed to in writing,   *
+ * software distributed under the License is distributed on an  *
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY       *
+ * KIND, either express or implied.  See the License for the    *
+ * specific language governing permissions and limitations      *
+ * under the License.                                           *
+ ****************************************************************/
+
+package org.apache.james.mailbox.elasticsearch.v6.json;
+
+import static org.assertj.core.api.Assertions.assertThat;
+import static org.assertj.core.api.Assertions.assertThatThrownBy;
+
+import org.junit.Test;
+
+import com.google.common.base.Joiner;
+import com.google.common.collect.ImmutableSet;
+
+public class SubjectsTest {
+
+    @Test
+    public void fromShouldThrowWhenSetIsNull() {
+        assertThatThrownBy(() -> Subjects.from(null))
+            .isInstanceOf(NullPointerException.class)
+            .hasMessage("'subjects' is mandatory");
+    }
+
+    @Test
+    public void serializeShouldReturnEmptyWhenEmptySet() {
+        Subjects subjects = Subjects.from(ImmutableSet.of());
+
+        assertThat(subjects.serialize()).isEmpty();
+    }
+
+    @Test
+    public void serializeShouldNotJoinWhenOneElement() {
+        String expected = "subject";
+        Subjects subjects = Subjects.from(ImmutableSet.of(expected));
+
+        assertThat(subjects.serialize()).isEqualTo(expected);
+    }
+
+    @Test
+    public void serializeShouldJoinWhenMultipleElements() {
+        String subject = "subject";
+        String subject2 = "subject2";
+        String subject3 = "subject3";
+
+        String expected = Joiner.on(" ").join(subject, subject2, subject3);
+
+        Subjects subjects = Subjects.from(ImmutableSet.of(subject, subject2, subject3));
+
+        assertThat(subjects.serialize()).isEqualTo(expected);
+    }
+}
diff --git a/mailbox/elasticsearch-v6/src/test/java/org/apache/james/mailbox/elasticsearch/v6/query/DateResolutionFormaterTest.java b/mailbox/elasticsearch-v6/src/test/java/org/apache/james/mailbox/elasticsearch/v6/query/DateResolutionFormaterTest.java
new file mode 100644
index 0000000..db48dad
--- /dev/null
+++ b/mailbox/elasticsearch-v6/src/test/java/org/apache/james/mailbox/elasticsearch/v6/query/DateResolutionFormaterTest.java
@@ -0,0 +1,99 @@
+/****************************************************************
+ * 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.mailbox.elasticsearch.v6.query;
+
+import static java.time.format.DateTimeFormatter.ISO_OFFSET_DATE_TIME;
+import static org.assertj.core.api.Assertions.assertThat;
+
+import java.text.ParseException;
+import java.time.ZonedDateTime;
+
+import org.apache.james.mailbox.model.SearchQuery;
+import org.junit.Test;
+
+
+public class DateResolutionFormaterTest {
+
+    private final String dateString = "2014-01-02T15:15:15Z";
+
+    @Test
+    public void calculateUpperDateShouldReturnDateUpToTheNextMinuteUsingMinuteUnit() throws ParseException {
+        assertThat(
+            ISO_OFFSET_DATE_TIME.format(
+                DateResolutionFormater.computeUpperDate(ZonedDateTime.parse(dateString, ISO_OFFSET_DATE_TIME), SearchQuery.DateResolution.Minute)
+            )
+        ).isEqualTo("2014-01-02T15:16:00Z");
+    }
+
+    @Test
+    public void calculateUpperDateShouldReturnDateUpToTheNextHourUsingHourUnit() throws ParseException {
+        assertThat(
+            ISO_OFFSET_DATE_TIME.format(
+                DateResolutionFormater.computeUpperDate(ZonedDateTime.parse(dateString, ISO_OFFSET_DATE_TIME), SearchQuery.DateResolution.Hour)
+            )
+        ).isEqualTo("2014-01-02T16:00:00Z");
+    }
+
+    @Test
+    public void calculateUpperDateShouldReturnDateUpToTheNextMonthUsingMonthUnit() throws ParseException {
+        assertThat(
+            ISO_OFFSET_DATE_TIME.format(
+                DateResolutionFormater.computeUpperDate(ZonedDateTime.parse(dateString, ISO_OFFSET_DATE_TIME), SearchQuery.DateResolution.Month)
+            )
+        ).isEqualTo("2014-02-01T00:00:00Z");
+    }
+
+    @Test
+    public void calculateUpperDateShouldReturnDateUpToTheNextYearUsingYearUnit() throws ParseException {
+        assertThat(
+            ISO_OFFSET_DATE_TIME.format(
+                DateResolutionFormater.computeUpperDate(ZonedDateTime.parse(dateString, ISO_OFFSET_DATE_TIME), SearchQuery.DateResolution.Year)
+            )
+        ).isEqualTo("2015-01-01T00:00:00Z");
+    }
+
+    @Test
+    public void calculateUpperDateShouldReturnDateUpToTheNextDayUsingDayUnit() throws ParseException {
+        assertThat(
+            ISO_OFFSET_DATE_TIME.format(
+                DateResolutionFormater.computeUpperDate(ZonedDateTime.parse(dateString, ISO_OFFSET_DATE_TIME), SearchQuery.DateResolution.Day)
+            )
+        ).isEqualTo("2014-01-03T00:00:00Z");
+    }
+
+    @Test
+    public void calculateLowerDateShouldReturnDateUpToThePreviousMinuteUsingMinuteUnit() throws ParseException {
+        assertThat(
+            ISO_OFFSET_DATE_TIME.format(
+                DateResolutionFormater.computeLowerDate(ZonedDateTime.parse(dateString, ISO_OFFSET_DATE_TIME), SearchQuery.DateResolution.Minute)
+            )
+        ).isEqualTo("2014-01-02T15:15:00Z");
+    }
+
+    @Test
+    public void calculateLowerDateShouldReturnDateUpToThePreviousDayUsingDayUnit() throws ParseException {
+        assertThat(
+            ISO_OFFSET_DATE_TIME.format(
+                DateResolutionFormater.computeLowerDate(ZonedDateTime.parse(dateString, ISO_OFFSET_DATE_TIME), SearchQuery.DateResolution.Day)
+            )
+        ).isEqualTo("2014-01-02T00:00:00Z");
+    }
+
+}
diff --git a/mailbox/elasticsearch-v6/src/test/java/org/apache/james/mailbox/elasticsearch/v6/query/SearchQueryTest.java b/mailbox/elasticsearch-v6/src/test/java/org/apache/james/mailbox/elasticsearch/v6/query/SearchQueryTest.java
new file mode 100644
index 0000000..bfa4245
--- /dev/null
+++ b/mailbox/elasticsearch-v6/src/test/java/org/apache/james/mailbox/elasticsearch/v6/query/SearchQueryTest.java
@@ -0,0 +1,77 @@
+/****************************************************************
+ * 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.mailbox.elasticsearch.v6.query;
+
+import java.util.Date;
+
+import org.apache.james.mailbox.model.SearchQuery;
+import org.apache.james.mailbox.model.SearchQuery.DateResolution;
+import org.junit.Rule;
+import org.junit.Test;
+import org.junit.rules.ExpectedException;
+
+public class SearchQueryTest {
+
+    @Rule
+    public ExpectedException expectedException = ExpectedException.none();
+
+    @Test
+    public void sentDateOnShouldThrowOnNullDate() {
+        expectedException.expect(NullPointerException.class);
+
+        SearchQuery.sentDateOn(null, DateResolution.Day);
+    }
+
+    @Test
+    public void sentDateOnShouldThrowOnNullResolution() {
+        expectedException.expect(NullPointerException.class);
+
+        SearchQuery.sentDateOn(new Date(), null);
+    }
+
+    @Test
+    public void sentDateAfterShouldThrowOnNullDate() {
+        expectedException.expect(NullPointerException.class);
+
+        SearchQuery.sentDateAfter(null, DateResolution.Day);
+    }
+
+    @Test
+    public void sentDateAfterShouldThrowOnNullResolution() {
+        expectedException.expect(NullPointerException.class);
+
+        SearchQuery.sentDateAfter(new Date(), null);
+    }
+
+    @Test
+    public void sentDateBeforeShouldThrowOnNullDate() {
+        expectedException.expect(NullPointerException.class);
+
+        SearchQuery.sentDateBefore(null, DateResolution.Day);
+    }
+
+    @Test
+    public void sentDateBeforeShouldThrowOnNullResolution() {
+        expectedException.expect(NullPointerException.class);
+
+        SearchQuery.sentDateOn(new Date(), null);
+    }
+
+}
diff --git a/mailbox/elasticsearch-v6/src/test/resources/eml/bodyMakeTikaToFail.eml b/mailbox/elasticsearch-v6/src/test/resources/eml/bodyMakeTikaToFail.eml
new file mode 100644
index 0000000..e4e7ede
--- /dev/null
+++ b/mailbox/elasticsearch-v6/src/test/resources/eml/bodyMakeTikaToFail.eml
@@ -0,0 +1,1272 @@
+Date: Mon, 30 Jan 2017 11:51:35 +0100
+From: Raphael OUAZANA <ra...@linagora.com>
+To: OUAZANA Raphael <ra...@linagora.com>
+Subject: subject should be parsed
+Message-ID: <25...@linagora.com>
+X-Sender: raph.ouazana@linagora.com
+User-Agent: Roundcube Webmail/1.1.4
+
+Return-Path: <ip...@obm.lng.org>
+Received: from lenny.obm.lng.org (localhost [127.0.0.1])
+	 by lenny.obm.lng.org (Cyrus v2.3.14-Debian-2.3.14-2) with LMTPA;
+	 Wed, 21 Mar 2012 14:51:59 +0100
+X-Sieve: CMU Sieve 2.3
+Received: from [192.168.2.48] (unknown [192.168.2.48])
+	by lenny.obm.lng.org (Postfix) with ESMTP id E495D32929
+	for <us...@obm.lng.org>; Wed, 21 Mar 2012 14:51:58 +0100 (CET)
+Message-ID: <4F...@obm.lng.org>
+Date: Wed, 21 Mar 2012 14:52:14 +0100
+ From: iphone <ip...@obm.lng.org>
+User-Agent: Mozilla/5.0 (X11; U; Linux i686 (x86_64); en-US; 
+rv:1.9.2.28) Gecko/20120306 Lightning/1.0b2 Thunderbird/3.1.20
+MIME-Version: 1.0
+To: usera <us...@obm.lng.org>
+Subject: Fwd: Re: email with sign
+Content-Type: multipart/mixed;
+  boundary="------------080809000000030101030405"
+
+This is a multi-part message in MIME format.
+--------------080809000000030101030405
+Content-Type: text/plain; charset=ISO-8859-1; format=flowed
+Content-Transfer-Encoding: 7bit
+
+new email text part
+
+--------------080809000000030101030405
+Content-Type: message/rfc822;
+  name="Re: email with sign.eml"
+Content-Transfer-Encoding: 7bit
+Content-Disposition: attachment;
+  filename="Re: email with sign.eml"
+
+Return-Path: <us...@obm.lng.org>
+Received: from lenny.obm.lng.org (localhost [127.0.0.1])
+	 by lenny.obm.lng.org (Cyrus v2.3.14-Debian-2.3.14-2) with LMTPA;
+	 Wed, 21 Mar 2012 14:19:29 +0100
+X-Sieve: CMU Sieve 2.3
+Received: from [192.168.2.48] (unknown [192.168.2.48])
+	by lenny.obm.lng.org (Postfix) with ESMTP id 47EC832D51
+	for <ip...@obm.lng.org>; Wed, 21 Mar 2012 14:19:29 +0100 (CET)
+Message-ID: <4F...@obm.lng.org>
+Date: Wed, 21 Mar 2012 14:19:44 +0100
+ From: usera <us...@obm.lng.org>
+User-Agent: Mozilla/5.0 (X11; U; Linux i686 (x86_64); en-US; 
+rv:1.9.2.28) Gecko/20120306 Thunderbird/3.1.20
+MIME-Version: 1.0
+To: iphone <ip...@obm.lng.org>
+Subject: Re: email with sign
+References: <4F...@obm.lng.org>
+In-Reply-To: <4F...@obm.lng.org>
+Content-Type: multipart/alternative;
+  boundary="------------050702060806040107070701"
+
+This is a multi-part message in MIME format.
+--------------050702060806040107070701
+Content-Type: text/plain; charset=ISO-8859-1; format=flowed
+Content-Transfer-Encoding: 7bit
+
+On 03/21/2012 01:59 PM, iphone wrote:
+> email with sign text part
+> --
+new email text part
+
+--------------050702060806040107070701
+Content-Type: multipart/related;
+  boundary="------------090109030206070103090500"
+
+
+--------------090109030206070103090500
+Content-Type: text/html; charset=ISO-8859-1
+Content-Transfer-Encoding: 7bit
+
+<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN">
+<html>
+   <head>
+     <meta content="text/html; charset=ISO-8859-1"
+       http-equiv="Content-Type">
+   </head>
+   <body text="#000000" bgcolor="#ffffff">
+     On 03/21/2012 01:59 PM, iphone wrote:
+     <blockquote cite="mid:4F69D0C6.501@obm.lng.org" type="cite">
+       <meta http-equiv="content-type" content="text/html;
+         charset=ISO-8859-1">
+       email with sign text part<br>
+       <div class="moz-signature">-- <br>
+         <img src="cid:part1.05020706.03070506@obm.lng.org" 
+border="0"></div>
+     </blockquote>
+     new email text part<br>
+   </body>
+
+</html>
+
+--------------090109030206070103090500
+Content-Type: image/jpeg
+Content-Transfer-Encoding: base64
+Content-ID: <pa...@obm.lng.org>
+
+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
+RvvR7cp9+nyYupWotquN7t17lQ1W/iOqfiKi4Sl3iAJbUmI2CNhIVz3Yykxd66HItw0joyzq
+lWSbK0tavBjTt3sSJ8Z5BaZQtzgKWNjmWEKSoKO3KgdwJoC46n1W1brNapdnipvUm9SG49qa
+bfDbchS21OhRcwdqA22tZUAThPIE4FQrfSXEtUqRa9awFWW7tPstNxoXGuKJXGbeW0WS20Fq
+3CM+MFtJy2Rg5TmTvGjus6XsdsttyFunWBbLttltxG9jbjbSmubKNqNim1uIKE7QAo7duBiM
+hdH85zVNu1VfNQNT7zGuCJTy2IHAZUy3Elx22G0FxRQEmY45uUpZJJHIEbQPub0raPtUORIv
+dzTH6uuaXjFiyZKGWo0l1hTjiksjh5UypPjAArCkoU4AFK+k9KmkWHZEa43EMyY7zyXkxosl
+9tlpEuRGDriwyA2nfGcClKwhBB8dSSlaud9IXRzrONGv9o0il+ajVMGdEnyVR44ZaTImzZKA
+SuQlbezrriVKS27vHclBxi4o6KNto1zA8PZ7V22XA39T/wA148u4yN+N/j7fCO3Hi54Wcjdh
+IFsh6005L1IrT0ec6qeHHGk5iPJZccbBLjaHikNLWkA7kJUVDarIGDjLqDVmn7BPhQLtcBHk
+zXWmmGw0tZUp15DLYO0EJ3OOJSCrA7z3JURUtNdFMGxdIb+qY5sRS5NlzgrwCz4RLskrK0qm
+klZbBcXtCUpVghJUUjB+ekLRGor/AKvdl2i5QrexJYta1SZUMyktOW6c5KQ3ww80r9Ip1GVA
+nxWlDkVJUAL/AGy5Qrm285CfDoYfcjujaUlDiFFKkkEAjmP3ggjIINbdVvRNpm2+dqefNbDJ
+u95VLaZ3BWxtDDMdJ5EjxwxxMeTfzwcirJQClKUApSlAKUpQClKUApSlAKUpQClKUApSlAKU
+pQClKUApSlAKUpQClKUApSlAKUpQClKUBjkuLajuutsOPrQgqS02UhSyB9UbiBk93MgecioX
+w9dfUq/++hfmKnqUBA+Hrr6lX/30L8xTw9dfUq/++hfmKnqUBA+Hrr6lX/30L8xTw9dfUq/+
++hfmKnqUBA+Hrr6lX/30L8xTw9dfUq/++hfmKnqUBA+Hrr6lX/30L8xTw9dfUq/++hfmKnqU
+BA+Hrr6lX/30L8xTw9dfUq/++hfmKnqUBA+Hrr6lX/30L8xTw9dfUq/++hfmKnqUBA+Hrr6l
+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
+IVsZZfbzsWknIyCD5fMTUxSld2LBjwrbjior4KjglOUncnYpSlalRSlKAUpSgIzUNqVc2GSy
+/wBXkxnOKw4U7gFYIII8oIJH76iPBGqvtOz/AHNz5lWlSgkFSiAB5Sax9ZjekNf1xQFa8Eaq
++07P9zc+ZTwRqr7Ts/3Nz5lWXrMb0hr+uKdZjekNf1xUUTZWvBGqvtOz/c3PmV+Ks2qFbc3K
+znaoKH8jd7wQR/rPOBVm6zG9Ia/rinWY3pDX9cUoWVrwRqr7Ts/3Nz5lPA+qfLc7Rj2RHM/2
+lWXrMb0hr+uKdZj+kNf1xShZq2C2ptVuTFDqnVlanHFn+ktRyo/vJrWvlmdmXCJdIExMO4RU
+rQ2txritqQvG5Kk5SSOQPIg5AqYBBGQcivlxaG07nFpQnzqOBUkEJ1XWH23YvhDv5mnVdYfb
+di+EO/mal+txPSmPeCnW4npTHvBQER1XWH23YvhDv5mnVdYfbdi+EO/mal+txPSmPeCnW4np
+THvBQGpYbYq2syC9JMqVKeL8l4oCQte0JGEjuASlKQOfIDmTzqRr8SpK0hSVBQPcQciv2gFK
+UoBSlKAUpSgFKUoBSlKAVB631Ta9IWZNzuvHWl2Q3FjsR0b3ZDzhwhtCcjKifOQOR51OVTul
+rSErV9ltibdKYjXKz3eNd4RfBLS3WSSELxzCSFEZGccuRoWjV8m9atXQ34Fwm3m33HTDdvcC
+JCr0lthsAjkpLoWppafJlKzg8jitmTq3SkW0MXiTqaysW2QcMTHJ7SWXT5krKtp/capet9J6
+41lYogui9ORJtsvsW6wYbDrzjDqGSSWn3VIBVuyTlLYxgcjVfY6ILqxZDIUiG7qJV9nXdh+J
+eX4KbYZO0KbZWlhZWnCRnchOefnqC6jB9WdRt+qrTcNRtWWBIYll63eEW5DEyOtC2uJw+SA5
+xSM/09mzybt3Kp2uWaA0FrK2dI1t1bqm+wLu8zpQ2eU+2FJddkdcLwUE7QnYEEJ3ZBJGdvOu
+p1JSaSfApSlCopSlAKUpQGtdp8a12uVcprqWo0VlbzqyeSUpBJP8BX84umnpRvnSHrFy4TVP
+M2kKPg6NkhCW88lEfrEcya949O1luuouh7VNlsiVLuMq3uIYQk4K1d+0ftAI/fXhRWmpUmxM
+M3SzTrZMYSG1syo6m1ZSMEpyOdUndHVpau+5XrYtwPNvsuFLiFBSfYa9KW/6UZ07p+128aF6
+42xFQzxhdtmVISARjgnHd5zyrzMqDPtcwpfYWpnd4isHar2GrILXKmaXutzmYjw47KVt+JhK
+3VLASlP7t37hWMLi6PSyQhlScj1F0R/SSGvukK2aS7GeDuv8X+U+E+Ls2NLc+rwk5zsx3jvz
+XoCv5+/RH/8AeE0x/wBr/uj1f0CreLtHmarHHHNKPoKgtears2idLy9R36QWYUYDIQAVuKJw
+lCBkZUT5P38gCanaqHTJozt/0c3XSyZfVXpSEqZdKlBAcQoLTvA705SMg58+MgVYwjW5X0JC
+z6qgz9HL1W+w9AtyGFySp15l39ClO4uBTDjiCMA9ys8u6tDo26QrJr1iYu0sTorsMMLdYmNp
+Q5w3mw6y4NqlDatByOefOBWRFguF06Np2lr0hqE7MgPQVKZuL0/CXGyjeXXkpWo+MT42f2mq
+L0W9HWutDqcmMS9NvTZ79qh3BC1PqbTbocbgKU0QlJ46sBQChtHcSagulFp+pMyemawRH7nG
+mWDU0SVAiomJjyYSGXJLK5IjJWhK1gpy4RgObCRzAxV7sNwl3KGt+ZY7hZnEuFAYmrYUtQwD
+vBZccTjmRzIPI8sYJ5Lc+jDWF8vmp7zfFaSW7dLYzDTEZEpMWc8zJDrUiQlKkrSpKEobwla+
+7vI8Wrn0M6QuOjNNTrfcn4hVLukiczFhqUqPBacIKY7RUEkoTg/0U8yeVOSZqG3jqTOq0Jkz
+bNb3smNKlqS+gHAWlLK1gH2ZSMjyjlVNuuquja26+a0bI05GMxT8eK5IRbmTHZfkIWtlpZ+t
+uWltRGEkd2SM1cNUq2XjT6s4xMd/u7tcs1J0YXK6dLnalq4Q0WuRdbZdpKVKVx0vQWnW0ISn
+G0pVxASSoEYPI0ZXGou9x1rs3pr1etP3Nv8Awp2b016vWn7m3/hWTrR/WP8AGnWj+sf40KGP
+s3pr1etP3Nv/AArXnWDTrDCVo07ZyS62jnCb7lLSk+TzGtzrR/WP8a15z5W20nPfIZ/tU0BG
+6nj6SsMFLzml4MyS8rhxYUWA0p+S5gnYgHAzgEkkhIAJJABNZ7Jb9HXq2InwLHbC0slKgqCh
+txpYOFIUkgFC0kEEHmCK+NTXG9xIaJllhNXFxlW56GVhDj6MHk2tRCUrzgjdyOMEpzuGxYpV
+1VbkOXgRm5jhK1tRyShoE8kbj9YgYBVgZOSAO6hBn0QtZtDzKlrWmNNkR2ypWSEIdUlIJPfy
+Aqq9Ll6stmnx5eqdzlhh26RMkMBO7iLStpCBt7lZLmADyyR5s1ZtCHda5qvPc5Z/8ZVUnpz0
+i5rt/sozKRFenWWTwnVglKVokRnE7sc8EoAOPJTsWjW7noSuhYPR3rC0yJ9u0jCjqizHYMuN
+KhNpdjvtHC21BJUnI5dxI5jnU/2G0b6r2j7qj/Co3oi0lP0naLybs/FcuN6vcq7yUxVKU00t
+5Q8RClBJUAEjmQOeeVXSglV8Fd7DaN9V7R91R/hTsNo31XtH3VH+FWKlSVK/o1pEN692tjKY
+kG4BuOgqJ4aFR2XCkZ8m5xWB5By8lWCoLTP+m9Uf70b/ALnGqdoBSlKAUpSgFKUoBSlKAUpS
+gFKUoBSlKAUpSgFKUoBSlKAUpSgFROq9OWjU9pctl5iIkMqHinuU2r9ZJ7walqjtS3q36dsU
+y9XV7gw4jZcdVjJx5gPKSeQFGWipOSUepxV/oLlNTxHaksSoCl81uEJXt/2hjv8AaKv0Xol0
+Uuzt2+8WePdUpUF/pwdoOMDABAArnuofpCzGrZ4ZselUu2pLvCL0yTw1rP8AsoAPL21FQPpQ
+uy1qbGj2kuJGSkzzzHn/AJusHmxrue2vBvEslLb80vqdk050X9H+nbyxebJpW3wbhH3cJ9pJ
+CkbklKsc/KlRH76uFcZ6Num5/V+tYGnV6cbhpl8TLwllZTsbUvu2DOduO/y12ar48kciuJ5+
+v0Op0WRY9Qqk1fVPj8r9BSlK0OIUpSgFKUoDQvdrZusZDTjjjS21hxp1s4U2oeUf/fOojsxc
+PWm4fd2PwVOXOfFtsUyJbmxGQkYGSonuAA5knzVG9pof2fe/hT/4Kgk1ezFw9abh93Y/BTsx
+cPWm4fd2PwVtdpof2fe/hT/4Kdpof2fe/hT/AOCnA5NXsxcPWm4fd2PwV+HS884zqiecEEfy
+djkQcg/Urb7TQ/s+9/Cn/wAFO00P7Pvfwp/8FOByavZi4etNw+7sfgp2Yn+XVFwI83AY/BW1
+2mh/Z97+FP8A4KHU8IDKoF6SB3k2t8Af92nA5JG0W9i2QURI+4pTklSjkqJ7yT5zWvebKxcn
+o8oSJMOZGzwZMdSQtAPeMKBSQfMQR3eat2DKjzYjcqK6l1lwbkqSeRFal9vdvsrTa5ziwXVb
+W22m1OOLOM4SlIJPLzVJBp+A7r65Xz3MP5FPAd19cr57mH8itTt1Z/Qr78Hkfgp26s/oV9+D
+yPwVBJt+A7r65Xz3MP5FPAd09cr57mH8itTt1Z/Qr78Hkfgp26s/oV9+DyPwUBN2a2MWuMtl
+lbrq3HC6888rct1Z71KPn5AcsAAAAACt2tS0XKHdoKJsF3iMqJGSMEEHBBB5gg+Q1t1JApSl
+AKUpQClKUByrVHSNfbLqPVh6tbXbNpt63peb4SxIdRJSNygvftBSo8hs5g94xznT0o6V7X9m
+eM8ZXXvB/Ey3s6x+pt38TGfF3bNueWay3To4sty1HcrxLm3JaLm9Gemwd7YjvKjpAaB8TfgY
+yRuwT3+TG3C0VAg35+6Qbnd4rciaZ78FmSER3XyMKWoBO8g4BKd20kd1YJZUz2pZPD5QScXa
+j2452x+e7c/TlGvaOkK1XW3zblDt106hGaU63MebbajyUpcLaih1awgEKSeSyk454xVc1B0r
+Lf0/a5+kLaqU7NvqbO4ZAbcSy737RteSlalAgpKV7CM5UOWZgdFlg7PXDT/hG9m1TG+GiJ1s
+cKKONxv0SduM7/6StxxyzjlX2x0ZWRrYBcLqpCL61ftqnGyDLQCCSdmdqsgqGfINu3nmGsrV
+Ewl4bCTlTdPhO+ld/j/HdMrtp6YEsybudS28wm27s9brfHQWULUWRl3iOLf4e5O5GfqpyoBK
+l5O3cmdMFhjuC5IVKkWk2RFy4bUIcXxpYj/XLoGQo4KNnkJCz9WpgdGllblOTYs+6xZ6rrJu
+rUtpxviMuyEhLqU5QU7CEjkoE+2sF/6KrDe0OCfc744ty1Ita3VSkuOKbRITICypaVErK0gZ
+PLHIAcqisyRp5nhUppuLS4uvnS/Dvd3fwNtXSLaEJvKXoU6O/Z3Wm5TElyOwQHUlTagpx1KM
+EDuKgr2VGPdLNqK9NPxLVOftl8Zkv9cUttAjoYCi7lBVklG3Khy5fVKz4tSN66NrHdb3PvD8
+u5Ny5s2HOKmnUANOxUKQ2UAoPIhRyDn2YrWY6KdOtQLTBTLuhjWlcrqranGyOFJGHmVeJkoU
+CoZ+sNxwruxZ+b7/AB/gyg/DKTld/n/x+k6r4XZKaR1zatSXAQI8SfCkrhIuDCJbaU8eMs4S
+6napXLOORweY5Vaaq2kdD2rTdwE+PKnzZKISLewuW4lRYjIOUtJ2pTyzjmcnl31aa0hur7x5
+2r8jzP8Awf4ilKVc5hSlKAUpSgFcg+l3OcidDUplskKlzI7OR5t+/wD/AOK6/XmD6WOpbjNu
+7uj5DHV4bKWpURZH+cL8YLOfYD3ftrPLLbFnqeDaaWo1kFHs7/RnCnr1drvaotrluMJYiJIb
+LbISTk/0scifbirDpSyxWrfOdDYckKiKO5XMjA3cvN3VXoDAYQd4AUeVWK339nT8V24uLa/R
+NKKUuAKQpWOQKTyIz5K4Yq3yfp+bF5WByS5XP1Lb9HP/AJ5bD/2j+7u17Frm3QVBsl60FpzW
+jmjrVZbzKi8RfV4obKFHcgqT5QlQyQM9ysZNdJrq0+F4o7Wfm/j/AIpDxLUrLCLSSrn8W/qK
+q3SrqpejNETb8zGRJfaKENNrWEpK1KCQTzBIGc4HPl5Bki01HamssDUVhmWS5tqXElt7HAlW
+FDnkEHyEEAj9lbTTcXXU8vTSxxzRllVxtWvh3IqFf5THR5I1PcHIsxTMJ2biKhKEKShBVtBS
+66knkeYWRUR0R61uWq1XKLdo0RqTDYhSQqMlSUFuUwHUpwok7k8wTnn5hVrj2hPgN60XGdKu
+rLzamnFyg2FqQobSk8NKBjGfJn21XbF0cWqyMtIt13vjLiJkaQ48iUlK30R0cNuO5tSApkJ5
+FOMnHM1Rqdquh2QyaV4ssZr7zf3Wlwufy7WundFZv3SFq2xz7/b7hGsYfgQ2JLa2m3ilBdkp
+aSnCilTw2KBK0BICvF76vmhrwb3aHZZu0K5lEhbKlxoLkThqTgFtbbi1KCwc5zjkRy8pi2Oj
+u2tTJ85V71E7NlxDDRLXPPHjM8Uu7W3AAr6x71FRwMd3KpnSOm4OmYEiLCdkvrlS3Jkl+QoF
+x55wjctW0Ac8DkAByqIRmpc9C+ry6SWGsSqXHbrwr+K5+Pfv1Meo8eHNOg4x1x0kH2R3SP8A
+jVMvvSRPgdJPgBuHEVbWbjAtz6lBXGU5LbcWlaTnASnYAQQc57xVu1gsM3CxSFna23MWFKPc
+NzLiRn9qlAfvqvT9H2Sbq1vUrypPWUusvrZSsBpx1pKktOKGM7khZAwQPODU5FJ1tOfQz08J
+S89Wqdfja+ll+4g/WH8acQfrD+NRHWPbTrHtrSziol+IP1h/GtW5vKTGQULKSX2RlJxyLiQR
+/CtLrHtrFKdK0tJHP9O0T7AHEkmlijNqeVe0QkMaejxlzn1bEyJRyxFGCS4tIUFLHLASnBJI
+yUjKhnsUyfJtra7rCTCmpJQ62h0OIJBxuQocyhXeMgHB5gHlUFqWLNuMJBtl2dtlwYVxI74S
+XG92CMON5AcQQeYJB8oKSARnsjCrZbURnZ8ma6CVuyJC8qcWTlR8yRk8kpAAHIAAUsijc0R/
+o6cB3C5ywB5hxlVUel/Ua9J3Zm/tx0SXIlokqbaWTtK1Px0JJx5AV/wzVr0Cd9mkOjmh2fJc
+QodykqdUQR7CCDUJr+zW6/ast9pvCT1CdbJUZRCtp3lbS0hJ/W8QqH/VqJW4uupvp5Y45ovK
+rjav8L5JPo21HM1FbroLi1HRNtd1kW19UdJS24pojx0hRJAIUORJq01D6S07B01bnYcJyQ8X
+5LkqQ++oFx55w5UtWABk8u4AcqmKQTUVY1MscssniVR7ClKVYwILTHK9anSOQF0RgftiRyf+
+JJqdqA0mtD1y1JJZUFsu3QcNaTlKtsZhCsHy4UhQ/aDU/QClKwolxVznYKJLKpbLSHnWA4C4
+hCyoIWU94SotrAJ5EoVjuNAZqUpQClKUApSsM+XFgQZE6dJZixIzSnn33nAhtpCRlS1KPJKQ
+ASSeQAoDNSlKAUpSgFKUoBSlKAUpSgFKUoBSlKAVBav0jp3VsMRb/a2JqE/UKhhSD5wRzFTt
+KVZaE5QkpRdNHGbp9HHQ0t/iR5d4gpz/ADbMkFP/AHga3LH9Hvo5t0pmVJgybq6yoKR157iJ
+BHl28h/wrrVKqoRTtI68niWryw8ueRtfifLLTbLSGWUJbbQAlKUjASB3ACvqlKscQpSlAKUp
+QClKUBilxo8uOqPKZQ80sYUhYyDUP2O0t9gwPcip2lAQXY7S32BA9yKdjtLfYED3IqdpQEF2
+O0t9gQPcinY7S32BA9yKnaUBBdjtLfYED3IoNH6XBBFhgAjuPCFTtKA+GWm2WktNIShCRhKQ
+OQrFcIMK4RlRp8SPLYV3tvNhaT+48q2KUBBdjdIeq1j+4Nfhp2N0h6rWP7g1+Gp2lAQXY3SH
+qtY/uDX4adjdIeq1j+4NfhqdpQGOMwxFYRHjMtssoGENtpCUpHmAHdWSlKAVzm5XpjTXTDe5
+1ztuoHIk7T9rZjvwLFMnNqW1IuBcQVR2lhKgHWzhWDhQroUl9mNHdkyXm2WGkFbjjiglKEgZ
+KiTyAA55qF7a6N9bbB8RZ/FQHLWHtYx+mqJcC1f2LUb2/EuEREe5SGOrLaeTHe4jjyo5Spzg
+LIYZHCBO9aQlW7F0h3K5xOkKRx7hqyNKOqbFHtYiOvotyoDjsQPoc2nglalmQFBX6Qp248Td
+XV+2ujfW2wfEWfxVEPTuih7UKNRvTNFOXpsAIuKnIpkpAGMB36w5cu+gOMI/yjKvsRA7YxIl
+2kRo86PGZuqhAfFzhKcT1iQ85lAjdbBebS0yRkZVkATUq168Yct8aPO1spqZcZUWWsyJK1NR
+mNRQmYygo/U3QVSFFfe4jetRUE5HZO2ujfW2wfEWfxU7a6N9bbB8RZ/FQHGbpA6SYNsfTZ5u
+q1OyGruw8qSZEnhR415jNRlISVJVxVQVSFJKVJce+sFEgKE5Ht+oZP0ctfW5+TfL3Jk265tW
+1Eu1yo0hxCou1DaGpDz0lYK920uK3kqwBgJz0rtro31tsHxFn8VO2ujfW2wfEWfxUBVdRax6
+/K09dbLB1eIFsvIXeG+z9wjrXHchS20YaW0lb6Q8pkkISvaQlRAwDVCbia8uVn1xenXNcRZk
+C1S59giceS1vlC5XdbKOGk4dIaTDTwvGSUKbGCNmOz9tdG+ttg+Is/ip210b622D4iz+KgOI
+aluWrEanTGtFw1WjVkm9X1ppp114Wx1pEGeqAlsKPAVjbGJCO5YPE5hNdH6H+ueFb0Y/avwB
+1eH1XtH1nrPW/wBN1nb1n9Jsx1fu8Tdv2cqkYU7oog32RfoUzRUa7ych+ey5FRIdz37nB4ys
++01L9tdG+ttg+Is/ioDk6H77dteMyX7pqmNHVcL3GupYdkNwokVsSWY694VwkKCW2F7SAsqd
+bWhQAcC+s9HlwuF20Bp263dvh3GbaosiWjbt2uraSpYx5PGJ5VqOak6PXWZjLl+0utudnraF
+TGCmRlAQd4z43ipCeeeQA7hWyNa6NAwNW2D4iz+KgJ+lQPbXRvrbYPiLP4qdtdG+ttg+Is/i
+oCepUD210b622D4iz+KnbXRvrbYPiLP4qAnqVA9tdG+ttg+Is/ip210b622D4iz+KgJ6lQPb
+XRvrbYPiLP4qdtdG+ttg+Is/ioCepUD210b622D4iz+KnbXRvrbYPiLP4qAnqVA9tdG+ttg+
+Is/ip210b622D4iz+KgJ6lQPbXRvrbYPiLP4qdtdG+ttg+Is/ioCepUD210b622D4iz+KnbX
+RvrbYPiLP4qAnqVA9tdG+ttg+Is/ip210b622D4iz+KgJ6lQPbXRvrbYPiLP4qdtdG+ttg+I
+s/ioCepUD210b622D4iz+KnbXRvrbYPiLP4qAnqVA9tdG+ttg+Is/ip210b622D4iz+KgJ6l
+QPbXRvrbYPiLP4qdtdG+ttg+Is/ioCepUD210b622D4iz+KnbXRvrbYPiLP4qAnqVA9tdG+t
+tg+Is/ip210b622D4iz+KgJ6lQPbXRvrbYPiLP4qdtdG+ttg+Is/ioCepUD210b622D4iz+K
+nbXRvrbYPiLP4qAnqUpQClKUApSlAKUpQClKUApSlAKUpQClKUApSlAKUpQClKUApSlAKZFf
+iu6uF/SC6bWtISezOnnGnL04n9M8fGTFSfZ5VeypSvoVnNQW5nci60HA2XEBZ7klQya+68Tp
+hP3N2Drm3Xi63C6QH235gclKLmAoElIzgJIyMYr2Rpy8Qb9ZIt3tzwdjSWwtB8o84PmI7qlx
+oyw6iOW6JClKVU3FKUoBSlKAUpSgFKitQTpUXqcWClsyprxaaU59VGElZUcd+EpPLy91a/VN
+Ufb9u+Fq+dQE7SoLqmqPt+3fC1fOp1TVH2/bvhavnUBO0qC6pqj7ft3wtXzq+HmdSMoC3NQ2
+5KSpKQfBau9RAH+t85FAWClQRianAydQW0Af9Fq+dQxNUAZF9tqj5jbFDP7+LQE7So3Tlwcu
+Vt4z7aW32nXGHkpOUhaFFKsHzZFaGpbnc0XiDY7OY7UyU04+XpCCtDbaCkE7QRk5UnlkeXzc
+wLDSqv1HXnrFZPha/m06jrz1isnwtfzaAtFKq/UdeesVk+Fr+bTqOvPWKyfC1/NoC0UqI0xP
+mS2Zka4paE2BJ6u+prOxZ2IcSpOeYylxPLyHI599S9AKUpQCq10rf812rP8Acsz+wXVlpUp0
+ys47otHCrQLvovog05dbULHARd/BTc64QLOll2JGWjLj761LWl5Q3Dx1JABUo458li1nrS8a
+l0tZfDzrEK5XS8RU3BuIzvnRY7aFMvp3IKQTlYykBJ8oNd1pVt/qjl+ytUoyaSr9/wAe5501
+jfLzD6cHbVKvr0uONUWREODOYYdQll1DinFtJU3lBQohAcRhXjeMVKwRYtLay1OrUcrT9z1B
+FuF2djS1x34MiK9bI6kJUUF9KGw8ykeKPHWckfw7TSpc010EdLKMm1N9b/11PNup9d3l7o11
+RBuNxTeLnDhxX1vhMC4WwkymkEJ2MgBXMkIc3EDn3gGrSdcat/yi+Deufpu1Hg3wH1ZH+jdm
+eubtvE9ud23yYrtNKb16ELS5E73vt8r+PxOT3q8WiyfSXTKvN0g22OvRobS7LkIZQVmaSEgq
+IGcAnHsNV/pG6S79aVdIQtt+abEZi1SdOKQy04lTTuzjuNkpIcQc/WO4DIxjlXeKVCku6Lz0
+82moyq23+qr1/M4WzrjWCLsJS73xYo6Rl6c6oqK0EmKru8YJ3bk+Q5/bmoyx9JWt5Fw08PCn
+XLjNTelTrL1RtPBdjtLVHYyE7xkpSe/cc8zg16HqpWvQdviakh36Td71dJEAPiAifKDqYvG+
+vtO0LVkcvHUrA5CpUo+hlLT5U1tm/bXxKn0N6v1DftRphzLr4ZgrsTE2W91dtvqM5S8Li5Qk
+dwycKyoY766zSlUk7Z14oOEabsUpSoNBSlKAUpSgIbXV6Rp3Rl4vzn1YEN2Rjz7Ukiv5xXrw
+ldpj1+muKekzlmQtzOclRzj/ANK/pVfLZBvVnmWi5MJkQpjKmH2ldy0KGCP4VwnU/wBGbT8e
+xqb0VNlQ5beVJZmvqeZdH6vPmn2Efvq8Gl1Mc0HNcHmro81fJsF0bKllIztIPcoeY1aNS3iy
+OamjIshK2Lh/OoQMoZexk7T5R56ibvoKba727B1BbXoL7J/m3OSV+ZSVdyk/srpOiOgrUD1o
+buUSKhDpJUx1p3ZgKGCQMebynz1twuTyJYG20k/wNj6P/wDzu2T/ALR/d3K9aVwbop6KtV6b
+19bb1ckwREj8XicN/crxmlpGBjzqFd5rGbtnd4djljxNSVc/wK5/9Idm8PdEN7TZFPiQEIU4
+GVYWpoLHEHIEkbc5AI5Z5+Q9ApVU6dnZkh5kHH1KDaG2EdDE5vSTluclC2SAyq1ONLQZPCOM
+KabbSV529yEnPkqg/R7vtvsTU4zZS49quLtngQP0a1IcuTkMdYQNoOFFweMTgZ7zXfKVbdw0
+YvTvdGSf+JwLTg0Y30hatkwoCbnppjTqpMtp1pxTYdbkKW4iSh/Klv7kFSVKxhAAAIANdC6C
+LW1b+jeDNTFjRnbwpV0eajthtpJewpKUpHJICNicf7NXulHK0MWmWOW78e3qQOpVbb3p1R8k
+x3+7O1xTWDlzP0gm1o43W/DFpMDGc9Q4L/W9v+xuxu8mcZrturIcx4QZsJrjuwny6WgQCtKk
+KQQM+XCif3VFeEbp6s3j+DPzKrGW1svnw+akrqnZZesp81Osp81VrwjdPVm8fwZ+ZTwjdPVm
+8fwZ+ZVbN6LL1lPmrVub4XHbSPLIZ/tU1CeEbp6s3j+DPzK+HJ10Xszpm8Da4hf1Wee1QVj+
+c9lBRl114BnRIdv1HJcbtsqRwnGFHbHlEpO1p5WOSCf6JICzhJ3Z2nZ0VKt3Z9pNquEqfAQt
+aI70hRUSgKIASsgFaB3JWd24AHcrvMZcXJFygvwLho65S4j6C28w+0wttxJ7wpJcwR7DWZud
+ckIS23pe7IQkBKQEshKR5Byc5CliiU0Md1unHz3SYf8AxlVzv6SIuRt8rwTxuteApP8ANZ3c
+PrEbid3+xvz7M10zSMGRAtBRLSlLzz7shaAc7S4sqxn2ZrU1BCntalt1/hRFThGjvR3Y7a0p
+cKXCk7k7iEkgoHIkcialOnZTJDfFx9UVr6PwV2ZvfAz4JOoZvgfH831PeNnD/wBjO7GOVdHq
+C8O3P1NvvvYfz6eHbn6m333sP59S3bsjFj8uCj6E7SoLw7c/U2++9h/Pp4dufqdffew/n1Bc
+aZ/03qj/AHo3/c41TtQ+mIkxo3KdOZEd+4y+sFgLCi0kNNtJBI5E4bBOOWSRk99TFAKUpQCl
+KUApSsIlxDOVBEpgy0th1TAcHECCSAop78ZBGe7lQGalaMK82edJEWFdYEl8tqdDTMhC1lAW
+UFWAc7QoFJPdkY763qlprqBStdidCfmSYTEyO7Ki7esModCls7hlO9IOU5HMZ762KgCla/Xo
+XhLwb1yP17g8fq3FHF4edu/bnO3PLOMZ5VsUApSlAKUpQClKUApSlAKUpQCvzI89Fd1VHpP1
+hC0nYSpaFSbjMyxBhtn9I84R/wAEjvJ8n7SKtCDnJRj1IbUVbJxL9gu8kNpdts9+MvITuQ4p
+pXn8pSaksivI3Z63aCsou8qa9H1K6eKHo7pSWiTnB/W/Ya6v0H9M1q1bAfg32dFhXKGAVuOu
+BtDyO7cMnGfOK682injjvjyjDHqIye18M7GCKVGQb/YJ0pEaFfLbJkLzsaZlIWtWBk4AOTyB
+P7qk643Frqbpp9BSlY5L7MaO5IkvNsstpKluOKCUpA7ySeQFQSZKVq225W65xOt22fFmxskc
+aO8lxGR3jckkUtlyt10YU/bLhEnNJWUKXHeS4kKHeCUk8/ZU0xZtUqKVqXTiUS1qv9qSiGQJ
+SjMbwwSdoC+fi8yBzxz5Vs2m62u7xlSbTcodwYSsoU5FfS6kKABKSUkjOCDj2iji1zRFo3KV
+D6lky0OW+BDe6u5OkFovbcltKUKWSAfLhJA9pqPdjMtXJu2O65uCJzqd7cZT8YOrT5wjh5I5
+H+FR16ElopUF4Dl+tN7/AIx/lU8By/Wm9/xj/KoCdpUF4Dl+tN7/AIx/lVik2qSw2Fr1RfSC
+tCOXV+9Sgkf6rzmgLFSqxdIjdqguT7pra5wYjWOI/IejNtpyQBlSmwBkkD99bPgSZjKdU3rP
+kzwCP7KgJ6lRWlZsida1GWUqfYkOxnFpGAstrKSrHkzjNRWr7hL8NwrMxcxaWXYz0uRMATlD
+bZSCAVeKPrg5IIwD+4C1Uqn2+yTLhERLt/SJdpcZz6jzHVVoV5OSg3g1sdl7x68333cf5VOg
+LRSqv2XvHrzffdx/lU7MXj15vvu4/wAqgLRSoXSkiYtNxt8+R1p+3S+rmRt2l0Fpt1JIHIHD
+gBx5R5O6pqgFKUoBSlKAVRukxi7W+fB1Np+DImT0R37e40w2VKUl1BU0ogf0UuoRk+QKJq80
+q0JbXZDVo4/dNP6mtV1VY7BIu7UKBo9JjOMKcSw7Obkhfk8UuLAII7ylR8la+o3ddSdMx34U
+C+Il3iXPkj9JJS5bkhOIzWxtaNu7an6+UpJJKTnB7RStlqHxaKeX8TztPs+qL3pbXct603zw
+lLh2VSAY7zK5LrbQRIATgcQAleU4IzggfVNWa29su1UXgdpArw8jZ1jj9U8D8MY38TxeL593
+6Td3867HSrPVNqq90l9AsfxOd3Zx219OSb1Jt90ctytNCKJEW3vyU8XrJVsPCQrB2jP8POKr
+WvZesidc+CWdUKTcGbY9ZFRmZA4SU7eOEgAFpR57kYCjzyO+u00qkc21p17Tslwvucaaa1q3
+cxPDmpCoa9XHDSlPKa8GK71bDy4XmV9UeQioa2z9bsXvTUJ+Zfmr/KTeesszHHExnn0srLGx
+KvEUgeIRjxR+3Nd+qAs+jdN2i5puNvtoakI3hol5xaWd5yvhoUopbye/aBmtI6hU7RV432ZU
+OiftR4eT17w74O8Cs9d8K8TPhHf4/C4nPZtz9Xxe6unUpXPknvldGkVSoUpSqEilKUApSlAY
+pjimYjzyUFxTaCoIH9IgZxXkPTnSjDuNwvGtNXBSbvlTVujr/m2G0nmhPmV5899ewFc0nNeb
+elzodixblIvkOCV24uLecQ0chBUcqKk+bOefdXoeHyx73Gfc5tUpbbicB1jqa4awua3QpYZK
+uXOsNsbVpp1m9LVhDCxxkk43tk4Un+FdG0h0bXW/XQw9NW7dFzlc17lHZB8m7+kfYP34rpb3
+0bY8pDYn3WLMUghWXWlgZ/6oVjFetm1OLH91s4ceGcuUjU6Hm+D0qWxrOdqnwD5/0Lleka5h
+oroxnWHV0S+yLwxJDJcKkJaKSrchSe/P+1XT68bXZY5cicXfB36eDhFpiqX022W5X7o1ulut
+KVuSiEOJaRnc6ErCikYIySAeRznzZwRdKVyQk4SUl2N2rVFTSxJuXRhNt0JUozHLa9GbVIjv
+x1lwtkDk+S53kcypX7apPQ+i66cXKlTtPXpLFxVara00iGQppxuKEPPLScFLQUMFfd5s12Kl
+aLNUXGupVx5TOUafbkQ9e33UFr0jcYcGNYFNsx3oIYKH0OqUWGUt+K4HCN+4bjlWMjuq4dF1
+vlW/RMFVxS6LlNBmzi6kpcL7p3qCgeYIyE48m0CrPSonl3KqJUaIDU6tl608rzTHf7s7XLdS
+2e9yOl4y2YMlbL13tc1qSlsltthhp1LySvuSSVDxScnNde1DalXNhksv9XkxnOKw4U7gFYII
+I8oIJH76iPBGqvtOz/c3PmVGPI8bbXcmUVImut/sp1v9lQvgjVX2nZ/ubnzKeCNVfadn+5uf
+MrIsTXW/2VrXGRvZbRy5yGf7VNR3gjVX2nZ/ubnzK/FWbVCtublZztUFD+Ru94II/wBZ5wKA
+19czIbDMKfcNOv3uNGdUVIYbL62VKSUhYZ/1neU5GSndnGNxElplYiWCFHTbhbUttAJh8bic
+BPkRu7uQwMDIGMAkAVreCNVfadn+5ufMp4H1T5bnaMeyI5n+0oDb0Kd1tnK890ln/wAZVUbp
+4tlxvDirdamlvTHbLIKG0fWWEyIylJHnJSCMeWuk2C2ptVuTFDqnVlanHFn+ktRyo/vJrWvl
+mdmXCJdIExMO4RUrQ2txritqQvG5Kk5SSOQPIg5Aq8JOElJdiGrVED0PwJsO03t+XEfiNT77
+LmRGX2y2tDC1DblB5pzgnBA76u1QXVdYfbdi+EO/madV1h9t2L4Q7+ZpOe+TZCVKidpUF1XW
+H23YvhDv5mnVdYfbdi+EO/maqSNM/wCm9Uf70b/ucap2o6w2xVtZkF6SZUqU8X5LxQEha9oS
+MJHcAlKUgc+QHMnnUjQClKUApSlAKVrXSa1boDkx9K1Nt4yEAE8yB5f218G4JQttMlhcUubz
++lcbGAkZJ5KOR+zOMc8CsJ6nHCeyT54+bpfqy6xyatI3KVgbmRHN3DlML2J3K2uA7R5z5hXy
+bhADHHM2MGt23fxU7c+bOe+refjq9y/UjZL0NmlairnbUhJVcIgCxlJLyeYyRkc/OCP3Vm6z
+G6x1brDXG7+HvG7+HfRZ8Uukl+vqHCS6oy0rW6614V8HbV8XgcfOBt27tuP25r7clxW+LxJL
+KODji7nANme7Pmz7aLNjab3dOPzQ2S9DNSsCZkNTvCTLYLm4o2BwZ3DvGPOKImQ1vcFEthTh
+JGwOAqyO8Y9lT52P/kv1GyXoZ6VijyY0jd1eQ07tOFbFhWP24rLVoyjJXF2iGmuGKUpViBSl
+KAUpSgFa82WxDaK3ie7O1IyTWxXOdRX8J6U2dOy2nFxHIiXAUH6qhk8/OK5NbqHp8Lmuprhx
++ZKi2t3qK0ltCIEhtK8lIShH/kD/AOVScSSzKa4jCwpPcfIQfMR5K4P0ndLWiEONMQ7pITcY
+bp2toYI7u8Z7qz9EvS5O1QzPmNQGGW0LCEpcyVnHLcSCOZry4eLywxlPUr7q7pep0fZN9KHU
+7vSqjp7VE243hiG8xHShzdkpByMJJ8/sq3V6Wh1+HXY3kwvhOvf6mGfTzwS2z6ilK17jNYt8
+NcqSra2jzd5PmHtrqnOOOLnN0kZRi5OkbFK1mJjbkEzFJU20EleVKSrxQM5ykkf8ax2q5x7k
+lwspcQUbSpLgAOFDKTyJ5EVmtTicox3cy6fEt5cqbrobtKjmbu29Icjohy+MhHEDakBJWndt
+yMkY5+fFbFumJmtLcQ061scLZC9vMjvxgkEeT91Rj1eHI0oO7+hMsU4q2jYUoJBUogAeUmsf
+WY3pDX9cVDarQmTNs1veyY0qWpL6AcBaUsrWAfZlIyPKOVaj0DSDVxEFWnrZvKkoKhBa2pUo
+EpB5ZycGr5c+PEk5urdfmRGEp9EWTrMb0hr+uKdZjekNf1xUX2b016vWn7m3/hTs3pr1etP3
+Nv8AwrUoSnWY3pDX9cU6zG9Ia/riovs3pr1etP3Nv/CtedYNOsMJWjTtnJLraOcJvuUtKT5P
+MaAnOsxvSGv64p1mP6Q1/XFVXU8fSVhgpec0vBmSXlcOLCiwGlPyXME7EA4GcAkkkJABJIAJ
+rPZLfo69WxE+BY7YWlkpUFQUNuNLBwpCkkAoWkggg8wRQFoBBGQcivlxaG07nFpQnzqOBULo
+hazaHmVLWtMabIjtlSskIQ6pKQSe/kBUNrcwpGrLZBu6ONbEwZEl1g80uLSptKcjuV9c8jyz
+jzVWc4wi5SdJEqLk6Rb+txPSmPeCnW4npTHvBVat2ktETmVONaWtaSham1oXEQFJUO8HFbPY
+bRvqvaPuqP8ACox5I5IqUXaZMouLpk51uJ6Ux7wU63E9KY94Kg+w2jfVe0fdUf4U7DaN9V7R
+91R/hVypYUqStIUlQUD3EHIr9qv6NaRDevdrYymJBuAbjoKieGhUdlwpGfJucVgeQcvJVgoB
+SlKAUpSgI/UUJ242d+GwpCXHNuCskDkoHyfsrTu9j47jHUG40dtDUhKkhO0FTje0HAH8anKV
+xajw/BqG5ZFy9q/+rtfN8m2PUTxpKPa/mqK1I07IebDYeZbHg1EYlOebiVBWe7uOO/v9lZ/B
+dwbhSURurMvSVJC1B9xR2AYPjKzz8g5ch58VPUrBeD6aLcopp1V/quPTq+nqaPV5GqZCSLdN
+WITKI0MRI4yY/HUApQPLJ2cwOR7u818eBZPX9/Fa4PXuub8nid31MYxj25qepVn4Xgk7lb6f
+JVXC6fD9K5KrUzXQi5MOam/i5RkR3EdV4BQ46UHO/dnkk1o3Sy3CUblw1Rk9eSyVBS1eIpGM
+geLzHt/4VYqVObwzDmjKMm6bb/Npp/qmxDUzg012+jsr/gOTu3b2N3hbrmcnPD83d3+zu9tR
+MKJxZkC3tPNuBpMpC3WwrekKBAKwQMHJq7Urmy+CYZSi4uqq/jynXXjoaR1s0nfvhr6kNZbV
+IiS0SJCmRw4iYyUtEndg53HIHOpmlK9LTaaGmhsh0OfJklklukKUpXQZilKUApSlACcAnzVw
+qXcTdemqY8EYRGiFKT+xJrup5jFc71BoGUm8yb1p+S21JfbKFtupyCCPIa8zxXBlz4duNWdO
+lnCE7keKNeu51ZLc87yv/Or59Gm6hmTLt2NxecJ/YPPVhvn0dtb3K7OSNkdCFrKiovoPf7M1
+1joP6EYug313G5Sm505Y5JSnxEfxrknoHqdM8ElVnR9oWPJvTJvRX/KeJ/8Az/8AoVXS6wtx
+YzawtuOyhQ7lJQARWat/BvDH4dgeJy3W7+SX0MdbqVqcimlXFCtK+wPCVrehhexSwCk5OMg5
+GfZW7SvTzYoZscsc1aap/mc0JOElJdUaYjOvWpyHICW1LbU2Sl1TnIjGcqAJqOs9ruNvJcSu
+KpxxTKHQSogNNo25HIeMf4VO0rnnocU5wm7uPR/L6v8AU0WeSTiujIZmBchOlzVuRUOuxy0g
+NbglSwTtWrPcQMDy1v2iKYVsjxVFJU2gBRT3FXlP8c1tUqcGjx4Zbo3fPX4u2RPNKap+6K/q
+lWy8afVnGJjv93drSkwXHbv1sOoDanmnlAk7tzYIAH8anr3a2brGQ04440ttYcadbOFNqHlH
+/wB86iOzFw9abh93Y/BVtTpMepSWRdHf0/ZjHlljtx7kj1o/rH+NOtH9Y/xqO7MXD1puH3dj
+8FOzFw9abh93Y/BXQZkj1o/rH+Na858rbaTnvkM/2qa1uzFw9abh93Y/BX4dLzzjOqJ5wQR/
+J2ORByD9SgMeprje4kNEyywmri4yrc9DKwhx9GDybWohKV5wRu5HGCU53DYsUq6qtyHLwIzc
+xwla2o5JQ0CeSNx+sQMAqwMnJAHdXx2YuHrTcPu7H4KdmJ/l1RcCPNwGPwUBm0Id1rmq89zl
+n/xlVFauhG468tsNKwhTlpl7Se7IdYI/8qtVot7FsgoiR9xSnJKlHJUT3knzmte82Vi5PR5Q
+kSYcyNngyY6khaAe8YUCkg+Ygju81Uy4o5scsc+jVP8ABkwm4SUl1RkskJyEw/xlILsiQt9Y
+QSUgq8gJ7+6t+oLwHdfXK+e5h/Ip4DuvrlfPcw/kVGHFHDBQj0QnJzluZO0qC8B3X1yvnuYf
+yKeA7p65Xz3MP5FalRpn/TeqP96N/wBzjVO1pWa2MWuMtllbrq3HC6888rct1Z71KPn5AcsA
+AAAACt2gFKVRukLUuobZrLSunNPi1pcvaZxW7NYW4ElhpLiQAlacbskEnOMg45YNZSUVbNMW
+J5ZbY/F/orfyReaVymJ046Zb0vZrpdGH2pdwhLluRmltjhIQ4ptRBcWjdlSFbUpyogHAqzw+
+kOyz9Qs2e1xLrcd7cZx2VFi72I4kIK2S4c7khSRndtKRkZIzVFmg+jN56HUQvdB8X8uC30rn
+Nx6WLX1fUka1wH5N2sttdn9X48dxC0IO0krbdUBtOCpJIXjuSSQDWLX0x3qPcLWrU1qag206
+dF6nvtsJKlpcXsa4QEhW1BUptIKsrKjzQgHKYeogn1Lw8O1E02l/Prx6nbaVzNPS7ZLkmALS
+64265fYlrkNrYak/z4UU4W0+EAHYfHCl7SCCgnu3dOdLFgvirQGLdd4yLwxJdguSW2kIdMfP
+FRniHBAGcnCfb31KzQfcpLQ54q3H31/ZX+Bf6Vy+69M9lZ0pfb3bLVLuDlkdYblMJkxylPGO
+G18VtxaCknxfE3KB70jBImIvSdY3rw1bnIF0jBy4ptSpLjbZZbnFO4xlFKyd47iQCnPco99F
+mg+4eh1CVuPvh/s0XilVLtNP/wAsfY3gxvB/Z7wnxNquLxescLGc427eeMZz5fJWtqLpMsNi
+7VdbiXJfZjqfXeE2g8TrOOHw8rGcZGc7fZmrPJFctlFpcsmlFW2k/wBXS+bLtSqIz0pWFy7C
+Aq33dtHh5dgMpTKOCJae5OQsqwryHH7cVgg9L2mJUi3jql1Zh3ETVxZzrKAwtuKhSnXOSyrb
+hJA8XOfIO+o86HqW+xZ/+L9/0zoVKqejte2nU9xFvjxLjBkuQEXGOiY2lPHirO1LqNqleLnH
+I4PMcqtlWjJSVowyY545bZqmKUpVigpSlAKUpQCo7UN8tVgt6p93mtRI4ONyz3nzAeU1I1xL
+6Rt6s9rv1gfvdtdukOLvdXES9sCycbc8jkAju8tZ5ZuEG0dWiwRz5lCXT4dS2L6Zej9tex68
+ONYIBLkZaRz8vMVeLZcIV0gtTrfKalRnU7kONq3JUK8B6q1A9qnUcy5Oo4a5DpUEAYShPclI
+A8wwK2bi5Kt1ltwiz5SArfuCHCkZyPIDXnrXTVuS4PpJ/wDT2CaisU2m+t8/we/KV4z+jdcb
+g/002Bp+dKdbV1nKVuqIP8md8hNezK7dPn86O6qPC8T8PegyrG5Xav07v+BSlVPpc1cvRGg5
+2oWYqJT7JQ2y2tYSkrWoJBPMEgZzhPPl5BkjWUlFNs4cWOWWahHq+C2UqrQdQy2OjeRqq4uR
+JqmYLs3ERCUIUlCCraCl11JPinxkrIqG6HNc3PV6rnFu8aG1KhMQZQVFSpKFNyo4eSkhSlHc
+nJBOefmFV8yNpepr9lybJTXSPX9joVK5xaNT6zla2vGlJ6tPQpES3omtyUMPONs7ncBBStbZ
+fHD5lxG1KVHackYM70W3y66k0wq8XNUNbb8p0QXY0dbAdjpVtS4UKWsgqIUfrdxTSORSdInJ
+pZ447m12+fQssqQxFYU/JeQy0gZUtZwBUT2u0v8Ab9u9+mvjU6EO3awMOpC2nJqytChkK2sO
+KTkexSQf3VSL/wBJtxt3Sf2dahRFWxi5W+2PqUFcZTsttxaVpOdoSnYAQUnOTzFTPIodSuDT
+zztqHZWXrtdpf7ft3v007XaX+37d79NS+6m6rmBEdrtL/b9u9+mna7S/2/bvfpqX3Vr3F9xq
+OlTatqi80nOPIpxIP/AmgNDtdpf7ft3v00GrtMEgC/24k/8Az001RdLnb4rabNZXLtOeXtba
+LvBaSBzUpx0ghIxyHIkkgYxkjdtssXC2syVxJEbjIyuPJb2uNnypUOYyO7kSD3gkYNAbjTiH
+W0uNrStChkKByCK17pcoFrjGTcZjERkd63VhI/iai9DAItUplAw2zcJTTaR3JQl5QSkewAYq
+mdNmouy0xm+KiNTeo2x95lh3mjjF5hpCj+zin9xNVlJRVsvjxyyTUI9XwW7t3oz1ntP3lP8A
+jTt3oz1ntP3lP+NaHRjfHNS2y6i5wYKJ1pu8m1vqjtFLbimiPHSlRJAIUORJ/bVt6rG9HZ/q
+CkZblaJy43jm4S6oge3ejPWe0/eU/wCNO3ejPWe0/eU/41PdVjejs/1BTqsb0dn+oKsZn5Dl
+R5kZEmI8h9lwZQtByFD2Gs1QGkm249x1HFYQlthm5jhtpGEo3RmFqwPJlS1H9pNT9AKrGstF
+w9TXa03Vy6XS3TLUmQmM7CW2Dh9AQ5nehX9EYBGCMk9+MWelRKKkqZfHkljlui+faKQvoysL
+KbebPMutjdg29VuQ9b5CUOLjqVvKFKUlXPdlW5OFZJINbiNB2xrVXaKLcr1FkLDHWmmppDcw
+sIKGy8cb14CjkbsK5bgatdKr5cPQ1eqzPrI5xa+hzTVsaeah3G8toetkq1LSXm1fyZ9SlqRz
+b5bVrKknvz3lQ5VtS+ijS8xttqY5cH2kafasAbU6kAsNuJcQvkkHiBSUnPdy+rV9pVfJhVUW
+eu1Dd73ZTZHR7CmIgeE7/qC4uwbtHurTkmUhR4jIIQjaEBCUczkJSkk8yc1oRuiPTLNnsVq6
+1dXI1ljz47AW8jLiJiVJd3kIGSAo7du3HlzXQaVPlQfYhazOlSl7pr9mzm7XQ3plFluto8I3
+lcW6w4sSUFPN5UIxTwVg8PkpISE/qkd4J51IROjGxMXhq4uTrpIDdxF1VGdcb4Lk4I2mSoJQ
+DvPeQCE57kjuq8UosMF2Jetzu7k/fH7JFWvOi2Z+sk6si3272q5i3i3FUQR1IUzxC5gpdaXz
+3HvHmHtzEai6KbJflXdU68XsKvLEZq5Fp1pPWVR8cN0jh4CuXMJATz+qOWOgUo8UX1RWGrzQ
+pxlVf3+5Sf8AJnYfS7l/yn7TfziP86/U+p/Nez63+1VG090a3JerLGzKskuBp61JuaHY8q4s
+yGVIlIKOGwWwlYSdxUeIARnGTiu30qrwQdGsNfmgmru/lw1x+TKno7QVp0xcRcI8u4TZLcFF
+uYcmOIUWIqDlLSNqU+LnHM5PIc6tlKVpGKiqRy5Ms8kt03bFKUqxQUpSgFKUoD8WragqwTgZ
+5V4y6atXv6tnvSn2kxyy6thLOMFCUqIGfb5TXs6uVdJPQnp/Vkp+4Rlqt859W5xaPqrPlOP/
+APK59RjnONRPT8M1OHTzbyL8H6HjaFydznGBU9udvc2zaZt0RUm5TZBbYCVhPPHlzyxy7668
+fou3jijbq+MhvPPDBKh+/GP+FdQ6JehPTeg5wu5deul42bRKf/1Y8uwdw/bXJHSTk6kqR6+T
+xjDijeJ3Lsc16EOiXXemelC0Xy82huPBjcfiuCW0sp3MOIHJKiTzUK9OUpXbhwxwx2xPC12v
+ya7IsmRK0q49/EVGapsdv1Lp6bYrq2pyHMb4bgSrChzBBB8hBAI9oqTpWrSapnJGTi1KPVEX
+GsyfAL1nuU+Xd2X2lsurlhsLW2pO0pPDQgYxnnjPPvqt2DoytFiZaRbbxfmHETIslx5EtKVv
+ojt8NqO5tSApkJ5FOMnHM1eKVVwi6tGkdRkimouk+pS4nRxamZd0mO3e+TJVwtzls6xKlh1y
+NHWpSyhtRTnkpWQV7iMAdwxVl05aYthsFvskIuKjQY6I7SnCCtSUJABUQAMnGTgDnW/SpjCM
+eiIyZ8mRVJ2V3WDgYuFikLO1tuYsKUe4bmXEjP7VKA/fVbuOi7FO1i3qh8yhKS6y+tlLgDLr
+zKVJacUMZ3JC1AYIHdkGugy40eXHVHlMoeaWMKQsZBqH7HaW+wYHuRSUFLqRjyyx24ur4Prr
+Ptp1n2189jtLfYED3Ip2O0t9gQPcipopwfXWfbWGU8XEtJHP9O0T7AHEkmsnY7S32BA9yKdj
+tLfYED3IpQ4IvU0e5T4rarPenLVOZXubd4XGaUDyUlbZIChjmOYIIBzjIO7bf5Db2YqpciSW
+kYU/IXuccPlUo92T38gAO4ADlWfsdpb7Age5FBo/S4IIsMAEdx4QpQ4MegTvs0h0c0Oz5LiF
+DuUlTqiCPYQQag+kKyW3UOqoFnvSVeD59slRVEK2neVtLSEn9bxCof8AVq9MtNstJaaQlCEj
+CUgchWK4QYVwjKjT4keWwrvbebC0n9x5UaTVMmMnGSlHqiN0fpuBpe2PQoLkh9UiS5LkvyFB
+Tj7zhypatoAyeXcAOVTVQXY3SHqtY/uDX4adjdIeq1j+4NfholSpCc3OTlJ8snaVBdjdIeq1
+j+4Nfhp2N0h6rWP7g1+GpKnzpNaHrlqSSyoLZdug4a0nKVbYzCFYPlwpCh+0Gp+scZhiKwiP
+GZbZZQMIbbSEpSPMAO6slAKUpQClKUApSlAKUpQClKUApSlAKUpQClKUApSlAKUpQClKUApS
+lAKUpQClKUApSlAKUpQClKUApSlAKUpQClKUApSlAKUpQClKUApSlAKUpQH/2Q==
+--------------090109030206070103090500--
+
+--------------050702060806040107070701--
+
+--------------080809000000030101030405--
diff --git a/mailbox/elasticsearch-v6/src/test/resources/eml/emailWith3Attachments.eml b/mailbox/elasticsearch-v6/src/test/resources/eml/emailWith3Attachments.eml
new file mode 100644
index 0000000..7cacfcb
--- /dev/null
+++ b/mailbox/elasticsearch-v6/src/test/resources/eml/emailWith3Attachments.eml
@@ -0,0 +1,50 @@
+To: Laura ROYET <la...@linagora.com>
+From: Laura Royet <la...@linagora.com>
+Subject: test
+Message-ID: <cb...@linagora.com>
+Date: Wed, 11 Jan 2017 11:52:35 +0100
+User-Agent: Mozilla/5.0 (X11; Linux x86_64; rv:45.0) Gecko/20100101
+ Thunderbird/45.6.0
+MIME-Version: 1.0
+Content-Type: multipart/mixed;
+ boundary="------------36566F1E9D791340FFB75FF8"
+
+This is a multi-part message in MIME format.
+--------------36566F1E9D791340FFB75FF8
+Content-Type: text/plain; charset=utf-8; format=flowed
+Content-Transfer-Encoding: 7bit
+
+
+
+-- 
+Laura Royet
+
+
+--------------36566F1E9D791340FFB75FF8
+Content-Type: application/vnd.oasis.opendocument.text;
+ name="attachment1.odt"
+Content-Transfer-Encoding: base64
+Content-Disposition: attachment;
+ filename="attachment1.odt"
+
+UEsDBBQAAAgAAGJVK0pexjIMJwAAACcAAAAIAAAAbWltZXR5cGVhcHBsaWNhdGlvbi92bmQu
+dC54bWxQSwUGAAAAABEAEQBwBAAAjyUAAAAA
+--------------36566F1E9D791340FFB75FF8
+Content-Type: application/vnd.oasis.opendocument.text;
+ name="attachment2-nonIndexableAttachment.html"
+Content-Transfer-Encoding: base64
+Content-Disposition: attachment;
+ filename="attachment2-nonIndexableAttachment.odt"
+
+PCFET0NUWVBFIGh0bWw+CjxodG1sIGNsYXNzPSJtb3ppbGxhIiBsYW5nPSJlbiI+PGhlYWQ+
+CI+PC9kaXY+PC9kaXY+PC9ib2R5PjwvaHRtbD4=
+--------------36566F1E9D791340FFB75FF8
+Content-Type: application/vnd.oasis.opendocument.text;
+ name="attachment3.odt"
+Content-Transfer-Encoding: base64
+Content-Disposition: attachment;
+ filename="attachment3.odt"
+
+UEsDBBQAAAgAAG9VK0pexjIMJwAAACcAAAAIAAAAbWltZXR5cGVhcHBsaWNhdGlvbi92bmQu
+AAAAEgkAABNRVRBLUlORi9tYW5pZmVzdC54bWxQSwUGAAAAABEAEQBwBAAApyUAAAAA
+--------------36566F1E9D791340FFB75FF8--
diff --git a/mailbox/elasticsearch-v6/src/test/resources/eml/mailWithHeaders.eml b/mailbox/elasticsearch-v6/src/test/resources/eml/mailWithHeaders.eml
new file mode 100644
index 0000000..2aff55d
--- /dev/null
+++ b/mailbox/elasticsearch-v6/src/test/resources/eml/mailWithHeaders.eml
@@ -0,0 +1,14 @@
+Content-Type: text/plain; Charset=UTF-8
+Date: Fri, 17 Sep 2010 17:12:26 +0200
+Subject: my subject
+To: a@test, B <b...@test>
+Cc: c@test
+Bcc: dD <d...@test>
+MIME-Version: 1.0
+Message-Id: <20...@lenny>
+From: Ad Min <ad...@opush.test>
+
+Mail content
+
+-- 
+Ad Min
diff --git a/mailbox/elasticsearch-v6/src/test/resources/logback-test.xml b/mailbox/elasticsearch-v6/src/test/resources/logback-test.xml
new file mode 100644
index 0000000..b0c305c
--- /dev/null
+++ b/mailbox/elasticsearch-v6/src/test/resources/logback-test.xml
@@ -0,0 +1,24 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<configuration>
+
+        <contextListener class="ch.qos.logback.classic.jul.LevelChangePropagator">
+                <resetJUL>true</resetJUL>
+        </contextListener>
+
+        <appender name="CONSOLE" class="ch.qos.logback.core.ConsoleAppender">
+                <encoder>
+                        <pattern>%d{HH:mm:ss.SSS} [%-5level] %logger{15} - %msg%n%rEx</pattern>
+                        <immediateFlush>false</immediateFlush>
+                </encoder>
+        </appender>
+
+        <root level="ERROR">
+                <appender-ref ref="CONSOLE" />
+        </root>
+
+
+        <logger name="org.apache.james" level="WARN" >
+                <appender-ref ref="CONSOLE" />
+        </logger>
+
+</configuration>
diff --git a/mailbox/pom.xml b/mailbox/pom.xml
index 449bb35..7ae95b1 100644
--- a/mailbox/pom.xml
+++ b/mailbox/pom.xml
@@ -40,6 +40,7 @@
         <module>caching</module>
         <module>cassandra</module>
         <module>elasticsearch</module>
+        <module>elasticsearch-v6</module>
 
         <module>event/event-cassandra</module>
         <module>event/event-memory</module>


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