kuzymail 1.4.1__tar.gz
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- kuzymail-1.4.1/AGENT_USAGE.md +700 -0
- kuzymail-1.4.1/HUMAN_USAGE.md +310 -0
- kuzymail-1.4.1/LICENSE +661 -0
- kuzymail-1.4.1/MANIFEST.in +16 -0
- kuzymail-1.4.1/PKG-INFO +205 -0
- kuzymail-1.4.1/README.md +177 -0
- kuzymail-1.4.1/debian/.gitignore +7 -0
- kuzymail-1.4.1/debian/changelog +170 -0
- kuzymail-1.4.1/debian/control +29 -0
- kuzymail-1.4.1/debian/copyright +20 -0
- kuzymail-1.4.1/debian/kuzymail.install +3 -0
- kuzymail-1.4.1/debian/kuzymail.kuzymaild-worker@.service +23 -0
- kuzymail-1.4.1/debian/kuzymail.kuzymaild.service +19 -0
- kuzymail-1.4.1/debian/rules +16 -0
- kuzymail-1.4.1/debian/source/format +1 -0
- kuzymail-1.4.1/docs/CLIENT.md +508 -0
- kuzymail-1.4.1/docs/DAEMON_ARCHITECTURE.md +429 -0
- kuzymail-1.4.1/docs/DISTRIBUTION_PACKAGING.md +35 -0
- kuzymail-1.4.1/docs/reference.md +424 -0
- kuzymail-1.4.1/justfile +23 -0
- kuzymail-1.4.1/packaging/rpm/kuzymail.spec +61 -0
- kuzymail-1.4.1/pyproject.toml +64 -0
- kuzymail-1.4.1/setup.cfg +4 -0
- kuzymail-1.4.1/src/kuzymail/__init__.py +5 -0
- kuzymail-1.4.1/src/kuzymail/__main__.py +7 -0
- kuzymail-1.4.1/src/kuzymail/attention.py +299 -0
- kuzymail-1.4.1/src/kuzymail/attention_match.py +115 -0
- kuzymail-1.4.1/src/kuzymail/cli.py +6248 -0
- kuzymail-1.4.1/src/kuzymail/daemon.py +780 -0
- kuzymail-1.4.1/src/kuzymail/daemon_client.py +63 -0
- kuzymail-1.4.1/src/kuzymail/data/inject-adapters/default.json +67 -0
- kuzymail-1.4.1/src/kuzymail/data/prompt-templates/default.json +22 -0
- kuzymail-1.4.1/src/kuzymail/idle.py +167 -0
- kuzymail-1.4.1/src/kuzymail/inject_adapters.py +210 -0
- kuzymail-1.4.1/src/kuzymail/inject_state.py +197 -0
- kuzymail-1.4.1/src/kuzymail/injector.py +115 -0
- kuzymail-1.4.1/src/kuzymail/layout.py +150 -0
- kuzymail-1.4.1/src/kuzymail/mail_accounts.py +123 -0
- kuzymail-1.4.1/src/kuzymail/markdown.py +118 -0
- kuzymail-1.4.1/src/kuzymail/prompt_templates.py +532 -0
- kuzymail-1.4.1/src/kuzymail/schedule.py +157 -0
- kuzymail-1.4.1/src/kuzymail/settings.py +499 -0
- kuzymail-1.4.1/src/kuzymail/tokens.py +104 -0
- kuzymail-1.4.1/src/kuzymail/version.py +13 -0
- kuzymail-1.4.1/src/kuzymail.egg-info/PKG-INFO +205 -0
- kuzymail-1.4.1/src/kuzymail.egg-info/SOURCES.txt +55 -0
- kuzymail-1.4.1/src/kuzymail.egg-info/dependency_links.txt +1 -0
- kuzymail-1.4.1/src/kuzymail.egg-info/entry_points.txt +3 -0
- kuzymail-1.4.1/src/kuzymail.egg-info/requires.txt +4 -0
- kuzymail-1.4.1/src/kuzymail.egg-info/top_level.txt +1 -0
- kuzymail-1.4.1/tests/test_attention_cli.py +165 -0
- kuzymail-1.4.1/tests/test_attention_match.py +62 -0
- kuzymail-1.4.1/tests/test_daemon_logic.py +359 -0
- kuzymail-1.4.1/tests/test_inject_adapters.py +127 -0
- kuzymail-1.4.1/tests/test_layout_and_accounts.py +4580 -0
- kuzymail-1.4.1/tests/test_prompt_templates.py +182 -0
- kuzymail-1.4.1/tests/test_version.py +31 -0
|
@@ -0,0 +1,700 @@
|
|
|
1
|
+
# Agent Usage
|
|
2
|
+
|
|
3
|
+
This document is for agent participants using `kuzymail` as a client tool.
|
|
4
|
+
Profiles and accounts are configured locally on the machine where `kuzymail`
|
|
5
|
+
runs. A shared registry may provide optional metadata, but it is not required
|
|
6
|
+
for local setup.
|
|
7
|
+
|
|
8
|
+
It assumes a working mail service already exists.
|
|
9
|
+
|
|
10
|
+
Examples below assume `kuzymail` is installed or that the local `.venv` is
|
|
11
|
+
activated.
|
|
12
|
+
|
|
13
|
+
## 1. Mental Model
|
|
14
|
+
|
|
15
|
+
Use:
|
|
16
|
+
|
|
17
|
+
- `kuzymail` as the canonical agent-facing facade for:
|
|
18
|
+
- account selection
|
|
19
|
+
- current-profile selection
|
|
20
|
+
- profile/runtime setup
|
|
21
|
+
- `sync`
|
|
22
|
+
- `list`
|
|
23
|
+
- `show`
|
|
24
|
+
- `attachments`
|
|
25
|
+
- `send`
|
|
26
|
+
- `reply`
|
|
27
|
+
- `archive`
|
|
28
|
+
- `delete`
|
|
29
|
+
- raw `notmuch` for deep search/debugging when needed
|
|
30
|
+
|
|
31
|
+
Output contract:
|
|
32
|
+
|
|
33
|
+
- `secret` stays plaintext because `mbsync` and `msmtp` consume it directly
|
|
34
|
+
- the agent-facing operational commands are JSON-first by default
|
|
35
|
+
|
|
36
|
+
You do not need to manage IMAP sessions or SMTP sessions manually.
|
|
37
|
+
|
|
38
|
+
Normal workflow:
|
|
39
|
+
|
|
40
|
+
1. select your account once
|
|
41
|
+
2. select your profile once
|
|
42
|
+
3. sync your mailbox
|
|
43
|
+
4. inspect/search local mail with `kuzymail list/show`
|
|
44
|
+
5. send new mail with `kuzymail send` or answer with `kuzymail reply`
|
|
45
|
+
6. archive or delete with explicit dry-run first
|
|
46
|
+
|
|
47
|
+
## 2. Profiles
|
|
48
|
+
|
|
49
|
+
Create your local profile after Reception grants your service identity and you
|
|
50
|
+
have claimed your password:
|
|
51
|
+
|
|
52
|
+
```bash
|
|
53
|
+
kuzymail profile create --profile zorbax --address zorbax@mail.example.invalid --display-name "Zorbax"
|
|
54
|
+
```
|
|
55
|
+
|
|
56
|
+
Use `profile modify` for corrections to an existing profile:
|
|
57
|
+
|
|
58
|
+
```bash
|
|
59
|
+
kuzymail profile modify --profile zorbax --display-name "Zorbax"
|
|
60
|
+
```
|
|
61
|
+
|
|
62
|
+
Use this command to inspect the currently known mailbox inventory:
|
|
63
|
+
|
|
64
|
+
```bash
|
|
65
|
+
kuzymail mailboxes
|
|
66
|
+
```
|
|
67
|
+
|
|
68
|
+
Your profile determines:
|
|
69
|
+
|
|
70
|
+
- your email address
|
|
71
|
+
- where your local runtime is stored
|
|
72
|
+
|
|
73
|
+
### Select your current profile
|
|
74
|
+
|
|
75
|
+
```bash
|
|
76
|
+
kuzymail profile use --profile zorbax
|
|
77
|
+
```
|
|
78
|
+
|
|
79
|
+
After that, most commands can omit `--profile`.
|
|
80
|
+
|
|
81
|
+
## 2.1 Accounts
|
|
82
|
+
|
|
83
|
+
An account is one concrete mailbox account for a profile.
|
|
84
|
+
|
|
85
|
+
It carries:
|
|
86
|
+
|
|
87
|
+
- mailbox address
|
|
88
|
+
- login username
|
|
89
|
+
- secret key name
|
|
90
|
+
- IMAP host/port/security
|
|
91
|
+
- SMTP host/port/security
|
|
92
|
+
|
|
93
|
+
Account names are scoped by profile.
|
|
94
|
+
`zorbax/primary` and `quindle/primary` are different accounts even though the account id is the same.
|
|
95
|
+
|
|
96
|
+
Typical service setup:
|
|
97
|
+
|
|
98
|
+
```bash
|
|
99
|
+
kuzymail account set \
|
|
100
|
+
--account primary \
|
|
101
|
+
--profile zorbax \
|
|
102
|
+
--address zorbax@mail.example.invalid \
|
|
103
|
+
--imap-host mail.example.invalid \
|
|
104
|
+
--imap-security ssl \
|
|
105
|
+
--smtp-host mail.example.invalid \
|
|
106
|
+
--smtp-security starttls \
|
|
107
|
+
--set-current
|
|
108
|
+
```
|
|
109
|
+
|
|
110
|
+
Example second account for the same profile:
|
|
111
|
+
|
|
112
|
+
```bash
|
|
113
|
+
kuzymail account set \
|
|
114
|
+
--account external \
|
|
115
|
+
--profile zorbax \
|
|
116
|
+
--address zorbax@example.net \
|
|
117
|
+
--login-user zorbax@example.net \
|
|
118
|
+
--secret-key ZORBAX_EXTERNAL_PASSWORD \
|
|
119
|
+
--imap-host imap.example.net \
|
|
120
|
+
--imap-security ssl \
|
|
121
|
+
--smtp-host smtp.example.net \
|
|
122
|
+
--smtp-security ssl
|
|
123
|
+
```
|
|
124
|
+
|
|
125
|
+
Inspect configured accounts:
|
|
126
|
+
|
|
127
|
+
```bash
|
|
128
|
+
kuzymail account list
|
|
129
|
+
kuzymail account show
|
|
130
|
+
```
|
|
131
|
+
|
|
132
|
+
By default, account secrets are kept under:
|
|
133
|
+
|
|
134
|
+
```text
|
|
135
|
+
secrets/profiles/<profile>/accounts/<account>.env
|
|
136
|
+
```
|
|
137
|
+
|
|
138
|
+
Use `--secrets-file` only when you intentionally want an explicit shared or external env file.
|
|
139
|
+
|
|
140
|
+
## 2.2 Profile Tokens
|
|
141
|
+
|
|
142
|
+
If a profile token is enabled, sensitive commands require one of:
|
|
143
|
+
|
|
144
|
+
- `--token-file <path>`
|
|
145
|
+
- `KUZYMAIL_TOKEN`
|
|
146
|
+
|
|
147
|
+
Example:
|
|
148
|
+
|
|
149
|
+
```bash
|
|
150
|
+
kuzymail profile issue-token --profile zorbax
|
|
151
|
+
printf '%s' '...token...' > ~/.config/kuzymail/zorbax.token
|
|
152
|
+
kuzymail sync --token-file ~/.config/kuzymail/zorbax.token
|
|
153
|
+
```
|
|
154
|
+
|
|
155
|
+
This is a local capability guard.
|
|
156
|
+
It is not strong host-level isolation.
|
|
157
|
+
|
|
158
|
+
## 2.3 Strict Current Profile
|
|
159
|
+
|
|
160
|
+
In an agent-local environment, enable strict mode after selecting your profile:
|
|
161
|
+
|
|
162
|
+
```bash
|
|
163
|
+
kuzymail profile use --profile zorbax
|
|
164
|
+
kuzymail profile strict --on
|
|
165
|
+
```
|
|
166
|
+
|
|
167
|
+
After this, `kuzymail` refuses mailbox operations for another profile in the same environment.
|
|
168
|
+
This reduces accidental or casual cross-profile use; it does not replace host-level isolation.
|
|
169
|
+
|
|
170
|
+
### Initialize a newly granted profile
|
|
171
|
+
|
|
172
|
+
After Reception grants mail access and you claim the one-time password, initialize the local runtime and secret like this:
|
|
173
|
+
|
|
174
|
+
```bash
|
|
175
|
+
kuzymail account set --account primary --profile blorvax --address blorvax@mail.example.invalid --imap-host mail.example.invalid --imap-security ssl --smtp-host mail.example.invalid --smtp-security starttls --set-current
|
|
176
|
+
kuzymail init-profile --profile blorvax --password-prompt --set-current
|
|
177
|
+
```
|
|
178
|
+
|
|
179
|
+
## 3. Core Commands
|
|
180
|
+
|
|
181
|
+
### Show runtime paths
|
|
182
|
+
|
|
183
|
+
```bash
|
|
184
|
+
kuzymail paths
|
|
185
|
+
```
|
|
186
|
+
|
|
187
|
+
Returns JSON.
|
|
188
|
+
|
|
189
|
+
### Sync mailbox
|
|
190
|
+
|
|
191
|
+
```bash
|
|
192
|
+
kuzymail sync
|
|
193
|
+
```
|
|
194
|
+
|
|
195
|
+
Returns JSON, including captured `mbsync` / `notmuch` command output.
|
|
196
|
+
|
|
197
|
+
This pulls:
|
|
198
|
+
|
|
199
|
+
- `INBOX`
|
|
200
|
+
- `Sent`
|
|
201
|
+
- `Archive`
|
|
202
|
+
|
|
203
|
+
Then refreshes the local notmuch database.
|
|
204
|
+
It also runs `notmuch reindex '*'` every time. That is deliberate: on the current build, structured header queries become reliable only after reindex, so the wrapper pays the extra cost to keep search semantics correct.
|
|
205
|
+
|
|
206
|
+
### Lightweight check
|
|
207
|
+
|
|
208
|
+
```bash
|
|
209
|
+
kuzymail check
|
|
210
|
+
```
|
|
211
|
+
|
|
212
|
+
Returns a single JSON object from an IMAP `STATUS` probe. It is read-only: no
|
|
213
|
+
message bodies or headers are fetched, no MIME is parsed, no local Maildir is
|
|
214
|
+
updated, and no IMAP flags are changed. Use `should_sync` and `sync_reason` to
|
|
215
|
+
decide whether to run a full `kuzymail sync`.
|
|
216
|
+
|
|
217
|
+
The check reads the local profile/account cursor from `imap-status.json` when it
|
|
218
|
+
exists. A successful `sync` refreshes that cursor with the latest `UIDNEXT` and
|
|
219
|
+
`UIDVALIDITY`; `check` never writes it. If no cursor exists yet, unseen mail can
|
|
220
|
+
still trigger `should_sync=true`, but UID advancement cannot be inferred.
|
|
221
|
+
|
|
222
|
+
### Managed-mode inject prompt templates
|
|
223
|
+
|
|
224
|
+
`kuzymaild` wakes an agent with the `mail.digest` prompt template when managed
|
|
225
|
+
mail attention decides that new mail should be injected.
|
|
226
|
+
|
|
227
|
+
The upstream default is generic and policy-free:
|
|
228
|
+
|
|
229
|
+
```text
|
|
230
|
+
Open one directly with `{show_command}`, or sync the mailbox with `{sync_command}`.
|
|
231
|
+
```
|
|
232
|
+
|
|
233
|
+
Inspect and validate the effective template:
|
|
234
|
+
|
|
235
|
+
```bash
|
|
236
|
+
kuzymail prompt template list
|
|
237
|
+
kuzymail prompt template show mail.digest
|
|
238
|
+
kuzymail prompt template render mail.digest
|
|
239
|
+
kuzymail prompt template validate
|
|
240
|
+
```
|
|
241
|
+
|
|
242
|
+
Set an override from a text file:
|
|
243
|
+
|
|
244
|
+
```bash
|
|
245
|
+
kuzymail prompt template set mail.digest --file template.txt
|
|
246
|
+
```
|
|
247
|
+
|
|
248
|
+
Add local policy text without replacing the whole template:
|
|
249
|
+
|
|
250
|
+
```bash
|
|
251
|
+
kuzymail prompt policy set --file policy.txt
|
|
252
|
+
```
|
|
253
|
+
|
|
254
|
+
Precedence is package default, `/etc/kuzymail/prompt-templates.json`, user
|
|
255
|
+
override, profile override, then account override. Use `--profile` and
|
|
256
|
+
`--account` on the prompt commands to inspect or set profile/account scoped
|
|
257
|
+
overrides. Use `--system` only for host-wide policy.
|
|
258
|
+
|
|
259
|
+
Managed-mode inject adapters are also registry-backed. The package ships default
|
|
260
|
+
kuzywrap adapters under `kuzymail/data/inject-adapters/default.json`; host-wide
|
|
261
|
+
overrides can be placed in `/etc/kuzymail/inject-adapters.json`, and user
|
|
262
|
+
overrides in `$XDG_CONFIG_HOME/kuzymail/inject-adapters.json`. The attention
|
|
263
|
+
field `inject_wrapper` names one configured adapter. Adapter definitions use
|
|
264
|
+
argv lists, not shell strings. The packaged adapters are `kuzywrap-claude`,
|
|
265
|
+
`kuzywrap-codex`, `kuzywrap-codewhale`, and `kuzywrap-antigravity`;
|
|
266
|
+
Antigravity-hosted agents should use `kuzywrap-antigravity`, and
|
|
267
|
+
CodeWhale-hosted agents should use `kuzywrap-codewhale`.
|
|
268
|
+
|
|
269
|
+
### List inbox threads
|
|
270
|
+
|
|
271
|
+
```bash
|
|
272
|
+
kuzymail list
|
|
273
|
+
```
|
|
274
|
+
|
|
275
|
+
### Search / list with JSON
|
|
276
|
+
|
|
277
|
+
```bash
|
|
278
|
+
kuzymail list --query "tag:inbox subject:BLOCKER"
|
|
279
|
+
```
|
|
280
|
+
|
|
281
|
+
### Show message or thread
|
|
282
|
+
|
|
283
|
+
```bash
|
|
284
|
+
kuzymail show --message-id '<message-id>'
|
|
285
|
+
kuzymail show --thread 0000000000000001 --entire-thread
|
|
286
|
+
```
|
|
287
|
+
|
|
288
|
+
### Attachments
|
|
289
|
+
|
|
290
|
+
```bash
|
|
291
|
+
kuzymail attachments list --message-id '<message-id>'
|
|
292
|
+
kuzymail attachments extract --message-id '<message-id>' --part 3 --output /tmp/file.bin
|
|
293
|
+
```
|
|
294
|
+
|
|
295
|
+
### Raw notmuch remains available
|
|
296
|
+
|
|
297
|
+
```bash
|
|
298
|
+
notmuch --config runtime/profiles/zorbax/accounts/primary/notmuch-config search --sort=newest-first tag:inbox
|
|
299
|
+
notmuch --config runtime/profiles/zorbax/accounts/primary/notmuch-config search --sort=newest-first subject:extid-1
|
|
300
|
+
notmuch --config runtime/profiles/zorbax/accounts/primary/notmuch-config show --entire-thread=false id:<message-id>
|
|
301
|
+
```
|
|
302
|
+
|
|
303
|
+
### Threaded reply
|
|
304
|
+
|
|
305
|
+
```bash
|
|
306
|
+
kuzymail reply \
|
|
307
|
+
--profile zorbax \
|
|
308
|
+
--message-id '<message-id>' \
|
|
309
|
+
--body "Reviewed. I agree with the proposed direction."
|
|
310
|
+
```
|
|
311
|
+
|
|
312
|
+
`reply` is the safer default for agents: it replies only to `Reply-To` when
|
|
313
|
+
present, otherwise `From`, and removes the current account address. It does not
|
|
314
|
+
copy the original `To` or `Cc` recipients.
|
|
315
|
+
|
|
316
|
+
Use `reply --include-cc` when you intentionally want a sender-only reply that
|
|
317
|
+
also keeps the original `Cc` recipients. It still does not copy the original
|
|
318
|
+
`To` list.
|
|
319
|
+
|
|
320
|
+
Use `reply-all` only when you intentionally want to include the sender plus the
|
|
321
|
+
original thread recipients:
|
|
322
|
+
|
|
323
|
+
```bash
|
|
324
|
+
kuzymail reply-all \
|
|
325
|
+
--profile zorbax \
|
|
326
|
+
--message-id '<message-id>' \
|
|
327
|
+
--x project thecost-accounting \
|
|
328
|
+
--x task-id extid-2026-03 \
|
|
329
|
+
--body "Reviewed. Including the thread."
|
|
330
|
+
```
|
|
331
|
+
|
|
332
|
+
Use `reply-all --exclude-cc` when you want the sender plus original `To`
|
|
333
|
+
recipients, but do not want to copy the original `Cc` recipients.
|
|
334
|
+
|
|
335
|
+
Both reply commands report `to`, `cc`, and `external_recipients` in JSON.
|
|
336
|
+
`external_recipients` is visibility by default; account policy can require
|
|
337
|
+
`--allow-external` or block external delivery.
|
|
338
|
+
|
|
339
|
+
To add recipients deliberately, use additive flags:
|
|
340
|
+
|
|
341
|
+
```bash
|
|
342
|
+
kuzymail reply \
|
|
343
|
+
--profile zorbax \
|
|
344
|
+
--message-id '<message-id>' \
|
|
345
|
+
--add-to reviewer@example.invalid \
|
|
346
|
+
--add-cc zorbax@example.invalid \
|
|
347
|
+
--add-bcc audit@example.net \
|
|
348
|
+
--x project thecost-accounting \
|
|
349
|
+
--x task-id extid-2026-03 \
|
|
350
|
+
--body "Reviewed. Explicit recipients included."
|
|
351
|
+
```
|
|
352
|
+
|
|
353
|
+
`--add-to`, `--add-cc`, and `--add-bcc` are explicit additions to the computed
|
|
354
|
+
reply recipients. kuzymail removes the current account only from implicit
|
|
355
|
+
computed recipients; configured sender aliases are also treated as self
|
|
356
|
+
addresses for implicit reply/reply-all filtering. If an agent explicitly adds
|
|
357
|
+
its own address, it is kept.
|
|
358
|
+
Bcc recipients are included in the SMTP envelope and local JSON output, but are
|
|
359
|
+
not written into the outgoing message headers or the sent-copy serialization.
|
|
360
|
+
`send` also accepts repeatable `--bcc` for envelope-only Bcc recipients.
|
|
361
|
+
|
|
362
|
+
For multiline replies, prefer `--body-stdin` or `--body-file -`. Inline
|
|
363
|
+
`--body` text interprets shell-safe escaped newlines by default: `\n`, `\r`,
|
|
364
|
+
`\t`, and `\\`. Pass `--no-body-escape` only when you need literal backslashes.
|
|
365
|
+
`send`, `reply`, and `reply-all` reject empty bodies by default; pass
|
|
366
|
+
`--empty-body` only when an empty message body is intentional. `send` also
|
|
367
|
+
rejects an empty `--subject` unless `--empty-subject` is passed.
|
|
368
|
+
|
|
369
|
+
### HTML mail
|
|
370
|
+
|
|
371
|
+
Plain text remains the default. To send HTML, provide both an explicit
|
|
372
|
+
plain-text body and an HTML body; kuzymail emits `multipart/alternative` with
|
|
373
|
+
the plain part first.
|
|
374
|
+
|
|
375
|
+
```bash
|
|
376
|
+
kuzymail send \
|
|
377
|
+
--profile zorbax \
|
|
378
|
+
--to quindle@mail.example.invalid \
|
|
379
|
+
--subject "Readable report" \
|
|
380
|
+
--x project kuzymail \
|
|
381
|
+
--x task-id html-report-1 \
|
|
382
|
+
--body-file plain.txt \
|
|
383
|
+
--html-body-file report.html
|
|
384
|
+
```
|
|
385
|
+
|
|
386
|
+
Markdown mail is explicit and symmetric with HTML input. Use `--markdown-body`,
|
|
387
|
+
`--markdown-body-file`, or `--markdown-stdin`; kuzymail renders the Markdown to
|
|
388
|
+
the HTML part and uses the original Markdown as the plain-text part unless an
|
|
389
|
+
explicit `--body`, `--body-file`, or `--body-stdin` fallback is provided.
|
|
390
|
+
Markdown options cannot be combined with `--html-body`, `--html-body-file`, or
|
|
391
|
+
`--html-stdin`. Markdown images with `http://` or `https://` sources remain
|
|
392
|
+
remote HTML images. Non-remote Markdown image targets are local files, resolved
|
|
393
|
+
relative to the Markdown file directory for `--markdown-body-file`; they must
|
|
394
|
+
exist as regular files and are attached inline with `cid:` references.
|
|
395
|
+
|
|
396
|
+
```bash
|
|
397
|
+
kuzymail send \
|
|
398
|
+
--profile zorbax \
|
|
399
|
+
--to quindle@mail.example.invalid \
|
|
400
|
+
--subject "Readable report" \
|
|
401
|
+
--x project kuzymail \
|
|
402
|
+
--x task-id markdown-report-1 \
|
|
403
|
+
--markdown-body-file report.md
|
|
404
|
+
```
|
|
405
|
+
|
|
406
|
+
### Sending attachments
|
|
407
|
+
|
|
408
|
+
`send` and `reply` accept repeatable `--attach` / `--attachment` flags:
|
|
409
|
+
|
|
410
|
+
```bash
|
|
411
|
+
kuzymail send \
|
|
412
|
+
--profile zorbax \
|
|
413
|
+
--to quindle@mail.example.invalid \
|
|
414
|
+
--subject "Review request" \
|
|
415
|
+
--x project kuzymail \
|
|
416
|
+
--x task-id contract-review-1 \
|
|
417
|
+
--body "Attached for review." \
|
|
418
|
+
--attach ./contract.tex
|
|
419
|
+
```
|
|
420
|
+
|
|
421
|
+
### Archive
|
|
422
|
+
|
|
423
|
+
Dry-run first:
|
|
424
|
+
|
|
425
|
+
```bash
|
|
426
|
+
kuzymail archive --profile zorbax --thread 0000000000000001
|
|
427
|
+
```
|
|
428
|
+
|
|
429
|
+
Apply:
|
|
430
|
+
|
|
431
|
+
```bash
|
|
432
|
+
kuzymail archive --profile zorbax --thread 0000000000000001 --yes
|
|
433
|
+
```
|
|
434
|
+
|
|
435
|
+
This also removes the affected messages from the local `notmuch` inbox/unread view so the operator-visible state stays coherent after the IMAP move.
|
|
436
|
+
|
|
437
|
+
### Delete
|
|
438
|
+
|
|
439
|
+
Dry-run first:
|
|
440
|
+
|
|
441
|
+
```bash
|
|
442
|
+
kuzymail delete --profile zorbax --message-id '<message-id>'
|
|
443
|
+
```
|
|
444
|
+
|
|
445
|
+
Apply:
|
|
446
|
+
|
|
447
|
+
```bash
|
|
448
|
+
kuzymail delete --profile zorbax --message-id '<message-id>' --yes
|
|
449
|
+
```
|
|
450
|
+
|
|
451
|
+
This also tags the affected local messages as `deleted` and removes them from the `notmuch` inbox/unread view.
|
|
452
|
+
|
|
453
|
+
## 4. Sending Mail
|
|
454
|
+
|
|
455
|
+
Example:
|
|
456
|
+
|
|
457
|
+
```bash
|
|
458
|
+
kuzymail send \
|
|
459
|
+
--profile zorbax \
|
|
460
|
+
--to quindle@mail.example.invalid \
|
|
461
|
+
--subject "Proposal: namespace cleanup" \
|
|
462
|
+
--body "Intent: tighten noisy IDs. Action requested: review proposed cleanup."
|
|
463
|
+
```
|
|
464
|
+
|
|
465
|
+
Use `--from` only for the account address or an explicitly configured sender
|
|
466
|
+
alias. This keeps the same SMTP login, kuzymail secret, runtime account, Sent
|
|
467
|
+
copy, and notmuch index while changing the RFC822 `From:` header:
|
|
468
|
+
|
|
469
|
+
```bash
|
|
470
|
+
kuzymail account modify \
|
|
471
|
+
--profile ada \
|
|
472
|
+
--account proton-bridge \
|
|
473
|
+
--sender-alias "Ada Example <ada@example.org>"
|
|
474
|
+
|
|
475
|
+
kuzymail send \
|
|
476
|
+
--profile ada \
|
|
477
|
+
--account proton-bridge \
|
|
478
|
+
--from "Ada Example <ada@example.org>" \
|
|
479
|
+
--to customer@example.org \
|
|
480
|
+
--subject "Order update" \
|
|
481
|
+
--body "Your order has been updated."
|
|
482
|
+
```
|
|
483
|
+
|
|
484
|
+
Unauthorized `--from` addresses fail before SMTP with `send_from_not_allowed`.
|
|
485
|
+
Header injection and multi-address values are rejected. The SMTP provider must
|
|
486
|
+
also know the alias; otherwise it may reject the message even after kuzymail
|
|
487
|
+
accepts the local configuration. Use `--dry-run` to inspect `from`,
|
|
488
|
+
`from_address`, `account_address`, and `login_user` before sending. `reply` and
|
|
489
|
+
`reply-all` accept the same `--from` option.
|
|
490
|
+
|
|
491
|
+
Outbound attributes are optional by default. Add them when they help audit,
|
|
492
|
+
routing, or operational context:
|
|
493
|
+
|
|
494
|
+
```bash
|
|
495
|
+
kuzymail send \
|
|
496
|
+
--profile zorbax \
|
|
497
|
+
--to quindle@mail.example.invalid \
|
|
498
|
+
--subject "Proposal: namespace cleanup" \
|
|
499
|
+
--x project thecost-accounting \
|
|
500
|
+
--x task-id extid-2026-03 \
|
|
501
|
+
--body "Intent: tighten noisy IDs. Action requested: review proposed cleanup."
|
|
502
|
+
```
|
|
503
|
+
|
|
504
|
+
`--x NAME VALUE` is a short alias for `--attribute NAME VALUE`. Attribute names
|
|
505
|
+
map directly to custom mail headers: `--x project email2` emits
|
|
506
|
+
`X-Project: email2`; `--x x-task-id abc` emits `X-Task-ID: abc`. Attribute names
|
|
507
|
+
are case-insensitive for validation and duplicate detection.
|
|
508
|
+
|
|
509
|
+
For multiline mail, prefer stdin:
|
|
510
|
+
|
|
511
|
+
```bash
|
|
512
|
+
cat <<'EOF' | kuzymail send \
|
|
513
|
+
--profile zorbax \
|
|
514
|
+
--to quindle@mail.example.invalid \
|
|
515
|
+
--subject "Proposal: namespace cleanup" \
|
|
516
|
+
--x project thecost-accounting \
|
|
517
|
+
--x task-id extid-2026-03 \
|
|
518
|
+
--body-stdin
|
|
519
|
+
Intent: tighten noisy IDs.
|
|
520
|
+
Action requested: review proposed cleanup.
|
|
521
|
+
Why now: the current state is too noisy to trust.
|
|
522
|
+
EOF
|
|
523
|
+
```
|
|
524
|
+
|
|
525
|
+
Multiple recipients:
|
|
526
|
+
|
|
527
|
+
```bash
|
|
528
|
+
kuzymail send \
|
|
529
|
+
--profile zorbax \
|
|
530
|
+
--to quindle@mail.example.invalid \
|
|
531
|
+
--to vornix@mail.example.invalid \
|
|
532
|
+
--subject "Handoff: matcher analysis" \
|
|
533
|
+
--x project thecost-core \
|
|
534
|
+
--x task-id matcher-7 \
|
|
535
|
+
--body "Passing the current state and next recommended step."
|
|
536
|
+
```
|
|
537
|
+
|
|
538
|
+
With CC:
|
|
539
|
+
|
|
540
|
+
```bash
|
|
541
|
+
kuzymail send \
|
|
542
|
+
--profile zorbax \
|
|
543
|
+
--to quindle@mail.example.invalid \
|
|
544
|
+
--cc umbrik@mail.example.invalid \
|
|
545
|
+
--subject "Escalation: external ID policy" \
|
|
546
|
+
--x project thecost-accounting \
|
|
547
|
+
--x task-id extid-escalation-2 \
|
|
548
|
+
--escalation HUMAN_REQUIRED \
|
|
549
|
+
--body "Need a human decision on long-term policy."
|
|
550
|
+
```
|
|
551
|
+
|
|
552
|
+
## 5. Structured Header Contract
|
|
553
|
+
|
|
554
|
+
Attribute semantics:
|
|
555
|
+
|
|
556
|
+
- `--x project email2` -> `X-Project: email2`
|
|
557
|
+
- `--x task-id extid-1` -> `X-Task-ID: extid-1`
|
|
558
|
+
- `--x x-project email2` -> `X-Project: email2`
|
|
559
|
+
- `--x my_important_field yes` -> `X-My-Important-Field: yes`
|
|
560
|
+
|
|
561
|
+
Optional:
|
|
562
|
+
|
|
563
|
+
- `--escalation` -> `X-Escalation`
|
|
564
|
+
- `--header NAME VALUE` -> sets a standard outbound header from a fixed allow-list
|
|
565
|
+
(`Auto-Submitted`, `List-Unsubscribe`, `List-Unsubscribe-Post`). Repeat for
|
|
566
|
+
multiple headers. Kept separate from `--attribute`/`--x` so arbitrary custom
|
|
567
|
+
headers can't be smuggled in through this path. Names are case-insensitive
|
|
568
|
+
and emitted in canonical casing. Duplicate names (including case variants)
|
|
569
|
+
and values containing CR or LF are rejected.
|
|
570
|
+
|
|
571
|
+
If an operator wants `X-Agent-Type`, pass `--x agent-type VALUE` explicitly.
|
|
572
|
+
|
|
573
|
+
To make attributes mandatory or restrict their names for a specific account:
|
|
574
|
+
|
|
575
|
+
```bash
|
|
576
|
+
kuzymail account modify \
|
|
577
|
+
--profile zorbax \
|
|
578
|
+
--account primary \
|
|
579
|
+
--attributes-allowed project \
|
|
580
|
+
--attributes-allowed task-id \
|
|
581
|
+
--attributes-allowed context \
|
|
582
|
+
--attributes-mandatory project
|
|
583
|
+
```
|
|
584
|
+
|
|
585
|
+
To return to free-form optional attributes:
|
|
586
|
+
|
|
587
|
+
```bash
|
|
588
|
+
kuzymail account modify --profile zorbax --account primary --attributes-allow-any --attributes-clear-mandatory
|
|
589
|
+
```
|
|
590
|
+
|
|
591
|
+
Attributes are included in JSON output. They are not for secrets.
|
|
592
|
+
Standard outbound headers are reported separately as `standard_headers` in
|
|
593
|
+
`send` and dry-run JSON, using canonical names and their final values.
|
|
594
|
+
|
|
595
|
+
Use `--dry-run` on `send`, `reply`, and `reply-all` before risky outbound mail.
|
|
596
|
+
It builds the message plan and validates recipients, attributes, attachments,
|
|
597
|
+
and policy without SMTP or sent-copy side effects.
|
|
598
|
+
|
|
599
|
+
External recipients are visible in JSON by default. Accounts can tighten this:
|
|
600
|
+
|
|
601
|
+
```bash
|
|
602
|
+
kuzymail account modify \
|
|
603
|
+
--profile zorbax \
|
|
604
|
+
--account primary \
|
|
605
|
+
--external-recipients-policy require-confirm
|
|
606
|
+
```
|
|
607
|
+
|
|
608
|
+
With `require-confirm`, pass `--allow-external` for an intentional external
|
|
609
|
+
send. With `block`, external recipients are rejected even if
|
|
610
|
+
`--allow-external` is present.
|
|
611
|
+
|
|
612
|
+
Recommended escalation values:
|
|
613
|
+
|
|
614
|
+
- `NONE`
|
|
615
|
+
- `HUMAN_REQUIRED`
|
|
616
|
+
|
|
617
|
+
## 6. Query Prefixes in Notmuch
|
|
618
|
+
|
|
619
|
+
Configured custom query prefixes:
|
|
620
|
+
|
|
621
|
+
- `Escalation:`
|
|
622
|
+
|
|
623
|
+
Examples:
|
|
624
|
+
|
|
625
|
+
```bash
|
|
626
|
+
notmuch --config runtime/profiles/zorbax/accounts/primary/notmuch-config search --sort=newest-first Escalation:HUMAN_REQUIRED
|
|
627
|
+
```
|
|
628
|
+
|
|
629
|
+
## 7. What Send Actually Does
|
|
630
|
+
|
|
631
|
+
When you call `send` or `reply`, the facade:
|
|
632
|
+
|
|
633
|
+
1. builds an RFC822 message
|
|
634
|
+
2. sends it through `msmtp` to local authenticated SMTP submission
|
|
635
|
+
3. archives the same message into local `Sent`
|
|
636
|
+
4. syncs `Sent`
|
|
637
|
+
5. refreshes the notmuch database
|
|
638
|
+
|
|
639
|
+
So your `Sent` view should remain coherent without manual steps.
|
|
640
|
+
It also pays the `notmuch reindex '*'` cost so local index state remains truthful
|
|
641
|
+
after generated sent-copy changes.
|
|
642
|
+
|
|
643
|
+
If `--from` uses a configured sender alias, the login and envelope config still
|
|
644
|
+
come from the account. kuzymail does not create a second profile/runtime just to
|
|
645
|
+
send as an alias.
|
|
646
|
+
|
|
647
|
+
Known addresses are formatted as `Display Name <email>` using local profiles first, then the optional shared registry.
|
|
648
|
+
|
|
649
|
+
`archive` and `delete` are intentionally dry-run by default and only mutate the real mailbox with `--yes`.
|
|
650
|
+
|
|
651
|
+
## 8. Expectations and Boundaries
|
|
652
|
+
|
|
653
|
+
This is a message system and lightweight agent facade, not an execution channel.
|
|
654
|
+
|
|
655
|
+
Do not treat mail as:
|
|
656
|
+
|
|
657
|
+
- shell command transport
|
|
658
|
+
- arbitrary code transport
|
|
659
|
+
- secret exfiltration path
|
|
660
|
+
|
|
661
|
+
Use it for:
|
|
662
|
+
|
|
663
|
+
- handoffs
|
|
664
|
+
- dissent
|
|
665
|
+
- blockers
|
|
666
|
+
- context updates
|
|
667
|
+
- escalation
|
|
668
|
+
|
|
669
|
+
## 9. Debugging
|
|
670
|
+
|
|
671
|
+
If sync fails:
|
|
672
|
+
|
|
673
|
+
```bash
|
|
674
|
+
mbsync -c runtime/profiles/zorbax/accounts/primary/mbsyncrc zorbax-inbox zorbax-sent
|
|
675
|
+
```
|
|
676
|
+
|
|
677
|
+
If the wrapper output feels surprising:
|
|
678
|
+
|
|
679
|
+
```bash
|
|
680
|
+
kuzymail list --profile zorbax --query "tag:inbox" --limit 5
|
|
681
|
+
kuzymail show --profile zorbax --message-id '<message-id>'
|
|
682
|
+
```
|
|
683
|
+
|
|
684
|
+
If search feels wrong:
|
|
685
|
+
|
|
686
|
+
```bash
|
|
687
|
+
notmuch --config runtime/profiles/zorbax/accounts/primary/notmuch-config search '*'
|
|
688
|
+
```
|
|
689
|
+
|
|
690
|
+
If send fails:
|
|
691
|
+
|
|
692
|
+
```bash
|
|
693
|
+
msmtp -C runtime/profiles/zorbax/accounts/primary/msmtprc --serverinfo
|
|
694
|
+
```
|
|
695
|
+
|
|
696
|
+
Use raw mail tools only when needed:
|
|
697
|
+
|
|
698
|
+
- `mbsync`
|
|
699
|
+
- `notmuch`
|
|
700
|
+
- `msmtp`
|