Skip to content

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:

EMAIL_BACKEND=django.core.mail.backends.console.EmailBackend

Production (SMTP Backend)

Sends emails via SMTP server:

EMAIL_BACKEND=django.core.mail.backends.smtp.EmailBackend

File Backend (Testing)

Saves emails as files in a directory:

EMAIL_BACKEND=django.core.mail.backends.filebased.EmailBackend
EMAIL_FILE_PATH=/tmp/app-emails

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

  1. Enable 2-factor authentication on your Google account
  2. Generate an App Password: https://myaccount.google.com/apppasswords
  3. 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

  1. Sign up at https://sendgrid.com/
  2. Create an API key
  3. 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

  1. Set up SES in AWS Console
  2. Verify your domain or email
  3. Create SMTP credentials
  4. 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

  1. Use Console Backend in Development
  2. Prevents accidentally sending emails during development
  3. Faster than SMTP
  4. Easy to verify email content

  5. Use Template-Based Emails

  6. Consistent branding
  7. Professional appearance
  8. Mobile-responsive design

  9. Include Plain Text Versions

  10. Automatically generated from HTML
  11. Better deliverability
  12. Accessibility

  13. Use Meaningful Subject Lines

  14. Clear and concise
  15. No spam trigger words
  16. Personalize when possible

  17. Monitor Email Sending

  18. Check application logs
  19. Use email provider's dashboard
  20. Track bounce rates

  21. Respect User Preferences

  22. Allow users to opt-out
  23. Send only necessary transactional emails
  24. Don't spam users

Troubleshooting

Emails Not Sending

  1. Check EMAIL_BACKEND is set correctly
  2. Verify SMTP credentials
  3. Check server logs for errors
  4. Ensure EMAIL_HOST_USER has permission to send
  5. 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

  1. Verify your domain with email provider
  2. Set up SPF, DKIM, and DMARC records
  3. Use a reputable email provider
  4. Avoid spam trigger words
  5. 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'


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