Files
mailx/from.go
T
2026-08-15 01:38:05 +08:00

145 lines
3.4 KiB
Go

package mailx
import (
"encoding/json"
"fmt"
"strings"
)
// FromBytes 从 JSON 字节构建消息(便捷入口,用于接入配置/存储)。
func FromBytes(data []byte) (*Message, error) {
var m Message
if err := json.Unmarshal(data, &m); err != nil {
return nil, fmt.Errorf("mailx: unmarshal message: %w", err)
}
return &m, nil
}
// FromMap 从 map 构建消息,常用字段自动映射:
// - from / to / cc / bcc / subject / text / html / body / replyto / reply_to
// - to/cc/bcc 可为 []string、[]any 或 "a@x.com,b@y.com" 分隔串
// - attachments: []map{name,path,data} 或 []string(path)
func FromMap(m map[string]any) (*Message, error) {
if m == nil {
return nil, fmt.Errorf("%w: map is nil", ErrInvalidConfig)
}
msg := &Message{}
var err error
str := func(keys ...string) string {
for _, k := range keys {
if v, ok := m[k].(string); ok {
return v
}
}
return ""
}
msg.From = str("from")
msg.Subject = str("subject")
msg.TextBody = firstNonEmptyStr(str("text"), str("textbody"), str("text_body"))
msg.Body = firstNonEmptyStr(str("html"), str("body"))
msg.ReplyTo = firstNonEmptyStr(str("replyto"), str("reply_to"))
if msg.To, err = toList(m["to"]); err != nil {
return nil, err
}
if msg.Cc, err = toList(m["cc"]); err != nil {
return nil, err
}
if msg.Bcc, err = toList(m["bcc"]); err != nil {
return nil, err
}
if atts, ok := m["attachments"]; ok {
msg.Attachments, err = toAttachments(atts)
if err != nil {
return nil, err
}
}
return msg, nil
}
// toList 将任意输入转为地址列表([]string、[]any 或逗号/分号分隔串)
func toList(v any) ([]string, error) {
switch t := v.(type) {
case nil:
return nil, nil
case []string:
return t, nil
case string:
var out []string
for _, p := range strings.FieldsFunc(t, func(r rune) bool { return r == ',' || r == ';' }) {
if p = strings.TrimSpace(p); p != "" {
out = append(out, p)
}
}
return out, nil
case []any:
out := make([]string, 0, len(t))
for _, item := range t {
if s, ok := item.(string); ok {
out = append(out, s)
}
}
return out, nil
default:
return nil, fmt.Errorf("mailx: invalid address list type %T", v)
}
}
// toAttachments 将 attachments 输入转为附件列表
func toAttachments(v any) ([]Attachment, error) {
switch t := v.(type) {
case []string:
out := make([]Attachment, 0, len(t))
for _, p := range t {
out = append(out, Attachment{Name: fileBaseName(p), Path: p})
}
return out, nil
case []map[string]any:
out := make([]Attachment, 0, len(t))
for _, mm := range t {
var att Attachment
if name, ok := mm["name"].(string); ok {
att.Name = name
}
if p, ok := mm["path"].(string); ok {
att.Path = p
if att.Name == "" {
att.Name = fileBaseName(p)
}
}
if d, ok := mm["data"]; ok {
if bs, ok := d.([]byte); ok {
att.Data = bs
}
}
out = append(out, att)
}
return out, nil
case []any:
return toAttachments(mapsFromAny(t))
default:
return nil, fmt.Errorf("mailx: invalid attachments type %T", v)
}
}
// mapsFromAny 将 []any 转为 []map[string]any(忽略非 map 元素)
func mapsFromAny(arr []any) []map[string]any {
out := make([]map[string]any, 0, len(arr))
for _, item := range arr {
if mm, ok := item.(map[string]any); ok {
out = append(out, mm)
}
}
return out
}
func firstNonEmptyStr(vals ...string) string {
for _, v := range vals {
if v != "" {
return v
}
}
return ""
}