---
title: "The webmail in depth: search, offline mail, expiring messages, send-as and recovery"
url: https://www.hmailserver.co.uk/topic/28254/the-webmail-in-depth-search-offline-mail-expiring-messages-send-as-and-recovery
author: "Progressiverobot"
published: 2026-09-27T19:36:13.731Z
updated: 2026-09-27T19:36:13.731Z
category: "Webmail, portal & Control Deck"
tags: ["webmail","portal","administration","limitations"]
site: hMailServer Community Forum
---

# The webmail in depth: search, offline mail, expiring messages, send-as and recovery

*Written for 6.3.4. hMailServer 6.3.7 (17 October 2026) signs an authenticated SMTP submission as another domain hosted here only when its account may send as the address its From names - the list the From picker below draws on: its own address, an alias pointing at it, a mailbox that granted it the post right, an address it proved or a masked address of its own; otherwise the mail is still accepted and sent, unsigned as that domain. The webmail's own send already holds From to the account, so mail sent from the page is signed as it was. 6.3.7 also carries the first step of the Control Deck's and the webmail's rebuild planned for 6.4 - the framework decision, the threat model of the web surface and the authorisation matrix with its check - with no product code. See [the 6.3.7 announcement](/topic/28277).*

This topic goes deeper into the webmail that hMailServer serves at `/portal` on the REST listener; what the page is and how it is turned on is in [The webmail portal at /portal](/topic/28191). The one thing to know first: most of what follows is the reader's own choice, bounded by a setting the administrator holds. Search with operators, the keyboard map, the rich-text editor, the From picker over aliases and granted mailboxes, plain signatures and the offline inbox listing were in 6.3.3; the three stars, the importance marker and its keys, and the rest of what follows are since 6.3.4.

### What the administrator bounds

Each is a setting on `PUT /api/v1/settings` and the Control Deck's Settings view; since 6.3.4 many can also be set per domain or per account.

| Setting | What it bounds | Default |
|---|---|---|
| `recover_deleted_days` | How long deleted mail can be put back | 0, off; at most 365 |
| `reader_offline_days_max` | The most days a reader may keep offline | 30; at most 365; 0 offers none |
| `reader_masked_addresses_max` | Masked addresses per person | 20; at most 200; 0 takes the page away |
| `reader_sender_addresses_max` | Send-as addresses per person, proved or not | 5; at most 20; 0 takes the section away |
| `brand_logos_enabled` | Brand logos at all | On; needs `AuthenticationResultsEnabled` and DMARC |
| `confidential_base_url` | The address the webmail is reached at from outside, which links are written against; falls back to `quarantine_digest_base_url`, then `import_oauth_redirect_base_url` | Empty |

### Search operators and keyboard shortcuts

The search box searches the folder shown; the options panel beside it builds the same syntax from fields and can search every folder the account may read.

