Rewrite the service in Go and ship it as a static container
The PHP app, Apache, and .htaccess are replaced by a single Go binary (standard library only). Routing, the JSON response, the landing page, the shared email design, and all four parsers are ported with the same output; JSON object keys are kept in sender order via an ordered decoder. - mail.go: SMTP delivery with quoted-printable body and RFC 2047 subject - main.go: routing, client IP from the proxy, /healthz, -check flag - render.go: email shell, escaping, table helpers, generic renderer - parser_*.go: github, grafana, json, wxinteract - main_test.go: handler, response shape, IP forwarding, every parser - Dockerfile: multi-stage build to distroless static, non-root, HEALTHCHECK - deploy/webhooks.dixon.cx.service: systemd unit for the container - README and PARSER_PROMPT updated for Go; IMPLEMENTATION_SUMMARY removed
This commit is contained in:
@@ -0,0 +1,67 @@
|
||||
package main
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"mime"
|
||||
"mime/quotedprintable"
|
||||
"net/smtp"
|
||||
"os"
|
||||
"time"
|
||||
)
|
||||
|
||||
var (
|
||||
smtpAddr = envOr("SMTP_ADDR", "127.0.0.1:25")
|
||||
mailFrom = envOr("MAIL_FROM", "no-reply@dixon.cx")
|
||||
)
|
||||
|
||||
// sendMail is a variable so tests can capture messages instead of sending them.
|
||||
var sendMail = smtpSend
|
||||
|
||||
func smtpSend(to, subject, htmlBody string) error {
|
||||
c, err := smtp.Dial(smtpAddr)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
defer c.Close()
|
||||
if err := c.Mail(mailFrom); err != nil {
|
||||
return err
|
||||
}
|
||||
if err := c.Rcpt(to); err != nil {
|
||||
return err
|
||||
}
|
||||
w, err := c.Data()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
if _, err := w.Write(buildMessage(to, subject, htmlBody)); err != nil {
|
||||
return err
|
||||
}
|
||||
if err := w.Close(); err != nil {
|
||||
return err
|
||||
}
|
||||
return c.Quit()
|
||||
}
|
||||
|
||||
func buildMessage(to, subject, htmlBody string) []byte {
|
||||
host, _ := os.Hostname()
|
||||
var b []byte
|
||||
b = fmt.Appendf(b, "From: Webhook Call <%s>\r\n", mailFrom)
|
||||
b = fmt.Appendf(b, "To: <%s>\r\n", to)
|
||||
b = fmt.Appendf(b, "Subject: %s\r\n", mime.QEncoding.Encode("utf-8", subject))
|
||||
b = fmt.Appendf(b, "Date: %s\r\n", time.Now().Format(time.RFC1123Z))
|
||||
b = fmt.Appendf(b, "Message-ID: <%d.%d@%s>\r\n", time.Now().UnixNano(), os.Getpid(), host)
|
||||
b = append(b, "MIME-Version: 1.0\r\n"...)
|
||||
b = append(b, "Content-Type: text/html; charset=UTF-8\r\n"...)
|
||||
b = append(b, "Content-Transfer-Encoding: quoted-printable\r\n\r\n"...)
|
||||
qp := quotedprintable.NewWriter(sliceWriter{&b})
|
||||
_, _ = qp.Write([]byte(htmlBody))
|
||||
_ = qp.Close()
|
||||
return b
|
||||
}
|
||||
|
||||
type sliceWriter struct{ b *[]byte }
|
||||
|
||||
func (s sliceWriter) Write(p []byte) (int, error) {
|
||||
*s.b = append(*s.b, p...)
|
||||
return len(p), nil
|
||||
}
|
||||
Reference in New Issue
Block a user