from django.core.mail import EmailMultiAlternatives
from django.template.loader import render_to_string
from django.conf import settings
def send_welcome_email(user):
"""Send welcome email with HTML template."""
context = {
'user': user,
'site_url': settings.SITE_URL,
}
# Render both plain text and HTML
text_content = render_to_string('emails/welcome.txt', context)
html_content = render_to_string('emails/welcome.html', context)
email = EmailMultiAlternatives(
subject='Welcome to our platform!',
body=text_content,
from_email=settings.DEFAULT_FROM_EMAIL,
to=[user.email],
)
email.attach_alternative(html_content, 'text/html')
email.send()
def send_bulk_newsletter(subscriber_list, subject, template_name, context):
"""Send newsletter to multiple subscribers efficiently."""
html_content = render_to_string(f'emails/{template_name}.html', context)
text_content = render_to_string(f'emails/{template_name}.txt', context)
emails = []
for subscriber in subscriber_list:
email = EmailMultiAlternatives(
subject=subject,
body=text_content,
from_email=settings.DEFAULT_FROM_EMAIL,
to=[subscriber.email],
)
email.attach_alternative(html_content, 'text/html')
emails.append(email)
# Send all at once
from django.core.mail import get_connection
connection = get_connection()
connection.send_messages(emails)
I send HTML emails using Django templates for consistent branding. The EmailMultiAlternatives class supports both plain text and HTML versions. I render templates with render_to_string and context data. For transactional emails, I queue them via Celery to avoid blocking requests. I use inline CSS because many email clients strip <style> tags. Testing email templates across clients (Gmail, Outlook) is crucial. I track email opens with pixel tracking when needed. This keeps emails maintainable and reusable across the application.