FS-MAIL(1)                    User Commands                    FS-MAIL(1)

NAME
    fs-mail - synchronize IMAP mail as text files and send queued drafts

SYNOPSIS
    fs-mail [-c FILE] [--accounts FILE] [-a NAME ...] [--root DIR]
            [--set KEY=VALUE ...] [-q]
            [--receive-only | --sync-only | --send-only]
            [--ask-password | --non-interactive]
    fs-mail [-c FILE] [--accounts FILE] [-a NAME ...] --watch [SECONDS]
            [--set KEY=VALUE ...] [-q]
            [--receive-only | --sync-only | --send-only]
            [--ask-password | --non-interactive]
    fs-mail [-c FILE] [--accounts FILE] [--root DIR] --init
    fs-mail [-c FILE] [--accounts FILE] --init -a NAME --root DIR
    fs-mail [-c FILE] [--accounts FILE] --migrate-config
    fs-mail [-c FILE] [--accounts FILE] [-a NAME ...] --list-accounts
    fs-mail [-c FILE] [--accounts FILE] [-a NAME ...] --check-config
            [--set KEY=VALUE ...]
    fs-mail [-c FILE] [--accounts FILE] [-a NAME ...] --show-config
            [--set KEY=VALUE ...]
    fs-mail [-c FILE] [--accounts FILE] [-a NAME ...] --status
    fs-mail [-c FILE] [--accounts FILE] [-a NAME ...] -n
            [--receive-only | --sync-only | --send-only]
            [--set KEY=VALUE ...]
    fs-mail [-c FILE] [--accounts FILE] [-a NAME] --reply FILE
    fs-mail [-c FILE] [--accounts FILE] [-a NAME ...] --migrate-outbox
    fs-mail [-c FILE] [--accounts FILE] [-a NAME] --resolve JOB_ID
            --result sent|retry
    fs-mail [-c FILE] [--accounts FILE] [-a NAME] --resolve-sync LOCAL_ID
            --prefer local|remote
    fs-mail -h | --help
    fs-mail --manual
    fs-mail --config-help
    fs-mail --version

