fix(api): make OTP email sender configurable via env#69
Conversation
The OTP sender was hardcoded to no-reply@txio-backend.com. Brevo only sends from verified senders, so unless a deployment happens to own and verify that exact domain, every OTP send fails (breaking registration, login OTP, and password reset). Read EMAIL_FROM / EMAIL_FROM_NAME from the environment, defaulting to the previous values, and document them in .env.example. Closes #56
|
The latest updates on your projects. Learn more about Vercel for GitHub.
|
📝 WalkthroughWalkthroughThe PR externalizes the hardcoded OTP email sender identity to environment variables. ChangesEmail sender configuration
Estimated code review effort🎯 2 (Simple) | ⏱️ ~8 minutes Poem
🚥 Pre-merge checks | ✅ 4 | ❌ 1❌ Failed checks (1 warning)
✅ Passed checks (4 passed)
✏️ Tip: You can configure your own custom pre-merge checks in the settings. ✨ Finishing Touches📝 Generate docstrings
🧪 Generate unit tests (beta)
Comment |
There was a problem hiding this comment.
Actionable comments posted: 2
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.
Inline comments:
In @.env.example:
- Line 10: The .env.example value for EMAIL_FROM_NAME contains whitespace and
should be quoted to avoid parsing ambiguity; update the EMAIL_FROM_NAME entry to
wrap its value in quotes (e.g., change the EMAIL_FROM_NAME line to use "txio
Team") so dotenv/shell loaders parse it consistently and preserve the space.
In `@backend/api/src/services/email_service.rs`:
- Around line 22-25: The current from_email and from_name initialization only
falls back when the env vars are missing; update their creation in
email_service.rs to treat empty or whitespace-only values as missing by trimming
and checking emptiness before using them. Replace the
std::env::var(...).unwrap_or_else(...) pattern for from_email and from_name with
logic that first obtains the env var (e.g., std::env::var(...).ok()), trims and
verifies it's not empty (or whitespace), and only then uses it; otherwise use
the existing defaults ("no-reply@txio-backend.com" and "txio Team") so
EMAIL_FROM and EMAIL_FROM_NAME set to empty strings do not become invalid
senders.
🪄 Autofix (Beta)
Fix all unresolved CodeRabbit comments on this PR:
- Push a commit to this branch (recommended)
- Create a new PR with the fixes
ℹ️ Review info
⚙️ Run configuration
Configuration used: defaults
Review profile: CHILL
Plan: Pro Plus
Run ID: 014b79e6-fa1b-40ab-9e97-06761d257492
📒 Files selected for processing (2)
.env.examplebackend/api/src/services/email_service.rs
| BREVO_API_KEY=your_brevo_api_key_here | ||
| # Sender for OTP emails. Must be a verified sender/domain in your Brevo account. | ||
| EMAIL_FROM=no-reply@txio-backend.com | ||
| EMAIL_FROM_NAME=txio Team |
There was a problem hiding this comment.
Quote EMAIL_FROM_NAME to avoid parser ambiguity.
txio Team contains whitespace; quoting it avoids inconsistent parsing across dotenv loaders/shell-based setups.
Suggested patch
-EMAIL_FROM_NAME=txio Team
+EMAIL_FROM_NAME="txio Team"📝 Committable suggestion
‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.
| EMAIL_FROM_NAME=txio Team | |
| EMAIL_FROM_NAME="txio Team" |
🧰 Tools
🪛 dotenv-linter (4.0.0)
[warning] 10-10: [UnorderedKey] The EMAIL_FROM_NAME key should go before the JWT_SECRET key
(UnorderedKey)
[warning] 10-10: [ValueWithoutQuotes] This value needs to be surrounded in quotes
(ValueWithoutQuotes)
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.
In @.env.example at line 10, The .env.example value for EMAIL_FROM_NAME contains
whitespace and should be quoted to avoid parsing ambiguity; update the
EMAIL_FROM_NAME entry to wrap its value in quotes (e.g., change the
EMAIL_FROM_NAME line to use "txio Team") so dotenv/shell loaders parse it
consistently and preserve the space.
Source: Linters/SAST tools
| let from_email = std::env::var("EMAIL_FROM") | ||
| .unwrap_or_else(|_| "no-reply@txio-backend.com".to_string()); | ||
| let from_name = | ||
| std::env::var("EMAIL_FROM_NAME").unwrap_or_else(|_| "txio Team".to_string()); |
There was a problem hiding this comment.
Handle empty env values, not just missing ones.
Current fallback only runs when the variable is absent. If EMAIL_FROM/EMAIL_FROM_NAME are set to empty (or whitespace), invalid sender data is sent and OTP delivery can still fail.
Suggested patch
- let from_email = std::env::var("EMAIL_FROM")
- .unwrap_or_else(|_| "no-reply@txio-backend.com".to_string());
- let from_name =
- std::env::var("EMAIL_FROM_NAME").unwrap_or_else(|_| "txio Team".to_string());
+ let from_email = std::env::var("EMAIL_FROM")
+ .ok()
+ .map(|v| v.trim().to_string())
+ .filter(|v| !v.is_empty())
+ .unwrap_or_else(|| "no-reply@txio-backend.com".to_string());
+ let from_name = std::env::var("EMAIL_FROM_NAME")
+ .ok()
+ .map(|v| v.trim().to_string())
+ .filter(|v| !v.is_empty())
+ .unwrap_or_else(|| "txio Team".to_string());📝 Committable suggestion
‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.
| let from_email = std::env::var("EMAIL_FROM") | |
| .unwrap_or_else(|_| "no-reply@txio-backend.com".to_string()); | |
| let from_name = | |
| std::env::var("EMAIL_FROM_NAME").unwrap_or_else(|_| "txio Team".to_string()); | |
| let from_email = std::env::var("EMAIL_FROM") | |
| .ok() | |
| .map(|v| v.trim().to_string()) | |
| .filter(|v| !v.is_empty()) | |
| .unwrap_or_else(|| "no-reply@txio-backend.com".to_string()); | |
| let from_name = std::env::var("EMAIL_FROM_NAME") | |
| .ok() | |
| .map(|v| v.trim().to_string()) | |
| .filter(|v| !v.is_empty()) | |
| .unwrap_or_else(|| "txio Team".to_string()); |
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.
In `@backend/api/src/services/email_service.rs` around lines 22 - 25, The current
from_email and from_name initialization only falls back when the env vars are
missing; update their creation in email_service.rs to treat empty or
whitespace-only values as missing by trimming and checking emptiness before
using them. Replace the std::env::var(...).unwrap_or_else(...) pattern for
from_email and from_name with logic that first obtains the env var (e.g.,
std::env::var(...).ok()), trims and verifies it's not empty (or whitespace), and
only then uses it; otherwise use the existing defaults
("no-reply@txio-backend.com" and "txio Team") so EMAIL_FROM and EMAIL_FROM_NAME
set to empty strings do not become invalid senders.
Summary
The OTP email
senderwas hardcoded tono-reply@txio-backend.com. Brevo only sends from verified senders/domains, so unless a deployment owns and verifies that exact domain, every OTP send is rejected — breaking registration confirmation, login OTP, and password reset, surfacing only as a genericExternalServiceerror.Changes
EMAIL_FROMandEMAIL_FROM_NAMEfrom the environment, defaulting to the previous values (no behavior change when unset).Testing
cargo check -p txio-apipasses.Closes #56
Summary by CodeRabbit