### Start SMTPServer with SimpleMessageListenerAdapter Source: https://context7.com/davidmoten/subethasmtp/llms.txt This example shows how to configure and start an SMTPServer using a SimpleMessageListenerAdapter, which buffers messages for multiple recipients. ```java SMTPServer server = SMTPServer .port(25000) .simpleMessageListener(new DomainFilteringListener()) .build(); server.start(); ``` -------------------------------- ### Create and Start an SMTP Server with SMTPServer Builder Source: https://context7.com/davidmoten/subethasmtp/llms.txt Configure and start an SMTP server using the fluent builder pattern. Supports various options like port, host, TLS, authentication, and connection limits. The server is immutable after building and can be started asynchronously. ```java import org.subethamail.smtp.server.SMTPServer; import java.util.concurrent.TimeUnit; import java.net.InetAddress; // Minimal server on port 25000 with default logging handler SMTPServer server = SMTPServer.port(25000).build(); server.start(); // Fully configured server with all options SMTPServer configuredServer = SMTPServer .port(2525) .hostName("mail.example.com") .bindAddress(InetAddress.getByName("0.0.0.0")) .connectionTimeout(2, TimeUnit.MINUTES) .backlog(100) .maxConnections(500) .maxRecipients(100) .maxMessageSize(10485760) // 10MB .enableTLS() .requireTLS() .softwareName("MyMailServer 1.0") .build(); configuredServer.start(); // Check server status System.out.println("Server running: " + configuredServer.isRunning()); System.out.println("Port allocated: " + configuredServer.getPortAllocated()); // Stop server gracefully configuredServer.stop(); ``` -------------------------------- ### Start Basic SMTPServer Source: https://github.com/davidmoten/subethasmtp/blob/master/README.md Starts an SMTP server on a specified port and logs messages to the console. Ensure the server is started asynchronously. ```java SMTPServer server = SMTPServer .port(25000) .build(); //start server asynchronously server.start(); ``` -------------------------------- ### Run Basic SubEthaSMTP Server Source: https://github.com/davidmoten/subethasmtp/blob/master/GettingStarted.md Execute this command to start a basic SubEthaSMTP server. Ensure the specified JAR file is in your classpath. The server will listen on TCP port 25000. ```bash java -cp subethasmtp-j3.1.8-jar-with-dependencies.jar org.subethamail.examples.BasicSMTPServer ``` -------------------------------- ### Eclipse Maven Project Setup Source: https://github.com/davidmoten/subethasmtp/blob/master/GettingStarted.md Steps to import and build the SubEthaSMTP project in Eclipse using Maven. This involves cloning the repository and running 'Maven Install'. ```xml Import->Maven->Existing Maven Projects Right click on the POM.XML file and select Run As->Maven Install ``` -------------------------------- ### Start SMTPServer with MessageHandlerFactory Source: https://context7.com/davidmoten/subethasmtp/llms.txt This alternative configuration demonstrates starting an SMTPServer by directly providing a MessageHandlerFactory, using SimpleMessageListenerAdapter to wrap the listener. ```java SMTPServer server2 = SMTPServer .port(25001) .messageHandlerFactory(new SimpleMessageListenerAdapter(new DomainFilteringListener())) .build(); server2.start(); ``` -------------------------------- ### Initialize and Start Basic SMTP Server Source: https://github.com/davidmoten/subethasmtp/blob/master/UsingSubEthaSMTP.md Configures and starts an SMTP server using the basic API with a custom message handler factory. ```java SMTPServer smtpServer = SMTPServer.port(25).messageHandlerFactory(myFactory).build(); smtpServer.start(); ``` -------------------------------- ### Start and Use Wiser for SMTP Testing Source: https://context7.com/davidmoten/subethasmtp/llms.txt Starts an in-memory SMTP server using Wiser for testing. Sends a test email and verifies received messages. Includes cleanup and an example of a filtered Wiser instance. ```java import org.subethamail.wiser.Wiser; import org.subethamail.wiser.WiserMessage; import jakarta.mail.internet.MimeMessage; import jakarta.mail.Session; import jakarta.mail.Transport; import jakarta.mail.Message; import jakarta.mail.internet.InternetAddress; import java.util.Properties; import java.util.List; // Start Wiser for testing Wiser wiser = Wiser.port(25000); wiser.start(); // Send a test email using JavaMail Properties props = new Properties(); props.put("mail.smtp.host", "localhost"); props.put("mail.smtp.port", "25000"); Session session = Session.getInstance(props); MimeMessage message = new MimeMessage(session); message.setFrom(new InternetAddress("sender@test.com")); message.setRecipient(Message.RecipientType.TO, new InternetAddress("recipient@test.com")); message.setSubject("Test Subject"); message.setText("Test body content"); Transport.send(message); // Verify received messages List messages = wiser.getMessages(); assert messages.size() == 1 : "Expected 1 message"; WiserMessage wiserMsg = messages.get(0); assert wiserMsg.getEnvelopeSender().equals("sender@test.com"); assert wiserMsg.getEnvelopeReceiver().equals("recipient@test.com"); // Convert to MimeMessage for detailed inspection MimeMessage received = wiserMsg.getMimeMessage(); assert received.getSubject().equals("Test Subject"); assert received.getContent().toString().contains("Test body content"); // Get raw message data byte[] rawData = wiserMsg.getData(); System.out.println("Raw message: " + new String(rawData)); // Dump all messages for debugging wiser.dumpMessages(System.out); // Clean up wiser.stop(); // Wiser with custom accepter (filter messages) Wiser filteredWiser = Wiser .accepter((from, recipient) -> recipient.endsWith("@allowed.com")) .port(25001); filteredWiser.start(); ``` -------------------------------- ### Start SMTPServer with Message Handler Source: https://github.com/davidmoten/subethasmtp/blob/master/README.md Starts an SMTP server and defines a message handler to process incoming emails. The handler receives sender, recipient, and email data, printing them to the console. ```java SMTPServer server = SMTPServer .port(PORT) .messageHandler( (ctx, from, to, data) -> System.out.println( "message from " + from + " to " + to + ":\n" + new String(data, StandardCharsets.UTF_8))) .build(); server.start(); ``` -------------------------------- ### Implement UsernamePasswordValidator for SMTP Authentication Source: https://context7.com/davidmoten/subethasmtp/llms.txt Implement the UsernamePasswordValidator interface to handle user credential verification for PLAIN and LOGIN authentication mechanisms. This example shows a simple map-based user store. ```java import org.subethamail.smtp.auth.EasyAuthenticationHandlerFactory; import org.subethamail.smtp.auth.UsernamePasswordValidator; import org.subethamail.smtp.auth.LoginFailedException; import org.subethamail.smtp.MessageContext; import org.subethamail.smtp.server.SMTPServer; import java.nio.charset.StandardCharsets; import java.util.HashMap; import java.util.Map; public class SimpleAuthValidator implements UsernamePasswordValidator { private final Map users = new HashMap<>(); public SimpleAuthValidator() { users.put("user1", "password123"); users.put("user2", "secret456"); } @Override public void login(String username, String password, MessageContext context) throws LoginFailedException { String expectedPassword = users.get(username); if (expectedPassword == null || !expectedPassword.equals(password)) { throw new LoginFailedException("Invalid username or password"); } System.out.println("User authenticated: " + username + " from " + context.getRemoteAddress()); } } ``` -------------------------------- ### Initialize Server with SimpleMessageListenerAdapter Source: https://github.com/davidmoten/subethasmtp/blob/master/UsingSubEthaSMTP.md Uses the higher-level SimpleMessageListenerAdapter to simplify message handling. ```java SMTPServer server = SMTPServer .port(25) .messageHandlerFactory(new SimpleMessageListenerAdapter(myListener)) .build(); server.start(); ``` -------------------------------- ### Configure SMTP Server with Optional STARTTLS Source: https://context7.com/davidmoten/subethasmtp/llms.txt Sets up an SMTPServer that supports STARTTLS, allowing clients to upgrade an existing plain connection to a TLS-encrypted one. TLS is optional. ```java // Server with optional STARTTLS SMTPServer starttlsServer = SMTPServer .port(25) .enableTLS() .startTlsSocketFactory(sslContext) .messageHandler((ctx, from, to, data) -> { System.out.println("Received message via " + (ctx.getTlsStatus() != null ? "TLS" : "plain")); }) .build(); starttlsServer.start(); ``` -------------------------------- ### Send Email with SmartClient (Authentication and STARTTLS) Source: https://context7.com/davidmoten/subethasmtp/llms.txt Connects to an SMTP server with authentication and STARTTLS support. Checks for STARTTLS availability and uses it if present. Handles potential SMTP exceptions. ```java import org.subethamail.smtp.client.SmartClient; import org.subethamail.smtp.client.PlainAuthenticator; import org.subethamail.smtp.client.SMTPException; import java.util.Optional; import java.nio.charset.StandardCharsets; // Connection with authentication SmartClient authClient = SmartClient.createAndConnect( "smtp.example.com", 587, Optional.empty(), // No specific bind point "myhostname.local", Optional.of(new PlainAuthenticator( () -> "smtp.example.com", // server getter "username", "password" )) ); try { // Check supported extensions after EHLO System.out.println("Server extensions: " + authClient.getExtensions()); // Use STARTTLS if available if (authClient.getExtensions().containsKey("STARTTLS")) { authClient.startTLS(); } authClient.from("sender@example.com"); authClient.to("recipient@example.com"); authClient.dataStart(); authClient.dataWrite("Subject: Authenticated Email\r\n\r\nBody".getBytes()); authClient.dataEnd(); } catch (SMTPException e) { System.err.println("SMTP Error: " + e.getResponse().getCode() + " " + e.getResponse().getMessage()); } finally { authClient.quit(); } ``` -------------------------------- ### Send Email with SmartClient (Simple) Source: https://context7.com/davidmoten/subethasmtp/llms.txt Establishes a simple SMTP connection using SmartClient and sends an email. Handles basic protocol negotiation. Ensure the server and port are correct. ```java import org.subethamail.smtp.client.SmartClient; import org.subethamail.smtp.client.PlainAuthenticator; import org.subethamail.smtp.client.SMTPException; import java.util.Optional; import java.nio.charset.StandardCharsets; // Simple connection and send SmartClient client = SmartClient.createAndConnect( "smtp.example.com", 25, "myhostname.local"); try { client.from("sender@example.com"); client.to("recipient@example.com"); client.to("another@example.com"); // Multiple recipients client.dataStart(); String emailContent = "From: sender@example.com\r\n" + "To: recipient@example.com\r\n" + "Subject: Test Email\r\n" + "\r\n" + "This is the message body.\r\n"; client.dataWrite(emailContent.getBytes(StandardCharsets.UTF_8)); client.dataEnd(); System.out.println("Recipients accepted: " + client.getRecipientCount()); } finally { client.quit(); } ``` -------------------------------- ### Load Keystore for TLS Configuration Source: https://context7.com/davidmoten/subethasmtp/llms.txt Loads a JKS keystore and initializes KeyManagerFactory and TrustManagerFactory for TLS/SSL configuration. Ensure the paths and passwords are correct. ```java import org.subethamail.smtp.server.SMTPServer; import javax.net.ssl.SSLContext; import javax.net.ssl.KeyManagerFactory; import javax.net.ssl.TrustManagerFactory; import java.security.KeyStore; import java.io.FileInputStream; import java.nio.charset.StandardCharsets; // Load keystore for TLS KeyStore keyStore = KeyStore.getInstance("JKS"); try (FileInputStream fis = new FileInputStream("/path/to/keystore.jks")) { keyStore.load(fis, "keystorePassword".toCharArray()); } KeyManagerFactory kmf = KeyManagerFactory.getInstance( KeyManagerFactory.getDefaultAlgorithm()); kmf.init(keyStore, "keyPassword".toCharArray()); TrustManagerFactory tmf = TrustManagerFactory.getInstance( TrustManagerFactory.getDefaultAlgorithm()); tmf.init(keyStore); SSLContext sslContext = SSLContext.getInstance("TLS"); sslContext.init(kmf.getKeyManagers(), tmf.getTrustManagers(), null); ``` -------------------------------- ### Configure SMTP Server Requiring STARTTLS Source: https://context7.com/davidmoten/subethasmtp/llms.txt Sets up an SMTPServer that requires clients to use STARTTLS before accepting any mail. Connections are initially plain but must be upgraded to TLS. ```java // Server requiring STARTTLS before accepting mail SMTPServer requiredTlsServer = SMTPServer .port(587) .requireTLS() .startTlsSocketFactory(sslContext) .messageHandler((ctx, from, to, data) -> { System.out.println("Secure message received"); }) .build(); ``` -------------------------------- ### Configure SMTPServer with Multiple Options Source: https://github.com/davidmoten/subethasmtp/blob/master/README.md Configures an SMTPServer with various options using a builder pattern. This includes connection timeouts, authentication, backlog, bind address, TLS settings, host name, message size, connection limits, message handler factory, executor service, and address validation. ```java SMTPServer server = SMTPServer .port(port) .connectionTimeout(1, TimeUnit.MINUTES) .authenticationHandlerFactory(ahf) .backlog(100) .bindAddress(address) .requireTLS() .hideTLS() .hostName("us") .maxMessageSize(10000) .maxConnections(20) .maxRecipients(20) .messageHandlerFactory(mhf) .executorService(executor) .startTlsSocketFactory(sslContext) .fromAddressValidator(emailValidator) .build(); ``` -------------------------------- ### Configure SMTP Server with Optional Authentication Source: https://context7.com/davidmoten/subethasmtp/llms.txt Sets up an SMTPServer that allows both authenticated and anonymous email submissions. Authentication is optional. ```java // Server with optional authentication SMTPServer serverOptionalAuth = SMTPServer .port(25000) .authenticationHandlerFactory( new EasyAuthenticationHandlerFactory(new SimpleAuthValidator())) .messageHandler((ctx, from, to, data) -> { // Check if user authenticated if (ctx.getAuthenticationHandler() != null) { System.out.println("Authenticated user: " + ctx.getAuthenticationHandler().getIdentity()); } else { System.out.println("Anonymous submission"); } System.out.println("Message from " + from + " to " + to); }) .build(); serverOptionalAuth.start(); ``` -------------------------------- ### Configure SMTP Server with Hidden TLS Source: https://context7.com/davidmoten/subethasmtp/llms.txt Sets up an SMTPServer that supports STARTTLS but does not advertise it in the EHLO response. This can be used for specific security scenarios. ```java // Server with hidden TLS (not advertised in EHLO) SMTPServer hiddenTlsServer = SMTPServer .port(2525) .enableTLS() .hideTLS() .startTlsSocketFactory(sslContext) .messageHandler((ctx, from, to, data) -> { System.out.println("Message received"); }) .build(); ``` -------------------------------- ### Configure SMTP Authentication Source: https://github.com/davidmoten/subethasmtp/blob/master/UsingSubEthaSMTP.md Sets up an SMTP server with an authentication handler factory for handling AUTH commands. ```java SMTPServer server = SMTPServer .port(port) .messageHandlerFactory(myMessageHandlerFactory); .authenticationHandlerFactory(new EasyAuthenticationHandlerFactory(myUsernamePasswordValidator)) .build(); server.start(); ``` -------------------------------- ### Configure SMTP Server Requiring Authentication Source: https://context7.com/davidmoten/subethasmtp/llms.txt Sets up an SMTPServer that enforces authentication before accepting any email. No mail is accepted until a user successfully authenticates. ```java // Server requiring authentication before accepting mail SMTPServer serverRequiredAuth = SMTPServer .port(25001) .authenticationHandlerFactory( new EasyAuthenticationHandlerFactory(new SimpleAuthValidator())) .requireAuth() .messageHandler((ctx, from, to, data) -> { System.out.println("Authenticated: " + ctx.getAuthenticationHandler().getIdentity()); }) .build(); serverRequiredAuth.start(); ``` -------------------------------- ### Configure Maven dependencies Source: https://context7.com/davidmoten/subethasmtp/llms.txt Include the SubEtha SMTP library and required runtime dependencies in your project's pom.xml. ```xml com.github.davidmoten subethasmtp 7.1.7 org.eclipse.angus angus-mail 2.0.5 runtime org.slf4j slf4j-simple 1.7.36 ``` -------------------------------- ### Configure Pure SSL/TLS SMTP Server Source: https://context7.com/davidmoten/subethasmtp/llms.txt Sets up an SMTPServer that uses SSL/TLS encryption from the very beginning of the connection. This is typically used for ports like 465. ```java // Pure SSL server (encrypted from connection start) SMTPServer sslServer = SMTPServer .port(465) .serverSocketFactory(sslContext) .messageHandler((ctx, from, to, data) -> { System.out.println("Pure SSL message received"); }) .build(); ``` -------------------------------- ### Send Email with SmartClient (BDAT) Source: https://context7.com/davidmoten/subethasmtp/llms.txt Sends an email using the BDAT command for chunked data transfer. This is an alternative to the standard DATA command. Ensure the server supports BDAT. ```java import org.subethamail.smtp.client.SmartClient; import org.subethamail.smtp.client.PlainAuthenticator; import org.subethamail.smtp.client.SMTPException; import java.util.Optional; import java.nio.charset.StandardCharsets; // Using BDAT (chunked transfer) instead of DATA SmartClient bdatClient = SmartClient.createAndConnect( "localhost", 25000, "myhostname"); try { bdatClient.from("sender@test.com"); bdatClient.to("recipient@test.com"); bdatClient.bdat("First chunk of data"); bdatClient.bdat("Second chunk"); bdatClient.bdatLast("Final chunk"); // Marks end of message } finally { bdatClient.quit(); } ``` -------------------------------- ### Simple Lambda-Based Message Handling with BasicMessageListener Source: https://context7.com/davidmoten/subethasmtp/llms.txt Process incoming emails using a lambda expression with BasicMessageListener. This is suitable for straightforward message processing, receiving the complete message as a byte array along with sender and recipient details. ```java import org.subethamail.smtp.server.SMTPServer; import java.nio.charset.StandardCharsets; // Process messages with a lambda handler SMTPServer server = SMTPServer .port(25000) .messageHandler((ctx, from, to, data) -> { System.out.println("=== New Message ==="); System.out.println("From: " + from); System.out.println("To: " + to); System.out.println("Remote Address: " + ctx.getRemoteAddress()); System.out.println("Session ID: " + ctx.getSessionId()); System.out.println("Content:"); System.out.println(new String(data, StandardCharsets.UTF_8)); System.out.println("==================="); }) .build(); server.start(); // Send test email using telnet or SMTP client: // HELO localhost // MAIL FROM: // RCPT TO: // DATA // Subject: Test // // Hello World! // . // QUIT ``` -------------------------------- ### Implement connection rate limiting with SessionHandler Source: https://context7.com/davidmoten/subethasmtp/llms.txt Implement the SessionHandler interface to monitor and control SMTP sessions. This is useful for rate limiting or blocking specific IP addresses. ```java import org.subethamail.smtp.server.SMTPServer; import org.subethamail.smtp.server.SessionHandler; import org.subethamail.smtp.server.Session; import java.net.InetSocketAddress; import java.util.concurrent.ConcurrentHashMap; import java.util.concurrent.atomic.AtomicInteger; import java.nio.charset.StandardCharsets; public class RateLimitingSessionHandler implements SessionHandler { private final ConcurrentHashMap connectionCounts = new ConcurrentHashMap<>(); private final int maxConnectionsPerIP = 5; @Override public boolean accept(Session session) { InetSocketAddress remote = (InetSocketAddress) session.getRemoteAddress(); String ip = remote.getAddress().getHostAddress(); AtomicInteger count = connectionCounts.computeIfAbsent(ip, k -> new AtomicInteger(0)); if (count.incrementAndGet() > maxConnectionsPerIP) { System.out.println("Rate limit exceeded for: " + ip); count.decrementAndGet(); return false; // Reject connection } System.out.println("Accepted connection from: " + ip + " (count: " + count.get() + ")"); return true; } @Override public void onSessionEnd(Session session) { InetSocketAddress remote = (InetSocketAddress) session.getRemoteAddress(); String ip = remote.getAddress().getHostAddress(); AtomicInteger count = connectionCounts.get(ip); if (count != null) { count.decrementAndGet(); } System.out.println("Session ended for: " + ip); } } SMTPServer server = SMTPServer .port(25000) .sessionHandler(new RateLimitingSessionHandler()) .messageHandler((ctx, from, to, data) -> { System.out.println("Message received in session: " + ctx.getSessionId()); }) .build(); server.start(); ``` -------------------------------- ### Implement Custom MessageHandlerFactory in Java Source: https://context7.com/davidmoten/subethasmtp/llms.txt Implement the MessageHandlerFactory interface to create custom MessageHandler instances for each incoming SMTP message. This allows for per-message logic and state management. ```java import org.subethamail.smtp.MessageHandler; import org.subethamail.smtp.MessageHandlerFactory; import org.subethamail.smtp.MessageContext; import org.subethamail.smtp.RejectException; import org.subethamail.smtp.TooMuchDataException; import org.subethamail.smtp.server.SMTPServer; import java.io.InputStream; import java.io.IOException; import java.io.BufferedReader; import java.io.InputStreamReader; import java.nio.charset.StandardCharsets; public class CustomMessageHandlerFactory implements MessageHandlerFactory { @Override public MessageHandler create(MessageContext ctx) { return new CustomMessageHandler(ctx); } } class CustomMessageHandler implements MessageHandler { private final MessageContext ctx; private String sender; private StringBuilder recipients = new StringBuilder(); public CustomMessageHandler(MessageContext ctx) { this.ctx = ctx; } @Override public void from(String from) throws RejectException { // Validate sender - reject if from blocked domain if (from.endsWith("@spam.com")) { throw new RejectException(550, "Sender domain is blocked"); } this.sender = from; System.out.println("Accepted sender: " + from); } @Override public void recipient(String recipient) throws RejectException { // Only accept mail for our domain if (!recipient.endsWith("@mycompany.com")) { throw new RejectException(550, "We do not relay for " + recipient); } recipients.append(recipient).append(", "); System.out.println("Accepted recipient: " + recipient); } @Override public String data(InputStream data) throws RejectException, TooMuchDataException, IOException { BufferedReader reader = new BufferedReader( new InputStreamReader(data, StandardCharsets.UTF_8)); StringBuilder content = new StringBuilder(); String line; int size = 0; int maxSize = 1024 * 1024; // 1MB limit while ((line = reader.readLine()) != null) { size += line.length(); if (size > maxSize) { throw new TooMuchDataException("Message exceeds 1MB limit"); } content.append(line).append("\n"); } System.out.println("Received " + size + " bytes from " + sender); // Return custom success message or null for default return "Message accepted for delivery"; } @Override public void done() { System.out.println("Transaction complete for: " + sender); } } // Usage SMTPServer server = SMTPServer .port(25000) .messageHandlerFactory(new CustomMessageHandlerFactory()) .build(); server.start(); ``` -------------------------------- ### SimpleMessageListener Interface Source: https://github.com/davidmoten/subethasmtp/blob/master/UsingSubEthaSMTP.md Provides a simplified interface for accepting recipients and delivering message data. ```java public interface SimpleMessageListener { /** * Called once for every RCPT TO during a SMTP exchange. Each accepted recipient * will result in a separate deliver() call later. */ public boolean accept(String from, String recipient); /** * When message data arrives, this method will be called for every recipient * this listener accepted. */ public void deliver(String from, String recipient, InputStream data) throws TooMuchDataException, IOException; } ``` -------------------------------- ### Implement Domain Filtering Listener Source: https://context7.com/davidmoten/subethasmtp/llms.txt This listener accepts or rejects recipients based on a predefined set of domains. It then processes the message data for each accepted recipient. ```java import org.subethamail.smtp.helper.SimpleMessageListener; import org.subethamail.smtp.helper.SimpleMessageListenerAdapter; import org.subethamail.smtp.TooMuchDataException; import org.subethamail.smtp.server.SMTPServer; import java.io.InputStream; import java.io.IOException; import java.util.Set; import java.util.HashSet; public class DomainFilteringListener implements SimpleMessageListener { private final Set acceptedDomains = new HashSet<>(); public DomainFilteringListener() { acceptedDomains.add("@mycompany.com"); acceptedDomains.add("@subsidiary.com"); } @Override public boolean accept(String from, String recipient) { // Accept only recipients in our domains for (String domain : acceptedDomains) { if (recipient.toLowerCase().endsWith(domain)) { System.out.println("Accepting: " + recipient); return true; } } System.out.println("Rejecting: " + recipient); return false; } @Override public void deliver(String from, String recipient, InputStream data) throws TooMuchDataException, IOException { // Called once for each accepted recipient System.out.println("Delivering mail from " + from + " to " + recipient); // Read and process the message data byte[] buffer = new byte[8192]; int totalBytes = 0; int bytesRead; while ((bytesRead = data.read(buffer)) != -1) { totalBytes += bytesRead; // Process data here (save to database, forward, etc.) } System.out.println("Delivered " + totalBytes + " bytes"); } } ``` -------------------------------- ### MessageHandler and Factory Interfaces Source: https://github.com/davidmoten/subethasmtp/blob/master/UsingSubEthaSMTP.md Defines the low-level interfaces for creating message handlers and processing SMTP transaction stages. ```java public interface MessageHandlerFactory { /** * Called for the exchange of a single message during an SMTP conversation. */ public MessageHandler create(MessageContext ctx); } public interface MessageHandler { /** * Called first, after the MAIL FROM during a SMTP exchange. */ public void from(String from) throws RejectException; /** * Called once for every RCPT TO during a SMTP exchange. * This will occur after a from() call. */ public void recipient(String recipient) throws RejectException; /** * Called when the DATA part of the SMTP exchange begins. */ public void data(InputStream data) throws RejectException, TooMuchDataException, IOException; } ``` -------------------------------- ### Add SubEthaSMTP Maven Dependency Source: https://github.com/davidmoten/subethasmtp/blob/master/ObtainingSubEthaSMTP.md Include this dependency in your project's POM file to use the SubEthaSMTP library. Adjust the version number as needed. ```xml com.github.davidmoten subethasmtp VERSION_HERE ``` -------------------------------- ### Maven Dependency for SubEthaSMTP Source: https://github.com/davidmoten/subethasmtp/blob/master/README.md Add this Maven dependency to your project to include the SubEtha SMTP library. Replace VERSION_HERE with the desired version. ```xml com.github.davidmoten subethasmtp VERSION_HERE ``` -------------------------------- ### Validate MAIL FROM addresses with custom predicates Source: https://context7.com/davidmoten/subethasmtp/llms.txt Use the fromAddressValidator method to enforce custom logic on sender addresses. Returning false triggers a 553 SMTP response. ```java import org.subethamail.smtp.server.SMTPServer; import java.util.regex.Pattern; import java.util.Set; import java.util.HashSet; import java.nio.charset.StandardCharsets; // Block specific senders Set blockedSenders = new HashSet<>(); blockedSenders.add("spammer@evil.com"); blockedSenders.add("blocked@domain.com"); SMTPServer server = SMTPServer .port(25000) .fromAddressValidator(from -> { // Reject if in blocklist if (blockedSenders.contains(from.toLowerCase())) { return false; } // Require valid email format return Pattern.matches("^[^@]+@[^@]+\\.[^@]+$", from); }) .messageHandler((ctx, from, to, data) -> { System.out.println("Accepted mail from: " + from); }) .build(); server.start(); // Client will receive: // 553 Invalid email address ``` === COMPLETE CONTENT === This response contains all available snippets from this library. No additional content exists. Do not make further requests.