mirror of
https://github.com/jhillyerd/inbucket.git
synced 2025-12-17 17:47:03 +00:00
163 lines
4.2 KiB
Go
163 lines
4.2 KiB
Go
package message
|
|
|
|
import (
|
|
"bytes"
|
|
"io"
|
|
"net/mail"
|
|
"strings"
|
|
"time"
|
|
|
|
"github.com/jhillyerd/enmime"
|
|
"github.com/jhillyerd/inbucket/pkg/msghub"
|
|
"github.com/jhillyerd/inbucket/pkg/policy"
|
|
"github.com/jhillyerd/inbucket/pkg/storage"
|
|
"github.com/jhillyerd/inbucket/pkg/stringutil"
|
|
)
|
|
|
|
// Manager is the interface controllers use to interact with messages.
|
|
type Manager interface {
|
|
Deliver(
|
|
to *policy.Recipient,
|
|
from string,
|
|
recipients []*policy.Recipient,
|
|
prefix string,
|
|
content []byte,
|
|
) (id string, err error)
|
|
GetMetadata(mailbox string) ([]*Metadata, error)
|
|
GetMessage(mailbox, id string) (*Message, error)
|
|
PurgeMessages(mailbox string) error
|
|
RemoveMessage(mailbox, id string) error
|
|
SourceReader(mailbox, id string) (io.ReadCloser, error)
|
|
MailboxForAddress(address string) (string, error)
|
|
}
|
|
|
|
// StoreManager is a message Manager backed by the storage.Store.
|
|
type StoreManager struct {
|
|
Store storage.Store
|
|
Hub *msghub.Hub
|
|
}
|
|
|
|
// Deliver submits a new message to the store.
|
|
func (s *StoreManager) Deliver(
|
|
to *policy.Recipient,
|
|
from string,
|
|
recipients []*policy.Recipient,
|
|
prefix string,
|
|
source []byte,
|
|
) (string, error) {
|
|
// TODO enmime is too heavy for this step, only need header.
|
|
// Go's header parsing isn't good enough, so this is blocked on enmime issue #64.
|
|
env, err := enmime.ReadEnvelope(bytes.NewReader(source))
|
|
if err != nil {
|
|
return "", err
|
|
}
|
|
fromaddr, err := env.AddressList("From")
|
|
if err != nil || len(fromaddr) == 0 {
|
|
fromaddr = []*mail.Address{{Address: from}}
|
|
}
|
|
toaddr, err := env.AddressList("To")
|
|
if err != nil {
|
|
toaddr = make([]*mail.Address, len(recipients))
|
|
for i, torecip := range recipients {
|
|
toaddr[i] = &torecip.Address
|
|
}
|
|
}
|
|
delivery := &Delivery{
|
|
Meta: Metadata{
|
|
Mailbox: to.Mailbox,
|
|
From: fromaddr[0],
|
|
To: toaddr,
|
|
Date: time.Now(),
|
|
Subject: env.GetHeader("Subject"),
|
|
},
|
|
Reader: io.MultiReader(strings.NewReader(prefix), bytes.NewReader(source)),
|
|
}
|
|
id, err := s.Store.AddMessage(delivery)
|
|
if err != nil {
|
|
return "", err
|
|
}
|
|
if s.Hub != nil {
|
|
// Broadcast message information.
|
|
broadcast := msghub.Message{
|
|
Mailbox: to.Mailbox,
|
|
ID: id,
|
|
From: delivery.From().String(),
|
|
To: stringutil.StringAddressList(delivery.To()),
|
|
Subject: delivery.Subject(),
|
|
Date: delivery.Date(),
|
|
Size: delivery.Size(),
|
|
}
|
|
s.Hub.Dispatch(broadcast)
|
|
}
|
|
return id, nil
|
|
}
|
|
|
|
// GetMetadata returns a slice of metadata for the specified mailbox.
|
|
func (s *StoreManager) GetMetadata(mailbox string) ([]*Metadata, error) {
|
|
messages, err := s.Store.GetMessages(mailbox)
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
metas := make([]*Metadata, len(messages))
|
|
for i, sm := range messages {
|
|
metas[i] = makeMetadata(sm)
|
|
}
|
|
return metas, nil
|
|
}
|
|
|
|
// GetMessage returns the specified message.
|
|
func (s *StoreManager) GetMessage(mailbox, id string) (*Message, error) {
|
|
sm, err := s.Store.GetMessage(mailbox, id)
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
r, err := sm.Source()
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
env, err := enmime.ReadEnvelope(r)
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
_ = r.Close()
|
|
header := makeMetadata(sm)
|
|
return &Message{Metadata: *header, env: env}, nil
|
|
}
|
|
|
|
// PurgeMessages removes all messages from the specified mailbox.
|
|
func (s *StoreManager) PurgeMessages(mailbox string) error {
|
|
return s.Store.PurgeMessages(mailbox)
|
|
}
|
|
|
|
// RemoveMessage deletes the specified message.
|
|
func (s *StoreManager) RemoveMessage(mailbox, id string) error {
|
|
return s.Store.RemoveMessage(mailbox, id)
|
|
}
|
|
|
|
// SourceReader allows the stored message source to be read.
|
|
func (s *StoreManager) SourceReader(mailbox, id string) (io.ReadCloser, error) {
|
|
sm, err := s.Store.GetMessage(mailbox, id)
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
return sm.Source()
|
|
}
|
|
|
|
// MailboxForAddress parses an email address to return the canonical mailbox name.
|
|
func (s *StoreManager) MailboxForAddress(mailbox string) (string, error) {
|
|
return policy.ParseMailboxName(mailbox)
|
|
}
|
|
|
|
// makeMetadata populates Metadata from a storage.Message.
|
|
func makeMetadata(m storage.Message) *Metadata {
|
|
return &Metadata{
|
|
Mailbox: m.Mailbox(),
|
|
ID: m.ID(),
|
|
From: m.From(),
|
|
To: m.To(),
|
|
Date: m.Date(),
|
|
Subject: m.Subject(),
|
|
Size: m.Size(),
|
|
}
|
|
}
|