Law firms lose an average of 30 minutes per attorney each day sifting through scattered news feeds, and that time adds up to lost billable hours. ## 1. Pull the Source Content with RSS and curl
The first step is to gather raw headlines from trusted legal‑tech outlets. Most industry sites expose an RSS feed; for example, Law.com, LegalTech News, and the ABA Journal.
# Download three RSS feeds in parallel and store them in ./feeds mkdir -p feeds curl -s https://www.law.com/rss/technology/ -o feeds/lawcom.xml & curl -s https://www.legaltechnews.com/rss/ -o feeds/ltnews.xml & curl -s https://www.americanbar.org/rss/technology/ -o feeds/abajournal.xml & wait
python
The command runs three curl processes simultaneously, ensuring the fetch finishes in under a second on a typical office connection. Takeaway: Set up a cron job that runs the snippet above each morning; the raw XML files will be the foundation for the AI prompt. ## 2. Clean and Summarize with Python + OpenAI
Next, strip the XML down to title, link, and description, then feed each item to a language model for a one‑sentence summary. The following script uses feedparser and the openai package.
import feedparser, os, json, openai def load_feeds(path='feeds'): items = [] for file in os.listdir(path): feed = feedparser.parse(os.path.join(path, file)) items.extend(feed.entries[:5]) # limit to top 5 per source return items openai.api_key = os.getenv('OPENAI_API_KEY') prompt_template = ( "Summarize the following legal‑tech news article in one concise sentence.\n" "Title: {title}\n" "Description: {desc}\n" "Summary:" ) def summarize(item): prompt = prompt_template.format(title=item.title, desc=item.summary) resp = openai.ChatCompletion.create( model='gpt-4o-mini', messages=[{'role':'user','content':prompt}], max_tokens=60, temperature=0.2) return resp.choices[0].message.content.strip() if __name__ == '__main__': entries = load_feeds() digest = [] for e in entries: summary = summarize(e) digest.append({ 'title': e.title, 'link': e.link, 'summary': summary }) # Save for email step with open('digest.json','w') as f: json.dump(digest, f, indent=2) The script pulls up to 15 items, asks the model to condense each to a single line, and writes a JSON array ready for distribution. Takeaway: Run the Python file after the RSS fetch; the output digest.json is a deterministic, reproducible data set you can hand off to any mailer. ## 3. Format and Send via Mailgun (or any SMTP)
Lawyers prefer email over Slack for daily briefings. The snippet below formats the JSON into an HTML table and posts it to Mailgun's API.
import json, requests, os def build_html(digest): rows = '' for item in digest: rows += f"<tr><td><a href='{item['link']}'>{item['title']}</a></td><td>{item['summary']}</td></tr>" return f""" <html><body> <h2>Daily Legal‑Tech Digest – {os.getenv('TODAY')}</h2> <table border='1' cellpadding='5' cellspacing='0'> <tr><th>Article</th><th>One‑Sentence Summary</th></tr> {rows} </table> </body></html> """ with open('digest.json') as f: digest = json.load(f) html_body = build_html(digest) response = requests.post( f"https://api.mailgun.net/v3/{os.getenv('MG_DOMAIN')}/messages", auth=('api', os.getenv('MG_API_KEY')), data={ 'from': f"Legal‑Tech Bot <news@{os.getenv('MG_DOMAIN')}>", 'to': os.getenv('RECIPIENTS').split(','), 'subject': f"Legal‑Tech News for {os.getenv('TODAY')}", 'html': html_body }) print('Mailgun status:', response.status_code)
systemd
Replace environment variables with real values and store the script as send_digest.py. When executed, every subscriber receives a tidy, one‑click read. Takeaway: Hook send_digest.py to the same daily cron schedule; the whole pipeline runs from 6 am to inbox without human intervention. ## 4. Deploy the Pipeline on a Low‑Cost VPS
A single‑core droplet on DigitalOcean costs $5/month and provides enough CPU to run the fetch‑summarize‑mail cycle in under 30 seconds. Create a systemd service that starts the three steps sequentially.
[Unit] Description=Daily Legal‑Tech Digest After=network.target [Service] Type=oneshot EnvironmentFile=/etc/digest.env ExecStart=/usr/bin/bash -c "\ /usr/local/bin/fetch_feeds.sh && \ /usr/bin/python3 /opt/digest/summarize.py && \ /usr/bin/python3 /opt/digest/send_digest.py\" [Install] WantedBy=multi-user.target Enable it with systemctl enable --now digest.service and set a cron entry like 0 6 * * * /bin/systemctl start digest.service. The service logs to journalctl -u digest, giving you visibility into failures. Takeaway: A $5 VPS plus free OpenAI credits for testing covers the entire stack; scale only if you add hundreds of recipients. ## 5. Iterate with Feedback Loops
The first version will include articles irrelevant to your practice area. Capture click data from Mailgun's tracking URLs and feed it back into the selection logic. For example, keep a CSV of article IDs and click counts, then adjust the load_feeds function to prioritize sources with higher engagement.
import csv def load_engagement(path='clicks.csv'): scores = {} with open(path) as f: for row in csv.DictReader(f): scores[row['link']] = int(row['clicks']) return scores engagement = load_engagement() # later, when building the digest, sort by engagement.get(item.link, 0) descending A simple ranking algorithm reduces noise and makes the digest more valuable over time. Takeaway: Implement a basic click‑tracking loop within two weeks; the data will immediately improve relevance. Start by creating the three scripts (fetch_feeds.sh, summarize.py, send_digest.py) and schedule them on a cheap VPS. By the end of the day you will have a fully automated, AI‑enhanced daily briefing that saves each lawyer at least 20 minutes of reading time. Action: Sign up for a free OpenAI trial, spin up a $5 DigitalOcean droplet, and run the fetch_feeds.sh command tonight to lay the groundwork for tomorrow's first digest.
If this was useful: I packaged a deeper version as Local SEO Audit Prompt Pack for 30‑Minute Walk Radius.
This article was drafted with AI assistance.


