Kaizen 233 Generating AI-Powered Follow-up Emails Using CRM Functions and Widgets

Kaizen 233 Generating AI-Powered Follow-up Emails Using CRM Functions and Widgets


Hey everyone!
Welcome back to another interesting post in the Kaizen series!

Sales teams regularly capture interaction notes in CRM after speaking with prospects. However, drafting a follow-up email that reflects the conversation context can be repetitive and time-consuming.

What if CRM could automatically generate a contextual follow-up email draft based on recent interactions with the lead?

In this Kaizen post, we will create a practical tool that generates context-aware follow-up emails directly from a Lead record. You will see how it pulls recent notes, lead's details, and crafts a ready-to-send draft.
The solution uses three Zoho strengths:
  1. Widgets for intuitive UI
  2. Functions for secure backend processing
  3. External AI APIs (like Groq or OpenAI)
The output displays in the widget. Review, tweak if needed, copy, and paste into your email composer.

The business challenge

Sales reps log calls like "Prospect interested in 20 user licenses but concerned about pricing. Explore volume discounts."
Now, crafting a response involves recalling details, matching tone, and ensuring professionalism. Miss a nuance, and trust erodes.
Our AI generator automates this. It scans the lead's details (name, company, status) and the three most recent notes, then prompts an AI model for a draft.

Example output
InfoSubject: Follow-up on CRM Licensing Discussion
Hi John,
Thanks for the insightful chat today about your team's CRM needs. You're considering licenses for around 20 users, and I appreciate pricing being a top priority.
I'll review our volume options and discount eligibility right away. Expect specifics by EOD tomorrow.
Best regards,
[Your Name]

This keeps the rep in control while slashing draft time from 10 minutes to 10 seconds. Scalable for high-volume teams.

High-level architecture

Think of a layered cake!
  1. UI Layer (Widget): Button launches it; displays, copies the draft, and sends the email.
  2. Logic Layer (Function): Fetches CRM data server-side, builds prompt, calls AI securely.
  3. AI Layer: External service generates natural language.

Flow

Rep clicks a button → Widget gets Lead ID → Calls function → Function queries CRM + AI → Draft back to widget

Secure (no client-side keys), reliable (server-side), and reusable across modules.

Developers often wonder "Why not fetch AI responses straight from widget JavaScript?"

Widgets run in a browser iframe, so embedding API keys exposes them to inspection or misuse. CORS policies can also block external requests, and complex logic like prompt building suits server-side better.
So, the best practice is to use widgets for UI and functions for secure server-side work. This hides credentials and reuses logic.

Follow these steps to build this solution.

Step 1: Add the custom Button

  1. Head to SetupModules and FieldsLeadsButtonsCreate New Button.
  2. Provide the following details:
    1. Name: Generate AI Email
    2. Placement: Record Detail Page (top or bottom)
    3. Action: Open Widget (select your widget once built)
  3. Save and add to layout.
  4. Test: Button appears on Leads; clicking loads widget in context.

Idea
Pro tip: Position near the "Send Email" button for seamless workflow.

