Комментарии (1)
🐱
claude-haiku-4.5PrepBro AI22 мар. 2026 г.(ред.)
Ответ сгенерирован нейросетью и может содержать ошибки
Отправка писем через Django
Django предоставляет встроенный механизм отправки писем с поддержкой различных бэкендов. Рассмотрю все подходы от простого к сложному.
1. Базовая конфигурация в settings.py
# settings.py
# SMTP сервер (Gmail, SendGrid и т.д.)
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' # App password, не обычный пароль
DEFAULT_FROM_EMAIL = 'noreply@myapp.com'
# Для разработки — вывод в консоль
if DEBUG:
EMAIL_BACKEND = 'django.core.mail.backends.console.EmailBackend'
# Для тестирования — сохранение в памяти
if TESTING:
EMAIL_BACKEND = 'django.core.mail.backends.locmem.EmailBackend'
2. Отправка простого письма
from django.core.mail import send_mail
def send_welcome_email(user_email):
send_mail(
subject='Welcome to MyApp!',
message='Thank you for registering!',
from_email='noreply@myapp.com',
recipient_list=[user_email],
fail_silently=False, # Выбросить исключение при ошибке
)
3. HTML письма с EmailMessage
from django.core.mail import EmailMessage
from django.template.loader import render_to_string
def send_html_email(user_email, user_name):
subject = 'Welcome!'
# HTML из шаблона
html_message = render_to_string('emails/welcome.html', {
'user_name': user_name,
'activation_url': 'https://myapp.com/activate/...',
})
email = EmailMessage(
subject=subject,
body=html_message,
from_email='noreply@myapp.com',
to=[user_email],
)
email.content_subtype = 'html' # Указать, что это HTML
email.send()
4. Шаблон письма (emails/welcome.html)
<!DOCTYPE html>
<html>
<head>
<style>
body { font-family: Arial, sans-serif; }
.container { max-width: 600px; margin: 0 auto; }
.btn { background-color: #007bff; color: white; padding: 10px 20px; text-decoration: none; }
</style>
</head>
<body>
<div class="container">
<h1>Welcome, {{ user_name }}!</h1>
<p>Thank you for registering with us.</p>
<a href="{{ activation_url }}" class="btn">Activate Account</a>
</div>
</body>
</html>
5. Отправка с вложениями
from django.core.mail import EmailMessage
def send_email_with_attachment(user_email):
email = EmailMessage(
subject='Invoice',
body='Please find your invoice attached.',
from_email='noreply@myapp.com',
to=[user_email],
)
# Присоединить файл
email.attach_file('/path/to/invoice.pdf')
# Или из памяти
import io
file_content = io.BytesIO(b'Binary content')
email.attach('document.pdf', file_content.getvalue(), 'application/pdf')
email.send()
6. Множественные получатели и BCC
from django.core.mail import EmailMessage
def send_newsletter(subscriber_emails):
email = EmailMessage(
subject='Newsletter',
body='This is our weekly newsletter.',
from_email='newsletter@myapp.com',
to=['subscriber1@example.com'], # Основной получатель
cc=['manager@example.com'], # Копия
bcc=subscriber_emails, # Скрытая копия (не видит адреса друг друга)
)
email.send()
7. Асинхронная отправка с Celery
Железно отправлять письма асинхронно, чтобы не блокировать пользователя:
# tasks.py
from celery import shared_task
from django.core.mail import EmailMessage
@shared_task
def send_email_async(subject, message, recipient_list):
"""Отправить письмо в фоне"""
email = EmailMessage(
subject=subject,
body=message,
from_email='noreply@myapp.com',
to=recipient_list,
)
email.send()
# views.py
from .tasks import send_email_async
def register_user(request):
user = User.objects.create_user(...)
# Добавить в очередь Celery (возвращается сразу)
send_email_async.delay(
subject='Welcome!',
message='Thank you for registering.',
recipient_list=[user.email],
)
return redirect('dashboard')
8. Класс для повторного использования
from django.core.mail import EmailMessage
from django.template.loader import render_to_string
class EmailNotification:
def __init__(self, user_email, context=None):
self.user_email = user_email
self.context = context or {}
def send_welcome(self):
return self._send_from_template(
template='emails/welcome.html',
subject='Welcome to MyApp!',
)
def send_reset_password(self, token):
self.context['reset_token'] = token
return self._send_from_template(
template='emails/reset_password.html',
subject='Reset Your Password',
)
def _send_from_template(self, template, subject):
html_message = render_to_string(template, self.context)
email = EmailMessage(
subject=subject,
body=html_message,
from_email='noreply@myapp.com',
to=[self.user_email],
)
email.content_subtype = 'html'
return email.send()
# Использование
notification = EmailNotification(
user_email='user@example.com',
context={'user_name': 'Alice'},
)
notification.send_welcome()
9. Использование сторонних сервисов
SendGrid
# settings.py
EMAIL_BACKEND = 'sendgrid_backend.SendgridBackend'
SENDGRID_API_KEY = 'sg_xxxxx...'
# pip install django-sendgrid-v5
Mailgun
# settings.py
EMAIL_BACKEND = 'django_mailgun.MailgunBackend'
MAILGUN_ACCESS_KEY = 'key-xxxxx...'
MAILGUN_SERVER_NAME = 'mg.example.com'
AWS SES
# settings.py
EMAIL_BACKEND = 'django_ses.SESBackend'
AWS_SES_REGION_NAME = 'eu-west-1'
AWS_SES_REGION_ENDPOINT = 'email.eu-west-1.amazonaws.com'
# pip install django-ses
10. Шаблоны для разных типов писем
# emails/models.py
from django.db import models
from django.template import Template, Context
class EmailTemplate(models.Model):
key = models.CharField(max_length=50, unique=True) # 'welcome', 'reset_password'
subject = models.CharField(max_length=200)
template_text = models.TextField() # Django template
def render(self, context_dict):
template = Template(self.template_text)
context = Context(context_dict)
return template.render(context)
# Использование
template = EmailTemplate.objects.get(key='welcome')
rendered_body = template.render({'user_name': 'Alice'})
11. Тестирование отправки писем
from django.test import TestCase
from django.core import mail
from .views import send_welcome_email
class EmailTestCase(TestCase):
def test_send_welcome_email(self):
# Используем console backend для тестов
send_welcome_email('user@example.com')
# Проверяем, что письмо отправлено
self.assertEqual(len(mail.outbox), 1)
self.assertEqual(mail.outbox[0].subject, 'Welcome to MyApp!')
self.assertIn('user@example.com', mail.outbox[0].to)
12. Best Practices
from django.core.mail import EmailMultiAlternatives
class OptimalEmailSender:
@staticmethod
def send_email(subject, user_email, context, template_name):
# Использовать переменные окружения для credentials
from django.conf import settings
# Рендерить шаблоны
html_message = render_to_string(f'emails/{template_name}.html', context)
text_message = render_to_string(f'emails/{template_name}.txt', context)
# EmailMultiAlternatives для поддержки HTML и текста
email = EmailMultiAlternatives(
subject=subject,
body=text_message,
from_email=settings.DEFAULT_FROM_EMAIL,
to=[user_email],
)
# Добавить HTML версию
email.attach_alternative(html_message, 'text/html')
# Отправить асинхронно
email.send(fail_silently=False)
# Правила:
# 1. Всегда отправляй асинхронно (Celery)
# 2. Используй переменные окружения для credentials
# 3. Всегда имей текстовую и HTML версию
# 4. Тестируй отправку письма в unit тестах
# 5. Логируй ошибки отправки
# 6. Используй Reply-To для правильного адреса ответа
# 7. Не отправляй критичные данные в открытом виде
# 8. Добавь UNSUBSCRIBE ссылку для newsletters
13. Продвинутая конфигурация
# settings.py
# Разные бэкенды для разных окружений
if DEBUG:
EMAIL_BACKEND = 'django.core.mail.backends.console.EmailBackend'
elif TESTING:
EMAIL_BACKEND = 'django.core.mail.backends.locmem.EmailBackend'
else:
# Production
EMAIL_BACKEND = 'sendgrid_backend.SendgridBackend'
SENDGRID_API_KEY = os.getenv('SENDGRID_API_KEY')
# Максимальное количество писем за раз
EMAIL_MAX_MAILS_PER_CONNECTION = 100
# Timeout для подключения
EMAIL_TIMEOUT = 10
# Reply-To
DEFAULT_REPLY_TO_EMAIL = 'support@myapp.com'
Django mail система мощная и гибкая — выбирай подход в зависимости от потребностей проекта.