← Назад к вопросам

Как отправлять письма через Django?

1.6 Junior🔥 151 комментариев
#Django

Комментарии (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 система мощная и гибкая — выбирай подход в зависимости от потребностей проекта.

Как отправлять письма через Django? | PrepBro