Files
summercms/postcard/drivers.go
Jakub Zych b4fd8339fe feat(04-03): render registered mail templates through memory
- Parse Winter INI + == Markdown templates and Goldmark HTML
- Memory driver stores rendered subject, text, and HTML
- Caller selects -en siblings by full dotted name

Co-authored-by: Cursor <cursoragent@cursor.com>
2026-09-18 13:58:02 +02:00

68 lines
1.5 KiB
Go

package postcard
import (
"context"
"fmt"
"sync"
)
// Driver delivers a fully rendered message.
type Driver interface {
Send(ctx context.Context, msg RenderedMessage) error
}
// RenderedMessage is the validated payload a driver transmits.
type RenderedMessage struct {
To []string
Cc []string
Bcc []string
From string
ReplyTo string
Subject string
HTML string
Text string
}
// MemoryDriver stores rendered messages for tests. It is concurrency-safe.
type MemoryDriver struct {
mu sync.Mutex
messages []RenderedMessage
}
// NewMemoryDriver returns an empty in-memory driver.
func NewMemoryDriver() *MemoryDriver {
return &MemoryDriver{}
}
// Send appends msg to the in-memory log.
func (d *MemoryDriver) Send(_ context.Context, msg RenderedMessage) error {
if d == nil {
return fmt.Errorf("postcard: memory driver is nil")
}
d.mu.Lock()
defer d.mu.Unlock()
d.messages = append(d.messages, cloneRendered(msg))
return nil
}
// Messages returns a copy of stored messages in send order.
func (d *MemoryDriver) Messages() []RenderedMessage {
if d == nil {
return nil
}
d.mu.Lock()
defer d.mu.Unlock()
out := make([]RenderedMessage, len(d.messages))
for i, msg := range d.messages {
out[i] = cloneRendered(msg)
}
return out
}
func cloneRendered(msg RenderedMessage) RenderedMessage {
msg.To = append([]string(nil), msg.To...)
msg.Cc = append([]string(nil), msg.Cc...)
msg.Bcc = append([]string(nil), msg.Bcc...)
return msg
}