Wraps IMAP/JMAP folder and message sync in tracing spans keyed by account/folder, logging completion counts (fetched/oversized/skipped) at INFO.
SMTP send attempts and their outcome are logged with the recipient COUNT only, never addresses.
Every destructive IMAP mutation (MOVE, DELETE + UID-scoped EXPUNGE) is logged with its UID set and the UIDVALIDITY guard's pass/fail result before the command reaches the server, so a log exists even if the guard then refuses the op. JMAP mirrors the pre-log for its Email/set move/destroy, keyed by the JMAP object id.
The IMAP UIDVALIDITY fail-closed guard is unchanged in behavior (restructured only so the pass/fail boolean is available for logging before the early return); all pre-existing UIDVALIDITY/UIDPLUS/MOVE-capability tests pass unmodified.
No proto changes (this is issue #361 / OBS-5, mail protocol observability only).
#[tracing::instrument(..., err)] on sync_folder_messages_batched and MailBackend::sync_folders.
Completion logs: imap folder sync complete (fetched/oversized/skipped) and imap folder list sync complete (folders count).
Destructive pre-log in apply_mutation_with_session: MOVE at info!, DELETE at warn!, both carrying op, folder_id, uid_set, uidvalidity_guard_passed before the guard's early return.
JMAP (jmap.rs)
Same #[tracing::instrument(..., err)] + completion-count pattern on sync_folders/sync_messages.
apply_mutation pre-logs destructive MOVE/DELETE keyed by the JMAP object id (no UIDVALIDITY-equivalent to guard).
SMTP (smtp.rs)
send_message/send_email_with_transport log smtp send attempt before dispatch, then smtp send succeeded or smtp send failed with recipient_count (1, +1 for a non-blank cc) -- never the address.
Error-context (scoped out)
Did not do a broad #[source]/#[from] refactor of MailError's String-folding variants -- that's a pervasive change across both imap.rs and jmap.rs; flagging as a follow-up story rather than doing it here.
Test-infrastructure note
Initial hand-rolled tracing::Subscriber-per-test (mirroring nuncio-filter/src/webhook.rs's pattern) was flaky under cargo test's parallel harness: tracing-core caches a callsite's Interest process-wide on first hit, and several pre-existing tests hit the exact same log call sites with no subscriber installed, permanently poisoning the cache to "never" for that callsite before my thread-local subscriber could register. Switched to the tracing-test crate (added as a nuncio-mail dev-dependency; explicitly an allowed option in the story brief) which installs one process-wide subscriber via Once and filters by thread name, avoiding the race. Verified stable across 10 consecutive --test-threads=8 runs.
New tests: destructive IMAP MOVE/DELETE pre-logging (including the guard-failure path where zero commands reach the server), IMAP sync completion counts, SMTP send attempt/success/failure with recipient-count-only + no-address assertion
Grepped the diff: no message bodies, subjects, sender/recipient addresses, credentials, or auth headers in any tracing macro added
## Summary
- Wraps IMAP/JMAP folder and message sync in tracing spans keyed by account/folder, logging completion counts (fetched/oversized/skipped) at INFO.
- SMTP send attempts and their outcome are logged with the recipient COUNT only, never addresses.
- Every destructive IMAP mutation (MOVE, DELETE + UID-scoped EXPUNGE) is logged with its UID set and the UIDVALIDITY guard's pass/fail result **before** the command reaches the server, so a log exists even if the guard then refuses the op. JMAP mirrors the pre-log for its `Email/set` move/destroy, keyed by the JMAP object id.
- The IMAP UIDVALIDITY fail-closed guard is unchanged in behavior (restructured only so the pass/fail boolean is available for logging before the early return); all pre-existing UIDVALIDITY/UIDPLUS/MOVE-capability tests pass unmodified.
- No proto changes (this is issue #361 / OBS-5, mail protocol observability only).
Refs #361
## Details
### IMAP (`imap.rs`)
- `#[tracing::instrument(..., err)]` on `sync_folder_messages_batched` and `MailBackend::sync_folders`.
- Completion logs: `imap folder sync complete` (fetched/oversized/skipped) and `imap folder list sync complete` (folders count).
- Destructive pre-log in `apply_mutation_with_session`: MOVE at `info!`, DELETE at `warn!`, both carrying `op`, `folder_id`, `uid_set`, `uidvalidity_guard_passed` before the guard's early return.
### JMAP (`jmap.rs`)
- Same `#[tracing::instrument(..., err)]` + completion-count pattern on `sync_folders`/`sync_messages`.
- `apply_mutation` pre-logs destructive MOVE/DELETE keyed by the JMAP object id (no UIDVALIDITY-equivalent to guard).
### SMTP (`smtp.rs`)
- `send_message`/`send_email_with_transport` log `smtp send attempt` before dispatch, then `smtp send succeeded` or `smtp send failed` with `recipient_count` (1, +1 for a non-blank `cc`) -- never the address.
### Error-context (scoped out)
Did not do a broad `#[source]`/`#[from]` refactor of `MailError`'s `String`-folding variants -- that's a pervasive change across both `imap.rs` and `jmap.rs`; flagging as a follow-up story rather than doing it here.
### Test-infrastructure note
Initial hand-rolled `tracing::Subscriber`-per-test (mirroring `nuncio-filter/src/webhook.rs`'s pattern) was flaky under `cargo test`'s parallel harness: `tracing-core` caches a callsite's `Interest` process-wide on first hit, and several pre-existing tests hit the exact same log call sites with no subscriber installed, permanently poisoning the cache to "never" for that callsite before my thread-local subscriber could register. Switched to the `tracing-test` crate (added as a `nuncio-mail` dev-dependency; explicitly an allowed option in the story brief) which installs one process-wide subscriber via `Once` and filters by thread name, avoiding the race. Verified stable across 10 consecutive `--test-threads=8` runs.
## Test plan
- [x] `cargo fmt --all -- --check` -- clean
- [x] `cargo check-all` (clippy `--all-targets --workspace -D warnings`) -- clean, zero warnings
- [x] `cargo test-all` -- all green, 0 ignored (workspace-wide; `nuncio-mail`: 74 tests)
- [x] New tests: destructive IMAP MOVE/DELETE pre-logging (including the guard-failure path where zero commands reach the server), IMAP sync completion counts, SMTP send attempt/success/failure with recipient-count-only + no-address assertion
- [x] Grepped the diff: no message bodies, subjects, sender/recipient addresses, credentials, or auth headers in any `tracing` macro added
Blocking a user prevents them from interacting with repositories, such as opening or commenting on pull requests or issues. Learn more about blocking a user.
Summary
Email/setmove/destroy, keyed by the JMAP object id.Refs #361
Details
IMAP (
imap.rs)#[tracing::instrument(..., err)]onsync_folder_messages_batchedandMailBackend::sync_folders.imap folder sync complete(fetched/oversized/skipped) andimap folder list sync complete(folders count).apply_mutation_with_session: MOVE atinfo!, DELETE atwarn!, both carryingop,folder_id,uid_set,uidvalidity_guard_passedbefore the guard's early return.JMAP (
jmap.rs)#[tracing::instrument(..., err)]+ completion-count pattern onsync_folders/sync_messages.apply_mutationpre-logs destructive MOVE/DELETE keyed by the JMAP object id (no UIDVALIDITY-equivalent to guard).SMTP (
smtp.rs)send_message/send_email_with_transportlogsmtp send attemptbefore dispatch, thensmtp send succeededorsmtp send failedwithrecipient_count(1, +1 for a non-blankcc) -- never the address.Error-context (scoped out)
Did not do a broad
#[source]/#[from]refactor ofMailError'sString-folding variants -- that's a pervasive change across bothimap.rsandjmap.rs; flagging as a follow-up story rather than doing it here.Test-infrastructure note
Initial hand-rolled
tracing::Subscriber-per-test (mirroringnuncio-filter/src/webhook.rs's pattern) was flaky undercargo test's parallel harness:tracing-corecaches a callsite'sInterestprocess-wide on first hit, and several pre-existing tests hit the exact same log call sites with no subscriber installed, permanently poisoning the cache to "never" for that callsite before my thread-local subscriber could register. Switched to thetracing-testcrate (added as anuncio-maildev-dependency; explicitly an allowed option in the story brief) which installs one process-wide subscriber viaOnceand filters by thread name, avoiding the race. Verified stable across 10 consecutive--test-threads=8runs.Test plan
cargo fmt --all -- --check-- cleancargo check-all(clippy--all-targets --workspace -D warnings) -- clean, zero warningscargo test-all-- all green, 0 ignored (workspace-wide;nuncio-mail: 74 tests)tracingmacro added