package com.mailserver.smtp; import com.mailserver.config.MailDomains; import com.mailserver.delivery.OutboundQueue; import com.mailserver.delivery.SmtpDeliveryClient; import com.mailserver.domain.User; import com.mailserver.repository.UserRepository; import com.mailserver.service.DkimService; import com.mailserver.service.LocalDelivery; import com.mailserver.service.UserService; import org.springframework.stereotype.Service; import java.util.Locale; /** * Where mail goes — one rule for SMTP and for the web client: * our domain → our mailbox (or "no such user"); catch-all set → everything into that mailbox; * someone else's domain → the delivery queue, only for a logged-in sender (never an open relay). */ @Service public class MailRouter implements SmtpBackend { private final MailDomains domains; private final UserRepository users; private final UserService userService; private final LocalDelivery localDelivery; private final OutboundQueue queue; private final DkimService dkim; private final SmtpDeliveryClient client; public MailRouter(MailDomains domains, UserRepository users, UserService userService, LocalDelivery localDelivery, OutboundQueue queue, DkimService dkim, SmtpDeliveryClient client) { this.domains = domains; this.users = users; this.userService = userService; this.localDelivery = localDelivery; this.queue = queue; this.dkim = dkim; this.client = client; } @Override public boolean authenticate(String username, String password) { User user = users.findByEmail(username.toLowerCase(Locale.ROOT)).block(); return user != null && user.isActive() && userService.checkPassword(user, password); } @Override public Route route(String recipient, String authenticatedUser) { if (domains.catchAll() != null) { return Route.LOCAL; } if (domains.isLocal(recipient)) { return Boolean.TRUE.equals(users.existsByEmail(recipient.toLowerCase(Locale.ROOT)).block()) ? Route.LOCAL : Route.UNKNOWN_USER; } if (authenticatedUser == null) { return Route.RELAY_DENIED; } return client.mode() == SmtpDeliveryClient.Mode.OFF ? Route.OUTBOUND_DISABLED : Route.OUTBOUND; } @Override public void accept(Envelope envelope, byte[] message) throws Exception { boolean trusted = envelope.authenticatedUser() != null; byte[] signed = null; for (Recipient recipient : envelope.recipients()) { switch (recipient.route()) { case LOCAL -> { String mailbox = domains.catchAll() != null ? domains.catchAll() : recipient.address(); localDelivery.deliver(message, mailbox, envelope.remoteIp(), envelope.mailFrom(), trusted); } case OUTBOUND -> { if (signed == null) { signed = dkim.sign(message); } queue.enqueue(envelope.mailFrom(), recipient.address(), signed).block(); } default -> throw new IllegalStateException("Recipient was not accepted: " + recipient); } } } }