AutomationFlowsData & Sheets › 04c Outreach: Send Approved (rate-limited)

04c Outreach: Send Approved (rate-limited)

04c Outreach: Send Approved (rate-limited). Uses postgres, emailSend. Scheduled trigger; 6 nodes.

Cron / scheduled trigger★★★★☆ complexity6 nodesPostgresEmail Send
Data & Sheets Trigger: Cron / scheduled Nodes: 6 Complexity: ★★★★☆ Added:

This workflow follows the Emailsend → 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 →

Download .json
{
  "name": "04c Outreach: Send Approved (rate-limited)",
  "nodes": [
    {
      "parameters": {
        "rule": {
          "interval": [
            {
              "field": "minutes",
              "minutesInterval": 10
            }
          ]
        }
      },
      "id": "trg-sched",
      "name": "Every 10 Minutes",
      "type": "n8n-nodes-base.scheduleTrigger",
      "typeVersion": 1.1,
      "position": [
        200,
        300
      ]
    },
    {
      "parameters": {
        "operation": "executeQuery",
        "query": "SELECT o.id AS outreach_id, o.subject, o.body, o.recruiter_id, o.application_id, r.email AS recruiter_email, (SELECT count(*) FROM app.outreach s WHERE s.status = 'sent' AND s.sent_at > now() - interval '24 hours') AS sent_today FROM app.outreach o JOIN app.recruiters r ON r.id = o.recruiter_id WHERE o.status = 'approved' AND r.email IS NOT NULL ORDER BY o.approved_at ASC LIMIT 1;",
        "options": {}
      },
      "id": "pg-next",
      "name": "Get Next Approved",
      "type": "n8n-nodes-base.postgres",
      "typeVersion": 2.5,
      "position": [
        400,
        300
      ],
      "credentials": {
        "postgres": {
          "name": "<your credential>"
        }
      }
    },
    {
      "parameters": {
        "conditions": {
          "options": {
            "caseSensitive": true,
            "typeValidation": "loose",
            "version": 2
          },
          "conditions": [
            {
              "leftValue": "={{ $json.sent_today }}",
              "rightValue": "={{ Number($env.OUTREACH_MAX_PER_DAY || 15) }}",
              "operator": {
                "type": "number",
                "operation": "lt"
              }
            }
          ],
          "combinator": "and"
        }
      },
      "id": "if-cap",
      "name": "Under Daily Cap?",
      "type": "n8n-nodes-base.if",
      "typeVersion": 2,
      "position": [
        620,
        300
      ]
    },
    {
      "parameters": {
        "fromEmail": "={{ $env.GMAIL_ADDRESS }}",
        "toEmail": "={{ $json.recruiter_email }}",
        "subject": "={{ $json.subject }}",
        "emailFormat": "text",
        "text": "={{ $json.body }}",
        "options": {}
      },
      "id": "smtp-send",
      "name": "Send Email",
      "type": "n8n-nodes-base.emailSend",
      "typeVersion": 2.1,
      "position": [
        840,
        220
      ],
      "credentials": {
        "smtp": {
          "name": "<your credential>"
        }
      }
    },
    {
      "parameters": {
        "jsCode": "// Mark the outreach sent and record an outbound interaction in one query.\nfunction q(s){ return String(s==null?'':s).replace(/'/g, \"''\"); }\nconst o = $('Get Next Approved').item.json;\nconst query = `UPDATE app.outreach SET status = 'sent', sent_at = now() WHERE id = '${o.outreach_id}'; INSERT INTO app.interactions (recruiter_id, application_id, outreach_id, direction, channel, subject, body, message_id) VALUES ('${o.recruiter_id}', ${o.application_id ? `'${o.application_id}'` : 'NULL'}, '${o.outreach_id}', 'outbound', 'email', '${q(o.subject)}', '${q(o.body)}', 'sent-${o.outreach_id}'); INSERT INTO app.followups (recruiter_id, application_id, due_at, kind) VALUES ('${o.recruiter_id}', ${o.application_id ? `'${o.application_id}'` : 'NULL'}, now() + (interval '1 day' * ${Number($env.FOLLOWUP_DEFAULT_DAYS || 4)}), 'nudge');`;\nreturn [{ json: { query } }];"
      },
      "id": "code-mark",
      "name": "Build Mark-Sent SQL",
      "type": "n8n-nodes-base.code",
      "typeVersion": 2,
      "position": [
        1060,
        220
      ]
    },
    {
      "parameters": {
        "operation": "executeQuery",
        "query": "={{ $json.query }}",
        "options": {}
      },
      "id": "pg-mark",
      "name": "Mark Sent + Log Interaction",
      "type": "n8n-nodes-base.postgres",
      "typeVersion": 2.5,
      "position": [
        1280,
        220
      ],
      "credentials": {
        "postgres": {
          "name": "<your credential>"
        }
      }
    }
  ],
  "connections": {
    "Every 10 Minutes": {
      "main": [
        [
          {
            "node": "Get Next Approved",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Get Next Approved": {
      "main": [
        [
          {
            "node": "Under Daily Cap?",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Under Daily Cap?": {
      "main": [
        [
          {
            "node": "Send Email",
            "type": "main",
            "index": 0
          }
        ],
        []
      ]
    },
    "Send Email": {
      "main": [
        [
          {
            "node": "Build Mark-Sent SQL",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Build Mark-Sent SQL": {
      "main": [
        [
          {
            "node": "Mark Sent + Log Interaction",
            "type": "main",
            "index": 0
          }
        ]
      ]
    }
  },
  "active": false,
  "settings": {
    "executionOrder": "v1"
  }
}

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

04c Outreach: Send Approved (rate-limited). Uses postgres, emailSend. Scheduled trigger; 6 nodes.

Source: https://github.com/AskariJafri/job-search-os/blob/main/n8n/workflows/04-outreach/sender.json — original creator credit. Request a take-down →

More Data & Sheets workflows → · Browse all categories →

Related workflows

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

Data & Sheets

Disparador 1.8. Uses itemLists, postgres, emailSend, httpRequest. Scheduled trigger; 85 nodes.

Item Lists, Postgres, Email Send +1
Data & Sheets

This n8n workflow runs daily to analyze active customer behavior, engineers relevant features from usage and transaction data, applies a machine learning or AI-based model to predict churn probability

HTTP Request, Postgres, Email Send
Data & Sheets

This n8n workflow automates continuous compliance monitoring across IT, OT, and cloud environments by aggregating security controls, validating policies (ISO 27001, NIST, GDPR, SOC2), detecting anomal

HTTP Request, Postgres, Email Send
Data & Sheets

Automates real-time market monitoring, technical analysis, AI-powered signal generation for cryptocurrencies (and stocks), filters high-confidence trades, and delivers actionable alerts via multiple c

HTTP Request, Postgres, Email Send
Data & Sheets

HIPAA-Compliant Healthcare Data Synchronization. Uses httpRequest, postgres, mongoDb, elasticsearch. Scheduled trigger; 19 nodes.

HTTP Request, Postgres, MongoDB +3