- 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
14 KiB
Email Service Documentation
Table of Contents
- Overview
- Architecture
- Configuration
- API Usage
- Django Email Backend
- Testing
- Management Commands
- Troubleshooting
- 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
- EmailConfiguration Model: Stores site-specific email settings
- EmailService: Core service class for sending emails
- ForwardEmailBackend: Django email backend implementation
- API Views: REST API endpoints for email sending
- 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 model stores the following fields:
api_key: ForwardEmail API keyfrom_email: Default sender email addressfrom_name: Display name for the senderreply_to: Reply-to email addresssite: Associated Django site (ForeignKey)created_at: Creation timestampupdated_at: Last update timestamp
Creating Configuration via Admin
- Access Django admin at
/admin/ - Navigate to "Email Configurations"
- Click "Add Email Configuration"
- 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:
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:
# 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
{
"to": "recipient@example.com",
"subject": "Email Subject",
"text": "Email body text",
"from_email": "sender@example.com" // optional
}
Response Format
Success (200 OK):
{
"message": "Email sent successfully",
"response": {
// ForwardEmail API response
}
}
Error (400 Bad Request):
{
"error": "Missing required fields",
"required_fields": ["to", "subject", "text"]
}
Error (500 Internal Server Error):
{
"error": "Failed to send email: [error details]"
}
Example Usage
cURL:
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):
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):
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 class directly in your Python code:
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:
# settings.py
EMAIL_BACKEND = 'apps.email_service.backends.ForwardEmailBackend'
Usage
Once configured, you can use Django's standard email functions:
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 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:
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:
cd backend && uv run manage.py test_email_service --to user@example.com
This command tests:
- Site configuration setup
- Direct EmailService usage
- API endpoint functionality
- Django email backend
Test Email Flows
Test all application email flows:
cd backend && uv run manage.py test_email_flows
This command tests:
- User registration emails
- Password change notifications
- Email change verification
- Password reset emails
Manual Testing
API Endpoint Testing
Test the API endpoint directly:
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:
# 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
Usage:
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:
- Site Configuration: Creates/updates email configuration
- Direct Service: Tests EmailService.send_email()
- API Endpoint: Tests REST API endpoint
- 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
Usage:
cd backend && uv run manage.py test_email_flows
Tests Performed:
- Registration: User registration email flow
- Password Change: Password change notification
- Email Change: Email change verification
- 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:
- Access Django admin
- Create EmailConfiguration for your site
- Or set environment variables as fallback
2. "Failed to send email (Status 401)"
Cause: Invalid or missing API key.
Solution:
- Verify API key in EmailConfiguration
- Check ForwardEmail account status
- Ensure API key has proper permissions
3. "Could not connect to server"
Cause: Django development server not running or wrong URL.
Solution:
- Start Django server:
cd backend && uv run manage.py runserver - Verify server is running on expected port
- Check FORWARD_EMAIL_BASE_URL setting
4. "Site matching query does not exist"
Cause: Default site not configured properly.
Solution:
# 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:
# 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
- API Key Protection: Store API keys securely, never in code
- Environment Variables: Use environment variables for sensitive data
- HTTPS: Always use HTTPS in production
- Rate Limiting: Implement rate limiting for API endpoints
Configuration Management
- Site-Specific Settings: Use database configuration for multi-site setups
- Fallback Configuration: Always provide environment variable fallbacks
- Admin Interface: Use Django admin for easy configuration management
- Configuration Validation: Test configurations after changes
Error Handling
- Graceful Degradation: Handle email failures gracefully
- Logging: Log email failures for debugging
- User Feedback: Provide appropriate user feedback
- Retry Logic: Implement retry logic for transient failures
Performance
- Async Processing: Consider using Celery for email sending
- Batch Operations: Group multiple emails when possible
- Connection Pooling: Reuse HTTP connections when sending multiple emails
- Monitoring: Monitor email delivery rates and failures
Testing
- Automated Tests: Include email testing in your test suite
- Test Environments: Use test email addresses in development
- Integration Tests: Test complete email flows
- Load Testing: Test email service under load
Monitoring
- Delivery Tracking: Monitor email delivery success rates
- Error Tracking: Track and alert on email failures
- Performance Metrics: Monitor email sending performance
- API Limits: Monitor ForwardEmail API usage limits
Example Production Configuration
# 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.