Blog / ERPNext How Email Notifications Work in ERPNext December 12, 2025 · 9 min read How Email Notifications Work in ERPNext — Technical Guide 1. Introduction to Email Notifications Email notifications in ERPNext automate messages to humans (customers, managers, teams) when business events occur. They reduce manual communication and integrate tightly with documents, workflows, and print formats. Notifications can be triggered immediately (on document events) or scheduled (date-based reminders). Practical examples include overdue invoice reminders, low-stock alerts, payroll distribution emails, approval requests, and automated customer confirmations. 2. Core Architecture of the Notification Engine The notification engine is a composition of framework components and background infrastructure. Key elements include: Notification Doctype — stores rules, events, conditions, recipients, subject, and template. Document Events — framework hooks (on_update, after_insert, on_submit, on_cancel) that trigger evaluation. Jinja Renderer — renders dynamic content inside message bodies and subjects. Email Queue — persistent doctype that stores outbound messages and metadata. Background Workers / RQ — processes queued jobs and performs actual SMTP delivery. Email Account Settings — SMTP credentials and preferences used by workers to send mail. Design follows a non-blocking pattern: events enqueue work and workers send emails asynchronously to avoid slowing user actions. 3. Understanding the Notification Doctype in Detail Each Notification record defines a rule. Important fields and their roles: FieldExplanation Document TypeThe doctype (Sales Invoice, Purchase Order, Employee) this notification monitors. All rules are scoped to a doctype. EventWhich event triggers evaluation: New, Save, Submit, Cancel, Value Change, Days Before, Days After. ConditionPython-like expression evaluated against the loaded document (use doc.field_name). RecipientsCan be static emails, roles (Role: Accounts Manager), dynamic fields ({{ doc.owner }}) or combinations. Subject & MessageJinja templates that render the email subject and body with document data. Attach Print FormatIf checked, ERPNext generates a PDF of the selected print format (wkhtmltopdf) and attaches it to the email. Days Before / AfterUsed for date-based triggers — notification triggers when the target date is within configured offset. 4. Workflow of Email Notification Processing Detailed sequence of actions from event to delivery: Event occurs — user creates, saves, submits, cancels, or modifies a document. Framework hook executes — ERPNext executes registered event handlers. Load notifications — fetch active Notification records for that doctype and matching event type. Evaluate conditions — for each rule, evaluate the condition expression against the document. Render templates — if true, render subject/message using Jinja with the doc context. Queue email — create an Email Queue entry (recipients, subject, body, attachments). Worker picks job — background worker (RQ) processes the queue entry and sends via SMTP. Logging — queue status and any errors are stored for auditing and debugging. This asynchronous flow prevents UI blocking and supports retry/monitoring for large volumes. 5. Event-Based Triggers Explained ERPNext supports several trigger types. Understanding these helps you pick the right trigger for each business need. New Fires after initial document insert. Use when you want a one-time welcome or acknowledgement. Save Fires every time the document is saved. Useful for draft-stage notifications but beware of noisy emails — combine with conditions. Submit Fires when a document is submitted (docstatus set to 1). Ideal for approvals and formal communications like invoices and purchase orders. Cancel Fires on cancellation. Useful to inform counterparties or internal teams about reversals. Value Change Fires when a specific field changes. Example: notify when status changes from Draft to Approved. Days Before / After Time-based triggers evaluated by scheduler jobs — used for reminders (e.g., payment due in 3 days). 6. Condition-Based Triggers — Technical Details Conditions are Python-like boolean expressions evaluated in the context of the document. They must resolve to True or False. Rules and Best Practices Reference fields as doc.field_name. Use logical operators (and, or, not). Prefer simple expressions; if logic grows complex, consider server scripts or custom methods. Be mindful of performance: conditions that access heavy child table processing can slow down evaluation. Examples doc.outstanding_amount > 0 doc.status == "Overdue" and doc.outstanding_amount > 1000 doc.delivery_date < nowdate() A condition error (syntax or undefined attribute) will prevent notification execution — watch logs for UndefinedError exceptions from Jinja or Python evaluation errors. 7. Creating Email Notifications — Full Steps Step-by-step process to configure a notification from ERPNext's UI: Open Settings → Email → Notification. Click New to create a notification rule. Select the Document Type to monitor. Choose the Event (New, Save, Submit, etc.). Optionally add a Condition to narrow triggers. Set Recipients (email addresses, roles, dynamic fields). Fill in Subject and Message using Jinja where appropriate. Enable Attach Print Format if a PDF should be included. Save the notification and test by triggering the associated event. Always test notifications in a staging environment before enabling in production to avoid spamming users. 8. Dynamic Fields in Email Body — Jinja Best Practices ERPNext uses Jinja templating to create dynamic content. The template is rendered with the document accessible as doc. Common Patterns Basic field insertion: Dear {{ doc.customer_name }}, Your invoice {{ doc.name }} for {{ doc.grand_total }} has been generated. Looping child tables: {% for item in doc.items %} - {{ item.item_name }}: {{ item.qty }} @ {{ item.rate }} {% endfor %} Conditional blocks: {% if doc.discount_amount > 0 %} You received a discount of {{ doc.discount_amount }}. {% endif %} Document links: use {{ doc.get_url() }} to add a link to the document in the ERPNext UI. Avoid heavy CPU/IO operations in Jinja templates (e.g., large loops or external API calls). Keep templates focused on presentation only. 9. Filters vs Conditions — Deep Comparison ERPNext supports both filters and conditions; they serve different purposes and have different performance characteristics. CharacteristicFiltersConditions Execution locationDatabase-level (pre-fetch)In-memory, after loading document Use caseBulk date-based reminders and simple equality checksComplex business logic, multi-field comparisons PerformanceFaster for large datasetsMore flexible but potentially slower When sending scheduled reminders for thousands of records, prefer filters. Use conditions when you need field-level or computed comparisons. 10. Email Templates & Jinja Rendering Engine Email templates allow reuse of HTML/Jinja snippets across notifications. Templates are rendered by passing the document context into Jinja and replacing variables. How rendering happens Load template text from the database. Prepare render context (commonly {'doc': doc, 'now': nowdate()}). Run template through Jinja renderer to produce final HTML/text. Assign rendered HTML to the Email Queue object. Keep templates modular and maintain a library for branded headers/footers to ensure consistent communications. 11. Attach Print Formats Automatically ERPNext can attach a PDF print format to outgoing emails. When enabled, the system generates a PDF and appends it to the message during queueing. Internal steps Select the desired print format in the notification configuration. When notification triggers, generate the print format HTML for the document. Convert HTML to PDF using wkhtmltopdf (or alternative configured converter). Attach the generated PDF to the Email Queue entry before enqueueing the send job. Generating PDFs can be CPU-expensive — for bulk sends schedule generation jobs during off-peak hours or pre-generate PDFs if feasible. 12. Event Logging & Debugging Email Notifications Notifications can fail for several reasons — SMTP problems, Jinja errors, or worker failures. ERPNext provides multiple places to investigate: Email Queue — inspect queued messages, status, recipients, and error messages. Error Log — framework-level exceptions get recorded here. Background job logs — RQ worker logs detail job execution and tracebacks. Debugging workflow Confirm notification is enabled and the event was fired. Check Email Queue for a corresponding entry and any attached traceback. If the queue contains an error, view the traceback and fix the underlying issue (Jinja syntax, missing fields, SMTP auth). If the queue is empty, ensure scheduler/worker processes are running. 13. Common Business Use Cases Typical scenarios where notifications deliver value: Invoice Due Reminder Trigger: Days After due_date & outstanding_amount > 0. Action: email to customer and accounts receivable team. HR Welcome Email Trigger: New Employee record. Action: send onboarding instructions and manager notification. Stock Reorder Alert Trigger: Item reaches reorder level. Action: alert purchasing team with item list and locations. Workflow Approval Request Trigger: document submitted or status value change. Action: notify approvers with a link to approve in ERPNext. 14. Cron Jobs & Scheduler Events — Internal Mechanics Scheduler processes run at configured intervals to evaluate date-based notifications and other periodic tasks. The scheduler queries notifications configured with Days Before / Days After and applies filters to fetch candidate documents. Scheduler responsibilities Evaluate date-based rules daily/hourly. Queue matching notifications into Email Queue for worker processing. Perform cleanup tasks for old queue entries if configured. Scheduler performance depends on the number of documents to evaluate; using efficient filters reduces load. 15. Redis Queue (RQ) Worker Process Explained ERPNext relies on RQ to handle asynchronous tasks. RQ uses Redis as a broker and worker processes to execute jobs. Email sending is delegated to workers to maintain responsiveness. Queue lifecycle A job is enqueued (Email Queue entry created). A worker picks the job from the Redis queue. The worker executes the mail-sending function (connects to SMTP, sends mail). On success, the queue entry is marked sent; on failure, it may be retried or marked failed. Workers can be horizontally scaled for higher throughput. Monitor Redis memory usage when scaling. 16. Server Scripts + Notifications Integration Server Scripts provide a way to programmatically send emails when Notification doctype cannot express the desired logic. They run on the server and can invoke frappe.sendmail or create Email Queue entries directly. Example: After Save Script frappe.sendmail( recipients=[doc.owner], subject=f"Document {doc.name} updated", message=f"The document {doc.name} was updated by {frappe.session.user}.") Use server scripts for complex logic, external API integrations, or when you need to programmatically select recipients based on cross-document queries. 17. Python Code: Sending Custom Emails Programmatically Developers can use Frappe's API to send emails from custom apps or hooks. The frappe.sendmail helper handles recipients, subject, body, attachments, and related metadata. frappe.sendmail( recipients=["admin@example.com"], subject="Custom Notification", message="This is a test email", reference_doctype="Sales Order", reference_name="SO-0001" ) Advanced usage supports CC, BCC, file attachments, and inline images. When sending large batches, create queue entries instead of synchronous sends. 18. Webhooks vs Email Notifications — Technical Comparison Both webhooks and email notifications react to events, but their consumers differ. FeatureEmail NotificationWebhook Primary consumerHumans (customers, staff)External systems / services PayloadHTML or plain text emailJSON payload via HTTP POST Use caseAlerts, confirmations, remindersIntegrations, real-time sync, triggers Choose webhooks when you need programmatic handoffs to other systems; choose emails when communicating with people. 19. SQL Example: Retrieving Notification Logs Use SQL queries against ERPNext database (read-only in production environments) to audit recent email queue activity. SELECT name, status, reference_doctype, reference_name, creation FROM `tabEmail Queue` ORDER BY creation DESC LIMIT 50; Use this query in a safe, read-only context (e.g., analytics DB or while connected through appropriate privileges). 20. Performance Considerations & Optimization When your tenant sends many notifications, consider these optimizations: Prefer filters over conditions for bulk date-based operations. Avoid heavy loops in Jinja templates; precompute lists in server logic if necessary. Prune old queue entries to reduce table size and improve query speed. Scale workers horizontally if sending spikes occur, and monitor Redis usage. Cache or pre-generate expensive print format PDFs where possible. Profiling and monitoring are essential — measure queue length, worker latency, and SMTP response times to identify bottlenecks. 21. Security, Permissions, and Access Control Notifications can expose data by email, so secure configuration is essential: Limit recipients to necessary roles; avoid broad distributions. Mask or exclude sensitive fields (payment credentials, personal identifiers) in templates. Use secure SMTP with TLS and strong credentials stored in Email Account settings. Audit notification definitions regularly to ensure they do not leak confidential information. Notification sending may bypass some document-level permissions — the sender should ensure templates are safe for recipients. 22. Troubleshooting Errors — Real Examples & Fixes Issue: Email Not Sending Causes: SMTP credentials incorrect, worker down, queue failure, or notification disabled. Fixes: verify SMTP settings in Email Account, check worker processes (bench worker), inspect Email Queue for tracebacks. Issue: Jinja Template Error Example error: UndefinedError: 'items' is undefined Fix: ensure you reference the correct variable (doc.items) and handle empty lists in templates with conditional blocks. Issue: Email Queue Stuck Fix: restart bench/restart workers, inspect Redis, check for long-running jobs, and clear or requeue failed entries. Issue: Duplicate Emails Cause: overlapping notification rules or multiple triggers firing for the same event. Fix: consolidate rules, add precise conditions, or deduplicate in server scripts before queueing.
No comments yet. Login to start a new discussion Start a new discussion