Django Email Sending: SMTP Configuration and Email Templates

Email communication enables applications to send notifications, confirmations, password resets, newsletters, and transactional messages keeping users informed and engaged. Django's email framework provides comprehensive infrastructure for sending emails through SMTP servers supporting simple text emails, HTML emails with styling, attachments, bulk mailing, and email templates. This system integrates seamlessly with Django's authentication system for password resets, user registration confirmations, and notification workflows. This comprehensive guide explores Django 6.0 email capabilities including configuring SMTP settings for Gmail, SendGrid, and custom servers, sending simple emails with send_mail function, creating HTML emails with EmailMessage class, using email templates for consistent formatting, attaching files and inline images, sending bulk emails efficiently, handling email errors and failures, implementing email backends for development and testing, and best practices for email deliverability. Mastering email sending enables building professional applications with reliable communication channels from account notifications to marketing campaigns.
SMTP Configuration
SMTP configuration establishes connection parameters for email servers including hostname, port, authentication credentials, and security settings. Django supports various email backends including SMTP for production, console for development, file-based for testing, and third-party services like SendGrid or AWS SES. Proper SMTP configuration ensures reliable email delivery while development backends facilitate testing without sending real emails.
# settings.py - SMTP Configuration
# Gmail SMTP settings
EMAIL_BACKEND = 'django.core.mail.backends.smtp.EmailBackend'
EMAIL_HOST = 'smtp.gmail.com'
EMAIL_PORT = 587
EMAIL_USE_TLS = True
EMAIL_HOST_USER = '[email protected]'
EMAIL_HOST_PASSWORD = 'your-app-password' # Use app-specific password
DEFAULT_FROM_EMAIL = '[email protected]'
SERVER_EMAIL = '[email protected]'
# SendGrid configuration
EMAIL_HOST = 'smtp.sendgrid.net'
EMAIL_PORT = 587
EMAIL_USE_TLS = True
EMAIL_HOST_USER = 'apikey'
EMAIL_HOST_PASSWORD = 'your-sendgrid-api-key'
# Amazon SES configuration
EMAIL_HOST = 'email-smtp.us-east-1.amazonaws.com'
EMAIL_PORT = 587
EMAIL_USE_TLS = True
EMAIL_HOST_USER = 'your-ses-smtp-username'
EMAIL_HOST_PASSWORD = 'your-ses-smtp-password'
# Custom SMTP server
EMAIL_HOST = 'smtp.yourserver.com'
EMAIL_PORT = 465 # SSL port
EMAIL_USE_SSL = True
EMAIL_HOST_USER = 'your-username'
EMAIL_HOST_PASSWORD = 'your-password'
# Development: Console backend (prints to console)
if DEBUG:
EMAIL_BACKEND = 'django.core.mail.backends.console.EmailBackend'
# Testing: File backend (saves to files)
EMAIL_BACKEND = 'django.core.mail.backends.filebased.EmailBackend'
EMAIL_FILE_PATH = '/tmp/app-emails'
# Dummy backend (discards emails)
EMAIL_BACKEND = 'django.core.mail.backends.dummy.EmailBackend'
# Email timeout settings
EMAIL_TIMEOUT = 10 # seconds
# Environment variables (recommended for production)
import os
EMAIL_HOST = os.getenv('EMAIL_HOST', 'smtp.gmail.com')
EMAIL_PORT = int(os.getenv('EMAIL_PORT', 587))
EMAIL_USE_TLS = os.getenv('EMAIL_USE_TLS', 'True') == 'True'
EMAIL_HOST_USER = os.getenv('EMAIL_HOST_USER')
EMAIL_HOST_PASSWORD = os.getenv('EMAIL_HOST_PASSWORD')
DEFAULT_FROM_EMAIL = os.getenv('DEFAULT_FROM_EMAIL', '[email protected]')Sending Simple Emails
Django provides send_mail function for simple email sending accepting subject, message, sender, and recipient list. For advanced features including HTML content, attachments, and custom headers, use EmailMessage class offering complete control over email construction. Both approaches handle connection management, error handling, and SMTP protocol communication automatically.
# Simple email with send_mail
from django.core.mail import send_mail
from django.conf import settings
def send_welcome_email(user):
subject = 'Welcome to Our Platform'
message = f'Hi {user.username},\n\nThank you for registering!'
from_email = settings.DEFAULT_FROM_EMAIL
recipient_list = [user.email]
send_mail(
subject,
message,
from_email,
recipient_list,
fail_silently=False, # Raise exception on error
)
# Send multiple emails with send_mass_mail
from django.core.mail import send_mass_mail
def send_bulk_notifications(users):
messages = []
for user in users:
message = (
f'Notification for {user.username}',
f'Hi {user.username}, you have a new notification.',
settings.DEFAULT_FROM_EMAIL,
[user.email]
)
messages.append(message)
send_mass_mail(messages, fail_silently=False)
# Advanced email with EmailMessage
from django.core.mail import EmailMessage
def send_custom_email(to_email, subject, body):
email = EmailMessage(
subject=subject,
body=body,
from_email=settings.DEFAULT_FROM_EMAIL,
to=[to_email],
bcc=['[email protected]'], # Blind carbon copy
reply_to=['[email protected]'], # Reply-to address
headers={'Message-ID': 'unique-id'}, # Custom headers
)
email.send()
# HTML email
def send_html_email(user):
subject = 'Welcome'
html_message = f'''
<html>
<body>
<h1>Welcome {user.username}!</h1>
<p>Thank you for <strong>registering</strong>.</p>
</body>
</html>
'''
plain_message = f'Welcome {user.username}! Thank you for registering.'
from django.core.mail import send_mail
send_mail(
subject,
plain_message,
settings.DEFAULT_FROM_EMAIL,
[user.email],
html_message=html_message,
)
# Alternative: EmailMultiAlternatives
from django.core.mail import EmailMultiAlternatives
def send_multipart_email(user):
subject = 'Welcome'
text_content = f'Welcome {user.username}!'
html_content = f'<h1>Welcome {user.username}!</h1>'
email = EmailMultiAlternatives(
subject,
text_content,
settings.DEFAULT_FROM_EMAIL,
[user.email]
)
email.attach_alternative(html_content, "text/html")
email.send()
# Send email with error handling
import logging
logger = logging.getLogger(__name__)
def safe_send_email(subject, message, recipient):
try:
send_mail(
subject,
message,
settings.DEFAULT_FROM_EMAIL,
[recipient],
fail_silently=False,
)
logger.info(f'Email sent to {recipient}')
return True
except Exception as e:
logger.error(f'Failed to send email to {recipient}: {str(e)}')
return FalseEmail Templates
Email templates separate content from code enabling consistent formatting, easy updates, and designer-friendly email management. Django templates work for emails supporting variables, filters, and template inheritance. Using render_to_string function renders templates to strings suitable for email bodies. Template-based emails maintain professional appearance across email clients while allowing dynamic content insertion.
# Email templates
# templates/emails/welcome_email.txt
"""
Hi {{ user.username }},
Welcome to {{ site_name }}!
Your account has been created successfully.
Username: {{ user.username }}
Email: {{ user.email }}
Please verify your email by clicking the link below:
{{ verification_link }}
Best regards,
The {{ site_name }} Team
"""
# templates/emails/welcome_email.html
"""
<!DOCTYPE html>
<html>
<head>
<style>
body { font-family: Arial, sans-serif; line-height: 1.6; }
.header { background: #007bff; color: white; padding: 20px; text-align: center; }
.content { padding: 20px; }
.button { background: #28a745; color: white; padding: 10px 20px; text-decoration: none; border-radius: 5px; display: inline-block; }
</style>
</head>
<body>
<div class="header">
<h1>Welcome to {{ site_name }}</h1>
</div>
<div class="content">
<p>Hi {{ user.username }},</p>
<p>Your account has been created successfully!</p>
<p><strong>Username:</strong> {{ user.username }}</p>
<p><strong>Email:</strong> {{ user.email }}</p>
<p>
<a href="{{ verification_link }}" class="button">Verify Your Email</a>
</p>
<p>Best regards,<br>The {{ site_name }} Team</p>
</div>
</body>
</html>
"""
# Using email templates
from django.template.loader import render_to_string
from django.core.mail import EmailMultiAlternatives
from django.conf import settings
def send_welcome_email_template(user, verification_link):
context = {
'user': user,
'site_name': 'My Platform',
'verification_link': verification_link
}
# Render templates
text_content = render_to_string('emails/welcome_email.txt', context)
html_content = render_to_string('emails/welcome_email.html', context)
# Create email
email = EmailMultiAlternatives(
subject='Welcome to My Platform',
body=text_content,
from_email=settings.DEFAULT_FROM_EMAIL,
to=[user.email]
)
email.attach_alternative(html_content, "text/html")
email.send()
# Reusable email function
def send_template_email(template_name, context, subject, to_email):
"""
Generic function to send template-based emails
"""
text_content = render_to_string(f'emails/{template_name}.txt', context)
html_content = render_to_string(f'emails/{template_name}.html', context)
email = EmailMultiAlternatives(
subject=subject,
body=text_content,
from_email=settings.DEFAULT_FROM_EMAIL,
to=[to_email]
)
email.attach_alternative(html_content, "text/html")
email.send()
# Usage
context = {'user': user, 'order_number': '12345', 'total': 99.99}
send_template_email(
'order_confirmation',
context,
'Order Confirmation',
user.email
)
# Email with inline images
from django.core.mail import EmailMessage
from django.conf import settings
import os
def send_email_with_logo(user):
email = EmailMessage(
'Welcome',
'<h1>Welcome!</h1><img src="cid:logo">',
settings.DEFAULT_FROM_EMAIL,
[user.email]
)
email.content_subtype = 'html'
# Attach inline image
logo_path = os.path.join(settings.BASE_DIR, 'static/images/logo.png')
with open(logo_path, 'rb') as f:
email.attach('logo.png', f.read(), 'image/png')
email.send()Email Attachments
Email attachments enable sending files like PDFs, images, or documents alongside email messages. Django's EmailMessage class provides attach and attach_file methods for including file data or file paths. Attachments support various file types with automatic MIME type detection ensuring proper handling across email clients.
# Email with file attachment
from django.core.mail import EmailMessage
from django.conf import settings
def send_invoice_email(user, invoice_pdf_path):
email = EmailMessage(
subject='Your Invoice',
body='Please find your invoice attached.',
from_email=settings.DEFAULT_FROM_EMAIL,
to=[user.email]
)
# Attach file from path
email.attach_file(invoice_pdf_path)
email.send()
# Attach generated content
from io import BytesIO
from reportlab.pdfgen import canvas
def send_generated_pdf(user):
# Generate PDF in memory
buffer = BytesIO()
p = canvas.Canvas(buffer)
p.drawString(100, 750, f"Report for {user.username}")
p.showPage()
p.save()
# Create email
email = EmailMessage(
'Your Report',
'Please find your report attached.',
settings.DEFAULT_FROM_EMAIL,
[user.email]
)
# Attach PDF from buffer
email.attach('report.pdf', buffer.getvalue(), 'application/pdf')
email.send()
# Multiple attachments
def send_email_with_multiple_files(user, file_paths):
email = EmailMessage(
'Your Documents',
'Please find your documents attached.',
settings.DEFAULT_FROM_EMAIL,
[user.email]
)
for file_path in file_paths:
email.attach_file(file_path)
email.send()
# Attach Django file field
from .models import Document
def send_document_email(user, document_id):
document = Document.objects.get(pk=document_id)
email = EmailMessage(
f'Document: {document.title}',
f'Please find {document.title} attached.',
settings.DEFAULT_FROM_EMAIL,
[user.email]
)
# Attach file from model FileField
email.attach_file(document.file.path)
email.send()Email Best Practices
- Use environment variables: Store SMTP credentials in environment variables never committing passwords to version control
- Provide text alternatives: Always include plain text versions of HTML emails for email clients not supporting HTML
- Queue emails asynchronously: Use Celery for sending emails asynchronously preventing request timeouts and improving user experience
- Handle failures gracefully: Implement error handling and retry logic for failed email sending attempts
- Use email templates: Separate email content into templates enabling consistent formatting and easy updates
- Test thoroughly: Use console or file backends in development testing email functionality without sending real emails
Conclusion
Django's email framework provides comprehensive infrastructure for sending emails through SMTP servers supporting various email service providers. SMTP configuration establishes connection parameters enabling email delivery through Gmail, SendGrid, AWS SES, or custom servers. Simple emails use send_mail function while EmailMessage class offers advanced features including HTML content, attachments, and custom headers. Email templates separate content from code enabling consistent professional formatting with dynamic content insertion through Django template system. Attachments support sending files alongside messages from file paths, generated content, or model FileField instances. HTML emails with inline CSS provide rich formatting while plain text alternatives ensure compatibility across email clients. Following best practices including environment variable credentials, text alternatives, asynchronous sending, error handling, template usage, and thorough testing ensures reliable email delivery. Understanding Django email capabilities enables building professional applications with robust communication channels supporting transactional emails, notifications, and marketing campaigns throughout Django 6.0 development.
$ share --platform
$ cat /comments/ (0)
$ cat /comments/
// No comments found. Be the first!


