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
The following commit(s) were added to refs/heads/master by this push: new 3217d0c06a JAMES-2080 Allow turning off header indexing in OpenSearch (#1516) 3217d0c06a is described below commit 3217d0c06ab9d25181d5d3a11d65356afebed354 Author: Benoit TELLIER <btell...@linagora.com> AuthorDate: Thu Apr 13 17:00:59 2023 +0700 JAMES-2080 Allow turning off header indexing in OpenSearch (#1516) * JAMES-2080 Allow turning off header indexing in OpenSearch Indicates if you wish to index headers or not (default: true). Note that specific headers (From, To, Cc, Bcc, Subject, Message-Id, Date, Content-Type) are still indexed in their dedicated type. Header indexing is expensive as each header currently need to be stored as a nested document but turning off headers indexing result in non-strict compliance with the IMAP / JMAP standards. --- .../james/mailbox/opensearch/IndexHeaders.java | 24 +++++++++ .../opensearch/OpenSearchMailboxConfiguration.java | 35 ++++++++++--- .../mailbox/opensearch/json/IndexableMessage.java | 19 ++++++- .../opensearch/json/MessageToOpenSearchJson.java | 11 ++-- .../opensearch/OpenSearchIntegrationTest.java | 2 +- .../OpenSearchListeningMessageSearchIndexTest.java | 7 ++- .../opensearch/json/IndexableMessageTest.java | 45 +++++++++++++++++ .../json/MessageToOpenSearchJsonTest.java | 58 +++++++++++++++------- .../opensearch/search/OpenSearchSearcherTest.java | 3 +- .../src/test/resources/eml/spamMailNoHeaders.json | 45 +++++++++++++++++ .../elasticsearch/host/OpenSearchHostSystem.java | 3 +- .../modules/ROOT/pages/configure/opensearch.adoc | 6 +++ .../modules/mailbox/OpenSearchMailboxModule.java | 8 ++- .../james/webadmin/routes/MailboxesRoutesTest.java | 3 +- .../webadmin/routes/UserMailboxesRoutesTest.java | 3 +- src/site/xdoc/server/config-opensearch.xml | 5 ++ 16 files changed, 238 insertions(+), 39 deletions(-) diff --git a/mailbox/opensearch/src/main/java/org/apache/james/mailbox/opensearch/IndexHeaders.java b/mailbox/opensearch/src/main/java/org/apache/james/mailbox/opensearch/IndexHeaders.java new file mode 100644 index 0000000000..699f62cc59 --- /dev/null +++ b/mailbox/opensearch/src/main/java/org/apache/james/mailbox/opensearch/IndexHeaders.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.opensearch; + +public enum IndexHeaders { + NO, YES +} diff --git a/mailbox/opensearch/src/main/java/org/apache/james/mailbox/opensearch/OpenSearchMailboxConfiguration.java b/mailbox/opensearch/src/main/java/org/apache/james/mailbox/opensearch/OpenSearchMailboxConfiguration.java index a3a0f7144b..cfa20857f2 100644 --- a/mailbox/opensearch/src/main/java/org/apache/james/mailbox/opensearch/OpenSearchMailboxConfiguration.java +++ b/mailbox/opensearch/src/main/java/org/apache/james/mailbox/opensearch/OpenSearchMailboxConfiguration.java @@ -34,12 +34,14 @@ public class OpenSearchMailboxConfiguration { private Optional<ReadAliasName> readAliasMailboxName; private Optional<WriteAliasName> writeAliasMailboxName; private Optional<IndexAttachments> indexAttachment; + private Optional<IndexHeaders> indexHeaders; Builder() { indexMailboxName = Optional.empty(); readAliasMailboxName = Optional.empty(); writeAliasMailboxName = Optional.empty(); indexAttachment = Optional.empty(); + indexHeaders = Optional.empty(); } Builder indexMailboxName(Optional<IndexName> indexMailboxName) { @@ -57,20 +59,23 @@ public class OpenSearchMailboxConfiguration { return this; } - Builder indexAttachment(IndexAttachments indexAttachment) { this.indexAttachment = Optional.of(indexAttachment); return this; } - + Builder indexHeaders(IndexHeaders indexHeaders) { + this.indexHeaders = Optional.of(indexHeaders); + return this; + } public OpenSearchMailboxConfiguration build() { return new OpenSearchMailboxConfiguration( indexMailboxName.orElse(MailboxOpenSearchConstants.DEFAULT_MAILBOX_INDEX), readAliasMailboxName.orElse(MailboxOpenSearchConstants.DEFAULT_MAILBOX_READ_ALIAS), writeAliasMailboxName.orElse(MailboxOpenSearchConstants.DEFAULT_MAILBOX_WRITE_ALIAS), - indexAttachment.orElse(IndexAttachments.YES)); + indexAttachment.orElse(IndexAttachments.YES), + indexHeaders.orElse(IndexHeaders.YES)); } } @@ -85,7 +90,9 @@ public class OpenSearchMailboxConfiguration { private static final String OPENSEARCH_ALIAS_READ_MAILBOX_NAME = "opensearch.alias.read.mailbox.name"; private static final String OPENSEARCH_ALIAS_WRITE_MAILBOX_NAME = "opensearch.alias.write.mailbox.name"; private static final String OPENSEARCH_INDEX_ATTACHMENTS = "opensearch.indexAttachments"; + private static final String OPENSEARCH_INDEX_HEADERS = "opensearch.indexHeaders"; private static final boolean DEFAULT_INDEX_ATTACHMENTS = true; + private static final boolean DEFAULT_INDEX_HEADERS = true; public static final OpenSearchMailboxConfiguration DEFAULT_CONFIGURATION = builder().build(); @@ -95,6 +102,7 @@ public class OpenSearchMailboxConfiguration { .readAliasMailboxName(computeMailboxReadAlias(configuration)) .writeAliasMailboxName(computeMailboxWriteAlias(configuration)) .indexAttachment(provideIndexAttachments(configuration)) + .indexHeaders(provideIndexHeaders(configuration)) .build(); } @@ -119,29 +127,35 @@ public class OpenSearchMailboxConfiguration { .map(ReadAliasName::new)); } - private static IndexAttachments provideIndexAttachments(Configuration configuration) { if (configuration.getBoolean(OPENSEARCH_INDEX_ATTACHMENTS, DEFAULT_INDEX_ATTACHMENTS)) { return IndexAttachments.YES; } return IndexAttachments.NO; } - + + private static IndexHeaders provideIndexHeaders(Configuration configuration) { + if (configuration.getBoolean(OPENSEARCH_INDEX_HEADERS, DEFAULT_INDEX_HEADERS)) { + return IndexHeaders.YES; + } + return IndexHeaders.NO; + } private final IndexName indexMailboxName; private final ReadAliasName readAliasMailboxName; private final WriteAliasName writeAliasMailboxName; private final IndexAttachments indexAttachment; + private final IndexHeaders indexHeaders; private OpenSearchMailboxConfiguration(IndexName indexMailboxName, ReadAliasName readAliasMailboxName, - WriteAliasName writeAliasMailboxName, IndexAttachments indexAttachment) { + WriteAliasName writeAliasMailboxName, IndexAttachments indexAttachment, IndexHeaders indexHeaders) { this.indexMailboxName = indexMailboxName; this.readAliasMailboxName = readAliasMailboxName; this.writeAliasMailboxName = writeAliasMailboxName; this.indexAttachment = indexAttachment; + this.indexHeaders = indexHeaders; } - public IndexName getIndexMailboxName() { return indexMailboxName; } @@ -158,12 +172,17 @@ public class OpenSearchMailboxConfiguration { return indexAttachment; } + public IndexHeaders getIndexHeaders() { + return indexHeaders; + } + @Override public final boolean equals(Object o) { if (o instanceof OpenSearchMailboxConfiguration) { OpenSearchMailboxConfiguration that = (OpenSearchMailboxConfiguration) o; return Objects.equals(this.indexAttachment, that.indexAttachment) + && Objects.equals(this.indexHeaders, that.indexHeaders) && Objects.equals(this.indexMailboxName, that.indexMailboxName) && Objects.equals(this.readAliasMailboxName, that.readAliasMailboxName) && Objects.equals(this.writeAliasMailboxName, that.writeAliasMailboxName); @@ -173,6 +192,6 @@ public class OpenSearchMailboxConfiguration { @Override public final int hashCode() { - return Objects.hash(indexMailboxName, readAliasMailboxName, writeAliasMailboxName, indexAttachment, writeAliasMailboxName); + return Objects.hash(indexMailboxName, readAliasMailboxName, writeAliasMailboxName, indexAttachment, indexHeaders, writeAliasMailboxName); } } diff --git a/mailbox/opensearch/src/main/java/org/apache/james/mailbox/opensearch/json/IndexableMessage.java b/mailbox/opensearch/src/main/java/org/apache/james/mailbox/opensearch/json/IndexableMessage.java index 68725eff0f..be7e22b6d8 100644 --- a/mailbox/opensearch/src/main/java/org/apache/james/mailbox/opensearch/json/IndexableMessage.java +++ b/mailbox/opensearch/src/main/java/org/apache/james/mailbox/opensearch/json/IndexableMessage.java @@ -31,6 +31,7 @@ import org.apache.james.mailbox.ModSeq; import org.apache.james.mailbox.extractor.TextExtractor; import org.apache.james.mailbox.model.MessageAttachmentMetadata; import org.apache.james.mailbox.opensearch.IndexAttachments; +import org.apache.james.mailbox.opensearch.IndexHeaders; import org.apache.james.mailbox.store.mail.model.MailboxMessage; import org.apache.james.mailbox.store.search.SearchUtil; import org.apache.james.mime4j.MimeException; @@ -56,9 +57,9 @@ public class IndexableMessage { } private IndexAttachments indexAttachments; + private IndexHeaders indexHeaders; private MailboxMessage message; private TextExtractor textExtractor; - private ZoneId zoneId; private Builder() { @@ -68,6 +69,7 @@ public class IndexableMessage { Preconditions.checkNotNull(message.getMailboxId()); Preconditions.checkNotNull(textExtractor); Preconditions.checkNotNull(indexAttachments); + Preconditions.checkNotNull(indexHeaders); Preconditions.checkNotNull(zoneId); try { @@ -87,6 +89,11 @@ public class IndexableMessage { return this; } + public Builder indexHeaders(IndexHeaders indexHeaders) { + this.indexHeaders = indexHeaders; + return this; + } + public Builder message(MailboxMessage message) { this.message = message; return this; @@ -149,7 +156,7 @@ public class IndexableMessage { date, from, hasAttachment, - headers, + filterHeadersIfNeeded(headers), isAnswered, isDeleted, isDraft, @@ -173,6 +180,14 @@ public class IndexableMessage { }); } + private List<HeaderCollection.Header> filterHeadersIfNeeded(List<HeaderCollection.Header> headers) { + if (IndexHeaders.YES.equals(indexHeaders)) { + return headers; + } else { + return ImmutableList.of(); + } + } + private List<MimePart> setFlattenedAttachments(MimePart parsingResult, IndexAttachments indexAttachments) { if (IndexAttachments.YES.equals(indexAttachments)) { return parsingResult.getAttachmentsStream() diff --git a/mailbox/opensearch/src/main/java/org/apache/james/mailbox/opensearch/json/MessageToOpenSearchJson.java b/mailbox/opensearch/src/main/java/org/apache/james/mailbox/opensearch/json/MessageToOpenSearchJson.java index fb7b97fdb1..4dfed28820 100644 --- a/mailbox/opensearch/src/main/java/org/apache/james/mailbox/opensearch/json/MessageToOpenSearchJson.java +++ b/mailbox/opensearch/src/main/java/org/apache/james/mailbox/opensearch/json/MessageToOpenSearchJson.java @@ -27,6 +27,7 @@ import javax.mail.Flags; import org.apache.james.mailbox.ModSeq; import org.apache.james.mailbox.extractor.TextExtractor; import org.apache.james.mailbox.opensearch.IndexAttachments; +import org.apache.james.mailbox.opensearch.IndexHeaders; import org.apache.james.mailbox.store.mail.model.MailboxMessage; import com.fasterxml.jackson.core.JsonProcessingException; @@ -44,19 +45,21 @@ public class MessageToOpenSearchJson { private final TextExtractor textExtractor; private final ZoneId zoneId; private final IndexAttachments indexAttachments; + private final IndexHeaders indexHeaders; - public MessageToOpenSearchJson(TextExtractor textExtractor, ZoneId zoneId, IndexAttachments indexAttachments) { + public MessageToOpenSearchJson(TextExtractor textExtractor, ZoneId zoneId, IndexAttachments indexAttachments, IndexHeaders indexHeaders) { this.textExtractor = textExtractor; this.zoneId = zoneId; this.indexAttachments = indexAttachments; + this.indexHeaders = indexHeaders; this.mapper = new ObjectMapper(); this.mapper.registerModule(new GuavaModule()); this.mapper.registerModule(new Jdk8Module()); } @Inject - public MessageToOpenSearchJson(TextExtractor textExtractor, IndexAttachments indexAttachments) { - this(textExtractor, ZoneId.systemDefault(), indexAttachments); + public MessageToOpenSearchJson(TextExtractor textExtractor, IndexAttachments indexAttachments, IndexHeaders indexHeaders) { + this(textExtractor, ZoneId.systemDefault(), indexAttachments, indexHeaders); } public Mono<String> convertToJson(MailboxMessage message) { @@ -67,6 +70,7 @@ public class MessageToOpenSearchJson { .extractor(textExtractor) .zoneId(zoneId) .indexAttachments(indexAttachments) + .indexHeaders(indexHeaders) .build() .map(Throwing.function(mapper::writeValueAsString)); } @@ -77,6 +81,7 @@ public class MessageToOpenSearchJson { .extractor(textExtractor) .zoneId(zoneId) .indexAttachments(IndexAttachments.NO) + .indexHeaders(indexHeaders) .build() .map(Throwing.function(mapper::writeValueAsString)); } diff --git a/mailbox/opensearch/src/test/java/org/apache/james/mailbox/opensearch/OpenSearchIntegrationTest.java b/mailbox/opensearch/src/test/java/org/apache/james/mailbox/opensearch/OpenSearchIntegrationTest.java index 4d6c23f7a1..66c25e9f46 100644 --- a/mailbox/opensearch/src/test/java/org/apache/james/mailbox/opensearch/OpenSearchIntegrationTest.java +++ b/mailbox/opensearch/src/test/java/org/apache/james/mailbox/opensearch/OpenSearchIntegrationTest.java @@ -135,7 +135,7 @@ class OpenSearchIntegrationTest extends AbstractMessageSearchIndexTest { MailboxOpenSearchConstants.DEFAULT_MAILBOX_WRITE_ALIAS), new OpenSearchSearcher(client, new QueryConverter(new CriterionConverter()), SEARCH_SIZE, MailboxOpenSearchConstants.DEFAULT_MAILBOX_READ_ALIAS, routingKeyFactory), - new MessageToOpenSearchJson(textExtractor, ZoneId.of("Europe/Paris"), IndexAttachments.YES), + new MessageToOpenSearchJson(textExtractor, ZoneId.of("Europe/Paris"), IndexAttachments.YES, IndexHeaders.YES), preInstanciationStage.getSessionProvider(), routingKeyFactory, messageIdFactory)) .noPreDeletionHooks() .storeQuotaManager() diff --git a/mailbox/opensearch/src/test/java/org/apache/james/mailbox/opensearch/events/OpenSearchListeningMessageSearchIndexTest.java b/mailbox/opensearch/src/test/java/org/apache/james/mailbox/opensearch/events/OpenSearchListeningMessageSearchIndexTest.java index c50e447cb6..22d9e723c8 100644 --- a/mailbox/opensearch/src/test/java/org/apache/james/mailbox/opensearch/events/OpenSearchListeningMessageSearchIndexTest.java +++ b/mailbox/opensearch/src/test/java/org/apache/james/mailbox/opensearch/events/OpenSearchListeningMessageSearchIndexTest.java @@ -67,6 +67,7 @@ import org.apache.james.mailbox.model.ThreadId; import org.apache.james.mailbox.model.UidValidity; import org.apache.james.mailbox.model.UpdatedFlags; import org.apache.james.mailbox.opensearch.IndexAttachments; +import org.apache.james.mailbox.opensearch.IndexHeaders; import org.apache.james.mailbox.opensearch.MailboxIdRoutingKeyFactory; import org.apache.james.mailbox.opensearch.MailboxIndexCreationUtil; import org.apache.james.mailbox.opensearch.MailboxOpenSearchConstants; @@ -188,7 +189,8 @@ class OpenSearchListeningMessageSearchIndexTest { MessageToOpenSearchJson messageToOpenSearchJson = new MessageToOpenSearchJson( new DefaultTextExtractor(), ZoneId.of("UTC"), - IndexAttachments.YES); + IndexAttachments.YES, + IndexHeaders.YES); InMemoryMessageId.Factory messageIdFactory = new InMemoryMessageId.Factory(); @@ -272,7 +274,8 @@ class OpenSearchListeningMessageSearchIndexTest { MessageToOpenSearchJson messageToOpenSearchJson = new MessageToOpenSearchJson( new FailingTextExtractor(), ZoneId.of("Europe/Paris"), - IndexAttachments.YES); + IndexAttachments.YES, + IndexHeaders.YES); testee = new OpenSearchListeningMessageSearchIndex(mapperFactory, ImmutableSet.of(), openSearchIndexer, openSearchSearcher, diff --git a/mailbox/opensearch/src/test/java/org/apache/james/mailbox/opensearch/json/IndexableMessageTest.java b/mailbox/opensearch/src/test/java/org/apache/james/mailbox/opensearch/json/IndexableMessageTest.java index b477c69f49..96ff8a3a45 100644 --- a/mailbox/opensearch/src/test/java/org/apache/james/mailbox/opensearch/json/IndexableMessageTest.java +++ b/mailbox/opensearch/src/test/java/org/apache/james/mailbox/opensearch/json/IndexableMessageTest.java @@ -44,6 +44,7 @@ import org.apache.james.mailbox.model.MessageId; import org.apache.james.mailbox.model.TestId; import org.apache.james.mailbox.model.ThreadId; import org.apache.james.mailbox.opensearch.IndexAttachments; +import org.apache.james.mailbox.opensearch.IndexHeaders; import org.apache.james.mailbox.store.extractor.DefaultTextExtractor; import org.apache.james.mailbox.store.mail.model.MailboxMessage; import org.apache.james.mailbox.tika.TikaConfiguration; @@ -112,6 +113,7 @@ class IndexableMessageTest { .extractor(new DefaultTextExtractor()) .zoneId(ZoneId.of("Europe/Paris")) .indexAttachments(IndexAttachments.YES) + .indexHeaders(IndexHeaders.YES) .build() .block(); @@ -145,6 +147,7 @@ class IndexableMessageTest { .extractor(new DefaultTextExtractor()) .zoneId(ZoneId.of("Europe/Paris")) .indexAttachments(IndexAttachments.NO) + .indexHeaders(IndexHeaders.YES) .build() .block(); @@ -176,6 +179,7 @@ class IndexableMessageTest { .extractor(new DefaultTextExtractor()) .zoneId(ZoneId.of("Europe/Paris")) .indexAttachments(IndexAttachments.NO) + .indexHeaders(IndexHeaders.YES) .build() .block(); @@ -183,6 +187,38 @@ class IndexableMessageTest { assertThat(indexableMessage.getAttachments()).isEmpty(); } + @Test + void headersShouldNotBeenIndexedWhenAsked() throws Exception { + //Given + MailboxMessage mailboxMessage = mock(MailboxMessage.class); + TestId mailboxId = TestId.of(1); + when(mailboxMessage.getMailboxId()) + .thenReturn(mailboxId); + when(mailboxMessage.getModSeq()) + .thenReturn(ModSeq.first()); + 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) + .extractor(new DefaultTextExtractor()) + .zoneId(ZoneId.of("Europe/Paris")) + .indexAttachments(IndexAttachments.YES) + .indexHeaders(IndexHeaders.NO) + .build() + .block(); + + // Then + assertThat(indexableMessage.getHeaders()).isEmpty(); + } + @Test void attachmentsShouldBeenIndexedWhenAsked() throws Exception { //Given @@ -207,6 +243,7 @@ class IndexableMessageTest { .extractor(new DefaultTextExtractor()) .zoneId(ZoneId.of("Europe/Paris")) .indexAttachments(IndexAttachments.YES) + .indexHeaders(IndexHeaders.YES) .build() .block(); @@ -246,6 +283,7 @@ class IndexableMessageTest { .extractor(textExtractor) .zoneId(ZoneId.of("Europe/Paris")) .indexAttachments(IndexAttachments.YES) + .indexHeaders(IndexHeaders.YES) .build() .block(); @@ -283,6 +321,7 @@ class IndexableMessageTest { .extractor(textExtractor) .zoneId(ZoneId.of("Europe/Paris")) .indexAttachments(IndexAttachments.YES) + .indexHeaders(IndexHeaders.YES) .build() .block(); @@ -317,6 +356,7 @@ class IndexableMessageTest { .extractor(textExtractor) .zoneId(ZoneId.of("Europe/Paris")) .indexAttachments(IndexAttachments.YES) + .indexHeaders(IndexHeaders.YES) .build() .block(); @@ -348,6 +388,7 @@ class IndexableMessageTest { .extractor(textExtractor) .zoneId(ZoneId.of("Europe/Paris")) .indexAttachments(IndexAttachments.YES) + .indexHeaders(IndexHeaders.YES) .build() .block(); @@ -381,6 +422,7 @@ class IndexableMessageTest { .extractor(textExtractor) .zoneId(ZoneId.of("Europe/Paris")) .indexAttachments(IndexAttachments.YES) + .indexHeaders(IndexHeaders.YES) .build() .block(); @@ -415,6 +457,7 @@ class IndexableMessageTest { .extractor(new DefaultTextExtractor()) .zoneId(ZoneId.of("Europe/Paris")) .indexAttachments(IndexAttachments.NO) + .indexHeaders(IndexHeaders.YES) .build() .block(); @@ -451,6 +494,7 @@ class IndexableMessageTest { .extractor(new DefaultTextExtractor()) .zoneId(ZoneId.of("Europe/Paris")) .indexAttachments(IndexAttachments.NO) + .indexHeaders(IndexHeaders.YES) .build() .block(); @@ -486,6 +530,7 @@ class IndexableMessageTest { .extractor(new DefaultTextExtractor()) .zoneId(ZoneId.of("Europe/Paris")) .indexAttachments(IndexAttachments.NO) + .indexHeaders(IndexHeaders.YES) .build() .block(); diff --git a/mailbox/opensearch/src/test/java/org/apache/james/mailbox/opensearch/json/MessageToOpenSearchJsonTest.java b/mailbox/opensearch/src/test/java/org/apache/james/mailbox/opensearch/json/MessageToOpenSearchJsonTest.java index 5108af0739..ba3af351c0 100644 --- a/mailbox/opensearch/src/test/java/org/apache/james/mailbox/opensearch/json/MessageToOpenSearchJsonTest.java +++ b/mailbox/opensearch/src/test/java/org/apache/james/mailbox/opensearch/json/MessageToOpenSearchJsonTest.java @@ -43,6 +43,7 @@ import org.apache.james.mailbox.model.TestId; import org.apache.james.mailbox.model.TestMessageId; import org.apache.james.mailbox.model.ThreadId; import org.apache.james.mailbox.opensearch.IndexAttachments; +import org.apache.james.mailbox.opensearch.IndexHeaders; import org.apache.james.mailbox.store.extractor.DefaultTextExtractor; import org.apache.james.mailbox.store.extractor.JsoupTextExtractor; import org.apache.james.mailbox.store.mail.model.MailboxMessage; @@ -95,7 +96,7 @@ class MessageToOpenSearchJsonTest { void spamEmailShouldBeWellConvertedToJson() throws IOException { MessageToOpenSearchJson messageToOpenSearchJson = new MessageToOpenSearchJson( new DefaultTextExtractor(), - ZoneId.of("Europe/Paris"), IndexAttachments.YES); + ZoneId.of("Europe/Paris"), IndexAttachments.YES, IndexHeaders.YES); MailboxMessage spamMail = new SimpleMailboxMessage(MESSAGE_ID, THREAD_ID, date, @@ -112,11 +113,32 @@ class MessageToOpenSearchJsonTest { .isEqualTo(ClassLoaderUtils.getSystemResourceAsString("eml/spamMail.json")); } + @Test + void spamEmailShouldBeWellConvertedToJsonWhenNoHeaders() throws IOException { + MessageToOpenSearchJson messageToOpenSearchJson = new MessageToOpenSearchJson( + new DefaultTextExtractor(), + ZoneId.of("Europe/Paris"), IndexAttachments.NO, IndexHeaders.NO); + MailboxMessage spamMail = new SimpleMailboxMessage(MESSAGE_ID, + THREAD_ID, + date, + SIZE, + BODY_START_OCTET, + new ByteContent(IOUtils.toByteArray(ClassLoaderUtils.getSystemResourceAsSharedStream("eml/spamMail.eml"))), + new Flags(), + propertyBuilder.build(), + MAILBOX_ID); + spamMail.setUid(UID); + spamMail.setModSeq(MOD_SEQ); + assertThatJson(messageToOpenSearchJson.convertToJson(spamMail).block()) + .when(IGNORING_ARRAY_ORDER) + .isEqualTo(ClassLoaderUtils.getSystemResourceAsString("eml/spamMailNoHeaders.json")); + } + @Test void inlinedMultipartEmailShouldBeWellConvertedToJson() throws IOException { MessageToOpenSearchJson messageToOpenSearchJson = new MessageToOpenSearchJson( new DefaultTextExtractor(), - ZoneId.of("Europe/Paris"), IndexAttachments.YES); + ZoneId.of("Europe/Paris"), IndexAttachments.YES, IndexHeaders.YES); MailboxMessage mail = new SimpleMailboxMessage(MESSAGE_ID, THREAD_ID, date, @@ -138,7 +160,7 @@ class MessageToOpenSearchJsonTest { void invalidCharsetShouldBeWellConvertedToJson() throws IOException { MessageToOpenSearchJson messageToOpenSearchJson = new MessageToOpenSearchJson( new DefaultTextExtractor(), - ZoneId.of("Europe/Paris"), IndexAttachments.YES); + ZoneId.of("Europe/Paris"), IndexAttachments.YES, IndexHeaders.YES); MailboxMessage spamMail = new SimpleMailboxMessage(MESSAGE_ID, THREAD_ID, date, @@ -161,7 +183,7 @@ class MessageToOpenSearchJsonTest { void htmlEmailShouldBeWellConvertedToJson() throws IOException { MessageToOpenSearchJson messageToOpenSearchJson = new MessageToOpenSearchJson( new DefaultTextExtractor(), - ZoneId.of("Europe/Paris"), IndexAttachments.YES); + ZoneId.of("Europe/Paris"), IndexAttachments.YES, IndexHeaders.YES); MailboxMessage htmlMail = new SimpleMailboxMessage(MESSAGE_ID, THREAD_ID, date, @@ -182,7 +204,7 @@ class MessageToOpenSearchJsonTest { void pgpSignedEmailShouldBeWellConvertedToJson() throws IOException { MessageToOpenSearchJson messageToOpenSearchJson = new MessageToOpenSearchJson( new DefaultTextExtractor(), - ZoneId.of("Europe/Paris"), IndexAttachments.YES); + ZoneId.of("Europe/Paris"), IndexAttachments.YES, IndexHeaders.YES); MailboxMessage pgpSignedMail = new SimpleMailboxMessage(MESSAGE_ID, THREAD_ID, date, @@ -203,7 +225,7 @@ class MessageToOpenSearchJsonTest { void simpleEmailShouldBeWellConvertedToJson() throws IOException { MessageToOpenSearchJson messageToOpenSearchJson = new MessageToOpenSearchJson( new DefaultTextExtractor(), - ZoneId.of("Europe/Paris"), IndexAttachments.YES); + ZoneId.of("Europe/Paris"), IndexAttachments.YES, IndexHeaders.YES); MailboxMessage mail = new SimpleMailboxMessage(MESSAGE_ID, THREAD_ID, date, @@ -224,7 +246,7 @@ class MessageToOpenSearchJsonTest { void recursiveEmailShouldBeWellConvertedToJson() throws IOException { MessageToOpenSearchJson messageToOpenSearchJson = new MessageToOpenSearchJson( new DefaultTextExtractor(), - ZoneId.of("Europe/Paris"), IndexAttachments.YES); + ZoneId.of("Europe/Paris"), IndexAttachments.YES, IndexHeaders.YES); MailboxMessage recursiveMail = new SimpleMailboxMessage(MESSAGE_ID, THREAD_ID, date, @@ -245,7 +267,7 @@ class MessageToOpenSearchJsonTest { void emailWithNoInternalDateShouldUseNowDate() throws IOException { MessageToOpenSearchJson messageToOpenSearchJson = new MessageToOpenSearchJson( new DefaultTextExtractor(), - ZoneId.of("Europe/Paris"), IndexAttachments.YES); + ZoneId.of("Europe/Paris"), IndexAttachments.YES, IndexHeaders.YES); MailboxMessage mailWithNoInternalDate = new SimpleMailboxMessage(MESSAGE_ID, THREAD_ID, null, @@ -282,7 +304,7 @@ class MessageToOpenSearchJsonTest { MessageToOpenSearchJson messageToOpenSearchJson = new MessageToOpenSearchJson( new DefaultTextExtractor(), ZoneId.of("Europe/Paris"), - IndexAttachments.YES); + IndexAttachments.YES, IndexHeaders.YES); String convertToJson = messageToOpenSearchJson.convertToJson(mailWithNoInternalDate).block(); // Then @@ -311,7 +333,7 @@ class MessageToOpenSearchJsonTest { MessageToOpenSearchJson messageToOpenSearchJson = new MessageToOpenSearchJson( new DefaultTextExtractor(), ZoneId.of("Europe/Paris"), - IndexAttachments.NO); + IndexAttachments.NO, IndexHeaders.YES); String convertToJson = messageToOpenSearchJson.convertToJson(mailWithNoInternalDate).block(); // Then @@ -325,7 +347,7 @@ class MessageToOpenSearchJsonTest { void emailWithNoMailboxIdShouldThrow() throws Exception { MessageToOpenSearchJson messageToOpenSearchJson = new MessageToOpenSearchJson( new DefaultTextExtractor(), - ZoneId.of("Europe/Paris"), IndexAttachments.YES); + ZoneId.of("Europe/Paris"), IndexAttachments.YES, IndexHeaders.YES); MailboxMessage mailWithNoMailboxId = new SimpleMailboxMessage(MESSAGE_ID, THREAD_ID, date, SIZE, BODY_START_OCTET, @@ -346,7 +368,7 @@ class MessageToOpenSearchJsonTest { MessageToOpenSearchJson messageToOpenSearchJson = new MessageToOpenSearchJson( new DefaultTextExtractor(), ZoneId.of("Europe/Paris"), - IndexAttachments.YES); + IndexAttachments.YES, IndexHeaders.YES); assertThatJson(messageToOpenSearchJson.getUpdatedJsonMessagePart(new Flags(), MOD_SEQ)) .isEqualTo("{\"modSeq\":42,\"isAnswered\":false,\"isDeleted\":false,\"isDraft\":false,\"isFlagged\":false,\"isRecent\":false,\"userFlags\":[],\"isUnread\":true}"); } @@ -356,7 +378,7 @@ class MessageToOpenSearchJsonTest { MessageToOpenSearchJson messageToOpenSearchJson = new MessageToOpenSearchJson( new DefaultTextExtractor(), ZoneId.of("Europe/Paris"), - IndexAttachments.YES); + IndexAttachments.YES, IndexHeaders.YES); assertThatJson(messageToOpenSearchJson.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}"); } @@ -366,7 +388,7 @@ class MessageToOpenSearchJsonTest { MessageToOpenSearchJson messageToOpenSearchJson = new MessageToOpenSearchJson( new DefaultTextExtractor(), ZoneId.of("Europe/Paris"), - IndexAttachments.YES); + IndexAttachments.YES, IndexHeaders.YES); assertThatThrownBy(() -> messageToOpenSearchJson.getUpdatedJsonMessagePart(null, MOD_SEQ)) .isInstanceOf(NullPointerException.class); @@ -377,7 +399,7 @@ class MessageToOpenSearchJsonTest { MessageToOpenSearchJson messageToOpenSearchJson = new MessageToOpenSearchJson( textExtractor, ZoneId.of("Europe/Paris"), - IndexAttachments.YES); + IndexAttachments.YES, IndexHeaders.YES); MailboxMessage spamMail = new SimpleMailboxMessage(MESSAGE_ID, THREAD_ID, date, SIZE, BODY_START_OCTET, @@ -413,7 +435,7 @@ class MessageToOpenSearchJsonTest { MessageToOpenSearchJson messageToOpenSearchJson = new MessageToOpenSearchJson( new DefaultTextExtractor(), ZoneId.of("Europe/Paris"), - IndexAttachments.NO); + IndexAttachments.NO, IndexHeaders.YES); String convertToJsonWithoutAttachment = messageToOpenSearchJson.convertToJsonWithoutAttachment(message).block(); // Then @@ -442,7 +464,7 @@ class MessageToOpenSearchJsonTest { MessageToOpenSearchJson messageToOpenSearchJson = new MessageToOpenSearchJson( new JsoupTextExtractor(), ZoneId.of("Europe/Paris"), - IndexAttachments.NO); + IndexAttachments.NO, IndexHeaders.YES); String convertToJsonWithoutAttachment = messageToOpenSearchJson.convertToJsonWithoutAttachment(message).block(); // Then @@ -458,7 +480,7 @@ class MessageToOpenSearchJsonTest { Date saveDate = new Date(1433628000000L); // 2015/06/07 00:00:00 0200 (Paris time zone) MessageToOpenSearchJson messageToOpenSearchJson = new MessageToOpenSearchJson( new DefaultTextExtractor(), - ZoneId.of("Europe/Paris"), IndexAttachments.YES); + ZoneId.of("Europe/Paris"), IndexAttachments.YES, IndexHeaders.YES); MailboxMessage mail = new SimpleMailboxMessage(MESSAGE_ID, THREAD_ID, date, diff --git a/mailbox/opensearch/src/test/java/org/apache/james/mailbox/opensearch/search/OpenSearchSearcherTest.java b/mailbox/opensearch/src/test/java/org/apache/james/mailbox/opensearch/search/OpenSearchSearcherTest.java index 70fbde8e8b..42faa77a2d 100644 --- a/mailbox/opensearch/src/test/java/org/apache/james/mailbox/opensearch/search/OpenSearchSearcherTest.java +++ b/mailbox/opensearch/src/test/java/org/apache/james/mailbox/opensearch/search/OpenSearchSearcherTest.java @@ -47,6 +47,7 @@ import org.apache.james.mailbox.model.MessageId; import org.apache.james.mailbox.model.MultimailboxesSearchQuery; import org.apache.james.mailbox.model.SearchQuery; import org.apache.james.mailbox.opensearch.IndexAttachments; +import org.apache.james.mailbox.opensearch.IndexHeaders; import org.apache.james.mailbox.opensearch.MailboxIdRoutingKeyFactory; import org.apache.james.mailbox.opensearch.MailboxIndexCreationUtil; import org.apache.james.mailbox.opensearch.MailboxOpenSearchConstants; @@ -124,7 +125,7 @@ class OpenSearchSearcherTest { MailboxOpenSearchConstants.DEFAULT_MAILBOX_WRITE_ALIAS), new OpenSearchSearcher(client, new QueryConverter(new CriterionConverter()), SEARCH_SIZE, MailboxOpenSearchConstants.DEFAULT_MAILBOX_READ_ALIAS, routingKeyFactory), - new MessageToOpenSearchJson(textExtractor, ZoneId.of("Europe/Paris"), IndexAttachments.YES), + new MessageToOpenSearchJson(textExtractor, ZoneId.of("Europe/Paris"), IndexAttachments.YES, IndexHeaders.YES), preInstanciationStage.getSessionProvider(), routingKeyFactory, messageIdFactory)) .noPreDeletionHooks() .storeQuotaManager() diff --git a/mailbox/store/src/test/resources/eml/spamMailNoHeaders.json b/mailbox/store/src/test/resources/eml/spamMailNoHeaders.json new file mode 100644 index 0000000000..6a9ca3f2f3 --- /dev/null +++ b/mailbox/store/src/test/resources/eml/spamMailNoHeaders.json @@ -0,0 +1,45 @@ +{ + "messageId":"184", + "threadId": "184", + "uid":25, + "mailboxId": "18", + "modSeq": 42, + "size": 25, + "date": "2015-06-07T00:00:00+0200", + "saveDate": null, + "mediaType": "plain", + "subtype": "text", + "mimeMessageID": "<vass-izaxqm...@spam.minet.net>", + "userFlags": [], + "headers": [], + "from": [ + { + "name": "Content-filter at spam.minet.net", + "address": "postmas...@minet.net", + "domain": "minet" + } + ], + "to": [ + { + "name": null, + "address": "r...@listes.minet.net", + "domain": "listes.minet" + } + ], + "cc": [], + "bcc": [], + "subject": [ + "[root] UNCHECKED contents in mail FROM <quenti...@riseup.net>" + ], + "sentDate": "2015-06-03T09:05:46+0000", + "attachments": [], + "textBody": "No viruses were found.\r\n\r\nContent type: Unchecked\r\nInternal reference code for the message is 12583-16/Ss-IZaXqmZao\r\n\r\nAccording to a 'Received:' trace, the message apparently originated at:\r\n [198.252.153.129], [127.0.0.1] localhost [127.0.0.1] Authenticated sender:\r\n quentin.h\r\n\r\nReturn-Path: <quenti...@riseup.net>\r\nFrom: Quentin <quenti...@riseup.net>\r\nMessage-ID: <556ec361.6000...@riseup.net>\r\nSubject: =?UTF-8?B?UmU6IEZ3ZDogW1RtcGxhYl0gW0FQUEV [...] + "htmlBody": null, + "isAnswered": false, + "isDeleted": false, + "isDraft": false, + "isFlagged": false, + "isRecent": false, + "hasAttachment": false, + "isUnread": true +} diff --git a/mpt/impl/imap-mailbox/opensearch/src/test/java/org/apache/james/mpt/imapmailbox/elasticsearch/host/OpenSearchHostSystem.java b/mpt/impl/imap-mailbox/opensearch/src/test/java/org/apache/james/mpt/imapmailbox/elasticsearch/host/OpenSearchHostSystem.java index a8dcfcf86b..9808814988 100644 --- a/mpt/impl/imap-mailbox/opensearch/src/test/java/org/apache/james/mpt/imapmailbox/elasticsearch/host/OpenSearchHostSystem.java +++ b/mpt/impl/imap-mailbox/opensearch/src/test/java/org/apache/james/mpt/imapmailbox/elasticsearch/host/OpenSearchHostSystem.java @@ -38,6 +38,7 @@ import org.apache.james.mailbox.MailboxManager; import org.apache.james.mailbox.inmemory.InMemoryMessageId; import org.apache.james.mailbox.inmemory.manager.InMemoryIntegrationResources; import org.apache.james.mailbox.opensearch.IndexAttachments; +import org.apache.james.mailbox.opensearch.IndexHeaders; import org.apache.james.mailbox.opensearch.MailboxIdRoutingKeyFactory; import org.apache.james.mailbox.opensearch.MailboxIndexCreationUtil; import org.apache.james.mailbox.opensearch.MailboxOpenSearchConstants; @@ -103,7 +104,7 @@ public class OpenSearchHostSystem extends JamesImapHostSystem { MailboxOpenSearchConstants.DEFAULT_MAILBOX_WRITE_ALIAS), new OpenSearchSearcher(client, new QueryConverter(new CriterionConverter()), OpenSearchSearcher.DEFAULT_SEARCH_SIZE, MailboxOpenSearchConstants.DEFAULT_MAILBOX_READ_ALIAS, routingKeyFactory), - new MessageToOpenSearchJson(new DefaultTextExtractor(), ZoneId.of("Europe/Paris"), IndexAttachments.YES), + new MessageToOpenSearchJson(new DefaultTextExtractor(), ZoneId.of("Europe/Paris"), IndexAttachments.YES, IndexHeaders.YES), preInstanciationStage.getSessionProvider(), routingKeyFactory, messageIdFactory)) .noPreDeletionHooks() .storeQuotaManager() diff --git a/server/apps/distributed-app/docs/modules/ROOT/pages/configure/opensearch.adoc b/server/apps/distributed-app/docs/modules/ROOT/pages/configure/opensearch.adoc index 80ddd1260e..85b289e8c8 100644 --- a/server/apps/distributed-app/docs/modules/ROOT/pages/configure/opensearch.adoc +++ b/server/apps/distributed-app/docs/modules/ROOT/pages/configure/opensearch.adoc @@ -85,6 +85,12 @@ The target of the alias is the index name configured above. | opensearch.indexAttachments | Indicates if you wish to index attachments or not (default: true). + +| opensearch.indexHeaders +| Indicates if you wish to index headers or not (default: true). Note that specific headers +(From, To, Cc, Bcc, Subject, Message-Id, Date, Content-Type) are still indexed in their dedicated type. +Header indexing is expensive as each header currently need to be stored as a nested document but +turning off headers indexing result in non-strict compliance with the IMAP / JMAP standards. |=== === Quota search diff --git a/server/container/guice/opensearch/src/main/java/org/apache/james/modules/mailbox/OpenSearchMailboxModule.java b/server/container/guice/opensearch/src/main/java/org/apache/james/modules/mailbox/OpenSearchMailboxModule.java index 6f7e90bd04..c7aaa8e772 100644 --- a/server/container/guice/opensearch/src/main/java/org/apache/james/modules/mailbox/OpenSearchMailboxModule.java +++ b/server/container/guice/opensearch/src/main/java/org/apache/james/modules/mailbox/OpenSearchMailboxModule.java @@ -39,6 +39,7 @@ import org.apache.james.lifecycle.api.StartUpCheck; import org.apache.james.lifecycle.api.Startable; import org.apache.james.mailbox.model.MailboxId; import org.apache.james.mailbox.opensearch.IndexAttachments; +import org.apache.james.mailbox.opensearch.IndexHeaders; import org.apache.james.mailbox.opensearch.MailboxIdRoutingKeyFactory; import org.apache.james.mailbox.opensearch.MailboxIndexCreationUtil; import org.apache.james.mailbox.opensearch.MailboxOpenSearchConstants; @@ -180,11 +181,16 @@ public class OpenSearchMailboxModule extends AbstractModule { return configuration.getIndexAttachment(); } + @Provides + @Singleton + public IndexHeaders provideIndexHeaders(OpenSearchMailboxConfiguration configuration) { + return configuration.getIndexHeaders(); + } + @ProvidesIntoSet InitializationOperation createIndex(MailboxIndexCreator instance) { return InitilizationOperationBuilder .forClass(MailboxIndexCreator.class) .init(instance::createIndex); } - } diff --git a/server/protocols/webadmin/webadmin-mailbox/src/test/java/org/apache/james/webadmin/routes/MailboxesRoutesTest.java b/server/protocols/webadmin/webadmin-mailbox/src/test/java/org/apache/james/webadmin/routes/MailboxesRoutesTest.java index d78b2899cd..376271045d 100644 --- a/server/protocols/webadmin/webadmin-mailbox/src/test/java/org/apache/james/webadmin/routes/MailboxesRoutesTest.java +++ b/server/protocols/webadmin/webadmin-mailbox/src/test/java/org/apache/james/webadmin/routes/MailboxesRoutesTest.java @@ -67,6 +67,7 @@ import org.apache.james.mailbox.model.MessageResult; import org.apache.james.mailbox.model.ThreadId; import org.apache.james.mailbox.model.UpdatedFlags; import org.apache.james.mailbox.opensearch.IndexAttachments; +import org.apache.james.mailbox.opensearch.IndexHeaders; import org.apache.james.mailbox.opensearch.MailboxIdRoutingKeyFactory; import org.apache.james.mailbox.opensearch.MailboxIndexCreationUtil; import org.apache.james.mailbox.opensearch.MailboxOpenSearchConstants; @@ -161,7 +162,7 @@ class MailboxesRoutesTest { MailboxOpenSearchConstants.DEFAULT_MAILBOX_WRITE_ALIAS), new OpenSearchSearcher(client, new QueryConverter(new CriterionConverter()), SEARCH_SIZE, MailboxOpenSearchConstants.DEFAULT_MAILBOX_READ_ALIAS, routingKeyFactory), - new MessageToOpenSearchJson(new DefaultTextExtractor(), ZoneId.of("Europe/Paris"), IndexAttachments.YES), + new MessageToOpenSearchJson(new DefaultTextExtractor(), ZoneId.of("Europe/Paris"), IndexAttachments.YES, IndexHeaders.YES), preInstanciationStage.getSessionProvider(), routingKeyFactory, messageIdFactory)) .noPreDeletionHooks() .storeQuotaManager() diff --git a/server/protocols/webadmin/webadmin-mailbox/src/test/java/org/apache/james/webadmin/routes/UserMailboxesRoutesTest.java b/server/protocols/webadmin/webadmin-mailbox/src/test/java/org/apache/james/webadmin/routes/UserMailboxesRoutesTest.java index 9a818bc828..3fa93a7d3e 100644 --- a/server/protocols/webadmin/webadmin-mailbox/src/test/java/org/apache/james/webadmin/routes/UserMailboxesRoutesTest.java +++ b/server/protocols/webadmin/webadmin-mailbox/src/test/java/org/apache/james/webadmin/routes/UserMailboxesRoutesTest.java @@ -90,6 +90,7 @@ import org.apache.james.mailbox.model.UidValidity; import org.apache.james.mailbox.model.UpdatedFlags; import org.apache.james.mailbox.model.search.MailboxQuery; import org.apache.james.mailbox.opensearch.IndexAttachments; +import org.apache.james.mailbox.opensearch.IndexHeaders; import org.apache.james.mailbox.opensearch.MailboxIdRoutingKeyFactory; import org.apache.james.mailbox.opensearch.MailboxIndexCreationUtil; import org.apache.james.mailbox.opensearch.MailboxOpenSearchConstants; @@ -1479,7 +1480,7 @@ class UserMailboxesRoutesTest { MailboxOpenSearchConstants.DEFAULT_MAILBOX_WRITE_ALIAS), new OpenSearchSearcher(client, new QueryConverter(new CriterionConverter()), SEARCH_SIZE, MailboxOpenSearchConstants.DEFAULT_MAILBOX_READ_ALIAS, routingKeyFactory), - new MessageToOpenSearchJson(new DefaultTextExtractor(), ZoneId.of("Europe/Paris"), IndexAttachments.YES), + new MessageToOpenSearchJson(new DefaultTextExtractor(), ZoneId.of("Europe/Paris"), IndexAttachments.YES, IndexHeaders.YES), preInstanciationStage.getSessionProvider(), routingKeyFactory, messageIdFactory)) .noPreDeletionHooks() .storeQuotaManager() diff --git a/src/site/xdoc/server/config-opensearch.xml b/src/site/xdoc/server/config-opensearch.xml index 09dedf2aac..bea64dc242 100644 --- a/src/site/xdoc/server/config-opensearch.xml +++ b/src/site/xdoc/server/config-opensearch.xml @@ -113,6 +113,11 @@ <dd>Minimum delay between connection attempts</dd> <dt><strong>opensearch.indexAttachments</strong></dt> <dd>Indicates if you wish to index attachments or not (default: true).</dd> + <dt><strong>opensearch.indexHeaders</strong></dt> + <dd>Indicates if you wish to index headers or not (default: true). Note that specific headers + (From, To, Cc, Bcc, Subject, Message-Id, Date, Content-Type) are still indexed in their dedicated type. + Header indexing is expensive as each header currently need to be stored as a nested document but + turning off headers indexing result in non-strict compliance with the IMAP / JMAP standards.</dd> <dt><strong>opensearch.index.quota.ratio.name</strong></dt> <dd>Specify the OpenSearch alias name used for quotas</dd> <dt><strong>opensearch.alias.read.quota.ratio.name</strong></dt> --------------------------------------------------------------------- To unsubscribe, e-mail: notifications-unsubscr...@james.apache.org For additional commands, e-mail: notifications-h...@james.apache.org