<feed xmlns='http://www.w3.org/2005/Atom'>
<title>dotemacs/modules/mail-config.el, branch load-graph-classify-start</title>
<subtitle>My Emacs configuration
</subtitle>
<id>https://git.cjennings.net/dotemacs/atom?h=load-graph-classify-start</id>
<link rel='self' href='https://git.cjennings.net/dotemacs/atom?h=load-graph-classify-start'/>
<link rel='alternate' type='text/html' href='https://git.cjennings.net/dotemacs/'/>
<updated>2026-05-23T09:10:35+00:00</updated>
<entry>
<title>refactor(mail): consolidate compose-buffer kill policy to one home</title>
<updated>2026-05-23T09:10:35+00:00</updated>
<author>
<name>Craig Jennings</name>
<email>c@cjennings.net</email>
</author>
<published>2026-05-23T09:10:35+00:00</published>
<link rel='alternate' type='text/html' href='https://git.cjennings.net/dotemacs/commit/?id=83c6a6d016853cb298605d892fc9e9302cfa151a'/>
<id>urn:sha1:83c6a6d016853cb298605d892fc9e9302cfa151a</id>
<content type='text'>
org-msg only reads message-kill-buffer-on-exit (in org-msg--widen-and-undo) and never sets it, so the duplicate setq in org-msg's :config was redundant. I removed it and kept the single t in the mu4e :config, with a comment noting org-msg honors whatever mu4e leaves in place. No behavior change. Compose buffers still kill on exit.
</content>
</entry>
<entry>
<title>feat(mail): kill org-msg compose buffers on exit</title>
<updated>2026-05-23T09:07:42+00:00</updated>
<author>
<name>Craig Jennings</name>
<email>c@cjennings.net</email>
</author>
<published>2026-05-23T09:07:42+00:00</published>
<link rel='alternate' type='text/html' href='https://git.cjennings.net/dotemacs/commit/?id=82978c792c7e0d11da273cb4432407c86432e2f6'/>
<id>urn:sha1:82978c792c7e0d11da273cb4432407c86432e2f6</id>
<content type='text'>
The earlier setup kept compose buffers after exit (org-msg set message-kill-buffer-on-exit to nil), so HTML draft buffers lingered after a message was sent or aborted. I want them cleaned up, so I set the org-msg value to t to match the mu4e default. Both composers now kill the buffer on exit.

The modules byte-compile and the mail-config tests stay green. The kill-on-exit behavior itself only shows up in live use, not in batch.
</content>
</entry>
<entry>
<title>docs(mail): clarify message-kill-buffer-on-exit ownership</title>
<updated>2026-05-23T08:53:10+00:00</updated>
<author>
<name>Craig Jennings</name>
<email>c@cjennings.net</email>
</author>
<published>2026-05-23T08:53:10+00:00</published>
<link rel='alternate' type='text/html' href='https://git.cjennings.net/dotemacs/commit/?id=dd671f8c18d1e6d739bb668fa3c2482af9c3f81a'/>
<id>urn:sha1:dd671f8c18d1e6d739bb668fa3c2482af9c3f81a</id>
<content type='text'>
mail-config.el set message-kill-buffer-on-exit to t in mu4e's config and nil in org-msg's, with no note on which wins. org-msg-mode runs in every compose buffer, so org-msg's nil is the effective policy: compose buffers are kept, not killed. The org-msg comment said "always kill buffers on exit", which is backwards.

