This workflow corresponds to n8n.io template #17049 — we link there as the canonical source.
This workflow follows the Gmail Trigger → HTTP Request 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": "f2ca7596-6958-40f8-a9e3-32fcb7ba052f",
"meta": {
"templateCredsSetupCompleted": false
},
"name": "Create data deletion requests from Gmail to Jira and BigQuery",
"tags": [
{
"name": "creator-template"
},
{
"name": "privacy"
},
{
"name": "jira"
},
{
"name": "bigquery"
}
],
"nodes": [
{
"id": "d23297d2-43e5-44b4-a9c8-0b140343a448",
"name": "Overview - template description",
"type": "n8n-nodes-base.stickyNote",
"position": [
-560,
-980
],
"parameters": {
"color": 4,
"width": 3620,
"height": 560,
"content": "## Create data deletion requests from Gmail to Jira and BigQuery\n\nUse this workflow to turn incoming privacy deletion requests into tracked Jira work, a limited BigQuery audit row, and internal Slack notifications.\n\n## Review before publishing\n\nThis workflow has been manually laid out so sticky note text stays visible and nodes do not cover instructions. Keep the notes in place when customizing the workflow.\n\n## Requirements\n\nConnect Gmail, Jira, BigQuery, and Slack credentials. Do not paste API keys, tokens, real customer emails, private URLs, or production IDs directly into nodes.\n\n## How to set up\n\n1. Update `Set workflow variables`.\n2. Replace placeholder URLs and IDs with your own values.\n3. Test with the manual trigger before activating the Gmail trigger.\n4. Review all sensitive requests before sending customer-facing replies."
},
"typeVersion": 1
},
{
"id": "68a19c3d-bbec-4f11-a811-9e95d4e218fb",
"name": "Step 1 - Capture privacy requests",
"type": "n8n-nodes-base.stickyNote",
"position": [
-560,
-340
],
"parameters": {
"color": 5,
"width": 700,
"height": 560,
"content": "## Step 1: Capture privacy requests\n\nUse the Gmail trigger in production.\n\nUse the manual trigger to test the workflow with sample data before activating it."
},
"typeVersion": 1
},
{
"id": "8a0128a5-625c-4843-8f5f-192ad8367fbb",
"name": "Step 2 - Configure variables",
"type": "n8n-nodes-base.stickyNote",
"position": [
200,
-340
],
"parameters": {
"color": 6,
"width": 520,
"height": 560,
"content": "## Step 2: Configure variables\n\nUpdate this node first.\n\nKeep project keys, dataset names, channels, and SLA settings in one place."
},
"typeVersion": 1
},
{
"id": "b074773c-f4fe-4566-a406-193373f9f1e2",
"name": "Step 3 - Normalize and classify",
"type": "n8n-nodes-base.stickyNote",
"position": [
780,
-340
],
"parameters": {
"color": 5,
"width": 700,
"height": 620,
"content": "## Step 3: Normalize and classify\n\nClean the email body, detect the request type, and calculate the SLA due date.\n\nUnclear requests are sent to manual review."
},
"typeVersion": 1
},
{
"id": "fa8736f1-2bac-401d-9e71-1d753f69055d",
"name": "Step 4 - Create task and audit trail",
"type": "n8n-nodes-base.stickyNote",
"position": [
1540,
-340
],
"parameters": {
"color": 5,
"width": 760,
"height": 760,
"content": "## Step 4: Create task and audit trail\n\nClear deletion requests create a Jira task and a limited BigQuery audit record.\n\nManual review requests follow the lower branch."
},
"typeVersion": 1
},
{
"id": "1c34139d-f0e4-4b57-bba6-d6e6bc116318",
"name": "Step 5 - Notify and confirm",
"type": "n8n-nodes-base.stickyNote",
"position": [
2360,
-340
],
"parameters": {
"color": 5,
"width": 700,
"height": 620,
"content": "## Step 5: Notify and confirm\n\nNotify the privacy team in Slack.\n\nCreate a Gmail draft for customer confirmation so a person can review it before sending."
},
"typeVersion": 1
},
{
"id": "cf358d15-2d8c-4566-befe-c2a8757b1415",
"name": "Security warning",
"type": "n8n-nodes-base.stickyNote",
"position": [
1540,
480
],
"parameters": {
"color": 3,
"width": 1520,
"height": 300,
"content": "## Security warning\n\nDo not store full personal data in the audit table unless your privacy policy allows it.\n\nUse n8n credentials for authentication. Never paste API keys, OAuth tokens, customer emails, private URLs, Slack channel IDs, or production IDs directly into this template."
},
"typeVersion": 1
},
{
"id": "e0b2b73d-96a2-4e80-961c-87c00bea74d5",
"name": "Manual test trigger",
"type": "n8n-nodes-base.manualTrigger",
"position": [
-400,
-40
],
"parameters": {},
"typeVersion": 1
},
{
"id": "f9ecb406-fd69-48ba-82b8-5d5e624d4434",
"name": "Watch privacy request inbox",
"type": "n8n-nodes-base.gmailTrigger",
"position": [
-400,
120
],
"parameters": {
"simple": false,
"filters": {
"q": "(delete my data OR erase my data OR data deletion OR privacy request OR remove my account)"
},
"options": {},
"pollTimes": {
"item": [
{
"mode": "everyMinute"
}
]
}
},
"typeVersion": 1.2
},
{
"id": "edd48537-39a1-4df5-aa73-639b6c9665c9",
"name": "Set workflow variables",
"type": "n8n-nodes-base.set",
"position": [
340,
40
],
"parameters": {
"options": {},
"assignments": {
"assignments": [
{
"id": "d07fa77f-86a1-4830-87f2-9f3271f73a1b",
"name": "jira_base_url",
"type": "string",
"value": "https://your-domain.atlassian.net"
},
{
"id": "70b51d75-ce39-43fe-9fdd-2a374c9cee80",
"name": "jira_project_key",
"type": "string",
"value": "PRIV"
},
{
"id": "44e828b7-dfc0-4edf-bbe0-24a9c0cd1f3e",
"name": "jira_issue_type",
"type": "string",
"value": "Task"
},
{
"id": "fc3b4d32-4267-45ec-9d94-bf2224b2a5d8",
"name": "privacy_sla_days",
"type": "number",
"value": "30"
},
{
"id": "02c4eef7-909d-416d-a1d1-679b5ad79421",
"name": "bigquery_project_id",
"type": "string",
"value": "your-gcp-project-id"
},
{
"id": "63378a0b-601f-428b-a40f-e021961d9d22",
"name": "bigquery_dataset",
"type": "string",
"value": "privacy_ops"
},
{
"id": "1dd1a282-0f92-4945-a094-ffc7c9c3b848",
"name": "bigquery_table",
"type": "string",
"value": "data_requests"
},
{
"id": "c332016c-1c92-4949-8ae5-a2286c4f04b3",
"name": "slack_channel_id",
"type": "string",
"value": "C0123456789"
},
{
"id": "1e6bc19a-b15f-473d-aba9-2674ec48a605",
"name": "manual_review_label",
"type": "string",
"value": "Needs privacy review"
},
{
"id": "5413766d-1bdb-42c7-a640-a272b1b632c7",
"name": "confirmation_email_enabled",
"type": "boolean",
"value": "true"
},
{
"id": "a8b35d64-7fb9-4138-bcac-1526ab98db01",
"name": "minimum_confidence",
"type": "number",
"value": "0.75"
}
]
},
"includeOtherFields": true
},
"typeVersion": 3.4
},
{
"id": "9334768d-5cfd-4651-985c-d8817e5c2992",
"name": "Normalize and classify privacy request",
"type": "n8n-nodes-base.code",
"position": [
900,
20
],
"parameters": {
"jsCode": "const item = $input.first().json;\nconst cfg = {\n jira_base_url: item.jira_base_url,\n jira_project_key: item.jira_project_key,\n jira_issue_type: item.jira_issue_type,\n privacy_sla_days: Number(item.privacy_sla_days || 30),\n bigquery_project_id: item.bigquery_project_id,\n bigquery_dataset: item.bigquery_dataset,\n bigquery_table: item.bigquery_table,\n slack_channel_id: item.slack_channel_id,\n manual_review_label: item.manual_review_label,\n confirmation_email_enabled: item.confirmation_email_enabled === true || item.confirmation_email_enabled === 'true',\n minimum_confidence: Number(item.minimum_confidence || 0.75),\n};\n\nconst source = item.payload || item.message || item;\nconst rawSubject = source.subject || item.subject || 'Please delete my account';\nconst rawFrom = source.from || source.sender || item.from || 'user@example.com';\nconst rawText = source.textPlain || source.text || source.body || item.text || 'Hello, please delete my personal data from your systems.';\nconst cleanText = String(rawText)\n .replace(/\\r/g, '\\n')\n .replace(/\\n{3,}/g, '\\n\\n')\n .replace(/--\\s*[\\s\\S]*$/m, '')\n .trim();\n\nconst lower = `${rawSubject} ${cleanText}`.toLowerCase();\nconst patterns = [\n { type: 'deletion', keywords: ['delete my data', 'erase my data', 'remove my account', 'right to erasure', 'data deletion'] },\n { type: 'access', keywords: ['copy of my data', 'access my data', 'data access request', 'dsar'] },\n { type: 'correction', keywords: ['correct my data', 'update my data', 'rectify'] },\n];\n\nlet requestType = 'unclear';\nlet hits = 0;\nfor (const p of patterns) {\n const score = p.keywords.filter(k => lower.includes(k)).length;\n if (score > hits) {\n hits = score;\n requestType = p.type;\n }\n}\n\nconst confidence = hits === 0 ? 0.35 : Math.min(0.95, 0.55 + hits * 0.2);\nconst receivedAt = new Date();\nconst dueDate = new Date(receivedAt.getTime() + cfg.privacy_sla_days * 24 * 60 * 60 * 1000);\n\nreturn [{\n json: {\n config: cfg,\n requesterEmail: String(rawFrom).match(/[A-Z0-9._%+-]+@[A-Z0-9.-]+\\.[A-Z]{2,}/i)?.[0] || rawFrom,\n subject: rawSubject,\n sanitizedPreview: cleanText.slice(0, 500),\n requestType,\n confidence,\n routeToPrivacyTask: confidence >= cfg.minimum_confidence && requestType !== 'unclear',\n receivedAt: receivedAt.toISOString(),\n dueDate: dueDate.toISOString().slice(0, 10),\n sourceMessageId: source.id || item.id || 'manual-test-message',\n }\n}];"
},
"typeVersion": 2
},
{
"id": "b47ffe68-7300-422f-846f-ab3c7d948816",
"name": "Check if request is clear enough",
"type": "n8n-nodes-base.if",
"position": [
1160,
180
],
"parameters": {
"options": {},
"conditions": {
"options": {
"version": 3,
"leftValue": "",
"caseSensitive": true,
"typeValidation": "loose"
},
"combinator": "and",
"conditions": [
{
"id": "80d9fab2-16f2-4a0c-a5bf-8cb1b31ee037",
"operator": {
"type": "boolean",
"operation": "true",
"singleValue": true
},
"leftValue": "={{ $json.routeToPrivacyTask }}",
"rightValue": ""
}
]
},
"looseTypeValidation": true
},
"typeVersion": 2.3
},
{
"id": "0ff4f1b8-7842-4655-a448-e9c798bee1cb",
"name": "Create Jira privacy task",
"type": "n8n-nodes-base.httpRequest",
"position": [
1660,
20
],
"parameters": {
"url": "={{ $json.config.jira_base_url + \"/rest/api/3/issue\" }}",
"method": "POST",
"options": {},
"jsonBody": "={{\n{\n \"fields\": {\n \"project\": { \"key\": $json.config.jira_project_key },\n \"summary\": \"[\" + $json.requestType + \"] Privacy request from \" + $json.requesterEmail,\n \"description\": {\n \"type\": \"doc\",\n \"version\": 1,\n \"content\": [\n {\n \"type\": \"paragraph\",\n \"content\": [\n {\n \"type\": \"text\",\n \"text\": \"Requester: \" + $json.requesterEmail + \"\\nRequest type: \" + $json.requestType + \"\\nDue date: \" + $json.dueDate + \"\\nSource message: \" + $json.sourceMessageId + \"\\n\\nPreview:\\n\" + $json.sanitizedPreview\n }\n ]\n }\n ]\n },\n \"issuetype\": { \"name\": $json.config.jira_issue_type },\n \"labels\": [\"privacy-request\", $json.requestType]\n }\n}\n}}",
"sendBody": true,
"contentType": "json",
"specifyBody": "json"
},
"notesInFlow": false,
"typeVersion": 4.2
},
{
"id": "30faebc3-9331-4d42-8b7f-750b34008bea",
"name": "Insert audit row in BigQuery",
"type": "n8n-nodes-base.httpRequest",
"position": [
1920,
20
],
"parameters": {
"url": "={{ \"https://bigquery.googleapis.com/bigquery/v2/projects/\" + $json.config.bigquery_project_id + \"/datasets/\" + $json.config.bigquery_dataset + \"/tables/\" + $json.config.bigquery_table + \"/insertAll\" }}",
"method": "POST",
"options": {},
"jsonBody": "={{\n{\n \"rows\": [\n {\n \"insertId\": $json.sourceMessageId + \"-\" + $json.receivedAt,\n \"json\": {\n \"requester_domain\": $json.requesterEmail.split(\"@\")[1] || \"unknown\",\n \"request_type\": $json.requestType,\n \"confidence\": $json.confidence,\n \"received_at\": $json.receivedAt,\n \"due_date\": $json.dueDate,\n \"jira_created\": true\n }\n }\n ]\n}\n}}",
"sendBody": true,
"contentType": "json",
"specifyBody": "json"
},
"notesInFlow": false,
"typeVersion": 4.2
},
{
"id": "3e73a6e1-e5a7-4b25-87c0-394da566054a",
"name": "Send Slack privacy alert",
"type": "n8n-nodes-base.httpRequest",
"position": [
2460,
40
],
"parameters": {
"url": "https://slack.com/api/chat.postMessage",
"method": "POST",
"options": {},
"jsonBody": "={{\n{\n \"channel\": $json.config.slack_channel_id,\n \"text\": \"New privacy request routed to Jira\",\n \"blocks\": [\n { \"type\": \"section\", \"text\": { \"type\": \"mrkdwn\", \"text\": \"*New privacy request*\\nType: \" + $json.requestType + \"\\nRequester: \" + $json.requesterEmail + \"\\nDue: \" + $json.dueDate } }\n ]\n}\n}}",
"sendBody": true,
"contentType": "json",
"specifyBody": "json"
},
"notesInFlow": false,
"typeVersion": 4.2
},
{
"id": "86c7ab2f-99fd-4ab0-8623-172a155b8fab",
"name": "Create Gmail confirmation draft",
"type": "n8n-nodes-base.httpRequest",
"position": [
2720,
40
],
"parameters": {
"url": "https://gmail.googleapis.com/gmail/v1/users/me/drafts",
"method": "POST",
"options": {},
"jsonBody": "={{\n{\n \"message\": {\n \"raw\": \"Replace this with a base64url encoded MIME message in your final setup. Keep this node as a draft step for human review.\"\n }\n}\n}}",
"sendBody": true,
"contentType": "json",
"specifyBody": "json"
},
"notesInFlow": false,
"typeVersion": 4.2
},
{
"id": "cb1d02eb-c052-4bee-8524-966e565a64de",
"name": "Create manual review Jira task",
"type": "n8n-nodes-base.httpRequest",
"position": [
1660,
260
],
"parameters": {
"url": "={{ $json.config.jira_base_url + \"/rest/api/3/issue\" }}",
"method": "POST",
"options": {},
"jsonBody": "={{\n{\n \"fields\": {\n \"project\": { \"key\": $json.config.jira_project_key },\n \"summary\": \"[Review] Possible privacy request from \" + $json.requesterEmail,\n \"description\": {\n \"type\": \"doc\",\n \"version\": 1,\n \"content\": [\n {\n \"type\": \"paragraph\",\n \"content\": [\n { \"type\": \"text\", \"text\": \"This request was not classified with enough confidence. Review before taking action.\\n\\nSubject: \" + $json.subject + \"\\nPreview: \" + $json.sanitizedPreview }\n ]\n }\n ]\n },\n \"issuetype\": { \"name\": $json.config.jira_issue_type },\n \"labels\": [\"privacy-review\"]\n }\n}\n}}",
"sendBody": true,
"contentType": "json",
"specifyBody": "json"
},
"notesInFlow": false,
"typeVersion": 4.2
},
{
"id": "a59cd1eb-d88e-41d8-a5f1-1ba034048e88",
"name": "Send Slack manual review alert",
"type": "n8n-nodes-base.httpRequest",
"position": [
1920,
260
],
"parameters": {
"url": "https://slack.com/api/chat.postMessage",
"method": "POST",
"options": {},
"jsonBody": "={{\n{\n \"channel\": $json.config.slack_channel_id,\n \"text\": \"Possible privacy request needs manual review: \" + $json.subject\n}\n}}",
"sendBody": true,
"contentType": "json",
"specifyBody": "json"
},
"notesInFlow": false,
"typeVersion": 4.2
}
],
"active": false,
"settings": {
"timezone": "America/Sao_Paulo",
"executionOrder": "v1",
"saveDataErrorExecution": "all",
"saveDataSuccessExecution": "none"
},
"versionId": "9578baf0-aef3-4fde-b9c8-1aa69d9cfd76",
"connections": {
"Manual test trigger": {
"main": [
[
{
"node": "Set workflow variables",
"type": "main",
"index": 0
}
]
]
},
"Set workflow variables": {
"main": [
[
{
"node": "Normalize and classify privacy request",
"type": "main",
"index": 0
}
]
]
},
"Create Jira privacy task": {
"main": [
[
{
"node": "Insert audit row in BigQuery",
"type": "main",
"index": 0
}
]
]
},
"Send Slack privacy alert": {
"main": [
[
{
"node": "Create Gmail confirmation draft",
"type": "main",
"index": 0
}
]
]
},
"Watch privacy request inbox": {
"main": [
[
{
"node": "Set workflow variables",
"type": "main",
"index": 0
}
]
]
},
"Insert audit row in BigQuery": {
"main": [
[
{
"node": "Send Slack privacy alert",
"type": "main",
"index": 0
}
]
]
},
"Create manual review Jira task": {
"main": [
[
{
"node": "Send Slack manual review alert",
"type": "main",
"index": 0
}
]
]
},
"Check if request is clear enough": {
"main": [
[
{
"node": "Create Jira privacy task",
"type": "main",
"index": 0
}
],
[
{
"node": "Create manual review Jira task",
"type": "main",
"index": 0
}
]
]
},
"Normalize and classify privacy request": {
"main": [
[
{
"node": "Check if request is clear enough",
"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 monitors a Gmail inbox for potential privacy/data deletion requests, classifies each email, creates the appropriate Jira issue, logs a minimal audit record to BigQuery, and alerts the team in Slack, with an optional Gmail confirmation draft for human review.…
Source: https://n8n.io/workflows/17049/ — 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.
This template is built to be customized for your specific needs. This template has the core logic and n8n node specific references sorted to work with dynamic file names throughout the workflow. Store
How it works
📘 Description
Email → AI triage → CRM pipeline (template). Uses gmailTrigger, httpRequest, googleSheets, gmail. Event-driven trigger; 17 nodes.
This n8n workflow is designed for IT security professionals, email administrators, and organizations that want to automatically scan URLs received in emails for potential security threats. It provides