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

    Nederlandse Hulpbronnen


      • Recent Topics

      • How to add a filter

        Hi Team, How can I set a filter like excel, instead of adding a new button.
      • A POS solution to complete the business solution for SME businesses

        For such a long time one aspect of SME business completely ignored has been a suitable POS solution native to Zoho and integrated with all the usual and necessary applications such as Inventory, Books, Commerce and CRM. The first and generally only option
      • Introducing SlyteUI : From Idea to a Working Interface in Minutes

        Hello everyone! Are you spending hours building basic UIs? Does even the smallest customization feel like a major task? CRM customization should feel intuitive and straightforward, not time consuming or exhausting. SlyteUI makes this possible by simplifying
      • Zoho Form not synching with Zoho CRM in CRM email template

        I have in the past successfully created an email template that has access to a Zoho Form in the url link to Forms in the email template. I am in the Contact Module of the CRM and I have created a Form for contacts and mapped the two. I am using the upsert
      • Using Zoho CRM to manage NBI Clearance applicants – need workflow advice

        Hi everyone, I’m currently helping manage applications related to NBI Clearance services (appointments, document tracking, and status updates). Right now, everything is being handled manually and it’s getting confusing when multiple applicants are involved.
      • Bulk upload images and specifications to products

        Hi, Many users have asked this over the years and I am also asking the same. Is there any way in which we can bulk upload product (variant) images and product specifications. The current way to upload/select image for every variant is too cumbersome.
      • Super Admin Logging in as another User

        How can a Super Admin login as another user. For example, I have a sales rep that is having issues with their Accounts and I want to view their Zoho Account with out having to do a GTM and sharing screens. Moderation Update (8th Aug 2025): We are working
      • Schedule Timeout 5 minutes vs. stated 15 minutes

        I am running into a function run timeout error after 5 minutes for my schedules. The Functions - Limits documents states it should be 15 minutes: Functions - Limits | Online Help - Zoho CRM. What should it actually be? Due to the 5 minute timeout, I'm
      • Coupon Codes and Cancelling Subscriptions

        We have two Zoho One organizations, one we use for dev/testing. In Zoho Billing when we cancel a subscription, we are getting two different behaviors with regards to coupons. In one environment, the coupon is removed upon cancellation. In the other, the
      • Zoho Books | Product updates | April 2026

        Hello users, Welcome to our April 2026 product updates roundup! Highlights include profit margin for sales transactions, insights in reports, recording deposits from undeposited funds in banking, and faster production workflows with improved assembly
      • Journal Entries Do Not Show Multiple Entries to the Same Account

        Another basic accounting function that Books ... Accountants sometimes write journal entries, debiting and/or crediting the same account in the same entry. This is due to the need to record specific activity in an account when we pull reports especially
      • Bulk Writer Export

        Pardon me if this has already been discussed (I can't find anything about it in these forums and my last attempt to start a thread seems to have failed). Is it possible to export more than one document at once? I would be really great to be able to burn OpenOffice.Org files of all my Zoho documents once a month to a CDR. If that feature is available/were created, this would be my main word processor. Without being able to do my own bulk backups I'm leery to count on Zoho's servers (which are robust
      • Sites API

        Is there a Sites API and if so where can we find documentation
      • Extracting phone number from variable

        Hi. I've created a flow between Calendly and Zoho CRM. So when someone schedules a meeting in Calendly, there is a lead created in Zoho CRM. However, I am not able to fill in the phone number field in Zoho CRM, because the phone number is included in
      • I can't fetch Calendly Fields

        Hello, I have set up a flow to connect Calendly with Zoho CRM, A few days ago I have mentioned that I should update the Calendly app connection and I have done, After Calendly has been updated I have some issues such as Event location missing I can map
      • Edit a previous reconciliation

        I realized that during my March bank reconciliation, I chose the wrong check to reconcile (they were for the same amount on the same date, I just chose the wrong check to reconcile). So now, the incorrect check is showing as un-reconciled. Is there any way I can edit a previous reconciliation (this is 7 months ago) so I can adjust the check that was reconciled? The amounts are exactly the same and it won't change my ending balance.
      • FSM- are we getting there

        We have now tried the FSM a couple of times. We have been defeated on the offline access. As you can imagine the enginner needs to know the customers details, the job and the equipment. This needs to be cache. Is it yet? Plus Our engineers do multiple
      • Canvas and calendar

        Is it possible to have a canvas view that shows say a contacts details with the meetings calendar on the same page?
      • What's new in Zoho Social - Q1 recap

        Hello everyone, We’ve rolled out a bunch of updates in Q1, and we’re excited to walk you through them. To help you explore these features in detail, we’re hosting a Q1 recap webinar where we’ll show you how to make the most of each update. Q1 recap webinar
      • Ignore Auto Sales Order number generation not working

        Hi, My Flow has broken and I'm no longer able to use the Ignore auto number generation function and instead use the field that came from the trigger (via Jotform) when creating a new Sales Order in Books. Any suggestions how to fix this?
      • Split Bills/Expsense between multiple projects and/or clients

        I need to be able to split vendor invoices/ expenses between multiple clients. Entering the bill multiple times is not only time consuming, it defeats the purpose of having a unquie identifity bill number and will allow for possible duplicated entry.  Below is an example from Quickbooks Desktop. Splitting costs over various projects is a common job costing function that I am very sad and surprised is not an option in Zoho Books. Unless I am missing it somewhere? Thanks for your help!
      • Vendor bills cannot be assigned to a customer or a customer project?

        I'm confused on how to handle outsourced contractor expenses on a customer project.  Between my business and the contractor, the invoice they send me fits obviously into Zoho Books as a Bill. However, I need to be able record those expenses to the client
      • Anyone using Books to track Project Profitability? If so, I could use some guidance

        Hello Zoho Community. I am a recent subscriber to Zoho, and its part of an ongoing evaluation.  My company (and my clients) have extensive project-tracking needs.  The Projects module seems to be good from a project management standpoint, but I am perplexed
      • Introducing parent-child ticketing in Zoho Desk [Early access]

        Hello Zoho Desk users! We have introduced the parent-child ticketing system to help customer service teams ensure efficient resolution of issues involving multiple, related tickets. You can now combine repetitive and interconnected tickets into parent-child
      • Problem in usage zoho

        Difficulty to submit the from in my training to handle ticket on your free trial
      • Automation Series: Assign Subsequent Task Owner on Completion

        When a project progresses, tasks get piled up over time. As new tasks are created, tracking ownership and assigning them can become time consuming. In a pharmaceutical manufacturing unit, the procurement phase involves a set of tasks such as raw material
      • In-House, Non-Billable Projects

        I use Zoho Projects solely for in-house projects with fixed cost budgets.  Only bills and expenses need to be charged against the budget.  There are no customers to be billed or invoices to be created. How can such a non-billable project be set up?   As
      • [Webinar] What's New in Zoho Analytics: Q1, 2026

        To all the data enthusiasts out there, we're back again with another power-packed webinar in the What's New series! This last quarter was marked by exciting new features and product updates focused on offering you top-notch solutions. With new data connectors,
      • Ask The Expert: Deep Dive into Zoho CRM, Desk, SalesIQ, and Campaigns!

        Are you using Zoho to power your sales, support, and marketing, and have questions about configuration, automation, or best practices? We have great news: the “Ask The Expert” session is coming to the Zoho Benelux Community! This session is specifically
      • Workflows being applied and the Large unwanted popup

        When a workflow is being applied do to an action, then the Agent is left with a large Window asking if they would like the see the changes this workflow did. Is there any way to disable this prompt from appearing?
      • Users I've shared the sheet with cannot use the Custom Functions

        Hi, I have a Zoho Sheet worksheet that I shared to 2 colleagues, giving them full access: In that worksheet, I created a button with a custom Deluge function and it works flawlessly for me: For those I shared the worksheet to, when they click the button,
      • Limiting the form - Zoho People

        Hi Team, I would like to limit the number of form/request submissions for employees within a given month. For example, if an employee has already submitted 3 requests in the current month, they should not be allowed to submit any further requests. An
      • Zoho Analytics: Clarification on Email Schedule Limits in Basic Plan

        Hi Team, I have a question regarding the email scheduling limits in the Zoho Analytics Basic Plan. The plan shows that I can create 4 email schedules. However, I understand that schedule consumption is calculated based on recipients (i.e., 1 schedule
      • Standardize your booking forms with Centralized Customer Form

        We’re excited to introduce Centralized Customer Form, a new way to manage and standardize how customer information is collected across your event types. With this feature, you can define a common set of booking form fields once and apply them across your
      • Zoho Creator In-App Notification

        Hi Team, I have implemented an in-app notification using code, as it required some customization. I followed the example in the link below: https://www.zoho.com/deluge/help/pushnotify-using-deluge.html#Example I have a couple of questions regarding this
      • Add Flexible Recurrence Options for Meeting Scheduling in Zoho Cliq (e.g., Every 2 Weeks)

        Hello Zoho Cliq Team, We hope you are doing well. Currently, when scheduling a meeting inside Zoho Cliq, the recurrence options are limited to Daily, Weekly, Monthly, and Yearly. There is no ability to set a meeting to occur every X weeks — for example,
      • Announcing Zoho Sheet desktop app for macOS and Windows (Beta)

        Hello Sheet users, We know you’ve been waiting for this one. It has always been the top priority on our roadmap to provide a single native desktop app for macOS and Windows that works both online and offline. Today, we are excited to announce that the
      • In App Auto Refresh/Update Features

        Hi,    I am trying to use Zoho Creator for Restaurant management. While using the android apps, I reliased the apps would not auto refresh if there is new entries i.e new kitchen order ticket (KOT) from other users.   The apps does received notification but would not auto refresh, users required to refresh the apps manually in order to see the new KOT in the apps.    I am wondering why this features is not implemented? Or is this feature being considered to be implemented in the future? With the
      • Unable to Log In to FSM Mobile App

        Hello FSM Team, We are encountering an issue when logging in to the FSM mobile app. When entering the user email, the system shows the error: “This account does not exist.” However, the same user is able to log in successfully via web (fsm.zoho.com).
      • Clarification on “Change Owner” vs Dispatcher Role in Work Orders

        Hi Mr. Abid, Good day! We would like to understand the purpose and correct usage of the “Change Owner” option in the Work Order module. As we noticed, there is an option to Change Owner in the Work Order. At the same time, there is also a separate field/role
      • Next Page