Save a copy of sent mail to the Sent folder - #5
Merged
Conversation
SMTP delivery never files a copy in the sender's Sent mailbox — that lives on IMAP and the client must APPEND it. `send` did neither, so sent mail vanished from Sent on every provider that doesn't auto-file (i.e. most of them). After a successful send, file an identical copy (the exact RFC822 bytes, flagged \Seen) into the Sent folder via IMAP APPEND. Folder precedence: --sent-folder > MAILCLI_SENT_FOLDER > \Sent special-use auto-discovery (RFC 6154) > the literal "Sent". Best-effort by design: the mail is already delivered when APPEND runs, so a failed copy warns and still exits 0 — a non-zero exit would invite a retry that double-sends. Default on; --no-save-sent / MAILCLI_SAVE_SENT=0 opt out; a one-line note (not a failure) when IMAP isn't configured. - config.rs: Env::sent_folder() (Option) + save_sent() (Result<bool>) - imap.rs: append_to_sent() + discover_sent() (\Sent special-use) - smtp.rs: formatted() exposes the sent bytes (single source of truth) - main.rs: --sent-folder / --no-save-sent; best-effort save_to_sent() - tests: config unit tests + tests/sent_integration.rs (GreenMail, MAILCLI_IT=1) - docs+skill synced (install-skill output byte-identical); CHANGELOG Co-authored by PeakBot!
The prior integration tests self-skip without MAILCLI_IT=1 and CI never set it, so the IMAP/SMTP-backed tests were dead weight there. Fix both: - tests/send_e2e.rs: a real send→INBOX+Sent loop. Builds the message with mail-cli's real smtp::build, takes the real smtp::formatted bytes, delivers over GreenMail, then files the copy with mail-cli's real imap::append_to_sent and asserts it lands in Sent flagged \Seen. Only the encrypted transport hop is substituted: mail-cli's SMTP TLS (lettre) trusts bundled webpki roots and cannot validate GreenMail's self-signed cert, and there is no accept-invalid-certs escape hatch by design; the delivered payload is byte-identical. Also a binary smoke test asserting the new flags parse and that an unreachable SMTP host is a fatal error. - .github/workflows/ci.yml: new `integration (GreenMail)` job runs search_integration + sent_integration + send_e2e with MAILCLI_IT=1 against a GreenMail service container (waits for the ports first, serialized with --test-threads=1). - lib.rs exposes `smtp` for the e2e test; docs/CHANGELOG updated. Co-authored by PeakBot!
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.
Problem
mail-cli sendonly relays the message over SMTP — it neverAPPENDs a copyinto the sender's Sent mailbox. SMTP delivery and the IMAP Sent folder are
separate protocols; the client is responsible for filing the copy. Gmail
auto-appends (so it "works" there), but most providers don't, so sent mail left
no trace in Sent.
Fix
After a successful send, file an identical copy (the exact RFC822 bytes, flagged
\Seen) into the Sent folder via IMAPAPPEND. Folder precedence:--sent-folder>MAILCLI_SENT_FOLDER>\Sentspecial-use auto-discovery(RFC 6154) > the literal
Sent.Design
APPENDruns, so a failed copy prints a
warning:and still exits0. A non-zero exitwould invite a retry that double-sends. If IMAP isn't configured, saving is
skipped with a one-line
note:(not silent — a silent skip looks like the verybug), silenceable via
MAILCLI_SAVE_SENT=0.--no-save-sent/MAILCLI_SAVE_SENT=0.config.rs, IMAP wire calls inimap.rs,runtime choices as flags. No new required env vars → existing setups unchanged.
ZoE review cuts (before coding)
--jsononsend(send had no JSON today; unrequested → YAGNI).--save-sentforce flag; collapsed to a single bool.Changes
config.rs:Env::sent_folder()(Option) +save_sent()(Result)imap.rs:append_to_sent()+discover_sent()(\Sentspecial-use)smtp.rs:formatted()exposes the sent bytes (single source of truth)main.rs:--sent-folder/--no-save-sent; best-effortsave_to_sent()Cargo.toml:imap-protodirect dep (pinned) to nameNameAttribute::SentTests
tests/sent_integration.rswrittenand confirmed red before implementation.
sent_folder/save_sentresolution matrix (38 lib + 33 bin pass).MAILCLI_IT=1): the copy lands in Sent flagged\Seen;discovery selects a valid mailbox. Verified passing against a live server.
cargo clippy --all-targetsandcargo fmt --checkclean.Docs / skill
bundled skill (SKILL.md + reference.md + evals.json,
+eval 8) updated.install-skill --forceoutput verified byte-identical toskill/.[Unreleased]entry (minor, additive).Co-authored by PeakBot!