config

package
v0.41.0 Latest Latest
Warning

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

Go to latest
Published: Jun 7, 2026 License: MIT Imports: 24 Imported by: 0

README

config

The config package handles all persistent application state: user configuration, email/contacts/drafts caching, folder caching, email signatures, and optional at-rest encryption. Configuration is stored under ~/.config/matcha/, cache data under ~/.cache/matcha/.

Architecture

This package acts as the data layer for Matcha. It manages:

  • Account configuration with multi-account support (Gmail, Outlook, iCloud, custom IMAP/SMTP)
  • Secure credential storage via the OS keyring (with automatic migration from plain-text passwords), or inside the encrypted config when encryption is enabled
  • Local caches for emails, email bodies, contacts, drafts, and folder listings to enable fast startup and offline browsing
  • Email body caching for instant display of previously viewed emails without network round-trips
  • Email signatures stored as plain text
  • Optional encryption of all data files using AES-256-GCM with Argon2id key derivation

All files use JSON serialization with restrictive file permissions (0600/0700). When encryption is enabled, all files (except secure.meta) are encrypted before writing to disk.

Storage Layout

Configuration (~/.config/matcha/):

Path Description
config.json Account settings, preferences
signature.txt Email signature
secure.meta Encryption metadata (salt + sentinel), only present when encryption is enabled
pgp/ PGP keys
plugins/ Installed Lua plugins
themes/ Custom theme JSON files

Cache (~/.cache/matcha/):

Path Description
email_cache.json Email metadata cache
contacts.json Contact autocomplete data
drafts.json Saved email drafts
folder_cache.json Folder listings per account
folder_emails/ Per-folder email list cache
email_bodies/ Cached email body content and attachment metadata

On startup, MigrateCacheFiles() moves any cache files from the old location (~/.config/matcha/) to ~/.cache/matcha/.

Files

File Description
config.go Core configuration types (Account, Config, MailingList) and functions for loading, saving, and managing accounts. Handles IMAP/SMTP server resolution per provider, OS keyring integration, legacy config migration, and cache directory management (cacheDir(), MigrateCacheFiles()).
cache.go Email, contacts, drafts, and email body caching. Provides CRUD operations for EmailCache, ContactsCache (with search and frequency-based ranking), DraftsCache (with save/delete/get operations), and EmailBodyCache (per-folder body + attachment metadata caching with pruning).
folder_cache.go Caches IMAP folder listings per account and per-folder email metadata. Stores folder names to avoid repeated IMAP LIST commands, and caches email headers per folder for fast navigation.
encryption.go Optional at-rest encryption using AES-256-GCM with Argon2id key derivation. Provides SecureReadFile/SecureWriteFile (transparent encryption wrappers used by all other files), EnableSecureMode/DisableSecureMode, password verification via an encrypted sentinel phrase, and session key management.
signature.go Loads and saves the user's email signature from ~/.config/matcha/signature.txt.
oauth.go OAuth2 integration — token retrieval, authorization flow launcher, and embedded Python helper extraction.
oauth_script.py Embedded OAuth2 helper script supporting Gmail and Outlook (browser-based auth, token refresh, secure storage).
config_test.go Unit tests for configuration logic.

Encryption

When enabled via Settings, all data files are encrypted at rest using a user-chosen password. The password is never stored anywhere.

How it works
  1. Key derivation: The password is combined with a random 256-bit salt using Argon2id (time=3, memory=64MB, threads=4) to produce a 256-bit AES key.
  2. Sentinel verification: A known phrase ("matcha-verified") is encrypted with the derived key and stored in secure.meta. On login, if decrypting the sentinel succeeds, the password is correct.
  3. Transparent I/O: All file read/write operations go through SecureReadFile/SecureWriteFile. When a session key is set, these encrypt/decrypt automatically. When no key is set (encryption disabled), they pass through to plain os.ReadFile/os.WriteFile.
  4. Password storage: When encryption is active, account passwords are stored inside the encrypted config.json (via secureDiskAccount) instead of the OS keyring. When encryption is disabled, passwords are restored to the keyring.
secure.meta format
{
  "salt": "<base64-encoded-32-byte-salt>",
  "sentinel": "<base64-encoded-AES-GCM-encrypted-sentinel>",
  "argon2_time": 3,
  "argon2_memory": 65536,
  "argon2_threads": 4
}

This file is never encrypted itself — its existence signals that encryption is enabled.

Email Body Cache

Email bodies and attachment metadata are cached per-folder in ~/.cache/matcha/email_bodies/. When a user views an email:

  1. The cache is checked first (GetCachedEmailBody).
  2. If found, the cached body is returned instantly without a network call.
  3. If not found, the body is fetched from the server and saved to cache (SaveEmailBody).
  4. When folder emails are refreshed, stale body cache entries (for emails no longer on the server) are pruned (PruneEmailBodyCache).

