package com.mailserver.smtp; import com.mailserver.config.MailDomains; import com.mailserver.delivery.OutboundQueue; import com.mailserver.delivery.SmtpDeliveryClient; import com.mailserver.repository.UserRepository; import com.mailserver.service.DkimService; import com.mailserver.service.LocalDelivery; import com.mailserver.service.UserService; import org.junit.jupiter.api.Test; import reactor.core.publisher.Mono; import java.util.List; import static org.assertj.core.api.Assertions.assertThat; import static org.mockito.ArgumentMatchers.any; import static org.mockito.ArgumentMatchers.anyBoolean; import static org.mockito.ArgumentMatchers.anyString; import static org.mockito.ArgumentMatchers.eq; import static org.mockito.Mockito.mock; import static org.mockito.Mockito.never; import static org.mockito.Mockito.verify; import static org.mockito.Mockito.when; /** Mail trap (75.4): existing mailboxes keep their mail, everything else goes into the catch-all mailbox. */ class MailRouterTest { private final UserRepository users = mock(UserRepository.class); private final LocalDelivery localDelivery = mock(LocalDelivery.class); private final OutboundQueue queue = mock(OutboundQueue.class); private final SmtpDeliveryClient client = mock(SmtpDeliveryClient.class); private MailRouter router(String catchAll) { when(users.existsByEmail(anyString())).thenReturn(Mono.just(false)); when(users.existsByEmail("bob@mail.test")).thenReturn(Mono.just(true)); when(client.mode()).thenReturn(SmtpDeliveryClient.Mode.OFF); return new MailRouter(new MailDomains("mail.test", catchAll), users, mock(UserService.class), localDelivery, queue, mock(DkimService.class), client); } @Test void withoutCatchAllUnknownAndOutsideAddressesAreRefused() { MailRouter router = router(""); assertThat(router.route("bob@mail.test", null)).isEqualTo(SmtpBackend.Route.LOCAL); assertThat(router.route("nobody@mail.test", null)).isEqualTo(SmtpBackend.Route.UNKNOWN_USER); assertThat(router.route("user@gmail.com", null)).isEqualTo(SmtpBackend.Route.RELAY_DENIED); assertThat(router.route("user@gmail.com", "bob@mail.test")).isEqualTo(SmtpBackend.Route.OUTBOUND_DISABLED); } @Test void catchAllTakesEverythingWithoutItsOwnMailboxButExistingMailboxesKeepTheirMail() throws Exception { MailRouter router = router("trap@mail.test"); assertThat(router.route("nobody@mail.test", null)).isEqualTo(SmtpBackend.Route.LOCAL); assertThat(router.route("user@gmail.com", null)).isEqualTo(SmtpBackend.Route.LOCAL); assertThat(router.mailbox("bob@mail.test")).isEqualTo("bob@mail.test"); assertThat(router.mailbox("user@gmail.com")).isEqualTo("trap@mail.test"); router.accept(new SmtpBackend.Envelope("10.0.0.5", "staging", "no-reply@jambotron.com", null, List.of( new SmtpBackend.Recipient("user@gmail.com", SmtpBackend.Route.LOCAL), new SmtpBackend.Recipient("bob@mail.test", SmtpBackend.Route.LOCAL))), "Subject: hi\r\n\r\nbody".getBytes()); verify(localDelivery).deliver(any(), eq("trap@mail.test"), eq("10.0.0.5"), eq("no-reply@jambotron.com"), anyBoolean()); verify(localDelivery).deliver(any(), eq("bob@mail.test"), eq("10.0.0.5"), eq("no-reply@jambotron.com"), anyBoolean()); verify(queue, never()).enqueue(any(), any(), any()); } }