Bichon Docs

Source mailbox cleanup moves mail that Bichon has already archived out of the source IMAP folders and into a dedicated folder, bichon_auto_created_trash, on the same server. It exists for archives that become the authoritative copy of a mailbox: once mail is safely in Bichon, the source mailbox no longer has to hold it.

The operation is a move, not a delete. The message leaves the source folder but still exists on the server (in the trash folder) and in Bichon's archive. Bichon never empties that folder: reclaiming the space is a separate, deliberate action you take with your own mail client.

Cleanup is not retention, and not an undo of deletion. Retention purges Bichon's local copy; cleanup moves the server's copy. Message restore pushes archived mail back to its source server — different from moving mail out of it.

What it does

  • Chooses, per account, which messages are eligible: archived long enough ago, old enough by message date, not starred, within the configured source folders.
  • Verifies each candidate against the server before touching it, using identity metadata the archive recorded.
  • Moves it into bichon_auto_created_trash with IMAP MOVE. Servers that do not advertise MOVE cannot run cleanup at all: copying would leave the source copy in place and free no space.
  • Records what moved and what failed, per folder, in a report you can revisit.

What it never does

  • Never permanently deletes a message. Even the fallback path only removes the source copy after the copy has been confirmed visible in the trash folder.
  • Never empties bichon_auto_created_trash. There is no "purge" button and nothing is scheduled; use your mail client when you want the space back.
  • Never deletes a mailbox (DELETE is never sent), never renames one, and never issues EXPUNGE at all — not a plain EXPUNGE that would flush unrelated messages other clients marked as deleted, and not a UID-scoped one either. The only way a message leaves a source folder is MOVE.
  • Never moves a message that is not in the archive, and never moves anything out of special-use folders (\All, \Archive, \Drafts, \Flagged, \Junk, \Sent, \Trash).
  • Never touches messages under legal hold (Enterprise), a disabled account, or an account that is being deleted.

Requirements

RequirementDetail
EditionCommunity, Pro and Enterprise
Account typeIMAP only — NoSync and View accounts have no source server
Server capabilityMust advertise MOVE (RFC 6851). A server without it cannot run cleanup — copying would not free the source mailbox — and every run is refused as blocked before anything is touched
Permissionaccount:manage to configure, preview or run; account:read_details to read the state/reports
Bichon versionThe cleanup API is available whenever the account update API accepts remote_cleanup

Where it lives

All three entry points are in the account row menu (Accounts → ⋯):

DialogPurpose
Source cleanupConfigure the feature: schedule, folders, age thresholds, batch size, starred messages
Run cleanup nowPreview and execute one batch immediately, using the saved configuration
Cleanup reportsThe last 30 runs with per-folder moved/failed counts and the failed messages

The configuration is deliberately outside the account create/edit form. Saving the cleanup dialog sends only remote_cleanup through the account update API, so it cannot overwrite other account settings.

The destination folder

The destination is fixed: bichon_auto_created_trash on the account's own server. It is created on first use if missing, and it cannot be configured as a source folder — the API rejects that with 400 InvalidParameter.

Do not delete or rename the folder while cleanup is configured. The next run re-creates it, but messages left in it are not tracked by Bichon beyond the archive itself.

Which messages are eligible

Eligibility is judged from Bichon's local index first; the server is only consulted to prove identity before a move.

ConditionSettingDefaultNotes
Source folder in scopeSource folders (optional)Account's download foldersComma-separated names; empty = the account's download folders, or every folder when the account has no folder scope
Folder is not special-use——\All, \Archive, \Drafts, \Flagged, \Junk, \Sent, \Trash are always skipped, as is the destination folder
Archived long enoughArchive age before moving (days)30Measured from ingest_at — the moment Bichon saved the message. 0 means "eligible on the next run"
Message old enough (optional)Only move messages older than (days)emptyUses the newer of the RFC 5322 Date header and the server's INTERNALDATE, so a message moves only when both are older. Messages with neither date are skipped
Not starredKeep starred messagesonA \Flagged message never moves, even when old enough
UID known——Candidates with no UID, or with a folder whose UIDVALIDITY is unknown, are skipped

Both age conditions must hold when the optional message-age floor is set. A message archived yesterday is not eligible even if its Date header is ten years old.

How a batch is selected

