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 2628a5b62e JAMES-4086 Mailet for folding long lines (#2490) 2628a5b62e is described below commit 2628a5b62e23b89d5a4d6e1bee356f28e6c71f57 Author: hungphan227 <45198168+hungphan...@users.noreply.github.com> AuthorDate: Mon Nov 11 17:35:29 2024 +0700 JAMES-4086 Mailet for folding long lines (#2490) --- docs/modules/servers/partials/FoldLongLines.adoc | 7 + .../james/transport/mailets/FoldLongLines.java | 107 ++++++++++++ .../apache/james/transport/mailets/MimeUtil.java | 80 +++++++++ .../james/transport/mailets/FoldLongLinesTest.java | 185 +++++++++++++++++++++ .../apache/james/mailets/DKIMIntegrationTest.java | 71 +++++++- 5 files changed, 449 insertions(+), 1 deletion(-) diff --git a/docs/modules/servers/partials/FoldLongLines.adoc b/docs/modules/servers/partials/FoldLongLines.adoc new file mode 100644 index 0000000000..0b913d756f --- /dev/null +++ b/docs/modules/servers/partials/FoldLongLines.adoc @@ -0,0 +1,7 @@ +=== FoldLongLines + +This mailet fold (wrap) any header lines of the mail that exceed the maximum number of characters. This sanitizing of EML message will prevent downstream server from applying it, and prevent them to break the DKIM signature positioned by James. + +It takes only one parameter: + +* maxCharacters: maximum number of characters. Default to 998 (This line limit is defined in RFC5322). diff --git a/mailet/standard/src/main/java/org/apache/james/transport/mailets/FoldLongLines.java b/mailet/standard/src/main/java/org/apache/james/transport/mailets/FoldLongLines.java new file mode 100644 index 0000000000..01608c9454 --- /dev/null +++ b/mailet/standard/src/main/java/org/apache/james/transport/mailets/FoldLongLines.java @@ -0,0 +1,107 @@ +/**************************************************************** + * 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.transport.mailets; + +import java.util.List; +import java.util.Set; + +import jakarta.mail.Header; +import jakarta.mail.MessagingException; + +import org.apache.commons.lang3.stream.Streams; +import org.apache.mailet.Mail; +import org.apache.mailet.base.GenericMailet; + +import com.github.fge.lambdas.Throwing; +import com.google.common.base.Preconditions; +import com.google.common.base.Splitter; +import com.google.common.collect.ImmutableSet; + +/** + * This mailet fold (wrap) any header lines of the mail that exceed the maximum number of characters. + * <br /> + * It takes only one parameter: + * <ul> + * <li>maxCharacters: maximum number of characters. Default to 998. + * </ul> + */ +public class FoldLongLines extends GenericMailet { + public static final String MAX_CHARACTERS_PARAMETER_NAME = "maxCharacters"; + public static final String HEADER_SEPARATOR = ": "; + + private static final int DEFAULT_MAX_CHARACTERS = 998; + private static final String SEPARATOR = "\n"; + + private int maxCharacters; + + @Override + public void init() throws MessagingException { + int maxCharacters = getInitParameterAsOptional(MAX_CHARACTERS_PARAMETER_NAME).map(Integer::parseInt).orElse(DEFAULT_MAX_CHARACTERS); + Preconditions.checkArgument(maxCharacters > 0, "maxCharacters must be positive"); + this.maxCharacters = maxCharacters; + } + + @Override + public void service(Mail mail) throws MessagingException { + Set<String> longHeaders = getHeadersExceedingMaxCharacters(mail); + + if (!longHeaders.isEmpty()) { + List<Header> headers = getHeadersWithTheSameNameAsLongHeaders(mail, longHeaders); + + // remove all long headers (as well as headers with same name) + longHeaders.forEach(Throwing.consumer(header -> mail.getMessage().removeHeader(header))); + + headers.forEach(Throwing.consumer(header -> { + if (exceedLineLimit(header)) { + mail.getMessage().addHeader(header.getName(), fold(header)); + } else { + mail.getMessage().addHeader(header.getName(), header.getValue()); + } + })); + mail.getMessage().saveChanges(); + } + } + + private Set<String> getHeadersExceedingMaxCharacters(Mail mail) throws MessagingException { + return Streams.of(mail.getMessage().getAllHeaders().asIterator()) + .filter(this::exceedLineLimit) + .map(Header::getName) + .collect(ImmutableSet.toImmutableSet()); + } + + private List<Header> getHeadersWithTheSameNameAsLongHeaders(Mail mail, Set<String> longHeaders) throws MessagingException { + return Streams.of(mail.getMessage().getAllHeaders().asIterator()) + .filter(header -> longHeaders.contains(header.getName())) + .toList(); + } + + private String fold(Header header) { + int headerNameLength = header.getName().length() + HEADER_SEPARATOR.length(); + // TODO After new release of mime4j with commit https://github.com/apache/james-mime4j/commit/66a09219457854c7a26e5b7c0e4c9dd59b4b0c32, update to use MimeUtil of mime4j and remove MimeUtil class file + return MimeUtil.fold(header.getValue(), headerNameLength, maxCharacters); + } + + private boolean exceedLineLimit(Header header) { + String fullHeader = header.getName() + HEADER_SEPARATOR + header.getValue(); + return Splitter.on(SEPARATOR) + .splitToStream(fullHeader) + .anyMatch(line -> line.length() > maxCharacters); + } +} \ No newline at end of file diff --git a/mailet/standard/src/main/java/org/apache/james/transport/mailets/MimeUtil.java b/mailet/standard/src/main/java/org/apache/james/transport/mailets/MimeUtil.java new file mode 100644 index 0000000000..ef6213a57d --- /dev/null +++ b/mailet/standard/src/main/java/org/apache/james/transport/mailets/MimeUtil.java @@ -0,0 +1,80 @@ +/**************************************************************** + * 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.transport.mailets; + +// TODO After new release of mime4j with commit https://github.com/apache/james-mime4j/commit/66a09219457854c7a26e5b7c0e4c9dd59b4b0c32, remove this class +public class MimeUtil { + /** + * Splits the specified string into a multiple-line representation with + * lines no longer than the maximum number of characters (because the line might contain + * encoded words; see <a href='http://www.faqs.org/rfcs/rfc2047.html'>RFC + * 2047</a> section 2). If the string contains non-whitespace sequences + * longer than the maximum number of characters a line break is inserted at the whitespace + * character following the sequence resulting in a line longer than the maximum number of + * characters. + * + * @param s + * string to split. + * @param usedCharacters + * number of characters already used up. Usually the number of + * characters for header field name plus colon and one space. + * @param maxCharacters + * maximum number of characters + * @return a multiple-line representation of the given string. + */ + public static String fold(String s, int usedCharacters, int maxCharacters) { + final int length = s.length(); + if (usedCharacters + length <= maxCharacters) { + return s; + } + + StringBuilder sb = new StringBuilder(); + + int lastLineBreak = -usedCharacters; + int wspIdx = indexOfWsp(s, 0); + while (true) { + if (wspIdx == length) { + sb.append(s.substring(Math.max(0, lastLineBreak))); + return sb.toString(); + } + + int nextWspIdx = indexOfWsp(s, wspIdx + 1); + + if (nextWspIdx - lastLineBreak > maxCharacters) { + sb.append(s, Math.max(0, lastLineBreak), wspIdx); + sb.append("\r\n"); + lastLineBreak = wspIdx; + } + + wspIdx = nextWspIdx; + } + } + + private static int indexOfWsp(String s, int fromIndex) { + final int len = s.length(); + for (int index = fromIndex; index < len; index++) { + char c = s.charAt(index); + if (c == ' ' || c == '\t') { + return index; + } + } + return len; + } +} diff --git a/mailet/standard/src/test/java/org/apache/james/transport/mailets/FoldLongLinesTest.java b/mailet/standard/src/test/java/org/apache/james/transport/mailets/FoldLongLinesTest.java new file mode 100644 index 0000000000..37a15f59b6 --- /dev/null +++ b/mailet/standard/src/test/java/org/apache/james/transport/mailets/FoldLongLinesTest.java @@ -0,0 +1,185 @@ +/**************************************************************** + * 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.transport.mailets; + +import static org.apache.james.transport.mailets.FoldLongLines.HEADER_SEPARATOR; +import static org.apache.james.transport.mailets.FoldLongLines.MAX_CHARACTERS_PARAMETER_NAME; +import static org.assertj.core.api.Assertions.assertThat; + +import java.util.List; + +import jakarta.mail.Header; +import jakarta.mail.MessagingException; + +import org.apache.commons.lang3.stream.Streams; +import org.apache.james.core.builder.MimeMessageBuilder; +import org.apache.mailet.Mail; +import org.apache.mailet.Mailet; +import org.apache.mailet.MailetContext; +import org.apache.mailet.base.test.FakeMail; +import org.apache.mailet.base.test.FakeMailContext; +import org.apache.mailet.base.test.FakeMailetConfig; +import org.assertj.core.api.SoftAssertions; +import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.Test; + +public class FoldLongLinesTest { + static final String HEADER_NAME = "References"; + static final String HEADER_VALUE = "<a1@gmailcom> <a2@gmailcom> <a3@gmailcom>"; + static final String FOLDED_LINE = "<a1@gmailcom> <a2@gmailcom>\r\n" + + " <a3@gmailcom>"; + + private Mailet foldMailet; + private MailetContext mailetContext; + + @BeforeEach + void beforeEach() { + foldMailet = new FoldLongLines(); + mailetContext = FakeMailContext.defaultContext(); + } + + @Test + void serviceShouldFoldLinesWhenTheyExceedMaxCharacters() throws MessagingException { + FakeMailetConfig mailetConfig = FakeMailetConfig.builder() + .mailetName("Test") + .mailetContext(mailetContext) + .setProperty(MAX_CHARACTERS_PARAMETER_NAME, String.valueOf(HEADER_NAME.length() + HEADER_SEPARATOR.length() + HEADER_VALUE.length() - 1)) + .build(); + foldMailet.init(mailetConfig); + + Mail mail = FakeMail.builder() + .name("mail").mimeMessage(MimeMessageBuilder.mimeMessageBuilder().addHeader(HEADER_NAME, HEADER_VALUE).build()) + .build(); + foldMailet.service(mail); + + List<Header> headers = Streams.of(mail.getMessage().getAllHeaders()).filter(header -> header.getName().equals(HEADER_NAME)).toList(); + assertThat(headers).hasSize(1); + assertThat(headers.getFirst().getValue()).isEqualTo(FOLDED_LINE); + } + + @Test + void serviceShouldFoldLinesWhenTheyExceedMaxCharactersAndTheHeaderHasMultiLines() throws MessagingException { + FakeMailetConfig mailetConfig = FakeMailetConfig.builder() + .mailetName("Test") + .mailetContext(mailetContext) + .setProperty(MAX_CHARACTERS_PARAMETER_NAME, "30") + .build(); + foldMailet.init(mailetConfig); + + Mail mail = FakeMail.builder() + .name("mail").mimeMessage(MimeMessageBuilder.mimeMessageBuilder().addHeader(HEADER_NAME, "<a1@gmailcom>\n<a2@gmailcom> <a3@gmailcom> <a4@gmailcom>").build()) + .build(); + foldMailet.service(mail); + + List<Header> headers = Streams.of(mail.getMessage().getAllHeaders()).filter(header -> header.getName().equals(HEADER_NAME)).toList(); + assertThat(headers).hasSize(1); + assertThat(headers.getFirst().getValue()).isEqualTo("<a1@gmailcom>\n" + + "<a2@gmailcom>\r\n" + + " <a3@gmailcom> <a4@gmailcom>"); + } + + @Test + void serviceShouldNotFoldLinesWhenTheyDoNotExceedMaxCharacters() throws MessagingException { + FakeMailetConfig mailetConfig = FakeMailetConfig.builder() + .mailetName("Test") + .mailetContext(mailetContext) + .setProperty(MAX_CHARACTERS_PARAMETER_NAME, "60") + .build(); + foldMailet.init(mailetConfig); + + Mail mail = FakeMail.builder() + .name("mail").mimeMessage(MimeMessageBuilder.mimeMessageBuilder().addHeader(HEADER_NAME, HEADER_VALUE).build()) + .build(); + foldMailet.service(mail); + + List<Header> headers = Streams.of(mail.getMessage().getAllHeaders()).filter(header -> header.getName().equals(HEADER_NAME)).toList(); + assertThat(headers).hasSize(1); + assertThat(headers.getFirst().getValue()).isEqualTo(HEADER_VALUE); + } + + @Test + void serviceShouldNotFoldLinesWhenTheirLengthEqualToMaxCharacters() throws MessagingException { + FakeMailetConfig mailetConfig = FakeMailetConfig.builder() + .mailetName("Test") + .mailetContext(mailetContext) + .setProperty(MAX_CHARACTERS_PARAMETER_NAME, String.valueOf(HEADER_NAME.length() + HEADER_SEPARATOR.length() + HEADER_VALUE.length())) + .build(); + foldMailet.init(mailetConfig); + + Mail mail = FakeMail.builder() + .name("mail").mimeMessage(MimeMessageBuilder.mimeMessageBuilder().addHeader(HEADER_NAME, HEADER_VALUE).build()) + .build(); + foldMailet.service(mail); + + List<Header> headers = Streams.of(mail.getMessage().getAllHeaders()).filter(header -> header.getName().equals(HEADER_NAME)).toList(); + assertThat(headers).hasSize(1); + assertThat(headers.getFirst().getValue()).isEqualTo(HEADER_VALUE); + } + + @Test + void serviceShouldNotRemoveTheHeaderThatHasTheSameNameAsHeadersWithLongLine() throws Exception { + FakeMailetConfig mailetConfig = FakeMailetConfig.builder() + .mailetName("Test") + .mailetContext(mailetContext) + .setProperty(MAX_CHARACTERS_PARAMETER_NAME, "40") + .build(); + foldMailet.init(mailetConfig); + + Mail mail = FakeMail.builder() + .name("mail").mimeMessage(MimeMessageBuilder.mimeMessageBuilder() + .addHeader(HEADER_NAME, "<b1@gmailcom>") + .addHeader(HEADER_NAME, HEADER_VALUE) + .build() + ) + .build(); + foldMailet.service(mail); + + List<Header> headers = Streams.of(mail.getMessage().getAllHeaders()).filter(header -> header.getName().equals(HEADER_NAME)).toList(); + assertThat(headers).hasSize(2); + SoftAssertions.assertSoftly(softly -> { + assertThat(headers.getFirst().getValue()).isEqualTo("<b1@gmailcom>"); + assertThat(headers.getLast().getValue()).isEqualTo(FOLDED_LINE); + }); + } + + @Test + void serviceShouldNotChangeTheRelativePositionOfTheHeaderThatHasTheSameNameAsHeadersWithLongLine() throws Exception { + FakeMailetConfig mailetConfig = FakeMailetConfig.builder() + .mailetName("Test") + .mailetContext(mailetContext) + .setProperty(MAX_CHARACTERS_PARAMETER_NAME, "30") + .build(); + foldMailet.init(mailetConfig); + + Mail mail = FakeMail.builder() + .name("mail").mimeMessage(MimeMessageBuilder.mimeMessageBuilder() + .addHeader(HEADER_NAME, HEADER_VALUE) + .addHeader(HEADER_NAME, "<b1@gmailcom>") + .addHeader(HEADER_NAME, HEADER_VALUE) + .build() + ) + .build(); + foldMailet.service(mail); + + List<Header> headers = Streams.of(mail.getMessage().getAllHeaders()).filter(header -> header.getName().equals(HEADER_NAME)).toList(); + assertThat(headers).hasSize(3); + assertThat(headers.get(1).getValue()).isEqualTo("<b1@gmailcom>"); + } +} diff --git a/server/mailet/integration-testing/src/test/java/org/apache/james/mailets/DKIMIntegrationTest.java b/server/mailet/integration-testing/src/test/java/org/apache/james/mailets/DKIMIntegrationTest.java index 26d098b93e..920d6d78b2 100644 --- a/server/mailet/integration-testing/src/test/java/org/apache/james/mailets/DKIMIntegrationTest.java +++ b/server/mailet/integration-testing/src/test/java/org/apache/james/mailets/DKIMIntegrationTest.java @@ -23,6 +23,7 @@ import static org.apache.james.mailets.configuration.Constants.DEFAULT_DOMAIN; import static org.apache.james.mailets.configuration.Constants.LOCALHOST_IP; import static org.apache.james.mailets.configuration.Constants.PASSWORD; import static org.apache.james.mailets.configuration.Constants.awaitAtMostOneMinute; +import static org.apache.james.transport.mailets.FoldLongLines.MAX_CHARACTERS_PARAMETER_NAME; import static org.assertj.core.api.Assertions.assertThat; import java.io.File; @@ -43,6 +44,7 @@ import org.apache.james.modules.protocols.ImapGuiceProbe; import org.apache.james.modules.protocols.SmtpGuiceProbe; import org.apache.james.probe.DataProbe; import org.apache.james.transport.mailets.ExtractAttributeStub; +import org.apache.james.transport.mailets.FoldLongLines; import org.apache.james.transport.matchers.All; import org.apache.james.utils.DataProbeImpl; import org.apache.james.utils.SMTPMessageSender; @@ -100,6 +102,12 @@ class DKIMIntegrationTest { .addProperty("attributeName", DKIMVerify.DKIM_AUTH_RESULT.asString()) .build(); + private static final MailetConfiguration FOLD_LONG_LINES_MAILET = MailetConfiguration.builder() + .matcher(All.class) + .mailet(FoldLongLines.class) + .addProperty(MAX_CHARACTERS_PARAMETER_NAME, "78") + .build(); + private static final PublicKeyRecordRetriever MOCK_PUBLIC_KEY_RECORD_RETRIEVER = new MockPublicKeyRecordRetriever( "v=DKIM1; k=rsa; p=MIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQDYDaYKXzwVYwqWbLhmuJ66aTAN8wmDR+rfHE8HfnkSOax0oIoTM5zquZrTLo30870YMfYzxwfB6j/Nz3QdwrUD/t0YMYJiUKyWJnCKfZXHJBJ+yfRHr7oW+UW3cVo9CG2bBfIxsInwYe175g9UjyntJpWueqdEIo1c2bhv9Mp66QIDAQAB;", "selector", "example.com"); @@ -231,13 +239,64 @@ class DKIMIntegrationTest { .hasValueSatisfying(result -> assertThat(result).startsWith("fail")); } - private void initJamesServer(File temporaryFolder, Module... overrideGuiceModules) throws Exception { + @Test + void incomingMessageShouldPassDKIMVerificationWhenLongHeadersAreFoldedBeforeSigning(@TempDir File temporaryFolder) throws Exception { MailetContainer.Builder mailetContainer = TemporaryJamesServer.simpleMailetContainerConfiguration() .putProcessor(ProcessorConfiguration.transport() + .addMailet(FOLD_LONG_LINES_MAILET) .addMailet(DKIMSIGN_MAILET) .addMailet(DKIMVERIFY_MAILET) .addMailet(STUB_MAILET) .addMailetsFrom(CommonProcessors.transport())); + initJamesServer(mailetContainer, temporaryFolder, binder -> binder.bind(PublicKeyRecordRetriever.class).toInstance(MOCK_PUBLIC_KEY_RECORD_RETRIEVER)); + + messageSender.connect(LOCALHOST_IP, jamesServer.getProbe(SmtpGuiceProbe.class).getSmtpPort()) + .authenticate(FROM, PASSWORD) + .sendMessageWithHeaders(FROM, ImmutableList.of(RECIPIENT), "Return-Path: <btell...@linagora.com>\n" + + "Content-Type: multipart/mixed; boundary=\"------------dsVZbfyUhMRjfuWnqQ80tHvc\"\n" + + "Message-ID: <a7a376a1-cadb-45bc-9deb-39f749f62...@linagora.com>\n" + + "Date: Tue, 7 Nov 2023 12:14:47 +0100\n" + + "MIME-Version: 1.0\n" + + "User-Agent: Mozilla Thunderbird\n" + + "Content-Language: en-US\n" + + "To: btell...@linagora.com\n" + + "From: \"btell...@linagora.com\" <btell...@linagora.com>\n" + + "References: <a...@gmail.com> <a...@gmail.com> <a...@gmail.com> <a...@gmail.com> <a...@gmail.com> <a...@gmail.com> <a...@gmail.com> <a...@gmail.com>\n" + + "Subject: Simple message\n" + + "\n" + + "This is a multi-part message in MIME format.\n" + + "--------------dsVZbfyUhMRjfuWnqQ80tHvc\n" + + "Content-Type: text/plain; charset=UTF-8; format=flowed\n" + + "Content-Transfer-Encoding: 7bit\n" + + "\n" + + "Simple body\n" + + "\n" + + "--------------dsVZbfyUhMRjfuWnqQ80tHvc\n" + + "Content-Type: message/rfc822; name=\"BNPP ADVICE LOLO.eml\"\n" + + "Content-Disposition: attachment; filename=\"BNPP.eml\"\n" + + "\n" + + "\n" + + "--------------dsVZbfyUhMRjfuWnqQ80tHvc--"); + + testIMAPClient.connect(LOCALHOST_IP, jamesServer.getProbe(ImapGuiceProbe.class).getImapPort()) + .login(RECIPIENT, PASSWORD) + .select(TestIMAPClient.INBOX) + .awaitMessage(awaitAtMostOneMinute); + + assertThat(dkimAuthResults) + .hasSize(1); + assertThat(dkimAuthResults.get(0)) + .hasValueSatisfying(result -> assertThat(result).startsWith("pass")); + + assertThat(testIMAPClient.readFirstMessageHeaders()) + .contains("DKIM-Signature"); + + assertThat(testIMAPClient.readFirstMessageHeaders()) + .contains("References: <a...@gmail.com> <a...@gmail.com> <a...@gmail.com> <a...@gmail.com>\r\n" + + " <a...@gmail.com> <a...@gmail.com> <a...@gmail.com> <a...@gmail.com>"); + } + + private void initJamesServer(MailetContainer.Builder mailetContainer, File temporaryFolder, Module... overrideGuiceModules) throws Exception { jamesServer = TemporaryJamesServer .builder() .withBase(MemoryJamesServerMain.IN_MEMORY_SERVER_AGGREGATE_MODULE) @@ -251,4 +310,14 @@ class DKIMIntegrationTest { dataProbe.addUser(RECIPIENT, PASSWORD); dataProbe.addUser(FROM, PASSWORD); } + + private void initJamesServer(File temporaryFolder, Module... overrideGuiceModules) throws Exception { + MailetContainer.Builder mailetContainer = TemporaryJamesServer.simpleMailetContainerConfiguration() + .putProcessor(ProcessorConfiguration.transport() + .addMailet(DKIMSIGN_MAILET) + .addMailet(DKIMVERIFY_MAILET) + .addMailet(STUB_MAILET) + .addMailetsFrom(CommonProcessors.transport())); + initJamesServer(mailetContainer, temporaryFolder, overrideGuiceModules); + } } --------------------------------------------------------------------- To unsubscribe, e-mail: notifications-unsubscr...@james.apache.org For additional commands, e-mail: notifications-h...@james.apache.org