Linux version?
Hey guys, I personally use Windows, so I developed Skim for Windows only.
But I see a lot of intent among people to use it on Linux.
Skim v1.0.31 — "Mojibake No More" 🀄
The one where Chinese, Japanese and Korean mail stops looking like a row of . Turns out "just assume UTF-8" isn't a real internationalization strategy. Who knew.
Fixed
CJK charsets decode properly. GBK, GB18030, Big5, Shift_JIS and EUC-KR subjects and bodies now come through as actual text, not replacement characters (#53).
Already-garbled mail repairs itself. Folders that were holding the broken messages get refetched once on the next sync, this time decoded properly. You don't need to do anything.
A stale connection no longer shows up as an error. When the server quietly drops the socket, sync reconnects once and carries on instead of complaining to you about it.
Housekeeping
Skim v1.0.16 — "Are You Still There?" 👻
The one where Skim stops impersonating a corpse.
A self-update could relaunch Skim into a window with a titlebar and nothing. Restarts didn't help. Reinstalling didn't help. Then, hours later, it just came back which is somehow more unsettling than staying broken.
Turns out nothing was broken. The whole UI was waiting on the first mailbox query, that query was politely queued behind the catch-up sync, and the app had no way to say "hang on, I'm reading" so it said nothing at all. For hours. In an empty window. Cool.
Fixed
Skim v1.0.30 — "Sixty-Eight Seconds" 🐢➡️🐇
The one where a big grouped inbox stops making you wait a full minute to open an email. Turns out asking SQLite to rescan the whole folder once per message is bad for business. Who knew. (We should have.)
Faster
Grouped inboxes are fast again. Picking the newest message in each thread used to walk the entire folder once per message. That's quadratic, and on a 15k-message inbox it took over a minute, and every other read waited in line behind it. So after launch you got a blank list and a nice long think. One new index later, the same query takes 68 s 20 ms. A test now pins the query plan so it can't quietly come back.
Inline images no longer freeze the window while a sync is running. They're now loaded off the UI thread, where they should have been all along.
New
Skim v1.0.28 — "Hi, my name is" 👋
The one where your mail finally stops introducing itself as a.very.long.address@example.com and starts signing off like a grown-up.
New
Your name on outgoing mail. Skim always had a slot for a display name it just never bothered to fill it. Now it does, per account. And it doesn't ask you: it takes a quiet look at your Sent folder, notices what you actually sign with, and adopts it. Guess once, never again, and never after you've touched the field yourself. (Microsoft OAuth hands the name over at connect time, because it's already right there in the token. Google makes us do it the hard way.) closes #43
Per-mailbox signatures. One plain-text sign-off per account, inserted into the draft the moment you open the composer so what you see is exactly what goes out, and the copy in IMAP Drafts matches. Comes with the proper -- delimiter pre-typed, which also means the AI co-author and the language detector politely skip over your sign-off instead of studying it. closes #42
Fixed
Skim v1.0.6 — "Bring Your Own Brain" 🧠
The one where Skim stops being picky about which AI you talk to, and the whole app goes on a diet at the same time. Efficiency and choice, in one download. You're welcome.
New
Bring your own AI endpoint (OpenAI-compatible). A third provider joins Anthropic and OpenRouter: point Skim at any OpenAI-compatible API Ollama, LM Studio, vLLM, your homelab gateway, whatever. Just a Base URL and a Model ID; the API key is optional (leave it blank for local servers that don't want one). No key = no Authorization header, so your Ollama box stops complaining. (Closes #12.)
AI chat that can actually breathe. The command palette (Ctrl+K) can now expand to near-fullscreen for reading long answers one toggle in the corner, only in chat mode. Repeat Ctrl+K flips it open/closed instead of nuking the palette. It remembers your preference, and text stays in a comfy ~760px reading column instead of sprawling edge-to-edge.
Fixed
Skim - Free, open-source AI email client for Windows
Skim v1.0.27 — "Old News" 📰
The one where your second computer stops greeting you with a breathless "12 NEW MESSAGES!" about mail you finished reading at lunch.
Fixed
No more ghost notifications. Read your mail at work all day, come home, boot the other machine and Skim used to toast about every single message that arrived meanwhile, badge and all. It had the "already read" flag right there in its hands the whole time. It just... didn't look. Now it looks. Only mail the server still holds unread gets a toast.
The tray badge tells the truth on startup. It used to paint yesterday's unread count the instant the icon appeared, then quietly correct itself minutes later after a full folder sweep. Now the badge waits for the first inbox sync and shows the real number no stale flash, no "wait, where did those 12 go?"
Badge follows push, not the 5-minute poll. The IDLE-driven inbox sync the one that actually fires when mail lands never repainted the badge. Now it does, on success and on failure (offline still gets the cached count, just honestly).
Housekeeping
Skim v1.0.24 — "You were knocking with the wrong key" 🔑
The one where OpenAI's smartest models finally answer. Turns out we'd been calling one JSON field by a name they retired back when o1 shipped, and they were not shy about it.
Fixed
-
Reasoning models on a custom OpenAI endpoint work again. Point the OpenAI-compatible provider at OpenAI itself, pick anything from the o-series or the GPT-5 family, and every single request died before the first token: Unsupported parameter: 'max_tokens' is not supported with this model. Use 'max_completion_tokens' instead. Which is a wonderfully clear error message to receive zero times, because you're in a chat window and all you see is that nothing happened.
The lazy fix would be to rename the field everywhere and move on. Except only about half of the OpenAI-compatible world speaks the new name: Mistral answers 422, and Ollama and llama-cpp-python ignore it in complete silence which doesn't fail your request, it just removes the ceiling on the answer. That's strictly worse than an error, because nobody ever finds out.
So Skim now opens with the name every server understands, and switches only for an endpoint that asks for the other one by name, in its own error and only when that error names both keys, which is what separates "use the other name" from "that number is too big". Cost: one rejected request the first time you talk to such an endpoint. No new settings, no model list to maintain, nothing for you to choose. Exactly the amount of thinking about this you should have to do: none.
Huge thanks to @ondrahracek for this one not just the fix, but a writeup that walked through what LangChain and goose each broke trying the obvious thing first, and two tests verified by mutation. Reviewing that was a genuine pleasure.
Housekeeping
Skim v1.0.26 — "Think Less, Answer More" 🧠
The one where OpenAI told us our tools and its own thinking couldn't be in the same room, and we said fine, we'll ask nicely twice.
Fixed
Mailbox chat works again on gpt-5.6 models. Point the OpenAI-compatible provider at OpenAI with a gpt-5.6-* model and every single round that carried tools came back as a 400 and a wall of English error prose in the chat bubble. Retrying showed you the same wall. Very helpful. (#40)
The twist: Skim never sent reasoning_effort at all. The model reasons at medium on its own, then refuses its own default alongside our tools so nothing in our request even named the thing that broke it.We still don't guess. No model-name regex, no "is this OpenAI?" sniffing the same base URL serves OpenRouter, Ollama, LM Studio, vLLM and whatever you typed in that box, and half of them would 422 on the "fix". So Skim sends nothing up front, waits for the endpoint to name the remedy in its own error, and retries exactly once with the value it asked for tools still attached, because answering without the search results would rather defeat the point.
