Programmatic Notifications in Frappe
In Frappe, notifications are used to inform users about important events like assignment, mention, share, alerts, etc.
But internally, Frappe does not directly send notifications one by one. AGAIN =>
In Frappe, notifications are not sent directly to users.
Instead, the system follows a proper flow:
First create Notification Log → then trigger realtime update → then optionally send email → based on user settings.
So instead of directly sending messages, we create a Notification Log entry, and Frappe handles the rest automatically (you are not “sending notification”, you are creating a trigger, and Frappe handles everything).
Our Samble Code:
users = ["email1", ...]
notification_doc = {
"document_type": self.doctype,
"type": "Alert",
"subject": notification_subject,
"email_content": notification_message,
"document_name": self.name,
"from_user": frappe.session.user,
}
make_notification_logs(notification_doc, users)
What This Code Actually Does
When you call make_notification_logs():
Step 1: It creates Notification Log records
For each user: A Notification Log document is inserted in DB
Step 2: after_insert hook triggers automatically
Inside Notification Log:
- Realtime notification is sent (frappe.publish_realtime)
- Unseen count is updated
- Email is sent (if user settings allow it)
So basically:
- You are not sending notification directly
- You are just creating a “log”, and Frappe system takes care of everything after that
Problem with Direct make_notification_logs()
Even though your code works, it is NOT the recommended approach in production.
Because:
- It is synchronous
It runs immediately → can slow down request if many users
- No queue management
It does not use background workers
- No installation safety checks
It may fail during system setup or high load conditions
Recommended Approach (Frappe Standard Pattern)
Instead of calling make_notification_logs() directly, Frappe uses enqueue_create_notification(). This is the official production-safe method.
why enqueue_create_notification() is better?
Because it:
- Runs in background (async)
Uses frappe.enqueue() → does not block request
- Handles large user lists safely
Automatically deduplicates users
- Filters invalid users
Only enabled + valid users get notifications
- Works with system safety checks
Skips during installation or unsafe states
- Uses proper Frappe worker queue system
So system stays fast even with heavy notifications
Recommended Code
from frappe.desk.doctype.notification_log.notification_log import enqueue_create_notification
users = ["email1", "email2"]
notification_doc = {
"document_type": self.doctype,
"type": "Alert",
"subject": notification_subject,
"email_content": notification_message,
"document_name": self.name,
"from_user": frappe.session.user,
}
enqueue_create_notification(users, notification_doc)
When you use enqueue_create_notification():
Step 1: You send request → “Notify these users”
Step 2: Frappe puts job in queue (Redis + worker system)
Step 3: Worker executes make_notification_logs()
Step 4: Notification Logs are created
Step 5: After insert:
- Realtime notification sent
- Email sent (if enabled)
- Unseen counter updated
How Email Notification Works in Frappe
Now the important part — Email sending is automatic but controlled.
- Frappe does NOT send email directly from your code.
- It sends email only when Notification Log is created.
Email Flow
- Step 1: Notification Log is created
- Step 2: after_insert hook triggers
- Step 3: System checks user settings
- Step 4: If allowed → email is sent
When Email is Sent Automatically?
email is sent only if:
- Global setting is ON: enable_email_notifications = 1
- Specific type is enabled: “Mention / Assignment / Share”
- Alert type special case:
Alertnotifications type do NOT trigger email by default
Programmatic Email Notification (Direct Method)
Sometimes you don’t want Notification Log system.
You just want to send email directly.
For that use: frappe.sendmail()
import frappe
frappe.sendmail(
recipients=["[email protected]"],
subject="Task Assigned",
message="You have been assigned a new task",
reference_doctype=self.doctype,
reference_name=self.name
)
Email Notification Settings
Users can control email notifications in their Notification Settings
- enable_email_notifications: Master switch for all email notifications
- enable_email_mention: Email for mentions
- enable_email_assignment: Email for assignments
- enable_email_share: Email for document shares
- enable_email_event_reminders: Email for calendar events
Key Concept (Very Important)
- You are NOT sending notification directly
- You are creating a Notification Log
Then Frappe system automatically handles:
- Realtime UI update
- Email sending
- User preference checks
- Notification type filtering
| Type | Use Case |
|---|---|
| Alert | System alerts, reminders |
| Mention | When users are mentioned in comments |
| Assignment | Document assignment updates |
| Share | When documents are shared with users |
| Energy Point | Gamification points awarded |
| Method | Use Case | Recommended |
|---|---|---|
make_notification_logs() |
Internal framework usage / testing / small scripts | Not recommended |
enqueue_create_notification() |
Production / real systems / System notification + email + realtime | Recommended |
frappe.sendmail() |
Only email (custom logic) |
One-Line Summary
In Frappe, notifications are not sent directly — we create Notification Logs, and the system automatically takes care of realtime + email + user preferences. Always use enqueue_create_notification() in production.