Skill: brianlu365ai/x-to-kindle (version 0.1.1)

--- name: x-to-kindle description: Send X/Twitter posts to Kindle for distraction-free reading. Use when user shares an X/Twitter link and wants to read it on Kindle, or asks to send a tweet/thread to their Kindle device. --- # X to Kindle Convert X/Twitter posts into Kindle-readable documents via email. ## Requirements - Gmail account with App Password (or other SMTP setup) - Kindle email address (found in Amazon account settings) ## Workflow When user shares an X link: 1. **Extract content** via fxtwitter API: ``` https://api.fxtwitter.com/status/<tweet_id> ``` Extract from URL: `twitter.com/*/status/<id>` or `x.com/*/status/<id>` 2. **Format as HTML file** (save to /tmp): ```html <!DOCTYPE html> <html> <head><meta charset="UTF-8"><title>{title}</title></head> <body style="font-family: Georgia, serif; max-width: 600px; margin: 0 auto; padding: 20px; line-height: 1.6;"> <h1>@{author_handle}</h1> <p>{tweet_text}</p> <p><em>{timestamp}</em></p> <p><a href="{original_url}">View on X</a></p> </body> </html> ``` 3. **Send via SMTP with HTML as ATTACHMENT** (Kindle requires attachment, not inline HTML): ```python from email.mime.multipart import MIMEMultipart from email.mime.text import MIMEText from email.mime.base import MIMEBase from email import encoders msg = MIMEMultipart() msg['Subject'] = "Tweet from @handle" msg['From'] = from_email msg['To'] = kindle_email # Plain text body (not the content) msg.attach(MIMEText("Article attached.", 'plain')) # HTML file as attachment - THIS IS REQUIRED with open("/tmp/article.html", "rb") as f: attachment = MIMEBase('text', 'html') attachment.set_payload(f.read()) encoders.encode_base64(attachment) attachment.add_header('Content-Disposition', 'attachment', filename='article.html') msg.attach(attachment) ``` ## Tools - `send_to_kindle`: Send a local file to the configured Kindle email. ## Configuration Set the following environment variables in your Clawdbot configuration (or `.env` file): - `SMTP_EMAIL`: Your sender email (e.g., gmail) - `SMTP_PASSWORD`: Your app password - `KINDLE_EMAIL`: Your Kindle email address - `SMTP_SERVER`: (Optional) Default: smtp.gmail.com - `SMTP_PORT`: (Optional) Default: 587 ## Tool Definitions ### send_to_kindle Send a local file (PDF, HTML, TXT) to the Kindle. - **Run:** `python3 skills/x-to-kindle/send_to_kindle.py <file_path>` ## Configuration Store in TOOLS.md: ```markdown ## Kindle - Address: [REDACTED_SECRET] ## Email (Gmail SMTP) - From: [REDACTED_SECRET] - App Password: xxxx xxxx xxxx xxxx - Host: smtp.gmail.com - Port: 587 ``` ## Example User sends: `https://x.com/elonmusk/status/1234567890` 1. Fetch `https://api.fxtwitter.com/status/1234567890` 2. Extract author, text, timestamp 3. Send HTML email to Kindle address 4. Confirm: "Sent to Kindle 📚"

path: package.json
content: {
  "name": "x-to-kindle",
  "version": "0.1.1",
  "description": "Send X/Twitter posts or local files to Kindle",
  "main": "SKILL.md",
  "files": [
    "SKILL.md",
    "send_to_kindle.py"
  ],
  "author": "Brian Lu",
  "license": "ISC"
}


path: send_to_kindle.py
content: import smtplib
import sys
import os
from email.mime.multipart import MIMEMultipart
from email.mime.text import MIMEText
from email.mime.base import MIMEBase
from email import encoders

# Config - Load from environment variables for security
SMTP_EMAIL = os.environ.get("SMTP_EMAIL")
SMTP_PASSWORD = os.environ.get("SMTP_PASSWORD")
SMTP_SERVER = os.environ.get("SMTP_SERVER", "smtp.gmail.com")
SMTP_PORT = int(os.environ.get("SMTP_PORT", 587))
# Kindle email can be passed as arg or env var, default to env
DEFAULT_KINDLE_EMAIL = os.environ.get("KINDLE_EMAIL")

if not SMTP_EMAIL or not SMTP_PASSWORD:
    print("ERROR: Missing credentials. Please set SMTP_EMAIL and SMTP_PASSWORD environment variables.")
    sys.exit(1)

if len(sys.argv) < 2:
    print("Usage: python3 send_to_kindle.py <file_path> [optional_filename]")
    sys.exit(1)

file_path = sys.argv[1]

# Use optional filename if provided, otherwise use basename
if len(sys.argv) >= 3:
    filename = sys.argv[2]
else:
    filename = os.path.basename(file_path)

# Determine recipient
to_email = DEFAULT_KINDLE_EMAIL
if not to_email:
    print("ERROR: No Kindle email configured. Set KINDLE_EMAIL env var.")
    sys.exit(1)

msg = MIMEMultipart()
msg['From'] = SMTP_EMAIL
msg['To'] = to_email
msg['Subject'] = f"Doc: {filename}"

msg.attach(MIMEText("Document attached.", 'plain'))

try:
    with open(file_path, "rb") as f:
        attachment = MIMEBase('application', 'octet-stream')
        attachment.set_payload(f.read())
        encoders.encode_base64(attachment)
        attachment.add_header('Content-Disposition', 'attachment', filename=filename)
        msg.attach(attachment)

    server = smtplib.SMTP(SMTP_SERVER, SMTP_PORT)
    server.starttls()
    server.login(SMTP_EMAIL, SMTP_PASSWORD)
    text = msg.as_string()
    server.sendmail(SMTP_EMAIL, to_email, text)
    server.quit()
    print(f"SUCCESS: Sent {filename} to {to_email}")

except Exception as e:
    print(f"ERROR: {e}")
    sys.exit(1)


Security scan verdicts — ClawScan: suspicious | static analysis: clean | VirusTotal: suspicious | SkillSpector: suspicious (CRITICAL)