How to Send Email from a Server Script on Button Click in Frappe?
Send Email on Button ClickLearn how to create a Frappe server script to send customized emails to a list of recipients from a child table when a custom button is clicked in a DocType.
This server-side script demonstrates a common business requirement in Frappe/ERPNext: sending bulk, personalized emails based on data within a document, triggered by a user action like a button click. This pattern is highly effective for sending event invitations, status notifications, or alerts to a list of stakeholders defined in a child table.
The code iterates through a child table to gather recipient emails, constructs a dynamic subject line, and utilizes Frappe's built-in `frappe.sendmail` utility to dispatch the emails.
1 # In [doctype_name].py 2 import frappe 3 from frappe.model.document import Document 4
5 class YourDocType(Document): 6 @frappe.whitelist() 7 def send_internal_invitation(self): 8 subject = "Invitation: '" + self.title + "' on date: " + self.get_formatted('date') 9
10 # 'meeting_company' is the fieldname of the child table 11 for row in self.meeting_company: 12 frappe.sendmail( 13 recipients=[row.user_id], # 'user_id' is a field in the child table holding the email 14 sender=frappe.session.user, 15 subject=subject, 16 message=self.invitation_message, # 'invitation_message' is a field in the parent DocType 17 reference_doctype=self.doctype, 18 reference_name=self.name 19 ) 20 21 self.status = "Invitation Sent" 22 self.save() 23 frappe.db.commit() 24 frappe.msgprint("Invitation Sent to Company Representatives")
Understanding This Code
What It Does
This server-side Python method sends an email to each user listed in a child table of a DocType. It's triggered by a custom button on the DocType form.
When To Use
Use this script when you need to perform a bulk action, like sending notifications, to multiple related records (stored in a child table) with a single click from the parent document form.
Prerequisites
- •A parent DocType with a custom button.
- •A child table within the parent DocType containing a field for the recipient's email address (e.g., a field of type 'Data' with option 'Email', or a Link to User).
- •The method must be whitelisted using `@frappe.whitelist()`.
Key Concepts
Important ideas to understand in this code
@frappe.whitelist()
A security decorator in Frappe that marks a Python method as callable from the client-side (e.g., through a UI button click or an API call). Any method intended to be triggered from the user interface must be whitelisted.
Learn morefrappe.sendmail
A high-level Frappe API for sending emails. It simplifies the process by handling email queueing and using the system's default email settings. It takes parameters like recipients, subject, message, and optional references.
Learn moreChild Table Iteration
Child Tables in Frappe are stored as a list of document objects on the parent document. You can iterate through this list using a standard Python 'for' loop to access the data in each row of the child table.
Learn moreself.save() and frappe.db.commit()
`self.save()` saves the document's current state within the ongoing database transaction. `frappe.db.commit()` permanently writes that transaction to the database. Committing ensures the status change is immediately visible to all users.
Learn moreStep-by-Step Tutorial
Follow along to understand how this code works
Define the Server-Side Method
In your custom app, locate your DocType's Python file (e.g., `my_app/doctype/my_doctype/my_doctype.py`). Add the method inside the DocType's class and make sure to decorate it with `@frappe.whitelist()`.
import frappe
from frappe.model.document import Document
class YourDocType(Document):
@frappe.whitelist()
def send_internal_invitation(self):
# ... implementation from above ...Create a Custom Button in the DocType
Navigate to 'DocType List', open your DocType, and scroll down to the 'Actions' section to add a new button. Give it a descriptive 'Label', like 'Send Invitation'.
// This is a UI configuration step, not code.
// 1. Go to 'DocType List' and select your DocType.
// 2. In the settings, scroll to the 'Actions' or 'Buttons' grid.
// 3. Add a new row and set the 'Label' for your button.Link the Button to the Method
To link the button to your server script, you need to create a simple Client Script that calls the whitelisted method.
// Create a new Client Script for your DocType
frappe.ui.form.on('YourDocType', {
refresh: function(frm) {
// Add the button if it doesn't exist
frm.add_custom_button(__('Send Invitation'), function() {
// Call the server-side method
frappe.call({
method: 'your_app.doctype.your_doctype.your_doctype.send_internal_invitation',
args: {
doc_name: frm.doc.name
},
callback: function(r) {
if (!r.exc) {
frm.reload_doc();
}
}
});
});
}
});Common Issues & Solutions
Troubleshoot problems you might encounter