Attachment binary data is not cached — only metadata (filename, MIME type, part ID, etc.) is stored. Attachment downloads always go to the server.

OAuth2 / XOAUTH2

Accounts with auth_method: "oauth2" use the XOAUTH2 mechanism instead of passwords. This is supported for Gmail and Outlook. The flow works across three layers:

  1. config/oauth.go — Go-side orchestration. Extracts the embedded Python helper to ~/.config/matcha/oauth/, invokes it to run the browser-based authorization flow (RunOAuth2Flow) or to retrieve a fresh access token (GetOAuth2Token). The IsOAuth2() method on Account checks the auth method.

  2. config/oauth_script.py — Embedded Python script that handles the full OAuth2 lifecycle for both Gmail and Outlook:

    • auth — Opens a browser for authorization (Google or Microsoft), captures the callback on localhost:8189, exchanges the code for tokens, and saves them to ~/.config/matcha/oauth_tokens/. The provider is auto-detected from the email domain or can be specified with --provider.
    • token — Returns a fresh access token, automatically refreshing if expired (with a 5-minute buffer).
    • revoke — Revokes tokens and deletes local storage.
    • Client credentials are stored per provider: ~/.config/matcha/oauth_client.json (Gmail), ~/.config/matcha/oauth_client_outlook.json (Outlook).
  3. fetcher/xoauth2.go — Implements the XOAUTH2 SASL mechanism (sasl.Client interface) for IMAP/SMTP authentication. Formats the initial response as user=<email>\x01auth=Bearer <token>\x01\x01 per the XOAUTH2 protocol spec.

Documentation

Index

Constants

View Source
const (
	ProviderGmail  = "gmail"
	ProviderICloud = "icloud"
	ProviderCustom = "custom"
)
View Source
const (
	DateFormatISO = "YYYY-MM-DD HH:MM"
	DateFormatUS  = "MM/DD/YYYY hh:MM AM"
	DateFormatEU  = "DD/MM/YYYY HH:MM"
)

Date format presets use human-readable tokens. Supported tokens:

YYYY (4-digit year), YY (2-digit year)
MM   (month, or minutes when following an hour token + colon)
mm   (minutes, explicit)
DD   (day)
HH   (24-hour), hh (12-hour, zero-padded)
SS, ss (seconds)
AM, PM (meridiem marker)

Variables

View Source
var Keybinds = defaultKeybinds()

Keybinds is the active keybind configuration. Initialized to defaults at package init; overwritten by LoadKeybindsFromDir when config is loaded.

Functions

func AddContact added in v0.8.0

func AddContact(name, email string) error

AddContact adds or updates a global contact in the cache.

func AddContactForAccount added in v0.38.0

func AddContactForAccount(name, email, accountID string) error

AddContactForAccount adds or updates a contact in the cache for an account.

func CleanupAccountCache added in v0.38.0

func CleanupAccountCache(accountID string) error

CleanupAccountCache removes cached data associated with an account.

func ClearEmailCache added in v0.8.0

func ClearEmailCache() error

ClearEmailCache removes the cache file.

func ClearSessionKey added in v0.32.0

func ClearSessionKey()

ClearSessionKey removes the session key from memory.

func Decrypt added in v0.32.0

func Decrypt(ciphertext, key []byte) ([]byte, error)

Decrypt decrypts ciphertext produced by Encrypt using AES-256-GCM.

func DeleteDraft added in v0.8.0

func DeleteDraft(id string) error

DeleteDraft removes a draft by ID.

func DeriveKey added in v0.32.0

func DeriveKey(password string, salt []byte) []byte

DeriveKey derives an AES-256 key from a password and salt using Argon2id.

func DisableSecureMode added in v0.32.0

func DisableSecureMode(cfg *Config) error

DisableSecureMode decrypts all files back to plain JSON and removes secure.meta. The config must be passed so passwords can be restored to the OS keyring.

func EnableSecureMode added in v0.32.0

func EnableSecureMode(password string, cfg *Config) error

EnableSecureMode sets up encryption with the given password. It initialises the vault, re-saves the config with passwords embedded in the encrypted JSON, and re-encrypts all existing data files.

func Encrypt added in v0.32.0

func Encrypt(plaintext, key []byte) ([]byte, error)

Encrypt encrypts plaintext using AES-256-GCM. The nonce is prepended to the ciphertext.

func EnsurePGPDir added in v0.30.0

func EnsurePGPDir() error

EnsurePGPDir creates the PGP keys directory if it doesn't exist.

