{
  "id": "otH1aF0ejVvfCAt5",
  "meta": {
    "templateCredsSetupCompleted": true
  },
  "name": "Email List Personalization - Icebreaker And Subject Line Generator With OpenAI",
  "tags": [],
  "nodes": [
    {
      "id": "231d850b-d5b1-4717-99dc-96d91a5ecfaf",
      "name": "Rate Limit Delay",
      "type": "n8n-nodes-base.wait",
      "position": [
        2384,
        -208
      ],
      "parameters": {
        "amount": 1
      },
      "typeVersion": 1.1,
      "alwaysOutputData": false
    },
    {
      "id": "114f3b67-0ad5-4445-a380-29beae9fae3c",
      "name": "Write Results to Sheet",
      "type": "n8n-nodes-base.googleSheets",
      "position": [
        2160,
        -272
      ],
      "parameters": {
        "columns": {
          "value": {
            "row_number": "={{ $('Needs Icebreaker?').item.json.row_number }}",
            "icebreakers": "={{ $json.message.content.icebreaker }}"
          },
          "schema": [
            {
              "id": "icebreakers",
              "type": "string",
              "display": true,
              "required": false,
              "displayName": "icebreakers",
              "defaultMatch": false,
              "canBeUsedToMatch": true
            },
            {
              "id": "row_number",
              "type": "number",
              "display": true,
              "readOnly": true,
              "required": false,
              "displayName": "row_number",
              "defaultMatch": false,
              "canBeUsedToMatch": true
            }
          ],
          "mappingMode": "defineBelow",
          "matchingColumns": [
            "row_number"
          ],
          "attemptToConvertTypes": false,
          "convertFieldsToString": false
        },
        "options": {},
        "operation": "update",
        "sheetName": {
          "__rl": true,
          "mode": "list",
          "value": "gid=0",
          "cachedResultName": "Sheet1"
        },
        "documentId": {
          "__rl": true,
          "mode": "id",
          "value": "your-google-sheet-id"
        }
      },
      "credentials": {
        "googleSheetsOAuth2Api": {
          "name": "<your credential>"
        }
      },
      "executeOnce": false,
      "typeVersion": 4.5,
      "alwaysOutputData": true
    },
    {
      "id": "81607b05-c805-470c-8dc4-b253592d974b",
      "name": "Filter Empty Rows",
      "type": "n8n-nodes-base.filter",
      "position": [
        912,
        -208
      ],
      "parameters": {
        "options": {},
        "conditions": {
          "options": {
            "version": 1,
            "leftValue": "",
            "caseSensitive": true,
            "typeValidation": "strict"
          },
          "combinator": "or",
          "conditions": [
            {
              "id": "filter-empty-icebreaker",
              "operator": {
                "type": "string",
                "operation": "empty",
                "singleValue": true
              },
              "leftValue": "={{ $json.icebreakers }}",
              "rightValue": ""
            },
            {
              "id": "1b9a3e6c-ef51-45e4-af52-50a4390aef5b",
              "operator": {
                "type": "string",
                "operation": "equals"
              },
              "leftValue": "={{ $json.subjectLine }}",
              "rightValue": ""
            }
          ]
        }
      },
      "retryOnFail": false,
      "typeVersion": 2,
      "alwaysOutputData": true
    },
    {
      "id": "df47db5f-686e-45f1-a7eb-949c8685574a",
      "name": "Limit to 200 Leads",
      "type": "n8n-nodes-base.limit",
      "position": [
        1136,
        -208
      ],
      "parameters": {
        "maxItems": 200
      },
      "retryOnFail": false,
      "typeVersion": 1,
      "alwaysOutputData": true
    },
    {
      "id": "77ee3852-5a6e-431d-822e-6d954cab755b",
      "name": "Read Lead Sheet",
      "type": "n8n-nodes-base.googleSheets",
      "position": [
        688,
        -208
      ],
      "parameters": {
        "options": {},
        "sheetName": {
          "__rl": true,
          "mode": "list",
          "value": "gid=0",
          "cachedResultName": "Sheet1"
        },
        "documentId": {
          "__rl": true,
          "mode": "id",
          "value": "your-google-sheet-id"
        }
      },
      "credentials": {
        "googleSheetsOAuth2Api": {
          "name": "<your credential>"
        }
      },
      "typeVersion": 4.7
    },
    {
      "id": "c675c220-32dc-4b26-b6df-25ad6f0f2023",
      "name": "Process One by One",
      "type": "n8n-nodes-base.splitInBatches",
      "position": [
        1360,
        -208
      ],
      "parameters": {
        "options": {
          "reset": false
        }
      },
      "retryOnFail": false,
      "typeVersion": 3,
      "alwaysOutputData": true
    },
    {
      "id": "32f41cbd-9d24-4134-8771-58a3285ef318",
      "name": "Needs Icebreaker?",
      "type": "n8n-nodes-base.if",
      "position": [
        1584,
        -272
      ],
      "parameters": {
        "options": {},
        "conditions": {
          "options": {
            "version": 2,
            "leftValue": "",
            "caseSensitive": true,
            "typeValidation": "strict"
          },
          "combinator": "or",
          "conditions": [
            {
              "id": "22b5a816-26b6-42bf-8544-1afc7a78c95a",
              "operator": {
                "type": "string",
                "operation": "isEmpty",
                "singleValue": true
              },
              "leftValue": "={{ $json.icebreakers }}",
              "rightValue": ""
            },
            {
              "id": "f9480eb5-c82b-4c20-bec7-f306c82b2fb3",
              "operator": {
                "type": "string",
                "operation": "equals"
              },
              "leftValue": "={{ $json.subjectLine }}",
              "rightValue": ""
            }
          ]
        }
      },
      "typeVersion": 2.2
    },
    {
      "id": "e5a3e768-1d2a-47cf-a4a3-639320297eda",
      "name": "Generate Icebreaker",
      "type": "@n8n/n8n-nodes-langchain.openAi",
      "position": [
        1808,
        -288
      ],
      "parameters": {
        "modelId": {
          "__rl": true,
          "mode": "list",
          "value": "gpt-4.1-mini",
          "cachedResultName": "GPT-4.1-MINI"
        },
        "options": {},
        "messages": {
          "values": [
            {
              "role": "system",
              "content": "You are a helpful, intelligent writing assistant."
            },
            {
              "content": "Your task is to take, as input, a bunch of information about a prospect, and then generate a customized, one-line email icebreaker to imply that the rest of my communique is personalized.\n\nYou'll return your icebreakers in the following JSON format:\n\n{\"verdict\":\"true or false, string\",\"subjectLine\":\"hey {name}, think I have something for you re: {thingAboutThem}\",\"icebreaker\":\"Hey {firstName}. Love {thing}, also work in {paraphrasedIndustry}. Wanted to run something by you.\", \"shortenedCompanyName\":\"Shortened version of company name (more on this in a moment)\"}\n\nRules:\n- Write in a spartan/laconic tone of voice.\n- Make sure to use the above format when constructing your icebreakers.\n- Sometimes, the data provided will not be of a person. Instead, it will be of a company. If this is the case, return a \"false\" string for \"verdict\"\n- Shorten the company name wherever possible (say, \"XYZ\" instead of \"XYZ Agency\"). More examples: \"Love AMS\" instead of \"Love AMS Professional Services\", \"Love Mayo\" instead of \"Love Mayo Inc.\",  \"Love PCG\" instead of \"Pacific Creative Group LLC\", etc.\n- Do the same with locations. \"San Fran\" instead of \"San Francisco\", \"BC\" instead of \"British Columbia\", etc."
            },
            {
              "content": "Aina Rakotoarinaly, CEO founder - Maki Agency / Ti'bouffe, Maki agency, outsourcing/offshoring, Antananarivo, Madagascar"
            },
            {
              "role": "assistant",
              "content": "{\"verdict\":\"true\",\"icebreaker\":\"Hey Aina,\\n\\nLove what you're doing at Maki. Also doing some outsourcing right now, wanted to run something by you.\",\"shortenedCompanyName\":\"Maki\"}"
            },
            {
              "content": "Adam Greenwood, Visionary Agency Leader | Digital Strategy & AI | Middle East, UK & Global Markets, the human tech agency, information technology & services, Dubai, United Arab Emirates"
            },
            {
              "role": "assistant",
              "content": "{\"verdict\":\"true\",\"icebreaker\":\"Hey Adam,\\n\\nLove what you're doing at the human tech agency (branding in particular is fantastic). Just getting an agency off the ground, wanted to run something by you.\",\"shortenedCompanyName\":\"the human tech agency\"}"
            },
            {
              "content": "=Write an icebreaker and subject line for this lead:\n\nName: {{ $json.first_name }} {{ $json.last_name }}\nTitle: {{ $json.job_title }}\nCompany: {{ $json.company }}\nIndustry: {{ $json.linkedin_industry }}\nLocation: {{ $json.location }}\nEmployees: {{ $json.linkedin_company_employee_count }}\nFounded: {{ $json.linkedin_founded_year }}\nAbout them: {{ $json.summary }}\nAbout the company: {{ $json.linkedin_description }}\nSpecialties: {{ $json.linkedin_specialities }}"
            }
          ]
        },
        "jsonOutput": true
      },
      "credentials": {
        "openAiApi": {
          "name": "<your credential>"
        }
      },
      "typeVersion": 1.8
    },
    {
      "id": "00868a39-6667-44e8-9da1-048b83233df1",
      "name": "When clicking 'Execute workflow'",
      "type": "n8n-nodes-base.manualTrigger",
      "position": [
        448,
        -208
      ],
      "parameters": {},
      "typeVersion": 1
    },
    {
      "id": "5a9fb0d0-fe01-4e38-b094-b769bc07692c",
      "name": "Main Description",
      "type": "n8n-nodes-base.stickyNote",
      "position": [
        -160,
        -896
      ],
      "parameters": {
        "color": "#565936",
        "width": 528,
        "height": 876,
        "content": "## Email List Personalization - Icebreaker & Subject Line Generator\n\nReads an enriched lead list from Google Sheets, generates a personalized icebreaker and subject line for each lead using OpenAI, and writes results back to the same sheet.\n\n### How it works\n\n1. Reads all rows from your enriched lead sheet\n2. Filters to only rows missing an icebreaker or subject line (safe to re-run)\n3. Caps at 200 leads per run, then loops through one by one\n4. OpenAI generates a JSON response with icebreaker, subject line, shortened company name, and a verdict flag\n5. Writes results back to the same row via row_number match\n\n### Setup\n\n- [ ] Connect Google Sheets OAuth2 in both sheet nodes\n- [ ] Set your spreadsheet ID in \"Read Lead Sheet\" and \"Write Results to Sheet\"\n- [ ] Connect your OpenAI API key\n- [ ] Required columns: first_name, last_name, email, job_title, company, linkedin_industry, location, summary, linkedin_description, linkedin_specialities, linkedin_company_employee_count, linkedin_founded_year, icebreakers, subjectLine, row_number\n\n### Customization\n\n- Replace Manual Trigger with Schedule or Google Drive Trigger for automation\n- Adjust the Limit node to match your daily send volume\n- Swap GPT-4.1-mini (~$0.002/lead) for GPT-4o (~$0.01/lead) on premium campaigns\n- Edit the few-shot examples in the OpenAI node to match your voice"
      },
      "typeVersion": 1
    },
    {
      "id": "c9f6417f-5511-4dc1-ad6c-b9f01ea1ab39",
      "name": "Section - Load",
      "type": "n8n-nodes-base.stickyNote",
      "position": [
        384,
        -384
      ],
      "parameters": {
        "color": 4,
        "width": 888,
        "height": 360,
        "content": "### Load leads\nReads the enriched lead sheet, filters to rows missing icebreakers or subject lines, and caps at 200 per run."
      },
      "typeVersion": 1
    },
    {
      "id": "dc14ec18-a02d-415e-abac-b5c93d4d7817",
      "name": "Section - Generate",
      "type": "n8n-nodes-base.stickyNote",
      "position": [
        1296,
        -384
      ],
      "parameters": {
        "color": 5,
        "width": 776,
        "height": 360,
        "content": "### Generate icebreakers\nLoops through each lead one by one. Checks the row still needs an icebreaker, then calls OpenAI with few-shot examples to produce personalized copy."
      },
      "typeVersion": 1
    },
    {
      "id": "d074dc09-9b38-4257-a1da-d60725335e6d",
      "name": "Section - Save",
      "type": "n8n-nodes-base.stickyNote",
      "position": [
        2112,
        -384
      ],
      "parameters": {
        "color": 2,
        "width": 432,
        "height": 360,
        "content": "### Save & loop\nWrites the generated icebreaker and subject line back to the same row via row_number match. Waits 1s between calls to avoid API throttling, then loops to the next lead."
      },
      "typeVersion": 1
    },
    {
      "id": "0a3c0cbb-e401-41a8-92d3-5af3376b36e2",
      "name": "Warning",
      "type": "n8n-nodes-base.stickyNote",
      "position": [
        384,
        -496
      ],
      "parameters": {
        "color": 3,
        "width": 336,
        "height": 100,
        "content": "**Dont forget to** Connect your Google Sheets and OpenAI credentials, and set the correct spreadsheet ID in both sheet nodes before running."
      },
      "typeVersion": 1
    }
  ],
  "active": false,
  "settings": {
    "binaryMode": "separate",
    "callerPolicy": "workflowsFromSameOwner",
    "availableInMCP": false,
    "executionOrder": "v1"
  },
  "versionId": "34b8826f-5f3b-49eb-b12f-446b653ec0b4",
  "connections": {
    "Read Lead Sheet": {
      "main": [
        [
          {
            "node": "Filter Empty Rows",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Rate Limit Delay": {
      "main": [
        [
          {
            "node": "Process One by One",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Filter Empty Rows": {
      "main": [
        [
          {
            "node": "Limit to 200 Leads",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Needs Icebreaker?": {
      "main": [
        [
          {
            "node": "Generate Icebreaker",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Limit to 200 Leads": {
      "main": [
        [
          {
            "node": "Process One by One",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Process One by One": {
      "main": [
        [],
        [
          {
            "node": "Needs Icebreaker?",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Generate Icebreaker": {
      "main": [
        [
          {
            "node": "Write Results to Sheet",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Write Results to Sheet": {
      "main": [
        [
          {
            "node": "Rate Limit Delay",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "When clicking 'Execute workflow'": {
      "main": [
        [
          {
            "node": "Read Lead Sheet",
            "type": "main",
            "index": 0
          }
        ]
      ]
    }
  }
}