Cleanup never looks at every message in a mailbox. Each run builds a bounded window:

  1. Collect eligible candidates from the in-scope folders, ordered oldest-first by ingest_at.
  2. Remove starred messages from the window before the batch is sized (they would otherwise occupy slots forever).
  3. Walk the window oldest-first, verifying each candidate, until the batch is full of messages that can actually move — or the window is exhausted.

The window holds batch size × 8 candidates (minimum 200, maximum 5,000). If the window was truncated, the run reports that the scan budget was reached: there may be more eligible mail than the window could see. The next run continues from the same place, because messages that moved are marked in the index and never offered again.

Skipped candidates do not shrink a batch. If six of the first fifty candidates turn out to be gone from the source, the run keeps walking the window until fifty messages have actually moved. A preview therefore normally shows exactly the configured batch size of ready to move messages; fewer than that means the window is exhausted, not that the run was cut short.

Verification before every move

Every candidate is proven against the server immediately before it is moved. The check is metadata-based: Bichon records a message's identity at ingest, and compares it with what the server reports now.

CheckWhat must match
Folder identityThe source folder's current UIDVALIDITY equals the archived one
LocatorThe archived UID still exists in the folder
IdentityThe remote message behind that UID has the same Message-ID; if the UID vanished or now holds another message, a HEADER Message-ID search locates the real one
UniquenessThe Message-ID search must resolve to exactly one candidate whose size and internal date agree; several indistinguishable copies stop the run
MetadataMessage-ID, RFC822.SIZE and INTERNALDATE agree with the archive (when both sides know them)
Local archiveThe stored copy still reassembles and hashes to the recorded content hash

The message body is not re-downloaded. A full body hash would add a complete download per message, and — because the move is reversible and the archive keeps its own full copy — it would only catch a server that rewrites content while preserving the Message-ID, size and internal date. Metadata verification is the deliberate default.

How a move is performed

  • UID MOVE only. The message is moved into bichon_auto_created_trash with RFC 6851 MOVE; the server must not answer OK until the message is in the destination. There is no copy-and-expunge fallback — Bichon never issues EXPUNGE, plain or UID-scoped — so a server that does not advertise MOVE cannot run cleanup at all.
  • Post-condition. Bichon searches the source folder for the UID after the move and counts the message as moved only if it is gone; otherwise the run stops with a failure.
  • Index update. Messages moved by a run are marked in the index when the run ends, so they never reappear as candidates.

Runs are intentionally slow: about 300 ms between messages, a 5-second pause every ten messages that also re-checks UIDVALIDITY, and one cleanup at a time per account.

Manual runs

Run cleanup now uses the saved configuration and works in two steps:

  1. Preview — read-only. Verifies the candidate window and shows how many messages are ready and how much they weigh. Closing the dialog does not cancel it; the job continues on the server and reopening the dialog reattaches to it (finished jobs stay readable for 30 minutes).
  2. Execute — requires ticking the acknowledgement. The preview issues a single-use token valid for 15 minutes, bound to the exact candidate window and configuration. Any change in between — new mail entering the window, a different folder scope, an edited threshold — invalidates the token and asks you to preview again.

The batch behaves the same as a scheduled batch: it fills to the configured size by continuing past candidates that cannot move.

Scheduled runs

Enable Enable scheduled moves and pick a frequency (daily, weekly, monthly at a chosen hour). The stored expression is a six-field cron (second minute hour day-of-month month day-of-week) evaluated in UTC; the dialogs expose the common presets, and the API accepts any valid expression.

A scheduled run is not one batch — it drains the backlog:

  • It repeats full batches — each one a complete, safety-checked run — until a batch moves nothing (everything left is unmovable) or the run has been working for 10 minutes.
  • The time budget keeps one schedule from monopolizing the account: whatever is left continues at the next scheduled occurrence.
  • Between batches the account is re-read, so disabling the account, removing the configuration, placing a legal hold, or starting a deletion stops the drain immediately.
  • Only one cleanup runs per account at a time; a second request is refused while one is active.
SituationWhat happens
A sync or manual download holds the accountThe batch is deferred and retried on the next scheduler tick (about a minute)
A backup capture window is openSame: deferred, retried shortly
Account disabled, deleted, or on legal holdSkipped; a manual run is blocked and recorded as such
Server does not advertise MOVEThe run is blocked before anything is touched; this consumes the schedule slot
Invalid cron expressionThe account is skipped with a warning in the server log

Reports

