HH/docs/EMAIL_SENDING_FIX.md

349 lines
12 KiB
Markdown

# Email Sending Fix - Complete Summary
## Problem Identified
Emails were not being sent in the development environment due to conflicting email backend configurations:
### Configuration Conflict
1. **`.env` file**: Configured to use SMTP backend
```
EMAIL_BACKEND=django.core.mail.backends.smtp.EmailBackend
```
2. **`config/settings/base.py`**: Read EMAIL_BACKEND from .env → SMTP
3. **`config/settings/dev.py`**: **OVERRRODE** with console backend
```python
EMAIL_BACKEND = 'django.core.mail.backends.console.EmailBackend'
```
4. **Simulator API**: Attempted to use Django's `send_mail()` which used console backend, but then tried to send via SMTP server that doesn't support STARTTLS
### Result
- Emails printed to console instead of being sent via simulator API
- SMTP connection errors: "STARTTLS extension not supported by server"
- All email requests failed with 500 status
## Solution Implemented
### 1. Updated `config/settings/dev.py`
**Changed**: Commented out console backend override to allow simulator API to work
```python
# Email backend for development
# Use simulator API for email (configured in .env with EMAIL_API_ENABLED=true)
# Emails will be sent to http://localhost:8000/api/simulator/send-email
# and displayed in terminal with formatted output
# EMAIL_BACKEND = 'django.core.mail.backends.console.EmailBackend' # Disabled for simulator API
```
**Effect**: Now uses the configuration from `.env` which enables EMAIL_API
### 2. Updated `apps/notifications/services.py`
**Changed**: Modified `send_email()` and `send_sms()` to check for API enabled first
```python
@staticmethod
def send_email(email, subject, message, html_message=None, related_object=None, metadata=None):
# Check if Email API is enabled and use it (simulator or external API)
email_api_config = settings.EXTERNAL_NOTIFICATION_API.get('email', {})
if email_api_config.get('enabled', False):
return NotificationService.send_email_via_api(...)
# Fallback to Django email backend if API disabled
...
```
**Effect**: Prioritizes API-based sending when enabled, falls back to Django's send_mail() otherwise
### 3. Updated `apps/simulator/views.py`
**Changed**: Modified email simulator to BOTH display formatted output AND send real emails via SMTP
```python
# Display formatted email to terminal
print(f"\n{'╔' + '═'*68 + '╗'}")
print(f"║{' ' * 15}📧 EMAIL SIMULATOR{' ' * 34}║")
# ... formatted output ...
print(f"╚{'═'*68}╝\n")
# Send real email via Django SMTP
send_mail(
subject=subject,
message=message,
from_email=settings.DEFAULT_FROM_EMAIL,
recipient_list=[to_email],
html_message=html_message,
fail_silently=False
)
```
**Effect**: Simulator displays emails in terminal with beautiful formatted output AND sends real emails via SMTP
### 4. Updated `.env` File
**Changed**: Disabled TLS for SMTP server
```bash
# Before
EMAIL_USE_TLS=True
# After
EMAIL_USE_TLS=False
```
**Effect**: Allows connection to SMTP server at 10.10.1.110:2225 which doesn't support STARTTLS
## Current Email Flow (Development)
```
NotificationService.send_email()
Checks EMAIL_API_ENABLED in settings
If enabled → Uses send_email_via_api()
Sends POST request to http://localhost:8000/api/simulator/send-email
Simulator receives request
Displays formatted email in terminal
Sends real email via SMTP (10.10.1.110:2225)
Returns 200 OK with success response
NotificationLog created with status='sent'
```
## Test Results
All tests passed successfully:
```
1. Testing plain text email... ✅
Log ID: 476a0fce-9a26-4244-877c-62e696c64169
Recipient: test@example.com
2. Testing HTML email... ✅
Log ID: f2bd7cbf-b5ee-4f02-9717-a3c61b46f88d
Recipient: test@example.com
3. Testing SMS sending... ✅
Log ID: edc987b6-aca6-4368-b3e3-8d42b3eb9dd5
Recipient: +966501234567
```
## Server Log Output
```
INFO [Email Simulator] Sending email to test@example.com: Test Email - Plain Text
INFO [Email Simulator] Email sent via SMTP to test@example.com
INFO [Email Simulator] Email sent successfully to test@example.com
INFO [Simulator] EMAIL Request #1: sent
INFO "POST /api/simulator/send-email HTTP/1.1" 200 170
```
## Formatted Output Example
### Email Simulator Output
```
╔════════════════════════════════════════════════════════════════════╗
║ 📧 EMAIL SIMULATOR ║
╠════════════════════════════════════════════════════════════════════╣
║ Request #: 1 ║
╠════════════════════════════════════════════════════════════════════╣
║ To: test@example.com ║
║ Subject: Test Email - Plain Text ║
╠════════════════════════════════════════════════════════════════════╣
║ Message: ║
║ This is a test email sent via simulator API. ║
╚════════════════════════════════════════════════════════════════════╝
```
### SMS Simulator Output
```
╔════════════════════════════════════════════════════════════════════╗
║ 📱 SMS SIMULATOR ║
╠════════════════════════════════════════════════════════════════════╣
║ Request #: 1 ║
╠════════════════════════════════════════════════════════════════════╣
║ To: +966501234567 ║
║ Time: 2026-01-12 18:57:13 ║
╠════════════════════════════════════════════════════════════════════╣
║ Message: ║
║ This is a test SMS sent via simulator API. ║
╚════════════════════════════════════════════════════════════════════╝
```
## Configuration
### Required `.env` Settings
```bash
# Email Configuration
EMAIL_BACKEND=django.core.mail.backends.smtp.EmailBackend
EMAIL_HOST=10.10.1.110
EMAIL_PORT=2225
EMAIL_USE_TLS=False # Disabled for this SMTP server
EMAIL_HOST_USER=
EMAIL_HOST_PASSWORD=
DEFAULT_FROM_EMAIL=noreply@px360.sa
# Enable Email API (simulator or external)
EMAIL_API_ENABLED=true
# Email Simulator API URL
EMAIL_API_URL=http://localhost:8000/api/simulator/send-email
EMAIL_API_KEY=simulator-test-key
EMAIL_API_AUTH_METHOD=bearer
# Enable SMS API (simulator or external)
SMS_API_ENABLED=true
# SMS Simulator API URL
SMS_API_URL=http://localhost:8000/api/simulator/send-sms
SMS_API_KEY=simulator-test-key
SMS_API_AUTH_METHOD=bearer
```
## Usage
### Send Email (Plain Text)
```python
from apps.notifications.services import NotificationService
log = NotificationService.send_email(
email='user@example.com',
subject='Welcome to PX360',
message='Thank you for registering!'
)
```
### Send Email (HTML)
```python
html_message = """
<html>
<body>
<h1>Welcome!</h1>
<p>Thank you for registering with <strong>PX360</strong>.</p>
</body>
</html>
"""
log = NotificationService.send_email(
email='user@example.com',
subject='Welcome to PX360',
message='Plain text version',
html_message=html_message
)
```
### Send SMS
```python
log = NotificationService.send_sms(
phone='+966501234567',
message='Your survey is ready. Please complete it today!'
)
```
## Benefits
1. **Dual-Mode Operation**: Displays formatted output AND sends real emails
2. **No SMTP Errors**: Fixed STARTTLS issue by disabling TLS for development
3. **Formatted Output**: Beautiful terminal display for both email and SMS
4. **Logged to Database**: All notifications logged in NotificationLog table
5. **API-First Architecture**: Easy to switch to external APIs (SendGrid, Twilio) in production
6. **Retry Logic**: Built-in retry with exponential backoff for API failures
7. **Testing Friendly**: Easy to verify emails are being sent
## Production Configuration
To use actual email/SMS providers in production:
```bash
# Email (e.g., SendGrid)
EMAIL_API_ENABLED=true
EMAIL_API_URL=https://api.sendgrid.com/v3/mail/send
EMAIL_API_KEY=your-sendgrid-api-key
EMAIL_API_AUTH_METHOD=bearer
# SMS (e.g., Twilio)
SMS_API_ENABLED=true
SMS_API_URL=https://api.twilio.com/2010-04-01/Accounts/{AccountSid}/Messages.json
SMS_API_KEY=your-twilio-api-key
SMS_API_AUTH_METHOD=basic
```
## Testing
Run the test script to verify email sending:
```bash
python test_email_sending.py
```
Expected output:
```
======================================================================
Testing Email Sending via Simulator API
======================================================================
1. Testing plain text email... ✅ Plain text email sent successfully!
2. Testing HTML email... ✅ HTML email sent successfully!
3. Testing SMS sending... ✅ SMS sent successfully!
======================================================================
Test Complete!
======================================================================
```
## Files Modified
1. `config/settings/dev.py` - Disabled console backend override
2. `apps/notifications/services.py` - Updated to prioritize API sending
3. `apps/simulator/views.py` - Changed to print formatted output AND send via SMTP
4. `.env` - Disabled TLS for SMTP server
5. `test_email_sending.py` - Created test script
6. `docs/EMAIL_SENDING_FIX.md` - Complete documentation
## Next Steps
- Consider implementing email templates for better formatting
- Add email preview functionality in admin panel
- Implement email tracking and analytics
- Add bounce and complaint handling for production
- Set up webhook notifications for delivery status
- Configure a more secure SMTP server for production with TLS enabled
## Troubleshooting
### Emails still not sending?
1. Check `.env` file has `EMAIL_API_ENABLED=true`
2. Verify server is running on port 8000
3. Check logs: `tail -f logs/px360.log`
4. Test simulator directly: `curl http://localhost:8000/api/simulator/health-check`
5. Verify SMTP server is accessible: `telnet 10.10.1.110 2225`
### Can't see formatted output?
The formatted output is printed to the terminal where the Django development server is running, not to the log file. Make sure you're watching the correct terminal.
### Email sent but not received?
1. Check spam/junk folder
2. Verify email address is correct
3. Check SMTP server logs
4. Verify `DEFAULT_FROM_EMAIL` is properly configured
5. Some email providers may reject emails from certain senders
## Date
Fixed on: January 12, 2026
Updated: January 12, 2026 - Added real SMTP sending capability