Start here

How it fits

MailingKit is a library, not a service. It runs inside your process, next to your code, and owns exactly one job: turning "send this email" into a delivered message.

The pipeline

Every send goes through the same steps, in this order:

  1. Render. For send_template(), the data is checked against the template's model, then the subject, HTML and text are rendered.
  2. Complete. The default sender is applied and a text part is generated from HTML when missing.
  3. Validate. Addresses, headers, subject, tags, recipient count and size are checked. Nothing unsafe reaches a provider.
  4. Redirect. If redirect_to is set, every recipient is replaced by that one inbox.
  5. Deduplicate. If an idempotency key was given and already used, the earlier result is returned.
  6. Send. The provider adapter delivers the message. Retryable failures are retried with backoff.
  7. Report. A SendResult is returned, hooks receive an event and a log line is written, with no personal data.

Core versus optional

The rule is simple: if most applications need it to send one email correctly, it is core. Everything else is opt-in.

Core (always installed)Optional (extras or your own code)
Message model and validationHTTP API providers such as Resend (mailingkit[resend])
Jinja2 templates with typed dataFramework glue (mailingkit.contrib.django, imported only by Django)
Console, file, memory and SMTP providersShared idempotency stores (Redis, SQL)
Error hierarchy, retries, idempotency keysMetrics and tracing, through hooks
Environment configuration, hooks, loggingQueues and background workers (planned for 0.2)

Library, not service

A central mail service sounds tidy, but it adds a network hop, an API contract, authentication and another thing to deploy before anyone needs it. A library gives every application the same behaviour with none of that. MailingKit is built so the bigger shapes can grow out of it later without changing your code.

ShapeHow it looksStatus
LibraryEach application calls mail.send() and delivers directly.0.1, today
Library plus workerApplications call mail.enqueue(); a mailingkit worker process sends from a queue.Planned for 0.2
Central serviceA small HTTP app you write on top of the library, if you ever need one.An example, never core

Monoliths and microservices

In a monolith, create one client at startup and share it. In a microservice architecture, each service installs MailingKit and configures it with the same environment variables, so every service validates, retries and reports errors the same way. Shared templates can live in a small internal package that each service depends on.

text
User service      ──┐
Billing service   ──┼──  MailingKit (same library, same config)  ──  provider
Notification svc  ──┘

When you want one place to own credentials and templates, the planned worker mode lets services only enqueue, while a single worker does the sending.

What MailingKit is not

  • Not a CRM, ATS, user system or workflow engine. Your application decides when to send.
  • Not a database. It returns results and emits events; storing history is up to you.
  • Not a marketing or newsletter tool.
  • Not a mail server or a hosted service.