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 }