DEV Community

Cover image for Solved: Automate Twitter/X Posts when a New Blog Post is Published (RSS to API)
Darian Vance
Darian Vance

Posted on • Originally published at wp.me

Solved: Automate Twitter/X Posts when a New Blog Post is Published (RSS to API)

🚀 Executive Summary

TL;DR: This guide provides a custom, serverless-friendly Python solution to automate X/Twitter posts for new blog articles, eliminating manual effort and recurring SaaS costs. It leverages RSS feeds and the X/Twitter API, scheduled via cron, to automatically announce new content.

🎯 Key Takeaways

  • The automation relies on feedparser to parse the blog’s RSS feed and a last\_checked\_timestamp.txt file to track the last published post, preventing duplicate tweets.
  • tweepy is used for X/Twitter API integration, requiring developer credentials (API Key, Secret, Access Token, Secret) stored securely in secrets.txt and ‘Read and Write’ app permissions.
  • The Python script is scheduled using cron (e.g., every 30 minutes) on Unix-like systems, ensuring periodic checks for new posts and automated tweeting, with output redirected to a log file for debugging.

Automate Twitter/X Posts when a New Blog Post is Published (RSS to API)

Introduction

In the fast-paced digital landscape, maintaining a strong online presence is paramount for any content creator or organization. For blog publishers, announcing new articles across social media platforms like X (formerly Twitter) is a critical step in driving traffic and engagement. However, the manual process of crafting a tweet, copying the link, and posting it every time a new article goes live is not only tedious and repetitive but also prone to human error and delays. Imagine the time saved if this process could be fully automated.

While various SaaS solutions offer social media scheduling and automation, they often come with recurring costs, restrictive feature sets, and a lack of granular control. As Senior DevOps Engineers, we understand the value of bespoke solutions that offer flexibility, cost-efficiency, and deep integration. This tutorial will guide you through building a custom, serverless-friendly automation pipeline using Python, your blog’s RSS feed, and the X/Twitter API. By the end, you’ll have a robust system that automatically tweets about your latest blog posts the moment they’re published, giving you full control and eliminating manual effort.

Prerequisites

Before we dive into the automation magic, ensure you have the following components and basic understanding:

  • X/Twitter Developer Account: You will need a developer account to create an application and obtain API keys (Consumer Key, Consumer Secret) and access tokens (Access Token, Access Token Secret). Ensure your app has “Read and Write” permissions.
  • Python 3.x: Installed on your local machine or a server where the script will run. We recommend Python 3.8 or newer.
  • Pip: Python’s package installer, usually bundled with Python 3.x.
  • A Blog with an RSS Feed: The core of our automation relies on detecting new posts via a standard RSS feed. Ensure your blog has one, e.g., https://yourblog.com/feed/.
  • Basic understanding of Python: Familiarity with Python scripting will help you understand and customize the code.
  • Basic understanding of Cron (for scheduling): If you plan to run this on a server.

Step-by-Step Guide

Step 1: Set Up Your X/Twitter Developer Application and Obtain Credentials

The first step is to register your application with the X/Twitter Developer platform and obtain the necessary API credentials. These credentials act as the key to allow your script to interact with the X API on your behalf.

  1. Navigate to the X Developer Portal.
  2. Create a new Project and then a new App within that Project. Give it a descriptive name.
  3. Under your App’s settings, go to the “Keys and Tokens” section.
  4. Generate a Consumer Key (API Key) and Consumer Secret (API Secret). Make sure to save these immediately as the Consumer Secret is only shown once.
  5. Under “Authentication settings”, enable “OAuth 1.0a” and set “App permissions” to “Read and Write”.
  6. Still in “Keys and Tokens”, generate your Access Token and Access Token Secret. These are personal to your account and allow your app to post.
  7. Security Best Practice: Never hardcode these credentials directly into your script. Use environment variables or a dedicated secrets file. For this tutorial, we’ll use a secrets.txt file for simplicity, which you should protect with appropriate file permissions.

Create a file named secrets.txt in your project directory and add your credentials:

API_KEY="YOUR_CONSUMER_KEY"
API_SECRET="YOUR_CONSUMER_SECRET"
ACCESS_TOKEN="YOUR_ACCESS_TOKEN"
ACCESS_TOKEN_SECRET="YOUR_ACCESS_TOKEN_SECRET"
Enter fullscreen mode Exit fullscreen mode

Step 2: Install Python Dependencies and Fetch RSS Feed

Our Python script will require two external libraries: feedparser to effortlessly parse RSS feeds and tweepy to interact with the X/Twitter API. Let’s install them:

pip install feedparser tweepy
Enter fullscreen mode Exit fullscreen mode

Now, let’s create a basic Python script, tweet_blog_post.py, to read your RSS feed. We’ll also introduce a simple mechanism to track the last published post to avoid tweeting old articles repeatedly.

import feedparser
import os
from datetime import datetime, timezone

RSS_FEED_URL = "https://techresolve.com/feed/" # <-- REPLACE WITH YOUR BLOG'S RSS FEED
LAST_CHECKED_FILE = "last_checked_timestamp.txt"