func GetCacheDir added in v0.32.0

func GetCacheDir() (string, error)

GetCacheDir returns the path to the cache directory (exported).

func GetCachedFolders added in v0.22.0

func GetCachedFolders(accountID string) ([]string, map[string]int)

GetCachedFolders returns cached folder names for a specific account.

func GetConfigDir added in v0.21.0

func GetConfigDir() (string, error)

GetConfigDir returns the path to the configuration directory (exported).

func GetContactsCachePath added in v0.33.0

func GetContactsCachePath() (string, error)

GetContactsCachePath returns the full path to the contacts cache file.

func GetOAuth2Token added in v0.28.0

func GetOAuth2Token(email string) (string, error)

GetOAuth2Token retrieves a fresh OAuth2 access token for the account by invoking the Python helper script. The script handles token refresh automatically.

func GetSessionKey added in v0.32.0

func GetSessionKey() []byte

GetSessionKey returns the current session key, or nil if the vault is locked. The caller must not modify the returned slice.

func HasAccountSignature added in v0.35.0

func HasAccountSignature(account *Account) bool

HasAccountSignature checks if an account has its own signature (file or inline).

func HasDrafts added in v0.8.0

func HasDrafts() bool

HasDrafts checks if there are any saved drafts.

func HasEmailCache added in v0.8.0

func HasEmailCache() bool

HasEmailCache checks if a cache file exists.

func HasSignature added in v0.15.0

func HasSignature() bool

HasSignature checks if a global signature file exists and is non-empty.

func IsFolderThreaded added in v0.37.0

func IsFolderThreaded(folderName string, defaultEnabled bool) bool

IsFolderThreaded returns the threading state for a folder. If the user has explicitly toggled threading for this folder, that override is returned. Otherwise defaultEnabled (from Config.EnableThreaded) is used.

func IsSecureModeEnabled added in v0.32.0

func IsSecureModeEnabled() bool

IsSecureModeEnabled checks whether encryption is active by looking for secure.meta.

func LoadFolderEmailHeaders added in v0.37.0

func LoadFolderEmailHeaders(folderName string) ([]threading.EmailHeader, error)

func LoadKeybindsFromDir added in v0.36.0

func LoadKeybindsFromDir(cfgDir string) error

LoadKeybindsFromDir reads keybinds.json from cfgDir, writing defaults if the file does not exist, then updates the package-level Keybinds var.

func LoadRawAccountSignature added in v0.35.0

func LoadRawAccountSignature(account *Account) (string, error)

LoadRawAccountSignature loads the per-account signature if one exists, without falling back to the global signature.

func LoadSignature added in v0.15.0

func LoadSignature() (string, error)

LoadSignature loads the signature from the global signature file.

func LoadSignatureForAccount added in v0.35.0

func LoadSignatureForAccount(account *Account) (string, error)

LoadSignatureForAccount loads the per-account signature if one exists, otherwise falls back to the global signature.

func MigrateCacheFiles added in v0.32.0

func MigrateCacheFiles() error

MigrateCacheFiles moves cache files from ~/.config/matcha/ to ~/.cache/matcha/ if needed. This is a one-time migration for existing installations.

func MigrateContactsCacheUsage added in v0.38.0

func MigrateContactsCacheUsage(accountIDs []string) error

MigrateContactsCacheUsage expands legacy global contact usage to all accounts.

func OAuthScriptPath added in v0.28.0

func OAuthScriptPath() (string, error)

OAuthScriptPath returns the path to the OAuth2 Python helper script. The script is embedded in the binary and extracted to ~/.config/matcha/oauth/ on first use.

func PruneEmailBodyCache added in v0.32.0

func PruneEmailBodyCache(folderName string, validUIDs map[uint32]string, threshold int) error

PruneEmailBodyCache removes cached bodies for emails that are no longer in the folder. validUIDs is a map of UID -> AccountID for emails still present.

func RunOAuth2Flow added in v0.28.0

func RunOAuth2Flow(email, provider, clientID, clientSecret string) error

RunOAuth2Flow launches the OAuth2 authorization flow by invoking the Python helper script. It opens the user's browser for authorization. provider should be "gmail" or "outlook". If empty, the script auto-detects from the email. clientID and clientSecret are optional — if empty, the script uses stored credentials.

func SaveAccountFolders added in v0.22.0

func SaveAccountFolders(accountID string, folders []string, unread map[string]int) error

SaveAccountFolders saves folder names for a specific account, merging into the existing cache.

func SaveConfig

func SaveConfig(config *Config) error

SaveConfig saves the given configuration to the config file and passwords to the keyring.

func SaveContactsCache added in v0.8.0

func SaveContactsCache(cache *ContactsCache) error

SaveContactsCache saves contacts to the cache file.

func SaveDraft added in v0.8.0

func SaveDraft(draft Draft) error

SaveDraft saves or updates a draft.

func SaveDraftsCache added in v0.8.0

func SaveDraftsCache(cache *DraftsCache) error

SaveDraftsCache saves drafts to the cache file.

func SaveEmailBody added in v0.32.0

func SaveEmailBody(folderName string, body CachedEmailBody, threshold int) error

SaveEmailBody saves or updates a cached email body for a folder.

func SaveEmailCache added in v0.8.0

func SaveEmailCache(cache *EmailCache) error

SaveEmailCache saves emails to the cache file.

func SaveFolderCache added in v0.22.0

func SaveFolderCache(cache *FolderCache) error

SaveFolderCache saves the folder cache to disk.

func SaveFolderEmailCache added in v0.22.0

func SaveFolderEmailCache(folderName string, emails []CachedEmail) error

SaveFolderEmailCache saves emails for a folder to disk.

func SaveSignature added in v0.15.0

func SaveSignature(signature string) error

SaveSignature saves the signature to the global signature file.

func SaveSignatureForAccount added in v0.35.0

func SaveSignatureForAccount(accountID, signature string) error

SaveSignatureForAccount saves a per-account signature file.

func SecureReadFile added in v0.32.0

func SecureReadFile(path string) ([]byte, error)

SecureReadFile reads a file, decrypting it if the vault is unlocked.

func SecureWriteFile added in v0.32.0

func SecureWriteFile(path string, data []byte, perm os.FileMode) error

SecureWriteFile writes data to a file, encrypting it if the vault is unlocked.

func SetFolderThreaded added in v0.37.0

func SetFolderThreaded(folderName string, threaded bool) error

SetFolderThreaded stores an explicit per-folder threading override.

func SetSessionKey added in v0.32.0

func SetSessionKey(_ []byte)

SetSessionKey is kept for API compatibility. VerifyPassword unlocks the vault internally, so callers that pass the returned key back through SetSessionKey are no-ops — the vault is already in the correct state.

func SyncMacOSContacts added in v0.35.0

func SyncMacOSContacts() error

SyncMacOSContacts fetches contacts from the macOS Contacts framework and merges them into the local contacts cache for all configured accounts.

func SyncMacOSContactsForAccounts added in v0.38.0

func SyncMacOSContactsForAccounts(accountIDs []string) error

SyncMacOSContactsForAccounts fetches contacts from the macOS Contacts framework and merges them into the local contacts cache for the given accounts.

func ValidateKeybinds added in v0.36.0

func ValidateKeybinds(kb KeybindsConfig) []string

ValidateKeybinds returns a list of conflict descriptions where two different actions within the same area are mapped to the same key. Cross-area duplicates are intentional (e.g. "d" = delete in both inbox and email view).

func VerifyPassword added in v0.32.0

func VerifyPassword(password string) ([]byte, error)

VerifyPassword checks the password against the stored sentinel and unlocks the vault. Returns the derived key for callers that store it via SetSessionKey.

Types

type Account added in v0.8.0

type Account struct {
	ID              string `json:"id"`
	Name            string `json:"name"`
	Email           string `json:"email"`
	Password        string `json:"-"`                // "-" prevents the password from being saved to config.json
	ServiceProvider string `json:"service_provider"` // "gmail", "outlook", "icloud", or "custom"
	// FetchEmail is the single email address for which messages should be fetched.
	// If empty, it will default to `Email` when accounts are added.
	FetchEmail string `json:"fetch_email,omitempty"`
	// SendAsEmail controls the visible From header on outgoing mail.
	// If empty, it defaults to FetchEmail, then Email.
	SendAsEmail string `json:"send_as_email,omitempty"`
	// CatchAll skips per-address filtering so all inbox messages are shown,
	// regardless of which address they were delivered to.
	CatchAll bool `json:"catch_all,omitempty"`

	SC *SessionCache `json:"-"` // "-" prevents the SessionCache from being saved to config.json

	// Custom server settings (used when ServiceProvider is "custom")
	IMAPServer string `json:"imap_server,omitempty"`
	IMAPPort   int    `json:"imap_port,omitempty"`
	SMTPServer string `json:"smtp_server,omitempty"`
	SMTPPort   int    `json:"smtp_port,omitempty"`
	Insecure   bool   `json:"insecure,omitempty"`

	// S/MIME settings
	SMIMECert          string `json:"smime_cert,omitempty"`            // Path to the public certificate PEM
	SMIMEKey           string `json:"smime_key,omitempty"`             // Path to the private key PEM
	SMIMESignByDefault bool   `json:"smime_sign_by_default,omitempty"` // Whether to enable S/MIME signing by default

	// PGP settings
	PGPPublicKey     string `json:"pgp_public_key,omitempty"`      // Path to public key (.asc or .gpg)
	PGPPrivateKey    string `json:"pgp_private_key,omitempty"`     // Path to private key (.asc or .gpg)
	PGPKeySource     string `json:"pgp_key_source,omitempty"`      // "file" (default) or "yubikey" for hardware key
	PGPPIN           string `json:"-"`                             // YubiKey PIN (stored in keyring, not JSON)
	PGPSignByDefault bool   `json:"pgp_sign_by_default,omitempty"` // Auto-sign outgoing emails

	// OAuth2 settings
	AuthMethod string `json:"auth_method,omitempty"` // "password" (default) or "oauth2"

	// Multi-protocol settings
	Protocol     string `json:"protocol,omitempty"`      // "imap" (default), "jmap", or "pop3"
	JMAPEndpoint string `json:"jmap_endpoint,omitempty"` // JMAP session URL (for protocol=jmap)
	POP3Server   string `json:"pop3_server,omitempty"`   // POP3 server hostname (for protocol=pop3)
	POP3Port     int    `json:"pop3_port,omitempty"`     // POP3 server port (for protocol=pop3)
	MaildirPath  string `json:"maildir_path,omitempty"`  // Local Maildir root (for protocol=maildir)

	// Per-account signature (overrides global signature)
	Signature string `json:"signature,omitempty"`
}

Account stores the configuration for a single email account.

func (*Account) FormatFromHeader added in v0.32.0

func (a *Account) FormatFromHeader() string

FormatFromHeader returns the display-ready From header value.

func (*Account) GetClientSessionCache added in v0.40.0

func (a *Account) GetClientSessionCache() tls.ClientSessionCache

func (*Account) GetFetchEmail added in v0.32.0

func (a *Account) GetFetchEmail() string

GetFetchEmail returns the configured fetch identity, falling back to Email.

func (*Account) GetIMAPPort added in v0.8.0

func (a *Account) GetIMAPPort() int

GetIMAPPort returns the IMAP port for the account.

func (*Account) GetIMAPServer added in v0.8.0

func (a *Account) GetIMAPServer() string

GetIMAPServer returns the IMAP server address for the account.

func (*Account) GetPOP3Port added in v0.29.0

func (a *Account) GetPOP3Port() int

GetPOP3Port returns the POP3 port for the account.

func (*Account) GetPOP3Server added in v0.29.0

func (a *Account) GetPOP3Server() string

GetPOP3Server returns the POP3 server address for the account.

func (*Account) GetSMTPPort added in v0.8.0

func (a *Account) GetSMTPPort() int

GetSMTPPort returns the SMTP port for the account.

func (*Account) GetSMTPServer added in v0.8.0

func (a *Account) GetSMTPServer() string

GetSMTPServer returns the SMTP server address for the account.

func (*Account) GetSendAsEmail added in v0.32.0

func (a *Account) GetSendAsEmail() string

GetSendAsEmail returns the visible sender address for outgoing mail.

func (*Account) IsOAuth2 added in v0.28.0

func (a *Account) IsOAuth2() bool

IsOAuth2 returns true if the account uses OAuth2 authentication.

type CachedAttachment added in v0.32.0

type CachedAttachment struct {
	Filename         string `json:"filename"`
	PartID           string `json:"part_id"`
	Encoding         string `json:"encoding,omitempty"`
	MIMEType         string `json:"mime_type,omitempty"`
	ContentID        string `json:"content_id,omitempty"`
	Inline           bool   `json:"inline,omitempty"`
	IsSMIMESignature bool   `json:"is_smime_signature,omitempty"`
	SMIMEVerified    bool   `json:"smime_verified,omitempty"`
	IsSMIMEEncrypted bool   `json:"is_smime_encrypted,omitempty"`
	IsCalendarInvite bool   `json:"is_calendar_invite,omitempty"`
	CalendarData     []byte `json:"calendar_data,omitempty"` // Raw .ics data for calendar invites
}

CachedAttachment stores attachment metadata (not the binary data).

type CachedEmail added in v0.8.0

type CachedEmail struct {
	UID        uint32    `json:"uid"`
	From       string    `json:"from"`
	To         []string  `json:"to"`
	Subject    string    `json:"subject"`
	Date       time.Time `json:"date"`
	MessageID  string    `json:"message_id"`
	InReplyTo  string    `json:"in_reply_to,omitempty"`
	References []string  `json:"references,omitempty"`
	AccountID  string    `json:"account_id"`
	IsRead     bool      `json:"is_read"`
}

