Skip to main content

A chainable Django email sender utility.

Project description

📧 Django Email Sender Utility

A clean, reusable, lightweight and chainable utility class for sending emails in Django using templates. It supports both HTML and plain text templates, context injection, and flexible usage — either directly, via subclassing, or abstracted into functions.

🧠 Why Use This?

While Django already provides a way to send emails, it can become verbose and repetitive. EmailSender abstracts the boilerplate and lets you send templated emails fluently.

✨ Features

  • Chainable API (.to(), .from_address(), etc.)
  • Supports HTML and plain text templates
  • Uses Django's template system for dynamic content
  • Easy to integrate and override
  • Encourages clean code and reusability
  • Supports subclassing or functional abstractions


🛠 Available Methods

Method Description


 - create()	                # Class factory method to instantiate the EmailSender.
 - from_address(email)	    # Sets the sender’s email address.
 - to(recipients)	        # Accepts a string or list of recipient email addresses.
 - with_subject(subject)	# Sets the email subject.
 - with_context(context)	# Context dictionary used in the templates.
 - with_text_template(path)	# Path to the plain text email template.
 - with_html_template(path)	# Path to the HTML email template.
 - with_headers(headers)	# Optional custom headers as a dictionary.
 - send()	                # Sends the email. Returns the number of successfully delivered messages.

🚨 Error Handling

 - Raises ValueError if required fields are missing.
 - Raises TypeError if headers are not provided as a dictionary.

🚀 Installation

This is a standalone utility. Copy the file into your Django project, or install it as a package using PyPI.


🧩 Requirements

  • Python 3.8+
  • Django >= 3.2

🧪 Basic Usage

Here's a simple example of how to send an email using EmailSender:

from email_sender import EmailSender

EmailSender.create()\
    .from_address("no-reply@example.com")\
    .to(["recipient@example.com"])\  
    .with_subject("Welcome!")\
    .with_context({"username": "John"})\
    .with_text_template("welcome.txt", folder_name="emails")\
    .with_html_template("welcome.html", folder_name="emails")\
    .send()