def get_last_checked_timestamp():
    if os.path.exists(LAST_CHECKED_FILE):
        with open(LAST_CHECKED_FILE, "r") as f:
            timestamp_str = f.read().strip()
            if timestamp_str:
                return datetime.fromisoformat(timestamp_str).replace(tzinfo=timezone.utc)
    return datetime.min.replace(tzinfo=timezone.utc)

def set_last_checked_timestamp(timestamp):
    with open(LAST_CHECKED_FILE, "w") as f:
        f.write(timestamp.isoformat())

def fetch_new_posts():
    feed = feedparser.parse(RSS_FEED_URL)
    new_posts = []
    last_checked = get_last_checked_timestamp()
    current_latest_post_timestamp = last_checked

    for entry in feed.entries:
        # Ensure 'published_parsed' exists and convert to datetime object with timezone
        if 'published_parsed' in entry:
            post_date = datetime(*entry.published_parsed[:6], tzinfo=timezone.utc)
            if post_date > last_checked:
                new_posts.append({
                    "title": entry.title,
                    "link": entry.link,
                    "published": post_date
                })
                # Keep track of the latest post found in this run
                if post_date > current_latest_post_timestamp:
                    current_latest_post_timestamp = post_date

    # Sort new posts by publication date to tweet them in order
    new_posts.sort(key=lambda x: x["published"])

    # Update the last checked timestamp if new posts were found
    if new_posts:
        set_last_checked_timestamp(current_latest_post_timestamp)
        print(f"Updated last checked timestamp to: {current_latest_post_timestamp}")

    return new_posts

if __name__ == "__main__":
    print("Fetching new blog posts...")
    posts = fetch_new_posts()
    if posts:
        for post in posts:
            print(f"New Post Found: {post['title']} - {post['link']} - {post['published']}")
    else:
        print("No new posts found since last check.")
Enter fullscreen mode Exit fullscreen mode

This script fetches the RSS feed, compares post publication dates with a stored timestamp in last_checked_timestamp.txt, and identifies truly new posts. The timestamp ensures that once a post is processed, it won’t be re-processed in subsequent runs.

Step 3: Integrate with X/Twitter API and Post Tweets

Now we’ll integrate the tweepy library to send tweets. We’ll modify our script to load credentials from secrets.txt and use them to authenticate with the X API.

import feedparser
import os
from datetime import datetime, timezone
import tweepy # <-- New import

# --- Configuration ---
RSS_FEED_URL = "https://techresolve.com/feed/" # <-- REPLACE WITH YOUR BLOG'S RSS FEED
LAST_CHECKED_FILE = "last_checked_timestamp.txt"
SECRETS_FILE = "secrets.txt" # <-- Path to your secrets file
MAX_TWEET_LENGTH = 280 # X/Twitter tweet character limit

def load_secrets(file_path):
    secrets = {}
    if os.path.exists(file_path):
        with open(file_path, "r") as f:
            for line in f:
                if "=" in line:
                    key, value = line.strip().split("=", 1)
                    secrets[key] = value.strip('"')
    return secrets

def get_last_checked_timestamp():
    if os.path.exists(LAST_CHECKED_FILE):
        with open(LAST_CHECKED_FILE, "r") as f:
            timestamp_str = f.read().strip()
            if timestamp_str:
                return datetime.fromisoformat(timestamp_str).replace(tzinfo=timezone.utc)
    return datetime.min.replace(tzinfo=timezone.utc)

def set_last_checked_timestamp(timestamp):
    with open(LAST_CHECKED_FILE, "w") as f:
        f.write(timestamp.isoformat())

def fetch_new_posts():
    feed = feedparser.parse(RSS_FEED_URL)
    new_posts = []
    last_checked = get_last_checked_timestamp()
    current_latest_post_timestamp = last_checked # Track the latest post in this run

    for entry in feed.entries:
        if 'published_parsed' in entry:
            post_date = datetime(*entry.published_parsed[:6], tzinfo=timezone.utc)
            if post_date > last_checked:
                new_posts.append({
                    "title": entry.title,
                    "link": entry.link,
                    "published": post_date
                })
                if post_date > current_latest_post_timestamp:
                    current_latest_post_timestamp = post_date

    new_posts.sort(key=lambda x: x["published"])

    if new_posts:
        set_last_checked_timestamp(current_latest_post_timestamp)
        print(f"Updated last checked timestamp to: {current_latest_post_timestamp}")

    return new_posts

def post_tweet(api, tweet_text):
    try:
        api.update_status(tweet_text)
        print(f"Successfully tweeted: {tweet_text}")
    except tweepy.TweepyException as e:
        print(f"Error posting tweet: {e}")