CachedEmail stores essential email data for caching.

func LoadFolderEmailCache added in v0.22.0

func LoadFolderEmailCache(folderName string) ([]CachedEmail, error)

LoadFolderEmailCache loads cached emails for a folder from disk.

type CachedEmailBody added in v0.32.0

type CachedEmailBody struct {
	UID            uint32             `json:"uid"`
	AccountID      string             `json:"account_id"`
	Body           string             `json:"body"`
	BodyMIMEType   string             `json:"body_mime_type,omitempty"` // empty for cache rows written before MIME-type tracking; renderer falls back to legacy markdown→HTML pre-pass
	Attachments    []CachedAttachment `json:"attachments,omitempty"`
	CachedAt       time.Time          `json:"cached_at"`
	LastAccessedAt time.Time          `json:"last_accessed_at"`
	SizeBytes      int                `json:"size_bytes"`
}

CachedEmailBody stores the body and attachment metadata for a single email.

func GetCachedEmailBody added in v0.32.0

func GetCachedEmailBody(folderName string, uid uint32, accountID string, threshold int) *CachedEmailBody

GetCachedEmailBody returns the cached body for a specific email, or nil if not cached. LastAccessedAt is updated by SaveEmailBody, not here -- a read should not mutate cache state.

type CachedFolders added in v0.22.0

type CachedFolders struct {
	AccountID string         `json:"account_id"`
	Folders   []string       `json:"folders"`
	Unread    map[string]int `json:"unread_counts,omitempty"`
	UpdatedAt time.Time      `json:"updated_at"`
}

CachedFolders stores folder names for a single account.

type ComposerKeys added in v0.36.0

type ComposerKeys struct {
	ExternalEditor string `json:"external_editor"`
	NextField      string `json:"next_field"`
	PrevField      string `json:"prev_field"`
	Delete         string `json:"delete"`
	SpellNext      string `json:"spell_next"`
	SpellPrev      string `json:"spell_prev"`
	SpellAccept    string `json:"spell_accept"`
	SpellDismiss   string `json:"spell_dismiss"`
	UndoSend       string `json:"undo_send"`
}

type Config

type Config struct {
	Accounts                []Account     `json:"accounts"`
	DisableImages           bool          `json:"disable_images,omitempty"`
	HideTips                bool          `json:"hide_tips,omitempty"`
	DisableNotifications    bool          `json:"disable_notifications,omitempty"`
	DisableDaemon           bool          `json:"disable_daemon,omitempty"`
	EnableSplitPane         bool          `json:"enable_split_pane,omitempty"`
	EnableThreaded          bool          `json:"enable_threaded,omitempty"`
	EnableDetailedDates     bool          `json:"enable_detailed_dates,omitempty"`
	DisableSpellcheck       bool          `json:"disable_spellcheck,omitempty"`
	DisableSpellSuggestions bool          `json:"disable_spell_suggestions,omitempty"`
	Theme                   string        `json:"theme,omitempty"`
	MailingLists            []MailingList `json:"mailing_lists,omitempty"`
	DateFormat              string        `json:"date_format,omitempty"`
	Language                string        `json:"language,omitempty"` // Language code (e.g., "en", "es", "de")
	BodyCacheThresholdMB    int           `json:"body_cache_threshold_mb,omitempty"`
	UndoDelaySeconds        int           `json:"undo_delay_seconds,omitempty"`
	// PluginSettings stores user-configurable values for installed plugins,
	// keyed by plugin name then setting key. Values are JSON-native types
	// (bool, float64, string) matching the plugin's declared schema.
	PluginSettings map[string]map[string]interface{} `json:"plugin_settings,omitempty"`
}

Config stores the user's email configuration with multiple accounts.

func LoadConfig

func LoadConfig() (*Config, error)

LoadConfig loads the configuration from the config file and passwords from the keyring. It automatically migrates plain-text passwords to the OS keyring if they exist.

func (*Config) AddAccount added in v0.8.0

func (c *Config) AddAccount(account Account)

AddAccount adds a new account to the configuration.

func (*Config) GetAccountByEmail added in v0.8.0

func (c *Config) GetAccountByEmail(email string) *Account

GetAccountByEmail returns an account by its email address.

func (*Config) GetAccountByID added in v0.8.0

func (c *Config) GetAccountByID(id string) *Account

GetAccountByID returns an account by its ID.

func (*Config) GetAccountIDs added in v0.38.0

func (c *Config) GetAccountIDs() []string

GetAccountIDs returns the configured account IDs.

func (*Config) GetBodyCacheThreshold added in v0.37.0

func (c *Config) GetBodyCacheThreshold() int

GetBodyCacheThreshold returns the email body cache threshold in bytes. It defaults to 100MB if unset or zero.

