Building Mailables
Mailable is an abstract dataclass base class. Every email you define subclasses it and implements build(), which configures the email through a fluent, chainable API and returns self.
from dataclasses import dataclassfrom python_mailable.mailable import Mailable
@dataclassclass OrderShipped(Mailable): user: User
def build(self): return ( self.to(self.user.email) .subject("Your order has shipped!") .template("emails/order_shipped.html.j2") .with_context({"user": self.user}) )Any dataclass fields you add (like user above) are available to build() for composing the recipient, subject, and template context.
Recipients
Section titled “Recipients”Sets the primary recipient’s email address.
self.to("jane@example.com")Adds one or more CC recipients. Accepts multiple arguments, and you can call it more than once; addresses just accumulate.
self.cc("manager@example.com")self.cc("manager@example.com", "ops@example.com")Adds one or more BCC recipients, with the same call signature as cc().
self.bcc("audit@example.com")self.bcc("audit@example.com", "compliance@example.com")Subject
Section titled “Subject”subject()
Section titled “subject()”Sets the email’s subject line.
self.subject("Your order has shipped!")Template paths
Section titled “Template paths”template()
Section titled “template()”Sets the path to the HTML Jinja2 template, resolved relative to the project root.
self.template("emails/order_shipped.html.j2")text_template()
Section titled “text_template()”Sets the path to a separate plain-text Jinja2 template, for sending a text alternative alongside (or instead of) HTML.
self.text_template("emails/order_shipped.txt.j2")Both are optional and independent: set either, both, or neither. For how to write the content of these template files, including Jinja2 syntax and examples, see Templates.
Context
Section titled “Context”with_context()
Section titled “with_context()”Merges a dict of template variables into the email’s context. Safe to call multiple times; later calls add to (and override matching keys in) the existing context.
self.with_context({"user": self.user, "order_id": self.order_id})@dataclassclass OrderShipped(Mailable): user: User
def build(self): return ( self.to(self.user.email) .subject("Your order has shipped!") .template("emails/order_shipped.html.j2") .text_template("emails/order_shipped.txt.j2") .with_context({"user": self.user}) )Attachments
Section titled “Attachments”attach()
Section titled “attach()”Registers a file path to be attached to the email. Call it once per file; paths accumulate in order.
self.attach("invoices/order_42.pdf")self.attach("invoices/order_42.pdf").attach("packing_slip.pdf")Python Mailable only tracks attachment paths. Actually attaching the files to an outgoing message is the responsibility of your mail-sending code, since this package doesn’t send mail itself (see Using your own mail client).
Method reference
Section titled “Method reference”| Method | Description |
|---|---|
to(recipient_email) |
Sets the primary recipient. |
cc(*emails) |
Adds CC recipients (accumulates across calls). |
bcc(*emails) |
Adds BCC recipients (accumulates across calls). |
subject(subject_line) |
Sets the subject line. |
template(path) |
Sets the HTML template path. |
text_template(path) |
Sets the plain-text template path. |
with_context(context_dict) |
Merges variables into the template context. |
attach(file_path) |
Registers a file path as an attachment. |
build() |
Abstract: implement it to configure and return the email. |
All configuration methods (to, cc, bcc, subject, template, text_template, with_context, attach) return self, so they chain freely in any order inside build().