A Django-based email forwarding service that manages mailing lists for the cyphy.life domain. It monitors a Gmail inbox for incoming emails addressed to @cyphy.life aliases and automatically forwards them to all active subscribers.
- Emails arrive at a Gmail inbox addressed to mailing list aliases (e.g.,
msgs@cyphy.life) - A background daemon polls Gmail IMAP every 60 seconds
- When it finds an email matching a mailing list alias, it forwards it to all active subscribers
- Forwarded emails preserve the original sender, threading, and attachments with a
[LISTNAME]subject prefix - Users can subscribe/unsubscribe via a web interface with email confirmation
- Python 3.9 / Django 4.2
- Gunicorn — WSGI server
- Supervisor — process manager (runs web server + email daemon)
- SQLite — database
- Gmail IMAP/SMTP — email sending and receiving
- Docker / Docker Compose — containerization
- Bootstrap 5 — frontend
- Python 3.9+
- A Gmail account with App Passwords enabled (requires 2FA)
- Docker & Docker Compose (for containerized deployment)
git clone <repo-url>
cd email_daemonEMAIL_ADDRESS=your-gmail@gmail.com
EMAIL_PASSWORD=your-gmail-app-passwordNote: You must use a Gmail App Password, not your regular Gmail password.
docker-compose up --buildThis will:
- Build the container
- Run database migrations
- Start Supervisor, which manages both the Django web server and the email daemon
The app will be available at http://localhost:8081.
# Create a virtual environment
python -m venv .venv
source .venv/bin/activate
# Install dependencies
pip install -r requirements.txt
# Run migrations
python manage.py migrate
# Start the web server (terminal 1)
python manage.py runserver 8081
# Start the email daemon (terminal 2)
python manage.py run_email_daemonemail_daemon/
├── emaildaemon/ # Django project config
│ ├── settings.py # Main settings (IMAP/SMTP, CSRF, logging)
│ ├── urls.py # URL routing
│ └── wsgi.py # WSGI entry point
├── emails/ # Main Django app
│ ├── models.py # MailingList & Subscriber models
│ ├── views.py # Subscribe/unsubscribe views
│ ├── forms.py # Subscription forms
│ ├── email_daemon.py # Email forwarding daemon
│ ├── utils.py # JWT tokens, email utilities
│ ├── admin.py # Django admin config
│ ├── management/commands/
│ │ └── run_email_daemon.py # Management command to start daemon
│ └── templates/emails/ # HTML templates
├── templates/
│ └── base.html # Base template (Bootstrap)
├── manage.py
├── requirements.txt
├── Dockerfile
├── docker-compose.yml
├── supervisord.conf
└── entrypoint.sh
| Route | Description |
|---|---|
/ |
Main page — subscribe, check subscriptions, unsubscribe |
/admin/ |
Django admin — manage mailing lists and subscribers |
/test-email/ |
Sends a test email to verify SMTP is working |
/unsubscribe/confirm/ |
Handles unsubscribe confirmation links (JWT) |
MailingList — an alias like msgs@cyphy.life with a description.
Subscriber — an email address subscribed to one or more mailing lists, with an active/inactive status.
Key settings in emaildaemon/settings.py:
| Setting | Value |
|---|---|
| Port | 8081 |
| IMAP server | imap.gmail.com |
| SMTP server | smtp.gmail.com:587 |
| Check interval | 60 seconds |
| JWT token expiry | 30 days |
| Gunicorn workers | 2 |
| Docker memory limit | 256MB |
Mailing lists are created through the Django admin at /admin/. Create a superuser first:
python manage.py createsuperuserThen log in at /admin/ and add mailing lists with their @cyphy.life aliases.