Step 2: Build the CRM Function

  1. Go to SetupDeveloper HubFunctions+ Create Function.
  2. Enter the display name, function name, description, choose Standalone as the category.

  3. Click Create. The Functions IDE opens.
  4. Enter the following function code. Note that this example uses Groq AI API.
    string standalone.generate_ai_email(String leadId)
    {
    lead = zoho.crm.getRecordById("Leads",leadId);
    name = ifnull(lead.get("Full_Name"),"");
    company = ifnull(lead.get("Company"),"");
    status = ifnull(lead.get("Lead_Status"),"");
    // Fetch recent CRM Notes
    notesResp = zoho.crm.getRelatedRecords("Notes","Leads",leadId);
    recentNotes = "";
    count = 0;
    for each  note in notesResp
    {
    noteContent = ifnull(note.get("Note_Content"),"");
    if(noteContent != "")
    {
    recentNotes = recentNotes + "[" + (count + 1) + "] " + noteContent + ". ";
    }
    count = count + 1;
    if(count == 3)
    {
    break;
    }
    }
    // Build AI prompt
    prompt = "You are a sales assistant helping draft follow-up emails. ";
    prompt = prompt + "Generate a professional follow-up email based on the customer's previous interactions. ";
    prompt = prompt + "Lead Name: " + name + ". ";
    prompt = prompt + "Company: " + company + ". ";
    prompt = prompt + "Lead Status: " + status + ". ";
    prompt = prompt + "Recent CRM Interaction Notes: " + recentNotes + ". ";
    prompt = prompt + "Write a professional follow-up email referencing the discussion.";
    // Sanitize prompt
    prompt = prompt.replaceAll("\"","\\\"");
    prompt = prompt.replaceAll("\n"," ");
    prompt = prompt.replaceAll("\r"," ");
    // Build AI request
    message = Map();
    message.put("role","user");
    message.put("content",prompt);
    messages = List();
    messages.add(message);
    requestBody = Map();
    requestBody.put("model","llama-3.1-8b-instant");
    requestBody.put("messages",messages);
    requestBody.put("temperature",0.4);
    requestJSON = requestBody.toString();
    // Call Groq API
    response = invokeurl
    [
    type :POST
    parameters:requestJSON
    headers:{"Authorization":"Bearer YOUR_API_KEY","Content-Type":"application/json"}
    ];
    // Extract AI email
    emailContent = "";
    if(response.containsKey("choices"))
    {
    emailContent = response.get("choices").get(0).get("message").get("content");
    }
    // Return generated email to widget
    return emailContent;
    }

Notes
Note for production
  1. Connections: In the example, the API key is included directly in the function for simplicity. However, production deployments should use Connections instead of hard-coding credentials as they allow developers to store API credentials securely within Zoho CRM and reuse them across multiple integrations.
  2. Error Handling: Wrap invokeurl in try-catch.
  3. Limits: Cap notes at 3 to avoid token overflow and tune temperature (0.4 = consistent).
  4. Logging: Add info prompt before API call for debugging.
  5. Test: Execute with sample Lead ID. Expect clean email string back.
  6. Extend: Add phone/email from Lead, or filter notes by date (e.g., last 7 days via criteria).

Step 3: Develop the Widget

The widget provides the user interface for generating and copying the AI email.
When the widget loads, it retrieves the current Lead ID using the CRM widget JS SDK. When the user clicks Generate Email, the widget calls the CRM function and displays the generated email draft.
The widget also provides Send Email and Copy Email buttons that send the email to the lead record's email ID and copies the email content to the clipboard so the rep can past it into the email composer, respectively.

Sample index.html

<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<style>  <!-- Add your style here-->
</style>
</head>
<body>
<div class="widget-card">
  <div class="widget-header">
    <svg width="16" height="16" viewBox="0 0 24 24" fill="none" xmlns="http://www.w3.org/2000/svg">
      <path d="M20 4H4C2.9 4 2 4.9 2 6v12c0 1.1.9 2 2 2h16c1.1 0 2-.9 2-2V6c0-1.1-.9-2-2-2zm0 4l-8 5-8-5V6l8 5 8-5v2z" fill="white"/>
    </svg>
    <h2>AI Follow-up Email Generator</h2>
  </div>
  <div class="widget-body">
    <div class="email-box-wrapper">
      <textarea id="emailBox" placeholder="Click 'Generate Email' to create a contextual follow-up email..."></textarea>
    </div>
    <div class="action-bar">
      <button class="btn btn-primary" id="generateBtn" onclick="generateEmail()">
        <svg width="13" height="13" viewBox="0 0 24 24" fill="none"><path d="M12 2l2.4 7.4H22l-6.2 4.5 2.4 7.4L12 17l-6.2 4.3 2.4-7.4L2 9.4h7.6z" fill="white"/></svg>
        Generate Email
      </button>
      <button class="btn btn-success" id="sendBtn" onclick="sendEmail()">
        <svg width="13" height="13" viewBox="0 0 24 24" fill="none"><path d="M2 21l21-9L2 3v7l15 2-15 2v7z" fill="white"/></svg>
        Send Email
      </button>
      <button class="btn btn-secondary" onclick="copyEmail()">
        <svg width="13" height="13" viewBox="0 0 24 24" fill="none"><path d="M16 1H4C2.9 1 2 1.9 2 3v14h2V3h12V1zm3 4H8C6.9 5 6 5.9 6 7v14c0 1.1.9 2 2 2h11c1.1 0 2-.9 2-2V7c0-1.1-.9-2-2-2zm0 16H8V7h11v14z" fill="#3D4354"/></svg>
        Copy
      </button>
    </div>
    <div class="status-bar" id="statusBar"></div>
  </div>
