diff --git a/common/constants.go b/common/constants.go index 5118da70..6caa7f5c 100644 --- a/common/constants.go +++ b/common/constants.go @@ -80,6 +80,7 @@ var InsecureTLSConfig = &tls.Config{InsecureSkipVerify: true} var SMTPServer = "" var SMTPPort = 587 var SMTPSSLEnabled = false +var SMTPForceAuthLogin = false var SMTPAccount = "" var SMTPFrom = "" var SMTPToken = "" diff --git a/common/email.go b/common/email.go index 9f574f06..c43ddec9 100644 --- a/common/email.go +++ b/common/email.go @@ -19,6 +19,20 @@ func generateMessageID() (string, error) { return fmt.Sprintf("<%d.%s@%s>", time.Now().UnixNano(), GetRandomString(12), domain), nil } +func shouldUseSMTPLoginAuth() bool { + if SMTPForceAuthLogin { + return true + } + return isOutlookServer(SMTPAccount) || slices.Contains(EmailLoginAuthServerList, SMTPServer) +} + +func getSMTPAuth() smtp.Auth { + if shouldUseSMTPLoginAuth() { + return LoginAuth(SMTPAccount, SMTPToken) + } + return smtp.PlainAuth("", SMTPAccount, SMTPToken, SMTPServer) +} + func SendEmail(subject string, receiver string, content string) error { if SMTPFrom == "" { // for compatibility SMTPFrom = SMTPAccount @@ -38,7 +52,7 @@ func SendEmail(subject string, receiver string, content string) error { "Message-ID: %s\r\n"+ // 添加 Message-ID 头 "Content-Type: text/html; charset=UTF-8\r\n\r\n%s\r\n", receiver, SystemName, SMTPFrom, encodedSubject, time.Now().Format(time.RFC1123Z), id, content)) - auth := smtp.PlainAuth("", SMTPAccount, SMTPToken, SMTPServer) + auth := getSMTPAuth() addr := fmt.Sprintf("%s:%d", SMTPServer, SMTPPort) to := strings.Split(receiver, ";") var err error @@ -80,9 +94,6 @@ func SendEmail(subject string, receiver string, content string) error { if err != nil { return err } - } else if isOutlookServer(SMTPAccount) || slices.Contains(EmailLoginAuthServerList, SMTPServer) { - auth = LoginAuth(SMTPAccount, SMTPToken) - err = smtp.SendMail(addr, auth, SMTPFrom, to, mail) } else { err = smtp.SendMail(addr, auth, SMTPFrom, to, mail) } diff --git a/model/option.go b/model/option.go index 967fa0aa..efa8c01d 100644 --- a/model/option.go +++ b/model/option.go @@ -62,6 +62,7 @@ func InitOptionMap() { common.OptionMap["SMTPAccount"] = "" common.OptionMap["SMTPToken"] = "" common.OptionMap["SMTPSSLEnabled"] = strconv.FormatBool(common.SMTPSSLEnabled) + common.OptionMap["SMTPForceAuthLogin"] = strconv.FormatBool(common.SMTPForceAuthLogin) common.OptionMap["Notice"] = "" common.OptionMap["About"] = "" common.OptionMap["HomePageContent"] = "" @@ -233,7 +234,7 @@ func updateOptionMap(key string, value string) (err error) { common.ImageDownloadPermission = intValue } } - if strings.HasSuffix(key, "Enabled") || key == "DefaultCollapseSidebar" || key == "DefaultUseAutoGroup" { + if strings.HasSuffix(key, "Enabled") || key == "DefaultCollapseSidebar" || key == "DefaultUseAutoGroup" || key == "SMTPForceAuthLogin" { boolValue := value == "true" switch key { case "PasswordRegisterEnabled": @@ -308,6 +309,8 @@ func updateOptionMap(key string, value string) (err error) { setting.StopOnSensitiveEnabled = boolValue case "SMTPSSLEnabled": common.SMTPSSLEnabled = boolValue + case "SMTPForceAuthLogin": + common.SMTPForceAuthLogin = boolValue case "WorkerAllowHttpImageRequestEnabled": system_setting.WorkerAllowHttpImageRequestEnabled = boolValue case "DefaultUseAutoGroup": diff --git a/web/bun.lock b/web/bun.lock index e3b293cb..9a841922 100644 --- a/web/bun.lock +++ b/web/bun.lock @@ -1,5 +1,6 @@ { "lockfileVersion": 1, + "configVersion": 0, "workspaces": { "": { "name": "react-template", @@ -10,7 +11,7 @@ "@visactor/react-vchart": "~1.8.8", "@visactor/vchart": "~1.8.8", "@visactor/vchart-semi-theme": "~1.8.8", - "axios": "1.12.0", + "axios": "1.13.5", "clsx": "^2.1.1", "dayjs": "^1.11.11", "history": "^5.3.0", @@ -776,7 +777,7 @@ "autoprefixer": ["autoprefixer@10.4.21", "", { "dependencies": { "browserslist": "^4.24.4", "caniuse-lite": "^1.0.30001702", "fraction.js": "^4.3.7", "normalize-range": "^0.1.2", "picocolors": "^1.1.1", "postcss-value-parser": "^4.2.0" }, "peerDependencies": { "postcss": "^8.1.0" }, "bin": { "autoprefixer": "bin/autoprefixer" } }, "sha512-O+A6LWV5LDHSJD3LjHYoNi4VLsj/Whi7k6zG12xTYaU4cQ8oxQGckXNX8cRHK5yOZ/ppVHe0ZBXGzSV9jXdVbQ=="], - "axios": ["axios@1.12.0", "", { "dependencies": { "follow-redirects": "^1.15.6", "form-data": "^4.0.4", "proxy-from-env": "^1.1.0" } }, "sha512-oXTDccv8PcfjZmPGlWsPSwtOJCZ/b6W5jAMCNcfwJbCzDckwG0jrYJFaWH1yvivfCXjVzV/SPDEhMB3Q+DSurg=="], + "axios": ["axios@1.13.5", "", { "dependencies": { "follow-redirects": "^1.15.11", "form-data": "^4.0.5", "proxy-from-env": "^1.1.0" } }, "sha512-cz4ur7Vb0xS4/KUN0tPWe44eqxrIu31me+fbang3ijiNscE129POzipJJA6zniq2C/Z6sJCjMimjS8Lc/GAs8Q=="], "babel-plugin-macros": ["babel-plugin-macros@3.1.0", "", { "dependencies": { "@babel/runtime": "^7.12.5", "cosmiconfig": "^7.0.0", "resolve": "^1.19.0" } }, "sha512-Cg7TFGpIr01vOQNODXOOaGz2NpCU5gl8x1qJFbb6hbZxR7XrcE2vtbAsTAbJ7/xwJtUuJEw8K8Zr/AE0LHlesg=="], @@ -1104,13 +1105,13 @@ "flatted": ["flatted@3.3.3", "", {}, "sha512-GX+ysw4PBCz0PzosHDepZGANEuFCMLrnRTiEy9McGjmkCQYwRq4A/X786G/fjM/+OjsWSU1ZrY5qyARZmO/uwg=="], - "follow-redirects": ["follow-redirects@1.15.9", "", {}, "sha512-gew4GsXizNgdoRyqmyfMHyAmXsZDk6mHkSxZFCzW9gwlbtOW44CDtYavM+y+72qD/Vq2l550kMF52DT8fOLJqQ=="], + "follow-redirects": ["follow-redirects@1.15.11", "", {}, "sha512-deG2P0JfjrTxl50XGCDyfI97ZGVCxIpfKYmfyrQ54n5FO/0gfIES8C/Psl6kWVDolizcaaxZJnTS0QSMxvnsBQ=="], "for-in": ["for-in@1.0.2", "", {}, "sha512-7EwmXrOjyL+ChxMhmG5lnW9MPt1aIeZEwKhQzoBUdTV0N3zuwWDZYVJatDvZ2OyzPUvdIAZDsCetk3coyMfcnQ=="], "foreground-child": ["foreground-child@3.3.1", "", { "dependencies": { "cross-spawn": "^7.0.6", "signal-exit": "^4.0.1" } }, "sha512-gIXjKqtFuWEgzFRJA9WCQeSJLZDjgJUOMCMzxtvFq/37KojM1BFGufqsCy0r4qSQmYLsZYMeyRqzIWOMup03sw=="], - "form-data": ["form-data@4.0.4", "", { "dependencies": { "asynckit": "^0.4.0", "combined-stream": "^1.0.8", "es-set-tostringtag": "^2.1.0", "hasown": "^2.0.2", "mime-types": "^2.1.12" } }, "sha512-KrGhL9Q4zjj0kiUt5OO4Mr/A/jlI2jDYs5eHBpYHPcBEVSiipAvn2Ko2HnPe20rmcuuvMHNdZFp+4IlGTMF0Ow=="], + "form-data": ["form-data@4.0.5", "", { "dependencies": { "asynckit": "^0.4.0", "combined-stream": "^1.0.8", "es-set-tostringtag": "^2.1.0", "hasown": "^2.0.2", "mime-types": "^2.1.12" } }, "sha512-8RipRLol37bNs2bhoV67fiTEvdTrbMUYcFTiy3+wuuOnUog2QBHCZWXDRijWQfAkhBj2Uf5UnVaiWwA5vdd82w=="], "fraction.js": ["fraction.js@4.3.7", "", {}, "sha512-ZsDfxO51wGAXREY55a7la9LScWpwv9RxIrYABrlvOFBlH/ShPnrtsXeuUIfXKKOVicNxQ+o8JTbJvjS4M89yew=="], diff --git a/web/src/components/settings/SystemSetting.jsx b/web/src/components/settings/SystemSetting.jsx index 91ef3645..63b20c70 100644 --- a/web/src/components/settings/SystemSetting.jsx +++ b/web/src/components/settings/SystemSetting.jsx @@ -91,6 +91,7 @@ const SystemSetting = () => { EmailDomainRestrictionEnabled: '', EmailAliasRestrictionEnabled: '', SMTPSSLEnabled: '', + SMTPForceAuthLogin: '', EmailDomainWhitelist: [], TelegramOAuthEnabled: '', TelegramBotToken: '', @@ -182,6 +183,7 @@ const SystemSetting = () => { case 'EmailDomainRestrictionEnabled': case 'EmailAliasRestrictionEnabled': case 'SMTPSSLEnabled': + case 'SMTPForceAuthLogin': case 'LinuxDOOAuthEnabled': case 'discord.enabled': case 'oidc.enabled': @@ -1335,6 +1337,15 @@ const SystemSetting = () => { > {t('启用SMTP SSL')} +