Improved performance by manually handling mail server communication instead of using smtp.SendMail() and thus opening a new connection for each mail
This commit is contained in:
parent
8c427cc571
commit
e5cc0ccbf1
1 changed files with 72 additions and 18 deletions
84
mail.go
84
mail.go
|
@ -3,12 +3,13 @@
|
||||||
package main
|
package main
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
"crypto/tls"
|
||||||
"encoding/base64"
|
"encoding/base64"
|
||||||
"fmt"
|
"fmt"
|
||||||
"net/mail"
|
"net/mail"
|
||||||
"net/smtp"
|
"net/smtp"
|
||||||
"slices"
|
"slices"
|
||||||
"strings"
|
"time"
|
||||||
)
|
)
|
||||||
|
|
||||||
const MAIL_LINE_SEP = "\r\n"
|
const MAIL_LINE_SEP = "\r\n"
|
||||||
|
@ -22,13 +23,7 @@ func (c MailContent) serializeValidMail(from string, to string) []byte {
|
||||||
// We'll send base64 encoded Subject & Body, because we Dschörmäns have umlauts
|
// We'll send base64 encoded Subject & Body, because we Dschörmäns have umlauts
|
||||||
// and I'm too lazy to encode ä into =E4 and so on
|
// and I'm too lazy to encode ä into =E4 and so on
|
||||||
subjectEncoded := base64.StdEncoding.EncodeToString([]byte(c.Subject))
|
subjectEncoded := base64.StdEncoding.EncodeToString([]byte(c.Subject))
|
||||||
bodyEncoded := base64.StdEncoding.EncodeToString(
|
bodyEncoded := base64.StdEncoding.EncodeToString([]byte(c.Body))
|
||||||
[]byte( // ensure that all lines end with CRLF
|
|
||||||
strings.ReplaceAll(
|
|
||||||
strings.ReplaceAll(c.Body, "\n", MAIL_LINE_SEP), "\r\r", "\r",
|
|
||||||
),
|
|
||||||
),
|
|
||||||
)
|
|
||||||
data := []byte(fmt.Sprintf(
|
data := []byte(fmt.Sprintf(
|
||||||
"Content-Type: text/plain; charset=\"utf-8\"\r\nContent-Transfer-Encoding: base64\r\nFrom: %v%vTo: %v%vSubject: =?utf-8?b?%v?=%v%v%v",
|
"Content-Type: text/plain; charset=\"utf-8\"\r\nContent-Transfer-Encoding: base64\r\nFrom: %v%vTo: %v%vSubject: =?utf-8?b?%v?=%v%v%v",
|
||||||
from, MAIL_LINE_SEP,
|
from, MAIL_LINE_SEP,
|
||||||
|
@ -68,6 +63,7 @@ func (r Recipient) filterAndSendNotices(notices []WidNotice, template MailTempla
|
||||||
logger.debug("Generating and sending mails to " + r.Address + " ...")
|
logger.debug("Generating and sending mails to " + r.Address + " ...")
|
||||||
cacheHits := 0
|
cacheHits := 0
|
||||||
cacheMisses := 0
|
cacheMisses := 0
|
||||||
|
mails := [][]byte{}
|
||||||
for _, n := range filteredNotices {
|
for _, n := range filteredNotices {
|
||||||
var data []byte
|
var data []byte
|
||||||
cacheResult := (*cache)[n.Uuid]
|
cacheResult := (*cache)[n.Uuid]
|
||||||
|
@ -86,22 +82,80 @@ func (r Recipient) filterAndSendNotices(notices []WidNotice, template MailTempla
|
||||||
// add to cache
|
// add to cache
|
||||||
(*cache)[n.Uuid] = data
|
(*cache)[n.Uuid] = data
|
||||||
}
|
}
|
||||||
err := smtp.SendMail(
|
mails = append(mails, data)
|
||||||
fmt.Sprintf("%v:%v", smtpConfig.ServerHost, smtpConfig.ServerPort),
|
}
|
||||||
|
logger.debug(fmt.Sprintf("%v mail cache hits, %v misses", cacheHits, cacheMisses))
|
||||||
|
err := sendMails(
|
||||||
|
smtpConfig,
|
||||||
auth,
|
auth,
|
||||||
smtpConfig.From,
|
r.Address,
|
||||||
[]string{r.Address},
|
mails,
|
||||||
data,
|
|
||||||
)
|
)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
}
|
|
||||||
logger.debug(fmt.Sprintf("%v mail cache hits, %v misses", cacheHits, cacheMisses))
|
|
||||||
logger.debug("Successfully sent all mails to " + r.Address)
|
logger.debug("Successfully sent all mails to " + r.Address)
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func sendMails(smtpConf SmtpSettings, auth smtp.Auth, to string, data [][]byte) error {
|
||||||
|
addr := fmt.Sprintf("%v:%v", smtpConf.ServerHost, smtpConf.ServerPort)
|
||||||
|
logger.debug("Connecting to mail server at " + addr + " ...")
|
||||||
|
connection, err := smtp.Dial(addr)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
defer connection.Close()
|
||||||
|
// can leave out connection.Hello
|
||||||
|
hasTlsExt, _ := connection.Extension("starttls")
|
||||||
|
if hasTlsExt {
|
||||||
|
err = connection.StartTLS(&tls.Config{ServerName: smtpConf.ServerHost})
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
logger.debug("Mail Server supports TLS")
|
||||||
|
} else {
|
||||||
|
logger.debug("Mail Server doesn't support TLS")
|
||||||
|
}
|
||||||
|
logger.debug("Authenticating to mail server ...")
|
||||||
|
err = connection.Auth(auth)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
if logger.LogLevel >= 3 {
|
||||||
|
fmt.Printf("DEBUG %v Sending mails to server ", time.Now().Format("2006/01/02 15:04:05.000000"))
|
||||||
|
}
|
||||||
|
for _, d := range data {
|
||||||
|
err = connection.Mail(smtpConf.From)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
err = connection.Rcpt(to)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
writer, err := connection.Data()
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
_, err = writer.Write(d)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
err = writer.Close()
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
if logger.LogLevel >= 3 {
|
||||||
|
print(".")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if logger.LogLevel >= 3 {
|
||||||
|
print("\n")
|
||||||
|
}
|
||||||
|
return connection.Quit()
|
||||||
|
}
|
||||||
|
|
||||||
func mailAddressIsValid(address string) bool {
|
func mailAddressIsValid(address string) bool {
|
||||||
_, err := mail.ParseAddress(address);
|
_, err := mail.ParseAddress(address);
|
||||||
return err == nil
|
return err == nil
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue