AutomationFlowsEmail & Gmail › Gmail to Slack: Ai-scored Upwork Job Alerts with Openrouter

Gmail to Slack: Ai-scored Upwork Job Alerts with Openrouter

ByJames Francis @paperjam on n8n.io

This workflow contains community nodes that are only compatible with the self-hosted version of n8n.

Event trigger★★★★☆ complexityAI-powered14 nodesOpenRouter ChatGmailGmail TriggerSlackInformation Extractor
Email & Gmail Trigger: Event Nodes: 14 Complexity: ★★★★☆ AI nodes: yes Added:

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

This workflow follows the Gmail → Gmail Trigger 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
{
  "meta": {
    "templateCredsSetupCompleted": true
  },
  "nodes": [
    {
      "id": "0dc258f0-4d50-4bbf-9063-b252f597c245",
      "name": "Convert To Markdown",
      "type": "n8n-nodes-base.markdown",
      "position": [
        440,
        -20
      ],
      "parameters": {
        "html": "={{ $('Get Filtered Messages').item.json.textAsHtml }}",
        "options": {},
        "destinationKey": "markdown"
      },
      "typeVersion": 1
    },
    {
      "id": "fced2dd2-720f-4534-a459-94f6cd13314b",
      "name": "OpenRouter Chat Model",
      "type": "@n8n/n8n-nodes-langchain.lmChatOpenRouter",
      "position": [
        748,
        200
      ],
      "parameters": {
        "options": {}
      },
      "credentials": {
        "openRouterApi": {
          "name": "<your credential>"
        }
      },
      "typeVersion": 1
    },
    {
      "id": "4b04a2bf-29a6-42f6-8e72-c264f092780e",
      "name": "Mark as Read",
      "type": "n8n-nodes-base.gmail",
      "position": [
        220,
        -20
      ],
      "parameters": {
        "messageId": "={{ $json.id }}",
        "operation": "markAsRead"
      },
      "credentials": {
        "gmailOAuth2": {
          "name": "<your credential>"
        }
      },
      "typeVersion": 2.1
    },
    {
      "id": "5c208e16-c987-4bf0-b3f6-27d560b3ce5e",
      "name": "Get Filtered Messages",
      "type": "n8n-nodes-base.gmailTrigger",
      "position": [
        0,
        -20
      ],
      "parameters": {
        "simple": false,
        "filters": {
          "q": "from:(user@example.com) subject:(New job:)"
        },
        "options": {},
        "pollTimes": {
          "item": [
            {
              "mode": "everyX",
              "unit": "minutes",
              "value": 10
            }
          ]
        }
      },
      "credentials": {
        "gmailOAuth2": {
          "name": "<your credential>"
        }
      },
      "typeVersion": 1.2
    },
    {
      "id": "6674d03e-91ca-4c6b-8091-b956920e7d9a",
      "name": "Send Slack Alert",
      "type": "n8n-nodes-base.slack",
      "position": [
        1860,
        -20
      ],
      "parameters": {
        "text": "=\ud83d\udea8 *New Upwork Job Opportunity!*\n----\n\n*{{ $json.job.jobName.toUpperCase() }}*\n_{{ $json.job.descriptionSnippet }}..._\n\n\ud83d\uddfa\ufe0f {{ $json.job.country }}\n{{ $json.output.paymentVerified ? \"\u2705 Payment verified\" : \"\u274c Payment not verified\"  }}\n\ud83d\udd67 {{ $json.job.jobType }} | {{ $json.job.price }}\n\ud83c\udff7\ufe0f {{ $json.job.tags.map(tag => `\\`${tag}\\``).join(', ') }}\n\u2b50 {{ $json.job.clientRating }}\n\ud83d\udcb0 {{ $json.job.amountSpent }}\n\ud83c\udfc6 {{ $json.job.experienceLevel }}\n\ud83d\udcc6 Posted {{ $json.job.postedAt }}\n\n----\n*AI EVALUATION*\nScore: *{{ $json.evaluation.score }}*\n_{{ $json.evaluation.reasoning }}_\n---\n\n_View this job:_ {{ $json.job.jobDetailUrl }}\n\n",
        "select": "channel",
        "channelId": {
          "__rl": true,
          "mode": "list",
          "value": "C090EHUFGEN",
          "cachedResultName": "testing"
        },
        "otherOptions": {
          "includeLinkToWorkflow": false
        }
      },
      "credentials": {
        "slackApi": {
          "name": "<your credential>"
        }
      },
      "typeVersion": 2.3
    },
    {
      "id": "0b9a8a79-3639-4a83-ac4d-9bbd22adef5e",
      "name": "OpenRouter Chat Model1",
      "type": "@n8n/n8n-nodes-langchain.lmChatOpenRouter",
      "position": [
        1124,
        200
      ],
      "parameters": {
        "options": {}
      },
      "credentials": {
        "openRouterApi": {
          "name": "<your credential>"
        }
      },
      "typeVersion": 1
    },
    {
      "id": "e282e1a2-70c7-40ca-a394-33e33976f855",
      "name": "Edit Fields",
      "type": "n8n-nodes-base.set",
      "position": [
        1440,
        -20
      ],
      "parameters": {
        "options": {},
        "assignments": {
          "assignments": [
            {
              "id": "43e777e8-2442-4cc9-8b58-65f1e8f591e5",
              "name": "evaluation",
              "type": "object",
              "value": "={{ $json.output }}"
            },
            {
              "id": "a2c26763-047f-4360-984a-272b88fe3bcc",
              "name": "job",
              "type": "object",
              "value": "={{ $('Job Data Extractor').item.json.output }}"
            }
          ]
        }
      },
      "typeVersion": 3.4
    },
    {
      "id": "37767da3-90bc-42c5-8fe4-a8d45be89cf3",
      "name": "Sticky Note",
      "type": "n8n-nodes-base.stickyNote",
      "position": [
        -60,
        -240
      ],
      "parameters": {
        "color": 7,
        "width": 660,
        "height": 460,
        "content": "## Fetch and format emails\n\nHere we use a Gmail search query to find all Upwork job alerts, and format the message body for LLM analysis. An Upwork Freelancer Plus subscription is required in order to receive job alerts.\n\nIMPORTANT: We're polling Gmail for new messages every 10 minutes. This will use a workflow execution each time. You may want to adjust this frequency based on the amount of workflow executions you want to use."
      },
      "typeVersion": 1
    },
    {
      "id": "96107c5a-8311-4836-a51e-09ce43994892",
      "name": "Sticky Note1",
      "type": "n8n-nodes-base.stickyNote",
      "position": [
        640,
        -240
      ],
      "parameters": {
        "color": 7,
        "width": 320,
        "height": 460,
        "content": "## Extract data from job\n\nPull out job information like country, price, etc."
      },
      "typeVersion": 1
    },
    {
      "id": "a8e422da-0984-4090-abde-eb2344dc2b28",
      "name": "Sticky Note2",
      "type": "n8n-nodes-base.stickyNote",
      "position": [
        1000,
        -240
      ],
      "parameters": {
        "color": 7,
        "width": 340,
        "height": 460,
        "content": "## Score the skillset match\n\nREQUIRED: Replace the placeholder text in the prompt between the <my_profile> tags with your own freelancer profile. Be as detailed as possible to achieve the best results."
      },
      "typeVersion": 1
    },
    {
      "id": "51b4e572-fe95-41ca-8ef1-e6638d6cbe8c",
      "name": "Filter By Score",
      "type": "n8n-nodes-base.filter",
      "position": [
        1640,
        -20
      ],
      "parameters": {
        "options": {},
        "conditions": {
          "options": {
            "version": 2,
            "leftValue": "",
            "caseSensitive": true,
            "typeValidation": "strict"
          },
          "combinator": "and",
          "conditions": [
            {
              "id": "ab20e70f-c9e3-4873-ab6a-e975dffefa35",
              "operator": {
                "type": "number",
                "operation": "gte"
              },
              "leftValue": "={{ $json.evaluation.score }}",
              "rightValue": 7
            }
          ]
        }
      },
      "typeVersion": 2.2
    },
    {
      "id": "bf621b43-05bd-47c2-bd29-4484400dff62",
      "name": "Opportunity Scorer",
      "type": "@n8n/n8n-nodes-langchain.informationExtractor",
      "position": [
        1040,
        -20
      ],
      "parameters": {
        "text": "=**Situation**\nYou are an expert job matching analyst specializing in freelance opportunities. You'll evaluate the compatibility between my professional profile (skills, experience, and preferences) and Upwork job listings to determine how well we match.\n\n**Task**\nAnalyze the provided Upwork job details against my skills and preferences, then generate a comprehensive match score on a scale of 1-10, where 10 indicates an exceptional match and 1 indicates a poor fit.\n\n**Objective**\nHelp me identify the most suitable job opportunities that align with my capabilities and preferences, saving me time by focusing only on highly compatible positions.\n\n**Knowledge**\n- The job information includes: job name, job type (hourly/fixed), price range, description snippet, country, payment verification status, client rating, amount spent, relevant tags, posting date, and required experience level\n- The description snippet provides limited information about the job requirements\n- Primary matching factors: job name, description snippet, and tags\n- Secondary matching factors: experience level, job type, and payment amount\n- My skills and preferences will be provided in my request\n\nWhen analyzing the match:\n1. Evaluate technical skill alignment based on job name, description snippet, and tags first and foremost\n2. Consider experience level requirements\n3. Factor in my stated job type preferences (hourly vs. fixed), if provided\n4. Account for payment range alignment with my expectations, if provided\n5. Assess if the job description suggests requirements outside my capabilities\n6. Consider any specific preferences I've mentioned (location, industry, etc.)\n\nYou must provide a nuanced, honest assessment of the match quality rather than inflating scores. For each match score, provide brief but specific reasoning explaining why the score was assigned, highlighting both strengths and potential misalignments.\n\n<my_profile>\nREPLACE THIS WITH YOUR PROFILE. BELOW IS AN EXAMPLE PROFILE.\nI\u2019m a seasoned web designer with over 8 years of experience crafting modern, user-friendly websites for startups, agencies, and global brands. My work spans across responsive design, UI/UX optimization, and full website redesigns that prioritize both aesthetic appeal and functional performance. I\u2019m highly proficient with tools like Figma, Adobe XD, Webflow, WordPress, and Shopify, and I frequently collaborate with developers to ensure seamless handoff using platforms like Zeplin or Storybook. Whether you\u2019re looking to improve conversions, refresh your brand\u2019s digital presence, or build something entirely new, I bring a strong design eye, clear communication, and a results-driven approach to every project.\n\nI have a slight preference for hourly projects with a rate about $30/hour. \n</my_profile>\n\n<job>\n{{ JSON.stringify($json.output, null, 2) }}\n</job>",
        "options": {},
        "schemaType": "manual",
        "inputSchema": "{\n\t\"type\": \"object\",\n    \"additionalProperties\": false,\n    \"required\": [\n      \"score\",\n      \"reasoning\"\n    ],\n\t\"properties\": {\n        \"score\": {\n          \"type\": \"integer\",\n          \"minimum\": 1,\n          \"maximum\": 10\n        },\n        \"reasoning\": {\n          \"type\": \"string\"\n        }\n\t}\n}"
      },
      "typeVersion": 1.2
    },
    {
      "id": "f768b4e4-3eba-41b1-a6aa-c34c14dead7c",
      "name": "Sticky Note3",
      "type": "n8n-nodes-base.stickyNote",
      "position": [
        1380,
        -240
      ],
      "parameters": {
        "color": 7,
        "width": 620,
        "height": 460,
        "content": "## Send filtered notifications to Slack\n\nHere we only send notifications for jobs that have a match score of 7 or greater, but you can filter the notifications however you'd like. Be sure to select a channel from your workspace in the Slack node."
      },
      "typeVersion": 1
    },
    {
      "id": "ffbe5e44-4e6d-4b88-92cd-042a47fdc77c",
      "name": "Job Data Extractor",
      "type": "@n8n/n8n-nodes-langchain.informationExtractor",
      "position": [
        660,
        -20
      ],
      "parameters": {
        "text": "=Below is a job alert email received from Upwork. Please extract the requested information in valid JSON format.\n\nSubject: {{ $('Get Filtered Messages').item.json.subject }}\nBody: {{ $json.markdown }}",
        "options": {},
        "schemaType": "manual",
        "inputSchema": "{\n\t\"type\": \"object\",\n    \"additionalProperties\": false,\n    \"required\": [\n      \"jobName\",\n      \"jobType\", \n      \"jobDetailUrl\", \n      \"price\", \n      \"descriptionSnippet\", \n      \"country\", \n      \"paymentVerified\",\n      \"clientRating\",\n      \"amountSpent\",\n      \"tags\",\n      \"postedAt\",\n      \"experienceLevel\"\n    ],\n\t\"properties\": {\n        \"jobName\": {\n          \"type\": \"string\"\n        },\n\t\t\"jobType\": {\n\t\t\t\"enum\": [\"Hourly\", \"Fixed\"]\n\t\t},\n        \"price\": {\n          \"type\": \"string\"\n        },\n        \"jobDetailUrl\": {\n          \"type\": \"string\"\n        },\n        \"descriptionSnippet\": {\n          \"type\": \"string\",\n          \"description\": \"The description of the job before the 'more' link\"\n        },\n      \"country\": {\n        \"type\": \"string\"\n      },\n      \"paymentVerified\": {\n        \"type\": \"boolean\"\n      },\n      \"clientRating\": {\n        \"type\": \"number\"\n      },\n      \"amountSpent\": {\n        \"type\": \"string\"\n      },\n      \"tags\": {\n        \"type\": \"array\",\n        \"description\": \"List of categories with a link typically found below the country. Just include the tag name, not the url.\",\n        \"items\": {\n          \"type\": \"string\"\n        }\n      },\n      \"postedAt\": {\n        \"type\": \"string\"\n      },\n      \"experienceLevel\": {\n        \"enum\": [\"Entry\", \"Intermediate\", \"Expert\"]\n      }\n\t}\n}"
      },
      "typeVersion": 1.2
    }
  ],
  "connections": {
    "Edit Fields": {
      "main": [
        [
          {
            "node": "Filter By Score",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Mark as Read": {
      "main": [
        [
          {
            "node": "Convert To Markdown",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Filter By Score": {
      "main": [
        [
          {
            "node": "Send Slack Alert",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Job Data Extractor": {
      "main": [
        [
          {
            "node": "Opportunity Scorer",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Opportunity Scorer": {
      "main": [
        [
          {
            "node": "Edit Fields",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Convert To Markdown": {
      "main": [
        [
          {
            "node": "Job Data Extractor",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Get Filtered Messages": {
      "main": [
        [
          {
            "node": "Mark as Read",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "OpenRouter Chat Model": {
      "ai_languageModel": [
        [
          {
            "node": "Job Data Extractor",
            "type": "ai_languageModel",
            "index": 0
          }
        ]
      ]
    },
    "OpenRouter Chat Model1": {
      "ai_languageModel": [
        [
          {
            "node": "Opportunity Scorer",
            "type": "ai_languageModel",
            "index": 0
          }
        ]
      ]
    }
  }
}

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.

Pro

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

About this workflow

This workflow contains community nodes that are only compatible with the self-hosted version of n8n.

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

More Email & Gmail workflows → · Browse all categories →

Related workflows

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

Email & Gmail

This workflow is for contractors, freelancers, local service businesses, and small teams that receive leads and customer requests through Gmail but do not have a dedicated sales or admin team.

Redis Trigger, Postgres, HTTP Request +5
Email & Gmail

This n8n template uses AI to automatically respond to your Gmail inbox by drafting response for your approval via email.

Gmail Trigger, Gmail, OpenAI Chat +1
Email & Gmail

NTF 03: Email Triage Agent. Uses gmailTrigger, lmChatAnthropic, chainLlm, gmail. Event-driven trigger; 9 nodes.

Gmail Trigger, Anthropic Chat, Chain Llm +2
Email & Gmail

Professionals and individuals who receive high volumes of emails, those who want to automatically organize their Gmail inbox using AI classification.

OpenRouter Chat, Chain Llm, Gmail Trigger +1
Email & Gmail

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

Gmail, Slack, Gmail Trigger +3