From c8cdbb84acf3d7120be9f48c7f3fc5848c522ee9 Mon Sep 17 00:00:00 2001 From: Oleandertengesdal Date: Fri, 10 Apr 2026 10:04:23 +0200 Subject: [PATCH] Send invite emails asynchronously Add AsyncMailSender component and enable async execution to avoid SMTP hangs blocking HTTP responses. --- .../src/main/java/backend/fullstack/Main.java | 2 + .../auth/invite/AsyncMailSender.java | 37 +++++++++++++++++++ .../auth/invite/UserInviteService.java | 12 +++--- 3 files changed, 44 insertions(+), 7 deletions(-) create mode 100644 backend/src/main/java/backend/fullstack/auth/invite/AsyncMailSender.java diff --git a/backend/src/main/java/backend/fullstack/Main.java b/backend/src/main/java/backend/fullstack/Main.java index 88cf18c..e86306d 100644 --- a/backend/src/main/java/backend/fullstack/Main.java +++ b/backend/src/main/java/backend/fullstack/Main.java @@ -2,8 +2,10 @@ import org.springframework.boot.SpringApplication; import org.springframework.boot.autoconfigure.SpringBootApplication; +import org.springframework.scheduling.annotation.EnableAsync; @SpringBootApplication +@EnableAsync public class Main { public static void main(String[] args) { SpringApplication.run(Main.class, args); diff --git a/backend/src/main/java/backend/fullstack/auth/invite/AsyncMailSender.java b/backend/src/main/java/backend/fullstack/auth/invite/AsyncMailSender.java new file mode 100644 index 0000000..5b08ad2 --- /dev/null +++ b/backend/src/main/java/backend/fullstack/auth/invite/AsyncMailSender.java @@ -0,0 +1,37 @@ +package backend.fullstack.auth.invite; + +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; +import org.springframework.mail.SimpleMailMessage; +import org.springframework.mail.javamail.JavaMailSender; +import org.springframework.scheduling.annotation.Async; +import org.springframework.stereotype.Component; + +import java.util.Optional; + +/** + * Sends emails on a background thread so SMTP hangs never block HTTP responses. + */ +@Component +public class AsyncMailSender { + + private static final Logger logger = LoggerFactory.getLogger(AsyncMailSender.class); + + private final Optional mailSender; + + public AsyncMailSender(Optional mailSender) { + this.mailSender = mailSender; + } + + @Async + public void send(SimpleMailMessage message) { + if (mailSender.isEmpty()) { + return; + } + try { + mailSender.get().send(message); + } catch (Exception ex) { + logger.error("Failed to send email to {}: {}", message.getTo(), ex.getMessage()); + } + } +} diff --git a/backend/src/main/java/backend/fullstack/auth/invite/UserInviteService.java b/backend/src/main/java/backend/fullstack/auth/invite/UserInviteService.java index 208ff6a..b84fa96 100644 --- a/backend/src/main/java/backend/fullstack/auth/invite/UserInviteService.java +++ b/backend/src/main/java/backend/fullstack/auth/invite/UserInviteService.java @@ -35,6 +35,7 @@ public class UserInviteService { private final UserRepository userRepository; private final PasswordEncoder passwordEncoder; private final Optional mailSender; + private final AsyncMailSender asyncMailSender; private final InviteProperties inviteProperties; private final SecureRandom secureRandom = new SecureRandom(); @@ -43,12 +44,14 @@ public UserInviteService( UserRepository userRepository, PasswordEncoder passwordEncoder, Optional mailSender, + AsyncMailSender asyncMailSender, InviteProperties inviteProperties ) { this.userInviteTokenRepository = userInviteTokenRepository; this.userRepository = userRepository; this.passwordEncoder = passwordEncoder; this.mailSender = mailSender; + this.asyncMailSender = asyncMailSender; this.inviteProperties = inviteProperties; } @@ -113,13 +116,8 @@ private void sendInviteEmail(User user, String token) { return; } - try { - mailSender.get().send(message); - logger.info("Invite email sent to userId={} email={}", user.getId(), user.getEmail()); - } catch (Exception ex) { - logger.error("Failed to send invite email to userId={} email={}: {}", - user.getId(), user.getEmail(), ex.getMessage()); - } + logger.info("Sending invite email to userId={} email={}", user.getId(), user.getEmail()); + asyncMailSender.send(message); } /**