feat: reopen SMTP connection if closed

This commit is contained in:
Balázs Keresztury 2024-07-06 16:40:01 +02:00
parent 1e7871b5c0
commit bfb71926a3
Signed by: belidzs
GPG Key ID: C0E76527468BF0C2

View File

@ -19,6 +19,9 @@ package mail
import (
"context"
"crypto/tls"
"errors"
"fmt"
"strings"
"time"
"code.vikunja.io/api/pkg/config"
@ -46,7 +49,6 @@ func getClient() (*mail.Client, error) {
if config.MailerForceSSL.GetBool() {
tlsPolicy = mail.TLSMandatory
}
opts := []mail.Option{
mail.WithTLSPortPolicy(tlsPolicy),
mail.WithTLSConfig(&tls.Config{
@ -82,6 +84,38 @@ func getClient() (*mail.Client, error) {
)
}
func resilientSend(client *mail.Client, message *mail.Msg) error {
const maxRetries = 3
retries := 0
for retries < maxRetries {
log.Debug("Sending mail")
err := client.Send(message)
if err == nil {
log.Debug("Mail sent")
return nil
}
var sendError *mail.SendError
_ = errors.As(err, &sendError)
if sendError.Reason != mail.ErrConnCheck {
// only ErrConnCheck is retried, other exceptions are thrown
return err
}
log.Warning("Connection was closed, reconnecting before retrying")
err = client.DialWithContext(context.Background())
if err != nil {
return err
}
log.Debug("Connection re-established")
retries++
}
return errors.New(fmt.Sprintf("could not send mail after %d retries", retries))
}
// StartMailDaemon starts the mail daemon
func StartMailDaemon() {
Queue = make(chan *mail.Msg, config.MailerQueuelength.GetInt())
@ -110,25 +144,32 @@ func StartMailDaemon() {
return
}
if !open {
log.Debug("Opening connection to mail server")
err = c.DialWithContext(context.Background())
if err != nil {
log.Errorf("Error during connect to smtp server: %s", err)
break
}
log.Debug("Connected to mail server")
open = true
}
err = c.Send(m)
err = resilientSend(c, m)
if err != nil {
log.Errorf("Error when sending mail: %s", err)
log.Errorf("Error sending mail: %s", err)
break
}
// Close the connection to the SMTP server if no email was sent in
// the last 30 seconds.
case <-time.After(config.MailerQueueTimeout.GetDuration() * time.Second):
if open {
log.Debug("Closing connection to mail server due to queue timeout")
open = false
err = c.Close()
if err != nil {
if strings.HasPrefix(err.Error(), "not connected to SMTP server") {
log.Warning("Connection to mail server was already closed")
break
}
log.Errorf("Error closing the mail server connection: %s\n", err)
break
}