package domain import ( "fmt" "github.com/matcornic/hermes/v2" ) // BuildHermesHTML renders a hermes email skeleton (same stack as stand-alone notification). func BuildHermesHTML(brand Brand, body hermes.Body) (string, error) { if brand.Name == "" { brand.Name = "Harbor Desk" } h := hermes.Hermes{ Product: hermes.Product{ Name: brand.Name, Link: brand.Link, Logo: brand.LogoURL, Copyright: brand.Copyright, }, // Default theme is clean table layout suitable for most clients. } return h.GenerateHTML(hermes.Email{Body: body}) } // GenerateTemplate builds subject + HTML for a kind/lang with placeholders still present // ({{.Username}}, {{.VerifyCode}}, {{.ResetURL}} filled later by text/template). func GenerateTemplate(kind TemplateKind, lang Language, brand Brand) (*EmailTemplate, error) { lang = NormalizeLanguage(string(lang)) switch kind { case TemplateEmailVerify: return generateEmailVerify(lang, brand) case TemplatePasswordReset: return generatePasswordReset(lang, brand) default: return nil, fmt.Errorf("unknown template kind: %s", kind) } } func generateEmailVerify(lang Language, brand Brand) (*EmailTemplate, error) { var subject string var intros, outros []string var instr string if lang == LangEnUS { subject = "[Harbor Desk] Verify your email" intros = []string{ "You received this email because we need to verify your email address.", } instr = "Copy this verification code and enter it on the verify page (valid for 30 minutes):" outros = []string{ "If you did not create an account, you can ignore this email.", "This is an automated message — please do not reply.", } } else { subject = "【Harbor Desk】信箱驗證碼" intros = []string{ "您收到此信是因為需要驗證您的電子信箱。", } instr = "請複製下方驗證碼,於 30 分鐘內到驗證頁完成確認:" outros = []string{ "若您並未註冊帳號,可忽略本信。", "此為系統自動發出,請勿直接回覆。", } } html, err := BuildHermesHTML(brand, hermes.Body{ Name: "{{.Username}}", Intros: intros, Actions: []hermes.Action{ { Instructions: instr, InviteCode: "{{.VerifyCode}}", }, }, Outros: outros, Signature: " ", }) if err != nil { return nil, err } return &EmailTemplate{Subject: subject, Body: html}, nil } func generatePasswordReset(lang Language, brand Brand) (*EmailTemplate, error) { var subject, instr, btnText string var intros, outros []string if lang == LangEnUS { subject = "[Harbor Desk] Reset your password" intros = []string{ "You received this email because a password reset was requested for your account.", } instr = "Copy this code, or open the reset page with the button below (valid for 30 minutes):" btnText = "Open reset page" outros = []string{ "If you did not request a password reset, no further action is required.", "This is an automated message — please do not reply.", } } else { subject = "【Harbor Desk】重設密碼" intros = []string{ "您收到此信是因為有人申請重設您的帳戶密碼。", } instr = "請複製下方驗證碼,或點擊按鈕開啟重設頁(30 分鐘內有效):" btnText = "開啟重設密碼頁" outros = []string{ "若您並未申請重設密碼,可忽略本信,帳號不會有任何變更。", "此為系統自動發出,請勿直接回覆。", } } actions := []hermes.Action{ { Instructions: instr, InviteCode: "{{.VerifyCode}}", }, } // Button only when ResetURL placeholder present after render — always include; // empty href is avoided by filling ResetURL before send. actions = append(actions, hermes.Action{ Button: hermes.Button{ Color: "#0f172a", Text: btnText, Link: "{{.ResetURL}}", }, }) html, err := BuildHermesHTML(brand, hermes.Body{ Name: "{{.Username}}", Intros: intros, Actions: actions, Outros: outros, Signature: " ", }) if err != nil { return nil, err } return &EmailTemplate{Subject: subject, Body: html}, nil }