Skip to content

Implement store_new_with_flags - #45

Merged
staktrace merged 1 commit into
staktrace:masterfrom
jmibanez:master
May 11, 2026
Merged

Implement store_new_with_flags#45
staktrace merged 1 commit into
staktrace:masterfrom
jmibanez:master

Conversation

@jmibanez

@jmibanez jmibanez commented May 7, 2026

Copy link
Copy Markdown
Contributor

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.

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 staktrace left a comment

Copy link
Copy Markdown
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This looks reasonable, thanks!

@staktrace
staktrace merged commit 2f5bb79 into staktrace:master May 11, 2026
7 checks passed
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>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Support a store_new_with_flags method

2 participants