diff --git a/internal/service/user_service.go b/internal/service/user_service.go index a22ee7e..f63bbb4 100644 --- a/internal/service/user_service.go +++ b/internal/service/user_service.go @@ -130,8 +130,7 @@ func (svc *UserService) SendEmailVerifyCode(ctx context.Context, emailAddr strin code := fmt.Sprintf("%06d", rand.Intn(1000000)) - subject := "Your verification code" - body := fmt.Sprintf("Your verification code is: %s\nIt will expire in 10 minutes.", code) + subject, body := email.BuildVerifyCodeEmail(emailAddr, code) if err := email.Send(ctx, emailAddr, subject, body); err != nil { log.Error(ctx, "func", "SendEmailVerifyCode", "msg", "send email error", "error", err) return err diff --git a/pkg/email/template.go b/pkg/email/template.go new file mode 100644 index 0000000..adf82c3 --- /dev/null +++ b/pkg/email/template.go @@ -0,0 +1,166 @@ +package email + +import "fmt" + +// BuildVerifyCodeEmail returns a locale-appropriate subject and HTML body for +// the verification code email. Chinese domains get a Chinese email; all others +// get an English one. +func BuildVerifyCodeEmail(toEmail, code string) (subject, body string) { + domain := toEmail[lastIndex(toEmail, '@')+1:] + if chineseDomainRe.MatchString(domain) { + return buildVerifyCodeZH(code) + } + return buildVerifyCodeEN(code) +} + +func buildVerifyCodeZH(code string) (subject, body string) { + subject = "您的验证码" + body = fmt.Sprintf(` + + + + +验证码 + + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + +
+ TexPixel +
+

验证您的邮箱

+

+ 请使用以下验证码完成注册。验证码仅对您本人有效,请勿分享给他人。 +

+ + + + + + +
+ %s +
+ +

+ 验证码 10 分钟内有效,请尽快使用 +

+
+
+
+

+ 如果您没有请求此验证码,可以忽略本邮件,您的账户仍然安全。
+ © 2025 TexPixel. 保留所有权利。 +

+
+
+ +`, code) + return +} + +func buildVerifyCodeEN(code string) (subject, body string) { + subject = "Your verification code" + body = fmt.Sprintf(` + + + + +Verification Code + + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + +
+ TexPixel +
+

Verify your email address

+

+ Use the verification code below to complete your registration. Never share this code with anyone. +

+ + + + + + +
+ %s +
+ +

+ This code expires in 10 minutes +

+
+
+
+

+ If you didn’t request this code, you can safely ignore this email. Your account is still secure.
+ © 2025 TexPixel. All rights reserved. +

+
+
+ +`, code) + return +} + +// lastIndex returns the last index of sep in s, or -1. +func lastIndex(s string, sep byte) int { + for i := len(s) - 1; i >= 0; i-- { + if s[i] == sep { + return i + } + } + return -1 +}