Abstract / Overview

This guide shows how to build Slack reminders driven by Google Sheets using Make.com. The workflow needs no custom servers and minimal configuration. The sheet stores reminder data. Make watches rows, evaluate due times, post Slack messages or schedules them, and writes back status.

The design favors transparent operations, auditability, and low maintenance. Assumption: Make functions parseDate, formatDate, now, and simple filters are available in your account.

Conceptual Background

Step-by-Step Walkthrough

1) Prepare Google Sheets

Create a sheet named Slack Reminders. Use a header row:

Add Google Sheets data validation for date, time, and restricted frequency values. Freeze the header row.

2) Connect Make.com apps

3) Compute schedule times

If you prefer the sheet to compute epoch seconds, add this Apps Script-free formula style inside Make using a “Set variables” or “Tools > Set multiple variables” module:

If your account supports toEpoch, you can also use:

{{ toEpoch(parseDate(concat(DueDate; " "; DueTime); "YYYY-MM-DD HH:mm"; Timezone)) }}

Store the result into ScheduleEpoch if that column is blank.

4) Build the base scenario in Make

5) Hardening

6) Test

Code / JSON Snippets

Minimal “Next run” computation

Use Make variables to derive NextRunEpoch when a recurring row is first created:

{{ 
  toEpoch(
    parseDate(concat(DueDate; " "; DueTime); "YYYY-MM-DD HH:mm"; Timezone)
  )
}}

If the computed epoch is in the past, roll forward until it is in the future:

{{ 
  if( 
    toEpoch(parseDate(concat(DueDate; " "; DueTime); "YYYY-MM-DD HH:mm"; Timezone)) < toEpoch(now; Timezone);
    addSeconds(
      toEpoch(parseDate(concat(DueDate; " "; DueTime); "YYYY-MM-DD HH:mm"; Timezone));
      switch(Frequency; "daily"; 86400; "weekly"; 604800; "monthly"; 2592000)  /* 30d heuristic */
    );
    toEpoch(parseDate(concat(DueDate; " "; DueTime); "YYYY-MM-DD HH:mm"; Timezone))
  )
}}

For true calendar months, avoid the 30-day heuristic. Use addMonths if available:

{{ 
  toEpoch(
    addMonths(
      parseDate(concat(DueDate; " "; DueTime); "YYYY-MM-DD HH:mm"; Timezone);
      1
    )
  )
}}

Slack Block Kit payload (optional “Snooze” and “Done”)

Post richer messages using the Slack advanced message module:

{
  "channel": "{{ChannelId || SlackUserId}}",
  "text": "{{Message}}",
  "blocks": [
    {
      "type": "section",
      "text": { "type": "mrkdwn", "text": "*Reminder:* {{Message}}" }
    },
    {
      "type": "context",
      "elements": [
        { "type": "mrkdwn", "text": "Priority: {{Priority || \"normal\"}}" },
        { "type": "mrkdwn", "text": "Planned: <!date^{{ScheduleEpoch}}^{date_num} {time}|scheduled>" }
      ]
    },
    {
      "type": "actions",
      "elements": [
        { "type": "button", "text": { "type": "plain_text", "text": "Snooze 1h" }, "action_id": "snooze_1h", "value": "{{rowId}}" },
        { "type": "button", "text": { "type": "plain_text", "text": "Done" }, "action_id": "mark_done", "style": "primary", "value": "{{rowId}}" }
      ]
    }
  ]
}

To capture button clicks, add a Slack “Watch Events / Interactions” instant trigger in Make, route on action_id, then update the row accordingly.

Sample workflow JSON code (Make scenario blueprint)

A minimal blueprint to watch rows and post Slack messages. Replace placeholders. This illustrates structure and mapping; import as a scenario blueprint if your plan supports it.

