{
  "name": "Send weekly timesheet reminders to security agents with Gmail and Google Sheets",
  "nodes": [
    {
      "name": "Overview",
      "type": "n8n-nodes-base.stickyNote",
      "position": [
        -580,
        -149
      ],
      "parameters": {
        "color": 7,
        "width": 420,
        "height": 1460,
        "content": "## Send Weekly Timesheet Reminders to Security Agents\n\nEvery Friday at 16:00, this workflow reads your active agent roster from Google Sheets, sends each active agent a personalized email reminding them to submit their weekly timesheet, and records the reminder date back in the sheet \u2014 no more chasing on Monday morning.\n\n### How it works\n\n1. **Every Friday 16:00** fires the workflow on a weekly schedule.\n2. **Configure** holds all user-facing settings (sheet URL, manager email).\n3. **Read Active Agents** fetches all rows from your agent roster.\n4. **Capture Row Index** assigns each row a unique index for the final update.\n5. **Filter Active** keeps only agents with Status = Active.\n6. **Send Timesheet Reminder** delivers a personalized reminder to each agent's email.\n7. **Prepare Row Update** retrieves the row index for the sheet update.\n8. **Record Reminder Date** writes today's date to the Last_Reminded column.\n\n### Setup\n\n1. Connect your **Google Sheets OAuth2** credential.\n2. Connect your **Gmail OAuth2** credential.\n3. In the **Configure** node, update `sheetUrl` and `managerEmail`.\n4. Ensure your agent sheet has columns: Agent_Name, Email, Status, Last_Reminded.\n5. Set Status to **Active** for agents who should receive reminders.\n6. Activate the workflow.\n\n### Customization\n\n- Change the trigger time in **Every Friday 16:00** (e.g. 14:00 for an earlier deadline).\n- Add a `Timesheet_Submitted` column and filter it in **Filter Active** to skip agents who already submitted.\n- CC the manager by adding a `cc` field in the Send Timesheet Reminder node."
      },
      "typeVersion": 1
    },
    {
      "name": "Trigger & Configure",
      "type": "n8n-nodes-base.stickyNote",
      "position": [
        -60,
        -149
      ],
      "parameters": {
        "color": 1,
        "width": 720,
        "height": 369,
        "content": "## Trigger & Configure\n\nFires every Friday at 16:00. The Configure node holds all user-facing settings \u2014 update `sheetUrl` and `managerEmail` before activating."
      },
      "typeVersion": 1
    },
    {
      "name": "Read Data",
      "type": "n8n-nodes-base.stickyNote",
      "position": [
        740,
        -147
      ],
      "parameters": {
        "color": 1,
        "width": 720,
        "height": 367,
        "content": "## Read Data\n\nFetches all rows from the agent roster sheet. Assigns each row a unique index for the final reminder-date update."
      },
      "typeVersion": 1
    },
    {
      "name": "Filter & Send",
      "type": "n8n-nodes-base.stickyNote",
      "position": [
        1540,
        -147
      ],
      "parameters": {
        "color": 1,
        "width": 720,
        "height": 367,
        "content": "## Filter & Send\n\nKeeps only agents with Status = Active. Sends a personalized HTML timesheet reminder to each active agent via Gmail."
      },
      "typeVersion": 1
    },
    {
      "name": "Record & Update",
      "type": "n8n-nodes-base.stickyNote",
      "position": [
        2340,
        -147
      ],
      "parameters": {
        "color": 1,
        "width": 720,
        "height": 367,
        "content": "## Record & Update\n\nRetrieves the row index after the email is sent. Updates Google Sheets: records today's date in the Last_Reminded column."
      },
      "typeVersion": 1
    },
    {
      "name": "Every Friday 16:00",
      "type": "n8n-nodes-base.scheduleTrigger",
      "position": [
        0,
        0
      ],
      "parameters": {
        "rule": {
          "interval": [
            {
              "field": "cronExpression",
              "expression": "0 16 * * 5"
            }
          ]
        }
      },
      "typeVersion": 1.3
    },
    {
      "name": "Configure",
      "type": "n8n-nodes-base.set",
      "position": [
        400,
        0
      ],
      "parameters": {
        "mode": "manual",
        "options": {},
        "assignments": {
          "assignments": [
            {
              "id": "cfg-sheet",
              "name": "sheetUrl",
              "type": "string",
              "value": "https://docs.google.com/spreadsheets/d/YOUR_SHEET_ID_HERE/edit"
            },
            {
              "id": "cfg-manager",
              "name": "managerEmail",
              "type": "string",
              "value": "user@example.com"
            }
          ]
        },
        "includeOtherFields": false
      },
      "typeVersion": 3.4
    },
    {
      "name": "Read Active Agents",
      "type": "n8n-nodes-base.googleSheets",
      "position": [
        800,
        0
      ],
      "parameters": {
        "options": {},
        "resource": "sheet",
        "operation": "read",
        "sheetName": {
          "__rl": true,
          "mode": "id",
          "value": 0
        },
        "documentId": {
          "__rl": true,
          "mode": "url",
          "value": "={{ $('Configure').first().json.sheetUrl }}"
        }
      },
      "typeVersion": 4.7
    },
    {
      "name": "Capture Row Index",
      "type": "n8n-nodes-base.set",
      "position": [
        1200,
        0
      ],
      "parameters": {
        "mode": "manual",
        "options": {},
        "assignments": {
          "assignments": [
            {
              "id": "assign-row",
              "name": "row_number",
              "type": "number",
              "value": "={{ $itemIndex + 2 }}"
            }
          ]
        },
        "includeOtherFields": true
      },
      "typeVersion": 3.4
    },
    {
      "name": "Filter Active",
      "type": "n8n-nodes-base.filter",
      "position": [
        1600,
        0
      ],
      "parameters": {
        "options": {},
        "conditions": {
          "options": {
            "version": 3,
            "leftValue": "",
            "caseSensitive": true,
            "typeValidation": "strict"
          },
          "combinator": "and",
          "conditions": [
            {
              "id": "cond-active",
              "operator": {
                "type": "string",
                "operation": "equals"
              },
              "leftValue": "={{ $json.Status }}",
              "rightValue": "Active"
            }
          ]
        }
      },
      "typeVersion": 2.3
    },
    {
      "name": "Send Timesheet Reminder",
      "type": "n8n-nodes-base.gmail",
      "position": [
        2000,
        0
      ],
      "parameters": {
        "sendTo": "={{ $json.Email }}",
        "message": "={{ \"<html><body style=\\\"font-family:Arial,sans-serif\\\"><p>Hello <strong>\" + $json.Agent_Name + \"</strong>,</p><p>This is a reminder to submit your weekly timesheet before end of day today.</p><p>Please send your hours to <a href=\\\"mailto:\" + $('Configure').first().json.managerEmail + \"\\\">\" + $('Configure').first().json.managerEmail + \"</a>.</p><p>If you have already submitted, please disregard this message.</p><p>Thank you</p></body></html>\" }}",
        "options": {
          "appendAttribution": false
        },
        "subject": "={{ \"Timesheet reminder \u2014 week of \" + $now.startOf('week').toFormat('dd/MM/yyyy') }}",
        "resource": "message",
        "emailType": "html",
        "operation": "send"
      },
      "typeVersion": 2.2
    },
    {
      "name": "Prepare Row Update",
      "type": "n8n-nodes-base.set",
      "position": [
        2400,
        0
      ],
      "parameters": {
        "mode": "manual",
        "options": {},
        "assignments": {
          "assignments": [
            {
              "id": "restore-row",
              "name": "row_number",
              "type": "number",
              "value": "={{ $('Filter Active').item.json.row_number }}"
            }
          ]
        }
      },
      "typeVersion": 3.4
    },
    {
      "name": "Record Reminder Date",
      "type": "n8n-nodes-base.googleSheets",
      "position": [
        2800,
        0
      ],
      "parameters": {
        "columns": {
          "value": {
            "row_number": "={{ $json.row_number }}",
            "Last_Reminded": "={{ $now.toFormat('dd/MM/yyyy') }}"
          },
          "mappingMode": "defineBelow",
          "matchingColumns": [
            "row_number"
          ]
        },
        "options": {},
        "resource": "sheet",
        "operation": "update",
        "sheetName": {
          "__rl": true,
          "mode": "id",
          "value": 0
        },
        "documentId": {
          "__rl": true,
          "mode": "url",
          "value": "={{ $('Configure').first().json.sheetUrl }}"
        }
      },
      "typeVersion": 4.7
    }
  ],
  "active": false,
  "settings": {
    "executionOrder": "v1"
  },
  "connections": {
    "Configure": {
      "main": [
        [
          {
            "node": "Read Active Agents",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Filter Active": {
      "main": [
        [
          {
            "node": "Send Timesheet Reminder",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Capture Row Index": {
      "main": [
        [
          {
            "node": "Filter Active",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Every Friday 16:00": {
      "main": [
        [
          {
            "node": "Configure",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Prepare Row Update": {
      "main": [
        [
          {
            "node": "Record Reminder Date",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Read Active Agents": {
      "main": [
        [
          {
            "node": "Capture Row Index",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Send Timesheet Reminder": {
      "main": [
        [
          {
            "node": "Prepare Row Update",
            "type": "main",
            "index": 0
          }
        ]
      ]
    }
  },
  "description": "Every Friday at 16:00, reads the active agent roster from Google Sheets, sends each active agent a personalized reminder to submit their weekly timesheet, and records the reminder date back in the sheet."
}