Zapier is brilliant but expensive. $50-100/month for automations that Python handles in 50 lines of code. Here's how to cut that bill to zero.
What Zapier Actually Does
Zapier connects apps through triggers and actions:
- "When I get an email with attachment → save to Google Drive"
- "When form submitted → add row to Google Sheet + send Slack notification"
- "Every day at 9am → pull data from API → send report email"
Python can do every one of these. The difference: you own the code and run it for free.
The Core Pattern: Webhooks + HTTP Requests
Most Zapier automations boil down to:
- Receive a trigger (webhook, time, email, API poll)
- Transform the data
- Send it somewhere
import httpx
from flask import Flask, request, jsonify
import json
app = Flask(__name__)
@app.route('/webhook', methods=['POST'])
def handle_webhook():
data = request.json
print(f"Received: {json.dumps(data, indent=2)}")
# Transform the data
processed = transform_data(data)
# Send somewhere
result = forward_to_slack(processed)
return jsonify({"status": "ok", "forwarded": result})
def transform_data(data: dict) -> dict:
# Your business logic here
return {
"text": f"New submission: {data.get('name', 'Unknown')}",
"details": data.get('message', '')
}
def forward_to_slack(data: dict) -> bool:
webhook_url = "https://hooks.slack.com/services/YOUR/WEBHOOK/URL"
r = httpx.post(webhook_url, json={"text": data['text']})
return r.status_code == 200
Email → Google Sheets (Classic Zapier Workflow)
import imaplib
import email
import gspread
from google.oauth2.service_account import Credentials
from datetime import datetime
import re
def check_emails_and_log():
# Connect to Gmail
mail = imaplib.IMAP4_SSL('imap.gmail.com')
mail.login('you@gmail.com', 'your-app-password')
mail.select('INBOX')
# Search for unread emails from specific sender
_, messages = mail.search(None, 'UNSEEN FROM "orders@shop.com"')
# Connect to Google Sheets
creds = Credentials.from_service_account_file('service_account.json',
scopes=['https://spreadsheets.google.com/feeds'])
gc = gspread.authorize(creds)
sheet = gc.open('Order Log').sheet1
for msg_id in messages[0].split():
_, msg_data = mail.fetch(msg_id, '(RFC822)')
msg = email.message_from_bytes(msg_data[0][1])
subject = msg['subject']
sender = msg['from']
date = msg['date']
body = get_body(msg)
# Extract order number from subject (adjust regex for your format)
order_match = re.search(r'Order #(\d+)', subject)
order_num = order_match.group(1) if order_match else 'unknown'
# Append to sheet
sheet.append_row([
datetime.now().strftime('%Y-%m-%d %H:%M'),
order_num,
sender,
subject,
body[:200] # First 200 chars of body
])
print(f"Logged order {order_num}")
# Mark as read
mail.store(msg_id, '+FLAGS', '\\Seen')
mail.logout()
def get_body(msg) -> str:
if msg.is_multipart():
for part in msg.walk():
if part.get_content_type() == "text/plain":
return part.get_payload(decode=True).decode()
return msg.get_payload(decode=True).decode()
Timed Automations (Replacing Zapier Schedules)
import schedule
import time
import httpx
from datetime import datetime
def daily_report():
"""Pull data from your API and email a report."""
# Get today's data
r = httpx.get('https://your-api.com/stats/today',
headers={'Authorization': 'Bearer YOUR_TOKEN'})
data = r.json()
# Format report
report = f"""
Daily Report - {datetime.now().strftime('%Y-%m-%d')}
Revenue: ${data['revenue']:.2f}
New signups: {data['signups']}
Active users: {data['active_users']}
"""
# Send email
send_email("Daily Report", report, "you@company.com")
print("Daily report sent!")
def weekly_cleanup():
"""Archive old records, free up space."""
print("Running weekly cleanup...")
# Your cleanup logic here
# Schedule tasks
schedule.every().day.at("09:00").do(daily_report)
schedule.every().monday.at("08:00").do(weekly_cleanup)
print("Scheduler running...")
while True:
schedule.run_pending()
time.sleep(60)
Form Submission → Multiple Destinations
Replace the "$20/month Zapier plan" for form routing:
from flask import Flask, request, jsonify
import httpx, smtplib
from email.mime.text import MIMEText
app = Flask(__name__)
@app.route('/contact', methods=['POST'])
def handle_contact():
data = request.json or request.form.to_dict()
name = data.get('name')
email = data.get('email')
message = data.get('message')
results = {}
# 1. Send confirmation email to user
send_confirmation_email(email, name)
results['confirmation_email'] = True
# 2. Notify you via Slack
notify_slack(name, email, message)
results['slack'] = True
# 3. Add to your CRM (e.g., Airtable)
add_to_crm(name, email, message)
results['crm'] = True
# 4. Log to Google Sheet
log_to_sheet(name, email, message)
results['sheet'] = True
return jsonify({"success": True, "results": results})
def notify_slack(name, email, message):
slack_webhook = "https://hooks.slack.com/services/YOUR/WEBHOOK"
httpx.post(slack_webhook, json={
"text": f"📬 New contact from {name} ({email}):\n{message[:200]}"
})
def add_to_crm(name, email, message):
# Airtable example
httpx.post(
'https://api.airtable.com/v0/YOUR_BASE_ID/Contacts',
headers={'Authorization': 'Bearer YOUR_KEY'},
json={'fields': {'Name': name, 'Email': email, 'Notes': message}}
)
The Math on Zapier vs Python
| Zapier | Python | |
|---|---|---|
| Monthly cost | $20-100 | $0 |
| Task limits | 750-50k/month | Unlimited |
| Custom logic | Limited | Full code |
| Debugging | Black box | Full logs |
| Setup time | 10 minutes | 30-60 minutes |
For less than 1 hour of setup, you eliminate a $50-100/month subscription permanently.
Running It for Free
Run your automation scripts on:
- Your own server (even a Raspberry Pi)
- Oracle Free Tier (always-free VMs)
- GitHub Actions (free for public repos, 2000 min/month private)
- PythonAnywhere free tier (for simple scripts)
Already built and packaged: The Python Business Automation Toolkit includes pre-built scripts for email automation, scheduling, form processing, and more — all configured and ready to customize for your business.
→ Get the toolkit for $29 — includes email-to-sheet automation, Slack notifications, scheduled reports, and invoice processing.
Top comments (0)