You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
PR #106 landed sub-group 2 of the open-issues roadmap (#70, #96, #97). The #96 work is partial: `Connection::move_messages` guards UIDVALIDITY correctly but cannot populate `MoveResult.new_uid` because `async-imap` does not expose the `[COPYUID uidvalidity src-uids dst-uids]` UIDPLUS response code.
Every `MoveResult` returned by `move_messages` currently has `new_uid: None` and `used_fallback_reason: Some("async_imap_copyuid_unavailable".to_string())` — a stable marker the audit layer / agent can filter on.
`MoveOutcome { results, used_fallback, source_uid_validity, destination_uid_validity }` already surfaces both folder UIDVALIDITY values for audit correlation, so the loss of per-result `new_uid` is bounded.
`ResponseCode::CopyUid(u32 /* uidvalidity /, Vec / src /, Vec / dst */)` exists in `imap-proto 0.16.6` (`types.rs:139`) but `async-imap 0.11.2`'s session methods (`uid_copy`, `uid_mv`) return `Result<()>` and discard response codes.
What this issue tracks
Once `async-imap` exposes the UIDPLUS response code — either via a new session method signature (e.g. `Result`) or via raw-command machinery that cleanly surfaces `Response::Done { code: Option, ... }` — flip `build_results` in `crates/rimap-imap/src/ops/move_message.rs` to:
Parse the `[COPYUID ...]` response code when available.
Populate `MoveResult.new_uid: Some(Uid::new(dst_uid))` for each matched source UID.
Set `used_fallback_reason: None` on results with populated `new_uid`.
Keep the current fallback (`new_uid: None` + `used_fallback_reason: Some("server_no_uidplus")` or similar) for servers that do not advertise UIDPLUS.
Acceptance criteria
When the server advertises UIDPLUS (`has_uidplus`) AND async-imap surfaces the response code, `MoveResult.new_uid` is populated with the mapped destination UID for every moved message. Verified via a Dovecot integration test that checks `new_uid` is `Some(...)` on a simple 3-message MOVE.
When the server does NOT advertise UIDPLUS, `new_uid` stays `None` with `used_fallback_reason: Some("server_no_uidplus".to_string())` (or equivalent).
`Connection::move_messages` signature is unchanged — flip is a behavior change, not an API change.
Upstream: track `async-imap` releases for UIDPLUS response-code support.
Fallback: if async-imap doesn't land the feature in a reasonable timeframe, consider using async-imap's internal `run_command_and_read_response` (or equivalent) to issue `UID COPY` / `UID MOVE` as raw commands and parse the tagged response manually. That's more invasive but removes the external dependency.
Context
PR #106 landed sub-group 2 of the open-issues roadmap (#70, #96, #97). The #96 work is partial: `Connection::move_messages` guards UIDVALIDITY correctly but cannot populate `MoveResult.new_uid` because `async-imap` does not expose the `[COPYUID uidvalidity src-uids dst-uids]` UIDPLUS response code.
What exists today (on `main` after #106 merges)
What this issue tracks
Once `async-imap` exposes the UIDPLUS response code — either via a new session method signature (e.g. `Result`) or via raw-command machinery that cleanly surfaces `Response::Done { code: Option, ... }` — flip `build_results` in `crates/rimap-imap/src/ops/move_message.rs` to:
Acceptance criteria
When the server advertises UIDPLUS (`has_uidplus`) AND async-imap surfaces the response code, `MoveResult.new_uid` is populated with the mapped destination UID for every moved message. Verified via a Dovecot integration test that checks `new_uid` is `Some(...)` on a simple 3-message MOVE.
When the server does NOT advertise UIDPLUS, `new_uid` stays `None` with `used_fallback_reason: Some("server_no_uidplus".to_string())` (or equivalent).
`Connection::move_messages` signature is unchanged — flip is a behavior change, not an API change.
`MoveMessageMeta` (in `rimap-server/src/tools/mailbox/move_message.rs`) surfaces the captured `new_uid` values in the per-result entries automatically; no server-side code change needed beyond what feat: UIDVALIDITY correctness — Option<u32>, MOVE guard, response echo, input check #106 already landed.
Blockers / watch
References
🤖 Generated with Claude Code