Explanation:

  • .from_address("no-reply@example.com"): Specifies the sender's email address.
  • .to(["recipient@example.com"]): Specifies the recipient's email address.
  • .with_subject("Welcome!"): The subject of the email.
  • .with_context({"username": "John"}): Context for the email templates, allowing dynamic insertion of values (e.g., the recipient's name).
  • .with_text_template("welcome.txt", folder_name="emails"): The path to the text-based email template. Here, we specify the folder name (emails) where the template is stored. If no folder name is provided, it defaults to email_templates/.
  • .with_html_template("welcome.html", folder_name="emails"): The path to the HTML-based email template. Similarly, you can specify the folder name (emails) for this template.
  • .send(): Sends the email.

🧱 Subclassing

You can also subclass the EmailSender class to create more specific types of emails.

Example: Password Reset Email

class PasswordResetEmail(EmailSender):
    def __init__(self, user):
        super().__init__()
        self.user = user

    def build(self):
        return self\
            .from_address("no-reply@example.com")\
            .to([self.user.email])\
            .with_subject("Reset Your Password")\
            .with_context({"username": self.user.username, "reset_link": generate_reset_link(self.user)})\
            .with_text_template("reset_password.txt", folder_name="emails")\
            .with_html_template("reset_password.html", folder_name="emails")

Usage:

PasswordResetEmail(user).build().send()

Here, the PasswordResetEmail class uses reset_password.txt and reset_password.html templates from the emails folder.


🛠️ Function-Based Abstractions

For a functional approach, you can also wrap EmailSender in specific functions to handle common email use cases.

Example: Sending a Verification Email

def send_verification_email(user):
    html_verification_path = "verification/verification.html"
    text_verification_path = "verification/verification.txt"
    subject = "Verify Your Email"
    from_email = "no-reply@example.com"

    return EmailSender.create()\
        .from_address(from_email)\
        .to([user.email])\
        .with_subject(subject)\
        .with_context({
            "username": user.username,
            "verification_link": generate_verification_link(user)
        })\
        .with_text_template(text_verification_path, folder_name="emails")\
        .with_html_template(html_verification_path, folder_name="emails")\
        .send()

Example: Sending a Registration Email

def send_registration_email(user):
    html_registration_path = "registration/registration.html"
    text_registration_path = "registration/registration.txt"
    
    subject = "Welcome to the Platform!"
    from_email = "no-reply@example.com"

    return EmailSender.create()\
        .from_address(from_email)\
        .to([user.email])\
        .with_subject(subject)\
        .with_context({"username": user.username})\
        .with_text_template(text_registration_path, folder_name="emails")\
        .with_html_template(html_registration_path, folder_name="emails")\
        .send()

Advantages of this Approach:

  • Keeps your logic functional and simple: It's straightforward to use and easy to test.
  • Keeps your email templates modular and easy to override: Templates are organized in subfolders (e.g., registration, verification), making them easier to manage.
  • Clean and maintainable codebase: You don’t have to subclass EmailSender each time, reducing complexity.


📁 Templates

Templates must reside inside a dedicated email_templates/ directory, which should exist inside your Django template directory.

This folder can contain your own structure to help organise different types of emails. For example:

Example

project/
├── templates/
│   └── email_templates/
│       └── registration/
│           ├── registration.html
│           └── registration.txt

When calling with_html_template() or with_text_template(), you can provide the subfolder and filename like so:

EmailSender.create()
    .with_html_template("registration.html", folder_name="registration")
    .with_text_template("registration.txt", folder_name="registration")

You must have both an .html and .txt version of the email template. These are required for rich content and email client compatibility.


💡 Tips

  • You can subclass EmailSender for different email types or simply wrap it in functions.
  • Organise your templates by email type (registration/, verification/, etc.)
  • Subject and context are fully customisable.

Project details


Download files

Download the file for your platform. If you're not sure which to choose, learn more about installing packages.

Source Distribution

django_email_sender-1.0.2.tar.gz (8.3 kB view details)

Uploaded Source

Built Distribution

If you're not sure about the file name format, learn more about wheel file names.

django_email_sender-1.0.2-py3-none-any.whl (8.3 kB view details)

Uploaded Python 3

File details

Details for the file django_email_sender-1.0.2.tar.gz.

File metadata

  • Download URL: django_email_sender-1.0.2.tar.gz
  • Upload date:
  • Size: 8.3 kB
  • Tags: Source
  • Uploaded using Trusted Publishing? No
  • Uploaded via: twine/6.1.0 CPython/3.12.6

File hashes

Hashes for django_email_sender-1.0.2.tar.gz
Algorithm Hash digest
SHA256 b9e854a8e292ab49d8357175e6def35c69236e60f083e2ea3563d44358eaa473
MD5 2a66352c3deb735e9a23ee150675d05a
BLAKE2b-256 993e7afe445746d15173fa877ebfaf4193809fb7537ce39054b0c79dba621b6f

See more details on using hashes here.

File details

Details for the file django_email_sender-1.0.2-py3-none-any.whl.

File metadata

File hashes

Hashes for django_email_sender-1.0.2-py3-none-any.whl
Algorithm Hash digest
SHA256 c2d1b0c8d9273e4adceeaedb06498cfce43499d906a1501be10add2af9606a7a
MD5 81cab9affb4d886c4f300e0eff973732
BLAKE2b-256 aa0cb7f59cf6b060c177ce34445786439ca84c47811c525a6bb4b5d5fb5ba6c8

See more details on using hashes here.

Supported by

AWS Cloud computing and Security Sponsor Datadog Monitoring Depot Continuous Integration Fastly CDN Google Download Analytics Pingdom Monitoring Sentry Error logging StatusPage Status page