This workflow corresponds to n8n.io template #13259 — we link there as the canonical source.
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 →
{
"id": "JZ8C3IFRtHrntshw",
"meta": {
"templateCredsSetupCompleted": true
},
"name": "Subscription Renewal Reminder \u2013 Email & ClickUp",
"tags": [],
"nodes": [
{
"id": "6528965f-aa90-4b6c-ac4c-60bfeeb1ef9f",
"name": "\ud83d\udcd2 Workflow Overview",
"type": "n8n-nodes-base.stickyNote",
"position": [
-672,
-80
],
"parameters": {
"width": 566,
"height": 706,
"content": "## How it works\nThis workflow listens for a Webhook call and immediately queries a ClickUp list that stores all active customer subscriptions. It calculates how many days remain until each subscription\u2019s due date, automatically filtering out any that are not approaching renewal. For every record that is due within your chosen threshold (default = 7 days), it personalises and throttles renewal-reminder emails to the customer. Once the batch is processed, the workflow sends a concise admin summary if at least one reminder went out\u2014or a quick \"nothing due\" note when there are none.\n\n## Setup steps\n1. Create a ClickUp List with tasks that include **due_date** and a custom field called **Email** for the customer address.\n2. Copy the List-ID and paste it into the *Set Defaults* node.\n3. Configure your SMTP credentials in n8n and reference them in both Email nodes.\n4. Add your sender address and admin address in the *Set Defaults* node.\n5. Deploy the workflow and copy the Webhook URL.\n6. Call that URL (POST/GET) from any scheduler, external app, or simply run manually to test.\n7. Verify that customer reminders and the admin summary arrive as expected."
},
"typeVersion": 1
},
{
"id": "648c1471-7fd3-48bb-a739-a9663af369e3",
"name": "Trigger & Data Fetch",
"type": "n8n-nodes-base.stickyNote",
"position": [
-64,
-80
],
"parameters": {
"color": 7,
"width": 530,
"height": 718,
"content": "## Trigger & Data Fetch\nThis section starts the automation every time the webhook is hit. After optional default parameters are set, the ClickUp node pulls every task in the configured list\u2014effectively giving us every active subscription on record. The list-ID is kept in the *Set Defaults* node so non-technical users can adjust it without digging into other nodes. The ClickUp node returns one item per task, including the built-in **due_date** plus any custom fields. No filtering happens yet; we simply retrieve the raw records that downstream nodes will process."
},
"typeVersion": 1
},
{
"id": "df975e2a-82ab-486e-9a02-68ce6f385e94",
"name": "Processing & Filtering",
"type": "n8n-nodes-base.stickyNote",
"position": [
464,
-80
],
"parameters": {
"color": 7,
"width": 722,
"height": 718,
"content": "## Processing & Filtering\nThe *Filter Expiring & Build Data* code node converts UNIX due-dates into ISO strings, calculates **daysLeft**, and emits two separate outputs: \u2780 a list of subscriptions that will expire within the configured threshold and \u2781 a single summary item containing statistics for admin reporting. Output 0 is then batched and each item moves through personalised email preparation, a small throttling delay, and an actual send. Output 1 feeds the decision logic that chooses between sending an admin summary or a simple \"nothing due\" notification."
},
"typeVersion": 1
},
{
"id": "441bceb5-9fb8-44f1-999f-62e1403bec80",
"name": "Notifications & Reporting",
"type": "n8n-nodes-base.stickyNote",
"position": [
1184,
-80
],
"parameters": {
"color": 7,
"width": 1250,
"height": 718,
"content": "## Notifications & Reporting\nIf at least one renewal reminder went out, the workflow builds an HTML summary listing each customer, days left, and due date, then emails that report to your admin address. When **no** reminders are necessary, it instead fires a lightweight note so the operations team knows the run completed successfully. A final cleanup node marks the execution as complete; you can expand it for logging or archiving as needed."
},
"typeVersion": 1
},
{
"id": "01fbe124-54ef-43a6-a681-020854625e06",
"name": "Incoming Request",
"type": "n8n-nodes-base.webhook",
"position": [
-16,
320
],
"parameters": {
"path": "subscription-renewal",
"options": {},
"httpMethod": "POST"
},
"typeVersion": 1
},
{
"id": "4be4bfce-c8a2-44a3-9103-2fdccd49e412",
"name": "Set Defaults",
"type": "n8n-nodes-base.set",
"position": [
208,
304
],
"parameters": {
"options": {}
},
"typeVersion": 3
},
{
"id": "8c62cf19-72d0-4f71-9c99-76869162fee2",
"name": "Filter Expiring & Build Data",
"type": "n8n-nodes-base.code",
"position": [
544,
288
],
"parameters": {
"jsCode": "// Output 0: reminders, Output 1: summary\nconst threshold = $json[0].daysThreshold || 7;\nconst adminEmail = $json[0].adminEmail;\nconst now = Date.now();\nconst MS_IN_DAY = 86400000;\n\nconst reminders = [];\n\nitems.forEach(item => {\n const task = item.json;\n if (!task.due_date) return; // Skip tasks without due date\n const dueTs = Number(task.due_date);\n const daysLeft = Math.ceil((dueTs - now) / MS_IN_DAY);\n if (daysLeft <= threshold) {\n // Try to locate a custom field named \"Email\"\n const emailField = (task.custom_fields || []).find(f => f.name === 'Email');\n const customerEmail = emailField ? emailField.value : 'user@example.com';\n\n reminders.push({\n json: {\n taskId: task.id,\n subscriptionName: task.name,\n dueDateISO: new Date(dueTs).toISOString(),\n daysLeft,\n customerEmail,\n fromEmail: item.json.fromEmail,\n adminEmail,\n threshold\n }\n });\n }\n});\n\nconst summary = [{\n json: {\n runAt: new Date().toISOString(),\n totalReminders: reminders.length,\n adminEmail,\n threshold\n }\n}];\n\nreturn [reminders, summary];"
},
"typeVersion": 2
},
{
"id": "5209eeca-53a5-4eae-a5c5-d1a772ec0595",
"name": "Split per Subscription",
"type": "n8n-nodes-base.splitInBatches",
"position": [
784,
160
],
"parameters": {
"options": {}
},
"typeVersion": 3
},
{
"id": "3d4ac165-d2f1-4cdd-9720-917d7e790a18",
"name": "Prepare Reminder Email",
"type": "n8n-nodes-base.set",
"position": [
1264,
80
],
"parameters": {
"options": {}
},
"typeVersion": 3
},
{
"id": "91761b47-e3b5-41fa-8471-7e622500b5b6",
"name": "Throttle Reminders",
"type": "n8n-nodes-base.wait",
"position": [
1552,
48
],
"parameters": {
"unit": "seconds"
},
"typeVersion": 1
},
{
"id": "fb104676-0af7-4fc0-8d9d-3b1b28d1d8c9",
"name": "Send Reminder Email",
"type": "n8n-nodes-base.emailSend",
"position": [
1792,
80
],
"parameters": {
"options": {},
"subject": "={{ $json.subject }}",
"toEmail": "={{ $json.toEmail }}",
"fromEmail": "={{ $json.fromEmail }}"
},
"typeVersion": 2
},
{
"id": "4eb2cc81-0567-4b6d-a99c-a6043f2018b2",
"name": "Log Reminder Status",
"type": "n8n-nodes-base.set",
"position": [
1968,
80
],
"parameters": {
"options": {}
},
"typeVersion": 3
},
{
"id": "c62f5422-acc7-4bc5-8c51-6e12d9334c0a",
"name": "Any Reminders Sent?",
"type": "n8n-nodes-base.if",
"position": [
1008,
288
],
"parameters": {
"options": {},
"conditions": {
"number": [
{
"value1": "={{ $json.totalReminders }}",
"value2": 0,
"operation": "larger"
}
]
}
},
"typeVersion": 2
},
{
"id": "b837f97e-e59f-46aa-8a69-460f76bf95a9",
"name": "Build Admin Summary",
"type": "n8n-nodes-base.code",
"position": [
1680,
256
],
"parameters": {
"jsCode": "const total = $json.totalReminders;\nconst threshold = $json.threshold;\nconst runAt = $json.runAt;\n\nconst html = `<p>Hi Team,</p>\n<p>${total} renewal reminder(s) were sent during the latest run (threshold: ${threshold} days).</p>\n<p>Run time: ${runAt}</p>\n<p>Regards,<br>n8n Bot</p>`;\n\nreturn [{\n json: {\n adminEmail: $json.adminEmail,\n fromEmail: $json.fromEmail || 'user@example.com',\n summarySubject: `${total} subscription reminder(s) sent`,\n summaryHtml: html\n }\n}];"
},
"typeVersion": 2
},
{
"id": "4db7aa08-fd1d-4c55-acd4-85c859506034",
"name": "Send Admin Summary",
"type": "n8n-nodes-base.emailSend",
"position": [
1872,
256
],
"parameters": {
"options": {},
"subject": "={{ $json.summarySubject }}",
"toEmail": "={{ $json.adminEmail }}",
"fromEmail": "={{ $json.fromEmail }}"
},
"typeVersion": 2
},
{
"id": "35aec01b-9358-4693-a672-b51aceb93913",
"name": "Prepare No-Expiry Email",
"type": "n8n-nodes-base.set",
"position": [
1392,
480
],
"parameters": {
"options": {}
},
"typeVersion": 3
},
{
"id": "21fbcd30-05d8-417f-a113-d46ded6a395a",
"name": "Send No-Expiry Email",
"type": "n8n-nodes-base.emailSend",
"position": [
1632,
480
],
"parameters": {
"options": {},
"subject": "={{ $json.subject }}",
"toEmail": "={{ $json.toEmail }}",
"fromEmail": "={{ $json.fromEmail }}"
},
"typeVersion": 2
},
{
"id": "001c98f6-ecfc-4596-9302-a76a67ed1a9a",
"name": "Cleanup Execution",
"type": "n8n-nodes-base.code",
"position": [
2160,
320
],
"parameters": {
"jsCode": "return [{json:{status:'completed',finishedAt:new Date().toISOString()}}];"
},
"typeVersion": 2
}
],
"active": false,
"settings": {
"executionOrder": "v1"
},
"versionId": "f724815a-3620-4e25-9ed2-17edbec9e902",
"connections": {
"Set Defaults": {
"main": [
[
{
"node": "Filter Expiring & Build Data",
"type": "main",
"index": 0
}
]
]
},
"Incoming Request": {
"main": [
[
{
"node": "Set Defaults",
"type": "main",
"index": 0
}
]
]
},
"Send Admin Summary": {
"main": [
[
{
"node": "Cleanup Execution",
"type": "main",
"index": 0
}
]
]
},
"Throttle Reminders": {
"main": [
[
{
"node": "Send Reminder Email",
"type": "main",
"index": 0
}
]
]
},
"Any Reminders Sent?": {
"main": [
[
{
"node": "Build Admin Summary",
"type": "main",
"index": 0
}
],
[
{
"node": "Prepare No-Expiry Email",
"type": "main",
"index": 0
}
]
]
},
"Build Admin Summary": {
"main": [
[
{
"node": "Send Admin Summary",
"type": "main",
"index": 0
}
]
]
},
"Send Reminder Email": {
"main": [
[
{
"node": "Log Reminder Status",
"type": "main",
"index": 0
}
]
]
},
"Send No-Expiry Email": {
"main": [
[
{
"node": "Cleanup Execution",
"type": "main",
"index": 0
}
]
]
},
"Prepare Reminder Email": {
"main": [
[
{
"node": "Throttle Reminders",
"type": "main",
"index": 0
}
]
]
},
"Split per Subscription": {
"main": [
[
{
"node": "Prepare Reminder Email",
"type": "main",
"index": 0
}
],
[
{
"node": "Any Reminders Sent?",
"type": "main",
"index": 0
}
]
]
},
"Prepare No-Expiry Email": {
"main": [
[
{
"node": "Send No-Expiry Email",
"type": "main",
"index": 0
}
]
]
},
"Filter Expiring & Build Data": {
"main": [
[
{
"node": "Split per Subscription",
"type": "main",
"index": 0
}
]
]
}
}
}
For the full experience including quality scoring and batch install features for each workflow upgrade to Pro
About this workflow
Automate the tracking of customer subscription expiry dates, create renewal tasks in ClickUp, and dispatch friendly email reminders before the due date. The workflow listens for incoming subscription data, schedules reminder sequences, and updates ClickUp so your support or…
Source: https://n8n.io/workflows/13259/ — 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.
This workflow automates flight price comparison across multiple booking platforms (Kayak, Skyscanner, Expedia, Google Flights). It accepts natural language queries, extracts flight details using NLP,
[NooviChat] Onboarding Pós-Pagamento (Exp 6). Uses emailSend. Webhook trigger; 11 nodes.
This automated n8n workflow processes student applications on a scheduled basis, validates data, updates databases, and sends welcome communications to students and guardians.
Rejected Workflow. Uses emailSend, httpRequest, respondToWebhook. Webhook trigger; 6 nodes.