9bb4b09a04
CI / Lint + build + test (push) Has been cancelled
Post-repair hardware validation pipeline for Proxmox cluster hosts. Go orchestrator + in-image agent + mkosi live image + bundled dnsmasq PXE + SQLite + HTMX/SSE UI + notify registry + janitor + full docs.
82 lines
2.3 KiB
Go
82 lines
2.3 KiB
Go
package notify
|
|
|
|
import (
|
|
"context"
|
|
"fmt"
|
|
"net/smtp"
|
|
"strconv"
|
|
"strings"
|
|
)
|
|
|
|
// SMTPNotifier sends a plaintext email. Authentication is left at zero
|
|
// (LAN-only relay assumed); if the configured server requires auth the
|
|
// Send call will return an error and the Registry will log it.
|
|
//
|
|
// SendMailFn is overridable so tests can capture the outgoing message
|
|
// without needing a live SMTP server.
|
|
type SMTPNotifier struct {
|
|
NameStr string
|
|
Host string
|
|
Port int
|
|
From string
|
|
To []string
|
|
SendMailFn func(addr string, a smtp.Auth, from string, to []string, msg []byte) error
|
|
}
|
|
|
|
func NewSMTP(name, host string, port int, from string, to []string) *SMTPNotifier {
|
|
if port == 0 {
|
|
port = 25
|
|
}
|
|
return &SMTPNotifier{
|
|
NameStr: name,
|
|
Host: host,
|
|
Port: port,
|
|
From: from,
|
|
To: to,
|
|
SendMailFn: smtp.SendMail,
|
|
}
|
|
}
|
|
|
|
func (s *SMTPNotifier) Name() string { return s.NameStr }
|
|
|
|
func (s *SMTPNotifier) Send(ctx context.Context, ev Event) error {
|
|
if s.Host == "" || s.From == "" || len(s.To) == 0 {
|
|
return fmt.Errorf("smtp: incomplete config (host/from/to required)")
|
|
}
|
|
// We intentionally don't honour ctx here — net/smtp.SendMail doesn't
|
|
// accept a context; for a LAN relay with a short TCP timeout the
|
|
// Registry's goroutine will outlive the timeout but only by seconds.
|
|
addr := s.Host + ":" + strconv.Itoa(s.Port)
|
|
msg := buildEmail(s.From, s.To, ev)
|
|
return s.SendMailFn(addr, nil, s.From, s.To, msg)
|
|
}
|
|
|
|
// buildEmail produces an RFC 5322 minimal message. Body is plaintext;
|
|
// the URL is appended so the recipient can click through from a text
|
|
// mail client. No MIME for now — keeps it robust.
|
|
func buildEmail(from string, to []string, ev Event) []byte {
|
|
var b strings.Builder
|
|
b.WriteString("From: ")
|
|
b.WriteString(from)
|
|
b.WriteString("\r\n")
|
|
b.WriteString("To: ")
|
|
b.WriteString(strings.Join(to, ", "))
|
|
b.WriteString("\r\n")
|
|
subject := ev.Title
|
|
if subject == "" {
|
|
subject = "[vetting] " + string(ev.Kind)
|
|
}
|
|
b.WriteString("Subject: ")
|
|
b.WriteString(subject)
|
|
b.WriteString("\r\n")
|
|
b.WriteString("Content-Type: text/plain; charset=UTF-8\r\n")
|
|
b.WriteString("\r\n")
|
|
b.WriteString(ev.Body)
|
|
if ev.URL != "" {
|
|
b.WriteString("\r\n\r\nLink: ")
|
|
b.WriteString(ev.URL)
|
|
}
|
|
b.WriteString("\r\n")
|
|
return []byte(b.String())
|
|
}
|