{"record":{"id":"94713d8f7efdcb82","repo":"halo-dev/halo","slug":"failed-to-send-email-please-check-your-email-conf","errorCode":null,"errorMessage":"Failed to send email, please check your email configuration.","messagePattern":"Failed to send email, please check your email configuration\\.","errorType":"http","errorClass":"ServerWebInputException","httpStatus":400,"severity":"error","filePath":"application/src/main/java/run/halo/app/notification/endpoint/EmailConfigValidationEndpoint.java","lineNumber":78,"sourceCode":"                                .requestBody(\n                                        requestBodyBuilder().required(true).implementation(ValidationRequest.class))\n                                .response(responseBuilder().implementation(Void.class)))\n                .build();\n    }\n\n    private Mono<ServerResponse> verifyEmailSenderConfig(ServerRequest request) {\n        return request.bodyToMono(ValidationRequest.class)\n                .switchIfEmpty(Mono.error(new ServerWebInputException(\"Required request body is missing.\")))\n                .flatMap(validationRequest -> getCurrentUserEmail().flatMap(recipient -> {\n                    var mailSender = emailSenderHelper.createJavaMailSender(validationRequest);\n                    var message = emailSenderHelper.createMimeMessagePreparator(\n                            validationRequest, recipient, EMAIL_SUBJECT, EMAIL_BODY, EMAIL_BODY);\n                    try {\n                        mailSender.send(message);\n                    } catch (MailException e) {\n                        String errorMsg = \"Failed to send email, please check your email configuration.\";\n                        log.error(errorMsg, e);\n                        throw new ServerWebInputException(errorMsg, null, e);\n                    }\n                    return ServerResponse.ok().build();\n                }));\n    }\n\n    Mono<String> getCurrentUserEmail() {\n        return ReactiveSecurityContextHolder.getContext()\n                .map(SecurityContext::getAuthentication)\n                .map(Principal::getName)\n                .flatMap(username -> client.fetch(User.class, username))\n                .flatMap(user -> {\n                    var email = user.getSpec().getEmail();\n                    if (StringUtils.isBlank(email)) {\n                        return Mono.error(\n                                new ServerWebInputException(\"Your email is missing, please set it in your profile.\"));\n                    }\n                    return Mono.just(email);\n                });","sourceCodeStart":60,"sourceCodeEnd":96,"githubUrl":"https://github.com/halo-dev/halo/blob/d2f5165f9c8f055ffcb3fa9c3f4032821a7b68c8/application/src/main/java/run/halo/app/notification/endpoint/EmailConfigValidationEndpoint.java#L60-L96","documentation":"Thrown as ServerWebInputException (HTTP 400) by EmailConfigValidationEndpoint.verifyEmailSenderConfig when mailSender.send(message) throws a MailException. The endpoint performs a live test send to the current user's email; any SMTP-level failure is wrapped into a bad-input response (the underlying cause is logged at error level).","triggerScenarios":"POST /apis/api.console.halo.run/v1alpha1/notifiers/default-email-notifier/verify-connection with an SMTP config that cannot deliver: wrong host/port, auth failure, TLS/SSL mismatch, blocked by firewall, or the recipient address rejected.","commonSituations":"Incorrect SMTP host/port/username/password in the notifier config; SMTP requires SSL but config uses STARTTLS (or vice versa); firewall blocking outbound 25/465/587; sender credentials revoked; recipient email invalid/unverified.","solutions":["Open the server error log: the wrapped MailException shows the exact SMTP failure (auth, connect, cert).","Correct the SMTP host, port, username, password and the encryption mode (SSL/TLS vs STARTTLS).","Verify outbound network connectivity and DNS resolution from the Halo host to the SMTP server.","Use app-specific credentials (e.g. Gmail/O365 app password) where plain passwords are disabled."],"exampleFix":"# before\nspring.mail.host=smtp.example.com\nspring.mail.port=25\nspring.mail.username=user\nspring.mail.password=oldpass\n\n# after\nspring.mail.host=smtp.example.com\nspring.mail.port=587\nspring.mail.properties.mail.smtp.starttls.enable=true\nspring.mail.username=user\nspring.mail.password=newAppPassword","handlingStrategy":"try-catch","validationCode":"// Pre-flight SMTP settings without sending (best-effort)\nif (!StringUtils.hasText(smtpHost) || port <= 0) {\n    throw new ServerWebInputException(\"SMTP host and port are required\");\n}","typeGuard":null,"tryCatchPattern":"try {\n    mailSender.send(message);\n} catch (MailException e) {\n    log.error(\"SMTP send failed\", e);\n    throw new ServerWebInputException(\"Failed to send email, please check your email configuration.\", null, e);\n}","preventionTips":["Validate SMTP host/port/credentials shape before test-send.","Match the encryption mode (SSL vs STARTTLS) to the provider's requirement.","Use app passwords for providers that disable basic auth.","Read the logged MailException root cause before changing config."],"tags":["notification","email","smtp","configuration","bad-request"],"backgroundTag":null,"analyzedSha":"d2f5165f9c8f055ffcb3fa9c3f4032821a7b68c8","analyzedAt":"2026-08-14T00:18:38.915Z","schemaVersion":2},"datasetVersion":"2026-08-14T05:17:29.042Z"}