I rewrote both comments. The mu4e t is the plain-mu4e fallback that only matters if org-msg is ever disabled, and org-msg owns the live policy of keeping a draft buffer on exit so an in-progress HTML message isn't lost. No behavior change.
</content>
</entry>
<entry>
<title>refactor(mail): extract the mu4e attachment workflow into its own module</title>
<updated>2026-05-12T05:34:03+00:00</updated>
<author>
<name>Craig Jennings</name>
<email>c@cjennings.net</email>
</author>
<published>2026-05-12T05:34:03+00:00</published>
<link rel='alternate' type='text/html' href='https://git.cjennings.net/dotemacs/commit/?id=22232fc39598ffc065ee134889c3143566be5faa'/>
<id>urn:sha1:22232fc39598ffc065ee134889c3143566be5faa</id>
<content type='text'>
The attachment-save UI (the MIME-part filters, the three save commands, and the `special-mode'-derived selection buffer) was ~230 lines in `mail-config.el' and depended on nothing else there. It moves to `modules/mu4e-attachments.el', which `mail-config' now requires. `cj/email-map' and its C-; e bindings stay put. The keymap just points at commands that now live next door.

The unit tests move with it: `test-mail-config-attachments.el' becomes `test-mu4e-attachments.el' and requires the new module directly instead of pulling in the whole mu4e and org-msg use-package stack. The two tests that check `cj/email-map' wiring move to a new `test-mail-config.el', since that map belongs to `mail-config'. One of the moved tests quietly relied on a real mu4e install (it loaded `mu4e-mime-parts' through a load-path entry that loading `mail-config' happens to add), so it now stubs that path itself.
</content>
</entry>
<entry>
<title>feat(mu4e): simpler attachment-save commands on C-; e S/s/m</title>
<updated>2026-05-11T22:17:54+00:00</updated>
<author>
<name>Craig Jennings</name>
<email>c@cjennings.net</email>
</author>
<published>2026-05-11T22:17:54+00:00</published>
<link rel='alternate' type='text/html' href='https://git.cjennings.net/dotemacs/commit/?id=1aa8d0f60ceec62d37c34d5cb31c46434a647ff6'/>
<id>urn:sha1:1aa8d0f60ceec62d37c34d5cb31c46434a647ff6</id>
<content type='text'>
Three project-owned commands that reuse mu4e's MIME metadata (`mu4e-view-mime-parts') and save primitives (`mm-save-part-to-file', `mu4e-uniquify-save-file-name-function') directly instead of driving mu4e's completion UI. `cj/mu4e-save-all-attachments' (`C-; e S') prompts once for a directory and saves every attachment-like part. `cj/mu4e-save-attachment-here' (`C-; e s') saves one attachment, picked by display label, with duplicate filenames shown as "name &lt;part N&gt;" so they don't collapse into one completion candidate. `cj/mu4e-save-some-attachments' (`C-; e m') opens a `*mu4e attachments*' selection buffer showing mark state, label, MIME type, and size per row, where `RET' toggles a row, `a' / `u' mark / unmark all, `s' saves the marked ones, and `q' quits. Replaced the old Embark/Vertico-workaround comment. Tests cover the attachment filtering, the duplicate-filename disambiguation, save-path construction, the no-handle error, command prompting, and the email-map bindings.
</content>
</entry>
<entry>
<title>refactor(system-lib): extract cj/executable-find-or-warn from mail-config</title>
<updated>2026-05-10T19:04:22+00:00</updated>
<author>
<name>Craig Jennings</name>
<email>c@cjennings.net</email>
</author>
<published>2026-05-10T19:04:22+00:00</published>
<link rel='alternate' type='text/html' href='https://git.cjennings.net/dotemacs/commit/?id=c75e36f4ec6764142499a3ec965d25895c564cb0'/>
<id>urn:sha1:c75e36f4ec6764142499a3ec965d25895c564cb0</id>
<content type='text'>
Phase 2 of utility-consolidation, first commit per the spec's recommended order. `cj/mail--executable-or-warn' was the right pattern -- check executable-find, return the path, otherwise emit a clear `display-warning' naming the feature -- but it was trapped in mail-config and only mail callers benefited. Lift it into `cj/executable-find-or-warn' in system-lib.el with one new argument: an optional GROUP symbol that flows through to `display-warning' (defaulting to `cj/system-lib') so per-feature warning filters keep working. Mail callers pass `mail-config' explicitly.

Migrate `cj/mail--mbsync-command' and `cj/mail-configure-smtpmail' to the new helper. Drop the local definition. Add `(require \='system-lib)' to mail-config.el per the spec's Phase 2 exit criterion ("consumer modules explicitly require system-lib").

Five Normal/Boundary tests cover the four return-shape cases (program found / program missing / warning content / default vs explicit group).

Other consumers (prog-*.el, dirvish-config.el, browser-config.el) still call `executable-find' directly. Migrating them is a follow-up commit, audited per call site -- the spec flags some `:if' silent checks as intentional and they should NOT switch to the warning helper.
</content>
</entry>
<entry>
<title>fix: validate mail transport executables and default debug off</title>
<updated>2026-05-04T00:57:30+00:00</updated>
<author>
<name>Craig Jennings</name>
<email>c@cjennings.net</email>
</author>
<published>2026-05-04T00:57:30+00:00</published>
<link rel='alternate' type='text/html' href='https://git.cjennings.net/dotemacs/commit/?id=3e9499f62c4fb621ec234a0cf5cee51eb2cf32c0'/>
<id>urn:sha1:3e9499f62c4fb621ec234a0cf5cee51eb2cf32c0</id>
<content type='text'>
`mail-config.el` had three related issues. SMTP transport debug was hard-coded to t, which is sensitive since mail bodies and headers land in debug buffers. The use-package `:config` was also setting `sendmail-program` and `mu4e-get-mail-command` directly from `executable-find` results. So a host without msmtp or mbsync silently got `nil` or `(concat nil " -a")` instead of a clear failure mode.

