Mailbox Registration Lifecycle¶
This page explains how the v1 filesystem mailbox decides which mailbox artifact is active for a full mailbox address and what the lifecycle modes do when that artifact changes.
Mental Model¶
Registrations are address-routed, not principal-routed.
- The key is the full mailbox address such as
research@houmao.localhost. - At most one registration for that address may be
active. - Older registrations may remain as
inactiveorstashed. - The registration record and the mailbox artifact can point either to an in-root mailbox directory or to a private mailbox directory reached through a symlink entry.
This design lets the transport keep canonical messages shared while still allowing address-specific mailbox locations to move.
Join Modes¶
safe¶
Use safe when you want the default behavior.
- Reuse the current active registration when it already matches the request.
- Reactivate a matching inactive registration when the mailbox artifact still matches.
- Fail if a different active registration already exists for the address.
- Fail if a preserved mailbox artifact still occupies the address path.
force¶
Use force when you want the active registration replaced.
- The prior active or occupying registration becomes inactive or removed from active use.
- Registration-scoped mutable state for the replaced registration is purged.
- The address receives a fresh active registration id.
stash¶
Use stash when you want to preserve the prior mailbox artifact before replacement.
- The prior mailbox artifact is renamed to
mailboxes/<address>--<uuid4hex>. - The prior registration becomes
stashed. - A new active registration is created for the original address entry.
sequenceDiagram
participant Req as Register<br/>request
participant Scr as register_mailbox.py
participant DB as index.sqlite
participant Box as mailboxes/<address>
Req->>Scr: mode=safe|force|stash
Scr->>DB: load active or occupying<br/>registration
alt safe and matching
Scr-->>Req: reuse existing active<br/>registration
else force replace
Scr->>DB: mark old inactive and<br/>purge registration state
Scr->>Box: replace active artifact
Scr->>DB: insert new active registration
Scr-->>Req: replaced_registration_id
else stash replace
Scr->>Box: rename old artifact to<br/><address>--<uuid4hex>
Scr->>DB: mark old registration stashed
Scr->>DB: insert new active registration
Scr-->>Req: stashed_registration_id
end
Leave Modes¶
deactivate¶
Use deactivate when you want delivery to stop without deleting the registration record.
- The active registration becomes
inactive. - Historical canonical messages remain untouched.
- The registration record stays in SQLite for later inspection or possible reuse.
purge¶
Use purge when you want to remove registration-scoped mutable state and shared-root registration artifacts.
- The registration row is deleted.
- Registration-scoped projection rows and mailbox state rows are removed.
- Shared-root registration artifacts are removed.
- Canonical messages under
messages/are preserved. - Historical recipient delivery records in canonical history remain meaningful even after the registration is gone.
sequenceDiagram
participant Req as Deregister<br/>request
participant Scr as deregister_mailbox.py
participant DB as index.sqlite
participant Box as mailbox artifact
Req->>Scr: mode=deactivate|purge
Scr->>DB: load active registration
alt deactivate
Scr->>DB: mark registration inactive
Scr-->>Req: resulting_status=inactive
else purge
Scr->>DB: remove registration-scoped<br/>state and registration row
Scr->>Box: remove shared-root entry
Scr-->>Req: resulting_status=purged
end
Practical Examples¶
- Re-running bootstrap for the same session address usually resolves through
safeand reuses the existing active registration. - Replacing an in-root mailbox with a different owner uses
forceorstash. - Moving an address to a private mailbox directory uses
mailbox_kind=symlinkwithsafe,force, orstashdepending on whether a conflicting registration already exists. - Purging a private mailbox registration removes the shared-root registration entry but does not delete canonical message history.
Cleanup Of Inactive And Stashed Registrations¶
houmao-mgr mailbox cleanup is the local janitor for filesystem mailbox registrations that are no longer active.
- It evaluates only
inactiveandstashedregistrations. - It preserves every
activeregistration. - It preserves canonical history under
messages/. --dry-runreports cleanup candidates without deleting them.--inactive-older-than-secondsand--stashed-older-than-secondslet operators keep recently deactivated or stashed registrations around for inspection before cleanup.
Examples:
houmao-mgr mailbox cleanup --mailbox-root /abs/path/shared-mail --dry-run
houmao-mgr mailbox cleanup --mailbox-root /abs/path/shared-mail --inactive-older-than-seconds 3600
Scope boundary:
houmao-mgr mailbox cleanupdoes not delete canonical messages.- It does not remove runtime-owned Stalwart credential files under
<runtime-root>/mailbox-credentials/; usehoumao-mgr admin cleanup runtime mailbox-credentialsfor those. - It does not remove one session's local Stalwart secret copy under
<session-root>/mailbox-secrets/; usehoumao-mgr agents cleanup mailboxfor that scope.
Clearing Delivered Messages While Keeping Accounts¶
Use clear-messages when you need to reset delivered filesystem mail without unregistering mailbox accounts:
houmao-mgr mailbox clear-messages --mailbox-root /abs/path/shared-mail --dry-run
houmao-mgr mailbox clear-messages --mailbox-root /abs/path/shared-mail --yes
houmao-mgr project mailbox clear-messages --dry-run
houmao-mgr project mailbox clear-messages --yes
This command removes canonical delivered messages, recorded projection artifacts, shared message index rows, mailbox-local message/thread state, and mailbox-owned managed-copy attachments. It preserves mailbox registrations, account directories, private symlink mailbox targets, root protocol/rules/locks/staging layout, and external path_ref attachment targets. It is separate from cleanup: cleanup is registration cleanup, while clear-messages is delivered-message reset.