email_notifications #7
@@ -14059,3 +14059,17 @@ IndexError: list index out of range
|
|||||||
2025-10-10 10:59:53 - alpine_bits_python.api - INFO - Hotel 39040_001 has no push_endpoint configured
|
2025-10-10 10:59:53 - alpine_bits_python.api - INFO - Hotel 39040_001 has no push_endpoint configured
|
||||||
2025-10-10 10:59:53 - alpine_bits_python.api - INFO - Database tables checked/created at startup.
|
2025-10-10 10:59:53 - alpine_bits_python.api - INFO - Database tables checked/created at startup.
|
||||||
2025-10-10 10:59:53 - httpx - INFO - HTTP Request: PUT http://testserver/api/hoteldata/conversions_import/test_reservation.xml "HTTP/1.1 401 Unauthorized"
|
2025-10-10 10:59:53 - httpx - INFO - HTTP Request: PUT http://testserver/api/hoteldata/conversions_import/test_reservation.xml "HTTP/1.1 401 Unauthorized"
|
||||||
|
2025-10-15 08:49:50 - root - INFO - Logging to file: alpinebits.log
|
||||||
|
2025-10-15 08:49:50 - root - INFO - Logging configured at INFO level
|
||||||
|
2025-10-15 08:49:52 - alpine_bits_python.email_service - INFO - Email service initialized: smtp.gmail.com:587
|
||||||
|
2025-10-15 08:49:52 - root - INFO - Logging to file: alpinebits.log
|
||||||
|
2025-10-15 08:49:52 - root - INFO - Logging configured at INFO level
|
||||||
|
2025-10-15 08:49:54 - alpine_bits_python.email_service - INFO - Email service initialized: smtp.gmail.com:587
|
||||||
|
2025-10-15 08:52:37 - root - INFO - Logging to file: alpinebits.log
|
||||||
|
2025-10-15 08:52:37 - root - INFO - Logging configured at INFO level
|
||||||
|
2025-10-15 08:52:54 - root - INFO - Logging to file: alpinebits.log
|
||||||
|
2025-10-15 08:52:54 - root - INFO - Logging configured at INFO level
|
||||||
|
2025-10-15 08:52:56 - alpine_bits_python.email_service - INFO - Email service initialized: smtp.titan.email:465
|
||||||
|
2025-10-15 08:52:56 - root - INFO - Logging to file: alpinebits.log
|
||||||
|
2025-10-15 08:52:56 - root - INFO - Logging configured at INFO level
|
||||||
|
2025-10-15 08:52:58 - alpine_bits_python.email_service - INFO - Email service initialized: smtp.titan.email:465
|
||||||
|
|||||||
@@ -44,15 +44,15 @@ alpine_bits_auth:
|
|||||||
email:
|
email:
|
||||||
# SMTP server configuration
|
# SMTP server configuration
|
||||||
smtp:
|
smtp:
|
||||||
host: "smtp.gmail.com" # Your SMTP server
|
host: "smtp.titan.email" # Your SMTP server
|
||||||
port: 587 # Usually 587 for TLS, 465 for SSL
|
port: 465 # Usually 587 for TLS, 465 for SSL
|
||||||
username: !secret EMAIL_USERNAME # SMTP username
|
username: info@99tales.net # SMTP username
|
||||||
password: !secret EMAIL_PASSWORD # SMTP password
|
password: !secret EMAIL_PASSWORD # SMTP password
|
||||||
use_tls: true # Use STARTTLS
|
use_tls: false # Use STARTTLS
|
||||||
use_ssl: false # Use SSL/TLS from start
|
use_ssl: true # Use SSL/TLS from start
|
||||||
|
|
||||||
# Email addresses
|
# Email addresses
|
||||||
from_address: "noreply@99tales.com" # Sender address
|
from_address: "info@99tales.net" # Sender address
|
||||||
from_name: "AlpineBits Monitor" # Sender display name
|
from_name: "AlpineBits Monitor" # Sender display name
|
||||||
|
|
||||||
# Monitoring and alerting
|
# Monitoring and alerting
|
||||||
@@ -61,8 +61,8 @@ email:
|
|||||||
daily_report:
|
daily_report:
|
||||||
enabled: false # Set to true to enable daily reports
|
enabled: false # Set to true to enable daily reports
|
||||||
recipients:
|
recipients:
|
||||||
- "admin@99tales.com"
|
- "jonas@vaius.ai"
|
||||||
- "dev@99tales.com"
|
#- "dev@99tales.com"
|
||||||
send_time: "08:00" # Time to send daily report (24h format, local time)
|
send_time: "08:00" # Time to send daily report (24h format, local time)
|
||||||
include_stats: true # Include reservation/customer stats
|
include_stats: true # Include reservation/customer stats
|
||||||
include_errors: true # Include error summary
|
include_errors: true # Include error summary
|
||||||
@@ -71,8 +71,8 @@ email:
|
|||||||
error_alerts:
|
error_alerts:
|
||||||
enabled: false # Set to true to enable error alerts
|
enabled: false # Set to true to enable error alerts
|
||||||
recipients:
|
recipients:
|
||||||
- "alerts@99tales.com"
|
- "jonas@vaius.ai"
|
||||||
- "oncall@99tales.com"
|
#- "oncall@99tales.com"
|
||||||
# Alert is sent immediately if threshold is reached
|
# Alert is sent immediately if threshold is reached
|
||||||
error_threshold: 5 # Send immediate alert after N errors
|
error_threshold: 5 # Send immediate alert after N errors
|
||||||
# Otherwise, alert is sent after buffer time expires
|
# Otherwise, alert is sent after buffer time expires
|
||||||
|
|||||||
@@ -20,11 +20,11 @@ email:
|
|||||||
|
|
||||||
## 2. Set Environment Variables
|
## 2. Set Environment Variables
|
||||||
|
|
||||||
Create a `.env` file in the project root:
|
In the secrets.yaml file add the secrets
|
||||||
|
|
||||||
```bash
|
```yaml
|
||||||
EMAIL_USERNAME=your-email@gmail.com
|
EMAIL_USERNAME: "your_email_username"
|
||||||
EMAIL_PASSWORD=your-app-password
|
EMAIL_PASSWORD: "your_email_password"
|
||||||
```
|
```
|
||||||
|
|
||||||
> **Note:** For Gmail, use an [App Password](https://support.google.com/accounts/answer/185833), not your regular password.
|
> **Note:** For Gmail, use an [App Password](https://support.google.com/accounts/answer/185833), not your regular password.
|
||||||
@@ -46,6 +46,7 @@ email:
|
|||||||
```
|
```
|
||||||
|
|
||||||
**How it works:**
|
**How it works:**
|
||||||
|
|
||||||
- Sends immediate alert after 5 errors
|
- Sends immediate alert after 5 errors
|
||||||
- Otherwise sends after 15 minutes
|
- Otherwise sends after 15 minutes
|
||||||
- Waits 15 minutes between alerts (cooldown)
|
- Waits 15 minutes between alerts (cooldown)
|
||||||
@@ -75,6 +76,7 @@ uv run python examples/test_email_monitoring.py
|
|||||||
```
|
```
|
||||||
|
|
||||||
This will:
|
This will:
|
||||||
|
|
||||||
- ✅ Send a test email
|
- ✅ Send a test email
|
||||||
- ✅ Trigger an error alert
|
- ✅ Trigger an error alert
|
||||||
- ✅ Send a test daily report
|
- ✅ Send a test daily report
|
||||||
@@ -124,12 +126,14 @@ Errors (3):
|
|||||||
### No emails received?
|
### No emails received?
|
||||||
|
|
||||||
1. Check your SMTP credentials:
|
1. Check your SMTP credentials:
|
||||||
|
|
||||||
```bash
|
```bash
|
||||||
echo $EMAIL_USERNAME
|
echo $EMAIL_USERNAME
|
||||||
echo $EMAIL_PASSWORD
|
echo $EMAIL_PASSWORD
|
||||||
```
|
```
|
||||||
|
|
||||||
2. Check application logs for errors:
|
2. Check application logs for errors:
|
||||||
|
|
||||||
```bash
|
```bash
|
||||||
tail -f alpinebits.log | grep -i email
|
tail -f alpinebits.log | grep -i email
|
||||||
```
|
```
|
||||||
@@ -167,6 +171,7 @@ Errors (3):
|
|||||||
## Support
|
## Support
|
||||||
|
|
||||||
For issues or questions:
|
For issues or questions:
|
||||||
|
|
||||||
- Check the [documentation](./EMAIL_MONITORING.md)
|
- Check the [documentation](./EMAIL_MONITORING.md)
|
||||||
- Review [test examples](../examples/test_email_monitoring.py)
|
- Review [test examples](../examples/test_email_monitoring.py)
|
||||||
- Open an issue on GitHub
|
- Open an issue on GitHub
|
||||||
|
|||||||
@@ -174,13 +174,12 @@ class EmailAlertHandler(logging.Handler):
|
|||||||
self._flush_buffer(immediate=True),
|
self._flush_buffer(immediate=True),
|
||||||
self.loop,
|
self.loop,
|
||||||
)
|
)
|
||||||
else:
|
# Schedule delayed flush if not already scheduled
|
||||||
# Schedule delayed flush if not already scheduled
|
elif not self._flush_task or self._flush_task.done():
|
||||||
if not self._flush_task or self._flush_task.done():
|
self._flush_task = asyncio.run_coroutine_threadsafe(
|
||||||
self._flush_task = asyncio.run_coroutine_threadsafe(
|
self._schedule_delayed_flush(),
|
||||||
self._schedule_delayed_flush(),
|
self.loop,
|
||||||
self.loop,
|
)
|
||||||
)
|
|
||||||
|
|
||||||
except Exception:
|
except Exception:
|
||||||
# Never let the handler crash - just log and continue
|
# Never let the handler crash - just log and continue
|
||||||
@@ -237,7 +236,9 @@ class EmailAlertHandler(logging.Handler):
|
|||||||
emoji = "⚠️"
|
emoji = "⚠️"
|
||||||
reason = f"({self.buffer_minutes} minute buffer)"
|
reason = f"({self.buffer_minutes} minute buffer)"
|
||||||
|
|
||||||
subject = f"{emoji} AlpineBits Error {alert_type}: {error_count} errors {reason}"
|
subject = (
|
||||||
|
f"{emoji} AlpineBits Error {alert_type}: {error_count} errors {reason}"
|
||||||
|
)
|
||||||
|
|
||||||
# Build plain text body
|
# Build plain text body
|
||||||
body = f"Error Alert - {datetime.now().strftime('%Y-%m-%d %H:%M:%S')}\n"
|
body = f"Error Alert - {datetime.now().strftime('%Y-%m-%d %H:%M:%S')}\n"
|
||||||
@@ -290,10 +291,18 @@ class EmailAlertHandler(logging.Handler):
|
|||||||
# Flush any remaining errors immediately
|
# Flush any remaining errors immediately
|
||||||
if self.error_buffer and self.loop:
|
if self.error_buffer and self.loop:
|
||||||
try:
|
try:
|
||||||
asyncio.run_coroutine_threadsafe(
|
# Check if the loop is still running
|
||||||
self._flush_buffer(immediate=False),
|
if not self.loop.is_closed():
|
||||||
self.loop,
|
future = asyncio.run_coroutine_threadsafe(
|
||||||
).result(timeout=5)
|
self._flush_buffer(immediate=False),
|
||||||
|
self.loop,
|
||||||
|
)
|
||||||
|
future.result(timeout=5)
|
||||||
|
else:
|
||||||
|
_LOGGER.warning(
|
||||||
|
"Event loop closed, cannot flush %d remaining errors",
|
||||||
|
len(self.error_buffer),
|
||||||
|
)
|
||||||
except Exception:
|
except Exception:
|
||||||
_LOGGER.exception("Error flushing buffer on close")
|
_LOGGER.exception("Error flushing buffer on close")
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user