Skip to content

Django Email HTML Template Fix

DodaTech Updated 2026-06-24 2 min read

In this tutorial, you'll learn about Django Email HTML Template Fix. We cover key concepts, practical examples, and best practices.

The Problem

Plain text emails look unprofessional. You need HTML emails with branding, styling, and clickable buttons, but Django's send_mail sends plain text by default.

Quick Fix

Wrong — plain text only

from django.core.mail import send_mail

send_mail(
    'Welcome to DodaTech',
    'Hi, thanks for signing up! Click the link to activate.',
    'noreply@dodatech.com',
    [user.email],
)

Output: Plain text email. No branding, no links, no formatting.

Correct — HTML email with template

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

def send_welcome_email(user):
    subject = 'Welcome to DodaTech'
    html_content = render_to_string('emails/welcome.html', {
        'username': user.username,
        'activate_url': f'https://dodatech.com/activate/{user.activation_key}/',
    })
    text_content = f"Hi {user.username}, welcome to DodaTech!"

    msg = EmailMultiAlternatives(
        subject, text_content,
        'noreply@dodatech.com',
        [user.email],
    )
    msg.attach_alternative(html_content, 'text/html')
    msg.send()

HTML email template

<!-- templates/emails/welcome.html -->
<!DOCTYPE html>
<html>
<head>
    <meta charset="UTF-8">
    <style>
        body { font-family: Arial, sans-serif; background: #f4f4f4; padding: 20px; }
        .container { max-width: 600px; margin: 0 auto; background: white; }
        .header { background: #2563eb; color: white; padding: 20px; text-align: center; }
        .content { padding: 30px; }
        .button { display: inline-block; padding: 12px 24px; background: #2563eb;
                   color: white; text-decoration: none; border-radius: 4px; }
        .footer { padding: 20px; color: #666; font-size: 12px; }
    </style>
</head>
<body>
    <div class="container">
        <div class="header"><h1>Welcome to DodaTech</h1></div>
        <div class="content">
            <p>Hi {{ username }},</p>
            <p>Thanks for signing up! Click the button below to activate your account:</p>
            <p style="text-align: center;">
                <a href="{{ activate_url }}" class="button">Activate Account</a>
            </p>
        </div>
        <div class="footer">Built by DodaTech developers</div>
    </div>
</body>
</html>

Inline CSS for email clients

# Install premailer: pip install premailer
from premailer import transform

html_content = render_to_string('emails/welcome.html', context)
html_content = transform(html_content)  # Inlines CSS

Batch HTML emails

def send_newsletter(users):
    from django.core.mail import get_connection
    connection = get_connection()
    messages = []

    for user in users:
        html = render_to_string('emails/newsletter.html', {'user': user})
        text = f"Your newsletter content here"
        msg = EmailMultiAlternatives(
            'Monthly Newsletter', text,
            'noreply@dodatech.com', [user.email],
        )
        msg.attach_alternative(html, 'text/html')
        messages.append(msg)

    connection.send_messages(messages)  # Reuses SMTP connection

Prevention

  • Always include a plain text fallback for email clients that don't render HTML.
  • Use inline CSS (or premailer) for email client compatibility.
  • Test emails with tools like Litmus or Mailtrap before sending to real users.

Common Mistakes with email html template

  1. Using head and tail instead of pattern matching, causing runtime errors on empty lists
  2. Forgetting that lazy evaluation defers computation until the value is forced, causing space leaks with unevaluated thunks
  3. Using return to exit a function early instead of wrapping a pure value in the monad

These mistakes appear frequently in real-world DJANGO code. DodaTech's contributors have identified these patterns through analysis of open-source projects and production systems.

Practice Exercise

Write a pure function that safely divides two integers using Maybe, then test it with edge cases like division by zero and negative numbers.

This exercise reinforces the concepts covered in this guide. Try implementing it before checking online solutions.

FAQ

### Why use EmailMultiAlternatives instead of send_mail?

send_mail only supports plain text. EmailMultiAlternatives lets you attach HTML as an alternative version alongside plain text.

Do I need inline CSS for emails?

Yes. Most email clients (Gmail, Outlook) strip