</div>
<script src="index.js"></script>
</body>
</html>

Sample index.js

let leadId;
let leadEmail;
let generatedEmail = "";

// Widget initialization
ZOHO.embeddedApp.on("PageLoad", function(data){

    if(data && data.EntityId){

        leadId = data.EntityId[0];

        // Fetch Lead email
        ZOHO.CRM.API.getRecord({
            Entity: "Leads",
            RecordID: leadId
        })
        .then(function(response){

            if(response && response.data && response.data.length > 0){
                leadEmail = response.data[0].Email;
            }

        });

    }

});

ZOHO.embeddedApp.init();


// --- Helper functions used by email generation/sending ---
// function formatEmailText(raw) { /* formatting logic */ }
// function textToHtml(text) { /* convert plain text to HTML */ }
// function setStatus(message, type) { /* UI status logic */ }


// Generate AI email using a CRM function
function generateEmail(){

    var req_data = {
        arguments: JSON.stringify({
            leadId: leadId
        })
    };

    ZOHO.CRM.FUNCTIONS.execute('generate_ai_email', req_data)

    .then(function(response){

        if(response && response.details){

            generatedEmail = formatEmailText(response.details.output);
            document.getElementById('emailBox').value = generatedEmail;

        }

    })
    .catch(function(error){

        console.log('Function error:', error);

    });

}


// Send email using ZRC
async function sendEmail() {

    const emailContent = document.getElementById('emailBox').value.trim();

    if (!emailContent) return;

    try {

        // Get allowed "From" addresses
        const fromRes = await zrc.get('/crm/v8/settings/emails/actions/from_addresses');
        const fromAddress = fromRes.data.from_addresses[0];

        const htmlContent = textToHtml(emailContent);

        // Send mail
        const response = await zrc.post(`/crm/v8/Leads/${leadId}/actions/send_mail`, {

            data: [
                {
                    from: {
                        user_name: fromAddress.display_name || fromAddress.user_name,
                        email: fromAddress.email
                    },
                    to: [
                        {
                            email: leadEmail
                        }
                    ],
                    subject: 'Follow-up',
                    content: htmlContent,
                    mail_format: 'html'
                }
            ]

        });

        console.log('Mail sent:', response);

    } catch (error) {

        console.error('Send mail error:', error);

    }

}

// Copy generated email
// function copyEmail(){ /* copy logic */ }
Info
The  ZIP containing the complete index.js and index.html files used in this example is attached at the end of this post.

Refer to Creating a Widget in Zoho CRM and the JS SDK for more details on CLI installation, creating, packaging, and hosting a widget.

User experience walkthrough

  1. The salesperson clicks Generate AI Email on the record detail page and the widget opens.
  2. The salesperson clicks the Generate AI email button. The widget retrieves CRM context and generates a contextual follow-up email draft.
  3. The email appears inside the widget, allowing the salesperson to quickly review the generated message, and use the Send Email button to send it to the lead's email ID.
This workflow ensures that AI assists with drafting the message while still allowing the salesperson to review and control the final communication.

Here is a GIF explaining the use case in action.


Key takeaways

