mail/smtp.go
2025-08-01 00:54:13 +08:00

136 lines
3.7 KiB
Go

package mail
import (
"crypto/tls"
"encoding/base64"
"io"
"apigo.cc/gojs"
"apigo.cc/gojs/goja"
"github.com/jaytaylor/html2text"
"github.com/ssgo/u"
"gopkg.in/gomail.v2"
)
type SendOption struct {
Cc []string
Bcc []string
Html bool
Attachments []Attachment
Embeds []Attachment
}
func (obj *Mailbox) Send(vm *goja.Runtime, to []string, subject, content string, option *SendOption) error {
logger := gojs.GetLogger(vm)
msg := gomail.NewMessage()
if obj.senderName != "" {
msg.SetHeader("From", msg.FormatAddress(obj.username, obj.senderName))
} else {
msg.SetHeader("From", obj.username)
}
msg.SetHeader("To", to...)
msg.SetHeader("Subject", subject)
useHtml := false
if option != nil {
if len(option.Cc) > 0 {
msg.SetHeader("Cc", option.Cc...)
}
if len(option.Bcc) > 0 {
msg.SetHeader("Bcc", option.Bcc...)
}
if len(option.Attachments) > 0 {
for _, attachment := range option.Attachments {
if attachment.Path != "" {
if u.FileExists(attachment.Path) {
msg.Attach(attachment.Path)
} else {
logger.Error("mail attachment file not exists", "filename", attachment.Path, "to", to, "subject", subject)
}
} else if attachment.Data != "" {
if attachment.Name == "" {
attachment.Name = "attachment"
}
if attachment.ContentType == "" {
attachment.ContentType = "text/plain"
}
buf, err := base64.StdEncoding.DecodeString(attachment.Data)
if err != nil {
buf = []byte(attachment.Data)
}
msg.Attach(attachment.Name, gomail.SetCopyFunc(func(w io.Writer) error {
_, err := w.Write(buf)
return err
}), gomail.SetHeader(map[string][]string{
"Content-Type": {attachment.ContentType},
}))
}
}
}
if len(option.Embeds) > 0 {
for _, attachment := range option.Embeds {
if attachment.Path != "" {
if u.FileExists(attachment.Path) {
msg.Attach(attachment.Path)
} else {
logger.Error("mail embed file not exists", "filename", attachment.Path, "to", to, "subject", subject)
}
} else if attachment.Data != "" {
if attachment.Name == "" {
attachment.Name = "image"
}
if attachment.ContentType == "" {
attachment.ContentType = "image/png"
}
buf, err := base64.StdEncoding.DecodeString(attachment.Data)
if err != nil {
buf = []byte(attachment.Data)
}
msg.Embed(attachment.Name, gomail.SetCopyFunc(func(w io.Writer) error {
_, err := w.Write(buf)
return err
}), gomail.SetHeader(map[string][]string{
"Content-Type": {attachment.ContentType},
"Content-ID": {"<" + attachment.Name + ">"},
}))
}
}
}
useHtml = option.Html
}
if useHtml {
msg.SetBody("text/html", content)
textContent, err := html2text.FromString(content, html2text.Options{TextOnly: true, PrettyTables: true})
if err != nil {
logger.Error("convert html to text failed", "err", err, "to", to, "subject", subject, "content", content)
textContent = content
}
msg.AddAlternative("text/plain", textContent)
} else {
msg.SetBody("text/plain", content)
}
conn := gomail.NewDialer(obj.smtpHost, obj.smtpPort, obj.username, obj.password)
switch obj.smtpPort {
case 465:
conn.SSL = true
case 587:
conn.TLSConfig = &tls.Config{
ServerName: obj.smtpHost,
InsecureSkipVerify: false,
}
}
// conn.Auth = smtp.PlainAuth("", obj.username, obj.password, obj.smtpHost)
err := conn.DialAndSend(msg)
if err != nil {
logger.Error("send mail failed", "err", err.Error(), "to", to, "subject", "from", obj.username, subject, "content", content)
} else {
logger.Info("send mail success", "to", to, "from", obj.username, "subject", subject)
}
return err
}