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:
- Open your Slack workspace in a browser (e.g.
https://your-company.slack.com) - Open DevTools (F12)
Get the d cookie:
- Go to Application > Storage > Cookies >
app.slack.com - Find the cookie named
d(its value starts withxoxd-) - Copy the full value
Get the xoxc token:
- Go to the Console tab
- If on chrome enable pasting by typing "allow pasting"
- Run:
JSON.parse(localStorage.getItem('localConfig_v2')).teams[Object.keys(JSON.parse(localStorage.getItem('localConfig_v2')).teams)[0]].token
- 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
Release history Release notifications | RSS feed
Download files
Download the file for your platform. If you're not sure which to choose, learn more about installing packages.
Source Distribution
Built Distribution
Filter files by name, interpreter, ABI, and platform.
If you're not sure about the file name format, learn more about wheel file names.
Copy a direct link to the current filters
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
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
448c31b8293eab1e7fee059602f247bee194b282dfe2f8cbf1048f461ff51aa2
|
|
| MD5 |
f1f389ba9fe0efcbdca847a0b4365dce
|
|
| BLAKE2b-256 |
7e58a40a4ce7034c7b0f8dad647705a1d311b4127ca0e2bcd641f6a0c9c9f2cf
|
File details
Details for the file slack_scheduler-0.1.0-py3-none-any.whl.
File metadata
- Download URL: slack_scheduler-0.1.0-py3-none-any.whl
- Upload date:
- Size: 15.5 kB
- Tags: Python 3
- Uploaded using Trusted Publishing? No
- Uploaded via: twine/6.2.0 CPython/3.12.3
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
858b209c084d772fb1510761ec746bbeb78577dfc81376f278d4589cae546c5e
|
|
| MD5 |
f221b6af5c91a9f405b06b4b252aa922
|
|
| BLAKE2b-256 |
cd2c8102241962bad078a2d19410766e3334dcaa3a159eac27e1044664893f59
|