Skip to content

Django - Sending E-mails

Django provides a convenient and robust API for sending emails, abstracting away the low-level details of SMTP (Simple Mail Transfer Protocol).

Before sending emails, you need to configure the email backend and connection details in your project’s settings.py file:

settings.py
EMAIL_BACKEND = 'django.core.mail.backends.smtp.EmailBackend'
EMAIL_HOST = 'smtp.example.com' # Your SMTP server address (e.g., smtp.gmail.com)
EMAIL_PORT = 587 # Common port for TLS
EMAIL_USE_TLS = True # Use TLS (Transport Layer Security) - Recommended
# EMAIL_USE_SSL = False # Use SSL (Secure Sockets Layer) - Less common now than TLS
EMAIL_HOST_USER = 'your_email@example.com' # Your SMTP username
EMAIL_HOST_PASSWORD = 'your_app_password' # Your SMTP password or App Password (e.g., for Gmail)
  • EMAIL_BACKEND: Specifies the backend to use. smtp.EmailBackend is standard. Others include console.EmailBackend (prints emails to console, great for development), filebased.EmailBackend (saves emails to files), and locmem.EmailBackend (stores emails in memory for testing).
  • EMAIL_HOST: The hostname or IP address of your SMTP server.
  • EMAIL_PORT: The port the SMTP server listens on (e.g., 587 for TLS, 465 for SSL, 25 for unencrypted - not recommended).
  • EMAIL_USE_TLS / EMAIL_USE_SSL: Boolean flags indicating whether to use a secure connection (TLS is generally preferred over SSL). They are mutually exclusive.
  • EMAIL_HOST_USER: Username for SMTP authentication.
  • EMAIL_HOST_PASSWORD: Password for SMTP authentication. Security Note: Avoid hardcoding credentials directly in settings.py. Use environment variables or a secrets management tool.
  • DEFAULT_FROM_EMAIL: (Optional) Sets a default ‘From’ address if not specified when sending mail. settings.py -> DEFAULT_FROM_EMAIL = 'webmaster@example.com'

The send_mail function is the quickest way to send a basic email.

# In a view or management command
from django.core.mail import send_mail
from django.http import HttpResponse
def send_simple_email_view(request):
try:
num_sent = send_mail(
'Test Subject',
'This is the email body message.',
'from@example.com', # Sender's email (often matches EMAIL_HOST_USER or DEFAULT_FROM_EMAIL)
['recipient1@example.com', 'recipient2@example.com'], # List of recipients
fail_silently=False, # If False (default), raises SMTPException on error
)
return HttpResponse(f'{num_sent} email(s) sent successfully.')
except Exception as e:
# Log the error e
return HttpResponse(f'Error sending email: {e}', status=500)
  • subject: Email subject line (string).
  • message: Plain text body of the email (string).
  • from_email: Sender’s email address (string).
  • recipient_list: A list or tuple of recipient email addresses (strings).
  • fail_silently: Boolean. If False (default), exceptions are raised. If True, errors are ignored silently (generally not recommended unless you have specific error handling).
  • auth_user, auth_password: Override settings.py credentials.
  • connection: Use a specific email backend connection.
  • html_message: Provide an HTML version of the email body. If provided, the email becomes multipart/alternative, and email clients will display the HTML version if possible, falling back to the plain text message.

Sending Multiple Emails Efficiently (send_mass_mail)

Section titled “Sending Multiple Emails Efficiently (send_mass_mail)”

To send multiple emails using a single connection (more efficient), use send_mass_mail.

from django.core.mail import send_mass_mail
from django.http import HttpResponse
def send_mass_email_view(request):
message1 = ('Subject 1', 'Message body 1', 'from@example.com', ['recipient1@example.com'])
message2 = ('Subject 2', 'Message body 2', 'from@example.com', ['recipient_other@example.com'])
datatuple = (message1, message2)
try:
num_sent = send_mass_mail(datatuple, fail_silently=False)
return HttpResponse(f'{num_sent} email(s) sent successfully using mass mail.')
except Exception as e:
# Log the error e
return HttpResponse(f'Error sending mass email: {e}', status=500)

send_mass_mail takes a tuple (datatuple) where each element is a tuple in the format (subject, message, from_email, recipient_list). Other arguments (fail_silently, auth_user, etc.) are similar to send_mail.

Sending HTML Emails and Attachments (EmailMessage)

Section titled “Sending HTML Emails and Attachments (EmailMessage)”

For more control, including HTML content, attachments, and headers, use the EmailMessage class.

from django.core.mail import EmailMessage
from django.http import HttpResponse
import os
from django.conf import settings # To access BASE_DIR for attachments
def send_html_email_with_attachment_view(request):
subject = 'Email with HTML and Attachment'
text_content = 'This is an important message.' # Plain text fallback
html_content = '<p>This is an **important** message in HTML.</p>'
from_email = 'from@example.com'
to = ['recipient@example.com']
try:
email = EmailMessage(subject, text_content, from_email, to)
email.attach_alternative(html_content, "text/html")
# Optional: Attach a file
# attachment_path = os.path.join(settings.BASE_DIR, 'path/to/your/file.pdf')
# if os.path.exists(attachment_path):
# email.attach_file(attachment_path)
# Or attach content directly:
# email.attach('filename.txt', 'File content here', 'text/plain')
num_sent = email.send()
return HttpResponse(f'{num_sent} HTML email(s) sent.')
except Exception as e:
# Log the error e
return HttpResponse(f'Error sending HTML email: {e}', status=500)
  • Initialization: EmailMessage(subject, body, from_email, to, bcc=None, connection=None, attachments=None, headers=None, cc=None, reply_to=None)
  • send(fail_silently=False): Sends the email.
  • attach(filename, content, mimetype): Attaches content generated in code.
  • attach_file(path, mimetype=None): Attaches a file from the filesystem.
  • attach_alternative(content, mimetype): Adds alternative content types (commonly used for text/html).

Emails to Admins and Managers (mail_admins, mail_managers)

Section titled “Emails to Admins and Managers (mail_admins, mail_managers)”

Django provides shortcuts to email administrators and managers defined in settings.py:

settings.py
ADMINS = [('Admin Name', 'admin@example.com'),]
MANAGERS = [('Manager Name', 'manager@example.com'),]
from django.core.mail import mail_admins, mail_managers
from django.http import HttpResponse
def notify_admins_view(request):
try:
mail_admins('Site Critical Alert', 'The site needs immediate attention!', fail_silently=False)
# mail_managers('Site Update', 'Content needs review.', fail_silently=False)
return HttpResponse('Notification email sent.')
except Exception as e:
return HttpResponse(f'Error sending admin/manager email: {e}', status=500)

These functions prepend the EMAIL_SUBJECT_PREFIX setting (default: [Django] ) to the subject.

During development, avoid sending real emails. Use the console or file-based backend:

# settings.py (for development)
EMAIL_BACKEND = 'django.core.mail.backends.console.EmailBackend'

Alternatively, use tools like MailHog or Mailtrap which set up a local fake SMTP server to catch outgoing emails for inspection without actually sending them.

Sending emails can sometimes be slow and block the web request. For production applications, especially those sending emails frequently or during user requests, it’s highly recommended to send emails asynchronously using a task queue like Celery with Redis or RabbitMQ. This offloads the email sending task to a background worker process, keeping your web application responsive.