mirror of
https://github.com/profullstack/agentbbs.git
synced 2026-08-13 14:27:27 +00:00
internal/mailbox is a transport-agnostic mail client for Founding Lifetime members: read, search, compose, send, reply, flag, delete. - types/transport/client: paid-gated facade returning JSON-serializable structs (same shapes as @logicsrc/plugin-agentmail) - memory.go: in-memory transport (tests/dev/reference) + tests - imap.go/smtp.go: real backend — go-imap/v2 (Dovecot IMAP, master-user login) + net/smtp submission via the co-located relay; go-message parses bodies/attachments - reader_tui.go: Bubble Tea reader for humans (list/read/flag/delete) - bot.go: JSON in/out mode for agents (ssh mail@host list|read|send|…) - wired as the paid "Mail" hub entry and the ssh mail@ route + auth.MailNames Connects to the self-hosted Mailu stack at mail.profullstack.com / smtp.profullstack.com. Rebased onto main; build + vet + tests clean (Go 1.26). Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
99 lines
2.8 KiB
Go
99 lines
2.8 KiB
Go
// Package mailbox is the BBS-side mail client for Founding Lifetime members: a
|
|
// transport-agnostic core (read, search, compose, send, flag, delete) with a
|
|
// Bubble Tea TUI for humans and a line-oriented JSON mode for agents/bots. It
|
|
// talks to the self-hosted Mailu stack (Dovecot IMAP + Postfix submission) at
|
|
// mail.profullstack.com / smtp.profullstack.com.
|
|
//
|
|
// The TS counterpart is @logicsrc/plugin-agentmail; the domain shapes here are
|
|
// deliberately the same so tooling can move between them.
|
|
package mailbox
|
|
|
|
import "time"
|
|
|
|
// Address is a parsed mail address.
|
|
type Address struct {
|
|
Name string `json:"name,omitempty"`
|
|
Address string `json:"address"`
|
|
}
|
|
|
|
// Mailbox is an IMAP folder with unread/total counts.
|
|
type Mailbox struct {
|
|
Name string `json:"name"`
|
|
Path string `json:"path"`
|
|
Unseen int `json:"unseen"`
|
|
Total int `json:"total"`
|
|
}
|
|
|
|
// MessageSummary is a lightweight row for list/search views.
|
|
type MessageSummary struct {
|
|
UID uint32 `json:"uid"`
|
|
Mailbox string `json:"mailbox"`
|
|
From Address `json:"from"`
|
|
To []Address `json:"to"`
|
|
Subject string `json:"subject"`
|
|
Date time.Time `json:"date"`
|
|
Seen bool `json:"seen"`
|
|
Flagged bool `json:"flagged"`
|
|
HasAttachments bool `json:"hasAttachments"`
|
|
Snippet string `json:"snippet"`
|
|
}
|
|
|
|
// Attachment is attachment metadata (bytes fetched separately).
|
|
type Attachment struct {
|
|
Filename string `json:"filename"`
|
|
ContentType string `json:"contentType"`
|
|
Size int `json:"size"`
|
|
}
|
|
|
|
// Message is a fully fetched message.
|
|
type Message struct {
|
|
MessageSummary
|
|
CC []Address `json:"cc,omitempty"`
|
|
ReplyTo *Address `json:"replyTo,omitempty"`
|
|
MessageID string `json:"messageId"`
|
|
References []string `json:"references,omitempty"`
|
|
Text string `json:"text"`
|
|
HTML string `json:"html,omitempty"`
|
|
Attachments []Attachment `json:"attachments,omitempty"`
|
|
}
|
|
|
|
// Draft is an outgoing message.
|
|
type Draft struct {
|
|
To []Address `json:"to"`
|
|
CC []Address `json:"cc,omitempty"`
|
|
BCC []Address `json:"bcc,omitempty"`
|
|
Subject string `json:"subject"`
|
|
Text string `json:"text"`
|
|
InReplyTo string `json:"inReplyTo,omitempty"`
|
|
}
|
|
|
|
// ListOptions controls a mailbox listing.
|
|
type ListOptions struct {
|
|
Mailbox string
|
|
Limit int
|
|
}
|
|
|
|
// SearchOptions controls a search.
|
|
type SearchOptions struct {
|
|
Mailbox string // empty = all mailboxes
|
|
Query string
|
|
Limit int
|
|
}
|
|
|
|
// FlagChange is a partial flag update; nil fields are left unchanged.
|
|
type FlagChange struct {
|
|
Seen *bool
|
|
Flagged *bool
|
|
}
|
|
|
|
// SendResult reports a sent message's id.
|
|
type SendResult struct {
|
|
MessageID string `json:"messageId"`
|
|
}
|
|
|
|
const (
|
|
// Inbox is the default mailbox.
|
|
Inbox = "INBOX"
|
|
// Sent is where sent mail is stored.
|
|
Sent = "Sent"
|
|
)
|