package com.mailserver.delivery; import com.icegreen.greenmail.util.GreenMail; import com.icegreen.greenmail.util.ServerSetup; import jakarta.mail.internet.MimeMessage; import org.junit.jupiter.api.AfterEach; import org.junit.jupiter.api.BeforeEach; import org.junit.jupiter.api.Test; import java.io.ByteArrayOutputStream; import java.net.ServerSocket; import java.nio.charset.StandardCharsets; import java.util.List; import static org.assertj.core.api.Assertions.assertThat; class SmtpDeliveryClientTest { private static final String MESSAGE = "From: alice@ours.test\r\nTo: bob@theirs.test\r\nSubject: Hi\r\n" + "DKIM-Signature: v=1; a=rsa-sha256; d=ours.test; s=mail; h=from; bh=x; b=y\r\n\r\nbody\r\n.dot line\r\n"; private GreenMail greenMail; @BeforeEach void start() { greenMail = new GreenMail(new ServerSetup(0, "127.0.0.1", ServerSetup.PROTOCOL_SMTP)); greenMail.setUser("relay-user", "relay-pass"); greenMail.start(); } @AfterEach void stop() { greenMail.stop(); } private int port() { return greenMail.getSmtp().getPort(); } private SmtpDeliveryClient mxClient(int mxPort, List hosts) { return new SmtpDeliveryClient(new SmtpDeliveryClient.Settings(SmtpDeliveryClient.Mode.MX, "", 0, "", "", SmtpDeliveryClient.Tls.NONE, "mx.ours.test", 5000, mxPort), domain -> hosts); } @Test void deliversToTheMxAndKeepsTheBytesUnchanged() throws Exception { SmtpDeliveryClient.Result result = mxClient(port(), List.of("127.0.0.1")) .deliver("alice@ours.test", "bob@theirs.test", MESSAGE.getBytes(StandardCharsets.UTF_8)); assertThat(result.outcome()).isEqualTo(SmtpDeliveryClient.Outcome.DELIVERED); MimeMessage[] received = greenMail.getReceivedMessages(); assertThat(received).hasSize(1); ByteArrayOutputStream out = new ByteArrayOutputStream(); received[0].writeTo(out); // GreenMail adds its Received/Return-Path; everything we sent is there byte for byte (DKIM stays valid) assertThat(out.toString(StandardCharsets.UTF_8)).contains(MESSAGE.stripTrailing()); } @Test void triesTheNextMxWhenTheFirstDoesNotAnswer() throws Exception { int closed; try (ServerSocket socket = new ServerSocket(0)) { closed = socket.getLocalPort(); } // first "host" refuses the connection, second is GreenMail — both on 127.0.0.1, so use two clients' ports: SmtpDeliveryClient.Result refused = mxClient(closed, List.of("127.0.0.1")) .deliver("alice@ours.test", "bob@theirs.test", MESSAGE.getBytes(StandardCharsets.UTF_8)); assertThat(refused.outcome()).isEqualTo(SmtpDeliveryClient.Outcome.TEMPORARY); SmtpDeliveryClient.Result fallback = mxClient(port(), List.of("unreachable.invalid", "127.0.0.1")) .deliver("alice@ours.test", "bob@theirs.test", MESSAGE.getBytes(StandardCharsets.UTF_8)); assertThat(fallback.outcome()).isEqualTo(SmtpDeliveryClient.Outcome.DELIVERED); } @Test void domainWithoutMailServerIsAPermanentFailure() { SmtpDeliveryClient.Result result = mxClient(port(), List.of()) .deliver("alice@ours.test", "bob@nowhere.test", MESSAGE.getBytes(StandardCharsets.UTF_8)); assertThat(result.outcome()).isEqualTo(SmtpDeliveryClient.Outcome.PERMANENT); } @Test void dnsTroubleIsTemporary() { SmtpDeliveryClient client = new SmtpDeliveryClient(new SmtpDeliveryClient.Settings(SmtpDeliveryClient.Mode.MX, "", 0, "", "", SmtpDeliveryClient.Tls.NONE, "mx.ours.test", 5000, port()), domain -> { throw new SmtpDeliveryClient.TemporaryDnsException("SERVFAIL"); }); assertThat(client.deliver("a@ours.test", "b@theirs.test", MESSAGE.getBytes()).outcome()) .isEqualTo(SmtpDeliveryClient.Outcome.TEMPORARY); } @Test void sendsThroughASmarthostWithLogin() { SmtpDeliveryClient client = new SmtpDeliveryClient(new SmtpDeliveryClient.Settings(SmtpDeliveryClient.Mode.SMARTHOST, "127.0.0.1", port(), "relay-user", "relay-pass", SmtpDeliveryClient.Tls.NONE, "mx.ours.test", 5000, 25)); assertThat(client.deliver("alice@ours.test", "bob@theirs.test", MESSAGE.getBytes()).outcome()) .isEqualTo(SmtpDeliveryClient.Outcome.DELIVERED); assertThat(greenMail.getReceivedMessages()).hasSize(1); } @Test void offModeSendsNothing() { SmtpDeliveryClient client = new SmtpDeliveryClient(new SmtpDeliveryClient.Settings(SmtpDeliveryClient.Mode.OFF, "", 0, "", "", SmtpDeliveryClient.Tls.NONE, "mx.ours.test", 5000, 25)); assertThat(client.deliver("a@ours.test", "b@theirs.test", MESSAGE.getBytes()).outcome()) .isEqualTo(SmtpDeliveryClient.Outcome.PERMANENT); assertThat(greenMail.getReceivedMessages()).isEmpty(); } }