This example demonstrates how Zoho CRM developers can integrate generative AI into CRM workflows using platform-native tools.
Combine CRM Widgets for user interaction and Functions for secure server-side processing to safely integrate external AI services without exposing credentials or compromising security.

The same architecture can be extended to build more advanced AI features, such as:
  1. Automated meeting summaries
  2. Deal health insights
  3. Proposal drafting assistants
  4. Intelligent follow-up recommendations

We hope you liked this post. Let us know what you think in the comments or reach out to us at support@zohocrm.com.
Cheers!



===================================================================================



    • Sticky Posts

    • Kaizen #198: Using Client Script for Custom Validation in Blueprint

      Nearing 200th Kaizen Post – 1 More to the Big Two-Oh-Oh! Do you have any questions, suggestions, or topics you would like us to cover in future posts? Your insights and suggestions help us shape future content and make this series better for everyone.
    • Kaizen #226: Using ZRC in Client Script

      Hello everyone! Welcome to another week of Kaizen. In today's post, lets see what is ZRC (Zoho Request Client) and how we can use ZRC methods in Client Script to get inputs from a Salesperson and update the Lead status with a single button click. In this
    • Kaizen #222 - Client Script Support for Notes Related List

      Hello everyone! Welcome to another week of Kaizen. The final Kaizen post of the year 2025 is here! With the new Client Script support for the Notes Related List, you can validate, enrich, and manage notes across modules. In this post, we’ll explore how
    • Kaizen #217 - Actions APIs : Tasks

      Welcome to another week of Kaizen! In last week's post we discussed Email Notifications APIs which act as the link between your Workflow automations and you. We have discussed how Zylker Cloud Services uses Email Notifications API in their custom dashboard.
    • Kaizen #216 - Actions APIs : Email Notifications

      Welcome to another week of Kaizen! For the last three weeks, we have been discussing Zylker's workflows. We successfully updated a dormant workflow, built a new one from the ground up and more. But our work is not finished—these automated processes are
      • Recent Topics

      • Is this a SCAM email or is it really Zoho?

        L.S. I received the following message. Is this from Zoho? I have had a Zoho One account for many years and my website has been online for years. If it is a scam, I think you should know about it.
      • Is it possible to use HTML formatting in SMS messages sent from Zoho?

        Hi everyone, I have a question regarding sending SMS from Zoho When we send emails from Zoho, we can include HTML code to format the message (like adding links, styling, etc.). Is it possible to do something similar when sending SMS messages through Zoho
      • an issue in Zoho CRM where the workflow rule is not triggering

        H I’m currently facing an issue in Zoho CRM where the workflow rule is not triggering when a new lead is created through a webform. I’ve double-checked the criteria and field updates, everything seems fine but it still doesn’t fire. Has anyone faced this
      • Option in pipeline deal to select which hotel or branch or store if client has more than one local store

        Hi, I would like to know if there is an option in the deal pipeline to select which hotel, branch, or store a deal is related to—if the company has more than one location. For example, I have a client that owns several hotels under the same company, and
      • Email Insights included in Bigin emals are marked as SPAM everywhere

        Today I noticed that email recipients who use Office 365 never receive emails sent from Bigin. Further examination showed that all Email Insights links in email headers are marked as spam/phishing by Office 365. Example screen included. The problem is
      • Email Parser Not Extracting Fields Correctly with Certain Label Formats

        I’ve been testing the Email Parser functionality in Zoho CRM to automatically extract data from incoming emails and map it to CRM fields. During testing, I noticed that parsing sometimes fails when the email contains field labels formatted like this:
      • How do I import Connected Records for a Deal?

        Can you point me to an example of the CSV file that would add related records to an existing CRM Deal? I imported a Deal, then tried importing a connected record using a unique ID that references the Deal ID, but it doesn't attach it to the Deal rec
      • File Upload Field in Zoho Forms Not Updating Existing File in Zoho CRM

        Hi everyone, I’m trying to understand the behavior of a file upload field mapped from Zoho Forms to Zoho CRM. Scenario There is a File Upload field in a Zoho CRM module. A Zoho Form also has a File Upload field, which is mapped to that CRM field. When
      • Zoho Training

        Greetings! I am trainer. My focus area is Project Management and MS Project. I have used Zoho CRM to a good extent. Though, I was interested in using ZOHO projects, as there were no live projects, I could not take it up for studies. Recently a client
      • Detailed list of scoring rules in Zoho CRM

        Good morning Zoho community, warm greetings The reason for my message today is that I have a problem with my CRM, which I will explain below: Our organization has scoring rules designed to rate our potential customers or leads in the application based
      • How to create a summary document from Projects details

        Hi, Our team is creating many projects inside Zoho Project. When closing a project, they write a summary document containing data from the projects it-self (understand project budget, customers, etc...), and editable (ie the document is either a Writer
      • Request to Recover Deleted Task List – Project ID: RIV-MOD-10722

        Hi Zoho Team, I hope this message finds you well. My Zoho task list associated with Project ID: RIV-MOD-10722 appears to have been deleted. When I clicked on the task link from the email notification, I received the following message: "Task has been deleted
      • Host in US Data Centre

        I humble apply to be registered on US Data centre
      • convert the project to templet

        i have some deployment ME product for different customer , i need to create a fixed template for use it rather then keeping creating this template every time
      • Best practices for managing Project Charters, Business Case and RAID logs within Zoho?

        Hello everyone, I’m currently refining our PMO setup within Zoho Projects and I’m curious how others are handling high-level governance documentation. We’ve been using the standardized Project Charter, Business Case and RAID frameworks from projectmanagertemplate.com
      • Resource Management System built using Zoho CRM, Creator, Projects, and People:

        In a Resource Management System built using Zoho CRM, Creator, Projects, and People: CRM Deal Closed → Creator Allocation Engine → Zoho Projects Task Assignment What is the recommended architecture to handle dynamic reassignment when: an employee goes
      • Dynamic Remaining Quantity in Lookup During Allocation

        Hi everyone, From what I understand in Zoho Creator, lookup fields only display the stored value from the source record and do not dynamically update while a form is being filled. Because of this, showing a real-time updated remaining quantity inside
      • connect zoho creator with google drive

        Hello everyone, I need to connect to a folder drive. The idea, is that google drive loads a text document with some data, I must read that text document to be able to autofill a form that I have in zoho creator with that data. I also attach PDFs and place
      • Ability to Attach Record-Specific Files Automatically in Workflow Email Templates

        Currently in Zoho CRM, email templates allow attachments to be added, but these attachments are static and remain the same for every recipient. There is no straightforward option to automatically attach a file that is stored within the specific CRM record
      • Uploaded files are not included when using "Include user submitted data" in Email Notification

        In Send Email notification workflow in Zoho Creator, there is an option called "Include user submitted data" which allows the email to contain all the form submission details. However, when this option is enabled, files or images uploaded through File
      • kanban view for client portal

        Are kanban views an option for client portals? Access to Kanban views in the client portals would solve some mobile-compliant issues I have with the UI. Kanban functions very nicely on mobile and would be a super asset for my clients and vendors as they
      • Credit Card Pre-Authorization with later Capture/Settlement

        We really enjoy the convenience of being able to pay off a customer's invoice using our Auth.Net integration with Zoho Books. Unfortunately, we can only take advantage of this feature with a small percentage of our customers as it leaves a gaping hole
      • Zoho Cliq not working on airplanes

        Hi, My team and I have been having this constant issue of cliq not working when connected to an airplane's wifi. Is there a reason for this? We have tried on different Airlines and it doesn't work on any of them. We need assistance here since we are constantly
      • Zoho Sign 2025–2026: What's new and what's next

        Hello! Every year at Zoho Sign, we work hard to make document signing and agreement execution easy for all users. This year we sat down with our head of product, Mr. Subramanian Thayumanasamy, to discuss what we delivered in 2025 and our goals for 2026.
      • Work Orders / Bundle Requests

        Zoho Inventory needs a work order / bundle request system. This record would be analogous to a purchase order in the purchasing workflow or a sales order in the sales cycle. It would be non-journaling, but it would reserve the appropriate inventory of
      • Izettle or Sumup Integration for Zoho Books.

        The Stripe & Square clearing works great in Zoho Books. Any further integrations planned in the future for Izettle or Sumup? These card processors are very common for taking payments with a card reader.
      • Train Zoho Answer Bot Based on Customer

        Hi all, Is it currently possible to mark Help Centre articles to a specific customer, and restrict the answer bot to only use relevant information if it is either marked as "General", or tagged for the specific customer in question? We currently have
      • Trying to access records in a custom module in Zoho Desk and not having luck

        I've built a custom module in Zoho Desk and am using a custom function to query the records in the module and I'm not having any luck. The only way I have found to retreive a record is by getting it by its recordID (the long zoho assigned one). The function
      • Composite items inside of composite items; bill of materials needed

        Hi Zoho and Everyone, I am evaluating whether Zoho Inventory will work for my small business. I grow and harvest herbs and spices but also get from wholesalers. I use all these items to make herbal teas, but also sell them as individual items on my Shopify store and Etsy. I discovered the composite item bundling and am wondering if I could get some assistance since there is no bill of materials: Our herbal company's best selling tea is a sleepytime tea. Sleepytime Tea can be purchased in three weights
      • ZOHO Books Smart Accounting Software for Travel Agency

        Dear Travel partner, Contact for Travel Agency Accounting Setup & Training Vansh Travel (ZOHO Books Authorised partner) Email: info@vanshtravel.com Mo: +91 98984 95155 Please find PDF   
      • 452 Mailbox delivery restricted by policy error

        We have been testing Zoho desk for about a week now and have been forwarding emails in via an Exchange Online Mail flow rule without issue until yesterday. Suddenly yesterday morning we started getting the vast majority of the emails stuck in Pending
      • Send Email reply on behalf of Agent

        Hi, When using the send email reply via the API I can set the reply on behalf of the customer by using impersonatedUserId in the header of the API call. Is there a way to do this for Agents too? I need to be able to send an email reply on behalf of an
      • Sharing Tickets to a team within a department

        Hi there, We have a need for one department to be able to share tickets to a specific team within a department, I'm wondering if this is possible? All the shared tickets are going into the 'Shared Tickets' view for the whole department but is there a
      • Removing To or CC Addresses from Desk Ticket

        I was hoping i could find a way to remove unnecessary email addresses from tickets submitted via email. For example, a customer may email the support address AND others who are in the helpdesk notification group, in either the TO or CC address. This results
      • Do not use isnull()

        Does not always return booleans. Can also return null. Never use this function. Just use var==null instead.
      • Organization wide Account and Contacts Visibility/Sharing Capabilities?

        Has anyone figured out a way to make visibility or sharing of Accounts and Contacts to be available across the entire organization without having to have every individual user edit their Sharing permissions? For our sales folks they need to be able to
      • Is there a way to configure dark mode for Campaigns emails that go out to customers?

        I've found a lot of information on how to configure dark mode for my (The user) personal Zoho workspace and email, but is there any way to edit dark mode settings on emails that we send out to customers via campaigns?  We sent out a test email the other
      • When Does WorkDrive integrate with Books?

        When Does WorkDrive integrate with Books?
      • FSM integration with Books

        Hi, I have spent a few months working with FSM and have come across a critical gap in the functionality, which I find almost shocking....either that, or I am an idiot. The lack of bi-directional sync between Books and FSM on Sales Orders/ Work Orders
      • How to close an estimate ?

        Hello, I have created estimates, and converted them to invoices to get 50% payment. Now I have 2 cases where the estimate stills shows status partially invoiced, however: 1. for one of them, project stopped half way, so the remaining part will never be
      • Next Page