func (*Config) GetDateFormat added in v0.33.0

func (c *Config) GetDateFormat() string

GetDateFormat returns the Go time reference layout translated from the user's configured human-readable format. Defaults to EU when unset.

func (*Config) GetFirstAccount added in v0.8.0

func (c *Config) GetFirstAccount() *Account

GetFirstAccount returns the first account or nil if none exist.

func (*Config) GetLanguage added in v0.35.0

func (c *Config) GetLanguage() string

GetLanguage returns the configured language code, defaulting to "en".

func (*Config) GetUndoDelaySeconds added in v0.41.0

func (c *Config) GetUndoDelaySeconds() int

func (*Config) HasAccounts added in v0.8.0

func (c *Config) HasAccounts() bool

HasAccounts returns true if there are any configured accounts.

func (*Config) RemoveAccount added in v0.8.0

func (c *Config) RemoveAccount(id string) bool

RemoveAccount removes an account by its ID and deletes its password from the keyring.

type Contact added in v0.8.0

type Contact struct {
	Name      string                  `json:"name"`
	Email     string                  `json:"email"`
	Addresses []string                `json:"addresses,omitempty"`
	Usage     map[string]ContactUsage `json:"usage_by_account"`
}

Contact stores a contact's name, email address, and per-account usage.

For regular contacts, Email holds a single address and Addresses is empty. For mailing-list virtual contacts emitted by SearchContacts, Email is empty and Addresses holds the expanded list of recipients. Callers that need to distinguish the two cases should check len(Addresses) > 0.

func SearchContacts added in v0.8.0

func SearchContacts(query string) []Contact

SearchContacts searches for contacts matching the query across all accounts.

func SearchContactsForAccount added in v0.38.0

func SearchContactsForAccount(query, accountID string) []Contact

SearchContactsForAccount searches for contacts matching the query for an account.

func (*Contact) UnmarshalJSON added in v0.38.0

func (c *Contact) UnmarshalJSON(data []byte) error

UnmarshalJSON accepts both the current usage_by_account format and the legacy last_used/use_count fields so old contacts can be migrated.

type ContactUsage added in v0.38.0

type ContactUsage struct {
	LastUsed time.Time `json:"last_used"`
	UseCount int       `json:"use_count"`
}

ContactUsage stores per-account contact usage metadata.

func ContactAggregateUsage added in v0.38.0

func ContactAggregateUsage(c Contact) ContactUsage

ContactAggregateUsage returns a contact's total usage across accounts.

type ContactsCache added in v0.8.0

type ContactsCache struct {
	Contacts  []Contact `json:"contacts"`
	UpdatedAt time.Time `json:"updated_at"`
}

ContactsCache stores all known contacts.

func LoadContactsCache added in v0.8.0

func LoadContactsCache() (*ContactsCache, error)

LoadContactsCache loads contacts from the cache file.

type Draft added in v0.8.0

type Draft struct {
	ID              string    `json:"id"`
	To              string    `json:"to"`
	Cc              string    `json:"cc,omitempty"`
	Bcc             string    `json:"bcc,omitempty"`
	Subject         string    `json:"subject"`
	Body            string    `json:"body"`
	AttachmentPaths []string  `json:"attachment_paths,omitempty"`
	AccountID       string    `json:"account_id"`
	FromOverride    string    `json:"from_override,omitempty"`
	InReplyTo       string    `json:"in_reply_to,omitempty"`
	References      []string  `json:"references,omitempty"`
	QuotedText      string    `json:"quoted_text,omitempty"`
	CreatedAt       time.Time `json:"created_at"`
	UpdatedAt       time.Time `json:"updated_at"`
}

Draft stores a saved email draft.

func GetAllDrafts added in v0.8.0

func GetAllDrafts() []Draft

GetAllDrafts retrieves all drafts sorted by update time (newest first).

func GetDraft added in v0.8.0

func GetDraft(id string) *Draft

GetDraft retrieves a draft by ID.

type DraftsCache added in v0.8.0

type DraftsCache struct {
	Drafts    []Draft   `json:"drafts"`
	UpdatedAt time.Time `json:"updated_at"`
}

DraftsCache stores all saved drafts.

func LoadDraftsCache added in v0.8.0

func LoadDraftsCache() (*DraftsCache, error)

LoadDraftsCache loads drafts from the cache file.

type DraftsKeys added in v0.36.0

type DraftsKeys struct {
	Open   string `json:"open"`
	Delete string `json:"delete"`
}

type EmailBodyCache added in v0.32.0

type EmailBodyCache struct {
	FolderName string            `json:"folder_name"`
	Bodies     []CachedEmailBody `json:"bodies"`
	UpdatedAt  time.Time         `json:"updated_at"`
}

