Semaphore/util/mailer/mailer.go
Thomas Boerger 5c8b87620e
feat: refactoring of alerts and send correct email alerts
Previously the sent email alerts have been missing mandatory headers
like `Date` and it was also missing content type, content transfer
encoding and mime version. I have taken proper examples form the
unmaintained gomail library to build right emails.

Besides that I have refactored the calls for alerts, they git the same
structure now and it should be prepared to inject custom templates for
all altering methods at some later point. Generally it is prepared for a
more flexible alert handling.
2024-03-03 20:12:28 +01:00

161 lines
2.0 KiB
Go

package mailer
import (
"bytes"
"net"
"net/smtp"
"strings"
"text/template"
"time"
)
const (
mailerBase = "MIME-version: 1.0\r\n" +
"Content-Type: text/plain; charset=UTF-8\r\n" +
"Content-Transfer-Encoding: quoted-printable\r\n" +
"Date: {{ .Date }}\r\n" +
"To: {{ .To }}\r\n" +
"From: {{ .From }}\r\n" +
"Subject: {{ .Subject }}\r\n\r\n" +
"{{ .Body }}"
)
var (
r = strings.NewReplacer(
"\r\n", "",
"\r", "",
"\n", "",
"%0a", "",
"%0d", "",
)
)
// Send simply sends the defined mail via SMTP.
func Send(
secure bool,
host string,
port string,
username,
password,
from,
to,
subject string,
content string,
) error {
body := bytes.NewBufferString("")
tpl, err := template.New("").Parse(mailerBase)
if err != nil {
return err
}
if err := tpl.Execute(body, struct {
Date string
To string
From string
Subject string
Body string
}{
Date: time.Now().UTC().Format(time.RFC1123),
To: r.Replace(to),
From: r.Replace(from),
Subject: r.Replace(subject),
Body: content,
}); err != nil {
return err
}
if secure {
return plainauth(
host,
port,
username,
password,
from,
to,
body,
)
}
return anonymous(
host,
port,
from,
to,
body,
)
}
func plainauth(
host string,
port string,
username string,
password string,
from string,
to string,
body *bytes.Buffer,
) error {
return smtp.SendMail(
net.JoinHostPort(
host,
port,
),
smtp.PlainAuth(
"",
username,
password,
host,
),
from,
[]string{to},
body.Bytes(),
)
}
func anonymous(
host string,
port string,
from string,
to string,
body *bytes.Buffer,
) error {
c, err := smtp.Dial(
net.JoinHostPort(
host,
port,
),
)
if err != nil {
return err
}
defer c.Close()
if err := c.Mail(
r.Replace(from),
); err != nil {
return err
}
if err = c.Rcpt(
r.Replace(to),
); err != nil {
return err
}
w, err := c.Data()
if err != nil {
return err
}
defer w.Close()
if _, err := body.WriteTo(w); err != nil {
return err
}
return nil
}