Celery + RabbitMQ + Jinja + .env do wysyłki maili.
Minimalny, działający przykład, który można od razu uruchomić na wielu workerach.
celery_mail_demo/ ├── celery_app.py ├── tasks.py ├── templates/ │ └── mail/ │ └── report.html ├── .env ├── requirements.txt └── run_worker.sh
requirements.txt
celery==5.3.1 jinja2 python-dotenv
.env
# RabbitMQ BROKER_URL=amqp://celery:secret@192.168.0.150:5672/analysis # SMTP SMTP_HOST=smtp.example.com SMTP_PORT=587 SMTP_USER=noreply@example.com SMTP_PASSWORD=SECRET SMTP_FROM=noreply@example.com
celery_app.py
import os
from celery import Celery
from dotenv import load_dotenv
load_dotenv() # wczytuje .env
celery = Celery(
"mail_demo",
broker=os.environ["BROKER_URL"],
backend="rpc://"
)
tasks.py
import os
from celery_app import celery
from jinja2 import Environment, FileSystemLoader
from email.message import EmailMessage
import smtplib
from datetime import datetime
BASE_DIR = os.path.dirname(os.path.abspath(__file__))
jinja_env = Environment(
loader=FileSystemLoader(os.path.join(BASE_DIR, "templates"))
)
def _send_smtp(msg):
with smtplib.SMTP(os.environ["SMTP_HOST"], int(os.environ["SMTP_PORT"]), timeout=30) as smtp:
smtp.starttls()
smtp.login(os.environ["SMTP_USER"], os.environ["SMTP_PASSWORD"])
smtp.send_message(msg)
@celery.task(bind=True, autoretry_for=(Exception,), retry_backoff=30, retry_kwargs={"max_retries": 3})
def send_report_mail(self, to, station, start, end, results):
template = jinja_env.get_template("mail/report.html")
html = template.render(
station=station,
start=start,
end=end,
results=results,
generated_at=datetime.utcnow().isoformat()
)
msg = EmailMessage()
msg["From"] = os.environ["SMTP_FROM"]
msg["To"] = to
msg["Subject"] = f"Raport {station}"
msg.set_content("Ten email zawiera raport HTML.")
msg.add_alternative(html, subtype="html")
_send_smtp(msg)
Szablon Jinja – templates/mail/report.html
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
</head>
<body>
<h2>Raport dla stacji {{ station }}</h2>
<p>Zakres: {{ start }} – {{ end }}</p>
<ul>
{% for key, value in results.items() %}
<li><b>{{ key }}</b>: {{ value }}</li>
{% endfor %}
</ul>
<p style="color: gray; font-size: 12px">Wygenerowano: {{ generated_at }}</p>
</body>
</html>
Skrypt uruchamiający worker – run_worker.sh
#!/bin/bash source venv/bin/activate export $(cat .env | xargs) # wczytuje zmienne środowiskowe z .env celery -A celery_app.celery worker --loglevel=info --concurrency=2
Co MUSI być na każdym workerze
- Ten sam kod: celery_app.py + tasks.py
- Szablony Jinja: templates/mail/report.html
- .env (lub ENV w systemd)
- Python + venv + dependencies
- Dostęp do SMTP i RabbitMQ
Uruchomienie workera
pip install -r requirements.txt chmod +x run_worker.sh ./run_worker.sh
Przykład wywołania zadania z Python (CLI)
from tasks import send_report_mail
send_report_mail.delay(
to="user@example.com",
station="ST001",
start="2025-12-01",
end="2025-12-29",
results={"temp_avg": 23, "humidity": 70}
)