Sending Notifications in Frappe Programmatically

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:

  1. It is synchronous

It runs immediately → can slow down request if many users

  1. No queue management

It does not use background workers

  1. 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:

  1. Runs in background (async)

Uses frappe.enqueue() → does not block request

  1. Handles large user lists safely

Automatically deduplicates users

  1. Filters invalid users

Only enabled + valid users get notifications

  1. Works with system safety checks

Skips during installation or unsafe states

  1. 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:

  1. Global setting is ON: enable_email_notifications = 1
  2. Specific type is enabled: “Mention / Assignment / Share”
  3. Alert type special case: Alert notifications 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.

3 Likes

Hi @mohamed-ameer

Thanks for these articles. It looks like you are an expert in these things.

I would suggest you help Frappe improve their core documentation as I fear these articles will get lost in the Forum and new users might miss these gems

If yes check out https://docs.frappe.io/framework/user/en/how_to_contribute

After contributing you can follow them up with a Frappe Approver on Frappe Community Chat | Raven

Hope this can benefit everyone

1 Like

Thank you so much sir :folded_hands:
definitly contribute in the documentation will be more better