forked from wrenn/wrenn
Add transactional email system via SMTP
Introduce internal/email package with SMTP sending, embedded HTML/text templates, and multipart MIME assembly. Emails use a generic EmailData struct (recipient name, message, optional button, optional closing) so new email types can be added without code changes. Wired into signup (welcome email), team creation, and team member addition. No-op mailer when SMTP_HOST is not configured.
This commit is contained in:
52
internal/email/templates.go
Normal file
52
internal/email/templates.go
Normal file
@ -0,0 +1,52 @@
|
||||
package email
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"embed"
|
||||
"fmt"
|
||||
"html/template"
|
||||
text_template "text/template"
|
||||
)
|
||||
|
||||
//go:embed templates/*.html templates/*.txt
|
||||
var templateFS embed.FS
|
||||
|
||||
// templates holds the parsed HTML and plain-text template sets.
|
||||
type templates struct {
|
||||
html *template.Template
|
||||
text *text_template.Template
|
||||
}
|
||||
|
||||
// mustLoadTemplates parses all embedded templates. Panics on error
|
||||
// because malformed templates are a build-time bug.
|
||||
func mustLoadTemplates() *templates {
|
||||
html, err := template.ParseFS(templateFS, "templates/*.html")
|
||||
if err != nil {
|
||||
panic(fmt.Sprintf("email: failed to parse HTML templates: %v", err))
|
||||
}
|
||||
|
||||
text, err := text_template.ParseFS(templateFS, "templates/*.txt")
|
||||
if err != nil {
|
||||
panic(fmt.Sprintf("email: failed to parse text templates: %v", err))
|
||||
}
|
||||
|
||||
return &templates{html: html, text: text}
|
||||
}
|
||||
|
||||
// renderHTML executes the HTML base template with the given data.
|
||||
func (t *templates) renderHTML(data EmailData) (string, error) {
|
||||
var buf bytes.Buffer
|
||||
if err := t.html.ExecuteTemplate(&buf, "base.html", data); err != nil {
|
||||
return "", fmt.Errorf("execute html template: %w", err)
|
||||
}
|
||||
return buf.String(), nil
|
||||
}
|
||||
|
||||
// renderText executes the plain-text base template with the given data.
|
||||
func (t *templates) renderText(data EmailData) (string, error) {
|
||||
var buf bytes.Buffer
|
||||
if err := t.text.ExecuteTemplate(&buf, "base.txt", data); err != nil {
|
||||
return "", fmt.Errorf("execute text template: %w", err)
|
||||
}
|
||||
return buf.String(), nil
|
||||
}
|
||||
Reference in New Issue
Block a user