Files
phishingclub/backend/service/mailHeader.go
T
2026-07-06 22:36:22 +02:00

78 lines
2.3 KiB
Go

package service
import (
"bytes"
"strings"
"text/template"
"github.com/phishingclub/phishingclub/model"
"github.com/wneessen/go-mail"
"go.uber.org/zap"
)
// sanitizeSMTPHeaderValue removes characters that are illegal in a single header
// line so a header value can never be used to inject additional headers, even if
// the underlying mail library stops encoding them. It strips all C0 control
// characters (including carriage return, line feed and NUL) and DEL.
func sanitizeSMTPHeaderValue(value string) string {
return strings.Map(func(r rune) rune {
if r < 0x20 || r == 0x7f {
return -1
}
return r
}, value)
}
// applyCustomSMTPHeaders sets the configured custom headers on the message.
//
// When templateData is not nil each header value is rendered with the same per
// recipient variables available in the email body and subject (for example
// {{.rID}} or {{.Email}}), using funcs as the template function map. Paths without
// a recipient context, such as the SMTP connectivity test, pass nil to send the
// values verbatim. Every value is sanitized before being set on the message.
func applyCustomSMTPHeaders(
msg *mail.Msg,
headers []*model.SMTPHeader,
templateData *map[string]any,
funcs template.FuncMap,
logger *zap.SugaredLogger,
) {
for _, header := range headers {
key := header.Key.MustGet().String()
value := header.Value.MustGet().String()
if templateData != nil {
value = renderSMTPHeaderValue(key, value, templateData, funcs, logger)
}
msg.SetGenHeader(mail.Header(key), sanitizeSMTPHeaderValue(value))
}
}
// renderSMTPHeaderValue renders a single header value as a template. On any parse
// or execution error it logs and falls back to the raw value so a broken header
// template never blocks a send.
func renderSMTPHeaderValue(
key string,
value string,
templateData *map[string]any,
funcs template.FuncMap,
logger *zap.SugaredLogger,
) string {
tmpl, err := template.New("smtpHeader").Funcs(funcs).Parse(value)
if err != nil {
logger.Warnw("failed to parse custom smtp header template, sending raw value",
"header", key,
"error", err,
)
return value
}
var buf bytes.Buffer
if err := tmpl.Execute(&buf, templateData); err != nil {
logger.Warnw("failed to execute custom smtp header template, sending raw value",
"header", key,
"error", err,
)
return value
}
return buf.String()
}