Repository navigation
v0.3.0
Image: ghcr.io/karatektus/pl_mail:0.3.0
Adding an account no longer puts new mail behind hours of follow-up work. Everything plMail does to a message after fetching it — sorting by the assistant, event extraction, insight cards, read receipts — was queued beside the fetching, on the one worker that fetches mail. A first import of a large mailbox therefore queued that work for every message it brought in, oldest first, and new mail waited behind it; with the assistant sorting mail that was a model call per message and could be hours. Fetching mail is now the only thing that worker does.
- Follow-up work has its own queues and workers.
worker-livehandles mail that has just arrived on an account whose import is over, and nothing else, so new mail is never behind an import.worker-enrichhandles an import's recent mail and then, only when that is done, old mail.worker-releaseonly ends the wait described below. See Mail ingest → What follows a message. - Only mail from the last 30 days gets follow-up work as it is imported. Older mail is stored, threaded, filed by the ordinary rules and run through your own rules, as before — but no events, insight cards or receipt handling are derived from it.
app:backfill insightsandapp:backfill event-extractionread history if you want it. - Old mail is sorted by the assistant after the import, not during it — newest first, in small batches, in the background, and only once every account of yours has finished importing.
- New mail waits for the assistant before it appears in a tab. If you let the assistant sort your mail, a message used to appear where the rules put it and move a few seconds later when the assistant answered. It is now kept out of the inbox tabs for those seconds and appears once, in the right tab. The wait is capped — 60 seconds by default — and past the cap the mail is shown where the rules put it, and moved if the assistant answers later. Mail from a first import is never held.
- Admin → AI has a switch for that wait, and shows what it costs. Wait for the assistant before showing new mail in a tab turns it off, Wait at most sets the cap (2–300 seconds), and the line underneath reports how long mail was actually held over the last 7 days and how often the wait ran out. See Administration.
"Move to" files a conversation under a label in one step. There was a label button, which adds a label and leaves the mail where it is, and dragging onto a folder, which only works with a pointer and a sidebar in reach. Filing mail the way Gmail does — label it and get it out of the list you are in — took two actions. A folder button beside the label button now does it in one, for a selection in the list and for an open conversation: the label you pick goes on, and the label of the list you were looking at comes off. From the inbox that is "label and archive"; from a label it swaps one label for the other; from Trash or Spam it takes the mail out of the bin without putting it back in the inbox. Everything else the conversation wears stays.
- The picker offers the Inbox, your labels, Spam and Trash, and applies the one you click at once. The list you are already in, a label the conversation already has, and the bin for mail already in it are left off. See Mail → Move to.
- Archive, label changes and moves can be undone. Each shows an Undo for eight seconds, and it puts back exactly the labels every conversation had, rather than reversing the action — so an already-archived conversation that was ticked along with the rest stays archived. Dragging onto a folder gets the same Undo. An action over a whole view runs in the background and has none.
- Labelling a selection is one request, not one per conversation. The toolbar's label menu posted once for every ticked row; it posts once now, which is also why there is one toast and one Undo for the lot.
Fixed
- Signing in with a two-factor code could leave you on the code form, its button reading "Checking…" for good. The code had been accepted — reloading showed the inbox. While the code form is on screen the page behind it still fetches things, and each of those requests, turned away because the sign-in was not finished, was remembered as "where you were going". After a correct code you were sent to the last of them. When that was the request that refreshes the live-update cookie, which has no page to show, the browser stayed where it was. It happened on installations whose live updates were failing, because that is when the page keeps making that request. Only a page you were actually opening is remembered now, and a part of a page loaded in the background is not one.
- Starting plMail took minutes on a NAS with spinning disks. After "Statement statistics are enabled" the log went quiet for two minutes and more before the web server came up. At every start each container set access-control entries on its cache directory, which is part of the image — and changing anything about an image file makes Docker copy the whole file into the container and flush it to disk. Two thousand files, one synchronous write each, in every container at once. Nothing needed those entries: the image already makes the directory writable. They are no longer set. Only installs running as root were affected, which is why the TrueNAS catalogue app was not.
- And thirty seconds before that, on the compose files in this repository. The web server and workers wait for the database to report healthy, Docker's first health probe comes one interval after the container starts, and the interval was never set — so it was the default thirty seconds, and sixty when Postgres was still replaying its log at the first look. It is five seconds now. If you keep your own copy of
compose.yamlortruenas.compose.yaml, addinterval: 5sandretries: 30to thedatabasehealth check. - A busy Gmail or Outlook quota no longer raises an alarm, and no longer costs mail. When a provider was still rate-limiting after five retries, the job was logged at the highest level with a full stack trace and parked on the failed queue — whatever the job was. For a sync that only looks for what is new, that was noise: the next sync resumes from the same point. For a job fetching particular messages it was worse than it looked: nothing asks for those messages again, so they stayed missing until somebody retried the parked job by hand. A throttled sync is now dropped with one warning, and a throttled fetch is put back to try again a quarter of an hour later, up to ten times, before it is allowed to fail.
- A fresh install had no live updates until the container was next restarted. The inbox did not refresh by itself and the browser console showed a blocked connection to
https://localhost. The address typed into the install form was saved, but the web server had started before it existed and kept telling pages to reach the live-update hub at the built-in default. The install form now ends by restarting the web server, on a page that waits until it is back and then opens the inbox. - The "plMail is restarting" page waits for the server instead of guessing. It used to reload after six seconds whether or not anything was listening yet, and on a slower machine that showed the browser's own connection error.
Before you upgrade
- One migration, applied on boot. It adds two columns to
messageand two toai_settings, and changes no existing row. - Holding new mail for the assistant is on by default, and applies only to people who sort by assistant. Switch it off under Admin → AI if your model host is slow.
- The worker container runs three more processes,
worker-live,worker-releaseandworker-enrich. Nothing to configure on the standard images. If you run your own consumers instead ofapp:work, addmessenger:consume enrich_live,messenger:consume releaseandmessenger:consume enrich enrich_backlog— without them nothing sorts mail, extracts events or indexes for search. - Jobs already queued at upgrade are worked through where they are, on
ingest, once.