Email is an essential feature in modern web applications — for account activation, password resets, notifications, contact forms, and more. Django makes it easy to send emails using its built-in EmailMessage
and send_mail
functionalities.
In this article, we’ll cover:
-
Django email settings
-
Sending plain text and HTML emails
-
Sending attachments
-
Using console, SMTP, and third-party email services
-
Best practices and common errors
✅ Prerequisites
Before you start:
-
Django should be installed (
pip install django
) -
A Django project should be initialized (
django-admin startproject
)
⚙️ Step 1: Configure Email Settings in settings.py
Start by adding the following to your settings.py
. These are needed for SMTP-based sending (e.g., using Gmail).
# settings.py
EMAIL_BACKEND = 'django.core.mail.backends.smtp.EmailBackend'
EMAIL_HOST = 'smtp.gmail.com' # For Gmail
EMAIL_PORT = 587
EMAIL_USE_TLS = True
EMAIL_HOST_USER = '[email protected]' # Replace with your email
EMAIL_HOST_PASSWORD = 'your_app_password' # Use App Passwords or SMTP credentials
DEFAULT_FROM_EMAIL = EMAIL_HOST_USER
Important: If using Gmail, enable “Less secure app access” or use App Passwords with 2FA enabled.
Step 2: Send a Simple Email
Django provides the send_mail()
function.
from django.core.mail import send_mail
def send_simple_email():
send_mail(
subject='Welcome to Django!',
message='Thank you for joining our site.',
from_email='[email protected]',
recipient_list=['[email protected]'],
fail_silently=False,
)
✅ Run this inside a view, signal, or shell (
python manage.py shell
).
Step 3: Send HTML Email
To send emails with rich formatting, pass the html_message
argument:
def send_html_email():
send_mail(
subject='Your Receipt',
message='This is a fallback text message.',
from_email='[email protected]',
recipient_list=['[email protected]'],
html_message="""
<h1>Thank You for Your Purchase</h1>
<p>We appreciate your business.</p>
""",
fail_silently=False,
)
Step 4: Send Emails with Attachments
Use the EmailMessage
class for advanced usage:
from django.core.mail import EmailMessage
def send_email_with_attachment():
email = EmailMessage(
subject='Invoice Attached',
body='Please find the invoice attached.',
from_email='[email protected]',
to=['[email protected]'],
)
email.attach_file('invoices/invoice.pdf')
email.send()
Testing Locally with the Console Backend
To avoid sending real emails during development, use the console backend.
# settings.py
EMAIL_BACKEND = 'django.core.mail.backends.console.EmailBackend'
Django will print emails to the terminal:
python manage.py runserver
Visit the page that triggers email sending, and the content will appear in the terminal.
Using the File-Based Email Backend
You can write emails to a file during testing:
EMAIL_BACKEND = 'django.core.mail.backends.filebased.EmailBackend'
EMAIL_FILE_PATH = BASE_DIR / 'sent_emails'
Check the sent_emails/
folder to inspect the emails.
Using Third-Party Services
For production, it’s better to use services like:
Provider | Notes |
---|---|
SendGrid | Free tier, great API |
Mailgun | Reliable and developer-friendly |
Amazon SES | Cost-effective and scalable |
SMTP2GO | Simple SMTP configuration |
You can use their SMTP credentials directly in Django or integrate via APIs using packages like django-anymail
.
Full Working View Example
Here’s a view that sends an email when visited:
# views.py
from django.core.mail import send_mail
from django.http import HttpResponse
def send_email_view(request):
send_mail(
'Hello from Django',
'This is a test email sent from a Django view.',
'[email protected]',
['[email protected]'],
fail_silently=False,
)
return HttpResponse('Email sent successfully!')
# urls.py
from django.urls import path
from .views import send_email_view
urlpatterns = [
path('send-email/', send_email_view),
]
Visit http://localhost:8000/send-email/
to test.
⚠️ Common Errors & Fixes
Error | Cause | Solution |
---|---|---|
SMTPAuthenticationError |
Wrong password or 2FA enabled | Use App Password with Gmail |
ConnectionRefusedError |
SMTP server not reachable | Check EMAIL_HOST and EMAIL_PORT |
Email not sending | fail_silently=True |
Set to False to debug |
Timeout | Slow or blocked connection | Check firewall or try a different provider |
HTML not rendering | Sent as plain text | Use html_message or EmailMultiAlternatives |
Tips & Best Practices
-
✅ Use
get_connection()
for sending multiple emails in bulk efficiently -
✅ Always use
fail_silently=False
during development -
✅ Store sensitive credentials in environment variables or
.env
files -
✅ Use a separate email account for app-based messaging
-
✅ Avoid hardcoding emails — use
settings.DEFAULT_FROM_EMAIL
Summary
Feature | Functionality |
---|---|
send_mail() |
Simple, quick emails |
EmailMessage |
Attachments, headers, and more |
html_message |
Send styled content |
Console backend | Development email output |
SMTP backend | Production delivery |
Bonus: Send Templated HTML Email with Context
from django.template.loader import render_to_string
from django.core.mail import EmailMessage
def send_templated_email():
context = {'username': 'Alice'}
html_content = render_to_string('emails/welcome.html', context)
email = EmailMessage(
subject='Welcome!',
body=html_content,
from_email='[email protected]',
to=['[email protected]']
)
email.content_subtype = 'html'
email.send()