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

    • Unable to create new finance account in Zoho Books Android app due to missing account number field.

      Free plan I have enabled a setting via the website requiring unique account codes to be specified for all accounts. When using the android app, go to expenses, new expense, select account, new account. Promoted to enter the Account name and description.
    • How to Fetch data from Sales Order and Insert into Purchase Order with Deluge

      Hello, I am wanting to write a Deluge script that would take the shipping address on a Sales Order and upon conversion to a Sales Order automatically insert it into that corresponding PO. I am new to Deluge but understand that it has great capabilities.
    • Google Drive shared folder

      My deluge script has stopped working, no longer collecting files from Google Drive - have these connections finally been deprecated ?? They seem to be active but errors occur when updating them ?
    • Zoho Desk: Mobile Updates | Q1 2026

      Hello everyone, Greetings! As we gear up for the end of Q1, we are excited to share a quick journey into all that released in the first quarter of 2026. We have brought in a few enhancements in the mobile apps that improve overall user experience and
    • CRM x WorkDrive: We're rolling out the WorkDrive-powered file storage experience for existing users

      Release plan: Gradual rollout to customers without file storage add-ons, in this order: 1. Standalone CRM 2. CRM Plus and Zoho One DCs: All | Editions: All Available now for: - Standalone CRM accounts in Free and Standard editions without file storage
    • Additional Address - Company Name

      It would be very helpful to have a "Company Name" field in the Additional Address shipping section.  In a situation where you drop-ship orders to a different address or different company entirely, it may be necessary to list the company name of the receiver. I understand that the Attention field can be used for that purpose, but that's not really the intended purpose of that field.
    • Zoho Payroll's Kuwait, Oman, Qatar, Bahrain and Canada edition is available in Zoho One

      Great news for Zoho One users! Zoho Payroll has expanded to five new regions: Kuwait, Oman, Qatar, Bahrain, and Canada. And the best part? These new editions are fully integrated with Zoho One, just like our existing editions in India, the UAE, Saudi
    • Does Zoho Creator support multilingual translation for user-entered data?

      I understand that Zoho Creator provides localization support for UI elements such as field labels and static text. I would like to know: Does Zoho Creator support automatic translation of user-entered data (for example, form inputs or stored records)
    • Upload field on tasks module

      Hello, Why I cannot add an upload field to a Task? Or maybe when creating the task make attachements visible, so you can add an attachement while creating the task? Looking forward to your response! Moderation Update: The Canvas detail view for the Tasks
    • WhatsApp phone number migration

      Hi @Gowri V and @Pheranda Nongpiur, Thanks for implementing the promised enhancements to the integration between Zoho CRM and WhatsApp. The previous discussion has been locked, so I'm opening this new one. I am copying below a specific
    • How to let club members update their own profile data

      Our club has about 200 members. We keep names, addresses, phones, emails, payment records, etc. for each, recently migrated to Creator. Once a year I send email to each member to confirm or correct their info on file with us, as well as ask for payment
    • Document retention in Zoho Sign

      Document management doesn’t end at signing. It extends to how long you retain agreements—and how securely you dispose of them. With the document retention option in Zoho Sign, you can define structured, policy-driven timelines for managing completed documents.
    • Sales Allowed Beyond Available Stock and Payment Recorded Without Restriction

      Hi, While testing in Zoho Inventory, I noticed that a sales order can be created with a quantity exceeding the available stock in the selected warehouse. In my case: Available stock: 5 units Ordered quantity: 6 units Despite this: I was able to convert
    • Deleting, Adding and Changing a Zoho Books Entry

      Zoho Books Community & Support, If a bulk upload of entries were added to an account, what is the process to: - Delete an entry - Change the amount of an entry - Is there a means to manually add an entry other than upload?
    • Zoho CRM - Feature Request - Analytics Components Group By Week Alternative Formats

      On the Zoho CRM Analytics Components, please consider adding an option to allow group by week format to be changed to other formats such as Week Commencing or Week Ending dates, rather than the current Week Number. This would provide improved usability
    • The Social Playbook March edition: Myth vs Facts

      We’ve all heard a lot of myths growing up. Some sound convincing, some feel believable, and over time they start to feel like facts. But the truth is, a myth is still a myth until it’s backed by real facts. Marketing is no different. Over time, many ideas
    • Updating Analytical Fields Data

      Dear Zoho team, I'm having an issue with the recently added fields in both Analytical Desk and Analytical. How can I generate the data in Analytical when new fields are added? https://analytics.zoho.com/workspace/2436819000000007005/edit/24368190000
    • Marketing Tip #26: Optimize product images for SEO

      Product images can do more than make your store look good. They can also help customers discover your products through search. Since search engines can’t "see" images, they rely on text signals to understand what an image is about. Two small actions make
    • What's New in Zoho Analytics - February 2026

      Hello Users! We're back with another round of updates for Zoho Analytics. This month's release focuses on giving you greater flexibility in how you visualize, manage, and act on your data - with new features like custom visualizations, remote MCP server,
    • Clone a Module??

      I am giong to repurpose the Vendors module but would like to have a separate but very similar module for another group of contacts called Buyers. I have already repurposed Contacts to Sellers. Is it possible to clone (make a duplicate) module of Vendors
    • [Webinar] Solving business challenges: Secure, real-time, and external collaboration

      Hi Zoho Writer users, We are excited to announce Zoho Writer's webinar for March 2026: Solving business challenges: Secure, real-time, and external collaboration. Zoho Writer supports real-time collaboration by allowing teams to work together in documents.
    • Realtime Translations of Video via OnAir

      It would be an amazing feature to have a drop down selector in the On Air video area for attendees to select a language to convert the original language to.
    • can change deal colors in bigin?

      can be super useful if we can change colors deals process any way to do it?
    • You have reached the maximum limit of bank accounts that can be connected to Zoho Books through token.

      I can no longer connect to my bank account to download transactions into Zoho Books. I egt the error message: "You have reached the maximum limit of bank accounts that can be connected to Zoho Books through token. To connect more accounts, write to us
    • Assign emails to lead

      I have some contacts who refers leads but there is no away to manually assign emails to lead.   
    • Print Sales Orders, Purchase Orders or Invoices from API

      Hello, Is it possible to use the print option that is available in Sales Orders Purchase Orders and Invoices with the API?. I don't see any information in the docs about this. Thanks
    • Push Forms to CRM

      Hello, I created a Form but forgot to integrate to CRM before many of the Forms were filled out. Is it possible to push those entries to CRM or should I just export a CSV then upload to CRM?
    • Layout Adjustment.

      Hello Latha, Hope you are doing well. I wanted to check with you about adjusting the layout columns in the Service Report from the backend, as currently there is no capability for us to customize the layout from our end. Below is the output that I am
    • Invoice emails repeatedly "Bounced back" from perfectly good email address of clients.

      Hi For a couple of months now I am getting tens of invoice email invoices "bounced back" from perfectly sound email addresses when they are sent via Zoho Books. (see attached or an example) (the common theme seems to be that the emails are going to either
    • Newby Questions - Vendors, Customers, and Income vs. Other Income Clarifications

      Q1. For Deposits, there does not seem to be an option for "Income". "Other Income" is an option however. What is the process to add the option to assign a deposit to type "Income"? Q2. In many cases Vendors and Customer are the same. Vendors may purchase
    • yodlee bank fees

      My bank feeds have been pretty much error-free until this recent Yodlee update.  I have configured it as per the information however nothing comes through. It says that bank feeds have been refreshed as of 30th June, 2022. It is the end of the financial
    • Create Item group from a composite Item

      I have applied my mind for hours but cannot figure this out. Can you have a composite item in an item group?. E.g. We bundle different color and size SKU's together as composite items. Also Using composite items as Bill of Materials. We want to create
    • Amazon.in FBA multiple warehouse integration with Zoho Inventory

      My organisation subscribed to Zoho One looking at the opportunity to integrate Amazon.in with Inventory. But during the configuration, we understood the integration has severe limitations when it involves multiple warehouses in the same Organisation.
    • Feature Request - Make Available "Alias Name" Field In Item List View

      Hi Zoho Inventory Team, I have noticed that the "Alias Name" field does not appear on the list of selectable columns in the Customise Columns feature in the Items module. This would be very useful to see for businesses who are using the Alias Name field
    • Feature Request - Option To Hide Default System Fields on Items

      Hi Zoho Inventory Team, As far as I know it is not possible to hid some of the defult system fields on Items, such as UPC, MPN, EAN, ISBN. A good use case is that in many cases ISBN is not relevant and it would be an improved user experience if we could
    • OpenAPI Specs are just plain wrong

      The provided yml files for generating the OpenAPI specs are absolutely riddled with errors and inconsistencies. From missing fields on the objects, to just incorrectly named resource objects. I'm having to go through and manually changing the spec to
    • Zoho Inventory - Composite Items - Assembly - Single Line Item Quantity of One

      Hi Zoho Inventory Team, Please consider relaxing the system rules which prevent an assembly items from consisting of a single line item and outputting a quantity of 1. A client I'm currently working with sells cosmetics and offers testers of their products
    • Categorize Items with Item Headers

      Hello customers, Did you ever want to classify items based on specific categories to help your customers understand your invoice better? With the new Item Header feature, you can easily categorize items in your invoices and estimates and give them a common title.  Item Headers are available in the Invoices, the Recurring Invoices and the Estimates module. It can be carried forward from estimates to invoices at the time of converting the estimates.  To add an item header: Go to the Estimates, Invoices
    • Zoho Creator Developer Console | Improved Distribution and Lifecycle Management for apps

      Hello everyone, We're excited to introduce new enhancements now in the Zoho Creator Developer Console. These updates strengthen private app distribution through licensing controls and extend environment support across all installed apps, helping teams
    • 554 5.1.1 – Mail sending blocked for the domain(s): [gmail.com]

      Here's your corrected text: Hello, I hope you are doing well. I was unable to send a message and received the following error: "554 5.1.1 – Mail sending blocked for the domain(s): [gmail.com]" I tried to send and deliver an email but got this error. I
    • Next Page