This workflow follows the HTTP Request → Postgres 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 →
{
"name": "job.2_email_classifier",
"nodes": [
{
"parameters": {
"operation": "executeQuery",
"query": "SELECT \n ecs.email_id,\n e.subject,\n e.body\nFROM\n email_classification_status ecs\nJOIN\n emails e ON ecs.email_id = e.email_id\nORDER BY\n ecs.email_id ASC \nLIMIT 10;",
"options": {}
},
"type": "n8n-nodes-base.postgres",
"typeVersion": 2.6,
"position": [
-880,
160
],
"id": "d5d38764-dd43-4337-a90e-efe4e1df96d8",
"name": "Execute EMAIL_RECEIVED Query",
"credentials": {
"postgres": {
"name": "<your credential>"
}
}
},
{
"parameters": {
"schema": {
"__rl": true,
"mode": "list",
"value": "public"
},
"table": {
"__rl": true,
"value": "events",
"mode": "list",
"cachedResultName": "events"
},
"columns": {
"mappingMode": "defineBelow",
"value": {
"event_type": "EMAIL_CLASSIFIED",
"payload": "={{{\nemail_id: $json.email_id,\ncategory: $json.category,\nconfidence: $json.confidence,\nrole_title: $json.role_title,\nrole_id:$json.external_ref_id,\nupcoming_date:$json.extracted_date,\ndate_context:$json.date_context,\nllm_company_guess:$json.company_name,\nsource : $json.source\n}\n}}",
"triggered_by": "system",
"application_id": "={{ null }}"
},
"matchingColumns": [],
"schema": [
{
"id": "event_id",
"displayName": "event_id",
"required": false,
"defaultMatch": false,
"display": true,
"type": "number",
"canBeUsedToMatch": true,
"removed": true
},
{
"id": "event_type",
"displayName": "event_type",
"required": true,
"defaultMatch": false,
"display": true,
"type": "string",
"canBeUsedToMatch": true
},
{
"id": "application_id",
"displayName": "application_id",
"required": false,
"defaultMatch": false,
"display": true,
"type": "number",
"canBeUsedToMatch": true
},
{
"id": "payload",
"displayName": "payload",
"required": false,
"defaultMatch": false,
"display": true,
"type": "object",
"canBeUsedToMatch": true
},
{
"id": "triggered_by",
"displayName": "triggered_by",
"required": true,
"defaultMatch": false,
"display": true,
"type": "string",
"canBeUsedToMatch": true
},
{
"id": "created_at",
"displayName": "created_at",
"required": false,
"defaultMatch": false,
"display": true,
"type": "dateTime",
"canBeUsedToMatch": true,
"removed": true
}
],
"attemptToConvertTypes": false,
"convertFieldsToString": false
},
"options": {}
},
"type": "n8n-nodes-base.postgres",
"typeVersion": 2.6,
"position": [
48,
-16
],
"id": "1ac9147c-bc77-4b19-9a88-566b5b1780a7",
"name": "Emit Classification Event",
"credentials": {
"postgres": {
"name": "<your credential>"
}
}
},
{
"parameters": {
"method": "POST",
"url": "http://classifier-api:8000/classify",
"sendBody": true,
"specifyBody": "json",
"jsonBody": "={{\n{\n \"email_id\": $json.email_id,\n \"subject\": $json.subject,\n \"body\": $json.body\n}\n}}",
"options": {}
},
"type": "n8n-nodes-base.httpRequest",
"typeVersion": 4.3,
"position": [
-656,
160
],
"id": "6e450449-d313-47c1-904d-f52f236aba5b",
"name": "HTTP Request"
},
{
"parameters": {
"jsCode": " return items.map(item => {\n // 'item.json' here will be the direct JSON response from your classifier-api\n const apiResponse = item.json;\n\n // Basic validation to ensure we got a valid response\n if (!apiResponse || apiResponse.email_id === undefined || apiResponse.category === undefined) {\n throw new Error(\"Invalid or incomplete response from Classifier API.\");\n }\n\n // Extract data directly from the API response\n const email_id = apiResponse.email_id;\n const category = apiResponse.category;\n const confidence = apiResponse.confidence;\n const extracted_data = apiResponse.extracted_data || {}; // Ensure it's an object even if null\n\n return {\n json: {\n email_id: email_id,\n category: category,\n confidence: confidence,\n // Extracted data fields are now nested under 'extracted_data'\n // We are flattening them here for easier access in subsequent nodes\n company_name: extracted_data.company_name || null,\n role_title: extracted_data.role_title || null,\n external_ref_id: extracted_data.external_ref_id || null,\n extracted_date: extracted_data.extracted_date || null,\n date_context: extracted_data.date_context || null,\n job_links: { \"links\": extracted_data.job_links || [] }\n }\n };\n });"
},
"type": "n8n-nodes-base.code",
"typeVersion": 2,
"position": [
-464,
160
],
"id": "34c488ae-1027-496c-841c-80d2ed197c5a",
"name": "Insert into links table"
},
{
"parameters": {
"conditions": {
"options": {
"caseSensitive": true,
"leftValue": "",
"typeValidation": "strict",
"version": 3
},
"conditions": [
{
"id": "fd432a46-d9a9-4c9b-b243-ecac61545097",
"leftValue": "={{ $json.category === 'OPPORTUNITY_SIGNAL' }}",
"rightValue": "",
"operator": {
"type": "boolean",
"operation": "false",
"singleValue": true
}
}
],
"combinator": "and"
},
"options": {}
},
"type": "n8n-nodes-base.if",
"typeVersion": 2.3,
"position": [
-272,
160
],
"id": "0c75c319-c61c-474b-a217-0cb85228530e",
"name": "If links or No links in body"
},
{
"parameters": {
"conditions": {
"options": {
"caseSensitive": true,
"leftValue": "",
"typeValidation": "strict",
"version": 3
},
"conditions": [
{
"id": "2120ff6d-b29a-4c48-8299-c01bd600274e",
"leftValue": "={{ $json.job_links.links.length > 0 }}",
"rightValue": "",
"operator": {
"type": "boolean",
"operation": "true",
"singleValue": true
}
}
],
"combinator": "and"
},
"options": {}
},
"type": "n8n-nodes-base.if",
"typeVersion": 2.3,
"position": [
16,
304
],
"id": "bf9e4a60-cb64-46dc-9a4c-94b23fad5f89",
"name": "if links or no links"
},
{
"parameters": {
"schema": {
"__rl": true,
"mode": "list",
"value": "public"
},
"table": {
"__rl": true,
"value": "manual_review_queue",
"mode": "list",
"cachedResultName": "manual_review_queue"
},
"columns": {
"mappingMode": "defineBelow",
"value": {
"email_id": "={{ $json.email_id }}",
"reason": "=No links found",
"status": "llm_revision"
},
"matchingColumns": [
"id"
],
"schema": [
{
"id": "id",
"displayName": "id",
"required": false,
"defaultMatch": true,
"display": true,
"type": "number",
"canBeUsedToMatch": true,
"removed": true
},
{
"id": "email_id",
"displayName": "email_id",
"required": true,
"defaultMatch": false,
"display": true,
"type": "number",
"canBeUsedToMatch": true
},
{
"id": "reason",
"displayName": "reason",
"required": false,
"defaultMatch": false,
"display": true,
"type": "string",
"canBeUsedToMatch": true
},
{
"id": "status",
"displayName": "status",
"required": false,
"defaultMatch": false,
"display": true,
"type": "string",
"canBeUsedToMatch": true
},
{
"id": "created_at",
"displayName": "created_at",
"required": false,
"defaultMatch": false,
"display": true,
"type": "dateTime",
"canBeUsedToMatch": true,
"removed": true
}
],
"attemptToConvertTypes": false,
"convertFieldsToString": false
},
"options": {}
},
"type": "n8n-nodes-base.postgres",
"typeVersion": 2.6,
"position": [
336,
464
],
"id": "541fb9d2-7a55-41b9-bccd-d5601edde766",
"name": "Insert to MQP table - no links",
"credentials": {
"postgres": {
"name": "<your credential>"
}
}
},
{
"parameters": {
"schema": {
"__rl": true,
"mode": "list",
"value": "public"
},
"table": {
"__rl": true,
"value": "opportunity_processing_queue",
"mode": "list",
"cachedResultName": "opportunity_processing_queue"
},
"columns": {
"mappingMode": "defineBelow",
"value": {
"email_id": "={{ $json.email_id }}",
"job_links": "={{ $json.job_links }}"
},
"matchingColumns": [
"id"
],
"schema": [
{
"id": "id",
"displayName": "id",
"required": false,
"defaultMatch": true,
"display": true,
"type": "number",
"canBeUsedToMatch": true,
"removed": true
},
{
"id": "email_id",
"displayName": "email_id",
"required": false,
"defaultMatch": false,
"display": true,
"type": "number",
"canBeUsedToMatch": true
},
{
"id": "job_links",
"displayName": "job_links",
"required": true,
"defaultMatch": false,
"display": true,
"type": "object",
"canBeUsedToMatch": true
},
{
"id": "status",
"displayName": "status",
"required": false,
"defaultMatch": false,
"display": true,
"type": "string",
"canBeUsedToMatch": true,
"removed": true
},
{
"id": "created_at",
"displayName": "created_at",
"required": false,
"defaultMatch": false,
"display": true,
"type": "dateTime",
"canBeUsedToMatch": true,
"removed": true
},
{
"id": "processed_at",
"displayName": "processed_at",
"required": false,
"defaultMatch": false,
"display": true,
"type": "dateTime",
"canBeUsedToMatch": true,
"removed": true
}
],
"attemptToConvertTypes": false,
"convertFieldsToString": false
},
"options": {}
},
"type": "n8n-nodes-base.postgres",
"typeVersion": 2.6,
"position": [
336,
208
],
"id": "9a257b2c-bae9-466f-a6fe-70117a536585",
"name": "Insert in OPQ table",
"credentials": {
"postgres": {
"name": "<your credential>"
}
}
},
{
"parameters": {
"operation": "executeQuery",
"query": "DELETE FROM email_classification_status \nWHERE email_id = {{ $json.payload.email_id }};",
"options": {}
},
"type": "n8n-nodes-base.postgres",
"typeVersion": 2.6,
"position": [
304,
-16
],
"id": "54b68303-196e-40ac-a848-3b587627380f",
"name": "DELETE from ECS table for others",
"credentials": {
"postgres": {
"name": "<your credential>"
}
}
},
{
"parameters": {
"operation": "executeQuery",
"query": "DELETE FROM email_classification_status \nWHERE email_id = {{ $json.email_id }};",
"options": {}
},
"type": "n8n-nodes-base.postgres",
"typeVersion": 2.6,
"position": [
608,
208
],
"id": "7328d220-72fb-4eda-bd5c-040cd075c6f0",
"name": "DELETE from ECS table for OPPO_SIGNAL",
"credentials": {
"postgres": {
"name": "<your credential>"
}
}
},
{
"parameters": {
"operation": "executeQuery",
"query": "DELETE FROM email_classification_status\nWHERE email_id = {{ $json.email_id }};",
"options": {}
},
"type": "n8n-nodes-base.postgres",
"typeVersion": 2.6,
"position": [
624,
464
],
"id": "7fdd956a-372e-49b6-9ee6-bc44e5776670",
"name": "Delete from ECS",
"credentials": {
"postgres": {
"name": "<your credential>"
}
}
},
{
"parameters": {
"fieldToSplitOut": "job_links.links",
"include": "selectedOtherFields",
"fieldsToInclude": "id, email_id",
"options": {
"destinationFieldName": "job_url"
}
},
"type": "n8n-nodes-base.splitOut",
"typeVersion": 1,
"position": [
1040,
208
],
"id": "400e1aa3-1ce8-4819-930a-f7ee0e210ae6",
"name": "Split Out For Links"
},
{
"parameters": {
"operation": "executeQuery",
"query": "SELECT id, email_id, job_links FROM opportunity_processing_queue WHERE\n status = 'pending' ORDER BY created_at ASC LIMIT 50;",
"options": {}
},
"type": "n8n-nodes-base.postgres",
"typeVersion": 2.6,
"position": [
832,
208
],
"id": "975851b4-6c7b-4739-aabe-d34f0064affa",
"name": "Fetch from OPQ",
"credentials": {
"postgres": {
"name": "<your credential>"
}
}
},
{
"parameters": {
"compare": "selectedFields",
"fieldsToCompare": "link_text",
"options": {
"removeOtherFields": true
}
},
"type": "n8n-nodes-base.removeDuplicates",
"typeVersion": 2,
"position": [
1664,
208
],
"id": "2b0c0762-f70e-45eb-9719-18047c71733d",
"name": "Remove Duplicates"
},
{
"parameters": {
"jsCode": " // Input: { id: 1, email_id: 22, job_url: \"linkA\" }\n const crypto = require('crypto');\n\n return items.map(item => {\n const jobUrl = item.json.job_url;\n const queueEntryId = item.json.id;\n const emailId = item.json.email_id;\n\n const md5Hash = crypto.createHash('md5').update(jobUrl).digest('hex');\n\n return {\n json: {\n queue_entry_id: queueEntryId,\n email_id: emailId,\n id: md5Hash,\n job_url: jobUrl,\n apply_url: jobUrl,\n source_type: 'email',\n source_id: emailId.toString(),\n discovered_at: new Date().toISOString(),\n }\n };\n });"
},
"type": "n8n-nodes-base.code",
"typeVersion": 2,
"position": [
1248,
208
],
"id": "2daceb7b-6655-49b1-b6de-b8a84dc278e7",
"name": "Normalize for opportunities"
},
{
"parameters": {
"schema": {
"__rl": true,
"mode": "list",
"value": "public"
},
"table": {
"__rl": true,
"value": "opportunities",
"mode": "list",
"cachedResultName": "opportunities"
},
"columns": {
"mappingMode": "defineBelow",
"value": {
"id": "={{ $json.id }}",
"job_url": "={{ $json.apply_url }}",
"apply_url": "={{ $json.apply_url }}",
"source_type": "={{ $json.source_type }}",
"source_id": "={{ $json.source_id }}",
"discovered_at": "={{ $json.discovered_at }}",
"link_text": "={{ $json.queue_entry_id }}"
},
"matchingColumns": [
"id"
],
"schema": [
{
"id": "id",
"displayName": "id",
"required": true,
"defaultMatch": true,
"display": true,
"type": "string",
"canBeUsedToMatch": true,
"removed": false
},
{
"id": "job_url",
"displayName": "job_url",
"required": true,
"defaultMatch": false,
"display": true,
"type": "string",
"canBeUsedToMatch": true
},
{
"id": "apply_url",
"displayName": "apply_url",
"required": true,
"defaultMatch": false,
"display": true,
"type": "string",
"canBeUsedToMatch": true
},
{
"id": "link_text",
"displayName": "link_text",
"required": false,
"defaultMatch": false,
"display": true,
"type": "string",
"canBeUsedToMatch": true,
"removed": false
},
{
"id": "score",
"displayName": "score",
"required": false,
"defaultMatch": false,
"display": true,
"type": "number",
"canBeUsedToMatch": true,
"removed": true
},
{
"id": "reasons",
"displayName": "reasons",
"required": false,
"defaultMatch": false,
"display": true,
"type": "object",
"canBeUsedToMatch": true,
"removed": true
},
{
"id": "discovered_at",
"displayName": "discovered_at",
"required": false,
"defaultMatch": false,
"display": true,
"type": "dateTime",
"canBeUsedToMatch": true
},
{
"id": "source_type",
"displayName": "source_type",
"required": false,
"defaultMatch": false,
"display": true,
"type": "string",
"canBeUsedToMatch": true
},
{
"id": "source_id",
"displayName": "source_id",
"required": false,
"defaultMatch": false,
"display": true,
"type": "string",
"canBeUsedToMatch": true
},
{
"id": "metadata",
"displayName": "metadata",
"required": false,
"defaultMatch": false,
"display": true,
"type": "string",
"canBeUsedToMatch": true,
"removed": true
}
],
"attemptToConvertTypes": false,
"convertFieldsToString": false
},
"options": {
"skipOnConflict": true
}
},
"type": "n8n-nodes-base.postgres",
"typeVersion": 2.6,
"position": [
1456,
208
],
"id": "4a3d06d7-72b5-41c9-832b-6ed8e2ac93ad",
"name": "insert opportunities",
"credentials": {
"postgres": {
"name": "<your credential>"
}
}
},
{
"parameters": {
"operation": "executeQuery",
"query": "DELETE FROM opportunity_processing_queue\nWHERE id = {{ $json.link_text }};",
"options": {}
},
"type": "n8n-nodes-base.postgres",
"typeVersion": 2.6,
"position": [
1872,
208
],
"id": "4be5dc0d-ec17-44c2-b392-c89e545b6237",
"name": "Delete from OPQ table",
"credentials": {
"postgres": {
"name": "<your credential>"
}
}
},
{
"parameters": {
"path": "21681f63-9a20-492f-bde9-3a6cde82585a",
"options": {}
},
"type": "n8n-nodes-base.webhook",
"typeVersion": 2.1,
"position": [
-1088,
160
],
"id": "2ba0e258-83a1-4e86-8048-370b8cc86955",
"name": "Trigger from wf1"
}
],
"connections": {
"Execute EMAIL_RECEIVED Query": {
"main": [
[
{
"node": "HTTP Request",
"type": "main",
"index": 0
}
]
]
},
"Emit Classification Event": {
"main": [
[
{
"node": "DELETE from ECS table for others",
"type": "main",
"index": 0
}
]
]
},
"HTTP Request": {
"main": [
[
{
"node": "Insert into links table",
"type": "main",
"index": 0
}
]
]
},
"Insert into links table": {
"main": [
[
{
"node": "If links or No links in body",
"type": "main",
"index": 0
}
]
]
},
"If links or No links in body": {
"main": [
[
{
"node": "Emit Classification Event",
"type": "main",
"index": 0
}
],
[
{
"node": "if links or no links",
"type": "main",
"index": 0
}
]
]
},
"if links or no links": {
"main": [
[
{
"node": "Insert in OPQ table",
"type": "main",
"index": 0
}
],
[
{
"node": "Insert to MQP table - no links",
"type": "main",
"index": 0
}
]
]
},
"Insert in OPQ table": {
"main": [
[
{
"node": "DELETE from ECS table for OPPO_SIGNAL",
"type": "main",
"index": 0
}
]
]
},
"Insert to MQP table - no links": {
"main": [
[
{
"node": "Delete from ECS",
"type": "main",
"index": 0
}
]
]
},
"DELETE from ECS table for others": {
"main": [
[]
]
},
"Split Out For Links": {
"main": [
[
{
"node": "Normalize for opportunities",
"type": "main",
"index": 0
}
]
]
},
"Fetch from OPQ": {
"main": [
[
{
"node": "Split Out For Links",
"type": "main",
"index": 0
}
]
]
},
"Remove Duplicates": {
"main": [
[
{
"node": "Delete from OPQ table",
"type": "main",
"index": 0
}
]
]
},
"Normalize for opportunities": {
"main": [
[
{
"node": "insert opportunities",
"type": "main",
"index": 0
}
]
]
},
"insert opportunities": {
"main": [
[
{
"node": "Remove Duplicates",
"type": "main",
"index": 0
}
]
]
},
"DELETE from ECS table for OPPO_SIGNAL": {
"main": [
[
{
"node": "Fetch from OPQ",
"type": "main",
"index": 0
}
]
]
},
"Trigger from wf1": {
"main": [
[
{
"node": "Execute EMAIL_RECEIVED Query",
"type": "main",
"index": 0
}
]
]
}
},
"active": false,
"settings": {
"executionOrder": "v1",
"availableInMCP": false
},
"versionId": "4e2435f8-c842-44aa-be74-5550e69e3180",
"meta": {
"templateCredsSetupCompleted": true
},
"id": "xLjJbuDddO3Bcq4p",
"tags": []
}
Credentials you'll need
Each integration node will prompt for credentials when you import. We strip credential IDs before publishing — you'll add your own.
postgres
For the full experience including quality scoring and batch install features for each workflow upgrade to Pro
About this workflow
job.2_email_classifier. Uses postgres, httpRequest. Webhook trigger; 18 nodes.
Source: https://github.com/daemon-Ad/Job-Aggregation-and-Email-Intelligence-System/blob/main/workflows/job.2_email_classifier.json — 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.
CMM. Uses httpRequest, postgres, redis. Webhook trigger; 90 nodes.
Scraping. Uses httpRequest, postgres, @apify/n8n-nodes-apify, respondToWebhook. Webhook trigger; 61 nodes.
Workflow B — AI Listing Engine. Uses httpRequest, postgres, errorTrigger. Webhook trigger; 47 nodes.
LogSentinel Workflow. Uses postgres, emailSend, httpRequest. Webhook trigger; 44 nodes.
Post-Prayer. Uses postgres, httpRequest. Webhook trigger; 44 nodes.