feat: contact form backend for linux and freebsd servers
Test / test (push) Successful in 2m1s
Release / gates (push) Successful in 1m57s
Release / build (amd64, freebsd) (push) Successful in 1m26s
Release / build (amd64, linux) (push) Successful in 1m30s
Release / build (arm64, freebsd) (push) Successful in 1m28s
Release / build (arm64, linux) (push) Successful in 1m49s
Release / build (loong64, linux) (push) Successful in 1m30s
Release / build (riscv64, linux) (push) Successful in 1m29s
Release / release (push) Successful in 41s
Test / test (push) Successful in 2m1s
Release / gates (push) Successful in 1m57s
Release / build (amd64, freebsd) (push) Successful in 1m26s
Release / build (amd64, linux) (push) Successful in 1m30s
Release / build (arm64, freebsd) (push) Successful in 1m28s
Release / build (arm64, linux) (push) Successful in 1m49s
Release / build (loong64, linux) (push) Successful in 1m30s
Release / build (riscv64, linux) (push) Successful in 1m29s
Release / release (push) Successful in 41s
Assisted-by: GLM 5.3 Flash
This commit is contained in:
@@ -0,0 +1,59 @@
|
||||
// Copyright (c) 2026 Petr Balvín <opensource@petrbalvin.org> (https://petrbalvin.org)
|
||||
// SPDX-License-Identifier: MIT
|
||||
|
||||
//go:build linux || freebsd
|
||||
|
||||
package email
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"fmt"
|
||||
"net/smtp"
|
||||
"time"
|
||||
|
||||
"sourcedock.dev/petrbalvin/nuntius/internal/config"
|
||||
)
|
||||
|
||||
// SendConfirmation mails the double opt-in link directly to the subscriber.
|
||||
// It uses the form's SMTP identity so replies land at the owner address,
|
||||
// which is set as Reply-To.
|
||||
func (s *FormSender) SendConfirmation(to, link string) error {
|
||||
auth := smtp.PlainAuth("", s.form.SMTP.User, s.form.SMTP.Password, s.form.SMTP.Host)
|
||||
msg := composeConfirmation(s.form.From, to, s.form.To, s.form, link)
|
||||
return sendMail(s.form.SMTP, auth, s.form.From, []string{to}, msg, s.form.SMTP.Timeout(), s.TLSConfig)
|
||||
}
|
||||
|
||||
// composeConfirmation builds a single-part plain-text message. Transactional
|
||||
// confirmations stay deliberately simple: one link, no tracking, no HTML.
|
||||
// The subject prefix and the footer brand come from the form's
|
||||
// configuration; the defaults reproduce the earlier wording.
|
||||
func composeConfirmation(from, to, replyToOwner string, form *config.Form, link string) []byte {
|
||||
subject := "Confirm your subscription"
|
||||
if prefix := form.EmailSubjectPrefix(); prefix != "" {
|
||||
subject = fmt.Sprintf("[%s/%s] %s", prefix, form.Name, subject)
|
||||
}
|
||||
|
||||
var body bytes.Buffer
|
||||
fmt.Fprintf(&body, "Hi,\r\n\r\n")
|
||||
fmt.Fprintf(&body, "someone signed this address up for the \"%s\" form.\r\n", form.Name)
|
||||
fmt.Fprintf(&body, "If that was you, please confirm the subscription by opening:\r\n\r\n")
|
||||
fmt.Fprintf(&body, " %s\r\n\r\n", link)
|
||||
fmt.Fprintf(&body, "If it was not you, ignore this message and nothing will happen:\r\n")
|
||||
fmt.Fprintf(&body, "the request expires automatically without any action from you.\r\n\r\n")
|
||||
if brand := form.Brand(); brand != "" {
|
||||
fmt.Fprintf(&body, "Delivered by %s\r\n", brand)
|
||||
}
|
||||
|
||||
var msg bytes.Buffer
|
||||
msg.WriteString(fmt.Sprintf("From: %s\r\n", sanitizeHeaderValue(from)))
|
||||
msg.WriteString(fmt.Sprintf("To: %s\r\n", sanitizeHeaderValue(to)))
|
||||
msg.WriteString(fmt.Sprintf("Subject: %s\r\n", sanitizeHeaderValue(subject)))
|
||||
msg.WriteString(fmt.Sprintf("Date: %s\r\n", time.Now().UTC().Format(time.RFC1123Z)))
|
||||
msg.WriteString(fmt.Sprintf("Reply-To: %s\r\n", sanitizeHeaderValue(replyToOwner)))
|
||||
msg.WriteString("MIME-Version: 1.0\r\n")
|
||||
msg.WriteString("Content-Type: text/plain; charset=UTF-8\r\n")
|
||||
msg.WriteString("Content-Transfer-Encoding: 8bit\r\n")
|
||||
msg.WriteString("\r\n")
|
||||
msg.Write(body.Bytes())
|
||||
return msg.Bytes()
|
||||
}
|
||||
Reference in New Issue
Block a user