mailbox

package
v0.2.1 Latest Latest
Warning

This package is not in the latest version of its module.

Go to latest
Published: Oct 23, 2026 License: MIT Imports: 15 Imported by: 0

Documentation

Overview

Package mailbox is the plain mailbox side of lfr: addresses that receive and send like any mail account, with aliases, catch-alls, plus-addressing, forwarding, folders, flags and full-text search.

Index

Constants

View Source
const MaxMessage = 20 << 20

MaxMessage is the largest message lfr sends: Outlook's limit, below Gmail's 25 MB, counted after attachments are encoded.

Variables

View Source
var ErrExists = errors.New("already exists")

ErrExists reports a duplicate address.

View Source
var Folders = []string{"inbox", "junk", "archive", "sent", "trash"}

Folders a message can be in.

Functions

func BlobRefs

func BlobRefs(ctx context.Context, db interface {
	QueryRowContext(context.Context, string, ...any) *sql.Row
}, hash string) (int, error)

BlobRefs counts what still points at a stored blob: messages, sends not done yet, issue images. A blob is removed only when this says 0 without an error; a failed query must never read as "unused".

func ValidFolder

func ValidFolder(f string) (string, bool)

ValidFolder reports whether f is a folder name, accepting "spam" for junk.

Types

type Delivery

type Delivery struct {
	MailboxID int64
	Folder    string
	Raw       []byte
	Parsed    *msg.Parsed // parsed when nil
	Spam      float64
	Verdict   string
	Features  string
	Seen      bool
}

Delivery is one message to store.

type Mailbox

type Mailbox struct {
	ID       int64     `json:"id"`
	DomainID int64     `json:"-"`
	Address  string    `json:"address"`
	Name     string    `json:"name,omitempty"`
	Forward  string    `json:"forward,omitempty"`
	Aliases  []string  `json:"aliases,omitempty"`
	Catchall bool      `json:"catchall,omitempty"`
	Unread   int       `json:"unread"`
	Total    int       `json:"total"`
	Created  time.Time `json:"created"`
}

Mailbox is one address that receives mail.

type Message

type Message struct {
	Summary
	ReplyTo string           `json:"reply_to,omitempty"`
	Text    string           `json:"text"`
	HTML    string           `json:"html,omitempty"`
	Files   []msg.Attachment `json:"attachments_list,omitempty"`
	Verdict json.RawMessage  `json:"verdict,omitempty"` // authentication and spam details
	// SenderCheck says in one line whether the From address is proven: a
	// "Rechnung" from an unproven sender is the classic phishing mail.
	SenderCheck string `json:"sender_check,omitempty"`
	// Events summarizes calendar invitations: what, when, where.
	Events     []string `json:"events,omitempty"`
	Trained    string   `json:"trained,omitempty"`
	Blob       string   `json:"-"`
	Features   string   `json:"-"`
	InReplyTo  string   `json:"in_reply_to,omitempty"`
	References []string `json:"references,omitempty"`
}

Message is a message as read.

type Outbox

type Outbox interface {
	EnqueueTx(ctx context.Context, tx outbound.Execer, items ...outbound.Item) (int, error)
	Wake()
}

Outbox queues messages for delivery.

type Query

type Query struct {
	Mailbox string // address; empty for every mailbox
	Folder  string // empty: inbox
	Unread  bool
	Thread  string
	Search  string // full-text query
	Limit   int
	Before  int64 // only messages with a smaller ID, for paging
}

Query selects messages to list.

type ReplyRequest

type ReplyRequest struct {
	Text  string     `json:"text"`
	HTML  string     `json:"html,omitempty"`
	All   bool       `json:"all"`
	Quote bool       `json:"quote"`
	Files []msg.File `json:"-"`
}

ReplyRequest answers a stored message.

type SendRequest

type SendRequest struct {
	From       string     `json:"from"` // a mailbox address (or one of its aliases)
	To         []string   `json:"to"`
	Cc         []string   `json:"cc,omitempty"`
	Bcc        []string   `json:"bcc,omitempty"`
	ReplyTo    string     `json:"reply_to,omitempty"`
	Subject    string     `json:"subject"`
	Text       string     `json:"text"`
	HTML       string     `json:"html,omitempty"`
	Files      []msg.File `json:"-"`
	InReplyTo  string     `json:"-"`
	References []string   `json:"-"`
}

SendRequest is a message to send from a mailbox.

type Service

type Service struct {
	DB    *store.DB
	Blobs *blob.Store
	Now   func() time.Time
}

Service is the mailbox store.

func (*Service) Add

func (s *Service) Add(ctx context.Context, email, name string) (*Mailbox, error)

Add creates a mailbox.

func (*Service) AddAlias

func (s *Service) AddAlias(ctx context.Context, alias, target string) error

AddAlias makes alias deliver into the mailbox target; both share a domain.

func (*Service) ByID

