Skip to content

feat: staging_mode that logs email instead of sending it#152

Merged
rubenhensen merged 1 commit into
mainfrom
feat/staging-mail-mode
May 13, 2026
Merged

feat: staging_mode that logs email instead of sending it#152
rubenhensen merged 1 commit into
mainfrom
feat/staging-mail-mode

Conversation

@dobby-coder
Copy link
Copy Markdown
Contributor

@dobby-coder dobby-coder Bot commented May 13, 2026

Adds a staging_mode boolean to CryptifyConfig. When set, send_email skips SMTP entirely and logs a single [STAGING] Email NOT sent ... line with the full intended recipients, sender, sender_attributes, expiry, download URL, and uuid. Returns Ok so the upload finalize flow completes normally.

Closes encryption4all/postguard#174

Changes

  • conf/config.dev.toml: documented (commented) staging_mode = true option.
  • src/config.rs: new staging_mode field, defaults to false. Test-only constructor CryptifyConfig::for_test.
  • src/email.rs: short-circuit in send_email plus staging_log_email helper.
  • New test staging_mode_skips_smtp_and_returns_summary (passes the staging_mode_skips_smtp_and_returns_summary happy path; SMTP path is unchanged).

How to enable in staging deploys

Add to the active config file (conf/config.toml):

staging_mode = true

Then tail the cryptify container logs after a finalize call:

[STAGING] Email NOT sent (staging_mode=true). Would have notified recipients=["alice@example.com", "bob@example.com"] from sender=... attributes=[orgName=Acme, phone=+31123] lang=EN expires=1700000000 confirm=true notify_recipients=true download_url=https://staging.example.com/download?uuid=... uuid=...

Reviewer quickstart

git fetch origin && git checkout feat/staging-mail-mode && cargo test

When staging_mode = true, finalize logs a [STAGING] line containing
recipients, sender, sender_attributes, expiry, download URL, and uuid
instead of contacting SMTP. Returns Ok so the upload flow completes.

Refs encryption4all/postguard#174.
Copy link
Copy Markdown
Contributor Author

@dobby-coder dobby-coder Bot left a comment

Choose a reason for hiding this comment

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

Self-review

This agent opened this PR, so GitHub blocks a formal APPROVE from this account. Posting a review-style comment instead — final approval needs to come from @rubenhensen.

The change is small, scoped, defaults safe (staging_mode = false), has direct test coverage, and CI is fully green (fmt/clippy/tests + Docker amd64/arm64). Ready for human review and, in this agent's read, ready to merge.

What looks good

  • Single short-circuit at the top of send_email; SMTP path is untouched, so production behavior is bit-identical when the flag is off.
  • New field is Option<bool> in RawCryptifyConfig with .unwrap_or(false) — existing config.toml files keep working without changes.
  • CryptifyConfig::for_test is gated on #[cfg(test)], so it can't leak into prod builds.
  • Test asserts the structural bits an operator would grep for ([STAGING] prefix, recipient addresses, sender, attributes, uuid, download URL).
  • Log line uses log::info! and returns the same summary string, so it surfaces in both container logs and the finalize response.

Minor (non-blocking) observations

  1. Recipient-level fidelity. The real flow sends one email per recipient (with a per-recipient recipient= query param on the download URL) plus an optional sender confirmation. The staging log collapses that into a single line with all recipients and a download URL that carries only uuid=. Fine for "did the flow fire", but a small loop emitting one [STAGING] line per recipient (mirroring the SMTP loop) would be a more faithful reproduction if a future debug session needs per-recipient URLs. Not required now.
  2. notify_recipients=false / confirm=false. In real mode with both off, zero emails are sent. The staging summary still prints recipients/sender. The notify_recipients=… and confirm=… fields in the summary disambiguate it — flagging just so it's intentional.
  3. mail_content is omitted. Probably correct (size/PII), but worth a one-line comment so a future reader doesn't think it's an oversight.

None of those block merge. Once merged, set staging_mode = true in the staging config.toml and restart the cryptify container (per the bind-mount restart convention); finalize calls will then emit [STAGING] Email NOT sent ... lines as designed.

Refs encryption4all/postguard#174.

@dobby-coder
Copy link
Copy Markdown
Contributor Author

dobby-coder Bot commented May 13, 2026

Rule compliance pass: updated the PR body to use Closes encryption4all/postguard#174 instead of Refs ... so the linked issue auto-closes when this merges (per the pr-close-issue-keywords rule — Refs is a soft mention and would have left the tracking issue orphaned). No code changes needed; everything else checked out (conventional title, reviewer assigned, ready-not-draft, tests added and passing locally, cargo fmt --check clean).

Copy link
Copy Markdown
Contributor Author

@dobby-coder dobby-coder Bot left a comment

Choose a reason for hiding this comment

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

Re-review (cycle 0 of pipeline). GitHub blocks a formal APPROVE because this agent is the PR author — posting as a review comment, but the verdict is ready to merge pending @rubenhensen.

Reviewed the diff, ran cargo test locally (58 passing), and confirmed CI is green (fmt/clippy/test + Docker amd64/arm64).

What looks good:

  • Short-circuit at the top of send_email is the right seam; SMTP path is untouched.
  • staging_mode defaults to false via Option<bool>::unwrap_or(false), so existing deployments are unaffected.
  • CryptifyConfig::for_test is #[cfg(test)]-gated.
  • The test covers the structural fields an operator would grep ([STAGING] prefix, both recipients, sender, attributes, uuid, parsed download URL).
  • Url::parse(...).and_then(...).join(...) falls back to a labelled string instead of panicking on a malformed server_url.

Non-blocking observations (already raised in the earlier self-review; recording here for the pipeline trace):

  1. Staging log collapses per-recipient sends into one line; faithful enough for a smoke check.
  2. notify_recipients=false / confirm=false will still print the recipients/sender — the explicit notify_recipients= / confirm= fields in the summary disambiguate.
  3. mail_content is intentionally omitted (size/PII).

Ready to merge.

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.

Staging version of emailing

1 participant