| Operator | What it matches |
|---|---|
| `word`, `"quoted phrase"` | The word in the subject or the sender, failing those anywhere in the message; the words together, in that order |
| `-term`, `a OR b` | What follows the minus must not match; one of the two must match. `OR` in capitals - `or` is a word |
| `from:`, `to:`, `cc:`, `bcc:`, `subject:` | The sender's address or name; a recipient's, in To or Cc; an address or name in Cc, or in Bcc (only in the sender's own copy); the subject |
| `has:attachment`, `has:link`, `filename:` | An attachment; an `http` or `https` link; an attachment whose file name contains the text |
| `larger:`, `smaller:` | By size, as in `larger:10M` |
| `before:YYYY-MM-DD`, `after:YYYY-MM-DD` | By date |
| `older_than:`, `newer_than:` | By age: `7d`, `2w`, `3m`, `1y` |
| `in:folder` | Messages in that folder; a whole path may be given |
| `is:unread`, `is:read`, `is:flagged`, `is:unflagged`, `is:answered`, `is:muted`, `is:pinned` | By the flag or keyword |
| `label:name` | An IMAP keyword; `label:$Important` is the sidebar's **Important** view |
| `category:` | The inbox tab: `primary`, `social`, `promotions`, `updates` or `forums` |
| `in_reply_to:` | Messages whose `In-Reply-To` or `References` names the message-id |

Since 6.3.4 a search request opens at most 2,000 message files and stops after about two and a half seconds, saying where to go on from; **Search older messages** carries on.

The keyboard map (`?` lists it) acts on the message list and an open message, and nothing is captured while the cursor is in a text field. `j` and `k` move, `Enter` or `o` opens, `u` or `Esc` goes back, `x` ticks a row, `e` archives, `!` files as junk (or, in Junk, as not junk), `#` deletes to Trash, `l` labels, `m` mutes, `c` writes, `r` `a` `f` reply, reply to all and forward, `1` to `9` run a quick step, `/` searches and `Ctrl`+`K` opens the palette. `s` gives the next of three stars; the second and third are the `$Star2` and `$Star3` keywords on top of the IMAP flag, so another client sees a flagged message.

### Offline mail

The webmail has always kept the inbox listing and the last opened messages - thirty-one of them according to [OfflineMail.md](https://gitlab.com/hmailserver/hmailserver/-/blob/v6.3.4/hmailserver/docs/OfflineMail.md) and [EvidencePack.md](https://gitlab.com/hmailserver/hmailserver/-/blob/v6.3.4/hmailserver/docs/EvidencePack.md), thirty according to [README.md](https://gitlab.com/hmailserver/hmailserver/-/blob/v6.3.4/hmailserver/docs/README.md) and the wiki - and an outbox of sends that failed for want of a connection. Since 6.3.4 it can also keep the text, formatting and attachments of the last days in the browser's own storage, and **nothing is kept until the reader chooses**. Settings, *Offline in this browser*, offers *Nothing beyond the inbox listing* and then the last 7, 14, 30, 60, 90, 180 or 365 days, up to the server's ceiling. The choice is the account's `offline_days` preference, so it follows the person between browsers; what is kept does not.

**How it fills.** The store is IndexedDB, database `hmPortalOffline`. A message goes in when it is opened and the window covers it, and in the background, newest first. An attachment above 8 MB is not kept, and a message's parts stop at 32 MB together. When the window is bigger than the browser allows the site, the card says so and the newest are kept.

**Without a connection** a message opens from the store, a folder lists what the store holds, and a search runs over the kept words with the operators the store can answer. `has:link` and `in_reply_to:` let a message through rather than hide it, `OR` is ignored, and a date operator is measured on the browser's clock.

**What it is not.** It is not a backup and it is not synchronised back: a flag set offline is not sent when the connection returns. It is not encrypted beyond what the browser does with its own storage, so anyone who can open this browser profile can read what is kept. It does not survive sign-out: the database is deleted. **Clear what is kept** deletes everything now and sets the choice to nothing.

### Important, and sections of the inbox

Gmail's importance marker, decided **in the browser**: no model is trained anywhere, and nothing about whom this person reads or writes to is sent to the server to decide it. The page counts in `localStorage` and forgets the whole of it at sign-out. What it decides is one IMAP keyword: `$Important` on a message judged important, `$NotImportant` on one the reader says is not, so Thunderbird, a phone and `hmctl` all see them.

Each inbox message is judged once, the first time this session lists it; **two points** make it important.

| Reason | Points |
|---|---|
| You marked mail from this sender important, or not important | +4, or -4 |
| You write to this sender | +3 |
| You answered this sender | +2 |
| You open mail from this sender (two or more opened here) | +1 |
| You starred mail from this sender | +1 |
| It was sent to you by name (a To of five or fewer) | +1 |
| It is in one of the other tabs: Social, Promotions, Updates or Forums | -2 |

A message that already carries either keyword is never judged again. The marker is changed from the arrow on the row, with an Undo, or with the keys `+` or `=` and `-`. Sent and Drafts have no marker. In Settings, **Importance marker** offers the page deciding (the default), marking by hand only, or no marker; **Inbox sections** can draw *Important, Starred, Everything else* (off by default).

It will be wrong, which is why every mark can be undone in one press. It does not sort, hide or delay anything, and what it has learned stays in this browser; the keywords on the mail travel.

### A message that expires

Gmail's *confidential mode*: the message is kept on this server, and what crosses the internet is a short notice with a link. **It is not end-to-end encryption.** A message this server can delete on a timer is a message this server can read, and anyone who administers the server, or a backup of it, can read a kept message while it exists. Nor does it stop a recipient photographing the screen.

**Sending.** On the compose form, **Expires** (never, in an hour, a day, a week, a month) and an optional **Passcode**. Over the API, `expires_in` (seconds, 1 to 7,776,000 - ninety days) and `passcode` (4 to 64 characters) on `POST /api/v1/me/messages`. The send is refused when the server has no public address to write the link against (403, `confidential_unavailable`), and for a message the page signed or encrypted. The kept copy is a file under `<data directory>/Confidential/<account id>/` with a row in `hm_confidential` (schema 6069); it counts against the mailbox's quota (413, `quota_exceeded`), and an account has at most 1,000 outstanding at once (400, `confidential_ceiling`). Each recipient is sent the notice; the sender's Sent folder gets the full message.

**Reading.** The page at `/confidential/<token>` takes no credentials. The reader proves they are a recipient in one of three ways: signed in to this server's webmail as a recipient address; a six-digit code mailed to a recipient address, good for ten minutes and five tries; or the passcode, where ten wrong answers pause it for a quarter of an hour. After thirty wrong answers in all, codes stop opening the message. The page answers the same way whether or not the address typed is a recipient's. It shows the text, names other attachments without offering them, and runs no script. After the expiry or a withdrawal it answers 410.

**The sender's side.** **Messages that expire**, on the Sent folder's menu, lists what was sent and whether and by whom it was opened, with a **Withdraw** button. The kept file is deleted when the expiry passes. The copies are not in the backup, but an archive taken by a 6.3.4 build made before the release holds them, in the clear: treat it as the mail itself, or delete it.

### Send-as and masked addresses

The webmail's **From** picker offers four kinds of address:

| Kind | Given by |
|---|---|
| The account's own address | Always |
| An alias that points at it | The administrator |
| Another mailbox on this server | That mailbox's owner, with the post (`p`) right on their INBOX |
| An address at another provider | The person, proved with a code mailed to it |

With `SmtpAuthenticatedSenderCheck` on, an authenticated SMTP session's `MAIL FROM` is held to the same list: see [who may send as whom](/topic/28239). Since 6.3.7 the DKIM signature follows the list too: an authenticated submission whose From names another domain hosted here is signed as that domain only when the account may send as that address, and is otherwise accepted and sent unsigned as that domain; the webmail's own send already holds From to the account.

**Proving an address elsewhere (since 6.3.4).** Under **Settings, Other accounts, Send mail as** the person types the address and presses **Send the code**. The server mails a six-digit code to it from the postmaster of the account's domain, and the person types it back. The code lives in the server's memory for an hour and is never stored; five wrong tries end it. An address of a domain on this server is refused. **What this cannot change:** mail this server sends as `someone@gmail.com` is not signed by Gmail's DKIM key and not sent from an address Gmail's SPF record names, so a receiver that honours the domain's DMARC policy will quarantine or refuse it when that policy says so. The page says so beside an address whose domain publishes `quarantine` or `reject`. For such an address, send from its own provider.

**Masked addresses.** Under **Settings, Masked addresses** the person says what the address is for and presses **Make an address**; the server makes one in the account's own domain, such as `bookshop.k3v9qa@example.com`. While it is on, mail to it is delivered to the account, it is in the From picker (`kind: masked`), and a reply to mail that came through it goes out from it. Switched off, mail to it is refused at `RCPT` exactly as mail to an address that never existed is - not handed to the domain's catch-all. An account, alias or list made later with the same address takes it over. Both kinds of address are carried by the backup with the account.

### Recovering deleted mail

It is **off by default**: `recover_deleted_days` (0 to 365) turns it on for the whole server, and a domain or an account may keep its copies for fewer days than the level above, never for more.

**What is kept** is a message a person deletes: IMAP `EXPUNGE`, `UID EXPUNGE` and `CLOSE` on a folder with messages marked `\Deleted`; POP3 `DELE`; the webmail's delete and its emptying of a folder; and the retention the person chose, or the administrator's retention policy. What is removed for any other reason is not kept: an IMAP `MOVE`, a scheduled draft that has been sent, an account being deleted.

**Putting it back.** **Recover deleted items**, on the Trash folder's menu and in the command palette, lists what was deleted within the window. **Put back** returns a message to its folder with its flags - or to a folder of the same path, or otherwise the INBOX - as a new message with a new UID. **Delete for good** removes it now. The copies are files under `<data directory>/Recoverable/<account id>/`; they count against no quota and are not in the backup. The retention task, six-hourly, ends the copies older than the window.

### Signatures and formatted messages

**A logo in the signature.** **Add image** in the signature's toolbar (**Settings > Name and signature**) takes a PNG, JPEG, GIF or WebP file, judged by its first bytes. The whole formatted signature is at most **64 KB - 64,000 bytes**, its images included, which leaves room for a logo of up to about 45 KB. A file that does not fit is drawn smaller, starting at 600 by 200 pixels. The limit is the account's signature through the webmail: the Control Panel, COM and the administrator's REST route do not check it.

**What the recipient receives.** Gmail and Outlook do not display a `data:` image, so the server moves each one into a part of its own with a `Content-ID` and points the HTML at it with a `cid:` URL - `multipart/related` inside the alternative. At most 64 different images in one message are moved. Not every mail client displays WebP; a logo that has to show everywhere is safer as a PNG.

**The formatted editor** rebuilds what is written from an allowed subset of HTML and drops everything else while keeping the words: a style, a `colspan`, a `<script>`, a remote `<img src="https://...">`. Since 6.3.4 it takes three more things:

- **Emoji**: a picker of about a thousand characters in eight groups, kept in the page itself. The names are English; there are no skin tones and no flags.
- **Pictures**, pasted, dropped or chosen: PNG, JPEG, GIF and WebP by their first bytes, with SVG refused; drawn down to 1,200 pixels on the longer side; at most 64 in a message.
- **Tables**, up to 50 by 20, written with `border="1" cellpadding="6" cellspacing="0"` as attributes, because Outlook renders mail with Word's engine and ignores most of a stylesheet. `Tab` moves to the next cell and, in the last cell, adds a row.

There are no merged cells, no column widths or colours of the reader's choosing, and no resizing a picture once it is in.

### A second account in the same page

Two mailboxes side by side: the account the person signed in as, and one more, added under **Settings, Other accounts** with its address and password. One press switches the whole page to the other. Nothing is collected or copied; this is not the *Other accounts* feature beside it, which collects mail from another mailbox into this one.

**The second account's session lives in the page, not in the browser.** A cookie is one per origin, so its session is a token the page holds in memory (`POST /api/v1/session?bearer=1`), written nowhere - so **a reload forgets it**, and the person adds the account again. Everything the browser keeps between visits stays the first account's: the offline store, the outbox, push, the recent searches and the Important tally.

**What is thinner.** One second account, not several. Remote images are not loaded in its messages, its S/MIME keys are unlocked by hand, and the one-session-per-device policy counts it. The form is never minted for the administrator (403), and a bearer session is the mailbox and nothing more: the server drops any administrative role from every request made on one.

### Brand logos

The list shows a sender's BIMI logo as its avatar only when the claim is checked. Three things have to be on: `AuthenticationResultsEnabled=1`, the DMARC check, and `BrandLogosEnabled` (on by default). `GET /api/v1/me/brand-logo?domain=` answers the SVG only when all of these hold:

1. `default._bimi.<domain>`, or the same name at its organizational domain, is a `v=BIMI1` record with an `l=` location.
2. The domain's DMARC policy is `quarantine` or `reject` with `pct=100`. A domain at `p=none` gets no logo, even for mail that passed.
3. The location is `https`, reached only at a public address, within ten seconds and 32 KB, with no redirect followed.
4. The file is SVG Tiny Portable/Secure.

Every answer is kept a day per domain. A refusal is `404` with an `outcome` - `no_record`, `declined`, `weak_policy`, `not_https`, `fetch_failed`, `not_tiny_ps` or `switched_off` - and the webmail shows the initials. A Verified Mark Certificate (`a=`) is not validated.

### What it does not do

- No ActiveSync and no Exchange Web Services: a phone uses [IMAP and SMTP](/topic/28255), and [CalDAV and CardDAV](/topic/28252).
- [Recall](/topic/28269) reaches this server's own mailboxes only, and only unread copies.
- A folder of a hundred thousand messages is paged, searched and selected whole without the page copying it: built, and not yet measured.

### Where to read more

- Wiki: [The Webmail](https://gitlab.com/hmailserver/hmailserver/-/wikis/The-Webmail).
- Documents: [WebmailShortcuts.md](https://gitlab.com/hmailserver/hmailserver/-/blob/v6.3.4/hmailserver/docs/WebmailShortcuts.md), [OfflineMail.md](https://gitlab.com/hmailserver/hmailserver/-/blob/v6.3.4/hmailserver/docs/OfflineMail.md), [ImportantMail.md](https://gitlab.com/hmailserver/hmailserver/-/blob/v6.3.4/hmailserver/docs/ImportantMail.md), [ConfidentialMessages.md](https://gitlab.com/hmailserver/hmailserver/-/blob/v6.3.4/hmailserver/docs/ConfidentialMessages.md), [SendAs.md](https://gitlab.com/hmailserver/hmailserver/-/blob/v6.3.4/hmailserver/docs/SendAs.md), [MaskedAddresses.md](https://gitlab.com/hmailserver/hmailserver/-/blob/v6.3.4/hmailserver/docs/MaskedAddresses.md), [RecoverDeleted.md](https://gitlab.com/hmailserver/hmailserver/-/blob/v6.3.4/hmailserver/docs/RecoverDeleted.md), [Signatures.md](https://gitlab.com/hmailserver/hmailserver/-/blob/v6.3.4/hmailserver/docs/Signatures.md), [FormattedMessages.md](https://gitlab.com/hmailserver/hmailserver/-/blob/v6.3.4/hmailserver/docs/FormattedMessages.md), [SecondAccount.md](https://gitlab.com/hmailserver/hmailserver/-/blob/v6.3.4/hmailserver/docs/SecondAccount.md), [BrandLogos.md](https://gitlab.com/hmailserver/hmailserver/-/blob/v6.3.4/hmailserver/docs/BrandLogos.md).
- The public documentation: [36.6 The portal: what a user gets](https://www.progressiverobot.com/hmailserver-documentation/#366-the-portal-what-a-user-gets).
- On this forum: [The webmail portal at /portal](/topic/28191), [The Control Deck](/topic/28192), [Signing in](/topic/28253) for passkeys and account recovery, and the [6.3.4 announcement](/topic/28218).
