Implement store_new_with_flags - #45
Merged
Merged
Conversation
Some MDAs such as OfflineIMAP and mbsync need to preserve flags when fetching from an IMAP upstream; e.g. because a server-side mail filter has flagged an email beforehand. Additionally, some MUAs such as mutt, unless configured, will only ever check the new/ directory of a Maildir for new mail. Because of this, if a user of this crate wants to ever support this use case they are forced to work around the crate by reimplementing store() themselves -- it's not safe to just call store_new() then rename the file themselves, as they may race a MUA: the MUA will see the bare file before the rename to add flags and move it to cur themselves. Support this use case by providing a method to store mesages in new/ with flags, and to iterate messages with flags in new/. Fixes staktrace#44.
jmibanez
added a commit
to jmibanez/jma-mail
that referenced
this pull request
May 7, 2026
Switch the `maildir` dep from crates.io 0.6.4 to a git dep on jmibanez/maildir at the SHA matching staktrace/maildir#45's head. The fork carries two changes that crates.io 0.6.4 lacks: 1. `Maildir::store_new_with_flags(data, flags)` -- atomic delivery into new/ with a `:2,<flags>` info suffix in place. Upstream's `store_new` writes a bare `new/<id>`; appending a suffix needs a second `fs::rename`, opening a race window where an MUA can scan new/, see the bare file, and promote it to `cur/<id>:2,S` -- losing any non-Seen flags from server-side filters. 2. Suffix-aware iteration of `new/`. Upstream hardcodes `(filename, "")` for new/ entries on the assumption strict maildir keeps `new/` suffix-free, which breaks DB lookups when those files actually carry a `:2,<flags>` suffix (the shape mbsync, OfflineIMAP, and our own delivery write so flags survive an MUA's first new/ -> cur/ promotion). The fork parses the suffix uniformly in both subdirs. Both behaviors are tracked upstream: Issue: staktrace/maildir#44 PR: staktrace/maildir#45 Pinned by `rev` to PR #45's head (0d6509ae) for build reproducibility. When upstream merges and ships, swap back to a versioned crates.io dep with a one-line Cargo.toml edit -- and delete this commit's whole rationale. This commit changes only the dep source; consumer code in `maildir_ops/` keeps the existing `use maildir::Maildir` imports and the original API call sites. The delivery and scan code that exercises the new APIs follows in subsequent commits, kept separate so reverting this pin once upstream lands is a single-commit revert. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
staktrace
approved these changes
May 11, 2026
staktrace
left a comment
Owner
There was a problem hiding this comment.
This looks reasonable, thanks!
jmibanez
added a commit
to jmibanez/jma-mail
that referenced
this pull request
May 15, 2026
Until now, installing jma required `cargo install --git` against
this repo. No tagged releases existed, so a Rust toolchain was a
hard prerequisite for end users.
Stand up a release pipeline using dist:
- Bump to 0.9.0 as the on-ramp to a future 1.0.
- Add `repository` and `license` to [package] so the crates.io
metadata and the GitHub release page link back correctly.
- dist-workspace.toml lists five build targets:
aarch64/x86_64-apple-darwin, aarch64/x86_64-unknown-linux-gnu,
x86_64-pc-windows-msvc. Installers: shell and powershell.
- .github/workflows/release.yml is generated by `dist generate`,
then hand-patched: `gh release create` gets `--generate-notes`
so GitHub's auto-generated "What's Changed" appends after
dist's artifact table. `dist plan` runs a staleness check on
this file, so dist-workspace.toml sets `allow-dirty = ["ci"]`
to let the hand-edit through. Future `dist generate` runs
will still overwrite the edit.
- .github/release.yml categorizes the auto-generated notes by
PR label. Inert for direct-to-mainline commits but ready for
the day PRs land.
A tag matching v*.*.* on origin/mainline triggers the workflow.
The Windows target needed one portability fix: `read_rss_bytes`
in src/profile.rs is gated on `cfg(unix)` because `getrusage` is
POSIX-only and the `libc` crate doesn't expose it on Windows. The
Windows shim returns 0, matching the function's pre-existing
"returns 0 when it can't query" contract.
Move the maildir git pin from the jmibanez/maildir fork to
staktrace/maildir upstream now that staktrace/maildir#45 has
merged. No crates.io release has shipped yet, so we still pin to
a commit rather than a versioned dep -- but the fork is no longer
load-bearing.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Some MDAs such as OfflineIMAP and mbsync need to preserve flags when fetching from an IMAP upstream; e.g. because a server-side mail filter has flagged an email beforehand. Additionally, some MUAs such as mutt, unless configured, will only ever check the new/ directory of a Maildir for new mail.
Because of this, if a user of this crate wants to ever support this use case they are forced to work around the crate by reimplementing store() themselves -- it's not safe to just call store_new() then rename the file themselves, as they may race a MUA: the MUA will see the bare file before the rename to add flags and move it to cur themselves.
Support this use case by providing a method to store mesages in new/ with flags, and to iterate messages with flags in new/.
Fixes #44.