diff --git a/app/proprietary/src/main/java/stirling/software/proprietary/security/configuration/MailConfig.java b/app/proprietary/src/main/java/stirling/software/proprietary/security/configuration/MailConfig.java index c9b6e9d77..6a565cade 100644 --- a/app/proprietary/src/main/java/stirling/software/proprietary/security/configuration/MailConfig.java +++ b/app/proprietary/src/main/java/stirling/software/proprietary/security/configuration/MailConfig.java @@ -35,15 +35,40 @@ public class MailConfig { JavaMailSenderImpl mailSender = new JavaMailSenderImpl(); mailSender.setHost(mailProperties.getHost()); mailSender.setPort(mailProperties.getPort()); - mailSender.setUsername(mailProperties.getUsername()); - mailSender.setPassword(mailProperties.getPassword()); mailSender.setDefaultEncoding("UTF-8"); + // Only set username and password if they are provided + String username = mailProperties.getUsername(); + String password = mailProperties.getPassword(); + boolean hasCredentials = + (username != null && !username.trim().isEmpty()) + || (password != null && !password.trim().isEmpty()); + + if (username != null && !username.trim().isEmpty()) { + mailSender.setUsername(username); + log.info("SMTP username configured"); + } else { + log.info("SMTP username not configured - using anonymous connection"); + } + + if (password != null && !password.trim().isEmpty()) { + mailSender.setPassword(password); + log.info("SMTP password configured"); + } else { + log.info("SMTP password not configured"); + } + // Retrieves the JavaMail properties to configure additional SMTP parameters Properties props = mailSender.getJavaMailProperties(); - // Enables SMTP authentication - props.put("mail.smtp.auth", "true"); + // Only enable SMTP authentication if credentials are provided + if (hasCredentials) { + props.put("mail.smtp.auth", "true"); + log.info("SMTP authentication enabled"); + } else { + props.put("mail.smtp.auth", "false"); + log.info("SMTP authentication disabled - no credentials provided"); + } // Enables STARTTLS to encrypt the connection if supported by the SMTP server props.put("mail.smtp.starttls.enable", "true"); diff --git a/app/proprietary/src/main/java/stirling/software/proprietary/security/controller/api/UserController.java b/app/proprietary/src/main/java/stirling/software/proprietary/security/controller/api/UserController.java index 9e31ee69c..f2b3fd510 100644 --- a/app/proprietary/src/main/java/stirling/software/proprietary/security/controller/api/UserController.java +++ b/app/proprietary/src/main/java/stirling/software/proprietary/security/controller/api/UserController.java @@ -407,7 +407,8 @@ public class UserController { public ResponseEntity> inviteUsers( @RequestParam(name = "emails", required = true) String emails, @RequestParam(name = "role", defaultValue = "ROLE_USER") String role, - @RequestParam(name = "teamId", required = false) Long teamId) + @RequestParam(name = "teamId", required = false) Long teamId, + HttpServletRequest request) throws SQLException, UnsupportedProviderException { // Check if email invites are enabled @@ -477,6 +478,9 @@ public class UserController { } } + // Build login URL + String loginUrl = buildLoginUrl(request); + int successCount = 0; int failureCount = 0; StringBuilder errors = new StringBuilder(); @@ -488,7 +492,7 @@ public class UserController { continue; } - InviteResult result = processEmailInvite(email, effectiveTeamId, role); + InviteResult result = processEmailInvite(email, effectiveTeamId, role, loginUrl); if (result.isSuccess()) { successCount++; } else { @@ -687,15 +691,45 @@ public class UserController { return ResponseEntity.ok(apiKey); } + /** + * Helper method to build the login URL from the application configuration or request. + * + * @param request The HTTP request + * @return The login URL + */ + private String buildLoginUrl(HttpServletRequest request) { + String baseUrl; + String configuredFrontendUrl = applicationProperties.getSystem().getFrontendUrl(); + if (configuredFrontendUrl != null && !configuredFrontendUrl.trim().isEmpty()) { + // Use configured frontend URL (remove trailing slash if present) + baseUrl = + configuredFrontendUrl.endsWith("/") + ? configuredFrontendUrl.substring(0, configuredFrontendUrl.length() - 1) + : configuredFrontendUrl; + } else { + // Fall back to backend URL from request + baseUrl = + request.getScheme() + + "://" + + request.getServerName() + + (request.getServerPort() != 80 && request.getServerPort() != 443 + ? ":" + request.getServerPort() + : ""); + } + return baseUrl + "/login"; + } + /** * Helper method to process a single email invitation. * * @param email The email address to invite * @param teamId The team ID to assign the user to * @param role The role to assign to the user + * @param loginUrl The URL to the login page * @return InviteResult containing success status and optional error message */ - private InviteResult processEmailInvite(String email, Long teamId, String role) { + private InviteResult processEmailInvite( + String email, Long teamId, String role, String loginUrl) { try { // Validate email format (basic check) if (!email.contains("@") || !email.contains(".")) { @@ -715,7 +749,7 @@ public class UserController { // Send invite email try { - emailService.get().sendInviteEmail(email, email, temporaryPassword); + emailService.get().sendInviteEmail(email, email, temporaryPassword, loginUrl); log.info("Sent invite email to: {}", email); return InviteResult.success(); } catch (Exception emailEx) { diff --git a/app/proprietary/src/main/java/stirling/software/proprietary/security/service/EmailService.java b/app/proprietary/src/main/java/stirling/software/proprietary/security/service/EmailService.java index 870c96f23..8df76fca3 100644 --- a/app/proprietary/src/main/java/stirling/software/proprietary/security/service/EmailService.java +++ b/app/proprietary/src/main/java/stirling/software/proprietary/security/service/EmailService.java @@ -115,10 +115,12 @@ public class EmailService { * @param to The recipient email address * @param username The username for the new account * @param temporaryPassword The temporary password + * @param loginUrl The URL to the login page * @throws MessagingException If there is an issue with creating or sending the email. */ @Async - public void sendInviteEmail(String to, String username, String temporaryPassword) + public void sendInviteEmail( + String to, String username, String temporaryPassword, String loginUrl) throws MessagingException { String subject = "Welcome to Stirling PDF"; @@ -144,6 +146,14 @@ public class EmailService {
⚠️ Important: You will be required to change your password upon first login for security reasons.
Or copy and paste this link in your browser:
+Please keep these credentials secure and do not share them with anyone.
— The Stirling PDF Team
@@ -155,7 +165,7 @@ public class EmailService {