Build a Slack Bot for Team Notifications with Python in 30 Minutes
Our marketing team was drowning in missed updates. Critical campaign launches, budget approvals, and performance alerts were buried in email threads and direct messages. The result? Delayed responses, missed deadlines, and constant "Did you see my message?" followups.
After building a simple Slack bot that automatically posts notifications to the right channels at the right times, everything changed:
- Campaign launch reminders: automatically posted 24 hours before go-live
- Budget alerts: instant notifications when spending exceeds thresholds
- Performance reports: daily summaries delivered every morning at 9 AM
- Response times: cut from hours to minutes
This tutorial walks you through building your own Slack bot using Python—from basic setup to advanced features like scheduled messages, interactive commands, and event monitoring.
What You'll Build
By the end of this tutorial, you'll have a Slack bot that can:
- Send messages to channels and users
- Post formatted messages with buttons and attachments
- Respond to commands (e.g.,
@bot status) - Schedule recurring messages (daily reports, reminders)
- Monitor channel activity and respond to keywords
- Handle interactive elements (button clicks, menu selections)
Prerequisites
Requirements:
- Python 3.8 or newer
- A Slack workspace (free tier works)
- Admin access to create Slack apps
- 30 minutes of focused time
Python Knowledge: Basic understanding of functions, APIs, and dictionaries
Step 1: Create Your Slack App
Setting Up in Slack
-
Go to api.slack.com/apps
-
Click "Create New App"
- Choose "From scratch"
- App name: "Team Notifier Bot"
- Workspace: Select your workspace
- Click "Create App"
-
Configure Bot Permissions
Navigate to "OAuth & Permissions" in the left sidebar
Scroll down to "Scopes" → "Bot Token Scopes"
Click "Add an OAuth Scope" and add:
chat:write(send messages)chat:write.public(send to channels without joining)channels:read(view channel info)groups:read(view private channels)im:read(view DMs)mpim:read(view group DMs)users:read(view user info)commands(create slash commands)
-
Install App to Workspace
Scroll to top of "OAuth & Permissions"
Click "Install to Workspace"
Authorize the permissions
Copy the "Bot User OAuth Token" (starts with
xoxb-)⚠️ Keep this token secret! Never commit it to GitHub
-
Get Your Channel ID (where bot will post)
In Slack desktop app:
- Right-click on your channel → "View channel details"
- Scroll to bottom and copy the Channel ID
Step 2: Set Up Python Environment
Install Required Packages
1# Create project directory2mkdir slack-notifier-bot3cd slack-notifier-bot45# Create virtual environment6python -m venv venv78# Activate virtual environment9# Windows:10venv\Scripts\activate11# Mac/Linux:12source venv/bin/activate1314# Install packages15pip install slack-sdk python-dotenv schedule requests
Create Environment Configuration
Create .env file in your project directory:
1# .env2SLACK_BOT_TOKEN=xoxb-your-token-here3SLACK_CHANNEL_ID=C0123456789
Important: Add .env to your .gitignore:
1echo ".env" >> .gitignore
Step 3: Build Your First Slack Bot
Basic Bot: Send Simple Messages
Create bot.py:
1# bot.py2import os3from dotenv import load_dotenv4from slack_sdk import WebClient5from slack_sdk.errors import SlackApiError67# Load environment variables8load_dotenv()910# Initialize Slack client11client = WebClient(token=os.getenv('SLACK_BOT_TOKEN'))1213def send_message(channel, text):14 """15 Send a simple text message to a Slack channel1617 Args:18 channel (str): Channel ID or name19 text (str): Message text20 """21 try:22 response = client.chat_postMessage(23 channel=channel,24 text=text25 )2627 print(f"Message sent successfully: {response['ts']}")28 return response2930 except SlackApiError as e:31 print(f"Error sending message: {e.response['error']}")32 return None333435if __name__ == "__main__":36 # Test the bot37 channel_id = os.getenv('SLACK_CHANNEL_ID')3839 send_message(40 channel=channel_id,41 text="Hello from Python! 🤖 Your bot is working!"42 )
Run it:
1python bot.py
You should see your message appear in Slack! 🎉
Step 4: Send Formatted Messages with Blocks
Slack's Block Kit allows rich formatting with buttons, images, and sections.
Create Formatted Notifications
Update bot.py with this function:
1def send_formatted_message(channel, title, message, color="good"):2 """3 Send a formatted message with color-coded sidebar45 Args:6 channel (str): Channel ID7 title (str): Message title8 message (str): Message body9 color (str): Sidebar color (good, warning, danger, or hex)10 """11 try:12 response = client.chat_postMessage(13 channel=channel,14 attachments=[15 {16 "color": color,17 "blocks": [18 {19 "type": "header",20 "text": {21 "type": "plain_text",22 "text": title,23 "emoji": True24 }25 },26 {27 "type": "section",28 "text": {29 "type": "mrkdwn",30 "text": message31 }32 },33 {34 "type": "context",35 "elements": [36 {37 "type": "mrkdwn",38 "text": f"Sent at: {datetime.now().strftime('%Y-%m-%d %H:%M:%S')}"39 }40 ]41 }42 ]43 }44 ]45 )4647 print("Formatted message sent successfully")48 return response4950 except SlackApiError as e:51 print(f"Error sending formatted message: {e.response['error']}")52 return None535455# Example usage:56if __name__ == "__main__":57 from datetime import datetime5859 send_formatted_message(60 channel=os.getenv('SLACK_CHANNEL_ID'),61 title="🚀 Deployment Complete",62 message="*Version:* 2.3.1\n*Environment:* Production\n*Status:* ✅ Success\n\nAll systems operational.",63 color="good"64 )
Step 5: Add Interactive Buttons
Messages with Action Buttons
1def send_message_with_buttons(channel, message, buttons):2 """3 Send a message with interactive buttons45 Args:6 channel (str): Channel ID7 message (str): Message text8 buttons (list): List of button dictionaries9 """10 try:11 # Convert buttons to Block Kit format12 button_elements = []13 for button in buttons:14 button_elements.append({15 "type": "button",16 "text": {17 "type": "plain_text",18 "text": button['text']19 },20 "value": button['value'],21 "action_id": button['action_id']22 })2324 response = client.chat_postMessage(25 channel=channel,26 text=message,27 blocks=[28 {29 "type": "section",30 "text": {31 "type": "mrkdwn",32 "text": message33 }34 },35 {36 "type": "actions",37 "elements": button_elements38 }39 ]40 )4142 return response4344 except SlackApiError as e:45 print(f"Error sending message with buttons: {e.response['error']}")46 return None474849# Example usage:50if __name__ == "__main__":51 send_message_with_buttons(52 channel=os.getenv('SLACK_CHANNEL_ID'),53 message="*Budget Alert:* Marketing spend is at 85% for this month.\nWhat action should we take?",54 buttons=[55 {56 'text': '✅ Approve Additional Budget',57 'value': 'approve',58 'action_id': 'budget_approve'59 },60 {61 'text': '⚠️ Pause Campaigns',62 'value': 'pause',63 'action_id': 'budget_pause'64 },65 {66 'text': '📊 View Details',67 'value': 'details',68 'action_id': 'budget_details'69 }70 ]71 )
Note: Handling button clicks requires setting up a web server endpoint. See "Step 8: Handle Interactive Events" for full implementation.
Step 6: Schedule Recurring Messages
Daily Reports Bot
Create scheduled_bot.py:
1# scheduled_bot.py2import os3import schedule4import time5from datetime import datetime6from dotenv import load_dotenv7from slack_sdk import WebClient89load_dotenv()10client = WebClient(token=os.getenv('SLACK_BOT_TOKEN'))1112def post_daily_report():13 """14 Post a daily team report at 9 AM15 """16 channel = os.getenv('SLACK_CHANNEL_ID')1718 # Generate report content (example - replace with your data source)19 report = f"""20*📊 Daily Team Report - {datetime.now().strftime('%B %d, %Y')}*2122*Yesterday's Highlights:*23• 15 pull requests merged24• 3 bugs fixed25• 2 new features deployed2627*Today's Focus:*28• Sprint planning meeting at 10 AM29• Code review for feature-X30• Performance optimization tasks3132*Blockers:*33• None reported3435Have a productive day! 💪36"""3738 try:39 client.chat_postMessage(40 channel=channel,41 text=report42 )43 print(f"Daily report posted at {datetime.now()}")4445 except Exception as e:46 print(f"Error posting daily report: {e}")474849def post_weekly_reminder():50 """51 Post weekly reminders on Monday mornings52 """53 channel = os.getenv('SLACK_CHANNEL_ID')5455 reminder = """56*📅 Week Start Reminders*57581. ⏰ Submit timesheets by Friday 5 PM592. 📝 Update project status in Jira603. 🎯 Review your weekly goals614. 💬 Schedule 1-on-1s with your manager6263Let's make it a great week! 🚀64"""6566 try:67 client.chat_postMessage(68 channel=channel,69 text=reminder70 )71 print(f"Weekly reminder posted at {datetime.now()}")7273 except Exception as e:74 print(f"Error posting weekly reminder: {e}")757677# Schedule jobs78schedule.every().day.at("09:00").do(post_daily_report)79schedule.every().monday.at("08:00").do(post_weekly_reminder)8081# Keep the script running82print("Scheduler started. Press Ctrl+C to stop.")83print(f"Next daily report: {schedule.next_run()}")8485while True:86 schedule.run_pending()87 time.sleep(60) # Check every minute
Run the scheduled bot:
1python scheduled_bot.py
Pro Tip: Run this on a server or cloud VM so it's always active, not just when your computer is on.
Step 7: Monitor Channels and Respond
Create an Event-Driven Bot
For this, you need Socket Mode (easier than webhooks):
1. Enable Socket Mode in Slack App Settings:
- Go to your app settings at api.slack.com/apps
- Navigate to "Socket Mode" → Enable
- Generate an App-Level Token with
connections:writescope - Copy the token (starts with
xapp-)
2. Subscribe to Events:
- Go to "Event Subscriptions" → Enable Events
- Add Bot Events:
message.channels(messages in public channels)message.groups(messages in private channels)message.im(direct messages)app_mention(when bot is mentioned)
3. Update .env:
1SLACK_BOT_TOKEN=xoxb-your-token2SLACK_APP_TOKEN=xapp-your-token3SLACK_CHANNEL_ID=C0123456789
4. Install additional package:
1pip install slack-bolt
5. Create event_bot.py:
1# event_bot.py2import os3import re4from slack_bolt import App5from slack_bolt.adapter.socket_mode import SocketModeHandler6from dotenv import load_dotenv78load_dotenv()910# Initialize app with bot token11app = App(token=os.getenv('SLACK_BOT_TOKEN'))121314@app.event("app_mention")15def handle_app_mention(event, say):16 """17 Respond when someone mentions the bot with @bot18 """19 user = event['user']20 text = event['text'].lower()2122 if 'status' in text:23 say(f"Hi <@{user}>! 👋 I'm online and working perfectly!")2425 elif 'help' in text:26 say(f"<@{user}>, here's what I can do:\n"27 "• `@bot status` - Check if I'm online\n"28 "• `@bot report` - Get the latest team report\n"29 "• `@bot reminder` - Set a reminder")3031 else:32 say(f"Hi <@{user}>! 👋 Not sure what you need. Try `@bot help` for commands.")333435@app.message("urgent")36def respond_to_urgent(message, say):37 """38 Automatically respond when someone says 'urgent' in a channel39 """40 say(f"⚠️ Urgent message detected from <@{message['user']}>!\n"41 f"CC: @channel - Please check the message above.")424344@app.message(re.compile(r"(bug|error|broken|not working)"))45def respond_to_issues(message, say):46 """47 Respond to messages containing bug/error keywords48 """49 say("🐛 Issue detected! Have you:\n"50 "1. Checked the error logs?\n"51 "2. Tried restarting the service?\n"52 "3. Created a ticket in Jira?\n\n"53 "Need help? Tag @dev-team")545556@app.command("/notify")57def handle_notify_command(ack, command, say):58 """59 Handle slash command /notify60 Usage: /notify #channel Your message here61 """62 ack() # Acknowledge command receipt6364 text = command['text']6566 # Parse channel and message67 parts = text.split(' ', 1)68 if len(parts) < 2 or not parts[0].startswith('#'):69 say("Usage: `/notify #channel-name Your message`")70 return7172 channel = parts[0].strip('#')73 message = parts[1]7475 try:76 app.client.chat_postMessage(77 channel=channel,78 text=f"📢 Notification from <@{command['user_id']}>:\n{message}"79 )80 say(f"✅ Notification sent to #{channel}")8182 except Exception as e:83 say(f"❌ Error sending notification: {str(e)}")848586# Start the app87if __name__ == "__main__":88 handler = SocketModeHandler(app, os.getenv('SLACK_APP_TOKEN'))89 print("⚡️ Bot is running!")90 handler.start()
Run the event bot:
1python event_bot.py
Now your bot will:
- Respond to @mentions
- React to keywords like "urgent" or "bug"
- Handle slash commands
Step 8: Handle Interactive Events
To handle button clicks from Step 5:
Add to event_bot.py:
1@app.action("budget_approve")2def handle_budget_approve(ack, body, say):3 ack()4 user = body['user']['id']5 say(f"✅ <@{user}> approved additional budget. Finance team has been notified.")678@app.action("budget_pause")9def handle_budget_pause(ack, body, say):10 ack()11 user = body['user']['id']12 say(f"⚠️ <@{user}> paused marketing campaigns. All active campaigns have been stopped.")131415@app.action("budget_details")16def handle_budget_details(ack, body, say):17 ack()18 say("📊 *Budget Details:*\n"19 "• Total Budget: $50,000\n"20 "• Spent: $42,500 (85%)\n"21 "• Remaining: $7,500\n"22 "• Projected End Date: March 5th\n"23 "• Top Spending Category: Google Ads ($18,000)")
Step 9: Real-World Bot Examples
Example 1: Deployment Notification Bot
1def notify_deployment(version, environment, status, details=""):2 """3 Notify team about code deployments4 """5 color = "good" if status == "success" else "danger"6 emoji = "✅" if status == "success" else "❌"78 message = f"""9*{emoji} Deployment {status.title()}*1011*Version:* {version}12*Environment:* {environment}13*Time:* {datetime.now().strftime('%Y-%m-%d %H:%M:%S')}1415{details if details else 'No additional details.'}16"""1718 send_formatted_message(19 channel=os.getenv('SLACK_CHANNEL_ID'),20 title=f"Deployment {status.title()}",21 message=message,22 color=color23 )242526# Usage (call from your CI/CD pipeline):27notify_deployment(28 version="2.5.0",29 environment="Production",30 status="success",31 details="• API response time improved by 30%\n• Fixed 3 critical bugs\n• Added new analytics dashboard"32)
Example 2: Performance Alert Bot
1def check_website_performance():2 """3 Monitor website performance and alert if slow4 """5 import requests6 import time78 url = "https://yourwebsite.com"9 threshold_seconds = 31011 try:12 start = time.time()13 response = requests.get(url, timeout=10)14 load_time = time.time() - start1516 if load_time > threshold_seconds:17 client.chat_postMessage(18 channel=os.getenv('SLACK_CHANNEL_ID'),19 text=f"⚠️ *Performance Alert*\n\n"20 f"Website load time: {load_time:.2f}s (threshold: {threshold_seconds}s)\n"21 f"Status: {response.status_code}\n"22 f"Time: {datetime.now().strftime('%H:%M:%S')}\n\n"23 f"@dev-team Please investigate."24 )2526 except Exception as e:27 client.chat_postMessage(28 channel=os.getenv('SLACK_CHANNEL_ID'),29 text=f"🚨 *Website Down*\n\nError: {str(e)}\n@dev-team @on-call"30 )313233# Schedule to run every 5 minutes34schedule.every(5).minutes.do(check_website_performance)
Example 3: Meeting Reminder Bot
1def send_meeting_reminder(meeting_name, time, participants, meeting_link=""):2 """3 Send automated meeting reminders4 """5 participant_mentions = " ".join([f"<@{p}>" for p in participants])67 message = f"""8*📅 Meeting Reminder*910*Meeting:* {meeting_name}11*Time:* {time}12*Participants:* {participant_mentions}13{f'*Link:* {meeting_link}' if meeting_link else ''}1415See you there! 👋16"""1718 client.chat_postMessage(19 channel=os.getenv('SLACK_CHANNEL_ID'),20 text=message21 )222324# Schedule meeting reminders25meetings = [26 {27 'name': 'Sprint Planning',28 'time': '10:00 AM',29 'participants': ['U01234ABCD', 'U05678EFGH'],30 'link': 'https://zoom.us/j/123456789'31 }32]3334for meeting in meetings:35 schedule.every().monday.at("09:45").do(36 send_meeting_reminder,37 meeting_name=meeting['name'],38 time=meeting['time'],39 participants=meeting['participants'],40 meeting_link=meeting['link']41 )
Step 10: Deploy Your Bot
Option 1: Keep Running on Your Computer
Pros: Free, simple Cons: Only works when your computer is on
Keep running in background (Linux/Mac):
1nohup python scheduled_bot.py &
Windows (use Task Scheduler): Create a task that runs Python script at startup
Option 2: Deploy to Cloud (Recommended)
Heroku (simple, free tier available):
- Create
requirements.txt:
1pip freeze > requirements.txt
- Create
Procfile:
worker: python scheduled_bot.py
- Deploy:
1heroku create your-slack-bot2git push heroku main3heroku ps:scale worker=1
AWS Lambda (serverless, pay-per-use):
- Good for event-driven bots
- Use AWS EventBridge for scheduling
- Package your code + dependencies
DigitalOcean / AWS EC2 (full control):
- Rent a small Linux VM ($5-10/month)
- Run bot as a systemd service
- Full control and flexibility
Option 3: Docker Container
Create Dockerfile:
1FROM python:3.11-slim23WORKDIR /app45COPY requirements.txt .6RUN pip install --no-cache-dir -r requirements.txt78COPY . .910CMD ["python", "scheduled_bot.py"]
Build and run:
1docker build -t slack-bot .2docker run -d --env-file .env slack-bot
Best Practices & Tips
1. Error Handling
Always wrap Slack API calls in try-except:
1try:2 response = client.chat_postMessage(...)3except SlackApiError as e:4 # Log error5 print(f"Slack API Error: {e.response['error']}")6 # Optionally notify admins7 client.chat_postMessage(8 channel='#bot-errors',9 text=f"Bot error: {e.response['error']}"10 )
2. Rate Limiting
Slack has rate limits (~1 message/second per channel):
1import time23def send_bulk_messages(messages):4 for msg in messages:5 send_message(channel, msg)6 time.sleep(1) # Respect rate limits
3. Logging
Add logging for debugging:
1import logging23logging.basicConfig(4 level=logging.INFO,5 format='%(asctime)s - %(name)s - %(levelname)s - %(message)s',6 handlers=[7 logging.FileHandler('bot.log'),8 logging.StreamHandler()9 ]10)1112logger = logging.getLogger(__name__)1314logger.info("Bot started")15logger.error(f"Failed to send message: {error}")
4. Configuration Management
Use config files for settings:
1# config.py2ALERTS = {3 'critical': {4 'channel': 'C0123456',5 'mentions': ['@oncall', '@devops-lead']6 },7 'warning': {8 'channel': 'C0123456',9 'mentions': []10 }11}1213SCHEDULES = {14 'daily_report': '09:00',15 'weekly_summary': 'monday at 08:00'16}
Troubleshooting
Bot doesn't respond:
- Verify bot token is correct (
xoxb-...) - Check bot has necessary permissions (OAuth scopes)
- Ensure bot is invited to the channel
"Not in channel" error:
- Use
chat:write.publicscope, OR - Manually invite bot to channel:
/invite @YourBot
Socket Mode connection fails:
- Verify App-Level Token is correct (
xapp-...) - Check Socket Mode is enabled in app settings
- Ensure you're using
slack-boltlibrary
Rate limit errors:
- Add delays between messages (
time.sleep(1)) - Batch notifications instead of sending individually
Frequently Asked Questions
Can the bot send direct messages to users?
Yes! Instead of a channel ID, use a user ID:
1client.chat_postMessage(2 channel='U01234ABCD', # User ID3 text='Private message!'4)
How do I get user IDs programmatically?
1def get_user_id_by_email(email):2 try:3 response = client.users_lookupByEmail(email=email)4 return response['user']['id']5 except SlackApiError:6 return None
Can I send files or images?
Yes, use files_upload:
1client.files_upload_v2(2 channel='C0123456',3 file='./report.pdf',4 title='Daily Report'5)
How secure is storing tokens in .env files?
For production, use proper secrets management:
- AWS Secrets Manager
- Azure Key Vault
- Environment variables in cloud platform
- Never commit
.envto version control
Related articles: Python API Automation Tutorial, Automate Email Sending with Python
Sponsored Content
Interested in advertising? Reach automation professionals through our platform.