- 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>
68 lines
1.5 KiB
Go
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
|
|
}
|