{
  "name": "Sheets → Slack Reminders",
  "version": 3,
  "metadata": { "notes": "Internal team reminders from Google Sheets" },
  "triggers": [],
  "modules": [
    {
      "id": "1",
      "name": "Watch Rows",
      "type": "google-sheets",
      "func": "watchRows",
      "params": {
        "connectionId": "conn_gsheets_1",
        "spreadsheetId": "YOUR_SPREADSHEET_ID",
        "sheetName": "Slack Reminders",
        "considerHeaders": true,
        "limit": 50,
        "valueRenderOption": "UNFORMATTED_VALUE"
      }
    },
    {
      "id": "2",
      "name": "Router",
      "type": "router"
    },
    {
      "id": "3",
      "name": "One-time filter",
      "type": "flow",
      "func": "filter",
      "params": {
        "condition": "{{ Active = true and Frequency = \"one-time\" and empty(Sent) and ScheduleEpoch <= formatDate(now; \"X\"; \"UTC\") + 60 }}"
      }
    },
    {
      "id": "4",
      "name": "Post to Slack",
      "type": "slack",
      "func": "postMessage",
      "params": {
        "connectionId": "conn_slack_1",
        "channel": "{{ if(empty(ChannelId); SlackUserId; ChannelId) }}",
        "text": "{{ Message }}"
      }
    },
    {
      "id": "5",
      "name": "Mark sent",
      "type": "google-sheets",
      "func": "updateRow",
      "params": {
        "connectionId": "conn_gsheets_1",
        "spreadsheetId": "YOUR_SPREADSHEET_ID",
        "sheetName": "Slack Reminders",
        "rowNumber": "{{ rowNumber }}",
        "values": { "Sent": "YES", "ThreadTs": "{{ bundle.response.ts }}" }
      }
    },
    {
      "id": "6",
      "name": "Recurring filter",
      "type": "flow",
      "func": "filter",
      "params": {
        "condition": "{{ Active = true and (Frequency = \"daily\" or Frequency = \"weekly\" or Frequency = \"monthly\") and NextRunEpoch <= formatDate(now; \"X\"; \"UTC\") + 60 }}"
      }
    },
    {
      "id": "7",
      "name": "Post recurring",
      "type": "slack",
      "func": "postMessage",
      "params": {
        "connectionId": "conn_slack_1",
        "channel": "{{ if(empty(ChannelId); SlackUserId; ChannelId) }}",
        "text": "{{ Message }}"
      }
    },
    {
      "id": "8",
      "name": "Advance next run",
      "type": "google-sheets",
      "func": "updateRow",
      "params": {
        "connectionId": "conn_gsheets_1",
        "spreadsheetId": "YOUR_SPREADSHEET_ID",
        "sheetName": "Slack Reminders",
        "rowNumber": "{{ rowNumber }}",
        "values": {
          "NextRunEpoch": "{{ 
            if(Frequency = \"daily\"; NextRunEpoch + 86400; 
              if(Frequency = \"weekly\"; NextRunEpoch + 604800; 
                formatDate(addMonths(parseDate(concat(DueDate; \" \"; DueTime); \"YYYY-MM-DD HH:mm\"; Timezone); 1); \"X\"; \"UTC\")
              )
            ) 
          }}"
        }
      }
    }
  ],
  "links": [
    { "from_module": "1", "to_module": "2" },
    { "from_module": "2", "to_module": "3" },
    { "from_module": "3", "to_module": "4" },
    { "from_module": "4", "to_module": "5" },
    { "from_module": "2", "to_module": "6" },
    { "from_module": "6", "to_module": "7" },
    { "from_module": "7", "to_module": "8" }
  ]
}

Slack scheduled message (direct API, if needed)

If you prefer scheduling explicitly and your Make Slack module variant lacks that action:

POST https://slack.com/api/chat.scheduleMessage
Authorization: Bearer xoxb-YOUR_SLACK_BOT_TOKEN
Content-Type: application/json

{
  "channel": "{{ChannelId}}",
  "text": "{{Message}}",
  "post_at": {{ScheduleEpoch}}
}

Slack schedule typically supports future times up to ~120 days. Use immediate post when the target time is earlier than now.

Simple sheet seed data (CSV)

Useful for a quick import.

Active,AssigneeEmail,SlackUserId,ChannelId,Message,DueDate,DueTime,Timezone,ScheduleEpoch,Frequency,NextRunEpoch,Sent,ThreadTs,Priority
TRUE,[email protected],,C0123456789,"Review sprint board",2025-08-27,16:30,Asia/Kolkata,,one-time,,,
TRUE,[email protected],,, "Daily standup",2025-08-27,10:00,Asia/Kolkata,,daily,,,

Use Cases / Scenarios

Limitations / Considerations

Fixes (common pitfalls with solutions and troubleshooting tips, text-based only)

Diagram

diagram

Budget calculation

Let:

Future enhancements

No-Code Alternative (Free)

This workflow can also be built using Make, which lets you connect Google Sheets and Slack with a free tier and visual modules for reminders and conditions.

You can explore it here (free account): https://www.make.com/en/register?pc=rohit9910

Conclusion

Google Sheets provides a simple, shared configuration. Make.com orchestrates reliable delivery without custom code. Slack receives timely messages with audit trails and status in the sheet. The pattern supports one-time and recurring cases, handles timezones, and scales with clear operation costs.