Documentation
¶
Overview ¶
Package mail defines the engine-neutral contract the control plane uses to manage an in-house mail server. Adapters live in subpackages.
Index ¶
- Constants
- Variables
- func AccountNameFor(address string) string
- func CreateAccount(ctx context.Context, e Engine, address string, sendCapPerHour int) (string, error)
- func DefaultSendCapPerHour() int
- func DeleteAccount(ctx context.Context, e Engine, account, confirm string, deleteMail bool) error
- func GeneratePassword() (string, error)
- func PasswordLength() int
- func ResumeAccount(ctx context.Context, e Engine, account string) error
- func SetAccountPassword(ctx context.Context, e Engine, account string) (string, error)
- func SplitAddress(addr string) (local, domain string, err error)
- func SuspendAccount(ctx context.Context, e Engine, account string) error
- type Account
- type AccountDetail
- type AccountSpec
- type Alias
- type CredentialSource
- type DKIMKey
- type DNSRecord
- type Domain
- type DomainSpec
- type Engine
- type Error
- type QueueEntry
- type QueueStats
- type Quota
Constants ¶
const ( PasswordLengthEnv = "APP_MAIL_PASSWORD_LENGTH" //nolint:gosec // env var name, not a credential // SuspendedMessage is what the engine tells a client that tries to log in. SuspendedMessage = "This mailbox is suspended. Ask your team admin." )
PasswordLengthEnv sets the length of generated mailbox passwords.
const (
SendCapEnv = "APP_MAIL_DEFAULT_SEND_CAP_PER_HOUR"
)
SendCapEnv sets the default per-account hourly send cap carried on AccountSpec. It is data only; nothing enforces it yet.
Variables ¶
var ( ErrNotFound = errors.New("mail: not found") ErrExists = errors.New("mail: already exists") ErrUnsupported = errors.New("mail: not supported by this engine") ErrInvalid = errors.New("mail: invalid request") )
Typed failures every adapter maps its engine errors onto.
var ErrHasMail = errors.New("mail: the mailbox still holds mail")
ErrHasMail refuses a delete while the account still holds mail.
Functions ¶
func AccountNameFor ¶
AccountNameFor derives the engine account name from an address. Names are the full lowercase address so two domains never collide.
func CreateAccount ¶
func CreateAccount(ctx context.Context, e Engine, address string, sendCapPerHour int) (string, error)
CreateAccount creates the account with a generated password and returns the password once. The caller shows it to the admin and never stores it.
func DefaultSendCapPerHour ¶
func DefaultSendCapPerHour() int
DefaultSendCapPerHour reads the default cap from the environment.
func DeleteAccount ¶
DeleteAccount removes the account. confirm must repeat the account name, and an account that still uses disk is refused unless deleteMail is set.
func GeneratePassword ¶
GeneratePassword returns a random password from crypto/rand.
func PasswordLength ¶
func PasswordLength() int
PasswordLength reads the generated password length, never below the minimum.
func ResumeAccount ¶
ResumeAccount allows logins again.
func SetAccountPassword ¶
SetAccountPassword rotates the password and returns the new one once.
func SplitAddress ¶
SplitAddress returns the localpart and lowercase domain of an address.
Types ¶
type Account ¶
type Account struct {
Name string `json:"name"`
// Disabled is true while the engine refuses logins for the account.
Disabled bool `json:"disabled"`
}
Account is a mailbox owner. Quota is reported only when the engine exposes it.
type AccountDetail ¶
type AccountDetail struct {
Name string `json:"name"`
Addresses []string `json:"addresses"`
LoginDisabled bool `json:"login_disabled"`
DiskUsageBytes int64 `json:"disk_usage_bytes"`
}
AccountDetail is one account's management view: addresses, login state and disk usage. It never carries a password or message content.
type AccountSpec ¶
type AccountSpec struct {
Name string
Address string
Password string
// SendCapPerHour is advisory data for a later enforcement slice; 0 means
// use DefaultSendCapPerHour.
SendCapPerHour int
}
AccountSpec creates an account with its first address.
func (AccountSpec) GoString ¶
func (a AccountSpec) GoString() string
GoString covers %#v with the same redaction.
func (AccountSpec) LogValue ¶
func (a AccountSpec) LogValue() slog.Value
LogValue redacts the password for slog.
func (AccountSpec) String ¶
func (a AccountSpec) String() string
String redacts the password so a printed spec never leaks it.
type CredentialSource ¶
CredentialSource yields the engine admin password at call time so callers can read it from internal/secrets and the adapter never stores it long term.
type DKIMKey ¶
type DKIMKey struct {
Selector string `json:"selector"`
PublicKey string `json:"public_key"`
TXT string `json:"txt"`
}
DKIMKey is a DKIM selector and public key found in the engine's records. PublicKey is the bare p= value, ready for mailrecords.Spec.DKIMPublicKey.
type DNSRecord ¶
type DNSRecord struct {
Name string `json:"name"`
TTL int `json:"ttl,omitempty"`
Type string `json:"type"`
Value string `json:"value"`
}
DNSRecord is one parsed zone-file line from the engine.
type Domain ¶
type Domain struct {
Name string `json:"name"`
}
Domain is a mail domain the engine serves.
type DomainSpec ¶
DomainSpec creates a domain. Account is an existing account that receives the domain's default address; leave Localpart empty to reuse it, or set both to create a new account with that first address.
type Engine ¶
type Engine interface {
Domains(ctx context.Context) ([]Domain, error)
AddDomain(ctx context.Context, d DomainSpec) error
RemoveDomain(ctx context.Context, name string) error
DNSRecords(ctx context.Context, domain string) ([]DNSRecord, error)
DKIMKeys(ctx context.Context, domain string) ([]DKIMKey, error)
Accounts(ctx context.Context) ([]Account, error)
AddAccount(ctx context.Context, a AccountSpec) error
RemoveAccount(ctx context.Context, name string) error
AddAddress(ctx context.Context, address, account string) error
SetPassword(ctx context.Context, account, password string) error
SetQuota(ctx context.Context, account string, q Quota) error
AddAlias(ctx context.Context, a Alias) error
RemoveAlias(ctx context.Context, address string) error
// Aliases lists the aliases of one domain.
Aliases(ctx context.Context, domain string) ([]Alias, error)
// AccountDetail reads one account's addresses, login state and disk usage.
AccountDetail(ctx context.Context, name string) (AccountDetail, error)
// SetLoginDisabled refuses logins with message as the reason; "" allows them again.
SetLoginDisabled(ctx context.Context, account, message string) error
QueueList(ctx context.Context, limit int) ([]QueueEntry, error)
// HoldMessages sets hold on the listed queue ids and returns how many changed.
HoldMessages(ctx context.Context, ids []int64, hold bool) (int, error)
QueueStats(ctx context.Context) (QueueStats, error)
// HoldQueue pauses delivery of every queued message; ReleaseQueue resumes it.
HoldQueue(ctx context.Context) error
ReleaseQueue(ctx context.Context) error
Health(ctx context.Context) error
}
Engine is the control plane's view of a mail server.
type QueueEntry ¶
type QueueEntry struct {
ID int64 `json:"id"`
Queued time.Time `json:"queued"`
Hold bool `json:"hold"`
SenderAccount string `json:"sender_account"`
RecipientDomain string `json:"recipient_domain"`
Attempts int `json:"attempts"`
NextAttempt time.Time `json:"next_attempt"`
LastError string `json:"last_error,omitempty"`
}
QueueEntry is one queued outbound message, limited to delivery metadata: never the subject, message id or body (ADR 059 section 2.8).
type QueueStats ¶
QueueStats summarises the outbound queue.
Directories
¶
| Path | Synopsis |
|---|---|
|
Package demo is a dev-only, in-memory stand-in for a mail server and its DNS zone, so the Mail page can be exercised without a container, provider or domain.
|
Package demo is a dev-only, in-memory stand-in for a mail server and its DNS zone, so the Mail page can be exercised without a container, provider or domain. |
|
Package mox adapts the mox admin API (Sherpa JSON-RPC) to mail.Engine.
|
Package mox adapts the mox admin API (Sherpa JSON-RPC) to mail.Engine. |