Installation

This guide will help you install and configure Django Email Learning in your Django project.

Prerequisites

  • Python 3.10 or higher

  • Django 5.0 or higher

  • A configured email backend (for sending course emails)

Installation Steps

  1. Install the Package

    Install Django Email Learning via pip:

    pip install django-email-learning
    

    If you want to use AI editing tools, install with the AI optional extra:

    pip install 'django-email-learning[ai]'
    
  2. Add to INSTALLED_APPS

    Add ‘django_email_learning’ to your INSTALLED_APPS in settings.py:

    INSTALLED_APPS = [
        # ... your other apps
        'django_email_learning',
        # ... more apps
    ]
    
  3. Run Database Migrations

    Create the necessary database tables:

    python manage.py migrate django_email_learning
    
  4. Configure URLs

    Add Django Email Learning URLs to your project’s main urls.py:

    from django.urls import path, include
    
    urlpatterns = [
        # ... your other URL patterns
        path('email-learning/', include('django_email_learning.urls')),
        # ... more URL patterns
    ]
    

    You can change email-learning/ to any URL path you prefer. This will make:

    • Platform (Admin Interface): Available at /email-learning/platform/

    • Public Course Pages: Available at /email-learning/public/organization/<org_id>/

    • API Endpoints: Available under /email-learning/api/

Access Control

Platform Access

The course management platform (/platform/) requires authentication and is accessible to:

  • Django superusers

  • Users assigned as Organization users (managed via Django admin panel)

Note

Since the platform views require authentication, ensure your Django project has authentication views configured. You can use Django’s built-in authentication views by including them in your URLconf. See Django’s authentication views documentation for setup instructions.

Public Access

Public course enrollment pages are accessible without authentication and are designed for learners to discover and enroll in courses.

Configuration

Django Email Learning requires specific configuration in your Django settings. Add a DJANGO_EMAIL_LEARNING dictionary to your settings.py:

Required Settings

SITE_BASE_URL

The base URL of your site, used to generate absolute URLs in emails and course links.

ENCRYPTION_SECRET_KEY

A secret key used for encrypting sensitive data. It should be a long, random string. This will be used for encrypting API keys and IMAP passwords. This key will be used for bidirectional encryption/decryption, so keep it secure.

Same as all other sensitive configurations, it’s a good practice to load this from an environment variable or a secure vault.

Important

Changing this key after data has been created will prevent access to previously encrypted data. Chaning requires re-encrypting all existing data with the new key.

JWT_SECRET_KEY

A dedicated secret key used for signing and verifying JSON Web Tokens (JWTs). It should be a long, random string, independent of Django’s SECRET_KEY and ENCRYPTION_SECRET_KEY.

Using a separate key ensures that a JWT secret compromise does not affect other parts of your application.

Same as all other sensitive configurations, it’s a good practice to load this from an environment variable or a secure vault.

DJANGO_EMAIL_LEARNING = {
    'SITE_BASE_URL': 'https://yourdomain.com',
    'ENCRYPTION_SECRET_KEY': 'your-very-long-random-string',
    'JWT_SECRET_KEY': 'another-very-long-random-string',
}

Optional Settings

FROM_EMAIL

The default email address for outgoing course emails. If not specified, falls back to Django’s DEFAULT_FROM_EMAIL setting.

DJANGO_EMAIL_LEARNING = {
    'SITE_BASE_URL': 'https://yourdomain.com',
    'ENCRYPTION_SECRET_KEY': 'your-very-long-random-string',
    'JWT_SECRET_KEY': 'another-very-long-random-string',
    'FROM_EMAIL': 'courses@yourdomain.com',
}

TERMS_OF_SERVICE_URL

Optional link to your terms of service. When provided, this link is displayed in the public enrollment dialog so learners can review your terms before submitting their email address.

DJANGO_EMAIL_LEARNING = {
    'SITE_BASE_URL': 'https://yourdomain.com',
    'ENCRYPTION_SECRET_KEY': 'your-very-long-random-string',
    'JWT_SECRET_KEY': 'another-very-long-random-string',
    'TERMS_OF_SERVICE_URL': 'https://yourdomain.com/terms',
}

QUIZ_DEFAULTS

Optional configuration for the initial default values shown in the quiz form when creating a new quiz.

All values are boolean.

  • LIMITED_ATTEMPTS: Sets the default state of the Limited Attempts switch. When enabled, learners only have 2 attempts to pass the quiz. When disabled, learners can retry as many times as needed.

  • IS_BLOCKING: Sets the default state of the Blocking Quiz switch. When enabled, learners must pass the quiz to continue receiving course content. When disabled, the quiz is treated as practice and does not gate course progress.

  • HAS_DEADLINE: Sets the default state of the quiz deadline switch. When enabled, new quizzes start with a deadline. When disabled, new quizzes default to having no deadline.

DJANGO_EMAIL_LEARNING = {
    'SITE_BASE_URL': 'https://yourdomain.com',
    'ENCRYPTION_SECRET_KEY': 'your-very-long-random-string',
    'JWT_SECRET_KEY': 'another-very-long-random-string',
    'QUIZ_DEFAULTS': {
        'LIMITED_ATTEMPTS': True,
        'IS_BLOCKING': True,
        'HAS_DEADLINE': True,
    },
}

SIDEBAR.CUSTOM_COMPONENT

Optional configuration for injecting a custom component in the platform sidebar.

  • SCRIPT_URL: URL of the JavaScript module that registers your custom element.

  • STYLE_URL: Optional stylesheet URL for the component (use None if not needed).

  • COMPONENT_TAG: HTML tag rendered in the sidebar.

