Skip to main content

Automated Slack message scheduler with cron-based scheduling, message rotation, and jitter support

Project description

slack-scheduler

Schedule and send Slack messages using browser session tokens — no Slack app or admin API approval required.

Quick Start

pip install slack-scheduler
slack-scheduler init
# Edit your config and credentials (paths shown by init)
slack-scheduler validate
slack-scheduler run

Getting Your Credentials

slack-scheduler authenticates using your browser session tokens (xoxc token + d cookie). Here's how to get them:

  1. Open your Slack workspace in a browser (e.g. https://your-company.slack.com)
  2. Open DevTools (F12)

Get the d cookie:

  1. Go to Application > Storage > Cookies > app.slack.com
  2. Find the cookie named d (its value starts with xoxd-)
  3. Copy the full value

Get the xoxc token:

  1. Go to the Console tab
  2. If on chrome enable pasting by typing "allow pasting"
  3. Run:
    JSON.parse(localStorage.getItem('localConfig_v2')).teams[Object.keys(JSON.parse(localStorage.getItem('localConfig_v2')).teams)[0]].token
    
  4. Copy the xoxc-... token

Save them to your credentials file:

slack-scheduler init  # creates the file with placeholders

Then edit the credentials file (path shown by init) and replace the placeholders:

SLACK_XOXC_TOKEN=xoxc-your-actual-token
SLACK_D_COOKIE=xoxd-your-actual-cookie

Note: These tokens expire (typically after ~1 year, shorter on workspaces with strict security policies). When they expire, repeat the steps above.

Configuration

After running slack-scheduler init, edit the config file:

workspace_url: "https://your-company.slack.com"

# Default message selection mode: "random" or "cycle"
default_selection_mode: "random"

# Dates to skip globally (YYYY-MM-DD)
skip_dates:
  - "2026-12-25"
  - "2026-01-01"

channels:
  - id: "C1234567890"        # Slack channel ID
    name: "standup"           # Human-readable label (for logs)

    messages:
      - "Good morning team! Ready for {day_of_week}."
      - "Morning all! Let's have a great {day_of_week}."
      - "Hey team, online and ready. Today is {date}."

    selection_mode: "cycle"   # Override default for this channel

    schedules:
      - cron: "0 9 * * 1-5"  # 9:00 AM, Monday-Friday
        jitter_minutes: 15    # Random delay up to 15 min (sends between 9:00-9:15)
        skip_weekends: true

  - id: "C0987654321"
    name: "random-chat"

    messages:
      - "Anyone up for a virtual coffee?"
      - "Happy {day_of_week}!"

    schedules:
      - cron: "0 14 * * 3"   # 2:00 PM every Wednesday
        jitter_minutes: 30

Tip: To find a channel's ID, right-click the channel name in Slack > "View channel details" > the ID is at the bottom.

CLI Commands

init — Set up config directories

slack-scheduler init

Creates config directories and template files at the OS-appropriate locations.

send — Send a message now

# Send a specific message
slack-scheduler send --channel C1234567890 --message "Good morning!"

# Pick randomly from multiple messages
slack-scheduler send --channel C1234567890 --message "Hello!" "Hey there!" "Morning!"

# Cycle through messages (no repeats until all are used)
slack-scheduler send --channel C1234567890 --message "Hello!" "Hey!" "Morning!" --selection-mode cycle

# Use messages from config file
slack-scheduler send --channel C1234567890

# Add a random delay before sending (useful with cron)
slack-scheduler send --channel C1234567890 --message "Good morning!" --jitter 15

# Override workspace URL
slack-scheduler send --channel C1234567890 --message "Hi" --workspace https://other.slack.com

# Preview without sending
slack-scheduler --dry-run send --channel C1234567890 --message "Test"
Flag Description
--channel (required) Target channel ID
--message One or more messages (random selection by default)
--workspace Workspace URL (overrides config)
--jitter <minutes> Random delay of 0 to N minutes before sending
--selection-mode random or cycle (overrides config)

run — Start the scheduler daemon

slack-scheduler run

# Preview mode (logs what would be sent)
slack-scheduler --dry-run run

Runs continuously and sends messages according to your config schedules. Stop with Ctrl-C.

status — Show upcoming messages

slack-scheduler status

# Show next 10 per schedule
slack-scheduler status --count 10

validate — Check credentials

slack-scheduler validate

Global Flags

Flag Description
--config <path> Path to config.yaml (overrides default)
--env <path> Path to credentials file (overrides default)
--dry-run Preview actions without sending
--verbose Enable debug logging

Message Templates

Messages support variable substitution:

Variable Example Output
{date} 2026-03-04
{day_of_week} Monday
{time} 09:15
messages:
  - "Good morning! Today is {day_of_week}, {date}."
  - "Online and ready at {time}."

Unknown variables are left as-is (e.g. {foo} stays {foo}).

Message Selection Modes

Random (default)

Picks a random message from the pool each time.

Cycle

Shuffles the message pool, then sends each message once before reshuffling. Guarantees every message is used before any repeats. State is persisted across restarts.

selection_mode: "cycle"

Scheduling

Cron Format

Standard 5-field cron syntax: minute hour day month weekday

0 9 * * 1-5     # 9:00 AM, Monday-Friday
30 8 * * *      # 8:30 AM, every day
0 14 * * 3      # 2:00 PM, Wednesdays
0 9,14 * * 1-5  # 9:00 AM and 2:00 PM, weekdays

Jitter

Adds a random delay of 0 to N minutes to the scheduled time so messages don't arrive at exactly the same second every day.

jitter_minutes: 15  # Sends up to 15 minutes after the scheduled time

A schedule at 09:00 with jitter_minutes: 15 will fire between 09:00 and 09:15.

Skip Rules

# Skip weekends
skip_weekends: true

# Skip specific dates (per-schedule, merged with global skip_dates)
skip_dates:
  - "2026-12-24"

File Locations

After running slack-scheduler init:

Linux macOS Windows
Config ~/.config/slack-scheduler/ ~/Library/Application Support/slack-scheduler/ %APPDATA%\slack-scheduler\
Credentials ~/.local/share/slack-scheduler/ ~/Library/Application Support/slack-scheduler/ %APPDATA%\slack-scheduler\
Logs ~/.local/share/slack-scheduler/logs/ ~/Library/Application Support/slack-scheduler/logs/ %APPDATA%\slack-scheduler\logs\

All paths are overridable with --config and --env flags.

Running as a Service

systemd (Linux)

Create ~/.config/systemd/user/slack-scheduler.service:

[Unit]
Description=Slack Scheduler

[Service]
ExecStart=slack-scheduler run
Restart=on-failure
RestartSec=30

[Install]
WantedBy=default.target
systemctl --user enable --now slack-scheduler

cron (alternative)

Instead of the daemon, use cron to call send directly:

# crontab -e
0 9 * * 1-5 slack-scheduler send --channel C1234567890 --message "Good morning!" --jitter 15

Project details


Download files

Download the file for your platform. If you're not sure which to choose, learn more about installing packages.

Source Distribution

slack_scheduler-0.1.0.tar.gz (24.9 kB view details)

Uploaded Source

Built Distribution

If you're not sure about the file name format, learn more about wheel file names.

slack_scheduler-0.1.0-py3-none-any.whl (15.5 kB view details)

Uploaded Python 3

File details

Details for the file slack_scheduler-0.1.0.tar.gz.

File metadata

  • Download URL: slack_scheduler-0.1.0.tar.gz
  • Upload date:
  • Size: 24.9 kB
  • Tags: Source
  • Uploaded using Trusted Publishing? No
  • Uploaded via: twine/6.2.0 CPython/3.12.3

File hashes

Hashes for slack_scheduler-0.1.0.tar.gz
Algorithm Hash digest
SHA256 448c31b8293eab1e7fee059602f247bee194b282dfe2f8cbf1048f461ff51aa2
MD5 f1f389ba9fe0efcbdca847a0b4365dce
BLAKE2b-256 7e58a40a4ce7034c7b0f8dad647705a1d311b4127ca0e2bcd641f6a0c9c9f2cf

See more details on using hashes here.

File details

Details for the file slack_scheduler-0.1.0-py3-none-any.whl.

File metadata

File hashes

Hashes for slack_scheduler-0.1.0-py3-none-any.whl
Algorithm Hash digest
SHA256 858b209c084d772fb1510761ec746bbeb78577dfc81376f278d4589cae546c5e
MD5 f221b6af5c91a9f405b06b4b252aa922
BLAKE2b-256 cd2c8102241962bad078a2d19410766e3334dcaa3a159eac27e1044664893f59

See more details on using hashes here.

Supported by

AWS Cloud computing and Security Sponsor Datadog Monitoring Depot Continuous Integration Fastly CDN Google Download Analytics Pingdom Monitoring Sentry Error logging StatusPage Status page