Fix some issues 11

This commit is contained in:
2026-01-26 09:48:32 +01:00
parent a32a90de71
commit 6c50a78dc8
3 changed files with 137 additions and 6 deletions

View File

@@ -868,10 +868,11 @@ email_open_rate = Gauge(
**Email (SMTP) Configuration:** **Email (SMTP) Configuration:**
- `SMTP_HOST` - SMTP server host - `SMTP_HOST` - SMTP server host
- `SMTP_PORT` - SMTP server port (default: 587) - `SMTP_PORT` - SMTP server port (default: 587)
- `SMTP_USERNAME` - SMTP username - `SMTP_USERNAME` - SMTP username (optional for trusted relay)
- `SMTP_PASSWORD` - SMTP password - `SMTP_PASSWORD` - SMTP password (optional for trusted relay)
- `SMTP_FROM_ADDRESS` - From email address - `SMTP_FROM_ADDRESS` - From email address
- `SMTP_USE_TLS` - Enable TLS (default: true) - `SMTP_USE_TLS` - Enable TLS (default: true)
- `SMTP_REQUIRE_AUTH` - Require SMTP authentication (default: false for trusted relay)
**Twilio Configuration:** **Twilio Configuration:**
- `TWILIO_ACCOUNT_SID` - Twilio account SID - `TWILIO_ACCOUNT_SID` - Twilio account SID
@@ -890,6 +891,86 @@ email_open_rate = Gauge(
- `SMS_COST_PER_MESSAGE` - Cost per SMS (default: 0.08 EUR) - `SMS_COST_PER_MESSAGE` - Cost per SMS (default: 0.08 EUR)
- `EMAIL_COST_PER_MESSAGE` - Cost per email (default: 0.001 EUR) - `EMAIL_COST_PER_MESSAGE` - Cost per email (default: 0.001 EUR)
## Mailu Integration
The notification service is designed to work seamlessly with Mailu email servers, especially for internal bakery communications.
### Internal Email Delivery (Recommended)
When sending emails to addresses within the same Mailu domain (e.g., `user@your-bakery.com`), Mailu handles these as internal messages:
- **No SMTP authentication required** - Mailu trusts internal subnet connections
- **Direct inbox delivery** - Messages stay within Mailu's internal mail store
- **Faster delivery** - No external SMTP relay needed
- **Better reliability** - No dependency on external email providers
### Configuration for Mailu
```bash
# Mailu internal configuration (recommended for bakery communications)
export SMTP_HOST=mailu.your-domain.com # or mailu.internal if using internal DNS
export SMTP_PORT=587 # Standard submission port
export SMTP_REQUIRE_AUTH=false # No authentication needed for internal relay
export DEFAULT_FROM_EMAIL=noreply@your-bakery.com
# Optional: If using Mailu's webmail interface
export SMTP_PORT=25 # Alternative: use port 25 for internal relay
```
### Mailu Subnet Trust Configuration
For Mailu to accept unauthenticated connections from the notification service:
1. **Configure Mailu's relay networks** in `mailu.env`:
```ini
# Add your Kubernetes service subnet to trusted networks
RELAYNETS=10.0.0.0/8 172.16.0.0/12 192.168.0.0/16
```
2. **Ensure DNS resolution** works between services:
```bash
# From notification service pod, test Mailu connectivity
nslookup mailu.your-domain.com
telnet mailu.your-domain.com 587
```
3. **Verify internal delivery** with Mailu logs:
```bash
# Check Mailu container logs for internal message processing
kubectl logs -f mailu-pod-name | grep "internal delivery"
```
## Trusted Relay Configuration
The notification service supports both authenticated SMTP and trusted relay modes:
### Trusted Relay Mode (Default)
For internal Mailu servers or other trusted SMTP relays that don't require authentication:
```bash
# No authentication - trusted relay mode (default)
export SMTP_HOST=mailu.example.com
export SMTP_PORT=587
export SMTP_REQUIRE_AUTH=false # Explicitly disable auth (default is false)
# SMTP_USERNAME and SMTP_PASSWORD can be empty
```
### Authenticated SMTP Mode
For external SMTP services like SendGrid, Amazon SES, or Gmail:
```bash
# With authentication - external SMTP services
export SMTP_HOST=smtp.sendgrid.net
export SMTP_PORT=587
export SMTP_USERNAME=apikey
export SMTP_PASSWORD=your_sendgrid_api_key
export SMTP_REQUIRE_AUTH=true # Explicitly enable auth
```
The service automatically detects the configuration:
- If `SMTP_REQUIRE_AUTH=false` (default), authentication is skipped
- If `SMTP_REQUIRE_AUTH=true` but credentials are missing, it will fail with clear error
- If credentials are provided but `SMTP_REQUIRE_AUTH=false`, it will still skip authentication
## Development Setup ## Development Setup
### Prerequisites ### Prerequisites
@@ -901,6 +982,8 @@ email_open_rate = Gauge(
- Twilio account (for WhatsApp/SMS) - Twilio account (for WhatsApp/SMS)
### Local Development ### Local Development
#### With Mailu (Recommended for Bakery-IA)
```bash ```bash
cd services/notification cd services/notification
python -m venv venv python -m venv venv
@@ -911,9 +994,43 @@ pip install -r requirements.txt
export DATABASE_URL=postgresql://user:pass@localhost:5432/notification export DATABASE_URL=postgresql://user:pass@localhost:5432/notification
export REDIS_URL=redis://localhost:6379/0 export REDIS_URL=redis://localhost:6379/0
export RABBITMQ_URL=amqp://guest:guest@localhost:5672/ export RABBITMQ_URL=amqp://guest:guest@localhost:5672/
# Mailu configuration (internal bakery communications)
export SMTP_HOST=mailu.bakery-ia.local # Internal Mailu service
export SMTP_PORT=587 # Submission port
export SMTP_REQUIRE_AUTH=false # No auth needed - Mailu subnet trust
export DEFAULT_FROM_EMAIL=noreply@bakeryforecast.es
# Optional: For testing external emails
export ENABLE_EMAIL_NOTIFICATIONS=true
export TWILIO_ACCOUNT_SID=your_twilio_sid
export TWILIO_AUTH_TOKEN=your_twilio_token
alembic upgrade head
python main.py
```
#### With External SMTP (SendGrid, Gmail, etc.)
```bash
cd services/notification
python -m venv venv
source venv/bin/activate
pip install -r requirements.txt
export DATABASE_URL=postgresql://user:pass@localhost:5432/notification
export REDIS_URL=redis://localhost:6379/0
export RABBITMQ_URL=amqp://guest:guest@localhost:5672/
# External SMTP configuration (SendGrid example)
export SMTP_HOST=smtp.sendgrid.net export SMTP_HOST=smtp.sendgrid.net
export SMTP_PORT=587
export SMTP_USERNAME=apikey export SMTP_USERNAME=apikey
export SMTP_PASSWORD=your_sendgrid_api_key export SMTP_PASSWORD=your_sendgrid_api_key
export SMTP_REQUIRE_AUTH=true # Explicit authentication required
export DEFAULT_FROM_EMAIL=noreply@yourdomain.com
export TWILIO_ACCOUNT_SID=your_twilio_sid export TWILIO_ACCOUNT_SID=your_twilio_sid
export TWILIO_AUTH_TOKEN=your_twilio_token export TWILIO_AUTH_TOKEN=your_twilio_token

View File

@@ -47,6 +47,7 @@ class NotificationSettings(BaseServiceSettings):
SMTP_PASSWORD: str = os.getenv("SMTP_PASSWORD", "") SMTP_PASSWORD: str = os.getenv("SMTP_PASSWORD", "")
SMTP_TLS: bool = os.getenv("SMTP_TLS", "true").lower() == "true" SMTP_TLS: bool = os.getenv("SMTP_TLS", "true").lower() == "true"
SMTP_SSL: bool = os.getenv("SMTP_SSL", "false").lower() == "true" SMTP_SSL: bool = os.getenv("SMTP_SSL", "false").lower() == "true"
SMTP_REQUIRE_AUTH: bool = os.getenv("SMTP_REQUIRE_AUTH", "false").lower() == "true"
# Email Settings # Email Settings
DEFAULT_FROM_EMAIL: str = os.getenv("DEFAULT_FROM_EMAIL", "noreply@bakeryforecast.es") DEFAULT_FROM_EMAIL: str = os.getenv("DEFAULT_FROM_EMAIL", "noreply@bakeryforecast.es")

View File

@@ -37,9 +37,16 @@ class EmailService:
self.smtp_password = settings.SMTP_PASSWORD self.smtp_password = settings.SMTP_PASSWORD
self.smtp_tls = settings.SMTP_TLS self.smtp_tls = settings.SMTP_TLS
self.smtp_ssl = settings.SMTP_SSL self.smtp_ssl = settings.SMTP_SSL
self.smtp_require_auth = settings.SMTP_REQUIRE_AUTH
self.default_from_email = settings.DEFAULT_FROM_EMAIL self.default_from_email = settings.DEFAULT_FROM_EMAIL
self.default_from_name = settings.DEFAULT_FROM_NAME self.default_from_name = settings.DEFAULT_FROM_NAME
# Log SMTP configuration mode
if not self.smtp_require_auth or (not self.smtp_user and not self.smtp_password):
logger.info("Email service configured for trusted relay mode (no authentication)")
else:
logger.info("Email service configured with SMTP authentication")
async def send_email( async def send_email(
self, self,
to_email: str, to_email: str,
@@ -287,9 +294,12 @@ class EmailService:
else: else:
raise starttls_error raise starttls_error
# Login only if credentials are provided (optional for trusted relay) # Login only if required by configuration or if credentials are provided
if self.smtp_user and self.smtp_password: # This allows for trusted relay mode where authentication is not needed
if self.smtp_require_auth and self.smtp_user and self.smtp_password:
await server.login(self.smtp_user, self.smtp_password) await server.login(self.smtp_user, self.smtp_password)
elif not self.smtp_require_auth:
logger.debug("Skipping SMTP authentication - trusted relay mode")
await server.quit() await server.quit()
logger.info("Email service health check passed") logger.info("Email service health check passed")
@@ -327,9 +337,12 @@ class EmailService:
if self.smtp_tls and not self.smtp_ssl: if self.smtp_tls and not self.smtp_ssl:
await server.starttls() await server.starttls()
# Login only if credentials are provided (optional for trusted relay) # Login only if required by configuration or if credentials are provided
if self.smtp_user and self.smtp_password: # This allows for trusted relay mode where authentication is not needed
if self.smtp_require_auth and self.smtp_user and self.smtp_password:
await server.login(self.smtp_user, self.smtp_password) await server.login(self.smtp_user, self.smtp_password)
elif not self.smtp_require_auth:
logger.debug("Skipping SMTP authentication - trusted relay mode")
# Send email # Send email
await server.send_message(message, from_addr=from_email, to_addrs=[to_email]) await server.send_message(message, from_addr=from_email, to_addrs=[to_email])