Simple Steps to Send Emails with Static Images in Django

Context

I wanted to send an email with a template that included an image using send_mail from Django. The image was stored in the static folder of the Django project. I wanted to use the Django template system to generate the email content, but I was not sure how to reference the image in the template.

Requirements

I asume you have a Django project with a static folder and a template that you want to use to generate an email.

Issue with {% static %} in Emails

The first thing I tried was to use the {% static %} template tag to generate the URL for the image. However, this tag does not generate a full URL, but a relative URL. This is not a problem when the template is rendered in the browser, but emails need a full URL to access the image.

This means that {% static %} only appends the relative path to the STATIC_URL, which is not sufficient for email clients to locate the image.

Solution - Generating Full URLs in the View (with code snippets)

The solution I found was to generate the full URL in the view and pass it as a context variable to the template.

This involves combining the site's domain with the static file path. This approach uses get_current_site to fetch the current site's domain and static to get the static file path, concatenating these to form a complete URL.

In the view

This is an example code to demonstrate how to create the full URL in a Django view:

This URL is then passed to the email template context and used in the src attribute of the img tag.

Please note that you need to adapt the paths to your project.

# in views.py

# imports we need to create the full URL
from django.contrib.sites.shortcuts import get_current_site
from django.templatetags.static import static

# imports we need to render the template to use in the email
from django.template.loader import render_to_string

# imports we need to send the email
from django.core.mail import send_mail

def my_view(request): # or any other view
    # we get the current site to get the domain
    current_site = get_current_site(request)

    # we get the static file path and concatenate it with the domain
    logo_url = f'https://{current_site.domain}{static("images/your-logo.png")}'

    # we generate a context with the variables we want to use in the template
    context = {
                'logo_url': logo_url,
                # ... other context variables ...
                }

    subject = 'Subject of your email'

    # we render the templates to use in the email
    message_plain = render_to_string('my_template.txt', context)
    message_html = render_to_string('my_template.html', context)

    email = '[email protected]'

    # we send the email
    send_mail(subject, message_plain, None, [email], html_message=message_html)

In the templates

When you send emails, it is recommended to provide both a plain text and an HTML version of the email. This is why we have two templates in the view.

HTML template

<!-- in my_template.html -->
<img src="{{ logo_url }}" alt="Your Logo">

Plain text template

In my case, I did not need to include the image in the plain text version of the email, but if you need to do so, you can use the same approach as in the HTML template.

<!-- in my_template.txt -->
Your Logo: {{ logo_url }}

Keep in mind

  • This approach is not limited to images. You can use it to generate full URLs for any static file.
  • This approach is not limited to emails. You can use it to generate full URLs for any static file in any context and render the templates.

Key Takeaways

  • Django's {% static %} template tag only generates a relative URL, which is not sufficient for email clients to locate the image.
  • To generate a full URL for a static file, you need to combine the site's domain with the static file path.
  • You can use get_current_site to fetch the current site's domain and static to get the static file path, concatenating these to form a complete URL.
  • You can use this approach to generate full URLs for any static file in any context and render the templates.
  • You construct the full URL in the view and pass it as a context variable to the template.

Happy coding!

References

Comments

Comments powered by Disqus