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 →
{
"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.
postgressmtp
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 →
Related workflows
Workflows that share integrations, category, or trigger type with this one. All free to copy and import.
Disparador 1.8. Uses itemLists, postgres, emailSend, httpRequest. Scheduled trigger; 85 nodes.
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
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
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
HIPAA-Compliant Healthcare Data Synchronization. Uses httpRequest, postgres, mongoDb, elasticsearch. Scheduled trigger; 19 nodes.