Email System
Overview
AppVector includes a comprehensive email system for sending transactional emails to users. The system supports HTML templates, multiple email backends, and provides pre-built templates for common scenarios.
Email Service: services/email_service.py
Features
- ✅ Template-based emails - Beautiful HTML emails with consistent branding
- ✅ Plain text fallback - Automatically generates plain text from HTML
- ✅ Multiple backends - SMTP, SendGrid, AWS SES, or console (development)
- ✅ Pre-built templates - 9 ready-to-use email templates
- ✅ Attachment support - Send PDFs, images, or other files
- ✅ Bulk sending - Efficiently send to multiple recipients
- ✅ Error handling - Graceful failure with logging
Configuration
Environment Variables
Add these to your .env file:
# Email Backend
EMAIL_BACKEND=django.core.mail.backends.console.EmailBackend # Development
# EMAIL_BACKEND=django.core.mail.backends.smtp.EmailBackend # Production
# SMTP Settings (for production)
EMAIL_HOST=smtp.gmail.com
EMAIL_PORT=587
EMAIL_USE_TLS=True
EMAIL_USE_SSL=False
EMAIL_HOST_USER=[email protected]
EMAIL_HOST_PASSWORD=your-app-password
# Email Addresses
DEFAULT_FROM_EMAIL=[email protected]
SERVER_EMAIL=[email protected]
# Frontend URL (for email links)
FRONTEND_URL=http://localhost:3000
Email Backends
Development (Console Backend)
Prints emails to the console instead of sending them:
Production (SMTP Backend)
Sends emails via SMTP server:
File Backend (Testing)
Saves emails as files in a directory:
Usage
Simple Text Email
from services.email_service import EmailService
EmailService.send_simple_email(
to_email='[email protected]',
subject='Welcome!',
message='Welcome to AppVector!'
)
Template-Based Email
from services.email_service import EmailService
EmailService.send_template_email(
to_email='[email protected]',
subject='Payment Receipt',
template_name='emails/subscription_confirmation.html',
context={
'user_name': 'John Doe',
'plan_name': 'Professional',
'amount': 149.00,
'next_billing_date': '2024-02-01'
}
)
Bulk Email
from services.email_service import EmailService
recipients = ['[email protected]', '[email protected]', '[email protected]']
EmailService.send_bulk_email(
recipients=recipients,
subject='Important Update',
message='We have an important update for you...'
)
Pre-Built Email Functions
The system includes convenient functions for common scenarios:
1. Welcome Email
from services.email_service import send_welcome_email
send_welcome_email(
user_email='[email protected]',
user_name='John Doe'
)
Template: emails/welcome.html
2. Password Reset
from services.email_service import send_password_reset_email
send_password_reset_email(
user_email='[email protected]',
reset_token='abc123xyz',
user_name='John Doe'
)
Template: emails/password_reset.html
3. Subscription Confirmation
from services.email_service import send_subscription_confirmation_email
send_subscription_confirmation_email(
user_email='[email protected]',
user_name='John Doe',
plan_name='Professional',
amount=149.00,
next_billing_date='2024-02-01'
)
Template: emails/subscription_confirmation.html
4. Payment Failed
from services.email_service import send_payment_failed_email
send_payment_failed_email(
user_email='[email protected]',
user_name='John Doe',
plan_name='Professional',
amount=149.00,
retry_date='2024-01-20'
)
Template: emails/payment_failed.html
5. Subscription Cancelled
from services.email_service import send_subscription_cancelled_email
send_subscription_cancelled_email(
user_email='[email protected]',
user_name='John Doe',
plan_name='Professional',
end_date='2024-01-31'
)
Template: emails/subscription_cancelled.html
6. Low Credit Warning
from services.email_service import send_credit_low_warning_email
send_credit_low_warning_email(
user_email='[email protected]',
user_name='John Doe',
credit_type='API Calls',
remaining_credits=250,
threshold_percentage=20
)
Template: emails/credit_low_warning.html
7. Invoice
from services.email_service import send_invoice_email
send_invoice_email(
user_email='[email protected]',
user_name='John Doe',
invoice_number='INV-202401-00123',
amount=149.00,
invoice_date='2024-01-15',
invoice_pdf_url='https://stripe.com/invoice/...'
)
Template: emails/invoice.html
8. Team Invitation
from services.email_service import send_team_invitation_email
send_team_invitation_email(
invitee_email='[email protected]',
inviter_name='John Doe',
workspace_name='Acme Corp',
role='ADMIN',
invitation_url='https://app.com/invite/abc123'
)
Template: emails/team_invitation.html
9. Project Shared
from services.email_service import send_project_shared_email
send_project_shared_email(
user_email='[email protected]',
user_name='Jane Smith',
project_name='WhatsApp Tracking',
shared_by='John Doe',
role='VIEWER',
project_url='https://app.com/projects/123'
)
Template: emails/project_shared.html
Available Templates
All templates are located in core/templates/emails/:
| Template | Purpose |
|---|---|
base.html |
Base template with styling and layout |
welcome.html |
Welcome new users |
password_reset.html |
Password reset instructions |
subscription_confirmation.html |
Subscription activated |
payment_failed.html |
Payment failure notification |
subscription_cancelled.html |
Subscription cancelled |
credit_low_warning.html |
Low credits warning |
invoice.html |
Invoice with download link |
team_invitation.html |
Workspace invitation |
project_shared.html |
Project access granted |
Creating Custom Email Templates
Step 1: Create Template File
Create a new HTML file in core/templates/emails/:
{% extends "emails/base.html" %}
{% block title %}Custom Email{% endblock %}
{% block header_title %}Your Custom Header{% endblock %}
{% block content %}
<h2>Hi {{ user_name }},</h2>
<p>Your custom email content goes here.</p>
<a href="{{ action_url }}" class="button">Call to Action</a>
<p>Best regards,<br>
The AppVector Team</p>
{% endblock %}
Step 2: Send Custom Email
from services.email_service import EmailService
EmailService.send_template_email(
to_email='[email protected]',
subject='Your Custom Email',
template_name='emails/your_custom_email.html',
context={
'user_name': 'John Doe',
'action_url': 'https://example.com/action'
}
)
Email Providers
Gmail Setup
- Enable 2-factor authentication on your Google account
- Generate an App Password: https://myaccount.google.com/apppasswords
- Use the app password (not your regular password):
EMAIL_HOST=smtp.gmail.com
EMAIL_PORT=587
EMAIL_USE_TLS=True
EMAIL_HOST_USER=[email protected]
EMAIL_HOST_PASSWORD=your-app-password
SendGrid Setup
- Sign up at https://sendgrid.com/
- Create an API key
- Configure:
EMAIL_HOST=smtp.sendgrid.net
EMAIL_PORT=587
EMAIL_USE_TLS=True
EMAIL_HOST_USER=apikey
EMAIL_HOST_PASSWORD=your-sendgrid-api-key
AWS SES Setup
- Set up SES in AWS Console
- Verify your domain or email
- Create SMTP credentials
- Configure:
EMAIL_HOST=email-smtp.us-east-1.amazonaws.com
EMAIL_PORT=587
EMAIL_USE_TLS=True
EMAIL_HOST_USER=your-ses-smtp-username
EMAIL_HOST_PASSWORD=your-ses-smtp-password
Testing
Test Email Sending
# In Django shell
python manage.py shell
from services.email_service import EmailService
# Test simple email
EmailService.send_simple_email(
to_email='[email protected]',
subject='Test Email',
message='This is a test email.'
)
# Test template email
from services.email_service import send_welcome_email
send_welcome_email(
user_email='[email protected]',
user_name='Test User'
)
Console Backend (Development)
With console backend, emails are printed to the terminal:
# In .env
EMAIL_BACKEND=django.core.mail.backends.console.EmailBackend
# Run server
docker compose up
# Send email - will appear in terminal
Integration Examples
In Webhook Handlers
# billing/webhooks.py
from services.email_service import (
send_subscription_confirmation_email,
send_payment_failed_email
)
def handle_invoice_payment_succeeded(invoice_data):
# ... existing code ...
# Send confirmation email
send_subscription_confirmation_email(
user_email=user.email,
user_name=user.first_name,
plan_name=subscription.plan.name,
amount=subscription.plan.monthly_price,
next_billing_date=subscription.current_period_end.strftime('%Y-%m-%d')
)
def handle_invoice_payment_failed(invoice_data):
# ... existing code ...
# Send failure notification
send_payment_failed_email(
user_email=user.email,
user_name=user.first_name,
plan_name=subscription.plan.name,
amount=invoice.total_amount,
retry_date=next_retry_date.strftime('%Y-%m-%d')
)
In Views
# workspaces/views.py
from services.email_service import send_team_invitation_email
class WorkspaceViewSet(viewsets.ModelViewSet):
@action(detail=True, methods=['post'])
def add_member(self, request, pk=None):
# ... existing code ...
# Send invitation email
send_team_invitation_email(
invitee_email=user_email,
inviter_name=request.user.get_full_name(),
workspace_name=workspace.name,
role=role,
invitation_url=f"{settings.FRONTEND_URL}/invite/{invitation_token}"
)
return Response(serializer.data)
Error Handling
All email functions have error handling built-in:
from services.email_service import EmailService
# Fail silently (returns False on error)
success = EmailService.send_simple_email(
to_email='[email protected]',
subject='Test',
message='Test',
fail_silently=True
)
if not success:
print("Email failed to send")
# Raise exception on error (default)
try:
EmailService.send_simple_email(
to_email='[email protected]',
subject='Test',
message='Test',
fail_silently=False # Default
)
except Exception as e:
print(f"Email error: {e}")
Best Practices
- Use Console Backend in Development
- Prevents accidentally sending emails during development
- Faster than SMTP
-
Easy to verify email content
-
Use Template-Based Emails
- Consistent branding
- Professional appearance
-
Mobile-responsive design
-
Include Plain Text Versions
- Automatically generated from HTML
- Better deliverability
-
Accessibility
-
Use Meaningful Subject Lines
- Clear and concise
- No spam trigger words
-
Personalize when possible
-
Monitor Email Sending
- Check application logs
- Use email provider's dashboard
-
Track bounce rates
-
Respect User Preferences
- Allow users to opt-out
- Send only necessary transactional emails
- Don't spam users
Troubleshooting
Emails Not Sending
- Check EMAIL_BACKEND is set correctly
- Verify SMTP credentials
- Check server logs for errors
- Ensure EMAIL_HOST_USER has permission to send
- Check firewall allows outbound SMTP connections
Gmail "Less Secure Apps" Error
Gmail no longer supports "less secure app" passwords. You must: 1. Enable 2-factor authentication 2. Generate an App Password 3. Use the App Password (16 characters)
Emails Going to Spam
- Verify your domain with email provider
- Set up SPF, DKIM, and DMARC records
- Use a reputable email provider
- Avoid spam trigger words
- Include unsubscribe links
Template Not Found Error
# Error: TemplateDoesNotExist at /...
# emails/my_template.html
# Solution: Check template path
# Templates should be in: core/templates/emails/
# Reference as: 'emails/my_template.html'
Related Documentation
Future Enhancements
Planned features:
- ❌ Email queue for asynchronous sending (Celery)
- ❌ Email analytics (open rates, click rates)
- ❌ User email preferences management
- ❌ Email templates in Django admin
- ❌ A/B testing for email content
- ❌ Scheduled emails