package db import ( "encoding/json" "time" ) // Mailbox is a real, IMAP-retrievable local mailbox — distinct from Sender (which is // relay/auth-only). PasswordHash authenticates the self-service web portal only; // IMAP/SMTP client login always goes through a MailboxAppPassword instead. type Mailbox struct { ID int64 Email string DomainID int64 PasswordHash string IsActive bool QuotaBytes int64 UsedBytes int64 DEKWrapped []byte DEKNonce []byte CreatedAt time.Time CreatedBy *int64 TOTPSecret string TOTPEnabled bool // MFAExempt overrides [Auth] enforce_mailbox_mfa off for this mailbox specifically, // even if its domain isn't exempt. MFAExempt bool // GroupMessages collapses a run of same-subject messages in a folder view into one // expandable row when true. Off by default — a display preference, not a policy. GroupMessages bool // RemoteImagesMode is "ask" (default), "trusted", or "always" — see the // remote_images_mode column comment in schema.go. RemoteImagesMode string } // MailboxSession is a self-service webmail portal login — a parallel schema to // AdminSession, not shared (see esrv_mailbox_sessions in schema.go). type MailboxSession struct { Token string MailboxID int64 MFAVerified bool CreatedAt time.Time ExpiresAt time.Time } // MailboxWebAuthnCredential is a mailbox owner's passkey — a parallel schema to // WebAuthnCredential, not shared. type MailboxWebAuthnCredential struct { ID int64 MailboxID int64 Name string CredentialID string CredentialData string CreatedAt time.Time } // MailboxAlias is an alternate address for a mailbox — receive-only by default, or // also usable as MAIL FROM once authenticated (CanSendAs). Login is always the // mailbox's own primary address, never an alias. type MailboxAlias struct { ID int64 MailboxID int64 Email string DomainID int64 CanSendAs bool IsActive bool CreatedAt time.Time } // MailboxAllowBlockEntry is one allow-, block-, or junk-list pattern for a mailbox — // see esrv_mailbox_allowblock's schema comment for what each list_type means. type MailboxAllowBlockEntry struct { ID int64 MailboxID int64 ListType string // "allow" | "block" | "junk" Pattern string CreatedAt time.Time } // MailboxContact is one entry in a mailbox owner's own address book. type MailboxContact struct { ID int64 MailboxID int64 Email string Name string Phone string CreatedAt time.Time } // MailboxFilterRule is one priority-ordered, first-match-wins delivery rule. // ConditionField/Op/Value are the legacy single-condition columns; ConditionsJSON // (when non-empty) is the current multi-condition representation — see Conditions(). type MailboxFilterRule struct { ID int64 MailboxID int64 Name string Priority int ConditionField string // "from" | "to" | "subject" | "body" | "has_attachment" | "recipient_type" ConditionOp string // "contains" | "equals" | "starts_with" ConditionValue string Action string // "move_to_folder" | "delete" | "mark_read" | "mark_as_spam" | "forward" ActionValue string ActionOptionsJSON string IsActive bool ConditionsJSON string MatchType string // "all" (AND, default) | "any" (OR) CreatedAt time.Time } // RuleCondition is one condition within a filter rule's "if" clause. Value may hold // several "\n"-joined values (e.g. several From addresses, or several subject // keywords picked in the rule builder's chip input) — matches if any one does, see // mailstore.matchCondition. type RuleCondition struct { Field string `json:"field"` Op string `json:"op"` Value string `json:"value"` } // RuleActionOptions holds action-specific parameters that only some actions need — // currently just "forward"'s KeepCopy. Stored as MailboxFilterRule.ActionOptionsJSON. type RuleActionOptions struct { // KeepCopy: for the "forward" action, whether a copy is also stored in this // mailbox (true) or the message is forwarded and dropped otherwise (false). // Defaults true (see ActionOptions) — the safer default is to not silently lose // mail just because forwarding was set up. KeepCopy bool `json:"keep_copy"` } // ActionOptions parses ActionOptionsJSON, defaulting KeepCopy true for a rule created // before this existed (or with the field simply left unset). func (r MailboxFilterRule) ActionOptions() RuleActionOptions { opts := RuleActionOptions{KeepCopy: true} if r.ActionOptionsJSON != "" { json.Unmarshal([]byte(r.ActionOptionsJSON), &opts) } return opts } // Conditions returns this rule's conditions and how they combine ("all"=AND, // "any"=OR) — parses ConditionsJSON when present, falling back to the single legacy // condition_field/op/value columns for rules created before multi-condition support // existed. Shared by mailstore.ApplyRules (evaluation) and the webui (display), so // both stay in sync with the same fallback rule. func (r MailboxFilterRule) Conditions() ([]RuleCondition, string) { if r.ConditionsJSON != "" { var parsed []RuleCondition if err := json.Unmarshal([]byte(r.ConditionsJSON), &parsed); err == nil && len(parsed) > 0 { matchType := r.MatchType if matchType != "any" { matchType = "all" } return parsed, matchType } } return []RuleCondition{{Field: r.ConditionField, Op: r.ConditionOp, Value: r.ConditionValue}}, "all" } // MailboxAppPassword is the only credential an IMAP/SMTP client ever uses. Plaintext // is shown once at creation and never stored. ExpiresAt is nil for a password that // never expires (the default). type MailboxAppPassword struct { ID int64 MailboxID int64 Label string PasswordHash string IsActive bool CreatedAt time.Time LastUsedAt *time.Time ExpiresAt *time.Time } // MailboxMessage is one stored message. CachedFrom/CachedTo/CachedSubject are // plaintext by design (see schema.go); the rest of the message lives encrypted at // StoragePath. CachedTo exists purely so folder listings (e.g. Sent) can show the // recipient without decrypting every message just to render a list. type MailboxMessage struct { ID int64 MailboxID int64 Folder string MessageIDHeader string Flags string InternalDate time.Time SizeBytes int64 CachedFrom string CachedTo string CachedSubject string CachedPreview string StoragePath string Nonce []byte CreatedAt time.Time } // MailboxSignature is one of a mailbox's saved email signatures — HTML content, shown // as an option in compose and optionally auto-inserted for a new message or a // reply/forward (IsDefaultNew/IsDefaultReply). type MailboxSignature struct { ID int64 MailboxID int64 Name string ContentHTML string IsDefaultNew bool IsDefaultReply bool CreatedAt time.Time } // SignatureAliasDefault is one per-alias override of which signature is the default // for a mailbox with send-as aliases — see GetDefaultSignature. type SignatureAliasDefault struct { ID int64 MailboxID int64 ForEmail string ForReply bool SignatureID int64 } // MailboxSMIMEIdentity is one of a mailbox's own S/MIME certificate + private key // pairs — a mailbox may hold several. Both halves are stored plain: S/MIME is // sign-only in this codebase, so the key never protects anything beyond what the // server already has access to. type MailboxSMIMEIdentity struct { ID int64 MailboxID int64 CertPEM string KeyPEM string NotAfter time.Time CreatedAt time.Time } // MailboxSMIMEContact is another address's public certificate a mailbox owner has // collected, either added by hand or auto-captured off a verified signature. type MailboxSMIMEContact struct { ID int64 MailboxID int64 Email string CertPEM string CreatedAt time.Time } // MailboxPGPIdentity is one of a mailbox's own PGP keypairs — a mailbox may hold // several. PrivateKeyArmor is stored exactly as the pgp package serializes it, // already passphrase-protected via OpenPGP's own native key-encryption format (no // separate ciphertext/nonce/salt columns needed, unlike MailboxSMIMEIdentity). // Label is a free-text user note distinguishing keys (PGP keys have no expiry). type MailboxPGPIdentity struct { ID int64 MailboxID int64 Label string Email string Fingerprint string PublicKeyArmor string PrivateKeyArmor string CreatedAt time.Time } // MailboxPGPContact is another address's PGP public key a mailbox owner has // collected — mirrors MailboxSMIMEContact. type MailboxPGPContact struct { ID int64 MailboxID int64 Email string Label string PublicKeyArmor string Fingerprint string CreatedAt time.Time }