I added `cj/smtpmail-debug-enabled` (default nil) plus `cj/set-smtpmail-debug` and `cj/toggle-smtpmail-debug` for temporary troubleshooting, mirroring the pattern from `auth-config.el`.

I extracted `cj/mail--executable-or-warn` so a missing program emits a one-time `display-warning` and returns nil. `cj/mail-configure-smtpmail` and `cj/mail--mbsync-command` both use it. Missing msmtp now leaves `sendmail-program` nil with a warning. Missing mbsync produces a nil sync command instead of the broken `(concat nil " -a")` string. I also wrapped the mbsync executable path in `shell-quote-argument` so unusual install paths don't fall apart on the `" -a"` concat.

I added `tests/test-mail-config-transport.el` with seven tests across Normal / Boundary / Error: debug-default-off, toggle wiring, msmtp present and missing, mbsync present, mbsync path with spaces, and mbsync missing. The `test-mail-config--with-executables` macro stubs `executable-find` from an alist so each test names its own environment.
</content>
</entry>
<entry>
<title>chore(deps): move remaining packages from :load-path to :vc; drop archived org-gcal</title>
<updated>2026-04-30T15:10:52+00:00</updated>
<author>
<name>Craig Jennings</name>
<email>c@cjennings.net</email>
</author>
<published>2026-04-30T15:10:52+00:00</published>
<link rel='alternate' type='text/html' href='https://git.cjennings.net/dotemacs/commit/?id=fc3fc42910f3dfa82dd9e00c20775ae318f8341c'/>
<id>urn:sha1:fc3fc42910f3dfa82dd9e00c20775ae318f8341c</id>
<content type='text'>
The three packages that still loaded from local checkouts now install
via :vc:

- chime → git@cjennings.net:chime.git (was :load-path "~/code/chime")
- wttrin → git@cjennings.net:emacs-wttrin.git (was :load-path
  "/home/cjennings/code/emacs-wttrin")
- org-msg → https://github.com/jeremy-compostella/org-msg (was
  :load-path "/home/cjennings/code/org-msg"; switching to upstream
  rather than a fork since the previous fork wasn't carrying any
  active changes)

For the two cjennings.net repos this matches the org-drill (be3e227)
and gloss (2e12131) shape: primary on cjennings.net, post-receive
hook mirroring to GitHub. The previously-commented :vc URLs in chime
and wttrin pointed at GitHub directly, which would have lost the
cjennings-first convention if uncommented later.

Also drops :ensure nil on chime (only relevant under package.el, not
:vc) and removes modules/archived/org-gcal-config.el. Nothing in
init.el or any module references org-gcal, so the file is genuinely
unused.
</content>
</entry>
<entry>
<title>feat(mail): add work account and reorganize C-; e bindings</title>
<updated>2026-04-28T00:06:11+00:00</updated>
<author>
<name>Craig Jennings</name>
<email>c@cjennings.net</email>
</author>
<published>2026-04-28T00:06:11+00:00</published>
<link rel='alternate' type='text/html' href='https://git.cjennings.net/dotemacs/commit/?id=bbec160f2279f203b98f4aead3c74515224e9988'/>
<id>urn:sha1:bbec160f2279f203b98f4aead3c74515224e9988</id>
<content type='text'>
Adds a third mu4e context for a work email account.

Reorganizes cj/email-map under C-; e: attach (A) and delete (D) move to uppercase to free c, d, g as account submaps. Each submap has i/u/s/l for inbox/unread/starred/large.

Trims mu4e-bookmarks to one unread query per account on b c, b g, b d. The full grid lives under C-; e.

mbsync and msmtp config for the new account lives in a separate dotfiles repo.
</content>
</entry>
<entry>
<title>fix(mail): default cj/custom-keymap so the file byte-compiles standalone</title>
<updated>2026-04-27T21:37:16+00:00</updated>
<author>
<name>Craig Jennings</name>
<email>c@cjennings.net</email>
</author>
<published>2026-04-27T21:37:16+00:00</published>
<link rel='alternate' type='text/html' href='https://git.cjennings.net/dotemacs/commit/?id=e52ea6a999a633e698757098328e763e2a10f69c'/>
<id>urn:sha1:e52ea6a999a633e698757098328e763e2a10f69c</id>
<content type='text'>
cj/custom-keymap is defined in keybindings.el, which init.el loads
before mail-config.el. The use-package org-msg :preface block calls
keymap-set on it, and use-package wraps :preface in eval-and-compile.
So byte-compiling mail-config.el on its own tries to call keymap-set
when cj/custom-keymap is still void.

Wrapping a defvar with a make-sparse-keymap default in eval-and-compile
gives the symbol a value during compilation. At runtime keybindings.el
has already populated the real keymap, so defvar does nothing.
</content>
</entry>
</feed>
