mirror of
https://github.com/certimate-go/certimate.git
synced 2026-09-24 23:10:13 +08:00
refactor: extract smtp module
This commit is contained in:
@@ -0,0 +1,96 @@
|
||||
package smtp
|
||||
|
||||
import (
|
||||
"context"
|
||||
"errors"
|
||||
"fmt"
|
||||
"time"
|
||||
|
||||
"github.com/wneessen/go-mail"
|
||||
|
||||
xtls "github.com/certimate-go/certimate/pkg/utils/tls"
|
||||
)
|
||||
|
||||
type Client struct {
|
||||
cli *mail.Client
|
||||
}
|
||||
|
||||
func NewClient(config *Config) (*Client, error) {
|
||||
if config == nil {
|
||||
return nil, fmt.Errorf("the configuration of SMTP client is nil")
|
||||
}
|
||||
|
||||
client, err := createSmtpClient(config)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
return &Client{cli: client}, nil
|
||||
}
|
||||
|
||||
func (c *Client) Close() error {
|
||||
return c.cli.Close()
|
||||
}
|
||||
|
||||
func (c *Client) Send(ctx context.Context, msg *Message) error {
|
||||
if err := c.cli.DialAndSendWithContext(ctx, msg); err != nil {
|
||||
errShouldBeIgnored := false
|
||||
|
||||
// REF: https://github.com/wneessen/go-mail/issues/463
|
||||
var sendErr *mail.SendError
|
||||
if errors.As(err, &sendErr) {
|
||||
if sendErr.Reason == mail.ErrSMTPReset {
|
||||
errShouldBeIgnored = true
|
||||
}
|
||||
}
|
||||
|
||||
if !errShouldBeIgnored {
|
||||
return fmt.Errorf("smtp: %w", err)
|
||||
}
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func createSmtpClient(config *Config) (*mail.Client, error) {
|
||||
clientOptions := []mail.Option{
|
||||
mail.WithSMTPAuth(mail.SMTPAuthAutoDiscover),
|
||||
mail.WithUsername(config.Username),
|
||||
mail.WithPassword(config.Password),
|
||||
mail.WithTimeout(time.Second * 30),
|
||||
}
|
||||
|
||||
if config.Port == 0 {
|
||||
if config.UseSsl {
|
||||
clientOptions = append(clientOptions, mail.WithPort(mail.DefaultPortSSL))
|
||||
} else {
|
||||
clientOptions = append(clientOptions, mail.WithPort(mail.DefaultPort))
|
||||
}
|
||||
} else {
|
||||
clientOptions = append(clientOptions, mail.WithPort(config.Port))
|
||||
}
|
||||
|
||||
if config.UseSsl {
|
||||
tlsConfig := xtls.NewCompatibleConfig()
|
||||
if config.SkipTlsVerify {
|
||||
tlsConfig.InsecureSkipVerify = true
|
||||
} else {
|
||||
tlsConfig.ServerName = config.Host
|
||||
}
|
||||
|
||||
clientOptions = append(clientOptions, mail.WithSSL())
|
||||
clientOptions = append(clientOptions, mail.WithTLSConfig(tlsConfig))
|
||||
clientOptions = append(clientOptions, mail.WithTLSPolicy(mail.TLSMandatory))
|
||||
} else {
|
||||
clientOptions = append(clientOptions, mail.WithTLSPolicy(mail.TLSOpportunistic))
|
||||
}
|
||||
|
||||
client, err := mail.NewClient(config.Host, clientOptions...)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("smtp: %w", err)
|
||||
}
|
||||
|
||||
client.ErrorHandlerRegistry.RegisterHandler("smtp.qq.com", "QUIT", &wQQMailQuitErrorHandler{})
|
||||
|
||||
return client, nil
|
||||
}
|
||||
@@ -0,0 +1,20 @@
|
||||
package smtp
|
||||
|
||||
const (
|
||||
defaultPort int = 25
|
||||
)
|
||||
|
||||
type Config struct {
|
||||
Host string
|
||||
Port int
|
||||
Username string
|
||||
Password string
|
||||
UseSsl bool
|
||||
SkipTlsVerify bool
|
||||
}
|
||||
|
||||
func NewDefaultConfig() *Config {
|
||||
return &Config{
|
||||
Port: defaultPort,
|
||||
}
|
||||
}
|
||||
+1
-1
@@ -1,4 +1,4 @@
|
||||
package email
|
||||
package smtp
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
@@ -0,0 +1,18 @@
|
||||
package smtp
|
||||
|
||||
import (
|
||||
"github.com/wneessen/go-mail"
|
||||
)
|
||||
|
||||
type Message = mail.Msg
|
||||
|
||||
func NewMessage() *Message {
|
||||
return mail.NewMsg()
|
||||
}
|
||||
|
||||
type MIMEType = mail.ContentType
|
||||
|
||||
const (
|
||||
MIMETypeTextHTML MIMEType = mail.TypeTextHTML
|
||||
MIMETypeTextPlain MIMEType = mail.TypeTextPlain
|
||||
)
|
||||
@@ -5,12 +5,9 @@ import (
|
||||
"errors"
|
||||
"fmt"
|
||||
"log/slog"
|
||||
"time"
|
||||
|
||||
"github.com/wneessen/go-mail"
|
||||
|
||||
"github.com/certimate-go/certimate/internal/tools/smtp"
|
||||
"github.com/certimate-go/certimate/pkg/core/notifier"
|
||||
xtls "github.com/certimate-go/certimate/pkg/utils/tls"
|
||||
)
|
||||
|
||||
type NotifierConfig struct {
|
||||
@@ -62,49 +59,23 @@ func (n *Notifier) SetLogger(logger *slog.Logger) {
|
||||
}
|
||||
|
||||
func (n *Notifier) Notify(ctx context.Context, subject string, message string) (*notifier.NotifyResult, error) {
|
||||
clientOptions := []mail.Option{
|
||||
mail.WithSMTPAuth(mail.SMTPAuthAutoDiscover),
|
||||
mail.WithUsername(n.config.Username),
|
||||
mail.WithPassword(n.config.Password),
|
||||
mail.WithTimeout(time.Second * 30),
|
||||
}
|
||||
|
||||
if n.config.SmtpPort == 0 {
|
||||
if n.config.SmtpTls {
|
||||
clientOptions = append(clientOptions, mail.WithPort(mail.DefaultPortSSL))
|
||||
} else {
|
||||
clientOptions = append(clientOptions, mail.WithPort(mail.DefaultPort))
|
||||
}
|
||||
} else {
|
||||
clientOptions = append(clientOptions, mail.WithPort(int(n.config.SmtpPort)))
|
||||
}
|
||||
|
||||
if n.config.SmtpTls {
|
||||
tlsConfig := xtls.NewCompatibleConfig()
|
||||
if n.config.AllowInsecureConnections {
|
||||
tlsConfig.InsecureSkipVerify = true
|
||||
} else {
|
||||
tlsConfig.ServerName = n.config.SmtpHost
|
||||
}
|
||||
|
||||
clientOptions = append(clientOptions, mail.WithSSL())
|
||||
clientOptions = append(clientOptions, mail.WithTLSConfig(tlsConfig))
|
||||
clientOptions = append(clientOptions, mail.WithTLSPolicy(mail.TLSMandatory))
|
||||
} else {
|
||||
clientOptions = append(clientOptions, mail.WithTLSPolicy(mail.TLSOpportunistic))
|
||||
}
|
||||
|
||||
client, err := mail.NewClient(n.config.SmtpHost, clientOptions...)
|
||||
clientCfg := smtp.NewDefaultConfig()
|
||||
clientCfg.Host = n.config.SmtpHost
|
||||
clientCfg.Port = int(n.config.SmtpPort)
|
||||
clientCfg.Username = n.config.Username
|
||||
clientCfg.Password = n.config.Password
|
||||
clientCfg.UseSsl = n.config.SmtpTls
|
||||
clientCfg.SkipTlsVerify = n.config.AllowInsecureConnections
|
||||
client, err := smtp.NewClient(clientCfg)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("failed to create smtp client: %w", err)
|
||||
return nil, fmt.Errorf("failed to create SMTP client: %w", err)
|
||||
}
|
||||
|
||||
client.ErrorHandlerRegistry.RegisterHandler("smtp.qq.com", "QUIT", &wQQMailQuitErrorHandler{})
|
||||
defer client.Close()
|
||||
|
||||
msg := mail.NewMsg()
|
||||
msg := smtp.NewMessage()
|
||||
msg.Subject(subject)
|
||||
msg.SetBodyString(mail.TypeTextPlain, message)
|
||||
msg.SetBodyString(smtp.MIMETypeTextPlain, message)
|
||||
if n.config.SenderName == "" {
|
||||
msg.From(n.config.SenderAddress)
|
||||
} else {
|
||||
@@ -112,20 +83,8 @@ func (n *Notifier) Notify(ctx context.Context, subject string, message string) (
|
||||
}
|
||||
msg.To(n.config.ReceiverAddress)
|
||||
|
||||
if err := client.DialAndSend(msg); err != nil {
|
||||
errShouldBeIgnored := false
|
||||
|
||||
// REF: https://github.com/wneessen/go-mail/issues/463
|
||||
var sendErr *mail.SendError
|
||||
if errors.As(err, &sendErr) {
|
||||
if sendErr.Reason == mail.ErrSMTPReset {
|
||||
errShouldBeIgnored = true
|
||||
}
|
||||
}
|
||||
|
||||
if !errShouldBeIgnored {
|
||||
return nil, fmt.Errorf("failed to send mail: %w", err)
|
||||
}
|
||||
if err := client.Send(ctx, msg); err != nil {
|
||||
return nil, fmt.Errorf("failed to send mail: %w", err)
|
||||
}
|
||||
|
||||
return ¬ifier.NotifyResult{}, nil
|
||||
|
||||
Reference in New Issue
Block a user