DJANGO_EMAIL_LEARNING = {
    'SITE_BASE_URL': 'https://yourdomain.com',
    'ENCRYPTION_SECRET_KEY': 'your-very-long-random-string',
    'JWT_SECRET_KEY': 'another-very-long-random-string',
    'SIDEBAR': {
        'CUSTOM_COMPONENT': {
            'SCRIPT_URL': 'url/path-to-your-component.js',
            'STYLE_URL': 'url/path-to-your-component.css',
            'COMPONENT_TAG': '<your-component />',
        }
    },
}

LOGO

Optional configuration for branding assets in the platform header.

  • HORIZONTAL_LOCKUP: Used on mobile devices where the sidebar is not open by default and the logo is shown in the top navbar.

  • VERTICAL_LOCKUP: Used for sidebar-oriented layouts.

    • LIGHT_BACKGROUND: Logo URL/path for light backgrounds.

    • DARK_BACKGROUND: Logo URL/path for dark backgrounds.

DJANGO_EMAIL_LEARNING = {
    'SITE_BASE_URL': 'https://yourdomain.com',
    'ENCRYPTION_SECRET_KEY': 'your-very-long-random-string',
    'JWT_SECRET_KEY': 'another-very-long-random-string',
    'LOGO': {
        'HORIZONTAL_LOCKUP': {
            'LIGHT_BACKGROUND': 'url/path-to-horizontal-logo-for-light-background.png',
            'DARK_BACKGROUND': 'url/path-to-horizontal-logo-for-dark-background.png',
        },
        'VERTICAL_LOCKUP': {
            'LIGHT_BACKGROUND': 'url/path-to-vertical-logo-for-light-background.png',
            'DARK_BACKGROUND': 'url/path-to-vertical-logo-for-dark-background.png',
        },
    },
}

PRIVATE_FILE_STORAGE_LOCATION

The filesystem path where privately uploaded files will be stored. Unlike media files served via Django’s MEDIA_URL which are publicly accessible, files stored here are not served publicly. They are only accessible through an authenticated endpoint, ensuring that sensitive files (such as assignment submissions or certificates) are protected and only available to authorised users.

If not specified, a default location will be used.

DJANGO_EMAIL_LEARNING = {
    'SITE_BASE_URL': 'https://yourdomain.com',
    'ENCRYPTION_SECRET_KEY': 'your-very-long-random-string',
    'JWT_SECRET_KEY': 'another-very-long-random-string',
    'PRIVATE_FILE_STORAGE_LOCATION': '/path/to/private/storage/',
}

Note

Ensure the directory exists and that the Django process has read/write permissions for the specified path. Do not place this directory inside your web server’s publicly served document root, as doing so would defeat the purpose of private storage.

AI

Optional configuration for AI-powered text editing features.

  • Configure this only if you have an OpenAI account and want to use AI edit tools.

  • If you do not use AI features, you can omit AI entirely.

  • Install AI dependencies with pip install 'django-email-learning[ai]'.

  • Add 'django_email_learning.ai' to INSTALLED_APPS when using AI tools.

INSTALLED_APPS = [
    # ... your other apps
    'django_email_learning',
    'django_email_learning.ai',
    # ... more apps
]

Available keys:

  • OPENAI_API_KEY: OpenAI API key used for AI requests.

  • TEXT_EDITING_MODEL: OpenAI model name used by text editing.

Currently supported built-in models are:

  • gpt-4o-mini

  • gpt-5-nano

  • gpt-5-mini

from django_email_learning.ai.language_models import LanguageModel

DJANGO_EMAIL_LEARNING = {
    'SITE_BASE_URL': 'https://yourdomain.com',
    'ENCRYPTION_SECRET_KEY': 'your-very-long-random-string',
    'JWT_SECRET_KEY': 'another-very-long-random-string',
    'AI': {
        'OPENAI_API_KEY': os.environ.get('OPENAI_API_KEY'),
        'TEXT_EDITING_MODEL': LanguageModel.GPT_4O_MINI.model_name,
    },
}

See AI Configuration for full details.

AMP_ENABLED

Optional flag to enable AMP email rendering for supported clients.

By default, AMP email support is disabled. Enable it only after your sending domain is registered as a dynamic email sender with Google:

Register dynamic email with Google

If AMP is enabled, you must also add trusted AMP mail client origins to Django’s CSRF_TRUSTED_ORIGINS so AMP form submissions are accepted.

DJANGO_EMAIL_LEARNING = {
    'SITE_BASE_URL': 'https://yourdomain.com',
    'ENCRYPTION_SECRET_KEY': 'your-very-long-random-string',
    'JWT_SECRET_KEY': 'another-very-long-random-string',
    'AMP_ENABLED': True,
}

CSRF_TRUSTED_ORIGINS = [
    'https://mail.google.com',
    'https://playground.amp.dev', # ⚠️ Do not include this in production - it's only needed for testing with the AMP playground
    # Add any other trusted AMP mail client origins you use
]

Note

Keep AMP disabled in environments where you have not completed sender registration and trusted-origin configuration.

Email Backend Configuration

Django Email Learning sends course content and notifications via email. Ensure your Django project has a properly configured email backend:

# Example SMTP configuration
EMAIL_BACKEND = 'django.core.mail.backends.smtp.EmailBackend'
EMAIL_HOST = 'smtp.gmail.com'
EMAIL_PORT = 587
EMAIL_USE_TLS = True
EMAIL_HOST_USER = 'your-email@gmail.com'
EMAIL_HOST_PASSWORD = 'your-app-password'
DEFAULT_FROM_EMAIL = 'your-email@gmail.com'

Management Command Scheduling

To automate content delivery, schedule the deliver_contents management command to run at regular intervals (e.g., every 15-60 minutes) using a task scheduler like cron or Celery Beat.

See Management Commands for more details.