AutomationFlowsEmail & Gmail › Automated Construction Project Alerts with Email Notifications and Data Apis

Automated Construction Project Alerts with Email Notifications and Data Apis

ByOneclick AI Squad @oneclick-ai on n8n.io

This n8n workflow monitors and alerts you about new construction projects in specified areas, helping you track competing builders and identify business opportunities. The system automatically searches multiple data sources and sends detailed email reports with upcoming…

Cron / scheduled trigger★★★★☆ complexity13 nodesEmail Read ImapHTTP RequestEmail Send
Email & Gmail Trigger: Cron / scheduled Nodes: 13 Complexity: ★★★★☆ Added:

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

This workflow follows the Emailreadimap → Emailsend 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
{
  "id": "tAZrn9nO8QUWfGQx",
  "meta": {
    "templateCredsSetupCompleted": true
  },
  "name": "Real-Time Competitive Construction Monitoring",
  "tags": [],
  "nodes": [
    {
      "id": "878dbf6e-dc80-457d-b212-03e98c69042f",
      "name": "Schedule Trigger",
      "type": "n8n-nodes-base.scheduleTrigger",
      "position": [
        0,
        0
      ],
      "parameters": {
        "rule": {
          "interval": [
            {}
          ]
        }
      },
      "typeVersion": 1.1
    },
    {
      "id": "bba4ec2c-854e-4c51-ba14-f19ab0af919c",
      "name": "Email Trigger",
      "type": "n8n-nodes-base.emailReadImap",
      "position": [
        0,
        180
      ],
      "parameters": {
        "options": {}
      },
      "credentials": {
        "imap": {
          "name": "<your credential>"
        }
      },
      "typeVersion": 2
    },
    {
      "id": "46fdbb5a-478a-488d-ba1f-c752f1d708b9",
      "name": "Check Email Subject",
      "type": "n8n-nodes-base.if",
      "position": [
        220,
        180
      ],
      "parameters": {
        "options": {},
        "conditions": {
          "options": {
            "version": 1,
            "leftValue": "",
            "caseSensitive": true,
            "typeValidation": "strict"
          },
          "combinator": "and",
          "conditions": [
            {
              "id": "condition1",
              "operator": {
                "type": "string",
                "operation": "contains"
              },
              "leftValue": "={{ $json.subject }}",
              "rightValue": "Construction Alert Request"
            }
          ]
        }
      },
      "typeVersion": 2
    },
    {
      "id": "af98d975-c83d-4cf6-b060-a33f8c5d3211",
      "name": "Extract Location Info",
      "type": "n8n-nodes-base.code",
      "position": [
        440,
        80
      ],
      "parameters": {
        "jsCode": "// Extract area/location from email body\nconst emailBody = $input.first().json.text || $input.first().json.html;\nconst lines = emailBody.split('\\n');\n\nlet area = '';\nlet city = '';\nlet state = '';\nlet zipcode = '';\n\n// Look for area information in email\nfor (const line of lines) {\n  if (line.toLowerCase().includes('area:') || line.toLowerCase().includes('location:')) {\n    area = line.split(':')[1]?.trim() || '';\n  }\n  if (line.toLowerCase().includes('city:')) {\n    city = line.split(':')[1]?.trim() || '';\n  }\n  if (line.toLowerCase().includes('state:')) {\n    state = line.split(':')[1]?.trim() || '';\n  }\n  if (line.toLowerCase().includes('zip:') || line.toLowerCase().includes('zipcode:')) {\n    zipcode = line.split(':')[1]?.trim() || '';\n  }\n}\n\n// If no structured data found, try to extract from general text\nif (!area && !city) {\n  const addressRegex = /([A-Za-z\\s]+),\\s*([A-Z]{2})\\s*(\\d{5})?/;\n  const match = emailBody.match(addressRegex);\n  if (match) {\n    city = match[1];\n    state = match[2];\n    zipcode = match[3] || '';\n  }\n}\n\nreturn {\n  json: {\n    searchArea: area || city,\n    city: city,\n    state: state,\n    zipcode: zipcode,\n    originalEmail: $input.first().json,\n    searchQuery: `${area || city} ${state} construction permits`.trim()\n  }\n};"
      },
      "typeVersion": 2
    },
    {
      "id": "85f1df36-93ce-4895-bbde-022ebe40a1e7",
      "name": "Search Government Data",
      "type": "n8n-nodes-base.httpRequest",
      "position": [
        660,
        0
      ],
      "parameters": {
        "url": "https://api.usa.gov/jobs/search.json",
        "options": {},
        "sendQuery": true,
        "authentication": "genericCredentialType",
        "genericAuthType": "httpQueryAuth",
        "queryParameters": {
          "parameters": [
            {
              "name": "keyword",
              "value": "construction permit"
            },
            {
              "name": "location_name",
              "value": "={{ $json.searchArea }}"
            },
            {
              "name": "size",
              "value": "20"
            }
          ]
        }
      },
      "credentials": {
        "httpQueryAuth": {
          "name": "<your credential>"
        }
      },
      "typeVersion": 4.1
    },
    {
      "id": "acc6341d-273f-4534-afb7-27771759a1df",
      "name": "Search Construction Sites",
      "type": "n8n-nodes-base.httpRequest",
      "position": [
        660,
        160
      ],
      "parameters": {
        "url": "https://www.construction.com/api/search",
        "options": {
          "timeout": 10000
        },
        "sendQuery": true,
        "sendHeaders": true,
        "queryParameters": {
          "parameters": [
            {
              "name": "q",
              "value": "={{ $json.searchArea }} construction projects"
            },
            {
              "name": "type",
              "value": "projects"
            },
            {
              "name": "limit",
              "value": "15"
            }
          ]
        },
        "headerParameters": {
          "parameters": [
            {
              "name": "User-Agent",
              "value": "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36"
            },
            {
              "name": "Accept",
              "value": "application/json"
            }
          ]
        }
      },
      "typeVersion": 4.1
    },
    {
      "id": "f8ca860e-b794-4749-9fa9-bb340e955845",
      "name": "Process Construction Data",
      "type": "n8n-nodes-base.code",
      "position": [
        900,
        40
      ],
      "parameters": {
        "jsCode": "const governmentData = $input.all()[0]?.json?.results || [];\nconst constructionData = $input.all()[1]?.json?.projects || [];\nconst searchInfo = $('Extract Location Info').first().json;\n\n// Process government construction data\nconst govProjects = governmentData.map(item => ({\n  title: item.position_title || 'Government Construction Project',\n  location: item.locations?.[0] || searchInfo.searchArea,\n  description: item.job_summary || 'No description available',\n  source: 'Government Database',\n  url: item.url || '#',\n  startDate: item.start_date || 'TBD',\n  type: 'Public Project'\n}));\n\n// Process construction industry data (fallback mock data if API fails)\nlet constructionProjects = [];\nif (constructionData.length > 0) {\n  constructionProjects = constructionData.map(item => ({\n    title: item.name || item.title || 'Construction Project',\n    location: item.location || searchInfo.searchArea,\n    description: item.description || 'Commercial construction project',\n    source: 'Construction Industry',\n    url: item.url || '#',\n    startDate: item.start_date || 'Q2 2024',\n    type: item.type || 'Private Project'\n  }));\n} else {\n  // Fallback mock data for demo purposes\n  constructionProjects = [\n    {\n      title: `New Commercial Complex - ${searchInfo.searchArea}`,\n      location: searchInfo.searchArea,\n      description: 'Mixed-use commercial and residential development',\n      source: 'Local Planning Department',\n      url: '#',\n      startDate: 'March 2024',\n      type: 'Mixed Development'\n    },\n    {\n      title: `Office Building Construction - ${searchInfo.city}`,\n      location: `${searchInfo.city}, ${searchInfo.state}`,\n      description: '5-story office building with retail space',\n      source: 'Building Permits',\n      url: '#',\n      startDate: 'April 2024',\n      type: 'Commercial'\n    }\n  ];\n}\n\n// Combine all projects\nconst allProjects = [...govProjects, ...constructionProjects];\n\n// Filter for recent/upcoming projects\nconst recentProjects = allProjects.filter(project => {\n  const startDate = new Date(project.startDate);\n  const now = new Date();\n  const threeMonthsFromNow = new Date(now.getTime() + (90 * 24 * 60 * 60 * 1000));\n  \n  return startDate >= now || project.startDate.includes('2024') || project.startDate === 'TBD';\n});\n\nreturn {\n  json: {\n    searchArea: searchInfo.searchArea,\n    totalProjects: recentProjects.length,\n    projects: recentProjects.slice(0, 10), // Limit to top 10\n    searchQuery: searchInfo.searchQuery,\n    generatedAt: new Date().toISOString(),\n    originalEmail: searchInfo.originalEmail\n  }\n};"
      },
      "typeVersion": 2
    },
    {
      "id": "5e85f511-81ac-42bf-af01-f465531874bb",
      "name": "Check if Projects Found",
      "type": "n8n-nodes-base.if",
      "position": [
        1320,
        80
      ],
      "parameters": {
        "options": {},
        "conditions": {
          "options": {
            "leftValue": "",
            "caseSensitive": true,
            "typeValidation": "strict"
          },
          "combinator": "and",
          "conditions": [
            {
              "id": "condition1",
              "operator": {
                "type": "number",
                "operation": "gt"
              },
              "leftValue": "={{ $json.totalProjects }}",
              "rightValue": 0
            }
          ]
        }
      },
      "typeVersion": 2
    },
    {
      "id": "3a614463-2f2d-4d28-8761-9dcb4349b653",
      "name": "Generate Email Report",
      "type": "n8n-nodes-base.code",
      "position": [
        1540,
        0
      ],
      "parameters": {
        "jsCode": "const data = $input.first().json;\nconst projects = data.projects;\n\n// Create HTML email content\nlet htmlContent = `\n<html>\n<head>\n  <style>\n    body { font-family: Arial, sans-serif; margin: 20px; }\n    .header { background-color: #f4f4f4; padding: 20px; border-radius: 5px; }\n    .project { border: 1px solid #ddd; margin: 10px 0; padding: 15px; border-radius: 5px; }\n    .project-title { color: #333; font-weight: bold; font-size: 16px; }\n    .project-meta { color: #666; font-size: 12px; margin: 5px 0; }\n    .project-desc { margin: 10px 0; }\n    .summary { background-color: #e8f4fd; padding: 15px; border-radius: 5px; margin: 20px 0; }\n  </style>\n</head>\n<body>\n  <div class=\"header\">\n    <h2>\ud83c\udfd7\ufe0f Construction Project Alert Report</h2>\n    <p><strong>Search Area:</strong> ${data.searchArea}</p>\n    <p><strong>Report Generated:</strong> ${new Date(data.generatedAt).toLocaleString()}</p>\n  </div>\n  \n  <div class=\"summary\">\n    <h3>\ud83d\udcca Summary</h3>\n    <p><strong>Total Projects Found:</strong> ${data.totalProjects}</p>\n    <p><strong>Search Query:</strong> ${data.searchQuery}</p>\n  </div>\n  \n  <h3>\ud83d\udd0d Upcoming Construction Projects</h3>\n`;\n\nif (projects.length === 0) {\n  htmlContent += '<p>No upcoming construction projects found in the specified area.</p>';\n} else {\n  projects.forEach((project, index) => {\n    htmlContent += `\n    <div class=\"project\">\n      <div class=\"project-title\">${project.title}</div>\n      <div class=\"project-meta\">\n        \ud83d\udccd Location: ${project.location} | \n        \ud83d\udcc5 Start Date: ${project.startDate} | \n        \ud83c\udfe2 Type: ${project.type}\n      </div>\n      <div class=\"project-desc\">\n        <strong>Description:</strong> ${project.description}\n      </div>\n      <div class=\"project-meta\">\n        <strong>Source:</strong> ${project.source}\n      </div>\n    </div>\n    `;\n  });\n}\n\nhtmlContent += `\n  <div style=\"margin-top: 30px; padding: 15px; background-color: #f9f9f9; border-radius: 5px;\">\n    <h4>\ud83d\udca1 Next Steps</h4>\n    <ul>\n      <li>Review each project for potential competition</li>\n      <li>Contact project owners for partnership opportunities</li>\n      <li>Monitor progress and timeline changes</li>\n      <li>Update your competitive analysis</li>\n    </ul>\n  </div>\n  \n  <p style=\"margin-top: 30px; color: #666; font-size: 12px;\">\n    This report was automatically generated by your Construction Alert System.<br>\n    To modify your alert preferences, reply to this email with your requirements.\n  </p>\n</body>\n</html>\n`;\n\n// Create plain text version\nlet textContent = `Construction Project Alert Report\\n\\n`;\ntextContent += `Search Area: ${data.searchArea}\\n`;\ntextContent += `Total Projects Found: ${data.totalProjects}\\n`;\ntextContent += `Report Generated: ${new Date(data.generatedAt).toLocaleString()}\\n\\n`;\n\nif (projects.length === 0) {\n  textContent += 'No upcoming construction projects found in the specified area.\\n';\n} else {\n  textContent += 'UPCOMING CONSTRUCTION PROJECTS:\\n';\n  textContent += '=' .repeat(40) + '\\n\\n';\n  \n  projects.forEach((project, index) => {\n    textContent += `${index + 1}. ${project.title}\\n`;\n    textContent += `   Location: ${project.location}\\n`;\n    textContent += `   Start Date: ${project.startDate}\\n`;\n    textContent += `   Type: ${project.type}\\n`;\n    textContent += `   Description: ${project.description}\\n`;\n    textContent += `   Source: ${project.source}\\n\\n`;\n  });\n}\n\nreturn {\n  json: {\n    subject: `\ud83c\udfd7\ufe0f Construction Alert: ${data.totalProjects} Projects Found in ${data.searchArea}`,\n    htmlContent: htmlContent,\n    textContent: textContent,\n    recipientEmail: data.originalEmail.from,\n    searchArea: data.searchArea,\n    projectCount: data.totalProjects\n  }\n};"
      },
      "typeVersion": 2
    },
    {
      "id": "4782972d-6b57-4faf-9ce1-cedbee42ecff",
      "name": "Send Alert Email",
      "type": "n8n-nodes-base.emailSend",
      "position": [
        1760,
        0
      ],
      "parameters": {
        "html": "={{ $json.htmlContent }}",
        "options": {},
        "subject": "={{ $json.subject }}",
        "toEmail": "={{ $json.recipientEmail }}",
        "fromEmail": "user@example.com"
      },
      "credentials": {
        "smtp": {
          "name": "<your credential>"
        }
      },
      "typeVersion": 2.1
    },
    {
      "id": "49d55c27-73f1-4436-99f9-f0e4ff2cf8ac",
      "name": "Send No Results Email",
      "type": "n8n-nodes-base.emailSend",
      "position": [
        1540,
        200
      ],
      "parameters": {
        "text": "No upcoming construction projects were found for the requested area: {{ $('Extract Location Info').first().json.searchArea }}\\n\\nSearch was triggered at: {{ new Date().toLocaleString() }}\\n\\nOriginal request from: {{ $('Extract Location Info').first().json.originalEmail.from }}",
        "options": {},
        "subject": "No Construction Projects Found",
        "toEmail": "user@example.com",
        "fromEmail": "user@example.com",
        "emailFormat": "text"
      },
      "credentials": {
        "smtp": {
          "name": "<your credential>"
        }
      },
      "typeVersion": 2.1
    },
    {
      "id": "9f9e205e-a6c6-4bf0-b25b-8d608eabc294",
      "name": "Wait For Data",
      "type": "n8n-nodes-base.wait",
      "position": [
        1120,
        40
      ],
      "parameters": {},
      "typeVersion": 1.1
    },
    {
      "id": "e5e98309-33a4-4b60-9cd6-f51925d77d7c",
      "name": "Sticky Note",
      "type": "n8n-nodes-base.stickyNote",
      "position": [
        220,
        -360
      ],
      "parameters": {
        "width": 860,
        "height": 300,
        "content": "\n## **How it works**\n* **Email Trigger** - Detects new email requests with \"Construction Alert Request\" in the subject line\n* **Check Email Subject** - Validates that the email contains the correct trigger phrase\n* **Extract Location Info** - Parses the email body to extract area, city, state, and zip code information\n* **Search Government Data** - Queries government databases for public construction projects and permits\n* **Search Construction Sites** - Searches construction industry databases for private projects\n* **Process Construction Data** - Combines and filters results from both sources, removing duplicates\n* **Wait For Data** - Wait for Combines and filters results\n* **Check If Projects Found** - Determines whether to send a results report or no-results notification\n* **Generate Email Report** - Creates a professional HTML email with project details and summaries\n* **Send Alert Email** - Delivers the construction project report to the requester\n* **Send No Results Email** - Notifies when no projects are found in the specified area\n\nThe workflow also includes a **Schedule Trigger** that can run automatically on weekdays at 9 AM for regular monitoring."
      },
      "typeVersion": 1
    }
  ],
  "active": false,
  "settings": {
    "executionOrder": "v1"
  },
  "versionId": "5e298be6-7660-412d-b5bb-15136626b35d",
  "connections": {
    "Email Trigger": {
      "main": [
        [
          {
            "node": "Check Email Subject",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Wait For Data": {
      "main": [
        [
          {
            "node": "Check if Projects Found",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Schedule Trigger": {
      "main": [
        [
          {
            "node": "Extract Location Info",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Check Email Subject": {
      "main": [
        [
          {
            "node": "Extract Location Info",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Extract Location Info": {
      "main": [
        [
          {
            "node": "Search Government Data",
            "type": "main",
            "index": 0
          },
          {
            "node": "Search Construction Sites",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Generate Email Report": {
      "main": [
        [
          {
            "node": "Send Alert Email",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Search Government Data": {
      "main": [
        [
          {
            "node": "Process Construction Data",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Check if Projects Found": {
      "main": [
        [
          {
            "node": "Generate Email Report",
            "type": "main",
            "index": 0
          }
        ],
        [
          {
            "node": "Send No Results Email",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Process Construction Data": {
      "main": [
        [
          {
            "node": "Wait For Data",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Search Construction Sites": {
      "main": [
        [
          {
            "node": "Process Construction Data",
            "type": "main",
            "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 n8n workflow monitors and alerts you about new construction projects in specified areas, helping you track competing builders and identify business opportunities. The system automatically searches multiple data sources and sends detailed email reports with upcoming…

Source: https://n8n.io/workflows/6963/ — 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

Email AI Auto-responder. Summerize and send email. Uses emailReadImap, emailSend, httpRequest, googleDrive. Event-driven trigger; 78 nodes.

Email Read Imap, Email Send, HTTP Request +2
Email & Gmail

Email AI Auto-responder. Summerize and send email. Uses emailReadImap, emailSend, httpRequest, googleDrive. Event-driven trigger; 78 nodes.

Email Read Imap, Email Send, HTTP Request +2
Email & Gmail

Email AI Auto-responder. Summerize and send email. Uses emailReadImap, emailSend, httpRequest, googleDrive. Event-driven trigger; 26 nodes.

Email Read Imap, Email Send, HTTP Request +1
Email & Gmail

Email AI Auto-responder. Summerize and send email. Uses emailReadImap, emailSend, httpRequest, googleDrive. Event-driven trigger; 26 nodes.

Email Read Imap, Email Send, HTTP Request +1
Email & Gmail

Transform your customer support operations with this enterprise-grade automation workflow that unifies, categorizes, and intelligently routes support tickets from multiple channels.

Email Read Imap, Email Send, Slack +1