Cleanup reports keeps the last 30 finished runs per account, including blocked and failed ones. For each run it shows:

  • the outcome (Success, Failed, Blocked, Cancelled), moved and failed counts, bytes moved and folders touched;
  • per folder, moved / failed / bytes;
  • the failed messages by subject, reason, folder and UID, capped at 200 entries per run.

Routine policy skips — too recently archived, too recent by message date, starred, or no longer in the source mailbox — are counted in the API (skipped, skipped_reasons) but are not listed in the UI. They are expected states that need no operator action; only failures do.

Stop conditions and safety rules

A run stops at the first condition that makes moving more messages unsafe:

ConditionResult
Account on legal holdBlocked before any move
Account disabled or being deletedBlocked
Server does not advertise MOVE (RFC 6851)Blocked
UIDVALIDITY changed for a folder (before or during the run)Stop, Failed
A message's identity cannot be proven (size, date or Message-ID mismatch)Stop at that message, Failed
Three consecutive local archive integrity failuresStop, Failed
More than one indistinguishable remote copy for a Message-IDStop, Failed
The source UID is still present after the moveCounted as failed, run stops
User cancellation (manual run)Stop at the next message boundary, Cancelled; the report keeps what moved so far

Messages that are simply gone from the source (deleted or moved elsewhere since Bichon archived them) are skipped, not failed: there is nothing to move and nothing to repair.

Caveats

  • Retention can outrun cleanup. If the account's local retention (retention_days) is shorter than the cleanup grace period, Bichon may purge its own copy before cleanup moves the server copy. The configuration dialog warns about this; keep local retention comfortably longer than the grace period.
  • Very short grace periods skip the backup safety net. With a grace under seven days, a message can be moved right after it is archived, before any backup captured it. The move is still reversible, but until a backup runs the local archive is the only verified copy. The dialog warns below seven days and when the last successful backup is old.
  • A scan budget can hide mail. The window is bounded; when it was truncated, a run says so. It still makes progress on the next run, but a mailbox with a very large unprocessed backlog drains across several runs.
  • Messages gone from the source stay in the window. They are skipped every time they are examined, which costs a little verification work per run but never blocks a batch from filling.

Undo and reclaiming space

  • Undo a move: move the message from bichon_auto_created_trash back to its original folder, with any mail client. Bichon does not need to be involved and its archive is unaffected.
  • Reclaim space: empty bichon_auto_created_trash with your mail client. This is a permanent deletion on the server — Bichon provides it nowhere in the UI or API, precisely because it cannot be undone.
  • Bring mail back from the archive: message restore pushes archived messages back to the source server. It appends a new copy to the original folder; it does not move anything out of the trash folder.

API

MethodPathPermission
GET/api/v1/accounts/{id}/remote-cleanup/stateaccount:read_details
POST/api/v1/accounts/{id}/remote-cleanup/previewaccount:manage
POST/api/v1/accounts/{id}/remote-cleanup/executeaccount:manage
GET/api/v1/accounts/{id}/remote-cleanup/jobsaccount:manage
GET/api/v1/accounts/{id}/remote-cleanup/jobs/{job_id}account:manage
POST/api/v1/accounts/{id}/remote-cleanup/jobs/{job_id}/cancelaccount:manage

Previews and runs are background jobs: the start call returns a job immediately, and the job's status, preview or run report is polled through the jobs endpoints. Jobs live in memory and stay readable for 30 minutes after they finish; a page reload or a closed dialog reattaches through GET …/jobs, which lists the account's jobs newest-first with running ones first. The durable record is the state/reports endpoint.

The configuration travels in the account update payload as remote_cleanup:

{
  "remote_cleanup": {
    "enabled": true,
    "schedule": "0 0 3 * * *",
    "folders": ["INBOX", "Projects"],
    "eligible_after_archive_days": 30,
    "min_message_age_days": 90,
    "max_messages_per_run": 50,
    "skip_flagged": true
  }
}

clear_remote_cleanup: true removes the configuration; messages already in bichon_auto_created_trash stay there.

Limits

LimitValue
Messages moved per batch1–500 (default 50)
Candidate window per runbatch × 8, clamped to 200–5,000
Scheduled drain per occurrence10 minutes, at most 50 batches
Preview token lifetime15 minutes, single-use
Finished job readability30 minutes
Run history per account30 runs
Failed-message detail per run200 entries
Pacing~300 ms per message, 5 s per ten messages

Related: Accounts, Archive Filtering, Editions, Legal Hold, CLI tools.

On this page