JAMES-1717 Implement a JMAP vacation mailet
Project: http://git-wip-us.apache.org/repos/asf/james-project/repo Commit: http://git-wip-us.apache.org/repos/asf/james-project/commit/3ecc0cc5 Tree: http://git-wip-us.apache.org/repos/asf/james-project/tree/3ecc0cc5 Diff: http://git-wip-us.apache.org/repos/asf/james-project/diff/3ecc0cc5 Branch: refs/heads/master Commit: 3ecc0cc57bc5b46c8d90ec74da7fc5ff9a827cb6 Parents: 661c15e Author: Benoit Tellier <[email protected]> Authored: Fri Apr 8 12:11:42 2016 +0700 Committer: Benoit Tellier <[email protected]> Committed: Fri May 20 18:52:11 2016 +0700 ---------------------------------------------------------------------- .../org/apache/mailet/base/test/FakeMail.java | 42 ++++ .../org/apache/james/jmap/JMAPCommonModule.java | 6 + .../james/jmap/mailet/VacationMailet.java | 104 ++++++++ .../apache/james/jmap/mailet/VacationReply.java | 101 ++++++++ .../james/jmap/mailet/VacationMailetTest.java | 244 +++++++++++++++++++ .../james/jmap/mailet/VacationReplyTest.java | 69 ++++++ .../jmap/src/test/resources/spamMail.eml | 10 +- 7 files changed, 567 insertions(+), 9 deletions(-) ---------------------------------------------------------------------- http://git-wip-us.apache.org/repos/asf/james-project/blob/3ecc0cc5/mailet/base/src/test/java/org/apache/mailet/base/test/FakeMail.java ---------------------------------------------------------------------- diff --git a/mailet/base/src/test/java/org/apache/mailet/base/test/FakeMail.java b/mailet/base/src/test/java/org/apache/mailet/base/test/FakeMail.java index b28a7a2..37295a8 100644 --- a/mailet/base/src/test/java/org/apache/mailet/base/test/FakeMail.java +++ b/mailet/base/src/test/java/org/apache/mailet/base/test/FakeMail.java @@ -26,8 +26,11 @@ import java.util.Collection; import java.util.Date; import java.util.HashMap; import java.util.Iterator; +import java.util.List; +import java.util.Properties; import javax.mail.MessagingException; +import javax.mail.Session; import javax.mail.internet.InternetAddress; import javax.mail.internet.MimeMessage; @@ -36,6 +39,45 @@ import org.apache.mailet.MailAddress; public class FakeMail implements Mail { + public static Builder builder() { + return new Builder(); + } + + public static class Builder { + + private String fileName; + private List<MailAddress> recipients = new ArrayList<MailAddress>(); + private MailAddress sender; + + public Builder fileName(String fileName) { + this.fileName = fileName; + return this; + } + + public Builder recipients(List<MailAddress> recipients) { + this.recipients.addAll(recipients); + return this; + } + + public Builder recipient(MailAddress recipient) { + this.recipients.add(recipient); + return this; + } + + public Builder sender(MailAddress sender) { + this.sender = sender; + return this; + } + + public FakeMail build() throws MessagingException { + FakeMail mail = new FakeMail(); + mail.setMessage(new MimeMessage(Session.getInstance(new Properties()) ,ClassLoader.getSystemResourceAsStream(fileName))); + mail.setSender(sender); + mail.setRecipients(recipients); + return mail; + } + } + private MimeMessage msg = null; private Collection<MailAddress> recipients = new ArrayList<MailAddress>(); http://git-wip-us.apache.org/repos/asf/james-project/blob/3ecc0cc5/server/container/guice/guice-common/src/main/java/org/apache/james/jmap/JMAPCommonModule.java ---------------------------------------------------------------------- diff --git a/server/container/guice/guice-common/src/main/java/org/apache/james/jmap/JMAPCommonModule.java b/server/container/guice/guice-common/src/main/java/org/apache/james/jmap/JMAPCommonModule.java index 405e0d7..9275010 100644 --- a/server/container/guice/guice-common/src/main/java/org/apache/james/jmap/JMAPCommonModule.java +++ b/server/container/guice/guice-common/src/main/java/org/apache/james/jmap/JMAPCommonModule.java @@ -32,10 +32,13 @@ import org.apache.james.jmap.send.MailFactory; import org.apache.james.jmap.send.MailSpool; import org.apache.james.jmap.utils.DefaultZonedDateTimeProvider; import org.apache.james.jmap.utils.ZonedDateTimeProvider; +import org.apache.mailet.base.AutomaticallySentMailDetector; +import org.apache.mailet.base.AutomaticallySentMailDetectorImpl; import com.google.common.collect.ImmutableList; import com.google.inject.AbstractModule; import com.google.inject.Provides; +import com.google.inject.Scopes; import com.google.inject.Singleton; import com.google.inject.name.Names; @@ -54,6 +57,9 @@ public class JMAPCommonModule extends AbstractModule { bind(MailSpool.class).in(Singleton.class); bind(MailFactory.class).in(Singleton.class); + + bind(AutomaticallySentMailDetectorImpl.class).in(Scopes.SINGLETON); + bind(AutomaticallySentMailDetector.class).to(AutomaticallySentMailDetectorImpl.class); } @Provides http://git-wip-us.apache.org/repos/asf/james-project/blob/3ecc0cc5/server/protocols/jmap/src/main/java/org/apache/james/jmap/mailet/VacationMailet.java ---------------------------------------------------------------------- diff --git a/server/protocols/jmap/src/main/java/org/apache/james/jmap/mailet/VacationMailet.java b/server/protocols/jmap/src/main/java/org/apache/james/jmap/mailet/VacationMailet.java new file mode 100644 index 0000000..8e9d181 --- /dev/null +++ b/server/protocols/jmap/src/main/java/org/apache/james/jmap/mailet/VacationMailet.java @@ -0,0 +1,104 @@ +/**************************************************************** + * Licensed to the Apache Software Foundation (ASF) under one * + * or more contributor license agreements. See the NOTICE file * + * distributed with this work for additional information * + * regarding copyright ownership. The ASF licenses this file * + * to you under the Apache License, Version 2.0 (the * + * "License"); you may not use this file except in compliance * + * with the License. You may obtain a copy of the License at * + * * + * http://www.apache.org/licenses/LICENSE-2.0 * + * * + * Unless required by applicable law or agreed to in writing, * + * software distributed under the License is distributed on an * + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY * + * KIND, either express or implied. See the License for the * + * specific language governing permissions and limitations * + * under the License. * + ****************************************************************/ + +package org.apache.james.jmap.mailet; + +import java.time.ZonedDateTime; +import java.util.concurrent.CompletableFuture; + +import javax.inject.Inject; +import javax.mail.MessagingException; + +import org.apache.james.jmap.api.vacation.AccountId; +import org.apache.james.jmap.api.vacation.Vacation; +import org.apache.james.jmap.api.vacation.VacationRepository; +import org.apache.james.jmap.utils.ZonedDateTimeProvider; +import org.apache.mailet.Mail; +import org.apache.mailet.MailAddress; +import org.apache.mailet.base.AutomaticallySentMailDetector; +import org.apache.mailet.base.GenericMailet; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +public class VacationMailet extends GenericMailet { + + private static final Logger LOGGER = LoggerFactory.getLogger(VacationMailet.class); + + private final VacationRepository vacationRepository; + private final ZonedDateTimeProvider zonedDateTimeProvider; + private final AutomaticallySentMailDetector automaticallySentMailDetector; + + @Inject + VacationMailet(VacationRepository vacationRepository, ZonedDateTimeProvider zonedDateTimeProvider, AutomaticallySentMailDetector automaticallySentMailDetector) { + this.vacationRepository = vacationRepository; + this.zonedDateTimeProvider = zonedDateTimeProvider; + this.automaticallySentMailDetector = automaticallySentMailDetector; + } + + @Override + public void service(Mail mail) { + try { + ZonedDateTime processingDate = zonedDateTimeProvider.get(); + mail.getRecipients() + .stream() + .map(mailAddress -> manageVacation(mailAddress, mail, processingDate)) + .forEach(CompletableFuture::join); + } catch (Throwable e) { + LOGGER.warn("Can not process vacation for one or more recipients in {}", mail.getRecipients(), e); + } + } + + public CompletableFuture<Void> manageVacation(MailAddress recipient, Mail processedMail, ZonedDateTime processingDate) { + AccountId accountId = AccountId.fromString(recipient.toString()); + CompletableFuture<Vacation> vacationFuture = vacationRepository.retrieveVacation(accountId); + return vacationFuture.thenAccept(vacation -> { + if (shouldSendNotification(vacation, processedMail, recipient, processingDate)) { + sendNotification(recipient, processedMail, vacation); + } + }); + } + + private boolean shouldSendNotification(Vacation vacation, Mail processedMail, MailAddress recipient, ZonedDateTime processingDate) { + try { + return vacation.isActiveAtDate(processingDate) + && ! automaticallySentMailDetector.isAutomaticallySent(processedMail); + } catch (MessagingException e) { + LOGGER.warn("Failed detect automatic response in a mail from {} to {}", processedMail.getSender(), recipient, e); + return false; + } + } + + private void sendNotification(MailAddress recipient, Mail processedMail, Vacation vacation) { + try { + VacationReply vacationReply = VacationReply.builder(processedMail) + .receivedMailRecipient(recipient) + .reason(vacation.getTextBody()) + .build(); + sendNotification(vacationReply); + } catch (MessagingException e) { + LOGGER.warn("Failed to send JMAP vacation notification from {} to {}", recipient, processedMail.getSender(), e); + } + } + + private void sendNotification(VacationReply vacationReply) throws MessagingException { + getMailetContext().sendMail(vacationReply.getSender(), + vacationReply.getRecipients(), + vacationReply.getMimeMessage()); + } +} http://git-wip-us.apache.org/repos/asf/james-project/blob/3ecc0cc5/server/protocols/jmap/src/main/java/org/apache/james/jmap/mailet/VacationReply.java ---------------------------------------------------------------------- diff --git a/server/protocols/jmap/src/main/java/org/apache/james/jmap/mailet/VacationReply.java b/server/protocols/jmap/src/main/java/org/apache/james/jmap/mailet/VacationReply.java new file mode 100644 index 0000000..bd15641 --- /dev/null +++ b/server/protocols/jmap/src/main/java/org/apache/james/jmap/mailet/VacationReply.java @@ -0,0 +1,101 @@ +/**************************************************************** + * Licensed to the Apache Software Foundation (ASF) under one * + * or more contributor license agreements. See the NOTICE file * + * distributed with this work for additional information * + * regarding copyright ownership. The ASF licenses this file * + * to you under the Apache License, Version 2.0 (the * + * "License"); you may not use this file except in compliance * + * with the License. You may obtain a copy of the License at * + * * + * http://www.apache.org/licenses/LICENSE-2.0 * + * * + * Unless required by applicable law or agreed to in writing, * + * software distributed under the License is distributed on an * + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY * + * KIND, either express or implied. See the License for the * + * specific language governing permissions and limitations * + * under the License. * + ****************************************************************/ + +package org.apache.james.jmap.mailet; + +import java.util.List; + +import javax.mail.MessagingException; +import javax.mail.internet.MimeMessage; + +import org.apache.mailet.Mail; +import org.apache.mailet.MailAddress; + +import com.google.common.base.Preconditions; +import com.google.common.collect.ImmutableList; + +public class VacationReply { + + public static Builder builder(Mail originalMail) { + return new Builder(originalMail); + } + + public static class Builder { + + public static final boolean NOT_REPLY_TO_ALL = false; + private final Mail originalMail; + private MailAddress mailRecipient; + private String reason; + + private Builder(Mail originalMail) { + Preconditions.checkNotNull(originalMail, "Origin mail shall not be null"); + this.originalMail = originalMail; + } + + public Builder receivedMailRecipient(MailAddress mailRecipient) { + Preconditions.checkNotNull(mailRecipient); + this.mailRecipient = mailRecipient; + return this; + } + + public Builder reason(String reason) { + Preconditions.checkNotNull(reason); + this.reason = reason; + return this; + } + + public VacationReply build() throws MessagingException { + Preconditions.checkState(mailRecipient != null, "Original recipient address should not be null"); + Preconditions.checkState(originalMail.getSender() != null, "Original sender address should not be null"); + + return new VacationReply(mailRecipient, ImmutableList.of(originalMail.getSender()), generateMimeMessage()); + } + + private MimeMessage generateMimeMessage() throws MessagingException { + MimeMessage reply = (MimeMessage) originalMail.getMessage().reply(NOT_REPLY_TO_ALL); + reply.setText(reason); + reply.setHeader("from", mailRecipient.toString()); + reply.setHeader("to", originalMail.getSender().toString()); + return reply; + } + } + + private final MailAddress sender; + private final List<MailAddress> recipients; + private final MimeMessage mimeMessage; + + private VacationReply(MailAddress sender, List<MailAddress> recipients, MimeMessage mimeMessage) { + this.sender = sender; + this.recipients = recipients; + this.mimeMessage = mimeMessage; + } + + public MailAddress getSender() { + return sender; + } + + public List<MailAddress> getRecipients() { + return recipients; + } + + public MimeMessage getMimeMessage() { + return mimeMessage; + } +} + http://git-wip-us.apache.org/repos/asf/james-project/blob/3ecc0cc5/server/protocols/jmap/src/test/java/org/apache/james/jmap/mailet/VacationMailetTest.java ---------------------------------------------------------------------- diff --git a/server/protocols/jmap/src/test/java/org/apache/james/jmap/mailet/VacationMailetTest.java b/server/protocols/jmap/src/test/java/org/apache/james/jmap/mailet/VacationMailetTest.java new file mode 100644 index 0000000..ff73594 --- /dev/null +++ b/server/protocols/jmap/src/test/java/org/apache/james/jmap/mailet/VacationMailetTest.java @@ -0,0 +1,244 @@ +/**************************************************************** + * Licensed to the Apache Software Foundation (ASF) under one * + * or more contributor license agreements. See the NOTICE file * + * distributed with this work for additional information * + * regarding copyright ownership. The ASF licenses this file * + * to you under the Apache License, Version 2.0 (the * + * "License"); you may not use this file except in compliance * + * with the License. You may obtain a copy of the License at * + * * + * http://www.apache.org/licenses/LICENSE-2.0 * + * * + * Unless required by applicable law or agreed to in writing, * + * software distributed under the License is distributed on an * + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY * + * KIND, either express or implied. See the License for the * + * specific language governing permissions and limitations * + * under the License. * + ****************************************************************/ + +package org.apache.james.jmap.mailet; + +import static org.mockito.Matchers.any; +import static org.mockito.Matchers.eq; +import static org.mockito.Mockito.doThrow; +import static org.mockito.Mockito.mock; +import static org.mockito.Mockito.verify; +import static org.mockito.Mockito.verifyNoMoreInteractions; +import static org.mockito.Mockito.when; + +import java.time.ZonedDateTime; +import java.util.Optional; +import java.util.concurrent.CompletableFuture; + +import javax.mail.MessagingException; + +import org.apache.james.jmap.api.vacation.AccountId; +import org.apache.james.jmap.api.vacation.Vacation; +import org.apache.james.jmap.api.vacation.VacationRepository; +import org.apache.james.jmap.utils.ZonedDateTimeProvider; +import org.apache.mailet.MailAddress; +import org.apache.mailet.MailetContext; +import org.apache.mailet.base.AutomaticallySentMailDetector; +import org.apache.mailet.base.test.FakeMail; +import org.apache.mailet.base.test.FakeMailetConfig; +import org.junit.Before; +import org.junit.Test; + +import com.google.common.collect.ImmutableList; + +public class VacationMailetTest { + + public static final ZonedDateTime DATE_TIME_2016 = ZonedDateTime.parse("2016-10-09T08:07:06+07:00[Asia/Vientiane]"); + public static final ZonedDateTime DATE_TIME_2017 = ZonedDateTime.parse("2017-10-09T08:07:06+07:00[Asia/Vientiane]"); + public static final ZonedDateTime DATE_TIME_2018 = ZonedDateTime.parse("2018-10-09T08:07:06+07:00[Asia/Vientiane]"); + + public static final String USERNAME = "[email protected]"; + private VacationMailet testee; + private VacationRepository vacationRepository; + private ZonedDateTimeProvider zonedDateTimeProvider; + private MailetContext mailetContext; + private MailAddress originalSender; + private MailAddress originalRecipient; + private AutomaticallySentMailDetector automaticallySentMailDetector; + + @Before + public void setUp() throws Exception { + originalSender = new MailAddress("[email protected]"); + originalRecipient = new MailAddress(USERNAME); + + vacationRepository = mock(VacationRepository.class); + zonedDateTimeProvider = mock(ZonedDateTimeProvider.class); + automaticallySentMailDetector = mock(AutomaticallySentMailDetector.class); + testee = new VacationMailet(vacationRepository, zonedDateTimeProvider, automaticallySentMailDetector); + mailetContext = mock(MailetContext.class); + testee.init(new FakeMailetConfig("vacation", mailetContext)); + } + + @Test + public void unactivatedVacationShouldNotSendNotification() throws Exception { + FakeMail mail = FakeMail.builder() + .fileName("spamMail.eml") + .recipient(originalRecipient) + .sender(new MailAddress("[email protected]")) + .build(); + when(zonedDateTimeProvider.get()).thenReturn(DATE_TIME_2017); + when(vacationRepository.retrieveVacation(AccountId.fromString(USERNAME))) + .thenReturn(CompletableFuture.completedFuture(VacationRepository.DEFAULT_VACATION)); + when(automaticallySentMailDetector.isAutomaticallySent(mail)).thenReturn(false); + + testee.service(mail); + + verifyNoMoreInteractions(mailetContext); + } + + @Test + public void activateVacationShouldSendNotification() throws Exception { + FakeMail mail = FakeMail.builder() + .fileName("spamMail.eml") + .recipient(originalRecipient) + .sender(originalSender) + .build(); + when(vacationRepository.retrieveVacation(AccountId.fromString(USERNAME))) + .thenReturn(CompletableFuture.completedFuture( + Vacation.builder() + .enabled(true) + .fromDate(Optional.of(DATE_TIME_2016)) + .toDate(Optional.of(DATE_TIME_2018)) + .textBody("Explaining my vacation") + .build())); + when(zonedDateTimeProvider.get()).thenReturn(DATE_TIME_2017); + when(automaticallySentMailDetector.isAutomaticallySent(mail)).thenReturn(false); + + testee.service(mail); + + verify(mailetContext).sendMail(eq(originalRecipient), eq(ImmutableList.of(originalSender)), any()); + verifyNoMoreInteractions(mailetContext); + } + + @Test + public void activateVacationShouldNotSendNotificationToMailingList() throws Exception { + FakeMail mail = FakeMail.builder() + .fileName("spamMail.eml") + .recipient(originalRecipient) + .sender(new MailAddress("[email protected]")) + .build(); + when(vacationRepository.retrieveVacation(AccountId.fromString(USERNAME))) + .thenReturn(CompletableFuture.completedFuture( + Vacation.builder() + .enabled(true) + .fromDate(Optional.of(DATE_TIME_2016)) + .toDate(Optional.of(DATE_TIME_2018)) + .textBody("Explaining my vacation") + .build())); + when(zonedDateTimeProvider.get()).thenReturn(DATE_TIME_2017); + when(automaticallySentMailDetector.isAutomaticallySent(mail)).thenReturn(true); + + testee.service(mail); + + verifyNoMoreInteractions(mailetContext); + } + + @Test + public void multipleRecipientShouldGenerateNotifications() throws MessagingException { + String secondUserName = "[email protected]"; + MailAddress secondRecipient = new MailAddress(secondUserName); + FakeMail mail = FakeMail.builder() + .fileName("spamMail.eml") + .recipients(ImmutableList.of(originalRecipient, secondRecipient)) + .sender(originalSender) + .build(); + when(vacationRepository.retrieveVacation(AccountId.fromString(USERNAME))) + .thenReturn(CompletableFuture.completedFuture( + Vacation.builder() + .enabled(true) + .fromDate(Optional.of(DATE_TIME_2016)) + .toDate(Optional.of(DATE_TIME_2018)) + .textBody("Explaining my vacation") + .build())); + when(vacationRepository.retrieveVacation(AccountId.fromString(secondUserName))) + .thenReturn(CompletableFuture.completedFuture( + Vacation.builder() + .enabled(true) + .fromDate(Optional.of(DATE_TIME_2016)) + .toDate(Optional.of(DATE_TIME_2018)) + .textBody("Explaining my vacation") + .build())); + when(zonedDateTimeProvider.get()).thenReturn(DATE_TIME_2017); + when(automaticallySentMailDetector.isAutomaticallySent(mail)).thenReturn(false); + + testee.service(mail); + + verify(mailetContext).sendMail(eq(originalRecipient), eq(ImmutableList.of(originalSender)), any()); + verify(mailetContext).sendMail(eq(secondRecipient), eq(ImmutableList.of(originalSender)), any()); + verifyNoMoreInteractions(mailetContext); + } + + @Test + public void serviceShouldNotSendNotificationUponErrorsRetrievingVacationObject() throws Exception { + FakeMail mail = FakeMail.builder() + .fileName("spamMail.eml") + .recipient(originalRecipient) + .sender(new MailAddress("[email protected]")) + .build(); + when(vacationRepository.retrieveVacation(AccountId.fromString(USERNAME))) + .thenReturn(CompletableFuture.supplyAsync(() -> { + throw new RuntimeException(); + })); + when(zonedDateTimeProvider.get()).thenReturn(DATE_TIME_2017); + when(automaticallySentMailDetector.isAutomaticallySent(mail)).thenReturn(false); + + testee.service(mail); + + verifyNoMoreInteractions(mailetContext); + } + + @Test + public void serviceShouldNotSendNotificationUponErrorsDetectingAutomaticallySentMails() throws Exception { + FakeMail mail = FakeMail.builder() + .fileName("spamMail.eml") + .recipient(originalRecipient) + .sender(originalSender) + .build(); + when(vacationRepository.retrieveVacation(AccountId.fromString(USERNAME))) + .thenReturn(CompletableFuture.completedFuture( + Vacation.builder() + .enabled(true) + .fromDate(Optional.of(DATE_TIME_2016)) + .toDate(Optional.of(DATE_TIME_2018)) + .textBody("Explaining my vacation") + .build())); + when(zonedDateTimeProvider.get()).thenReturn(DATE_TIME_2017); + when(automaticallySentMailDetector.isAutomaticallySent(mail)).thenThrow(new MessagingException()); + + testee.service(mail); + + verifyNoMoreInteractions(mailetContext); + } + + @Test + public void serviceShouldNotPropagateExceptionIfSendFails() throws Exception { + FakeMail mail = FakeMail.builder() + .fileName("spamMail.eml") + .recipient(originalRecipient) + .sender(originalSender) + .build(); + when(vacationRepository.retrieveVacation(AccountId.fromString(USERNAME))) + .thenReturn(CompletableFuture.completedFuture( + Vacation.builder() + .enabled(true) + .fromDate(Optional.of(DATE_TIME_2016)) + .toDate(Optional.of(DATE_TIME_2018)) + .textBody("Explaining my vacation") + .build())); + when(zonedDateTimeProvider.get()).thenReturn(DATE_TIME_2017); + when(automaticallySentMailDetector.isAutomaticallySent(mail)).thenReturn(false); + doThrow(new MessagingException()).when(mailetContext).sendMail(eq(originalSender), eq(ImmutableList.of(originalRecipient)), any()); + + testee.service(mail); + + verify(mailetContext).sendMail(eq(originalRecipient), eq(ImmutableList.of(originalSender)), any()); + verifyNoMoreInteractions(mailetContext); + } + +} http://git-wip-us.apache.org/repos/asf/james-project/blob/3ecc0cc5/server/protocols/jmap/src/test/java/org/apache/james/jmap/mailet/VacationReplyTest.java ---------------------------------------------------------------------- diff --git a/server/protocols/jmap/src/test/java/org/apache/james/jmap/mailet/VacationReplyTest.java b/server/protocols/jmap/src/test/java/org/apache/james/jmap/mailet/VacationReplyTest.java new file mode 100644 index 0000000..64bb6bf --- /dev/null +++ b/server/protocols/jmap/src/test/java/org/apache/james/jmap/mailet/VacationReplyTest.java @@ -0,0 +1,69 @@ +/**************************************************************** + * Licensed to the Apache Software Foundation (ASF) under one * + * or more contributor license agreements. See the NOTICE file * + * distributed with this work for additional information * + * regarding copyright ownership. The ASF licenses this file * + * to you under the Apache License, Version 2.0 (the * + * "License"); you may not use this file except in compliance * + * with the License. You may obtain a copy of the License at * + * * + * http://www.apache.org/licenses/LICENSE-2.0 * + * * + * Unless required by applicable law or agreed to in writing, * + * software distributed under the License is distributed on an * + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY * + * KIND, either express or implied. See the License for the * + * specific language governing permissions and limitations * + * under the License. * + ****************************************************************/ + +package org.apache.james.jmap.mailet; + +import static org.assertj.core.api.Assertions.assertThat; + +import java.util.Properties; + +import javax.mail.Session; +import javax.mail.internet.MimeMessage; + +import org.apache.commons.io.IOUtils; +import org.apache.mailet.MailAddress; +import org.apache.mailet.base.test.FakeMail; +import org.junit.Test; + +public class VacationReplyTest { + + public static final String REASON = "I am in vacation dudes !"; + + @Test + public void vacationReplyShouldGenerateASuitableAnswer() throws Exception { + MailAddress originalSender = new MailAddress("[email protected]"); + MailAddress originalRecipient = new MailAddress("[email protected]"); + FakeMail mail = new FakeMail(); + mail.setMessage(new MimeMessage(Session.getInstance(new Properties()) ,ClassLoader.getSystemResourceAsStream("spamMail.eml"))); + mail.setSender(originalSender); + + VacationReply vacationReply = VacationReply.builder(mail) + .reason(REASON) + .receivedMailRecipient(originalRecipient) + .build(); + + assertThat(vacationReply.getRecipients()).containsExactly(originalSender); + assertThat(vacationReply.getSender()).isEqualTo(originalRecipient); + assertThat(vacationReply.getMimeMessage().getHeader("subject")).containsExactly("Re: Original subject"); + assertThat(IOUtils.toString(vacationReply.getMimeMessage().getInputStream())).contains(REASON); + } + + @Test(expected = NullPointerException.class) + public void vacationReplyShouldThrowOnNullMail() { + VacationReply.builder(null); + } + + @Test(expected = NullPointerException.class) + public void vacationReplyShouldThrowOnNullOriginalEMailAddress() throws Exception { + VacationReply.builder(new FakeMail()) + .receivedMailRecipient(null) + .build(); + } + +} http://git-wip-us.apache.org/repos/asf/james-project/blob/3ecc0cc5/server/protocols/jmap/src/test/resources/spamMail.eml ---------------------------------------------------------------------- diff --git a/server/protocols/jmap/src/test/resources/spamMail.eml b/server/protocols/jmap/src/test/resources/spamMail.eml index 2359ec3..8121d99 100644 --- a/server/protocols/jmap/src/test/resources/spamMail.eml +++ b/server/protocols/jmap/src/test/resources/spamMail.eml @@ -34,17 +34,9 @@ From: "Content-filter at spam.minet.net" <[email protected]> Date: Wed, 3 Jun 2015 09:05:46 +0000 (UTC) To: <[email protected]> Message-ID: <[email protected]> -Subject: [root] UNCHECKED contents in mail FROM <[email protected]> +Subject: Original subject X-BeenThere: [email protected] X-Mailman-Version: 2.1.15 -Precedence: list -List-Id: <root.listes.minet.net> -List-Unsubscribe: <https://listes.minet.net/cgi-bin/mailman/options/root>, - <mailto:[email protected]?subject=unsubscribe> -List-Post: <mailto:[email protected]> -List-Help: <mailto:[email protected]?subject=help> -List-Subscribe: <https://listes.minet.net/cgi-bin/mailman/listinfo/root>, - <mailto:[email protected]?subject=subscribe> Errors-To: [email protected] Sender: "root" <[email protected]> --------------------------------------------------------------------- To unsubscribe, e-mail: [email protected] For additional commands, e-mail: [email protected]
