Files
thrillwiki_django_no_react/docs/email-service.md
pacnpal bb7da85516 Refactor API structure and add comprehensive user management features
- Restructure API v1 with improved serializers organization
- Add user deletion requests and moderation queue system
- Implement bulk moderation operations and permissions
- Add user profile enhancements with display names and avatars
- Expand ride and park API endpoints with better filtering
- Add manufacturer API with detailed ride relationships
- Improve authentication flows and error handling
- Update frontend documentation and API specifications
2025-08-29 16:03:51 -04:00

550 lines
14 KiB
Markdown

# Email Service Documentation
## Table of Contents
1. [Overview](#overview)
2. [Architecture](#architecture)
3. [Configuration](#configuration)
4. [API Usage](#api-usage)
5. [Django Email Backend](#django-email-backend)
6. [Testing](#testing)
7. [Management Commands](#management-commands)
8. [Troubleshooting](#troubleshooting)
9. [Best Practices](#best-practices)
## Overview
The Email Service is a comprehensive email delivery system built for the Django application. It provides a centralized way to send emails through the ForwardEmail API service, with support for site-specific configurations, Django email backend integration, and comprehensive testing tools.
### Key Features
- **Site-specific Configuration**: Different email settings per Django site
- **ForwardEmail Integration**: Uses ForwardEmail API for reliable email delivery
- **Django Backend Integration**: Drop-in replacement for Django's email backend
- **REST API Endpoint**: Send emails via HTTP API
- **Comprehensive Testing**: Built-in testing commands and flows
- **History Tracking**: All configurations are tracked with pghistory
- **Admin Interface**: Easy configuration management through Django admin
## Architecture
The email service consists of several key components:
```
apps/email_service/
├── models.py # EmailConfiguration model
├── services.py # Core EmailService class
├── backends.py # Django email backend implementation
├── admin.py # Django admin configuration
├── urls.py # URL patterns (legacy)
└── management/commands/ # Testing and utility commands
apps/api/v1/email/
├── views.py # Centralized API views
└── urls.py # API URL patterns
```
### Component Overview
1. **EmailConfiguration Model**: Stores site-specific email settings
2. **EmailService**: Core service class for sending emails
3. **ForwardEmailBackend**: Django email backend implementation
4. **API Views**: REST API endpoints for email sending
5. **Management Commands**: Testing and utility tools
## Configuration
### Database Configuration
Email configurations are stored in the database and managed through the Django admin interface.
#### EmailConfiguration Model
The [`EmailConfiguration`](../backend/apps/email_service/models.py:8) model stores the following fields:
- `api_key`: ForwardEmail API key
- `from_email`: Default sender email address
- `from_name`: Display name for the sender
- `reply_to`: Reply-to email address
- `site`: Associated Django site (ForeignKey)
- `created_at`: Creation timestamp
- `updated_at`: Last update timestamp
#### Creating Configuration via Admin
1. Access Django admin at `/admin/`
2. Navigate to "Email Configurations"
3. Click "Add Email Configuration"
4. Fill in the required fields:
- **Site**: Select the Django site
- **API Key**: Your ForwardEmail API key
- **From Name**: Display name (e.g., "ThrillWiki")
- **From Email**: Sender email address
- **Reply To**: Reply-to email address
### Environment Variables (Fallback)
If no database configuration exists, the system falls back to environment variables:
```bash
FORWARD_EMAIL_API_KEY=your_api_key_here
FORWARD_EMAIL_FROM=noreply@yourdomain.com
FORWARD_EMAIL_BASE_URL=https://api.forwardemail.net
```
### Django Settings
Add the email service to your Django settings:
```python
# settings.py
INSTALLED_APPS = [
# ... other apps
'apps.email_service',
]
# ForwardEmail API base URL
FORWARD_EMAIL_BASE_URL = 'https://api.forwardemail.net'
# Optional: Use custom email backend
EMAIL_BACKEND = 'apps.email_service.backends.ForwardEmailBackend'
```
## API Usage
### REST API Endpoint
The email service provides a REST API endpoint for sending emails.
#### Endpoint
```
POST /api/v1/email/send/
```
#### Request Format
```json
{
"to": "recipient@example.com",
"subject": "Email Subject",
"text": "Email body text",
"from_email": "sender@example.com" // optional
}
```
#### Response Format
**Success (200 OK):**
```json
{
"message": "Email sent successfully",
"response": {
// ForwardEmail API response
}
}
```
**Error (400 Bad Request):**
```json
{
"error": "Missing required fields",
"required_fields": ["to", "subject", "text"]
}
```
**Error (500 Internal Server Error):**
```json
{
"error": "Failed to send email: [error details]"
}
```
#### Example Usage
**cURL:**
```bash
curl -X POST http://localhost:8000/api/v1/email/send/ \
-H "Content-Type: application/json" \
-d '{
"to": "user@example.com",
"subject": "Welcome to ThrillWiki",
"text": "Thank you for joining ThrillWiki!"
}'
```
**JavaScript (fetch):**
```javascript
const response = await fetch('/api/v1/email/send/', {
method: 'POST',
headers: {
'Content-Type': 'application/json',
'X-CSRFToken': getCookie('csrftoken') // if CSRF protection enabled
},
body: JSON.stringify({
to: 'user@example.com',
subject: 'Welcome to ThrillWiki',
text: 'Thank you for joining ThrillWiki!'
})
});
const result = await response.json();
```
**Python (requests):**
```python
import requests
response = requests.post('http://localhost:8000/api/v1/email/send/', json={
'to': 'user@example.com',
'subject': 'Welcome to ThrillWiki',
'text': 'Thank you for joining ThrillWiki!'
})
result = response.json()
```
### Direct Service Usage
You can also use the [`EmailService`](../backend/apps/email_service/services.py:11) class directly in your Python code:
```python
from django.contrib.sites.shortcuts import get_current_site
from apps.email_service.services import EmailService
# In a view or other code
def send_welcome_email(request, user_email):
site = get_current_site(request)
try:
response = EmailService.send_email(
to=user_email,
subject="Welcome to ThrillWiki",
text="Thank you for joining ThrillWiki!",
site=site
)
return response
except Exception as e:
# Handle error
print(f"Failed to send email: {e}")
return None
```
## Django Email Backend
The email service includes a custom Django email backend that integrates with Django's built-in email system.
### Configuration
To use the custom backend, set it in your Django settings:
```python
# settings.py
EMAIL_BACKEND = 'apps.email_service.backends.ForwardEmailBackend'
```
### Usage
Once configured, you can use Django's standard email functions:
```python
from django.core.mail import send_mail
from django.contrib.sites.shortcuts import get_current_site
def send_notification(request):
site = get_current_site(request)
send_mail(
subject='Notification',
message='This is a notification email.',
from_email=None, # Will use site's default
recipient_list=['user@example.com'],
fail_silently=False,
)
```
### Backend Features
The [`ForwardEmailBackend`](../backend/apps/email_service/backends.py:7) provides:
- **Site-aware Configuration**: Automatically uses the correct site's email settings
- **Error Handling**: Proper error handling with optional silent failures
- **Multiple Recipients**: Handles multiple recipients (sends individually)
- **From Email Handling**: Automatic from email resolution
### Backend Limitations
- **Single Recipient**: ForwardEmail API sends to one recipient at a time
- **Text Only**: Currently supports text emails only (HTML support can be added)
- **Site Requirement**: Requires site context for configuration lookup
## Testing
The email service includes comprehensive testing tools to verify functionality.
### Management Commands
#### Test Email Service
Test the core email service functionality:
```bash
cd backend && uv run manage.py test_email_service
```
**Options:**
- `--to EMAIL`: Recipient email (default: test@thrillwiki.com)
- `--api-key KEY`: Override API key
- `--from-email EMAIL`: Override from email
**Example:**
```bash
cd backend && uv run manage.py test_email_service --to user@example.com
```
This command tests:
1. Site configuration setup
2. Direct EmailService usage
3. API endpoint functionality
4. Django email backend
#### Test Email Flows
Test all application email flows:
```bash
cd backend && uv run manage.py test_email_flows
```
This command tests:
1. User registration emails
2. Password change notifications
3. Email change verification
4. Password reset emails
### Manual Testing
#### API Endpoint Testing
Test the API endpoint directly:
```bash
curl -X POST http://localhost:8000/api/v1/email/send/ \
-H "Content-Type: application/json" \
-d '{
"to": "test@example.com",
"subject": "Test Email",
"text": "This is a test email."
}'
```
#### Django Shell Testing
Test using Django shell:
```python
# cd backend && uv run manage.py shell
from django.contrib.sites.models import Site
from apps.email_service.services import EmailService
site = Site.objects.get_current()
response = EmailService.send_email(
to="test@example.com",
subject="Test from Shell",
text="This is a test email from Django shell.",
site=site
)
print(response)
```
## Management Commands
### test_email_service
**Purpose**: Comprehensive testing of email service functionality
**Location**: [`backend/apps/email_service/management/commands/test_email_service.py`](../backend/apps/email_service/management/commands/test_email_service.py:12)
**Usage:**
```bash
cd backend && uv run manage.py test_email_service [options]
```
**Options:**
- `--to EMAIL`: Recipient email address
- `--api-key KEY`: ForwardEmail API key override
- `--from-email EMAIL`: Sender email override
**Tests Performed:**
1. **Site Configuration**: Creates/updates email configuration
2. **Direct Service**: Tests EmailService.send_email()
3. **API Endpoint**: Tests REST API endpoint
4. **Django Backend**: Tests Django email backend
### test_email_flows
**Purpose**: Test all application email flows
**Location**: [`backend/apps/email_service/management/commands/test_email_flows.py`](../backend/apps/email_service/management/commands/test_email_flows.py:13)
**Usage:**
```bash
cd backend && uv run manage.py test_email_flows
```
**Tests Performed:**
1. **Registration**: User registration email flow
2. **Password Change**: Password change notification
3. **Email Change**: Email change verification
4. **Password Reset**: Password reset email flow
## Troubleshooting
### Common Issues
#### 1. "Email configuration is missing for site"
**Cause**: No EmailConfiguration exists for the current site.
**Solution:**
1. Access Django admin
2. Create EmailConfiguration for your site
3. Or set environment variables as fallback
#### 2. "Failed to send email (Status 401)"
**Cause**: Invalid or missing API key.
**Solution:**
1. Verify API key in EmailConfiguration
2. Check ForwardEmail account status
3. Ensure API key has proper permissions
#### 3. "Could not connect to server"
**Cause**: Django development server not running or wrong URL.
**Solution:**
1. Start Django server: `cd backend && uv run manage.py runserver`
2. Verify server is running on expected port
3. Check FORWARD_EMAIL_BASE_URL setting
#### 4. "Site matching query does not exist"
**Cause**: Default site not configured properly.
**Solution:**
```python
# Django shell
from django.contrib.sites.models import Site
Site.objects.get_or_create(
id=1,
defaults={'domain': 'localhost:8000', 'name': 'localhost:8000'}
)
```
### Debug Mode
The EmailService includes debug output. Check console logs for:
- Request URL and data
- Response status and body
- API key (masked)
- Site information
### Testing Configuration
Verify your configuration:
```bash
# Test with specific configuration
cd backend && uv run manage.py test_email_service \
--api-key your_api_key \
--from-email noreply@yourdomain.com \
--to test@example.com
```
### API Response Codes
- **200**: Success
- **400**: Bad request (missing fields, invalid data)
- **401**: Unauthorized (invalid API key)
- **500**: Server error (configuration issues, network problems)
## Best Practices
### Security
1. **API Key Protection**: Store API keys securely, never in code
2. **Environment Variables**: Use environment variables for sensitive data
3. **HTTPS**: Always use HTTPS in production
4. **Rate Limiting**: Implement rate limiting for API endpoints
### Configuration Management
1. **Site-Specific Settings**: Use database configuration for multi-site setups
2. **Fallback Configuration**: Always provide environment variable fallbacks
3. **Admin Interface**: Use Django admin for easy configuration management
4. **Configuration Validation**: Test configurations after changes
### Error Handling
1. **Graceful Degradation**: Handle email failures gracefully
2. **Logging**: Log email failures for debugging
3. **User Feedback**: Provide appropriate user feedback
4. **Retry Logic**: Implement retry logic for transient failures
### Performance
1. **Async Processing**: Consider using Celery for email sending
2. **Batch Operations**: Group multiple emails when possible
3. **Connection Pooling**: Reuse HTTP connections when sending multiple emails
4. **Monitoring**: Monitor email delivery rates and failures
### Testing
1. **Automated Tests**: Include email testing in your test suite
2. **Test Environments**: Use test email addresses in development
3. **Integration Tests**: Test complete email flows
4. **Load Testing**: Test email service under load
### Monitoring
1. **Delivery Tracking**: Monitor email delivery success rates
2. **Error Tracking**: Track and alert on email failures
3. **Performance Metrics**: Monitor email sending performance
4. **API Limits**: Monitor ForwardEmail API usage limits
### Example Production Configuration
```python
# settings/production.py
EMAIL_BACKEND = 'apps.email_service.backends.ForwardEmailBackend'
FORWARD_EMAIL_BASE_URL = 'https://api.forwardemail.net'
# Use environment variables for sensitive data
import os
FORWARD_EMAIL_API_KEY = os.environ.get('FORWARD_EMAIL_API_KEY')
FORWARD_EMAIL_FROM = os.environ.get('FORWARD_EMAIL_FROM')
# Logging configuration
LOGGING = {
'version': 1,
'disable_existing_loggers': False,
'handlers': {
'email_file': {
'level': 'INFO',
'class': 'logging.FileHandler',
'filename': '/var/log/django/email.log',
},
},
'loggers': {
'apps.email_service': {
'handlers': ['email_file'],
'level': 'INFO',
'propagate': True,
},
},
}
```
This documentation provides comprehensive coverage of the email service functionality, from basic setup to advanced usage patterns and troubleshooting.