This workflow corresponds to n8n.io template #17721 — 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 →
{
"id": "zewdHLI58e4MieOE",
"meta": {
"templateCredsSetupCompleted": true
},
"name": "Automate RFP Answers with OpenAI Assistants, Google Docs, Gmail and Slack",
"tags": [],
"nodes": [
{
"id": "01c725a6-9dab-4f19-a2c0-146204e61031",
"name": "Get RFP Data",
"type": "n8n-nodes-base.extractFromFile",
"position": [
1936,
1440
],
"parameters": {
"options": {},
"operation": "pdf"
},
"typeVersion": 1
},
{
"id": "d2f7aa99-022a-4e2b-83bd-052bd6480be8",
"name": "Item List Output Parser",
"type": "@n8n/n8n-nodes-langchain.outputParserItemList",
"position": [
3072,
1568
],
"parameters": {
"options": {}
},
"typeVersion": 1
},
{
"id": "90f811aa-3cc9-4fd0-8b25-9d7197360f19",
"name": "For Each Question...",
"type": "n8n-nodes-base.splitInBatches",
"position": [
3456,
1408
],
"parameters": {
"options": {}
},
"typeVersion": 3
},
{
"id": "19f5ef2b-d668-4ad2-a968-38c767746157",
"name": "Set Variables",
"type": "n8n-nodes-base.set",
"position": [
2112,
1440
],
"parameters": {
"mode": "raw",
"options": {},
"jsonOutput": "={\n \"doc_title\": \"{{ $('Wait for Request').item.json.body.title }}\",\n \"doc_filename\": \"{{ $('Wait for Request').item.json.body.id }} | {{ $('Wait for Request').item.json.body.title }} | {{ $now.format('yyyyMMddhhmmss') }}| RFP Response\",\n \"reply_to\": \"{{ $('Wait for Request').item.json.body.reply_to }}\"\n}\n"
},
"typeVersion": 3.3
},
{
"id": "e385b913-6bc9-40ef-b222-20cbed4cbd84",
"name": "Create new RFP Response Document",
"type": "n8n-nodes-base.googleDocs",
"position": [
2320,
1440
],
"parameters": {
"title": "={{ $json.doc_filename }}",
"folderId": "=1y0I8MH32maIWCJh767mRE_NMHC6A3bUu"
},
"typeVersion": 2
},
{
"id": "b73d36f4-dd79-4c92-8e60-b62fcb4cc2b2",
"name": "OpenAI Chat Model",
"type": "@n8n/n8n-nodes-langchain.lmChatOpenAi",
"position": [
2896,
1568
],
"parameters": {
"options": {}
},
"typeVersion": 1
},
{
"id": "5e095a9e-a5af-44ae-a59a-e325a2ed5804",
"name": "Send Chat Notification",
"type": "n8n-nodes-base.slack",
"position": [
4736,
1408
],
"parameters": {
"text": "=RFP document \"{{ $('Set Variables').item.json.title }}\" completed!",
"select": "channel",
"channelId": {
"__rl": true,
"mode": "name",
"value": "RFP-channel"
},
"otherOptions": {}
},
"typeVersion": 2.1
},
{
"id": "ceb5e37d-1771-453f-b760-b8f5dcc4bce3",
"name": "Send Email Notification",
"type": "n8n-nodes-base.gmail",
"position": [
4544,
1408
],
"parameters": {
"sendTo": "={{ $('Set Variables').item.json.reply_to }}",
"message": "=Your RFP document \"{{ $('Set Variables').item.json.title }}\" is now complete!",
"options": {},
"subject": "=RFP Questionnaire \"{{ $('Set Variables').item.json.title }}\" Completed!",
"emailType": "text"
},
"typeVersion": 2.1
},
{
"id": "9269adf0-506d-448a-97b0-b067a3b19750",
"name": "Add Metadata to Response Doc",
"type": "n8n-nodes-base.googleDocs",
"position": [
2528,
1440
],
"parameters": {
"actionsUi": {
"actionFields": [
{
"text": "=Title: {{ $('Set Variables').item.json.doc_title }}\nDate generated: {{ $now.format(\"yyyy-MM-dd @ hh:mm\") }}\nRequested by: {{ $('Set Variables').item.json.reply_to }}\nExecution Id: http://localhost:5678/workflow/{{ $workflow.id }}/executions/{{ $execution.id }}\n\n---\n\n",
"action": "insert"
}
]
},
"operation": "update",
"documentURL": "={{ $json.id }}"
},
"typeVersion": 2
},
{
"id": "e9ff7b3d-2ad7-42e1-bc2b-b90dce8319ed",
"name": "Record Question & Answer in Response Doc",
"type": "n8n-nodes-base.googleDocs",
"position": [
4128,
1520
],
"parameters": {
"actionsUi": {
"actionFields": [
{
"text": "={{ $runIndex+1 }}. {{ $json.content }}\n{{ $json.output }}\n\n",
"action": "insert"
}
]
},
"operation": "update",
"documentURL": "={{ $('Create new RFP Response Document').item.json.id }}"
},
"typeVersion": 2
},
{
"id": "fc96dc9b-1ea3-485d-acb9-45d15b648148",
"name": "Answer Question with Context",
"type": "@n8n/n8n-nodes-langchain.openAi",
"position": [
3808,
1520
],
"parameters": {
"text": "={{ $json.response.text }}",
"prompt": "define",
"options": {},
"resource": "assistant",
"assistantId": {
"__rl": true,
"mode": "list",
"value": "asst_QBI5lLKOsjktr3DRB4MwrgZd",
"cachedResultName": "Nexus Digital Solutions Bot"
}
},
"typeVersion": 1.3
},
{
"id": "36644f17-d1dc-44e8-b298-d3b37d6580b6",
"name": "Wait for Request",
"type": "n8n-nodes-base.webhook",
"position": [
1744,
1440
],
"parameters": {
"path": "35e874df-2904-494e-a9f5-5a3f20f517f8",
"options": {},
"httpMethod": "POST"
},
"typeVersion": 2
},
{
"id": "4bad5af5-f52b-4e10-ba21-fa0b0474ecfb",
"name": "Extract Questions From RFP",
"type": "@n8n/n8n-nodes-langchain.chainLlm",
"position": [
2896,
1408
],
"parameters": {
"text": "=You have been given a RFP document as part of a tender process of a buyer. Please extract all questions intended for the supplier. You must ensure the questions extracted are exactly has they are written in the RFP document.\n\n<RFP>{{ $('Get RFP Data').item.json.text }}<RFP>",
"promptType": "define",
"hasOutputParser": true
},
"typeVersion": 1.4
},
{
"id": "b706f5ee-e845-4c7e-a647-5bb2b232106f",
"name": "Overview",
"type": "n8n-nodes-base.stickyNote",
"position": [
1104,
800
],
"parameters": {
"color": 7,
"width": 520,
"height": 1368,
"content": "## Automate RFP Answers with OpenAI Assistants, Google Docs, Gmail and Slack\n\nAutomatically turns an incoming RFP PDF into a complete response document. Every extracted question is answered by a trained OpenAI Assistant, recorded into a Google Doc, and the finished document is delivered by email and Slack.\n\n**Perfect for:** Sales engineers, bid managers, and proposal teams who respond to RFPs and RFIs on a recurring basis.\n\n---\n\n## How it works\n\n1. **Wait for Request**: Receives the RFP submission (PDF, title, and reply to address) via webhook.\n2. **Get RFP Data**: Extracts the raw text from the uploaded RFP PDF.\n3. **Set Variables**: Builds the document title, filename, and reply to address from the webhook payload.\n4. **Create new RFP Response Document**: Creates a new Google Doc in the target Drive folder to hold the response.\n5. **Add Metadata to Response Doc**: Inserts a header block with title, generation date, requester, and execution link.\n6. **Extract Questions From RFP**: Reads the full RFP text and pulls out every question addressed to the supplier, using the *OpenAI Chat Model* for reasoning and the *Item List Output Parser* to return a clean list.\n7. **For Each Question...**: Loops through the extracted questions one at a time.\n8. **Answer Question with Context**: Sends each question to a pretrained OpenAI Assistant (\"Nexus Digital Solutions Bot\") that answers using the company's own knowledge.\n9. **Record Question & Answer in Response Doc**: Appends the numbered question and answer into the Google Doc, then loops back for the next question.\n10. **Send Email Notification**: Once every question is answered, emails the requester that the response document is ready. *(runs on loop completion)*\n11. **Send Chat Notification**: Posts a matching completion message to the RFP Slack channel.\n\n---\n\n## Setup (~10 minutes)\n\n1. **Webhook**: Note the generated URL on the *Wait for Request* node and point your RFP intake form or system to it.\n2. **Google Docs**: Connect your account in *Create new RFP Response Document* and *Add Metadata to Response Doc*, and set the target folder ID.\n3. **OpenAI**: Add your API key in *OpenAI Chat Model*, and set your own Assistant ID in *Answer Question with Context*.\n4. **Gmail**: Connect your account in *Send Email Notification*.\n5. **Slack**: Connect your account and set the target channel in *Send Chat Notification*.\n> The OpenAI Assistant used in *Answer Question with Context* must already be trained on your company's RFP knowledge; this workflow does not build that Assistant for you."
},
"typeVersion": 1
},
{
"id": "efe41ae8-9fba-465f-8fe5-8a6184b28c28",
"name": "Section 1 - Intake & Document Setup",
"type": "n8n-nodes-base.stickyNote",
"position": [
1648,
1184
],
"parameters": {
"color": 5,
"width": 1073,
"height": 518,
"content": "## 1\ufe0f\u20e3 Intake & Document Setup\n\nThe **Wait for Request** webhook receives the incoming RFP along with its title and reply to address, and **Get RFP Data** pulls the raw text out of the attached PDF. **Set Variables** assembles the document title and filename, then **Create new RFP Response Document** and **Add Metadata to Response Doc** spin up a fresh Google Doc with a header block ready to receive answers."
},
"typeVersion": 1
},
{
"id": "189033d0-aa77-4f69-ac23-13ab9749f3ca",
"name": "Section 2 - Question Extraction",
"type": "n8n-nodes-base.stickyNote",
"position": [
2768,
1184
],
"parameters": {
"color": 3,
"width": 588,
"height": 584,
"content": "## 2\ufe0f\u20e3 Question Extraction\n\n**Extract Questions From RFP** reads the entire RFP text and identifies every question meant for the supplier, exactly as written. It relies on the **OpenAI Chat Model** for the reasoning and the **Item List Output Parser** to return the questions as a clean, structured list ready for looping."
},
"typeVersion": 1
},
{
"id": "c681b8a9-3d50-45d0-8e04-03c5e1a23dc6",
"name": "Section 3 - Answer Loop",
"type": "n8n-nodes-base.stickyNote",
"position": [
3408,
1184
],
"parameters": {
"color": 6,
"width": 968,
"height": 608,
"content": "## 3\ufe0f\u20e3 Answer Loop\n\n**For Each Question...** walks through the extracted list one item at a time. **Answer Question with Context** hands each question to a pretrained OpenAI Assistant that answers from the company's own knowledge, and **Record Question & Answer in Response Doc** writes the numbered question and answer straight into the Google Doc before the loop moves on."
},
"typeVersion": 1
},
{
"id": "a59c3630-36ba-4ef4-8587-c3f03d9106b2",
"name": "Section 4 - Completion & Notifications",
"type": "n8n-nodes-base.stickyNote",
"position": [
4416,
1232
],
"parameters": {
"color": 4,
"width": 592,
"height": 376,
"content": "## 4\ufe0f\u20e3 Completion & Notifications\n\nOnce the loop finishes, **Send Email Notification** emails the original requester that their RFP response is ready, and **Send Chat Notification** posts the same completion update to the team's RFP Slack channel."
},
"typeVersion": 1
}
],
"active": false,
"settings": {
"binaryMode": "separate",
"availableInMCP": false,
"executionOrder": "v1"
},
"versionId": "0580416c-49f3-4222-8a1b-2c2a7beb8d97",
"nodeGroups": [],
"connections": {
"Get RFP Data": {
"main": [
[
{
"node": "Set Variables",
"type": "main",
"index": 0
}
]
]
},
"Set Variables": {
"main": [
[
{
"node": "Create new RFP Response Document",
"type": "main",
"index": 0
}
]
]
},
"Wait for Request": {
"main": [
[
{
"node": "Get RFP Data",
"type": "main",
"index": 0
}
]
]
},
"OpenAI Chat Model": {
"ai_languageModel": [
[
{
"node": "Extract Questions From RFP",
"type": "ai_languageModel",
"index": 0
}
]
]
},
"For Each Question...": {
"main": [
[
{
"node": "Send Email Notification",
"type": "main",
"index": 0
}
],
[
{
"node": "Answer Question with Context",
"type": "main",
"index": 0
}
]
]
},
"Item List Output Parser": {
"ai_outputParser": [
[
{
"node": "Extract Questions From RFP",
"type": "ai_outputParser",
"index": 0
}
]
]
},
"Send Email Notification": {
"main": [
[
{
"node": "Send Chat Notification",
"type": "main",
"index": 0
}
]
]
},
"Extract Questions From RFP": {
"main": [
[
{
"node": "For Each Question...",
"type": "main",
"index": 0
}
]
]
},
"Add Metadata to Response Doc": {
"main": [
[
{
"node": "Extract Questions From RFP",
"type": "main",
"index": 0
}
]
]
},
"Answer Question with Context": {
"main": [
[
{
"node": "Record Question & Answer in Response Doc",
"type": "main",
"index": 0
}
]
]
},
"Create new RFP Response Document": {
"main": [
[
{
"node": "Add Metadata to Response Doc",
"type": "main",
"index": 0
}
]
]
},
"Record Question & Answer in Response Doc": {
"main": [
[
{
"node": "For Each Question...",
"type": "main",
"index": 0
}
]
]
}
}
}
For the full experience including quality scoring and batch install features for each workflow upgrade to Pro
About this workflow
This workflow accepts an RFP PDF via webhook, extracts supplier questions with OpenAI, answers each one using an OpenAI Assistant, writes the full Q&A into a Google Doc, and notifies the requester via Gmail and the team via Slack. Receives an HTTP POST webhook containing the RFP…
Source: https://n8n.io/workflows/17721/ — original creator credit. Request a take-down →
Related workflows
Workflows that share integrations, category, or trigger type with this one. All free to copy and import.
Automate Your Rfp Process With Openai Assistants. Uses extractFromFile, outputParserItemList, splitInBatches, stickyNote. Webhook trigger; 23 nodes.
This n8n workflow demonstrates how to automate oftern time-consuming form filling tasks in the early stages of the tendering process; the Request for Proposal document or "RFP".
This n8n workflow orchestrates a powerful suite of AI Agents and automations to manage and optimize various aspects of an e-commerce operation, particularly for platforms like Shopify. It leverages La
Main_Sourcing_Agent. Uses mySql, openAi, executeCommand, chainLlm. Webhook trigger; 70 nodes.
Main_Sourcing_Agent. Uses mySql, openAi, executeCommand, chainLlm. Webhook trigger; 70 nodes.