DESCRIPTION
    fs-mail uses ordinary files and directories as a mail interface. It runs
    in a terminal, from cron, or under a process supervisor. It has no
    graphical interface. Terminal runs ask for passwords privately when a
    configured secret file is absent or no source is configured. Scheduled
    runs use configured credential sources.

    Each account has an explicitly chosen mail root. The single-account
    default is ~/email. The server's INBOX is root/inbox/; other IMAP folders
    appear beneath that account's root. Downloaded messages are readable
    .txt files. Attachments are separate files named in each message.
    Original RFC message bytes are retained privately.

    A normal invocation submits eligible outbox/*.txt drafts over SMTP,
    reconciles tracked local IMAP changes against a stored baseline, and
    downloads new mail for all selected accounts. With no --account option,
    all configured accounts are selected in configuration order. Each has
    separate queue, state, locks, and error logs. A run finishes after one
    pass. --watch repeats this work in the foreground.

    Prepare new messages in drafts/. Moving a complete .txt file into
    outbox/ authorizes its submission on the next sending run. Each file
    contains its own recipients, subject, body, and attachment paths. There
    is no outbox address index. Outbox scanning is not recursive.

    A successfully submitted draft is removed from outbox/ and archived in
    sent-local/. Submission means that the SMTP server accepted the message;
    it does not prove delivery to a recipient's mailbox. If acceptance is
    uncertain, fs-mail holds the draft for explicit resolution.

COMMON COMMANDS
    Read help and configuration documentation without a configured account:

        fs-mail -h
        fs-mail --manual | less
        fs-mail --config-help | less

    Check setup, inspect effective values, and list account roots:

        fs-mail --check-config
        fs-mail --show-config
        fs-mail --list-accounts

    Choose an operation and, optionally, one account:

        fs-mail -a work --status
        fs-mail -a work -n
        fs-mail -a work --receive-only
        fs-mail -a work --sync-only
        fs-mail -a work --send-only
        fs-mail --reply ~/email/inbox/message.txt

    Limit one account's download pass without editing its INI:

        fs-mail -a work --receive-only --set download_folders=INBOX \
            --set max_download_mb_per_run=25

    Run unattended with a saved credential source:

        fs-mail --non-interactive --quiet

    --status and -n are local inspections. --receive-only downloads without
    applying local changes to the server. --sync-only can apply tracked
    moves, deletions, and flags. --send-only submits eligible outbox files.
    The ordinary command performs both sending and IMAP synchronization.

OPTIONS
    -c FILE, --config FILE
        Read behavior settings from FILE. The default is
        $XDG_CONFIG_HOME/fs-mail/config.ini, or
        ~/.config/fs-mail/config.ini when XDG_CONFIG_HOME is unset.
        A legacy combined file containing accounts remains supported.

    --accounts FILE
        Read account definitions from FILE. With split configuration, the
        default is accounts.ini beside the chosen behavior configuration.
        --init writes the account template here; --migrate-config writes the
        extracted account definitions here. Account roots are the explicit
        root values in those definitions, not directories inferred from FILE.

    -a NAME, --account NAME
        Select one configured account by name. Repeat this option to select
        several. Without it, ordinary runs and local account inspections
        select every account. A legacy configuration has the name default.
        An unknown name is an error before any account work begins.

    --list-accounts
        List selected account names, roots, and IMAP endpoints. Make no
        network connection, create no mail roots or state databases, and
        retrieve no credentials.

    --check-config
        Validate the complete INI configuration and effective selected-account
        settings, including command-line overrides. Print a successful check
        for the selected accounts. Make no network connection, resolve no
        credentials, and create no mail root or state database. This checks
        syntax and values, not provider authentication or server availability.

    --show-config
        Print effective selected-account configuration as formatted JSON after
        overrides. Resolve no credentials and create no mail directories or
        state. The output includes account names, roots, settings, and endpoints;
        credential-file paths and environment-variable names describe sources,
        while the entire configured credential command is redacted. No saved
        secret is read. This inspection output is not an INI file for reuse.

    --set KEY=VALUE
        Override a supported behavior setting for this invocation. Repeat for
        multiple keys; the last value for a repeated key wins. KEY may have a
        mail. prefix. Apply overrides only to selected accounts and reapply
        them after each watch reload. Do not change the INI. See CUSTOMIZATION
        and --config-help for supported keys, ranges, and precedence.
        Root, sender, endpoint, username, and credential settings are not
        accepted here; use the INI and the dedicated --root option.

    --root DIR
        Override the root of exactly one selected account for this run.
        With several selected accounts, require --account to choose one.
        The override must not overlap another configured account's root.
        Existing mail files or history bind a root to its IMAP host, port,
        and username. Do not use another account in an existing account's
        root.

    --init
        Create behavior and account templates plus the inbox/, outbox/, and
        drafts/ directories. The default files are config.ini and accounts.ini
        in the configuration directory. Refuse to overwrite existing files.
        Edit the server and account settings before connecting. A terminal
        run prompts when configured secret files are absent. With --account
        NAME, create one named-account template and require an explicit
        --root DIR. Account names never determine root directories.

    --migrate-config
        Back up and split an existing combined INI into behavior configuration
        and account definitions. Use --config for the input/behavior file and
        --accounts for an optional account-file destination. Perform no network
        or mail-state operations. This acts on the whole configuration;
        --account, --root, --set, and direction options do not apply. Existing
        combined configurations remain usable without migration.

    --status
        Report queued files, SMTP holds, local IMAP differences, and stored
        IMAP conflicts. Make no network connection. Server changes since
        the last synchronization are visible only after another sync.

    -n, --dry-run
        Perform local status checks and validate outgoing message content
        and attachment files. Make no network connection and send nothing.
        This does not validate server authentication or predict concurrent
        remote changes. Local state and error logs may be updated. Durable
        recovery can restore an interrupted local file replacement.
        With --send-only, inspect only outgoing drafts. With --sync-only,
        inspect only local IMAP changes. With --receive-only, show configured
        folder and size limits without opening state or creating mail roots;
        this policy preview cannot enumerate messages still on the server.

    --receive-only
        Download mail using read-only IMAP and BODY.PEEK. Do not submit
        outgoing drafts or apply local changes to the server. This mode
        does not mark downloaded mail as read. Read server flags and record
        a local baseline for newly downloaded messages, so later local moves
        or deletions can be synchronized on the next normal run.

    --sync-only
        Reconcile local IMAP changes and download mail without SMTP
        submission. Local message deletions and moves can change the server.

    --send-only
        Process the outbox without connecting to IMAP.

    --ask-password
        Obtain credentials through hidden terminal prompts, ignoring any
        configured credential_file, credential_env, or credential_command
        for this invocation. Ask only when a transport needs a credential;
        an empty outbox and offline commands do not cause SMTP prompts.
        With auth = xoauth2, ask for a current access token instead.
        No typed secret is saved to a file. Requires a controlling terminal.

    --non-interactive
        Disable credential prompts. Use this for cron, services, and
        detached watchers with configured credential sources. If a needed
        credential is unavailable, report an error without reading stdin
        or waiting for terminal input. This option does not suppress errors
        or change the explicit --reply editor command.

    --watch [SECONDS]
        Repeat runs, reloading configuration at least once a minute. SECONDS
        must be 30 through 86400 and overrides each selected account's interval.
        With no value, use each account's poll_interval, initially 300
        seconds after that account's preceding pass completes. Account runs
        are sequential; a slow account can delay others. A failed or busy
        account does not stop other accounts.
        Ctrl-C or SIGTERM stops the process. Combine with direction options.

    --reply FILE
        Create a new reply in drafts/ and open it in the selected editor.
        Use Reply-To, or From when Reply-To is absent. This is a reply to
        the sender, not reply-all. Quote the original body and preserve
        usable conversation threading headers. The new draft has its own
        required Subject. Do not copy attachments, local identity, or flags.
        Never send or place the reply in outbox/ automatically. Choose the
        account containing FILE, or use --account NAME explicitly. The
        reply belongs in that account's drafts/ and uses its outgoing sender.
        An explicit --account also permits replying to a separately saved
        text message outside the configured roots.
        For tracked received mail in the selected account, restore missing
        addressing/threading fields from its verified private raw archive.
        Explicit visible values, including empty ones, take precedence. Quote
        the current readable body. No network or arbitrary Raw-Message path
        is used. Exported files need their own visible addressing metadata.

    --resolve JOB_ID --result sent
        Record that an uncertain SMTP submission was accepted and complete
        local archive/queue cleanup. Obtain JOB_ID from --status. Check the
        server or recipient before making this assertion.

    --resolve JOB_ID --result retry
        Release a held SMTP draft for a later sending run. This command
        itself makes no network connection. Authorizing a retry after an
        unknown acceptance can produce a duplicate message.

    --resolve-sync LOCAL_ID --prefer local|remote
        Record how to resolve the specified IMAP conflict. Obtain LOCAL_ID
        from --status. Apply the resolution on a later normal or --sync-only
        run. This command itself makes no network connection. See RECOVERY.

    --migrate-outbox
        Convert legacy indexed drafts into self-contained .txt messages.
        Preserve backups, retire converted index entries, and send nothing.
        An interrupted migration can be rerun. A nonempty legacy index or
        unfinished migration blocks ordinary sending until resolved.

    -q, --quiet
        Suppress routine run progress. Errors remain visible on standard
        error. Explicit status, migration, reply, and resolution commands
        still report their result. Explicit configuration inspection also
        reports its result.

    -h, --help
        Display grouped command-line options and commonly used commands.
        Require no configuration and make no filesystem or network changes.

    --manual
        Print this release's complete plain-text manual to standard output.
        The installed executable includes it. Pipe through less or redirect
        it to a file as needed. Require no configuration, credentials, or
        network access.

    --config-help
        Print the supported configuration catalog, including defaults, types,
        limits, section rules, and override precedence. Require no account
        configuration and perform no network or mail-state operations.

    --version
        Display the program version.

    Action options such as --status, --reply, --resolve, and --watch are
    mutually exclusive. The three direction options are mutually exclusive.
    --result requires --resolve; --prefer requires --resolve-sync.
    --ask-password and --non-interactive are mutually exclusive.
    --resolve and --resolve-sync require exactly one selected account; add
    --account NAME when several accounts are configured. --root also requires
    one selected account. --status, --dry-run, and --migrate-outbox apply to
    every selected account. --list-accounts is a separate action.
    Direction options are supported with normal runs, --watch, and -n only.
    --set is rejected with --init, --migrate-config, --manual, --config-help,
    and --list-accounts. --migrate-config also rejects --account and --root.
    Use full long-option spellings; abbreviated long options are not accepted.

FILE FORMAT
    An outgoing file must start with To: on its first line and contain a
    nonempty Subject: header. Separate headers from the body with a blank
    line. An empty body is allowed. The canonical layout is:

        To: Alice Example <alice@example.net>, bob@example.net
        Cc:
        Bcc:
        Attachments: /home/user/Documents/report.pdf
        Subject: Quarterly report

        The report is attached.

    Cc:, Bcc:, and Attachments: may be omitted, empty, or appear in another
    order after To:. Attachment: is accepted as an alias for Attachments:.
    Header names are case insensitive after the required initial To:.
    Duplicate, unknown, folded, or malformed headers are errors. A line
    resembling a header below the blank separator is ordinary body text.

    To, Cc, and Bcc are comma-separated recipient lists. Quote display names
    containing commas, for example "Example, Alice" <alice@example.net>.
    At least one To recipient is required. Address groups, empty list items,
    and malformed addresses are rejected. Internationalized domain names
    are supported; address local parts must be ASCII. Unicode display names,
    subjects, and body text are supported.

    Bcc recipients are included in the SMTP envelope and omitted from the
    transmitted message headers. Duplicate envelope addresses are collapsed.
    Every recipient must be accepted before the message body is submitted;
    a rejected recipient leaves the whole draft queued.

    Attachments is a comma-separated list of absolute filesystem paths.
    Relative paths, ~ abbreviations, parent-directory components, empty list
    items, and malformed quoting are errors. Quote a path containing a comma
    or a quote; inside a quoted path, double a literal quote:

        Attachments: "/home/user/Reports/July, final.pdf", /tmp/chart.png

    Attachment files must be readable regular files, not symlinks or special
    files. They are copied into the durable submission record. The original
    attachment files are retained after sending. An empty Attachments header
    or an omitted header means no attachments.

    Subject is required for sending. A missing, empty, or whitespace-only
    subject is an error; a filename is never used as its replacement.

    By default, received files begin with To, Cc, Bcc, Attachments, and Subject,
    followed by Flags and available message metadata. view_headers selects
    and orders the visible fields for newly received views. To must be first,
    Subject must be present, and Local-ID and Account-ID are retained for
    synchronization. Keep existing identity metadata intact when moving,
    renaming, or editing a received message. See RECEIVED HEADERS.

    The selected account's configured from determines the sender of outgoing
    mail; in legacy configurations this is mail.from.
    Incoming From, Date, Message-ID, Local-ID, Account-ID, Flags, Raw-Message, and
    SMTP-Status metadata do not override the outgoing sender or become
    arbitrary transmitted headers. Supported Reply-To and conversation
    threading headers are preserved when valid.

    New downloaded files and replies use UTF-8. Input accepts LF, CRLF, or CR
    line endings. Automatic decoding recognizes UTF-8 and supported UTF-16
    and UTF-32 signatures, then falls back to mail.legacy_encoding, initially
    cp1252. mail.text_encoding selects the decoding of outgoing drafts.
    Received views and --reply inputs always recognize UTF-8 and Unicode
    byte-order marks first, even when outgoing decoding is forced. For those
    local files, the forced codec is a legacy fallback; otherwise the fallback
    is mail.legacy_encoding. Invalid byte sequences, binary NUL, and unsafe
    header controls are errors.

RECEIVED HEADERS
    view_headers is a comma-separated list of visible received-message header
    names in their desired order. Names are case insensitive. Configure it in
    [mail] in config.ini, in [account NAME] in accounts.ini, or with --set:

        view_headers = To,From,Subject,Date,Attachments

        fs-mail --receive-only \
            --set 'view_headers=To,From,Subject,Date,Attachments'

    To must be first and Subject must be included. Local-ID and Account-ID are
    mandatory; if not explicitly listed, they are appended. Duplicate, unknown,
    or empty names are errors. This is a presentation setting for new received
    views. Existing files are not rewritten to apply a changed layout. Keep
    identity fields already present in those files intact.

    The default order is To, Cc, Bcc, Attachments, Subject, Flags, From, Date,
    Message-ID, Reply-To, In-Reply-To, References, Local-ID, Account-ID, and
    Raw-Message. These are also the complete set of selectable
    fields. A field without source metadata is omitted, except that selected
    To, Cc, Bcc, Attachments, and Subject fields can be empty.

    To
        The visible primary recipients. Incoming mail may omit this header,
        for example for blind copies; a received view can therefore have an
        empty To. Sending requires at least one valid To address.

    Cc
        The visible copy recipients. Optional in an outgoing draft.

    Bcc
        Blind-copy recipients, when present in the source. Received mail often
        has no Bcc information. Outgoing Bcc is used for SMTP recipients and
        omitted from the transmitted message headers.

    Attachments
        Absolute local paths to extracted MIME files. Outgoing drafts use the
        same comma-separated path syntax to choose files to attach. Omitting
        this field from the received view does not avoid downloading or
        extracting attachments. Files remain in attachments/LOCAL_ID/.

    Subject
        The decoded message subject. A received view may have an empty value
        when the source has no subject; outgoing drafts require a nonempty
        value. The default filename does not include the subject.

    Flags
        Editable synchronization flags, such as seen, answered, flagged, or
        draft. An empty value means none of the editable flags are set. A
        view created without this header leaves flags in private state; it
        does not request clearing them. Add a Flags line when you want to
        edit flags in such a file. Once a tracked file has an explicit Flags
        line, preserve it; deleting the line is not a way to mark unread.
        Opening a file does not change its flags. See SYNCHRONIZATION.

    From
        The source message's sender. Changing this descriptive received field
        does not change the account used for outgoing mail; the configured
        account from setting controls that sender.

    Date
        The source message's date, which can differ from its arrival time.
        Filename date options use this message date. An invalid or absent
        date has the fallback described under FILENAMES.

    Message-ID
        The source message's protocol identifier. Replies use it for threading
        when usable. It is not fs-mail's filesystem synchronization identity;
        it may be absent or duplicated in real mail.

    Reply-To
        The source's requested reply address. --reply uses it in preference
        to From when it is available.

    In-Reply-To
        The protocol identifier of the message being answered, when supplied.
        It helps recipients place a reply in its conversation.

    References
        The available chain of protocol message identifiers for conversation
        threading. --reply preserves usable threading metadata.

    Raw-Message
        The local path of the preserved original RFC message. This archive
        retains MIME structure, original headers, and attachment bytes.
        Hiding the field does not remove the archive. Keep a previously
        recorded Raw-Message value intact in an existing tracked file.

    Local-ID
        A stable fs-mail identity tying the readable file to its recorded
        mailbox, UIDVALIDITY, and UID. Renaming or moving the text file within
        its account retains this identity. Required; never edit or remove it.

    Account-ID
        Provenance derived from the account's IMAP endpoint and username.
        It distinguishes otherwise similar identities in separate accounts.
        It is not the editable account label. Required; keep it intact.

    Received descriptive fields and local annotations do not rewrite server
    MIME content. Local-ID, Account-ID, and recorded Raw-Message values protect
    synchronization identity. Raw mail, attachments, and state remain available
    even when optional visible metadata is omitted.
    --reply can recover omitted recipient/threading metadata from the verified
    private archive of this account's tracked message. Explicit visible fields
    take precedence and the quote uses locally edited body text. Exported files
    must still carry usable visible sender information.

ATTACHMENT DOWNLOADS AND BANDWIDTH
    This release downloads complete messages, including embedded attachments.
    The default includes every selectable IMAP folder. The first synchronization
    may therefore fetch a large archive. Saved state prevents repeated body
    downloads for completed messages. DOWNLOAD POLICY describes folder filters,
    the per-run payload budget, and the other download limits.

    Headers-only views and on-demand MIME-part fetching are not implemented.
    The proposed --download-folder and --download-attachments commands are not
    available. --receive-only prevents remote changes and SMTP submission;
    download filters choose which folders supply new bodies. Reducing
    max_message_mb skips whole large messages, including their readable body.
    Disabling extraction alone would not save transfer of the raw message.

    Extracted attachments are ordinary files stored under:

        ACCOUNT_ROOT/attachments/LOCAL_ID/safe-filename.ext

    The default received view lists all extracted files as absolute paths in
    Attachments:. Hiding this header does not stop extraction or downloads.
    The Local-ID directory is stable when the readable .txt is
    renamed or moved between folders in the same account. Commas in paths are
    quoted. Names use portable ASCII and retain useful filename extensions;
    colliding names receive suffixes. The original names remain in raw mail.
    Moving attachments separately or relocating the whole account does not
    rewrite saved absolute paths; update those paths when relocating data.

    MIME transfer encodings are decoded. Inline binary parts and attached
    .eml messages are also saved. Files are never opened or executed, and
    linked remote images are not fetched. Deleting or editing an extracted
    file changes only that local copy. It does not edit the server message.
    Deleting the readable message does not purge attachments or raw mail.
    Completed downloads do not recreate manually deleted attachments on each
    run; use the original .eml file or a backup for recovery.

    Interrupted extraction reuses matching files. Changed files, symlinks,
    and unsafe paths cause an error instead of an overwrite. A download is
    marked complete only after durable publication of raw mail, attachments,
    and the readable view. The default Raw-Message field identifies the
    retained original; hiding the field does not remove the raw archive.

    Incoming metadata permits 4 MiB of headers so a complete attachment list
    remains usable with many files or long account paths. Outgoing drafts
    retain limits of 64 KiB of headers, 16,384 characters per header line,
    and 100 attachments. Select files or split the submission when forwarding
    a list that exceeds these limits. --reply creates a draft without attachments.

DOWNLOAD POLICY
    Configure these behavior settings in [mail], [account NAME], or --set:

        download_folders = *
        download_exclude =
        max_download_mb_per_run = 0

    download_folders is a comma-separated list of remote IMAP folder-name
    patterns. At least one include pattern must match for a folder's new
    message bodies to be downloaded. The default * includes all selectable
    folders. download_exclude is another pattern list; an exclusion always
    wins. Its default is empty.

    Patterns use shell-style *, ?, and bracket character classes. * may match
    the server's hierarchy delimiter. Matching is case sensitive except for
    the special INBOX name. Patterns match remote names, not the local escaped
    directory names. Quote a comma-containing pattern as one CSV field:

        download_folders = INBOX, "Projects, active"
        download_exclude = Trash, Junk

    For example, restrict one invocation to Inbox and a 25 MiB payload budget:

        fs-mail --receive-only --set download_folders=INBOX \
            --set max_download_mb_per_run=25

    Filters govern incoming message-body downloads. Existing local files are
    retained when a folder is excluded. Normal and --sync-only runs still
    reconcile already tracked messages in other folders; exclusions do not
    disable pending remote moves, deletions, or flag changes. --receive-only
    prevents those remote mutations and does not submit outbox messages.

    max_download_mb_per_run is an incoming raw-message payload budget per
    account and per run, in MiB. The default 0 is unlimited. Positive values
    range from 1 through 1048576. This covers complete raw messages, including
    attachments, but not protocol metadata or transport overhead. It is not
    an SMTP limit. max_messages_per_run still bounds attempted messages, and
    max_message_mb still limits each individual complete message.

    The advertised raw-message size is reserved before its body is requested.
    A message that will not fit the remaining budget is left pending for a
    later run; smaller messages may still fit. Deferred identities remain in
    the retry queue even if the new-mail cursor advances. A message larger
    than the entire per-run budget reports an error and stays on the server;
    increase max_download_mb_per_run or set it to 0 to fetch it. Reservations
    for failed fetches remain spent for that run because bytes may already
    have crossed the connection. Each new account pass starts a fresh budget.

SYNCHRONIZATION
    fs-mail stores a last-synchronized baseline. It compares the current
    files and server state against that
    baseline. Local-ID binds a readable file to a mailbox, UIDVALIDITY, and
    UID independently of its filename. --status shows the local differences.

    New received files carry Account-ID, derived from the bound IMAP endpoint
    and username. A foreign received file in a mailbox directory is held
    rather than matched to a coincident Local-ID from this account. Legacy
    tracked files use their saved Raw-Message reference to detect a foreign
    substitution. Keep the identity metadata and private baseline together.
    Removing or changing previously recorded Account-ID or Raw-Message
    metadata is held.
    Account-ID depends on the IMAP endpoint and username, not the account's
    configured label or root. Recognized legacy provenance permits moving an
    entire account tree together with its private state.

    Newly downloaded messages receive a local baseline even in --receive-only
    mode. Older files inherited without a saved baseline are adopted before
    local changes are pushed; their pending changes can take another run.
    An absent older file with no baseline does not authorize remote deletion.
    Batch limits can defer remaining work to a later invocation.

    Rename a file within a mailbox directory
        Retain its message identity and local filename. IMAP has no matching
        filename operation, so no remote message rename is required.

    Move a tracked file into another mailbox directory in the same account
        Request a server-side message move. If the destination directory
        represents a new mailbox, fs-mail creates the required mailbox when
        the server namespace can be mapped unambiguously. Empty directories
        alone do not create or remove server folders. A directory rename
        containing tracked messages is processed as individual message moves,
        not as an IMAP RENAME command.

    Delete a tracked file
        Request deletion of that exact remote message on the next sync.
        Removing it with a file manager is sufficient. Original raw bytes
        and stored snapshots remain locally available for recovery. To keep
        a local copy without requesting this deletion, copy the file outside
        the synchronized root and leave the tracked original in place. Moving
        the original outside the root normally leaves a local deletion and
        requests deletion of the remote message on the next sync. An
        identifiable move to another configured account root is held as
        described below.

    Change Flags
        Edit the comma-separated Flags header. An empty value means unread
        with no editable flags set. A view created without Flags leaves them
        unspecified locally; it is not a request to clear server flags. Add
        the header to make an explicit change. Removing an existing tracked
        Flags line is held as a conflict rather than interpreted as unread.

        Flags: seen, answered, flagged, $forwarded

        seen, answered, flagged, and draft map to the corresponding IMAP
        system flags. Names are case insensitive. User keywords must be
        safe ASCII IMAP atoms and are normalized to lower case. Quote a
        keyword that would otherwise be a system flag name: "seen" names
        the literal keyword, while seen names the Seen system flag.
        Recent and Deleted are not editable system flags. Delete the tracked
        file to request deletion. Opening or previewing a file does not
        automatically set seen.

    Change the body or descriptive headers
        Keep local annotations. Such edits are not uploaded as a replacement
        IMAP message body. Compose a new outbox draft to send revised content.

    Copy a tracked file
        Copies carrying the same Local-ID within the synchronized tree are
        ambiguous and held. They are not uploaded as new IMAP messages. Keep
        one tracked representation inside the tree; place independent
        archival copies outside it without removing the tracked original.

    Move a received file between account roots
        If an otherwise missing tracked file is identifiable in another
        account root in the same configuration, hold the source deletion.
        Consider all configured roots, including accounts not selected for
        this invocation. Foreign identity metadata is also held in the
        destination mailbox directory. This does not perform a server-side
        transfer or upload the file as a new IMAP message. Keep the identity
        metadata intact and move the file back to resolve an accidental move.
        The guard cannot search unknown or unconfigured directories; moving
        the original there can still request deletion from its source account.

    Peer-root identity checks
        These checks run only for otherwise missing tracked identities.
        They examine regular-file identity headers, including in peer drafts,
        outbox, and attachments areas, without following symlinks. Peer
        .fs-mail areas and root errors.log files are excluded. Account-ID
        establishes provenance; legacy files use the saved Raw-Message path.
        A matching legacy Local-ID with missing provenance is held as
        ambiguous. An unreadable or incomplete peer scan holds otherwise
        missing originals instead of authorizing deletion.

    Peer-root scan limits
        One scan is bounded to 100000 candidate files and 256 MiB of header
        reads across peer roots, with at most 256 KiB plus four bytes per
        candidate. Hitting a bound holds deletion. Accounts stored only in
        a different configuration file are not known peers of this invocation.
        A configured peer root that has not been created yet is skipped.

    Reserved areas
        drafts/, outbox/, sent-local/, and attachments/ are local-only areas,
        not IMAP move destinations. Moving a tracked message into one of
        these areas is held for IMAP correction. An extracted attachment
        containing a copy of a message does not create a duplicate-identity
        conflict while the tracked original remains in its synchronized
        location.

    An outgoing file with valid headers still requests SMTP submission.
    A durable guard keeps sending a moved received file from being interpreted
    as deletion of the original IMAP message after outbox cleanup. The IMAP
    identity remains held for explicit resolution. Prefer --reply, or copy
    the received file while leaving its original in the mailbox directory.

    When one account sends a received file originating from another account,
    accepted cleanup checks whether the original is still visible. If it
    cannot prove that, retain the received source separately from the sent
    receipt in the sending root's sent-local/retained-source-JOBID.txt.
    Collision suffixes keep an existing file intact. The retained source
    preserves received identity metadata so the originating account's peer
    scan can still protect its missing message after SMTP cleanup. Restore
    this source to its originating account's mailbox folder to repair an
    accidental move. A verified copy with its original still present uses
    ordinary cleanup. If the originating account's required local lock is
    busy or cannot be obtained, defer accepted-job cleanup for a later run;
    never resubmit it to SMTP.

    Server flag changes are reflected locally. If a remote message disappears,
    its readable file is retained as a local archive and remote tracking ends;
    conflicting local changes are held first. A message moved by another
    client may therefore leave an archive in its old local folder and a new
    downloaded file in its destination. fs-mail does not guess a cross-folder
    identity from matching content.

    Server changes are pulled when they can be reconciled safely. Concurrent
    incompatible changes, changed UIDVALIDITY, duplicate identities, invalid
    metadata, incomplete filesystem scans, and unknown mutation outcomes are
    held for review. fs-mail does not infer remote identity from Subject or
    Message-ID alone.

    Flag writes require CONDSTORE with a usable per-message MODSEQ and use
    UNCHANGEDSINCE. A MODIFIED response holds the change. Exact message
    deletion requires UIDPLUS, or the corresponding IMAP4rev2 support.
    Moves require MOVE and UIDPLUS, or IMAP4rev2, with a verified COPYUID
    mapping. fs-mail never falls back to global EXPUNGE. Download-only use
    remains available when a server lacks mutation capabilities.

FILES
    Paths below illustrate a single account rooted at ~/email. For named
    accounts, substitute each configured root. These directories, logs, and
    state belong to that account, not to a shared parent directory.

    ~/email/inbox/
        Readable INBOX messages. Older root-level INBOX files are migrated
        when fs-mail recognizes their saved download records.

    ~/email/<folder>/
        Readable files for other IMAP folders. Unsafe or colliding remote
        names are encoded in local directory names; the saved folder map
        records the correspondence.

    ~/email/outbox/
        Live submission queue. Only eligible non-hidden .txt files directly
        in this directory are considered. Temporary names and other file
        extensions are ignored; invalid .txt entries report an error.

    ~/email/drafts/
        Unsubmitted working drafts and saved replies. Duplicate held drafts
        moved out of the queue during explicit recovery are retained here.

    ~/email/sent-local/
        Readable archive of SMTP submissions accepted by the server. This
        is a local archive; fs-mail does not APPEND to a remote Sent folder.
        retained-source-JOBID.txt files preserve received originals when
        cross-account submission cleanup cannot prove the originals remain
        in their source account. They are separate from normal sent receipts.

    ~/email/attachments/
        Extracted received attachments and archived outgoing attachments,
        grouped by local message or job identity.

    ~/email/errors.log
        Append-only error log. Each line begins with a UTC timestamp. Run
        errors also go to standard error. --quiet does not suppress errors.
        The log is not rotated automatically.

    ~/email/.fs-mail/
        Private database, lock, original .eml files, submission journals,
        baseline snapshots, recovery files, and folder mappings. Retain this
        directory with the mail tree when backing up or moving an account.
        Deleting it discards synchronization and duplicate-send protection.

    ~/.config/fs-mail/config.ini
        Default behavior configuration when XDG_CONFIG_HOME is unset.
        Legacy combined account/behavior files remain supported.

    ~/.config/fs-mail/accounts.ini
        Default account definitions beside config.ini. --accounts can choose
        another file. Each account specifies its root, sender, and endpoints.

CONFIGURATION
    The configuration is UTF-8 INI text. --init writes config.ini for shared
    behavior and accounts.ini for named accounts, roots, senders, and transports.
    With no --account name, its example account is default with root ~/email.
    --accounts selects another account file; otherwise it is accounts.ini
    beside the chosen --config file. A missing behavior file is allowed when
    the account file exists; built-in defaults then apply.
    No shell is used for substitutions or credential commands. Percent signs
    in date_format are literal INI values, not configuration interpolation.
    Unknown keys and sections are errors. Section names are case sensitive;
    INI setting names are case insensitive. Use --check-config after editing.
    --config-help shows the complete accepted catalog without reading an INI.

    Existing combined INIs remain supported. The original [mail], [imap],
    [smtp] form represents one account named default, with root and from in
    [mail]. A combined named-account file can contain [mail] plus account and
    transport sections. Do not pass --accounts with an account-bearing combined
    --config file; split it using --migrate-config first.

    In split configuration, accounts.ini contains [account NAME], [imap NAME],
    and [smtp NAME]. Each account explicitly supplies root and from. Optional
    behavior settings in an account override config.ini's shared [mail] values.
    Do not put shared root or from values in [mail], or unqualified [imap]/[smtp]
    sections in accounts.ini. For example, the behavior config.ini contains:

        [mail]
        poll_interval = 300
        filename_format = {date}_{sender}_{id}.txt
        date_format = %Y-%m-%d
        filename_timezone = utc
        download_folders = *
        download_exclude =
        max_download_mb_per_run = 0

    The separate accounts.ini contains:

        [account personal]
        root = ~/email/account1
        from = Your Name <you@example.net>

        [imap personal]
        host = imap.example.net
        port = 993
        security = ssl
        username = you@example.net
        credential_file = ~/.config/fs-mail/personal-imap.secret

        [smtp personal]
        host = smtp.example.net
        port = 465
        security = ssl
        username = you@example.net
        credential_file = ~/.config/fs-mail/personal-smtp.secret

        [account work]
        root = ~/otheremail
        from = Your Name <you@example.org>
        poll_interval = 600

        [imap work]
        host = imap.example.org
        port = 993
        security = ssl
        username = you@example.org
        credential_file = ~/.config/fs-mail/work-imap.secret

        [smtp work]
        host = smtp.example.org
        port = 587
        security = starttls
        username = you@example.org
        credential_file = ~/.config/fs-mail/work-smtp.secret

    Replace the example addresses, usernames, and endpoints before connecting.
    examples/config.ini and examples/accounts.ini provide split examples.
    examples/multi-account.ini is a supported combined-format example.

    Account names are case sensitive and contain 1 through 64 ASCII letters,
    digits, dots, underscores, or hyphens, starting with a letter or digit.
    Use [mail] in config.ini for shared defaults; [DEFAULT] is not supported.

    root is the account's mail directory. A named account must specify an
    absolute path, with ~ allowed for the home directory. No root is inferred
    from its name or username. Roots must be distinct and must not contain
    one another; symlink aliases are refused. ~/email/account1 together with
    ~/email/account2 is valid, as is ~/email together with ~/otheremail. A
    root at ~/email cannot coexist with another at ~/email/account2 because
    the first account's filesystem scan would enter the second account.

    from is one sender address for that account. Its outbox is submitted
    through its SMTP section. Account state remains bound to the IMAP host,
    port, and username once mail files or history exist. Editing a login does
    not safely turn an existing root into another account. To add an account,
    add a new set of named sections and choose its own root.
    Unsent drafts count as account content. Empty directories and errors.log
    alone permit correcting an otherwise unused template account.

    To split an existing combined configuration with a retained exact backup:

        fs-mail --migrate-config
        fs-mail --check-config

    The backup is config.ini.pre-split beside the behavior file, with private
    permissions. Account definitions are published before replacing config.ini
    with behavior settings. Unrelated existing backups or account files are
    not overwritten. Matching interrupted artifacts can be resumed; an already
    split configuration is a no-op. --accounts selects another destination.
    Relative credential-file paths are made absolute when needed to preserve
    their original targets. Root paths and mail state are retained. Migration
    does not connect to a server, resolve credentials, or open mail state.

    Optional behavior settings, in [mail] or [account NAME], are:

        timeout = 60
        max_message_mb = 50
        max_messages_per_run = 500
        poll_interval = 300
        text_encoding = auto
        legacy_encoding = cp1252
        filename_format = {date}_{sender}_{id}.txt
        date_format = %Y-%m-%d
        filename_timezone = utc
        download_folders = *
        download_exclude =
        max_download_mb_per_run = 0

    timeout is the connection/credential-command timeout in seconds, from 1
    through 600. max_message_mb is the message-size limit in MiB, from 1
    through 512. MIME encoding can expand attachments, so outgoing content
    below the limit may still exceed it after encoding. The limit also
    bounds incoming raw messages. max_messages_per_run is from 1 through
    100000, per account. poll_interval is from 30 through 86400 seconds.
    See FILE FORMAT for text decoding, FILENAMES for naming options, RECEIVED
    HEADERS for view_headers, and DOWNLOAD POLICY for folder filtering and the
    per-run body-byte budget. --config-help lists every key and default.

    IMAP and SMTP sections accept host, port, security, username, auth, and
    one optional credential source. The default ports are IMAP 993 and SMTP
    465. security is ssl for implicit TLS or starttls for a required TLS
    upgrade. IMAP port 143 and SMTP port 587 normally use starttls. Use the
    provider's actual endpoints. Certificates and hostnames are verified;
    plaintext authentication is not available.

    auth defaults to password; xoauth2 instead expects a current OAuth access
    token. A password may be a provider-specific app password. fs-mail does
    not perform browser login or refresh tokens itself.

    Configure a secret file if it should supply a password when present:

        credential_file = ~/.config/fs-mail/personal-imap.secret

    A missing file falls back to a hidden terminal prompt. No configured
    credential source also means prompting. Existing secret files continue
    to serve cron and services. Typing a password never creates or updates
    the file. Local commands and an empty outbox do not need SMTP credentials.
    For auth = xoauth2, the prompt requests a current access token.

    A prompt uses the foreground controlling terminal, identifies the
    account, protocol, and endpoint, and never reads redirected standard
    input. Without a terminal, or with --non-interactive, a missing secret
    reports an error. --ask-password overrides configured sources for one
    invocation without editing config.ini. Prompts do not fall back to echo.

    Missing-file fallback is limited to an absent file. Unsafe permissions,
    symlinks including dangling symlinks, non-regular files, empty or malformed
    secrets, failed commands, and unset environment variables remain errors.
    A credential file must be a regular file owned by the current user with
    no group or other permission bits; mode 600 is suitable. Relative file
    paths are resolved beside the accounts file that defines the endpoint,
    or beside the legacy combined INI. Contents are only the
    password or token, optionally followed by a newline.

    Other sources are available; select no more than one per transport:

        credential_env = FS_MAIL_IMAP_PASSWORD
        credential_command = /usr/bin/pass show mail/imap

    Commands are split into arguments and run without a shell or terminal
    input. They must finish within timeout and print only the credential.
    Do not embed pipes, redirections, or interactive prompts.
    Output is capped at 64 KiB while it is read. A timed-out or overproducing
    helper and its ordinary child processes are stopped.

    Prompted credentials are retained only in process memory, separately
    for each account, root, transport, and endpoint, including --watch cycles.
    Configured sources are read when needed. A newly created secret file
    takes precedence over a cached prompted value. Restart to enter a
    different prompted password or token. No secret is shared automatically
    between accounts or IMAP and SMTP.

    Successful watch reloads discard typed credentials for removed accounts
    or changed endpoints. At most two typed credentials per selected account
    remain cached. A temporary invalid configuration preserves the last valid
    cache until settings can be loaded again.

    Configuration is validated before account operations. An invalid account
    or overlapping root stops the invocation. After validation, a runtime
    failure in one account is reported while remaining accounts continue.
    Each root contains its own errors.log, outbox, locks, and private state.
    Errors before account selection, such as invalid configuration, go to
    standard error without selecting an arbitrary account log.

    Mail directories are private and created with mode 700; ordinary
    generated message, state, and configuration files use mode 600.
    Symlink and special-file substitutions are rejected where files are
    read or replaced. Use a normal Unix filesystem for the working tree.

CUSTOMIZATION
    Settings have the following precedence, from lowest to highest:

        built-in defaults
        shared [mail] settings
        per-account [account NAME] settings
        --set overrides for selected accounts

    In the legacy single-account layout, [mail] contains that account's root,
    sender, and behavior settings. For named accounts, shared [mail] has only
    behavior settings; root and from are explicit in each account section.

    A command-line override leaves the stored configuration unchanged:

        fs-mail -a work --receive-only --set max_messages_per_run=10
        fs-mail -a work --sync-only --set timeout=120
        fs-mail -n --set max_message_mb=10
        fs-mail -a work --show-config --set date_format=%Y%m%d

    Quote a filename template or a value containing shell metacharacters:

        fs-mail --receive-only --set 'filename_format={sender}_{date}_{id}.txt'

    Supported behavior keys are timeout, max_message_mb, max_messages_per_run,
    poll_interval, text_encoding, legacy_encoding, filename_format, date_format,
    filename_timezone, view_headers, download_folders, download_exclude, and
    max_download_mb_per_run. The optional mail. prefix is equivalent, as in
    --set mail.timeout=120. A repeated key uses its last supplied value.

    The complete INI is validated, including unselected accounts, before
    overrides are applied. A command-line override does not conceal an invalid
    INI setting, unknown section, or overlapping root. Endpoint and credential
    settings stay in the configuration; they are not --set keys. --root remains
    a separate override with the normal account-identity and overlap checks.

    Watch mode reapplies the same command-line settings on each reload.
    An explicit --watch SECONDS controls that invocation's polling interval.
    Separate -c FILE configurations can provide different persistent profiles;
    -a NAME selects which accounts receive this invocation's overrides.

    --show-config emits JSON with schema_version 1, credentials_resolved false,
    and an accounts array. Each account includes its name, root, from address,
    behavior/account source paths, configuration_layout (split or combined),
    effective settings, and IMAP/SMTP endpoints. Credential
    commands are represented by [redacted]. Paths and environment-variable
    names identify sources without resolving them. The output still contains
    addresses, hosts, and paths; it is an inspection record, not a replacement
    INI file. It can be processed by ordinary JSON tools.

    Editors, schedulers, pagers, and file managers remain separate programs.
    Select an editor through EDITOR or VISUAL, schedule fs-mail through cron or
    a supervisor, and pipe --manual through your preferred pager. Message text
    files use the documented format; Local-ID, Account-ID, and Raw-Message are
    synchronization identity fields and must retain their meaning.

FILENAMES
    Newly downloaded messages and new sent-local archives use these defaults:

        filename_format = {date}_{sender}_{id}.txt
        date_format = %Y-%m-%d
        filename_timezone = utc

    A resulting name has this form:

        2026-10-24_nameATdomain.tld_2525253525235235.txt

    The subject remains inside the message by default. Set naming options
    globally in [mail] or override them in [account NAME]. Settings affect
    new downloads and new sent-local archive paths; completed and pending
    download paths and already recorded sent archive paths remain intact.
    Manual file renaming continues to work because identity is carried by
    Local-ID and private state, independently of the visible filename.

    Available filename fields are:

        {date}            Message Date formatted using date_format.
        {timestamp}       Message Date as UTC Unix seconds.
        {sender}          First From address, replacing @ with AT.
        {sender_address}  First From address, retaining a safe @.
        {sender_name}     Sender display name, or the address local part.
        {subject}         Decoded Subject as a safe filename component.
        {id}              Stable decimal representation of Local-ID.
        {local_id}        The original hexadecimal Local-ID.
        {uid}             Source mailbox IMAP UID.
        {uidvalidity}     Source mailbox UIDVALIDITY.
        {account}         The configured account name.

    For sent-local archives, use the submission's Date header for {date} and
    {timestamp}, its outgoing From address for sender fields, and its stable
    outgoing job identity for {id}; {local_id} is the hexadecimal job ID.
    IMAP-only {uid} and {uidvalidity} expand to no-uid and no-uidvalidity.
    These archives do not become synchronized
    IMAP messages merely because a filename contains an identity field.

    filename_timezone is utc or local. The message Date is converted to that
    timezone for {date}; {timestamp} always describes the same UTC instant.
    A Date without a timezone is assumed UTC. A missing or invalid Date uses
    unknown-date for both fields; the current time is not substituted.

    date_format accepts these strftime-style directives:

        %% %a %A %b %B %c %d %f %G %H %I %j %m %M %p %S
        %U %u %V %w %W %x %X %y %Y %z %Z

    Common examples are %Y-%m-%d for an ISO-style date, %Y%m%d-%H%M%S for a
    compact date and time, and %d-%m-%Y for day-month-year order. %% inserts a
    literal percent sign. Names and locale-based directives follow the
    process locale. Unknown directives are rejected. Slashes or backslashes
    in formatted dates become dashes rather than creating directories.

    Filename templates contain literal text and simple named fields only.
    They must produce one non-hidden .txt basename, with no path separator,
    control character, or leading dash. Attribute access, indexing, field
    conversions, and format specifiers are rejected. Use {{ and }} for
    literal braces. A template is limited to 512 UTF-8 bytes; date_format is
    limited to 256. These are text formats, not shell commands or programs.

    Header-derived components are transliterated to ASCII, unsafe characters
    become dashes, and each component is limited to 80 characters. The final
    filename is limited to 240 bytes; truncation keeps a stable numeric ID
    suffix. A template may omit {id}. If its name collides with another file,
    add _ID before .txt; if necessary, append a numbered collision suffix.
    Existing files are never overwritten by naming collisions.
    If a substituted field begins the whole filename with a dot or dash,
    prefix message_ so it remains visible and safe as a command argument.

    Example alternative settings:

        filename_format = {sender}_{date}_{id}.txt
        date_format = %Y%m%d-%H%M%S

    Or retain the subject in the filename:

        filename_format = {date}_{subject}_{id}.txt

    These settings control received-message and sent-local archive filenames.
    Draft and outbox names are user chosen. Raw-message and attachment
    identities retain their own stable storage names; error-log timestamps
    remain UTC.
    Retained received sources use the fixed recovery naming scheme
    retained-source-JOBID.txt rather than filename_format.

EDITOR
    --reply chooses the first nonempty EDITOR, then VISUAL, then vi on PATH,
    then nano on PATH. The selected value is split into executable arguments
    without invoking a shell. For example:

        export EDITOR='vi -n'
        fs-mail --reply ~/email/inbox/message.txt

    An invalid command, an editor failure, or an interruption leaves the
    saved reply in drafts/ and reports its path. Closing the editor does not
    queue or send the reply. Move the completed file to outbox/ when ready.

EXAMPLES
    Initialize an account and inspect its configuration:

        fs-mail --init
        vi ~/.config/fs-mail/accounts.ini
        vi ~/.config/fs-mail/config.ini
        fs-mail --check-config
        fs-mail --show-config
        fs-mail --receive-only

    If the configured secret file is absent, the last command prompts for
    the IMAP password without echo. To override an existing saved source:

        fs-mail --ask-password --receive-only

    Saved sources are optional. If using a secret file for unattended runs,
    create it privately and apply chmod 600 FILE. Keep the password out of
    shell command history. Files or commands must contain or print only the
    password or access token, with an optional trailing newline.

    With named accounts configured, list them and work on selected accounts:

        fs-mail --list-accounts
        fs-mail --account personal --receive-only
        fs-mail --account work --status
        fs-mail --account personal --account work --sync-only

    A command without --account operates on all configured accounts. Resolve
    one account's held job or reply to a file in its explicitly chosen root:

        fs-mail --account work --resolve JOB_ID --result sent
        fs-mail --reply ~/otheremail/inbox/message.txt

    Create a new, separate configuration containing one named account:

        fs-mail --config ~/.config/fs-mail/second/config.ini --init \
          --account personal --root ~/secondemail

    Add later accounts in that directory's accounts.ini; --init never overwrites
    an existing template file.

    Download without applying local changes:

        fs-mail --receive-only
        ls ~/email/inbox/

    Compose, review, and queue a message:

        vi ~/email/drafts/note.txt
        mv ~/email/drafts/note.txt ~/email/outbox/
        fs-mail --dry-run
        fs-mail --send-only

    A scheduled sender may act as soon as the file enters outbox/. Finish
    editing in drafts/ and move the completed file into the live queue.

    Move a tracked message to an existing or new folder, then synchronize:

        mkdir -p ~/email/Archive
        mv ~/email/inbox/message.txt ~/email/Archive/
        fs-mail --status
        fs-mail --sync-only

    With unattended credential sources configured, run every five minutes
    from a user crontab; substitute the real home path:

        */5 * * * * /home/user/.local/bin/fs-mail --non-interactive --quiet

    Or keep one foreground process under a supervisor:

        fs-mail --non-interactive --watch 300

    In a terminal, omit --non-interactive to enter passwords when needed;
    the watcher retains prompted credentials in memory until it exits.

    In ChromeOS, run inside the Linux environment and keep the mail root in
    Linux Files. A Linux cron job or service runs only while that environment
    is running; it does not start a stopped ChromeOS Linux environment.