if __name__ == "__main__":
    print("Loading secrets...")
    secrets = load_secrets(SECRETS_FILE)

    API_KEY = secrets.get("API_KEY")
    API_SECRET = secrets.get("API_SECRET")
    ACCESS_TOKEN = secrets.get("ACCESS_TOKEN")
    ACCESS_TOKEN_SECRET = secrets.get("ACCESS_TOKEN_SECRET")

    if not all([API_KEY, API_SECRET, ACCESS_TOKEN, ACCESS_TOKEN_SECRET]):
        print("Error: Missing one or more X/Twitter API credentials in secrets.txt")
        exit(1)

    # Authenticate with X/Twitter API
    auth = tweepy.OAuth1UserHandler(API_KEY, API_SECRET, ACCESS_TOKEN, ACCESS_TOKEN_SECRET)
    api = tweepy.API(auth)

    print("Fetching new blog posts...")
    posts = fetch_new_posts()

    if posts:
        for post in posts:
            title = post['title']
            link = post['link']
            # Craft the tweet. X/Twitter will automatically shorten URLs.
            # You might want to add hashtags dynamically or hardcode them.
            tweet_template = "New blog post published: \"{title}\" Read it here: {link} #TechResolve #DevOps #Automation"
            tweet_text = tweet_template.format(title=title, link=link)

            # Basic length check - X/Twitter's API handles actual link shortening for character count
            if len(tweet_text) > MAX_TWEET_LENGTH:
                # Truncate title if tweet is too long
                available_length_for_title = MAX_TWEET_LENGTH - (len(tweet_template) - len("{title}") + len(title) - len(link) + 23) # 23 for short_url length
                if available_length_for_title < len(title):
                    title = title[:available_length_for_title-3] + "..."
                tweet_text = tweet_template.format(title=title, link=link)


            print(f"Attempting to tweet: {tweet_text}")
            post_tweet(api, tweet_text)
    else:
        print("No new posts found to tweet.")
Enter fullscreen mode Exit fullscreen mode

This enhanced script now reads your API credentials, initializes the tweepy API client, fetches new blog posts, formats a tweet, and sends it out. It also includes a basic length check for the tweet content, although X’s API handles URL shortening which affects the final character count.

Step 4: Schedule the Automation with Cron

To make this a truly “set it and forget it” solution, you’ll need to schedule your Python script to run periodically. Cron is a time-based job scheduler in Unix-like operating systems and is perfect for this task.

  1. First, ensure your Python script is executable.
chmod +x /home/user/your_script_directory/tweet_blog_post.py
Enter fullscreen mode Exit fullscreen mode
  1. Edit your user’s crontab:
crontab -e
Enter fullscreen mode Exit fullscreen mode
  1. Add a line to run your script every, for example, 30 minutes. Replace /usr/bin/python3 with the actual path to your Python 3 interpreter and /home/user/your_script_directory/ with the actual path to your script.
*/30 * * * * /usr/bin/python3 /home/user/your_script_directory/tweet_blog_post.py >> /tmp/logs/tweet_automation.log 2>&1
Enter fullscreen mode Exit fullscreen mode

This cron entry will run the tweet_blog_post.py script every 30 minutes. All standard output and errors will be appended to /tmp/logs/tweet_automation.log, which is crucial for debugging.

Make sure the last_checked_timestamp.txt and secrets.txt files are in the same directory as your Python script, or adjust the paths in the script accordingly.

Common Pitfalls

While this automation is powerful, you might encounter a few common issues:

  • X/Twitter API Rate Limits: The X API has rate limits on how many requests your application can make within a certain timeframe. If you have a very active RSS feed or run the script too frequently, you might hit these limits. Always refer to the X Developer Documentation for current limits. For most blogs, checking every 30 minutes should be well within limits.
  • Authentication Errors: Incorrect API keys, expired access tokens, or insufficient app permissions (“Read and Write” is crucial) can lead to authentication failures. Double-check all credentials in your secrets.txt file and verify your app’s permissions in the X Developer Portal.
  • RSS Feed Malformation or Downtime: If your blog’s RSS feed is temporarily unavailable or malformed, feedparser might fail to parse it. Implement robust error handling (e.g., try-except blocks) and logging to catch these issues. Ensure your blog’s RSS feed is regularly updated and accessible.
  • Duplicate Posts (without last_checked_timestamp.txt): If you remove or corrupt the last_checked_timestamp.txt file, the script might re-tweet old posts. Always ensure this file persists and is correctly updated after each run.

Conclusion

You’ve successfully built a custom, automated solution to broadcast your new blog posts on X/Twitter. By leveraging the power of Python, RSS feeds, and the X API, you’ve eliminated a repetitive manual task, gained full control over your social media announcements, and reduced reliance on third-party services. This setup is not only cost-effective but also provides the flexibility to evolve with your specific needs.

This foundation opens doors for further enhancements. Consider adding more sophisticated error logging, integrating image attachments with your tweets, or even expanding this automation to other social media platforms like LinkedIn or Mastodon. For a more production-ready setup, you could containerize this application using Docker and deploy it to a cloud service, ensuring higher availability and scalability. The journey of automation is continuous, and you’ve just taken a significant step forward in making your content dissemination more efficient.


Darian Vance

👉 Read the original article on TechResolve.blog


☕ Support my work

If this article helped you, you can buy me a coffee:

👉 https://buymeacoffee.com/darianvance

Top comments (0)