EmailBodyCache stores cached email bodies for a folder.

func LoadEmailBodyCache added in v0.32.0

func LoadEmailBodyCache(folderName string) (*EmailBodyCache, error)

LoadEmailBodyCache loads the body cache for a folder.

type EmailCache added in v0.8.0

type EmailCache struct {
	Emails    []CachedEmail `json:"emails"`
	UpdatedAt time.Time     `json:"updated_at"`
}

EmailCache stores cached emails for all accounts.

func LoadEmailCache added in v0.8.0

func LoadEmailCache() (*EmailCache, error)

LoadEmailCache loads emails from the cache file.

type EmailKeys added in v0.36.0

type EmailKeys struct {
	Reply            string `json:"reply"`
	Forward          string `json:"forward"`
	Delete           string `json:"delete"`
	Archive          string `json:"archive"`
	ToggleImages     string `json:"toggle_images"`
	RsvpAccept       string `json:"rsvp_accept"`
	RsvpDecline      string `json:"rsvp_decline"`
	RsvpTentative    string `json:"rsvp_tentative"`
	FocusAttachments string `json:"focus_attachments"`
}

type FolderCache added in v0.22.0

type FolderCache struct {
	Accounts        []CachedFolders `json:"accounts"`
	ThreadedFolders map[string]bool `json:"threaded_folders,omitempty"`
	UpdatedAt       time.Time       `json:"updated_at"`
}

FolderCache stores cached folders for all accounts.

func LoadFolderCache added in v0.22.0

func LoadFolderCache() (*FolderCache, error)

LoadFolderCache loads the folder cache from disk.

type FolderEmailCache added in v0.22.0

type FolderEmailCache struct {
	FolderName string        `json:"folder_name"`
	Emails     []CachedEmail `json:"emails"`
	UpdatedAt  time.Time     `json:"updated_at"`
}

FolderEmailCache stores cached emails for a specific folder.

type FolderKeys added in v0.36.0

type FolderKeys struct {
	NextFolder   string `json:"next_folder"`
	PrevFolder   string `json:"prev_folder"`
	Move         string `json:"move"`
	FocusPreview string `json:"focus_preview"`
	FocusInbox   string `json:"focus_inbox"`
}

type GlobalKeys added in v0.36.0

type GlobalKeys struct {
	Quit    string `json:"quit"`
	Cancel  string `json:"cancel"`
	NavUp   string `json:"nav_up"`
	NavDown string `json:"nav_down"`
}

type InboxKeys added in v0.36.0

type InboxKeys struct {
	VisualMode     string `json:"visual_mode"`
	ToggleThreaded string `json:"toggle_threaded"`
	Delete         string `json:"delete"`
	Archive        string `json:"archive"`
	Refresh        string `json:"refresh"`
	Search         string `json:"search"`
	Filter         string `json:"filter"`
	Open           string `json:"open"`
	NextTab        string `json:"next_tab"`
	PrevTab        string `json:"prev_tab"`
}

type KeybindsConfig added in v0.36.0

type KeybindsConfig struct {
	Global   GlobalKeys   `json:"global"`
	Inbox    InboxKeys    `json:"inbox"`
	Email    EmailKeys    `json:"email"`
	Composer ComposerKeys `json:"composer"`
	Folder   FolderKeys   `json:"folder"`
	Drafts   DraftsKeys   `json:"drafts"`
}

KeybindsConfig holds all configurable key bindings organized by area.

type LRU added in v0.39.0

type LRU struct {
	// contains filtered or unexported fields
}

func GetLRUInstance added in v0.39.0

func GetLRUInstance(threshold int) *LRU

func (*LRU) Delete added in v0.39.0

func (lru *LRU) Delete(folder string, uid uint32, accountID string)

func (*LRU) Get added in v0.39.0

func (lru *LRU) Get(folder string, uid uint32, accountID string) *CachedEmailBody

func (*LRU) LoadFromDisk added in v0.39.0

func (lru *LRU) LoadFromDisk() error

func (*LRU) Put added in v0.39.0

func (lru *LRU) Put(folder string, uid uint32, accountID string, body *CachedEmailBody)

type MailingList added in v0.20.0

type MailingList struct {
	Name      string   `json:"name"`
	Addresses []string `json:"addresses"`
}

MailingList represents a named group of email addresses.

type Node added in v0.39.0

type Node struct {
	Key    string // key = folder:uid:accountID
	Folder string
	Body   *CachedEmailBody
}

type SessionCache added in v0.40.0

type SessionCache struct {
	// contains filtered or unexported fields
}

Jump to

Keyboard shortcuts

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