AutomationFlowsData & Sheets › Send Cold Outreach Emails and Follow-ups with Resend, Postgres and Hubspot

Send Cold Outreach Emails and Follow-ups with Resend, Postgres and Hubspot

ByGilbert Onyebuchi @gilbert-onyebuchi on n8n.io

Automate your cold email outreach with this 3-stage workflow that sends emails, triggers follow-ups after 3 days, and syncs responses to HubSpot CRM automatically. Uses: n8n, Postgres/Supabase, Resend API, HubSpot Features: Scheduled triggers, automatic follow-ups, response…

Cron / scheduled trigger★★★★☆ complexity20 nodesHTTP RequestPostgresHubSpot
Data & Sheets Trigger: Cron / scheduled Nodes: 20 Complexity: ★★★★☆ Added:

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

This workflow follows the HTTP Request → HubSpot 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": "eeebdbe7-00df-4419-a947-e142a85b22d3",
      "name": "Schedule Trigger",
      "type": "n8n-nodes-base.scheduleTrigger",
      "position": [
        -576,
        0
      ],
      "parameters": {
        "rule": {
          "interval": [
            {}
          ]
        }
      },
      "typeVersion": 1.3
    },
    {
      "id": "bb239eff-c26c-4dd0-a514-f23de7fc6b2a",
      "name": "HTTP Request",
      "type": "n8n-nodes-base.httpRequest",
      "position": [
        320,
        16
      ],
      "parameters": {
        "url": "https://api.resend.com/emails",
        "method": "POST",
        "options": {},
        "sendBody": true,
        "authentication": "genericCredentialType",
        "bodyParameters": {
          "parameters": [
            {
              "name": "from",
              "value": "user@example.com"
            },
            {
              "name": "to",
              "value": "={{ $json.Email }}"
            },
            {
              "name": "subject",
              "value": "My Elastic skin"
            },
            {
              "name": "text",
              "value": "=Hi {{ $json.properties.firstname.value }},\n\nI sent you the subject as my song title.\n\nBest,\nGilbert"
            }
          ]
        },
        "genericAuthType": "httpHeaderAuth"
      },
      "credentials": {
        "httpHeaderAuth": {
          "name": "<your credential>"
        }
      },
      "typeVersion": 4.3
    },
    {
      "id": "4ff5ce66-c0dc-4337-95b2-b63c39baa20f",
      "name": "Sticky Note",
      "type": "n8n-nodes-base.stickyNote",
      "position": [
        -704,
        -80
      ],
      "parameters": {
        "color": 7,
        "width": 1440,
        "height": 320,
        "content": "## 1. Get data, send emails and update"
      },
      "typeVersion": 1
    },
    {
      "id": "b573b321-49c6-4692-86b6-e348a08a396e",
      "name": "Select rows from a table",
      "type": "n8n-nodes-base.postgres",
      "position": [
        -368,
        0
      ],
      "parameters": {
        "table": {
          "__rl": true,
          "mode": "list",
          "value": "n8n tutorial",
          "cachedResultName": "n8n tutorial"
        },
        "where": {
          "values": [
            {
              "column": "Email sent",
              "condition": "IS NULL"
            }
          ]
        },
        "schema": {
          "__rl": true,
          "mode": "list",
          "value": "public"
        },
        "options": {},
        "operation": "select",
        "returnAll": true
      },
      "credentials": {
        "postgres": {
          "name": "<your credential>"
        }
      },
      "executeOnce": true,
      "typeVersion": 2.6
    },
    {
      "id": "8b26e5b6-9f80-43c6-a885-3d485e8cf958",
      "name": "Update rows in a table",
      "type": "n8n-nodes-base.postgres",
      "position": [
        512,
        16
      ],
      "parameters": {
        "table": {
          "__rl": true,
          "mode": "list",
          "value": "n8n tutorial",
          "cachedResultName": "n8n tutorial"
        },
        "schema": {
          "__rl": true,
          "mode": "list",
          "value": "public"
        },
        "columns": {
          "value": {
            "id": "={{ $('Wait').item.json.id }}",
            "Email sent": "={{ $now.toFormat('yyyy-MM-dd HH:mm:ss') }}"
          },
          "schema": [
            {
              "id": "id",
              "type": "number",
              "display": true,
              "removed": false,
              "required": false,
              "displayName": "id",
              "defaultMatch": true,
              "canBeUsedToMatch": true
            },
            {
              "id": "created_at",
              "type": "dateTime",
              "display": true,
              "required": false,
              "displayName": "created_at",
              "defaultMatch": false,
              "canBeUsedToMatch": true
            },
            {
              "id": "First name",
              "type": "string",
              "display": true,
              "required": true,
              "displayName": "First name",
              "defaultMatch": false,
              "canBeUsedToMatch": true
            },
            {
              "id": "Last name",
              "type": "string",
              "display": true,
              "required": false,
              "displayName": "Last name",
              "defaultMatch": false,
              "canBeUsedToMatch": true
            },
            {
              "id": "Email",
              "type": "string",
              "display": true,
              "required": false,
              "displayName": "Email",
              "defaultMatch": false,
              "canBeUsedToMatch": true
            },
            {
              "id": "Industry",
              "type": "string",
              "display": true,
              "required": false,
              "displayName": "Industry",
              "defaultMatch": false,
              "canBeUsedToMatch": true
            },
            {
              "id": "Website",
              "type": "string",
              "display": true,
              "required": false,
              "displayName": "Website",
              "defaultMatch": false,
              "canBeUsedToMatch": true
            },
            {
              "id": "Email sent",
              "type": "dateTime",
              "display": true,
              "required": false,
              "displayName": "Email sent",
              "defaultMatch": false,
              "canBeUsedToMatch": true
            },
            {
              "id": "1st follow-up",
              "type": "dateTime",
              "display": true,
              "removed": false,
              "required": false,
              "displayName": "1st follow-up",
              "defaultMatch": false,
              "canBeUsedToMatch": true
            },
            {
              "id": "2nd follow-up",
              "type": "dateTime",
              "display": true,
              "required": false,
              "displayName": "2nd follow-up",
              "defaultMatch": false,
              "canBeUsedToMatch": true
            }
          ],
          "mappingMode": "defineBelow",
          "matchingColumns": [
            "id"
          ],
          "attemptToConvertTypes": false,
          "convertFieldsToString": false
        },
        "options": {},
        "operation": "update"
      },
      "credentials": {
        "postgres": {
          "name": "<your credential>"
        }
      },
      "executeOnce": true,
      "typeVersion": 2.6
    },
    {
      "id": "632c17cb-a473-4cee-ad25-e13a53b42675",
      "name": "Loop Over Items",
      "type": "n8n-nodes-base.splitInBatches",
      "position": [
        -128,
        0
      ],
      "parameters": {
        "options": {}
      },
      "typeVersion": 3
    },
    {
      "id": "7e9919bd-0c49-4422-902d-5e82b06d5fef",
      "name": "Wait",
      "type": "n8n-nodes-base.wait",
      "position": [
        96,
        16
      ],
      "parameters": {},
      "typeVersion": 1.1
    },
    {
      "id": "4bbc7425-4559-40cd-9070-c9a6eb57b70a",
      "name": "Schedule Trigger1",
      "type": "n8n-nodes-base.scheduleTrigger",
      "position": [
        -560,
        368
      ],
      "parameters": {
        "rule": {
          "interval": [
            {}
          ]
        }
      },
      "typeVersion": 1.3
    },
    {
      "id": "03a57adb-aaf0-4e5a-ad5c-556e0a40f7f5",
      "name": "HTTP Request1",
      "type": "n8n-nodes-base.httpRequest",
      "position": [
        544,
        384
      ],
      "parameters": {
        "url": "https://api.resend.com/emails",
        "method": "POST",
        "options": {},
        "sendBody": true,
        "authentication": "genericCredentialType",
        "bodyParameters": {
          "parameters": [
            {
              "name": "from",
              "value": "user@example.com"
            },
            {
              "name": "to",
              "value": "={{ $json.Email }}"
            },
            {
              "name": "subject",
              "value": "My Elastic skin"
            },
            {
              "name": "text",
              "value": "=Hi {{ $json.properties.firstname.value }},\n\nI sent you the subject as my song title.\n\nBest,\nGilbert"
            }
          ]
        },
        "genericAuthType": "httpHeaderAuth"
      },
      "credentials": {
        "httpHeaderAuth": {
          "name": "<your credential>"
        }
      },
      "typeVersion": 4.3
    },
    {
      "id": "944bbf6e-c413-44ab-ab15-b595e189eaf3",
      "name": "Sticky Note1",
      "type": "n8n-nodes-base.stickyNote",
      "position": [
        -704,
        288
      ],
      "parameters": {
        "color": 7,
        "width": 1712,
        "height": 320,
        "content": "## 2. Filter by last day contacted, send follow-up, then update"
      },
      "typeVersion": 1
    },
    {
      "id": "4bd07ed9-e390-47fb-8b13-643ff88beff0",
      "name": "Select rows from a table1",
      "type": "n8n-nodes-base.postgres",
      "position": [
        -352,
        368
      ],
      "parameters": {
        "table": {
          "__rl": true,
          "mode": "list",
          "value": "n8n tutorial",
          "cachedResultName": "n8n tutorial"
        },
        "where": {
          "values": [
            {
              "column": "1st follow-up",
              "condition": "IS NULL"
            }
          ]
        },
        "schema": {
          "__rl": true,
          "mode": "list",
          "value": "public"
        },
        "options": {},
        "operation": "select",
        "returnAll": true
      },
      "credentials": {
        "postgres": {
          "name": "<your credential>"
        }
      },
      "executeOnce": true,
      "typeVersion": 2.6
    },
    {
      "id": "27341419-41cb-4bb6-956b-d4456e4d74aa",
      "name": "Update rows in a table1",
      "type": "n8n-nodes-base.postgres",
      "position": [
        736,
        384
      ],
      "parameters": {
        "table": {
          "__rl": true,
          "mode": "list",
          "value": "n8n tutorial",
          "cachedResultName": "n8n tutorial"
        },
        "schema": {
          "__rl": true,
          "mode": "list",
          "value": "public"
        },
        "columns": {
          "value": {
            "id": "={{ $('Wait1').item.json.id }}",
            "Email sent": "=",
            "1st follow-up": "={{ $now.toFormat('yyyy-MM-dd HH:mm:ss') }}"
          },
          "schema": [
            {
              "id": "id",
              "type": "number",
              "display": true,
              "removed": false,
              "required": false,
              "displayName": "id",
              "defaultMatch": true,
              "canBeUsedToMatch": true
            },
            {
              "id": "created_at",
              "type": "dateTime",
              "display": true,
              "required": false,
              "displayName": "created_at",
              "defaultMatch": false,
              "canBeUsedToMatch": true
            },
            {
              "id": "First name",
              "type": "string",
              "display": true,
              "required": true,
              "displayName": "First name",
              "defaultMatch": false,
              "canBeUsedToMatch": true
            },
            {
              "id": "Last name",
              "type": "string",
              "display": true,
              "required": false,
              "displayName": "Last name",
              "defaultMatch": false,
              "canBeUsedToMatch": true
            },
            {
              "id": "Email",
              "type": "string",
              "display": true,
              "required": false,
              "displayName": "Email",
              "defaultMatch": false,
              "canBeUsedToMatch": true
            },
            {
              "id": "Industry",
              "type": "string",
              "display": true,
              "required": false,
              "displayName": "Industry",
              "defaultMatch": false,
              "canBeUsedToMatch": true
            },
            {
              "id": "Website",
              "type": "string",
              "display": true,
              "required": false,
              "displayName": "Website",
              "defaultMatch": false,
              "canBeUsedToMatch": true
            },
            {
              "id": "Email sent",
              "type": "dateTime",
              "display": true,
              "required": false,
              "displayName": "Email sent",
              "defaultMatch": false,
              "canBeUsedToMatch": true
            },
            {
              "id": "1st follow-up",
              "type": "dateTime",
              "display": true,
              "removed": false,
              "required": false,
              "displayName": "1st follow-up",
              "defaultMatch": false,
              "canBeUsedToMatch": true
            },
            {
              "id": "2nd follow-up",
              "type": "dateTime",
              "display": true,
              "required": false,
              "displayName": "2nd follow-up",
              "defaultMatch": false,
              "canBeUsedToMatch": true
            }
          ],
          "mappingMode": "defineBelow",
          "matchingColumns": [
            "id"
          ],
          "attemptToConvertTypes": false,
          "convertFieldsToString": false
        },
        "options": {},
        "operation": "update"
      },
      "credentials": {
        "postgres": {
          "name": "<your credential>"
        }
      },
      "executeOnce": true,
      "typeVersion": 2.6
    },
    {
      "id": "3766fe7b-03f1-4638-86af-d06092ef1b2b",
      "name": "Loop Over Items1",
      "type": "n8n-nodes-base.splitInBatches",
      "position": [
        96,
        368
      ],
      "parameters": {
        "options": {}
      },
      "typeVersion": 3
    },
    {
      "id": "66167648-b165-4a89-8c2f-0841c817f870",
      "name": "Wait1",
      "type": "n8n-nodes-base.wait",
      "position": [
        320,
        384
      ],
      "parameters": {},
      "typeVersion": 1.1
    },
    {
      "id": "8c99d9b2-2ccb-4582-aa33-d678ce2632bf",
      "name": "Filter",
      "type": "n8n-nodes-base.filter",
      "position": [
        -144,
        368
      ],
      "parameters": {
        "options": {},
        "conditions": {
          "options": {
            "version": 3,
            "leftValue": "",
            "caseSensitive": true,
            "typeValidation": "strict"
          },
          "combinator": "and",
          "conditions": [
            {
              "id": "32108f04-5030-4160-94f8-367cd01f1bf1",
              "operator": {
                "type": "number",
                "operation": "equals"
              },
              "leftValue": "={{ $now.diff(DateTime.fromISO($json[\"Email sent\"]), 'days').days }}",
              "rightValue": 3
            }
          ]
        }
      },
      "typeVersion": 2.3
    },
    {
      "id": "d428a0d7-0026-4ad4-a509-70e347b1f9de",
      "name": "Webhook",
      "type": "n8n-nodes-base.webhook",
      "position": [
        848,
        16
      ],
      "parameters": {
        "path": "resend-email",
        "options": {},
        "httpMethod": "POST"
      },
      "typeVersion": 2.1
    },
    {
      "id": "754080cf-10ce-4db1-b00d-4c65dee32054",
      "name": "Update rows in a table2",
      "type": "n8n-nodes-base.postgres",
      "position": [
        1056,
        16
      ],
      "parameters": {
        "table": {
          "__rl": true,
          "mode": "list",
          "value": "n8n tutorial",
          "cachedResultName": "n8n tutorial"
        },
        "schema": {
          "__rl": true,
          "mode": "list",
          "value": "public"
        },
        "columns": {
          "value": {
            "Email": "={{ $json.body.data.from }}",
            "Email sent": "2026-01-04T00:00:00",
            "1st follow-up": "2026-01-04T00:00:00",
            "2nd follow-up": "2026-01-04T00:00:00"
          },
          "schema": [
            {
              "id": "id",
              "type": "number",
              "display": true,
              "removed": true,
              "required": false,
              "displayName": "id",
              "defaultMatch": true,
              "canBeUsedToMatch": true
            },
            {
              "id": "created_at",
              "type": "dateTime",
              "display": true,
              "required": false,
              "displayName": "created_at",
              "defaultMatch": false,
              "canBeUsedToMatch": true
            },
            {
              "id": "First name",
              "type": "string",
              "display": true,
              "required": true,
              "displayName": "First name",
              "defaultMatch": false,
              "canBeUsedToMatch": true
            },
            {
              "id": "Last name",
              "type": "string",
              "display": true,
              "required": false,
              "displayName": "Last name",
              "defaultMatch": false,
              "canBeUsedToMatch": true
            },
            {
              "id": "Email",
              "type": "string",
              "display": true,
              "removed": false,
              "required": false,
              "displayName": "Email",
              "defaultMatch": false,
              "canBeUsedToMatch": true
            },
            {
              "id": "Industry",
              "type": "string",
              "display": true,
              "required": false,
              "displayName": "Industry",
              "defaultMatch": false,
              "canBeUsedToMatch": true
            },
            {
              "id": "Website",
              "type": "string",
              "display": true,
              "required": false,
              "displayName": "Website",
              "defaultMatch": false,
              "canBeUsedToMatch": true
            },
            {
              "id": "Email sent",
              "type": "dateTime",
              "display": true,
              "required": false,
              "displayName": "Email sent",
              "defaultMatch": false,
              "canBeUsedToMatch": true
            },
            {
              "id": "1st follow-up",
              "type": "dateTime",
              "display": true,
              "removed": false,
              "required": false,
              "displayName": "1st follow-up",
              "defaultMatch": false,
              "canBeUsedToMatch": true
            },
            {
              "id": "2nd follow-up",
              "type": "dateTime",
              "display": true,
              "required": false,
              "displayName": "2nd follow-up",
              "defaultMatch": false,
              "canBeUsedToMatch": true
            }
          ],
          "mappingMode": "defineBelow",
          "matchingColumns": [
            "Email"
          ],
          "attemptToConvertTypes": false,
          "convertFieldsToString": false
        },
        "options": {},
        "operation": "update"
      },
      "credentials": {
        "postgres": {
          "name": "<your credential>"
        }
      },
      "executeOnce": true,
      "typeVersion": 2.6
    },
    {
      "id": "ddb82642-f103-42aa-a90d-21e059cb2347",
      "name": "Create or update a contact",
      "type": "n8n-nodes-base.hubspot",
      "position": [
        1264,
        16
      ],
      "parameters": {
        "email": "={{ $json.Email }}",
        "options": {},
        "authentication": "appToken",
        "additionalFields": {
          "industry": "={{ $json.Industry }}",
          "lastName": "={{ $json[\"Last name\"] }}",
          "firstName": "={{ $json[\"First name\"] }}",
          "websiteUrl": "={{ $json.Website }}"
        }
      },
      "credentials": {
        "hubspotAppToken": {
          "name": "<your credential>"
        }
      },
      "typeVersion": 2.2
    },
    {
      "id": "39e20889-37d6-4426-b747-18247c563841",
      "name": "Sticky Note2",
      "type": "n8n-nodes-base.stickyNote",
      "position": [
        768,
        -80
      ],
      "parameters": {
        "color": 7,
        "width": 688,
        "height": 320,
        "content": "## 3. Listen to email and stop when user reply. Then append to Hubspot"
      },
      "typeVersion": 1
    },
    {
      "id": "beb8f635-e03d-473f-81aa-2d9a3c69076d",
      "name": "Sticky Note3",
      "type": "n8n-nodes-base.stickyNote",
      "position": [
        -1632,
        -208
      ],
      "parameters": {
        "width": 800,
        "height": 1072,
        "content": "## Stop Manual Follow-ups with Automated Email Outreach Pipeline using n8n, Postgres and Resend\n\n## Watch my tutorial \n@[youtube](ZmN8jMhNJS4)\n\n## How it works\n- **The schedule Trigger nodes** are used to trigger the workflow\n- **Postgres nodes** are for making request calls to your postgres database\n- **Loop over items nodes** are to run data in sync repeatedly until the data finishes\n- **Wait nodes** are to run delay the workflow\n- **The HTTP request nodes** to make API call to [Resend](https://resend.com/) to send email\n- **Filter node** to filter data\n- **Webhook** to return data from [Resend](https://resend.com/) when email is received\n- **Hubspot node** to append data to your [HubSpot](https://www.hubspot.com/) CRM contact\n\n## Setup\n1. Register on [Supabase](https://supabase.com/) and create a table with data. Click connect above the supabase UI and set Method to transaction pooler. Connect the credential in Postgres node in n8n. Watch the tutorial video to understand better\n2. Register on [Resend](https://resend.com/). Link your Domain and verify. Connect API credential to HTTP request node\n3. Add Webhook in [Resend](https://resend.com/)\n4. Register on [HubSpot](https://www.hubspot.com/), create a legacy APP and connect credential to HubSpot node"
      },
      "typeVersion": 1
    }
  ],
  "connections": {
    "Wait": {
      "main": [
        [
          {
            "node": "HTTP Request",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Wait1": {
      "main": [
        [
          {
            "node": "HTTP Request1",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Filter": {
      "main": [
        []
      ]
    },
    "Webhook": {
      "main": [
        []
      ]
    },
    "HTTP Request": {
      "main": [
        [
          {
            "node": "Update rows in a table",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "HTTP Request1": {
      "main": [
        [
          {
            "node": "Update rows in a table1",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Loop Over Items": {
      "main": [
        [],
        [
          {
            "node": "Wait",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Loop Over Items1": {
      "main": [
        [],
        [
          {
            "node": "Wait1",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Schedule Trigger": {
      "main": [
        [
          {
            "node": "Select rows from a table",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Schedule Trigger1": {
      "main": [
        [
          {
            "node": "Select rows from a table1",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Update rows in a table": {
      "main": [
        [
          {
            "node": "Loop Over Items",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Update rows in a table1": {
      "main": [
        [
          {
            "node": "Loop Over Items1",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Update rows in a table2": {
      "main": [
        [
          {
            "node": "Create or update a contact",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Select rows from a table": {
      "main": [
        [
          {
            "node": "Loop Over Items",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Select rows from a table1": {
      "main": [
        [
          {
            "node": "Filter",
            "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

Automate your cold email outreach with this 3-stage workflow that sends emails, triggers follow-ups after 3 days, and syncs responses to HubSpot CRM automatically. Uses: n8n, Postgres/Supabase, Resend API, HubSpot Features: Scheduled triggers, automatic follow-ups, response…

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

Code Postgres. Uses httpRequest, splitInBatches, postgres, hubspot. Scheduled trigger; 23 nodes.

HTTP Request, Postgres, HubSpot +1
Data & Sheets

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

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

공유회_알림톡_크론. Uses postgres, httpRequest, n8n-nodes-solapi. Scheduled trigger; 39 nodes.

Postgres, HTTP Request, N8N Nodes Solapi
Data & Sheets

QuepasaAutomatic. Uses postgres, postgresTrigger, httpRequest. Scheduled trigger; 39 nodes.

Postgres, Postgres Trigger, HTTP Request
Data & Sheets

QuepasaAutomatic. Uses postgres, postgresTrigger, httpRequest. Scheduled trigger; 39 nodes.

Postgres, Postgres Trigger, HTTP Request