The platform offers two output services to modules: HTML-to-PDF rendering and a system mailbox that sends transactional mail. This page lists core/pdf_render.py, core/system_mail.py, the routes in server/routes/email.py, and the export helper in server/services/record_formatter.py. Personal mail accounts belong to the mail module; see mail.
Scope and source¶
- Defined in:
src/cluster_erp/core/pdf_render.py(PdfRenderer,get_renderer,close_renderer,font_face_css),src/cluster_erp/core/system_mail.py,src/cluster_erp/server/routes/email.py,src/cluster_erp/server/services/record_formatter.py - Count: 3 email routes (counted from the
@router.decorators); 5 export formats (text,pdf,xml,json,csv, from the request pattern insrc/cluster_erp/server/routes/email.py:73)
PDF renderer¶
PdfRenderer renders HTML to PDF with Playwright's Chromium. One browser is started per process on first use, guarded by a lock; each render opens its own browser context and page (src/cluster_erp/core/pdf_render.py:58-120).
| Member | Behaviour | Source |
|---|---|---|
render(html, footer_html=None, page_format="A4") |
Sets the page content, waits for fonts, and returns PDF bytes with backgrounds, CSS page size, and an optional footer template | src/cluster_erp/core/pdf_render.py:92-120 |
close() |
Closes the browser and Playwright | src/cluster_erp/core/pdf_render.py:122-131 |
get_renderer() |
Returns the process-wide renderer | src/cluster_erp/core/pdf_render.py:137-141 |
close_renderer() |
Closes it; called by the lifespan at shutdown | src/cluster_erp/core/pdf_render.py:144-148, src/cluster_erp/server/app.py:198-204 |
font_face_css() |
The web app's manrope.css with every font file inlined as a data URI |
src/cluster_erp/core/pdf_render.py:32-51 |
RENDER_TIMEOUT_MS is 30,000 (src/cluster_erp/core/pdf_render.py:28). When Playwright or Chromium is missing, the renderer raises AppError with PDF_RENDERER_UNAVAILABLE and HTTP 503 (src/cluster_erp/core/pdf_render.py:70-89). The renderer is used by the trade documents of the sales_orders module (src/cluster_erp/modules/sales_orders/trade_documents/render.py, src/cluster_erp/modules/sales_orders/trade_documents/services.py). See trade documents.
System mailbox¶
core/system_mail.py is the one SMTP sender for mail that the application sends itself (src/cluster_erp/core/system_mail.py:1-12).
| Member | Behaviour | Source |
|---|---|---|
is_configured(settings) |
True when smtp_host is set |
src/cluster_erp/core/system_mail.py:41-42 |
from_header(settings) |
smtp_from_name <smtp_from_email>, or the address alone |
src/cluster_erp/core/system_mail.py:45-48 |
build_message(...) |
A multipart/mixed message with text, an optional HTML alternative, and attachments |
src/cluster_erp/core/system_mail.py:51-80 |
send_blocking(settings, msg, recipients) |
Connects with a 25-second timeout, uses STARTTLS when smtp_use_tls is on, logs in when smtp_user is set, and sends |
src/cluster_erp/core/system_mail.py:83-98 |
send_system_email(...) |
Builds the message and sends it in a worker thread | src/cluster_erp/core/system_mail.py:101-123 |
SystemMailNotConfiguredError, SystemMailError |
Raised when no host is set, and when the SMTP conversation fails | src/cluster_erp/core/system_mail.py:33-38 |
Modules send transactional mail by emitting SendTransactionalEmail. The mail module handles it and calls send_system_email; when the mailbox is not configured it returns {"sent": False, "reason": "not_configured"} (src/cluster_erp/modules/mail/module.py:53, src/cluster_erp/modules/mail/module.py:72-100).
Email routes¶
The router prefix is /api/v1/email, and every route requires the permission email.send (src/cluster_erp/server/routes/email.py:22, src/cluster_erp/server/routes/email.py:100, src/cluster_erp/server/routes/email.py:126, src/cluster_erp/server/routes/email.py:191).
| Method and path | Purpose | Behaviour | Source |
|---|---|---|---|
POST /resolve |
Find e-mail addresses of records | Emits ResolveEntityEmails and collects the recipient lists from all handlers |
src/cluster_erp/server/routes/email.py:95-119 |
POST /send-records |
Send records as an export | Builds the export with generate_export, attaches it unless the format is text, and sends through the system mailbox |
src/cluster_erp/server/routes/email.py:122-184 |
POST /send |
Send a plain message | Sends a text and HTML message through the system mailbox | src/cluster_erp/server/routes/email.py:187-222 |
Both send routes answer HTTP 503 with SMTP_NOT_CONFIGURED when the server has no mail settings, and HTTP 502 with SMTP_ERROR when sending fails (src/cluster_erp/server/routes/email.py:131-136, src/cluster_erp/server/routes/email.py:184, src/cluster_erp/server/routes/email.py:195-200, src/cluster_erp/server/routes/email.py:222).
Record export formats¶
generate_export(fmt, entity_label, columns, records) returns (content, content_type, extension) (src/cluster_erp/server/services/record_formatter.py:308-318). The module docstring lists the formats: plain text, PDF through ReportLab, JSON (RFC 8259), CSV (RFC 4180, UTF-8 with BOM), and XML 1.0 (src/cluster_erp/server/services/record_formatter.py:1-11). This PDF path uses ReportLab, not the Chromium renderer above (src/cluster_erp/server/services/record_formatter.py:23-30).
Constraints and validation¶
send_blockingandsend_system_emailraiseSystemMailNotConfiguredErrorwhensmtp_hostis empty (src/cluster_erp/core/system_mail.py:85-86,src/cluster_erp/core/system_mail.py:112-113).- The settings validator requires
smtp_from_emailwhensmtp_hostis set (src/cluster_erp/config/settings.py:832-835). - Attachment file names in system mail use
safe_content_disposition(src/cluster_erp/core/system_mail.py:76-79).
Terms introduced¶
| Term | Code identifier | Definition | Turkish term | Source |
|---|---|---|---|---|
| system mailbox | core/system_mail.py |
The single SMTP identity that the application uses for its own mail, which other modules reach through SendTransactionalEmail. |
sistem posta kutusu | src/cluster_erp/core/system_mail.py:1-12 |
| PDF renderer | PdfRenderer |
The process-wide Chromium that turns HTML into PDF. | PDF oluşturucu | src/cluster_erp/core/pdf_render.py:58 |
Related pages¶
Verified against commit 92f8051 on 2026-11-13.