The WebUI's search page is a thin layer over POST /api/v1/search-messages. Everything described here is also available through the REST API.
Query behavior
A search combines a full-text term with optional structured filters.
textsearches subject, body, sender, recipients, and attachment names.subjectandbodynarrow the full-text match to one field.match_allcontrols whether every whitespace-separated term must match (true, the default) or any term may match (false). Replayed legacy saved searches usefalse.- When the query carries a text term and no sort is requested, results are sorted by relevance (BM25); otherwise by date descending. See Sorting.
Filters
| Filter | Matches |
|---|---|
from, to, cc, bcc | The corresponding address field |
any_recipient | to, cc, or bcc (OR) |
any_participant | from, to, cc, or bcc (OR) |
subject, body, text | Full-text fields |
message_id | Exact Message-ID |
since, before | Message Date header |
internal_date_since, internal_date_before | IMAP INTERNALDATE |
ingest_since, ingest_before | Bichon's archival timestamp |
account_ids, mailbox_ids | Restrict to accounts / folders |
min_size, max_size | Message size in bytes |
has_attachment | true / false |
attachment_name, attachment_extension, attachment_category, attachment_content_type | Attachment properties |
tags | At least one of the listed tags (OR) |
has_tags | true = tagged; false = untagged |
has_tags: false cannot be combined with a non-empty tags list — an untagged message cannot match any tag — and the request is rejected rather than returning an empty page.
Sorting
sort_by | Meaning |
|---|---|
DATE | Message Date header (API default without a text term) |
INTERNAL_DATE | IMAP INTERNALDATE / import timestamp |
INGEST_AT | Bichon archival timestamp |
SIZE | Message size |
RELEVANCE | BM25 score; always descending, desc ignored |
The API default with a text term is RELEVANCE. An explicit RELEVANCE with no text term falls back to DATE.
page and page_size are 1-based; page_size is capped at 500.
Saved searches
Save a query from the search page to re-run it later. Limits and behavior:
- 50 saved searches per user; names are 1–100 characters.
- A saved search stores the filter and sort, not the result set.
- Saved searches drive exports: the WebUI and
bichon-clican export exactly the saved search's scope. See Exporting via the WebUI. - Legacy saved searches replay with
match_all: falseso their original semantics are preserved.
API: GET/POST /api/v1/saved-searches, GET/POST/DELETE /api/v1/saved-searches/{id}.
Tags
Tags are called facets in the index. You can add, remove, or overwrite tags on messages and attachments in bulk, then filter by any combination with live counts.
GET /api/v1/all-tagsreturns the facets and their document counts.POST /api/v1/update-tagsadds/removes tags across selected messages.tagsin a search is OR-ed; combine withhas_tagsfor tagged/untagged views.
Tags are indexed values, not a separate label table: the facet list is derived from the documents that carry them. To rename a tag, add the new name and remove the old one across the selection.
Threads
Thread view reconstructs a conversation across folders within one account. Two boundaries:
- Threads are built per account; a thread does not span accounts.
- Thread view is unavailable through a View account — use search instead.
Contacts
The contacts view is a deduplicated sender/recipient address book across every account you are authorized to read. It is derived from indexed headers, not a separate address book; there is no editing surface.
GET /api/v1/all-contacts returns the aggregate list. Aggregate features (contacts, attachment search, dashboard) consider only unfiltered sources when a View is involved — see Views.
Attachments
- Metadata search — name, extension, category, content type, size, sender — is available in all editions.
- Content search (PDF/Word text) is a Pro feature: Attachment Search.
- Preview and download are permission-checked per account. Raw EML download requires a direct permission on the source account and bypasses a View's grant.
API: POST /api/v1/search-attachment, GET /api/v1/attachment_metadata, GET /api/v1/download-attachment/{account_id}/{envelope_id}, GET /api/v1/preview-attachment/{account_id}/{envelope_id}.
Message actions
From a search result or the message view:
| Action | Notes |
|---|---|
| View | HTML is sanitized; remote content is blocked by default |
| Download raw EML | Requires data:raw:download on the account |
| Tag / untag | Bulk action across the selection |
| Delete | Permanent — no trash or recycle bin. Permission data:delete; gated by dual control when enabled. Deleting every match of the current query runs as a background job — see Batch Deletion |
| Restore to source IMAP | Pushes archived messages back to their source server. Not an undo of deletion |
| Repair | Re-fetch missing content blobs from the source server. See Message Repair |
| GDPR erasure request | Enterprise; records the request and optionally erases under dual control. See GDPR Erasure Requests |
API: POST /api/v1/delete-messages (body: account ID → envelope IDs — the key is the account ID, not the mailbox ID), POST /api/v1/restore-messages/{account_id}, POST /api/v1/repair-message/{account_id}/{envelope_id}. The explicit-ID delete payload is described in Batch Deletion.
Dashboard and analytics
The Community dashboard shows fixed archive statistics: volume trends, top senders, storage usage, attachment stats, and per-account activity. The Pro analytics engine adds cross-account queries with arbitrary dimensions, filters, time buckets, and saved views — see Analytics Engine.
What a search can see
Every query is scoped to the caller's RBAC permissions: account-level ACLs, View scopes, and license state all apply. A search never widens access, and aggregate endpoints fail closed on filtered View sources rather than leaking the unfiltered set.
API summary
| Method | Path | Description |
|---|---|---|
POST | /api/v1/search-messages | Search email |
POST | /api/v1/search-attachment | Search attachments |
GET | /api/v1/get-thread-messages/{account_id} | Thread for a message |
GET | /api/v1/all-contacts | Aggregated contacts |
GET | /api/v1/all-tags | Tags with counts |
POST | /api/v1/update-tags | Add/remove tags |
GET/POST | /api/v1/saved-searches | List / create saved searches |
PATCH/DELETE | /api/v1/saved-searches/{id} | Rename / delete one |
GET | /api/v1/message-content/{account_id}/{envelope_id} | Parsed message content |
GET | /api/v1/download-message/{account_id}/{envelope_id} | Raw EML |
Archive Filtering
Per-account rules that decide which messages are archived — sender and subject patterns, size limits, and spam headers
Batch Deletion
Deleting every archived message that matches a search — preview and per-account permissions, the asynchronous job lifecycle, source-UID tombstones, legal hold, dual control, and what cannot be undone