March 26, 2026
3 pull requests merged across 2 repos
bahdotsh/blogr
- Add
POST /newsletters/sendendpoint to compose a custom newsletter from markdown content and send it to all approved subscribers (with optional tag filtering) - Add
POST /newsletters/previewendpoint to compose and return rendered HTML/text preview without sending - Both endpoints are protected behind API key auth, validate inputs, and use the existing queue-based sender with rate limiting and crash recovery
Test plan
-
cargo test— all 103 tests pass -
cargo clippy— no warnings - Verify
POST /newsletters/previewreturns composed HTML/text for valid subject + markdown content - Verify
POST /newsletters/sendcomposes and delivers to approved subscribers - Verify empty subject/content returns 400
- Verify unauthenticated requests return 401
- Verify optional
tagfield filters recipient list
- Startup cleanup: Wire up existing but uncalled
cleanup_expired_tokens(),cleanup_completed_send_queue(), andcleanup_old_send_recipients(90)onNewsletterManagerinitialization to prevent unbounded database growth - API rate limiting: Add sliding-window rate limiter middleware (configurable via
ApiConfig.rate_limit) that returns429 Too Many Requestswhen exceeded - Status transition fixes: Approving a subscriber now clears
declined_at, declining clearsapproved_at— both in the database layer (update_subscriber_status_by_email) and the API layer (update_subscriber) - Email validation hardening: Add RFC 5321 character validation for local part and per-label domain validation (max 63 chars, no leading/trailing hyphens, alphanumeric + hyphen only)
- Tag validation: New
is_valid_tag()withMAX_TAG_LENGTH(100) andMAX_TAGS_PER_SUBSCRIBER(50) enforced at database (add_tag,set_tags) and API (update_subscriber_tags) layers - 10 new tests covering email validation edge cases, status transitions, and tag validation (89 total passing)
Test plan
-
cargo test -p blogr-cli— 89 tests pass -
cargo clippy --all-targets --all-features -- -D warnings— clean -
cargo fmt --all -- --check— clean
rust-lang/this-week-in-rust
Community Links