{
  "name": "Warm up Gmail inboxes with OpenAI GPT-4o-mini and Data Tables",
  "nodes": [
    {
      "id": "ea803d08-d03d-4bae-b1a1-00845dedc9d0",
      "name": "Sticky Note",
      "type": "n8n-nodes-base.stickyNote",
      "position": [
        -880,
        -496
      ],
      "parameters": {
        "width": 2224,
        "height": 400,
        "content": "## 1) Generate warmup conversations (daily)\nCreates friendly conversation JSON and saves it to `warmup_conversations`.\n"
      }
    },
    {
      "id": "1eb066c2-6f60-478a-864c-e4fe3562c150",
      "name": "Sticky Note1",
      "type": "n8n-nodes-base.stickyNote",
      "position": [
        -896,
        -16
      ],
      "parameters": {
        "width": 2240,
        "height": 672,
        "content": "## 2) Build warmup queue (daily)\nPairs inboxes + assigns messages into `warmup_queue`.\n"
      }
    },
    {
      "id": "7e835764-6937-44aa-ade3-56aceed17c8e",
      "name": "Sticky Note2",
      "type": "n8n-nodes-base.stickyNote",
      "position": [
        -928,
        720
      ],
      "parameters": {
        "width": 3168,
        "height": 736,
        "content": "## 3) Send warmup messages (hourly)\nAssigns random send times and sends/replies via Gmail.\n"
      }
    },
    {
      "id": "a5067261-6354-434f-b42b-341502ed37fc",
      "name": "Sticky Note3",
      "type": "n8n-nodes-base.stickyNote",
      "position": [
        1376,
        -496
      ],
      "parameters": {
        "width": 1072,
        "height": 1152,
        "content": "## 4) Mark warmup emails as read (hourly)\nRemoves UNREAD and updates `marked_read` in queue.\n"
      }
    },
    {
      "id": "4e97ce7d-6c01-41b0-9717-62aff4240536",
      "name": "generate warmup conversations",
      "type": "n8n-nodes-base.scheduleTrigger",
      "position": [
        -688,
        -320
      ]
    },
    {
      "id": "a36062d6-2e20-4d39-b92c-fdcd7f731de8",
      "name": "Get warmup accounts (cold_email_accounts)",
      "type": "n8n-nodes-base.dataTable",
      "position": [
        -400,
        -320
      ]
    },
    {
      "id": "8e24409c-2c25-42f8-af46-993b196f30de",
      "name": "Build conversation generation loop",
      "type": "n8n-nodes-base.code",
      "position": [
        -144,
        -320
      ]
    },
    {
      "id": "52c5312c-215c-4e20-8b83-3323f44187d4",
      "name": "Loop: generate conversations",
      "type": "n8n-nodes-base.splitInBatches",
      "position": [
        176,
        -320
      ]
    },
    {
      "id": "3ce03cdc-2f71-4aa3-a5bf-b098f5934c71",
      "name": "Generate conversations (OpenAI)",
      "type": "@n8n/n8n-nodes-langchain.openAi",
      "position": [
        400,
        -400
      ]
    },
    {
      "id": "c5874af0-4e83-4919-a40a-eb251c429647",
      "name": "Format conversations for Data Table",
      "type": "n8n-nodes-base.code",
      "position": [
        752,
        -400
      ]
    },
    {
      "id": "03282eb8-d2bc-4845-b714-0ba005401d51",
      "name": "Save conversations (warmup_conversations)",
      "type": "n8n-nodes-base.dataTable",
      "position": [
        976,
        -320
      ]
    },
    {
      "id": "7420f840-f366-42e3-b154-23af9c1f289d",
      "name": "Daily trigger: build warmup queue",
      "type": "n8n-nodes-base.scheduleTrigger",
      "position": [
        -832,
        336
      ]
    },
    {
      "id": "cfb4dc7d-4428-4076-b4e1-6621bab61b91",
      "name": "Get warmup accounts for queue",
      "type": "n8n-nodes-base.dataTable",
      "position": [
        -608,
        336
      ]
    },
    {
      "id": "a9001fc2-6e13-4349-8ad1-c34476eef65a",
      "name": "Loop: build queue per inbox",
      "type": "n8n-nodes-base.splitInBatches",
      "position": [
        -384,
        336
      ]
    },
    {
      "id": "4044866f-0468-440b-b9fd-ee22ab4afc0a",
      "name": "Calculate daily warmup target",
      "type": "n8n-nodes-base.code",
      "position": [
        -160,
        336
      ]
    },
    {
      "id": "28899f7f-ff7a-4f82-aba6-72047d5007c8",
      "name": "Get recipient inboxes (excluding sender)",
      "type": "n8n-nodes-base.dataTable",
      "position": [
        64,
        432
      ]
    },
    {
      "id": "2f27a0a9-f33b-4538-bc4e-8fe89bae4118",
      "name": "Pick random recipient inboxes",
      "type": "n8n-nodes-base.code",
      "position": [
        288,
        432
      ]
    },
    {
      "id": "3e94e231-670d-49ea-98c7-1af579b2054b",
      "name": "Get conversations from table",
      "type": "n8n-nodes-base.dataTable",
      "position": [
        64,
        240
      ]
    },
    {
      "id": "41b5e014-f181-4547-9acb-74383662de41",
      "name": "Parse conversation JSON",
      "type": "n8n-nodes-base.code",
      "position": [
        288,
        240
      ]
    },
    {
      "id": "a8604c91-31d1-403f-bf05-2df5c1100ad1",
      "name": "Merge recipients + conversations",
      "type": "n8n-nodes-base.merge",
      "position": [
        512,
        336
      ]
    },
    {
      "id": "574c087d-c6bf-4659-9b50-8961c8522512",
      "name": "Loop: match conversations to recipients",
      "type": "n8n-nodes-base.splitInBatches",
      "position": [
        736,
        336
      ]
    },
    {
      "id": "c1afc47c-18ea-48ca-a530-a9cd7542c739",
      "name": "Split conversation into scheduled messages",
      "type": "n8n-nodes-base.code",
      "position": [
        960,
        416
      ]
    },
    {
      "id": "24442941-657d-4dd2-ba0d-d2bc3489deb6",
      "name": "Flatten message list",
      "type": "n8n-nodes-base.code",
      "position": [
        -160,
        48
      ]
    },
    {
      "id": "2ccfc8d7-35a1-45c9-9bad-1b5493460a66",
      "name": "Insert messages into warmup_queue",
      "type": "n8n-nodes-base.dataTable",
      "position": [
        64,
        48
      ]
    },
    {
      "id": "c833ce57-1ea1-4f95-b215-f346a42f0eb4",
      "name": "Hourly trigger: send scheduled warmup emails",
      "type": "n8n-nodes-base.scheduleTrigger",
      "position": [
        -768,
        1024
      ]
    },
    {
      "id": "808504b6-3b21-40e4-9fe3-a3c540680738",
      "name": "Get today unsent warmups",
      "type": "n8n-nodes-base.dataTable",
      "position": [
        -560,
        1024
      ]
    },
    {
      "id": "5c1d8c50-4b08-4d68-9119-2743836a747e",
      "name": "Assign random send time (IST window)",
      "type": "n8n-nodes-base.code",
      "position": [
        -160,
        912
      ]
    },
    {
      "id": "5ec0eb3e-9a32-4330-99d4-72caddd3d9aa",
      "name": "Update scheduled_at in queue",
      "type": "n8n-nodes-base.dataTable",
      "position": [
        32,
        912
      ]
    },
    {
      "id": "d89a6fff-dd14-4dfc-939c-f327fb3021f2",
      "name": "If scheduled_at is empty",
      "type": "n8n-nodes-base.if",
      "position": [
        -368,
        1024
      ]
    },
    {
      "id": "80391bba-e8c0-438c-80b3-133959eda31e",
      "name": "Filter messages due now",
      "type": "n8n-nodes-base.code",
      "position": [
        208,
        1056
      ]
    },
    {
      "id": "be7d31d6-2ab9-47d0-be06-833715ea2a54",
      "name": "Get accounts (for credentials)",
      "type": "n8n-nodes-base.dataTable",
      "position": [
        208,
        1216
      ]
    },
    {
      "id": "b2d8d6b1-9568-482a-9875-9596f9ffdac1",
      "name": "Merge queue with account credentials",
      "type": "n8n-nodes-base.merge",
      "position": [
        400,
        1072
      ]
    },
    {
      "id": "d133bd11-328d-49f7-a3da-d8ef3f599e90",
      "name": "Loop: send warmup message",
      "type": "n8n-nodes-base.splitInBatches",
      "position": [
        592,
        1072
      ]
    },
    {
      "id": "4ed85c55-ae2e-4c74-aecd-88be839f8b8d",
      "name": "If first message in thread",
      "type": "n8n-nodes-base.if",
      "position": [
        832,
        1088
      ]
    },
    {
      "id": "2d0f3169-f438-4c23-b19e-eb423e62671a",
      "name": "Send Gmail message (new thread)",
      "type": "n8n-nodes-run-node-with-credentials-x.runNodeWithCredentialsX",
      "position": [
        1136,
        992
      ]
    },
    {
      "id": "610d87c3-dd31-4051-9f34-44c4cc81b483",
      "name": "Get previous message (thread context)",
      "type": "n8n-nodes-base.dataTable",
      "position": [
        1040,
        1152
      ]
    },
    {
      "id": "e8bb9300-ad97-40fe-9661-339f0bca742e",
      "name": "Reply in existing Gmail thread",
      "type": "n8n-nodes-run-node-with-credentials-x.runNodeWithCredentialsX",
      "position": [
        1232,
        1152
      ]
    },
    {
      "id": "193aaa95-df1f-4446-bae1-cdaf3fca7db9",
      "name": "Label sent warmup email",
      "type": "n8n-nodes-run-node-with-credentials-x.runNodeWithCredentialsX",
      "position": [
        1472,
        1072
      ]
    },
    {
      "id": "893a4bcf-2ffd-4e22-8b00-2e83af877181",
      "name": "Update queue: sent + message/thread IDs",
      "type": "n8n-nodes-base.dataTable",
      "position": [
        1760,
        1072
      ]
    },
    {
      "id": "82e1e8cd-49b9-45ee-bd97-be8dc5bf7a76",
      "name": "Hourly trigger: mark warmups as read",
      "type": "n8n-nodes-base.scheduleTrigger",
      "position": [
        1408,
        -320
      ]
    },
    {
      "id": "1f6525ab-531c-417b-9a19-fec4e87234ce",
      "name": "Get sent warmups to mark read",
      "type": "n8n-nodes-base.dataTable",
      "position": [
        1760,
        -416
      ]
    },
    {
      "id": "d5bff093-3664-41c9-bd36-f61de7f601cf",
      "name": "Loop: mark warmups read",
      "type": "n8n-nodes-base.splitInBatches",
      "position": [
        1488,
        16
      ]
    },
    {
      "id": "bf1eee80-b7a4-40f8-840f-ff3cd5970257",
      "name": "If warmup row exists",
      "type": "n8n-nodes-base.if",
      "position": [
        1872,
        32
      ]
    },
    {
      "id": "5f6a72fe-ccd2-41b2-ba3a-bb297f5a9230",
      "name": "Fetch unread messages from sender",
      "type": "n8n-nodes-run-node-with-credentials-x.runNodeWithCredentialsX",
      "position": [
        1696,
        32
      ]
    },
    {
      "id": "9d08d6e0-f602-4982-bda4-d16d418c7661",
      "name": "Get accounts (for receiver creds)",
      "type": "n8n-nodes-base.dataTable",
      "position": [
        1760,
        -240
      ]
    },
    {
      "id": "e48b6981-84c8-4771-b717-78a128c782ac",
      "name": "Merge receiver inbox credentials",
      "type": "n8n-nodes-base.merge",
      "position": [
        2144,
        -336
      ]
    },
    {
      "id": "4834504f-ca2c-43d5-9854-5aa405e5a16e",
      "name": "Label warmup message (receiver)",
      "type": "n8n-nodes-run-node-with-credentials-x.runNodeWithCredentialsX",
      "position": [
        2064,
        -64
      ]
    },
    {
      "id": "589ae7f2-936a-47da-b11a-37d3e1b39cf0",
      "name": "Remove UNREAD label (mark read)",
      "type": "n8n-nodes-run-node-with-credentials-x.runNodeWithCredentialsX",
      "position": [
        2240,
        -64
      ]
    },
    {
      "id": "58afed9d-4db3-4a4f-b8a4-027d28d7a13c",
      "name": "Update queue: marked_read = true",
      "type": "n8n-nodes-base.dataTable",
      "position": [
        2240,
        368
      ]
    },
    {
      "id": "afa63fe5-da49-46c1-b446-6b4fdf71c904",
      "name": "Sticky Note5",
      "type": "n8n-nodes-base.stickyNote",
      "position": [
        -1696,
        -496
      ],
      "parameters": {
        "width": 720,
        "height": 448,
        "content": "## How it works\nThis workflow warms up Gmail inboxes by sending natural, non-sales email conversations between your own inboxes. It generates friendly multi-message conversations using OpenAI, stores "
      }
    }
  ],
  "connections": {
    "Flatten message list": {
      "main": [
        [
          {
            "node": "Insert messages into warmup_queue",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "If warmup row exists": {
      "main": [
        [
          {
            "node": "Label warmup message (receiver)",
            "type": "main",
            "index": 0
          }
        ],
        [
          {
            "node": "Loop: mark warmups read",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Filter messages due now": {
      "main": [
        [
          {
            "node": "Merge queue with account credentials",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Label sent warmup email": {
      "main": [
        [
          {
            "node": "Update queue: sent + message/thread IDs",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Loop: mark warmups read": {
      "main": [
        [],
        [
          {
            "node": "Fetch unread messages from sender",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Parse conversation JSON": {
      "main": [
        [
          {
            "node": "Merge recipients + conversations",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Get today unsent warmups": {
      "main": [
        [
          {
            "node": "If scheduled_at is empty",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "If scheduled_at is empty": {
      "main": [
        [
          {
            "node": "Assign random send time (IST window)",
            "type": "main",
            "index": 0
          }
        ],
        [
          {
            "node": "Filter messages due now",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Loop: send warmup message": {
      "main": [
        [],
        [
          {
            "node": "If first message in thread",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "If first message in thread": {
      "main": [
        [
          {
            "node": "Send Gmail message (new thread)",
            "type": "main",
            "index": 0
          }
        ],
        [
          {
            "node": "Get previous message (thread context)",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Loop: build queue per inbox": {
      "main": [
        [
          {
            "node": "Flatten message list",
            "type": "main",
            "index": 0
          }
        ],
        [
          {
            "node": "Calculate daily warmup target",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Get conversations from table": {
      "main": [
        [
          {
            "node": "Parse conversation JSON",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Loop: generate conversations": {
      "main": [
        [],
        [
          {
            "node": "Generate conversations (OpenAI)",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Update scheduled_at in queue": {
      "main": [
        [
          {
            "node": "Filter messages due now",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Calculate daily warmup target": {
      "main": [
        [
          {
            "node": "Get recipient inboxes (excluding sender)",
            "type": "main",
            "index": 0
          },
          {
            "node": "Get conversations from table",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Get sent warmups to mark read": {
      "main": [
        [
          {
            "node": "Merge receiver inbox credentials",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Get warmup accounts for queue": {
      "main": [
        [
          {
            "node": "Loop: build queue per inbox",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Pick random recipient inboxes": {
      "main": [
        [
          {
            "node": "Merge recipients + conversations",
            "type": "main",
            "index": 1
          }
        ]
      ]
    },
    "generate warmup conversations": {
      "main": [
        [
          {
            "node": "Get warmup accounts (cold_email_accounts)",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Get accounts (for credentials)": {
      "main": [
        [
          {
            "node": "Merge queue with account credentials",
            "type": "main",
            "index": 1
          }
        ]
      ]
    },
    "Reply in existing Gmail thread": {
      "main": [
        [
          {
            "node": "Label sent warmup email",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Generate conversations (OpenAI)": {
      "main": [
        [
          {
            "node": "Format conversations for Data Table",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Label warmup message (receiver)": {
      "main": [
        [
          {
            "node": "Remove UNREAD label (mark read)",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Remove UNREAD label (mark read)": {
      "main": [
        [
          {
            "node": "Update queue: marked_read = true",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Send Gmail message (new thread)": {
      "main": [
        [
          {
            "node": "Label sent warmup email",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Merge receiver inbox credentials": {
      "main": [
        [
          {
            "node": "Loop: mark warmups read",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Merge recipients + conversations": {
      "main": [
        [
          {
            "node": "Loop: match conversations to recipients",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Update queue: marked_read = true": {
      "main": [
        [
          {
            "node": "Loop: mark warmups read",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Daily trigger: build warmup queue": {
      "main": [
        [
          {
            "node": "Get warmup accounts for queue",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Fetch unread messages from sender": {
      "main": [
        [
          {
            "node": "If warmup row exists",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Get accounts (for receiver creds)": {
      "main": [
        [
          {
            "node": "Merge receiver inbox credentials",
            "type": "main",
            "index": 1
          }
        ]
      ]
    },
    "Insert messages into warmup_queue": {
      "main": [
        []
      ]
    },
    "Build conversation generation loop": {
      "main": [
        [
          {
            "node": "Loop: generate conversations",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Format conversations for Data Table": {
      "main": [
        [
          {
            "node": "Save conversations (warmup_conversations)",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Assign random send time (IST window)": {
      "main": [
        [
          {
            "node": "Update scheduled_at in queue",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Hourly trigger: mark warmups as read": {
      "main": [
        [
          {
            "node": "Get sent warmups to mark read",
            "type": "main",
            "index": 0
          },
          {
            "node": "Get accounts (for receiver creds)",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Merge queue with account credentials": {
      "main": [
        [
          {
            "node": "Loop: send warmup message",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Get previous message (thread context)": {
      "main": [
        [
          {
            "node": "Reply in existing Gmail thread",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Loop: match conversations to recipients": {
      "main": [
        [],
        [
          {
            "node": "Split conversation into scheduled messages",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Update queue: sent + message/thread IDs": {
      "main": [
        [
          {
            "node": "Loop: send warmup message",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Get recipient inboxes (excluding sender)": {
      "main": [
        [
          {
            "node": "Pick random recipient inboxes",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Get warmup accounts (cold_email_accounts)": {
      "main": [
        [
          {
            "node": "Build conversation generation loop",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Save conversations (warmup_conversations)": {
      "main": [
        [
          {
            "node": "Loop: generate conversations",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Split conversation into scheduled messages": {
      "main": [
        [
          {
            "node": "Loop: build queue per inbox",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Hourly trigger: send scheduled warmup emails": {
      "main": [
        [
          {
            "node": "Get today unsent warmups",
            "type": "main",
            "index": 0
          },
          {
            "node": "Get accounts (for credentials)",
            "type": "main",
            "index": 0
          }
        ]
      ]
    }
  }
}