RECOVERY
    Start with fs-mail --status and the error log. Preserve the private
    .fs-mail directory while investigating; it records already accepted
    submissions, message identities, and operations whose outcomes are held.

    SMTP greeting on an IMAP connection
        A greeting such as "220 thatiam.vip ESMTP OpenSMTPD" identifies an
        SMTP service at the configured IMAP endpoint. Check the account's
        IMAP host, port, and security in accounts.ini or its legacy combined
        configuration against the server's IMAP settings. Common
        combinations are port 993 with ssl, or port 143 with starttls.
        Changing the password does not correct a protocol mismatch.
        OpenSMTPD provides SMTP; mailboxes also need an IMAP service on
        the server. The greeting does not establish that IMAP is available.

    Password source unavailable
        A missing credential_file prompts in a terminal. For unattended
        runs, supply the file or another configured source and use
        --non-interactive. Existing files must belong to your user and have
        no group or other access. Invalid or unsafe present files remain
        errors; --ask-password explicitly overrides them for this run.
        Prompts never fall back to echoed input. Ctrl-C cancels without
        saving the password. A subsequently created file replaces the
        cached typed value on the next credential lookup.

    SMTP uncertainty
        A disconnect after message submission can hide the server's final
        reply. Inspect the server's sent mail or verify with the recipient,
        then choose --result sent or --result retry. The latter explicitly
        permits another submission. Renaming an uncertain draft or making
        an identical copy does not bypass the hold.

    SMTP edits during submission
        Accepted original content is archived. A changed draft stays held
        so cleanup cannot erase the edit or resend it automatically. Retry
        releases the edited version for a later sending run. If several
        different edited versions exist, move unwanted versions to drafts/
        before authorizing retry. Exact duplicate queue representations are
        removed or recovered as part of explicit resolution.

    IMAP conflicts
        Resolve the reported Local-ID with --prefer local to request the
        local state, or --prefer remote to accept the server state, then run
        --sync-only. The server and local files are checked again. A choice
        does not override unsupported capabilities or an ambiguous identity.
        For an ordinary pending local folder move, remote preference keeps
        the server location: move the file back to its mapped source folder
        and resolve again. The program retains its bytes while this is held.
        A resolution choice is consumed when its next mutation is journaled.
        Any newly uncertain command requires a fresh --resolve-sync choice.

    Unknown IMAP MOVE outcome
        Do not move or copy the message again to force a retry. A server may
        have moved it even if the final response or COPYUID was lost. The
        operation remains held until its outcome can be verified. Choosing
        --prefer remote abandons the uncertain local binding, keeps a local
        archival copy without Local-ID, and downloads the server's current
        messages. Keep that archival copy until the result is understood.

    Held deletion after local undo
        If a deleted local file is restored after fs-mail marks its remote
        UID Deleted but before expunging it, the operation is held. Choosing
        --prefer local can undo the Deleted mark that this journal verified
        setting. This correction requires CONDSTORE, the same UIDVALIDITY,
        and unchanged flags and MODSEQ since the mark. A pre-existing Deleted
        flag or subsequently changed server state is preserved and held.
        Lost corrective replies remain held for another explicit choice and
        verification. An already-expunged message is never recreated; a
        restored readable file remains a local archive. --prefer remote keeps
        the server's current Deleted state and retains or restores the local
        readable copy.

    Interrupted legacy conversion
        Correct the reported file or index problem and rerun
        --migrate-outbox. Original index and draft backups are retained in
        .fs-mail/migrations/outbox-v1/. Migration never submits messages.
        The old --index-outbox interface is no longer used.

    Interrupted local file replacement
        A saved replacement journal prevents a temporarily missing working
        file from being interpreted as a requested remote deletion. The next
        scan can safely restore a missing path and retain a hold. Inspect the
        versions retained in .fs-mail/working-recovery/, then resolve the
        reported Local-ID explicitly. Keep the private recovery records.

    Account change
        Add another named account with its own explicit root. An unused
        template root may be corrected, but existing mail files or history
        are not rebound to another account by editing its login. To retain
        the first account, preserve its root and private state while
        converting its sections.

    Overlapping account roots
        Use sibling roots or separate directories. No root may contain
        another account's root, even if only one account is selected for
        this invocation. Correct the configuration before running.