func (s *Service) ByID(ctx context.Context, id int64) (*Mailbox, error)

ByID loads a mailbox.

func (*Service) Counts

func (s *Service) Counts(ctx context.Context, mailboxID int64) (map[string]int, error)

Counts returns message counts per folder of a mailbox.

func (*Service) Delete

func (s *Service) Delete(ctx context.Context, id int64, purge bool) error

Delete moves a message to trash, or removes it for good when purge is set or it already is in trash.

func (*Service) Deliver

func (s *Service) Deliver(ctx context.Context, d Delivery) (int64, error)

Deliver stores a message in a mailbox and indexes it for search.

func (*Service) Flag

func (s *Service) Flag(ctx context.Context, id int64, flag string, on bool) error

Flag sets seen, flagged or answered.

func (*Service) ForwardItem

func (s *Service) ForwardItem(ctx context.Context, mb *Mailbox, raw []byte, p *msg.Parsed) (outbound.Item, error)

ForwardItem prepares a delivered message for the mailbox's forwarding address. The copy is sent as the mailbox (so SPF, DKIM and DMARC pass for lfr's domain) with the original sender as Reply-To.

func (*Service) Get

func (s *Service) Get(ctx context.Context, email string) (*Mailbox, error)

Get loads a mailbox by its address.

func (*Service) List

func (s *Service) List(ctx context.Context, domain string) ([]*Mailbox, error)

List returns mailboxes, of one domain when domain is set.

func (*Service) Messages

func (s *Service) Messages(ctx context.Context, q Query) ([]Summary, error)

Messages returns matching messages, newest first.

func (*Service) Move

func (s *Service) Move(ctx context.Context, id int64, folder string) (string, error)

Move puts a message into folder and returns the folder it came from.

func (*Service) Purge

func (s *Service) Purge(ctx context.Context, folder string, age time.Duration) (int, error)

Purge removes messages that sat in folder longer than age, returning how many.

func (*Service) Raw

func (s *Service) Raw(ctx context.Context, id int64) ([]byte, error)

Raw returns the stored message as received or sent.

func (*Service) Read

func (s *Service) Read(ctx context.Context, id int64, seen bool) (*Message, error)

Read returns a full message; seen marks it read.

func (*Service) Remove

func (s *Service) Remove(ctx context.Context, email string) error

Remove deletes a mailbox with all its messages.

func (*Service) RemoveAlias

func (s *Service) RemoveAlias(ctx context.Context, alias string) error

RemoveAlias deletes an alias.

func (*Service) Rename

func (s *Service) Rename(ctx context.Context, from, to string) (*Mailbox, error)

Rename moves a mailbox to a new address, keeping its messages.

func (*Service) Reply

func (s *Service) Reply(ctx context.Context, out Outbox, id int64, r ReplyRequest) (int64, error)

Reply answers message id from the mailbox that holds it.

func (*Service) Resolve

func (s *Service) Resolve(ctx context.Context, rcpt string) (int64, bool, error)

Resolve finds the mailbox mail to rcpt belongs in: the exact address, an alias, the address without its +tag, then the domain's catch-all.

func (*Service) Send

func (s *Service) Send(ctx context.Context, out Outbox, req SendRequest) (int64, error)

Send composes a message, files it in the sender's sent folder and queues it for every recipient. It returns the ID of the sent-folder copy.

func (*Service) SetCatchall

func (s *Service) SetCatchall(ctx context.Context, domain, target string) error

SetCatchall routes unknown addresses of domain to target; empty target turns it off.

func (*Service) SetTrained

func (s *Service) SetTrained(ctx context.Context, id int64, label string) error

SetTrained records how a message was used to train the spam filter.

func (*Service) Update

func (s *Service) Update(ctx context.Context, email string, name, forward *string) (*Mailbox, error)

Update changes the display name and forwarding address; nil leaves a value as is.

type Summary

type Summary struct {
	ID          int64     `json:"id"`
	Mailbox     string    `json:"mailbox"`
	Folder      string    `json:"folder"`
	From        string    `json:"from"`
	FromName    string    `json:"from_name,omitempty"`
	To          []string  `json:"to,omitempty"`
	Cc          []string  `json:"cc,omitempty"`
	Subject     string    `json:"subject"`
	Snippet     string    `json:"snippet"`
	Date        time.Time `json:"date"`
	Received    time.Time `json:"received"`
	Seen        bool      `json:"seen"`
	Flagged     bool      `json:"flagged"`
	Answered    bool      `json:"answered"`
	Attachments int       `json:"attachments"`
	Spam        float64   `json:"spam"`
	Thread      string    `json:"thread"`
	Size        int       `json:"size"`
	MessageID   string    `json:"message_id,omitempty"`
}

Summary is a message as listed.

Jump to

Keyboard shortcuts

? : This menu
/ : Search site
f or F : Jump to
y or Y : Canonical URL