Compare commits

..

2 Commits

Author SHA1 Message Date
AI Engineer
3d5f3ba909 feat(mail): 具名化 JS 导出并动态包裹错误(by AI) 2026-06-21 10:31:21 +08:00
AI Engineer
3173092d4f chore: align infrastructure to v1.5.x (by AI) 2026-06-11 22:27:55 +08:00
4 changed files with 75 additions and 35 deletions

View File

@ -1,5 +1,9 @@
# CHANGELOG # CHANGELOG
## v1.5.3 (2026-06-21)
- **JS 对齐**: 重构 JS 导出为具名函数,并引入 `jsmod.MakeError` 动态包装错误以获取调用栈。
- **依赖更新**: 升级依赖 `jsmod``v1.5.3``cast``v1.5.3``rand``v1.5.3``encoding``v1.5.4``shell``v1.5.3``safe``v1.5.2``id``v1.5.4``file``v1.5.5``config``v1.5.3``log``v1.5.8`
## v1.0.4 (2026-05-31) ## v1.0.4 (2026-05-31)
- **新增**: 注册到 `jsmod`。支持低代码环境下的邮件发送与接收。 - **新增**: 注册到 `jsmod`。支持低代码环境下的邮件发送与接收。
- 提供 `send`, `recv` 默认快捷操作。 - 提供 `send`, `recv` 默认快捷操作。

View File

@ -18,5 +18,6 @@
| 内存占用 | 低 | 采用流式处理及即时擦除 | | 内存占用 | 低 | 采用流式处理及即时擦除 |
## 验证结果 ## 验证结果
- **单元测试**: `go test -v ./...` 通过。 - **单元测试**: `go test -v ./...` 通过 (2026-06-21)
- **并发安全性**: 经过 `sync.RWMutex` 保护,支持多协程下注册 Handler 及发送。 - **并发安全性**: 经过 `sync.RWMutex` 保护,支持多协程下注册 Handler 及发送。
- **JS 错误调用栈**: JS 桥接层改用具名导出并使用 `jsmod.MakeError` 包裹错误,确保 JS 抛出异常时携带准确的 Go 运行时堆栈。

20
go.mod
View File

@ -3,11 +3,11 @@ module apigo.cc/go/mail
go 1.26.1 go 1.26.1
require ( require (
apigo.cc/go/cast v1.5.0 apigo.cc/go/cast v1.5.3
apigo.cc/go/file v1.5.0 apigo.cc/go/file v1.5.5
apigo.cc/go/jsmod v1.5.0 apigo.cc/go/jsmod v1.5.3
apigo.cc/go/log v1.5.0 apigo.cc/go/log v1.5.8
apigo.cc/go/safe v1.5.0 apigo.cc/go/safe v1.5.2
github.com/emersion/go-imap/v2 v2.0.0-beta.8 github.com/emersion/go-imap/v2 v2.0.0-beta.8
github.com/jaytaylor/html2text v0.0.0-20260303211410-1a4bdc82ecec github.com/jaytaylor/html2text v0.0.0-20260303211410-1a4bdc82ecec
github.com/jhillyerd/enmime v1.3.0 github.com/jhillyerd/enmime v1.3.0
@ -15,11 +15,11 @@ require (
) )
require ( require (
apigo.cc/go/config v1.5.0 // indirect apigo.cc/go/config v1.5.3 // indirect
apigo.cc/go/encoding v1.5.0 // indirect apigo.cc/go/encoding v1.5.4 // indirect
apigo.cc/go/id v1.5.0 // indirect apigo.cc/go/id v1.5.4 // indirect
apigo.cc/go/rand v1.5.0 // indirect apigo.cc/go/rand v1.5.3 // indirect
apigo.cc/go/shell v1.5.0 // indirect apigo.cc/go/shell v1.5.3 // indirect
github.com/cention-sany/utf7 v0.0.0-20170124080048-26cad61bd60a // indirect github.com/cention-sany/utf7 v0.0.0-20170124080048-26cad61bd60a // indirect
github.com/cespare/xxhash/v2 v2.3.0 // indirect github.com/cespare/xxhash/v2 v2.3.0 // indirect
github.com/clipperhouse/displaywidth v0.10.0 // indirect github.com/clipperhouse/displaywidth v0.10.0 // indirect

View File

@ -8,17 +8,36 @@ import (
func init() { func init() {
jsmod.Register("mail", map[string]any{ jsmod.Register("mail", map[string]any{
// 默认邮箱操作 (对齐 PascalCase) // 默认邮箱操作 (对齐 PascalCase)
"Send": func(to any, subject, content string, option *SendOption) error { "Send": jsSend,
var toList []string "Recv": jsRecv,
cast.Convert(&toList, to)
return Send(toList, subject, content, option)
},
"Recv": func(opt *RecvOption) (*RecvResult, error) {
return Recv(opt)
},
// 多实例获取 (对齐 PascalCase支持可选参数) // 多实例获取 (对齐 PascalCase支持可选参数)
"Mailbox": func(name *string) *jsMailbox { "Mailbox": jsMailboxGetter,
// 辅助工具
"FormatAddr": jsFormatAddr,
"ParseAddr": jsParseAddr,
})
}
func jsSend(to any, subject, content string, option *SendOption) error {
var toList []string
cast.Convert(&toList, to)
if err := Send(toList, subject, content, option); err != nil {
return jsmod.MakeError(err)
}
return nil
}
func jsRecv(opt *RecvOption) (*RecvResult, error) {
res, err := Recv(opt)
if err != nil {
return nil, jsmod.MakeError(err)
}
return res, nil
}
func jsMailboxGetter(name *string) *jsMailbox {
target := "default" target := "default"
if name != nil { if name != nil {
target = *name target = *name
@ -28,12 +47,18 @@ func init() {
return nil return nil
} }
return &jsMailbox{m: m} return &jsMailbox{m: m}
}, }
// 辅助工具 func jsFormatAddr(name, address string) string {
"FormatAddr": FormatAddr, return FormatAddr(name, address)
"ParseAddr": ParseAddr, }
})
func jsParseAddr(addr string) (string, string, error) {
name, address, err := ParseAddr(addr)
if err != nil {
return "", "", jsmod.MakeError(err)
}
return name, address, nil
} }
// jsMailbox 包装 Mailbox 实例 // jsMailbox 包装 Mailbox 实例
@ -44,13 +69,23 @@ type jsMailbox struct {
func (j *jsMailbox) Send(to any, subject, content string, option *SendOption) error { func (j *jsMailbox) Send(to any, subject, content string, option *SendOption) error {
var toList []string var toList []string
cast.Convert(&toList, to) cast.Convert(&toList, to)
return j.m.Send(toList, subject, content, option) if err := j.m.Send(toList, subject, content, option); err != nil {
return jsmod.MakeError(err)
}
return nil
} }
func (j *jsMailbox) Recv(opt *RecvOption) (*RecvResult, error) { func (j *jsMailbox) Recv(opt *RecvOption) (*RecvResult, error) {
return j.m.Recv(opt) res, err := j.m.Recv(opt)
if err != nil {
return nil, jsmod.MakeError(err)
}
return res, nil
} }
func (j *jsMailbox) Health() error { func (j *jsMailbox) Health() error {
return j.m.Health() if err := j.m.Health(); err != nil {
return jsmod.MakeError(err)
}
return nil
} }