package console import ( "fmt" "os" "path/filepath" "strings" "time" "yunyan/pb" "yunyan/sys/email" "github.com/gin-gonic/gin" ) // sendSmtpEmail 生产设备码后把授权码清单(CSV 附件)邮件下发给厂家。 // // 与其它 JSON 接口不同,这是 multipart 表单:字段 to/cc/bcc/subject/content + 可选附件 file。 // modules/api 版从 RPCX session 元数据取文件路径;console 直连 gin,直接解析 multipart: // 落临时文件 → SendMailForFile 带附件发送 → 删临时文件。无附件则发纯文本。 // 走全局 email 系统,与选中应用无关,故在 handleWeb 中先于设备域分派。 func (this *serverComp) sendSmtpEmail(c *gin.Context) { to := strings.TrimSpace(c.PostForm("to")) subject := c.PostForm("subject") content := c.PostForm("content") if to == "" { writeErr(c, pb.ErrorCode_ReqParameterError, "收件人(to)不能为空") return } recipients := splitMails(to) recipients = append(recipients, splitMails(c.PostForm("cc"))...) recipients = append(recipients, splitMails(c.PostForm("bcc"))...) if len(recipients) == 0 { writeErr(c, pb.ErrorCode_ReqParameterError, "收件人(to)不能为空") return } // 附件可选:无附件发纯文本,有附件落临时文件再带附件发。 fileHeader, ferr := c.FormFile("file") if ferr != nil { if err := email.SendMail(subject, content, recipients...); err != nil { writeErr(c, pb.ErrorCode_SystemError, "邮件发送失败: "+err.Error()) return } writeOK(c, &pb.ApiSendsmtpemailResp{}) return } tmpPath := filepath.Join(os.TempDir(), fmt.Sprintf("console_mail_%d_%s", time.Now().UnixNano(), filepath.Base(fileHeader.Filename))) if err := c.SaveUploadedFile(fileHeader, tmpPath); err != nil { writeErr(c, pb.ErrorCode_SystemError, "附件保存失败: "+err.Error()) return } defer os.Remove(tmpPath) if err := email.SendMailForFile(subject, content, tmpPath, fileHeader.Filename, recipients...); err != nil { writeErr(c, pb.ErrorCode_SystemError, "邮件发送失败: "+err.Error()) return } writeOK(c, &pb.ApiSendsmtpemailResp{}) } // splitMails 按逗号拆收件人,去空白与空项。 func splitMails(s string) []string { out := make([]string, 0) for _, p := range strings.Split(s, ",") { if p = strings.TrimSpace(p); p != "" { out = append(out, p) } } return out }