Django Sending Emails

Sending emails is a common feature in web applications — confirming registrations, sending password reset links, notifying users about new activity. Django provides a clean, built-in email system that works with any email provider (Gmail, Outlook, SMTP servers, and more) without needing any third-party library.

What is Django's Email System?

Django's email system lets you send plain text emails, HTML emails, and emails with attachments directly from your Python code. It connects to an email server (like Gmail's SMTP) using settings you configure in settings.py.

Example: Think of Django's email system as a post office built inside your application. You write a letter (compose the email in Python), put it in an envelope with the recipient's address (email address), and the post office (email backend) delivers it. You do not need to drive to the post office yourself — it handles the delivery automatically.

Email Settings in settings.py

Add these settings to settings.py to configure your email server. Here is the setup for Gmail:


# Email backend — use SMTP for real emails
EMAIL_BACKEND = 'django.core.mail.backends.smtp.EmailBackend'

EMAIL_HOST = 'smtp.gmail.com'     # Gmail's SMTP server address
EMAIL_PORT = 587                  # Port number for TLS
EMAIL_USE_TLS = True              # Use encryption (always True for Gmail)
EMAIL_HOST_USER = 'your_email@gmail.com'    # Your Gmail address
EMAIL_HOST_PASSWORD = 'your_app_password'  # Gmail App Password (see below)
DEFAULT_FROM_EMAIL = 'My School <your_email@gmail.com>'

Important — Gmail App Password

Gmail does not allow your regular account password to be used in code. You must generate an App Password:

  • Go to your Google Account → Security → 2-Step Verification → App Passwords.
  • Generate a new App Password for "Mail" and copy the 16-character code.
  • Use that code as EMAIL_HOST_PASSWORD — never your real Gmail password.

Console Backend — For Development Testing

During development, instead of actually sending emails, you can print them to the terminal using the console backend:


# In settings.py during development — emails print to the terminal instead
EMAIL_BACKEND = 'django.core.mail.backends.console.EmailBackend'

This is extremely useful for testing — you can see the email content in your terminal without needing a real email account.

Sending a Simple Plain Text Email

Use Django's send_mail() function to send a basic email:


from django.core.mail import send_mail

send_mail(
    subject='Welcome to My School',
    message='Hello Rahul, your registration is confirmed!',
    from_email='school@myschool.com',
    recipient_list=['rahul@example.com'],
    fail_silently=False,   # Raise an error if sending fails (True = ignore errors)
)

The parameters:

  • subject — The email subject line.
  • message — The plain text body of the email.
  • from_email — The sender's email address.
  • recipient_list — A list of recipient email addresses (can include multiple).
  • fail_silently — Set to False during development so errors are visible.

Sending an HTML Email

Plain text emails look basic. You can send a nicely formatted HTML email using EmailMultiAlternatives:


from django.core.mail import EmailMultiAlternatives

def send_welcome_email(student_name, student_email):
    subject = 'Welcome to My School!'
    text_content = f'Hello {student_name}, your account has been created.'
    html_content = f'''
        <h2>Welcome, {student_name}!</h2>
        <p>Your account at <strong>My School</strong> has been successfully created.</p>
        <p>Login now at: <a href="http://myschool.com/login">myschool.com/login</a></p>
    '''

    email = EmailMultiAlternatives(
        subject=subject,
        body=text_content,         # Plain text (for email clients that don't support HTML)
        from_email='school@myschool.com',
        to=[student_email]
    )
    email.attach_alternative(html_content, 'text/html')  # Attach the HTML version
    email.send()
Example: Sending both plain text and HTML is like sending a gift with two versions of the same card — one printed in colour (HTML) and one in plain black ink (text). Recipients who can read colour get the fancy version; others get the plain one. No one gets a blank card.

Sending Email with Attachments


from django.core.mail import EmailMessage

def send_report_email(student_email, report_file_path):
    email = EmailMessage(
        subject='Your Monthly Report',
        body='Please find your monthly report attached.',
        from_email='school@myschool.com',
        to=[student_email]
    )
    email.attach_file(report_file_path)   # Attach the file
    email.send()

You can also attach data directly (without a file on disk) using email.attach(filename, content, mimetype):


email.attach('report.pdf', pdf_data, 'application/pdf')

Sending Email in a View — Registration Example

Here is a complete example of sending a welcome email after a user registers:


from django.shortcuts import render, redirect
from django.contrib.auth.forms import UserCreationForm
from django.contrib import messages
from django.core.mail import send_mail

def register(request):
    if request.method == 'POST':
        form = UserCreationForm(request.POST)
        if form.is_valid():
            user = form.save()

            # Send welcome email after successful registration
            send_mail(
                subject='Registration Successful!',
                message=f'Welcome {user.username}! Your account has been created.',
                from_email='school@myschool.com',
                recipient_list=[user.email],
                fail_silently=True,
            )

            messages.success(request, 'Account created! Check your email.')
            return redirect('login')
    else:
        form = UserCreationForm()
    return render(request, 'registration/register.html', {'form': form})

Sending Email Using a Template

For longer, well-structured emails, it is cleaner to write the email body in a separate HTML template instead of writing HTML inside Python code:


from django.template.loader import render_to_string
from django.core.mail import EmailMultiAlternatives

def send_templated_email(student):
    subject = 'Your Exam Results are Available'

    # Render the HTML email from a template
    html_content = render_to_string('emails/exam_result.html', {
        'student_name': student.name,
        'grade': student.grade,
    })

    email = EmailMultiAlternatives(
        subject=subject,
        body='Please view this email in an HTML-capable email client.',
        from_email='school@myschool.com',
        to=[student.email]
    )
    email.attach_alternative(html_content, 'text/html')
    email.send()

Create templates/emails/exam_result.html:


<h2>Dear {{ student_name }},</h2>
<p>Your exam results for Grade <strong>{{ grade }}</strong> are now available.</p>
<p>Please log in to view your detailed results.</p>

Sending Emails to Multiple Recipients


# send_mail with multiple recipients
send_mail(
    subject='School Holiday Notice',
    message='School will remain closed on Monday due to a public holiday.',
    from_email='admin@myschool.com',
    recipient_list=['parent1@example.com', 'parent2@example.com', 'parent3@example.com'],
)

Quick Recap

  • Configure email settings in settings.py — use smtp.gmail.com for Gmail.
  • During development, use EMAIL_BACKEND = 'django.core.mail.backends.console.EmailBackend' to print emails in the terminal.
  • Use send_mail() for simple plain text emails.
  • Use EmailMultiAlternatives to send emails with both plain text and HTML versions.
  • Use EmailMessage with attach_file() to send emails with file attachments.
  • Use render_to_string() to build email content from a Django HTML template.
  • Always use Gmail App Passwords, never your real Gmail account password in code.

Leave a Comment

Your email address will not be published. Required fields are marked *