Created
July 14, 2025 08:46
-
-
Save maguay/9d83d1ef714cb6f828c29b3e255a5e15 to your computer and use it in GitHub Desktop.
Buttondown | Slack Top Threads to Email script
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| # A Bash script to pull the three most popular Slack threads from the last week and merge them with an email template. | |
| # Copy everything from line 7 on, add in your Slack token, channel ID, workspace URL, and Buttondown API key, then run in Terminal. | |
| # See https://buttondown.com/blog/api-powered-email-newsletter for more details. | |
| ----- | |
| #!/bin/bash | |
| SLACK_TOKEN="your-Slack-bot-token" | |
| CHANNEL_ID="your_channel_ID" | |
| WORKSPACE_URL="https://yourworkspace.slack.com" | |
| EMAIL_TEMPLATE="email_template.txt" | |
| BUTTONDOWN_API_TOKEN="buttondown_API_key" | |
| seven_days_ago=$(date -v-7d +%s) | |
| thread_data=$(curl -s -H "Authorization: Bearer $SLACK_TOKEN" \ | |
| "https://slack.com/api/conversations.history?channel=$CHANNEL_ID&limit=200" \ | |
| | jq -r --arg seven_days_ago "$seven_days_ago" '.messages[] | select(.thread_ts != null and .thread_ts == .ts and (.ts | tonumber) >= ($seven_days_ago | tonumber)) | "\(.ts)|\(.user)|\(.text)|\(.reply_count // 0)"' \ | |
| | sort -t'|' -k4,4nr \ | |
| | head -3) | |
| thread_num=0 | |
| while IFS='|' read -r thread_ts user_id text reply_count; do | |
| thread_num=$((thread_num + 1)) | |
| user_info=$(curl -s -H "Authorization: Bearer $SLACK_TOKEN" \ | |
| "https://slack.com/api/users.info?user=$user_id") | |
| username=$(echo "$user_info" | jq -r '.user.name') | |
| real_name=$(echo "$user_info" | jq -r '.user.real_name') | |
| timestamp=$(echo "$thread_ts" | cut -d'.' -f1) | |
| formatted_date=$(date -r "$timestamp" "+%A, %B %d, %l:%M%p" | sed 's/ / /g' | sed 's/AM/am/g' | sed 's/PM/pm/g') | |
| links=$(echo "$text" | grep -oE 'https?://[^>|[:space:]]+' | tr '\n' ' ') | |
| thread_link="$WORKSPACE_URL/archives/$CHANNEL_ID/p$(echo "$thread_ts" | tr -d '.')" | |
| reply_data=$(curl -s -H "Authorization: Bearer $SLACK_TOKEN" \ | |
| "https://slack.com/api/conversations.replies?channel=$CHANNEL_ID&ts=$thread_ts" \ | |
| | jq -r '.messages[1:] | map(. + {reaction_count: ((.reactions // []) | map(.count) | add // 0)}) | sort_by(.reaction_count) | reverse | .[0:3] | .[] | "\(.user)|\(.text)"') | |
| reply_count=1 | |
| while IFS='|' read -r reply_user reply_text; do | |
| if [[ -n "$reply_user" && -n "$reply_text" ]]; then | |
| reply_user_info=$(curl -s -H "Authorization: Bearer $SLACK_TOKEN" \ | |
| "https://slack.com/api/users.info?user=$reply_user") | |
| reply_username=$(echo "$reply_user_info" | jq -r '.user.name') | |
| eval "THREAD_${thread_num}_TOP_REPLY_${reply_count}=\"@$reply_username: $reply_text\"" | |
| ((reply_count++)) | |
| fi | |
| done <<< "$reply_data" | |
| while [[ $reply_count -le 3 ]]; do | |
| eval "THREAD_${thread_num}_TOP_REPLY_${reply_count}=\"\"" | |
| ((reply_count++)) | |
| done | |
| eval "THREAD_${thread_num}_USERNAME=\"$username\"" | |
| eval "THREAD_${thread_num}_REAL_NAME=\"$real_name\"" | |
| eval "THREAD_${thread_num}_DATE_TIME=\"$formatted_date\"" | |
| eval "THREAD_${thread_num}_TEXT=\"$text\"" | |
| eval "THREAD_${thread_num}_LINKS=\"$links\"" | |
| eval "THREAD_${thread_num}_LINK=\"$thread_link\"" | |
| done <<< "$thread_data" | |
| for i in 1 2 3; do | |
| if eval "[[ -n \"\$THREAD_${i}_USERNAME\" ]]"; then | |
| eval "export THREAD_${i}_USERNAME=\"\$THREAD_${i}_USERNAME\"" | |
| eval "export THREAD_${i}_REAL_NAME=\"\$THREAD_${i}_REAL_NAME\"" | |
| eval "export THREAD_${i}_DATE_TIME=\"\$THREAD_${i}_DATE_TIME\"" | |
| eval "export THREAD_${i}_TEXT=\"\$THREAD_${i}_TEXT\"" | |
| eval "export THREAD_${i}_LINKS=\"\$THREAD_${i}_LINKS\"" | |
| eval "export THREAD_${i}_LINK=\"\$THREAD_${i}_LINK\"" | |
| eval "export THREAD_${i}_TOP_REPLY_1=\"\$THREAD_${i}_TOP_REPLY_1\"" | |
| eval "export THREAD_${i}_TOP_REPLY_2=\"\$THREAD_${i}_TOP_REPLY_2\"" | |
| eval "export THREAD_${i}_TOP_REPLY_3=\"\$THREAD_${i}_TOP_REPLY_3\"" | |
| else | |
| eval "export THREAD_${i}_USERNAME=\"\"" | |
| eval "export THREAD_${i}_REAL_NAME=\"\"" | |
| eval "export THREAD_${i}_DATE_TIME=\"\"" | |
| eval "export THREAD_${i}_TEXT=\"\"" | |
| eval "export THREAD_${i}_LINKS=\"\"" | |
| eval "export THREAD_${i}_LINK=\"\"" | |
| eval "export THREAD_${i}_TOP_REPLY_1=\"\"" | |
| eval "export THREAD_${i}_TOP_REPLY_2=\"\"" | |
| eval "export THREAD_${i}_TOP_REPLY_3=\"\"" | |
| fi | |
| done | |
| if [[ -f "$EMAIL_TEMPLATE" ]]; then | |
| content=$(cat "$EMAIL_TEMPLATE") | |
| content=$(echo "$content" | envsubst) | |
| subject=$(echo "$content" | grep -m 1 '^# ' | sed 's/^# //') | |
| body=$(echo "$content" | sed -n '/^# /,$p' | tail -n +2) | |
| curl -X POST \ | |
| "https://api.buttondown.com/v1/emails" \ | |
| -H "Authorization: Token $BUTTONDOWN_API_TOKEN" \ | |
| -H "Content-Type: application/json" \ | |
| -d "$(jq -n --arg subject "$subject" --arg body "$body" '{subject: $subject, body: $body, status: "draft"}')" | |
| fi |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment