AutomationFlowsAI & RAG › Draft Google Review Reply Emails with Gmail, Openai, and Google Sheets

Draft Google Review Reply Emails with Gmail, Openai, and Google Sheets

By43 Sunsets @the43sunsets on n8n.io

This workflow monitors Gmail for Google Business Profile “new review” alert emails, uses OpenAI to extract the rating and review text and draft a policy-safe reply, then emails the draft to you and logs the review and reply draft to Google Sheets. Triggers when a new Google…

Event trigger★★★★☆ complexityAI-powered14 nodesGmail TriggerGoogle SheetsChain LlmOpenAI ChatOutput Parser StructuredGmail
AI & RAG Trigger: Event Nodes: 14 Complexity: ★★★★☆ AI nodes: yes Added:

This workflow corresponds to n8n.io template #16889 — we link there as the canonical source.

This workflow follows the Chainllm → Gmail recipe pattern — see all workflows that pair these two integrations.

The workflow JSON

Copy or download the full n8n JSON below. Paste it into a new n8n workflow, add your credentials, activate. Full import guide →

Download .json
{
  "name": "Draft AI replies to Google reviews with Gmail, OpenAI and Google Sheets",
  "nodes": [
    {
      "id": "f1a0s001-0000-4000-8000-000000000001",
      "name": "Sticky Note \u2014 read me first",
      "type": "n8n-nodes-base.stickyNote",
      "position": [
        -800,
        -40
      ],
      "parameters": {
        "width": 700,
        "height": 760,
        "content": "## Draft AI replies to Google reviews \u2014 you stay in control\n\n### How it works\nGoogle emails you every time your business gets a new review. This workflow watches your Gmail for those alerts, has AI write a reply draft that follows Google's reply-moderation rules (specific, no links, no promo language), then emails the draft to you. You read it, tweak it if you like, and paste it on your Google reviews page. **Nothing is ever posted automatically** \u2014 the draft lands in your inbox, and a ledger row lands in Google Sheets so you always know what was handled.\n\n### Setup\n1. Connect **Gmail** and **Google Sheets** (both work with n8n's one-click Google sign-in).\n2. Add your **OpenAI API key** to the model node.\n3. Create a Google Sheet with headers: `processed_at, gmail_message_id, rating, reviewer, review_excerpt, reply_draft, status` and select it in both Sheets nodes.\n4. Fill in the **\u2699\ufe0f Your settings** node: business name, your email, tone, contact channel.\n5. Activate. Send yourself a test by re-forwarding an old review alert.\n\n### Customization tips\nAdjust tone and sign-off in \u2699\ufe0f Your settings. Swap OpenAI for Gemini or Claude by replacing the model node."
      },
      "typeVersion": 1
    },
    {
      "id": "f1a0s002-0000-4000-8000-000000000002",
      "name": "Sticky Note \u2014 section 1",
      "type": "n8n-nodes-base.stickyNote",
      "position": [
        -60,
        -40
      ],
      "parameters": {
        "color": 7,
        "width": 1000,
        "height": 760,
        "content": "## 1. Catch the alert\nGmail trigger fires on Google's \"new review\" notification emails. The Sheets lookup + IF guard make re-runs safe: a review that is already in the ledger is never processed twice (no duplicate drafts in your inbox)."
      },
      "typeVersion": 1
    },
    {
      "id": "f1a0s003-0000-4000-8000-000000000003",
      "name": "Sticky Note \u2014 section 2",
      "type": "n8n-nodes-base.stickyNote",
      "position": [
        980,
        -40
      ],
      "parameters": {
        "color": 7,
        "width": 480,
        "height": 760,
        "content": "## 2. Think\nOne AI call extracts the rating, reviewer name and review text from the alert email, then drafts a reply that follows Google's moderation rules: references a concrete detail, no links, no promotions, apologetic-but-not-liable for 1\u20132\u2605. Uses your business name, tone and contact channel from \u2699\ufe0f Your settings."
      },
      "typeVersion": 1
    },
    {
      "id": "f1a0s004-0000-4000-8000-000000000004",
      "name": "Sticky Note \u2014 section 3",
      "type": "n8n-nodes-base.stickyNote",
      "position": [
        1500,
        -40
      ],
      "parameters": {
        "color": 7,
        "width": 480,
        "height": 760,
        "content": "## 3. Deliver + log\nThe draft is emailed to you with a one-click link to your Google reviews page, and the ledger row is appended to Google Sheets \u2014 so you can see every review, every draft, and what you did with it."
      },
      "typeVersion": 1
    },
    {
      "id": "f1a00001-0000-4000-8000-00000000000a",
      "name": "Watch Gmail for new review alerts",
      "type": "n8n-nodes-base.gmailTrigger",
      "position": [
        0,
        320
      ],
      "parameters": {
        "simple": false,
        "filters": {
          "q": "from:user@example.com subject:(review)"
        },
        "options": {}
      },
      "typeVersion": 1.2
    },
    {
      "id": "f1a00002-0000-4000-8000-00000000000b",
      "name": "\u2699\ufe0f Your settings",
      "type": "n8n-nodes-base.set",
      "position": [
        200,
        320
      ],
      "parameters": {
        "options": {},
        "assignments": {
          "assignments": [
            {
              "id": "a1",
              "name": "businessName",
              "type": "string",
              "value": "YOUR BUSINESS NAME"
            },
            {
              "id": "a2",
              "name": "ownerEmail",
              "type": "string",
              "value": "you@example.com"
            },
            {
              "id": "a3",
              "name": "brandTone",
              "type": "string",
              "value": "warm, professional, first-person plural (\"we\")"
            },
            {
              "id": "a4",
              "name": "contactChannel",
              "type": "string",
              "value": "call us at (555) 000-0000 or email hello@example.com"
            },
            {
              "id": "a5",
              "name": "signOff",
              "type": "string",
              "value": "\u2014 The YOUR BUSINESS NAME team"
            },
            {
              "id": "a6",
              "name": "replyPageUrl",
              "type": "string",
              "value": "https://business.google.com/reviews"
            }
          ]
        }
      },
      "typeVersion": 3.4
    },
    {
      "id": "f1a00003-0000-4000-8000-00000000000c",
      "name": "Check the ledger (already handled?)",
      "type": "n8n-nodes-base.googleSheets",
      "position": [
        400,
        320
      ],
      "parameters": {
        "options": {},
        "filtersUI": {
          "values": [
            {
              "lookupValue": "={{ $('Watch Gmail for new review alerts').item.json.id }}",
              "lookupColumn": "gmail_message_id"
            }
          ]
        },
        "operation": "lookup",
        "sheetName": {
          "__rl": true,
          "mode": "list",
          "value": ""
        },
        "documentId": {
          "__rl": true,
          "mode": "list",
          "value": ""
        }
      },
      "typeVersion": 4.5,
      "alwaysOutputData": true
    },
    {
      "id": "f1a00004-0000-4000-8000-00000000000d",
      "name": "Only continue if it is new",
      "type": "n8n-nodes-base.if",
      "position": [
        600,
        320
      ],
      "parameters": {
        "options": {},
        "conditions": {
          "options": {
            "leftValue": "",
            "caseSensitive": true,
            "typeValidation": "loose"
          },
          "combinator": "and",
          "conditions": [
            {
              "id": "c1",
              "operator": {
                "type": "string",
                "operation": "empty",
                "singleValue": true
              },
              "leftValue": "={{ $json.gmail_message_id || '' }}",
              "rightValue": ""
            }
          ]
        }
      },
      "typeVersion": 2.2
    },
    {
      "id": "f1a00005-0000-4000-8000-00000000000e",
      "name": "Already handled \u2014 stop",
      "type": "n8n-nodes-base.noOp",
      "position": [
        800,
        500
      ],
      "parameters": {},
      "typeVersion": 1
    },
    {
      "id": "f1a00006-0000-4000-8000-00000000000f",
      "name": "Draft the reply (AI)",
      "type": "@n8n/n8n-nodes-langchain.chainLlm",
      "maxTries": 3,
      "position": [
        1100,
        304
      ],
      "parameters": {
        "text": "=You are drafting a public reply to a Google review on behalf of {{ $('\u2699\ufe0f Your settings').item.json.businessName }}.\n\nBelow is the full text of a Google Business Profile \"new review\" notification email. First extract: the star rating (1-5), the reviewer's first name, and the review text. Then write reply_draft following ALL rules.\n\nRules for the reply:\n- Tone: {{ $('\u2699\ufe0f Your settings').item.json.brandTone }}. Maximum 110 words.\n- Address the reviewer by first name only (privacy: never use a full name).\n- Reference one concrete detail from their review. Never write a reply that could fit any review \u2014 generic AI boilerplate gets rejected by Google's reply moderation.\n- Never include: links, promotions, discounts, upsells, keyword stuffing, or requests to change the rating (these also get rejected).\n- 4-5 stars: thank them warmly and specifically.\n- 3 stars: thank them, acknowledge the specific gap they mention, state one concrete improvement.\n- 1-2 stars: apologize sincerely without admitting legal fault, address their specific issue, invite them to continue the conversation offline: {{ $('\u2699\ufe0f Your settings').item.json.contactChannel }}.\n- End with: {{ $('\u2699\ufe0f Your settings').item.json.signOff }}\n\nNOTIFICATION EMAIL:\n{{ $('Watch Gmail for new review alerts').item.json.text || $('Watch Gmail for new review alerts').item.json.snippet }}",
        "promptType": "define",
        "hasOutputParser": true
      },
      "retryOnFail": true,
      "typeVersion": 1.5,
      "waitBetweenTries": 5000
    },
    {
      "id": "f1a00007-0000-4000-8000-000000000010",
      "name": "OpenAI model (bring your own key)",
      "type": "@n8n/n8n-nodes-langchain.lmChatOpenAi",
      "position": [
        1080,
        560
      ],
      "parameters": {
        "model": {
          "__rl": true,
          "mode": "list",
          "value": "gpt-4o-mini"
        },
        "options": {
          "temperature": 0.4
        }
      },
      "typeVersion": 1.2
    },
    {
      "id": "f1a00008-0000-4000-8000-000000000011",
      "name": "Force clean JSON output",
      "type": "@n8n/n8n-nodes-langchain.outputParserStructured",
      "position": [
        1280,
        560
      ],
      "parameters": {
        "schemaType": "manual",
        "inputSchema": "{\n  \"type\": \"object\",\n  \"properties\": {\n    \"rating\": { \"type\": \"number\", \"description\": \"Star rating 1-5\" },\n    \"reviewer_first_name\": { \"type\": \"string\" },\n    \"review_excerpt\": { \"type\": \"string\", \"description\": \"The review text, max 200 chars\" },\n    \"reply_draft\": { \"type\": \"string\" }\n  },\n  \"required\": [\"rating\", \"reviewer_first_name\", \"review_excerpt\", \"reply_draft\"]\n}"
      },
      "typeVersion": 1.2
    },
    {
      "id": "f1a00009-0000-4000-8000-000000000012",
      "name": "Email the draft to the owner",
      "type": "n8n-nodes-base.gmail",
      "maxTries": 3,
      "position": [
        1560,
        304
      ],
      "parameters": {
        "sendTo": "={{ $('\u2699\ufe0f Your settings').item.json.ownerEmail }}",
        "message": "=<div style=\"font-family:Arial,sans-serif;max-width:560px\">\n<p><b>{{ $json.output.reviewer_first_name }}</b> left a <b>{{ $json.output.rating }}\u2605</b> review:</p>\n<blockquote style=\"border-left:3px solid #f5a24b;margin:0;padding:8px 14px;color:#555\">{{ $json.output.review_excerpt }}</blockquote>\n<p><b>Suggested reply</b> (copy, tweak if you like, then paste it on Google):</p>\n<div style=\"background:#f7f3ec;border-radius:8px;padding:14px 16px;white-space:pre-wrap\">{{ $json.output.reply_draft }}</div>\n<p style=\"margin-top:18px\"><a href=\"{{ $('\u2699\ufe0f Your settings').item.json.replyPageUrl }}\" style=\"background:#1a73e8;color:#fff;padding:10px 18px;border-radius:6px;text-decoration:none\">Open my Google reviews page \u2192</a></p>\n<p style=\"color:#888;font-size:12px\">Drafted automatically by your n8n workflow. Nothing is ever posted without you.</p>\n</div>",
        "options": {},
        "subject": "=\u270d\ufe0f Reply draft: {{ $json.output.rating }}\u2605 review from {{ $json.output.reviewer_first_name }} \u2014 {{ $('\u2699\ufe0f Your settings').item.json.businessName }}"
      },
      "retryOnFail": true,
      "typeVersion": 2.1,
      "waitBetweenTries": 5000
    },
    {
      "id": "f1a00010-0000-4000-8000-000000000013",
      "name": "Log to the reply ledger",
      "type": "n8n-nodes-base.googleSheets",
      "maxTries": 3,
      "position": [
        1760,
        304
      ],
      "parameters": {
        "columns": {
          "value": {
            "rating": "={{ $('Draft the reply (AI)').item.json.output.rating }}",
            "status": "draft-sent-to-owner",
            "reviewer": "={{ $('Draft the reply (AI)').item.json.output.reviewer_first_name }}",
            "reply_draft": "={{ $('Draft the reply (AI)').item.json.output.reply_draft }}",
            "processed_at": "={{ $now.toISO() }}",
            "review_excerpt": "={{ $('Draft the reply (AI)').item.json.output.review_excerpt }}",
            "gmail_message_id": "={{ $('Watch Gmail for new review alerts').item.json.id }}"
          },
          "mappingMode": "defineBelow"
        },
        "options": {},
        "operation": "append",
        "sheetName": {
          "__rl": true,
          "mode": "list",
          "value": ""
        },
        "documentId": {
          "__rl": true,
          "mode": "list",
          "value": ""
        }
      },
      "retryOnFail": true,
      "typeVersion": 4.5,
      "waitBetweenTries": 5000
    }
  ],
  "settings": {
    "executionOrder": "v1"
  },
  "connections": {
    "Draft the reply (AI)": {
      "main": [
        [
          {
            "node": "Email the draft to the owner",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "\u2699\ufe0f Your settings": {
      "main": [
        [
          {
            "node": "Check the ledger (already handled?)",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Force clean JSON output": {
      "ai_outputParser": [
        [
          {
            "node": "Draft the reply (AI)",
            "type": "ai_outputParser",
            "index": 0
          }
        ]
      ]
    },
    "Only continue if it is new": {
      "main": [
        [
          {
            "node": "Draft the reply (AI)",
            "type": "main",
            "index": 0
          }
        ],
        [
          {
            "node": "Already handled \u2014 stop",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Email the draft to the owner": {
      "main": [
        [
          {
            "node": "Log to the reply ledger",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "OpenAI model (bring your own key)": {
      "ai_languageModel": [
        [
          {
            "node": "Draft the reply (AI)",
            "type": "ai_languageModel",
            "index": 0
          }
        ]
      ]
    },
    "Watch Gmail for new review alerts": {
      "main": [
        [
          {
            "node": "\u2699\ufe0f Your settings",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Check the ledger (already handled?)": {
      "main": [
        [
          {
            "node": "Only continue if it is new",
            "type": "main",
            "index": 0
          }
        ]
      ]
    }
  }
}
Pro

For the full experience including quality scoring and batch install features for each workflow upgrade to Pro

About this workflow

This workflow monitors Gmail for Google Business Profile “new review” alert emails, uses OpenAI to extract the rating and review text and draft a policy-safe reply, then emails the draft to you and logs the review and reply draft to Google Sheets. Triggers when a new Google…

Source: https://n8n.io/workflows/16889/ — original creator credit. Request a take-down →

More AI & RAG workflows → · Browse all categories →

Related workflows

Workflows that share integrations, category, or trigger type with this one. All free to copy and import.

AI & RAG

This workflow logs Gmail receipt attachments to Google Sheets by extracting structured fields with OpenAI (including category selection from your list), prevents duplicates by checking the ledger, and

Gmail Trigger, Google Sheets, OpenAI +4
AI & RAG

The workflow runs every hour with a randomized delay of 5–20 minutes to help distribute load. It records the exact date and time a lead is emailed so you can track outreach. Follow-ups are automatical

Google Sheets, Agent, OpenAI Chat +5
AI & RAG

This workflow is perfect for graphic designers, creative agencies, marketing teams, or freelancers who regularly use AI-generated images in their projects. It's specifically beneficial for teams that

Google Sheets, Google Drive, HTTP Request +5
AI & RAG

This workflow automates the full lifecycle of a vehicle insurance claim — from an incoming Gmail email to a signed, watermarked PDF decision letter delivered back to the claimant.

Gmail Trigger, N8N Nodes Pdf Api Hub, Google Sheets +4
AI & RAG

n8n Graphic Design Team. Uses googleSheets, googleDrive, httpRequest, outputParserStructured. Event-driven trigger; 37 nodes.

Google Sheets, Google Drive, HTTP Request +5