更新
This commit is contained in:
@@ -0,0 +1,144 @@
|
||||
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 ""
|
||||
}
|
||||
Reference in New Issue
Block a user