EXIT STATUS
    0   The requested action completed without a reported failure or hold.
    1   A run, status check, or dry run found an error or held operation.
    2   Invalid arguments, configuration, or another command-level failure.
    3   The only failures were roots locked by another fs-mail process.
    130 Interrupted by Ctrl-C, or SIGTERM while watching or prompting.
    141 The output pipe was closed by its reader.

    For multiple accounts, a failure makes the combined invocation fail
    even when another account succeeds. Invalid configuration stops work
    before any account operations; runtime failures do not cancel remaining
    selected accounts. Each account writes its own errors.log.

    --watch continues after individual cycle failures. Consult errors.log
    and standard error instead of relying on a per-cycle exit status.

LIMITS
    Python 3.9 or newer is required. The program uses the Python standard
    library and POSIX facilities including fcntl locks, hard links, and
    directory synchronization. Linux, including the ChromeOS Linux environment,
    is supported. The reply command and portable file-replacement path are
    intended to work on OpenBSD; native OpenBSD execution has not been tested.

    Local file replacement uses atomic exchange where available. Its portable
    alternative journals the operation, retains the original inode in private
    recovery, and publishes with a no-overwrite hard link. Linux exchange and
    the forced portable branch, including process-exit recovery, are tested
    on Linux. Keep the working tree on a filesystem supporting the required
    Unix operations and retain .fs-mail with the rest of the account.

    Received MIME is rendered as inert text. Plain-text alternatives are
    preferred; HTML-only bodies become readable text with useful link URLs.
    Remote content is never loaded. Encryption is not decrypted, and rich
    HTML layout is not retained. Original .eml files remain available.
    Rendering is bounded by MIME depth, part count, and text/attachment size.
    Raw messages above the renderer's 64 MiB limit can be archived with a
    diagnostic text file if the configured download limit permits them.

    This format is neither Maildir nor a complete RFC 5322 message. An
    ordinary mail client should open the original .eml file, not assume the
    readable .txt file is a wire message. Local text edits do not rewrite
    remote message bodies. New arbitrary files outside outbox/ are not
    uploaded as messages. No remote Sent-folder append or provider-specific
    label model is supplied.

    A file manager can rename, move, delete, and edit tracked messages, but
    cannot distinguish reading from previewing. Use Flags to record read
    state. Keep a single Local-ID per tracked message and retain the private
    state alongside the visible files. Disk snapshots and the error log are
    not automatically pruned.

LICENSE
    fs-mail is distributed under the Insha-Allah License Agreement (IALA).
    The complete agreement is included unchanged in LICENSE. See that file
    for its terms and PROVENANCE.txt for the source and dependency record.
    The installer also copies both files to PREFIX/share/licenses/fs-mail/.
    PREFIX defaults to ~/.local; sh install.sh --prefix DIR changes it. Both
    files are retained inside the executable's zip archive. For example:

        less ~/.local/share/licenses/fs-mail/LICENSE

    The canonical agreement is:

        https://remfan1994.github.io/insha-allah-license-agreement

SEE ALSO
    cron(8), crontab(5), vi(1), python3(1)

    README.txt, docs/QUICKSTART.txt, docs/PROTOCOL-NOTES.txt,
    docs/VALIDATION.txt, docs/STRESS-REPORT.txt, docs/DOWNLOAD-DESIGN.txt,
    LICENSE, PROVENANCE.txt

fs-mail 2.3.0                    October 2026                   FS-MAIL(1)
