Fork me on GitHub Fork me on GitHub

uninformativ.de

GNU, Linux, Shell und Co.

Feed-To-E-Mail auf Basis von Newsbeuter

Pingu-Avatar

02.06.2012, 19:19:31

Als ich noch hauptsächlich an einem Rechner unterwegs war, habe ich Newsbeuter benutzt, um Feeds zu lesen. Das hat (fast) immer wunderbar funktioniert. Der größte Haken an dem Programm ist, dass es etwas ungemütlich wird, wenn man häufig den Rechner wechselt, was heute bei mir der Fall ist. Dann sind hier die Feeds schon als gelesen markiert, drüben aber noch nicht, am dritten Rechner wurde noch gar kein Refresh gemacht und so weiter.

Aus diesem Grund hatte ich mir vor langer Zeit ein Python-Skript unter Verwendung von feedparser geschrieben, um meine Feeds zu beobachten. Existierende Lösungen wie rss2email hatten mir damals nicht so zugesagt. Neue Items hat es mir per E-Mail zugeschickt, denn für E-Mails habe ich die notwendige Infrastruktur, um sie komfortabel auf mehreren Rechnern synchron zu halten. Außerdem hat dieser Ansatz den zusätzlichen Vorteil, dass ich auf den Clients kein extra Programm für Feeds mehr brauche: Es landet einfach alles in Mutt. Von der Feed-To-E-Mail-Methode will ich auch nicht mehr weg, denn das hat sich bewährt. Schließlich benutze ich E-Mails für alles mögliche (Geburtstagserinnerung, TODO-Reminder, allgemeine Notifications, …), da fügt sich das einfach sehr gut ein. Deswegen will auch nicht soetwas wie Tiny Tiny RSS verwenden (was auch gar nicht so „tiny“ ist, wie ich finde).

Eigentlich lief mein Skript ziemlich lange fehlerlos. Ich musste „lediglich“ von Zeit zu Zeit einen weiteren Sonderfall berücksichtigen oder noch einen Workaround für einen kaputten Feed einbauen. Vorhin ist dann wieder soetwas passiert: Bei zwei neuen Feeds hat sich das Skript am Encoding verschluckt. Selbstverständlich sind die Feeds nicht valide und werden auch vom W3C-Validator bemängelt, aber das hilft mir nunmal nicht weiter.

Das hat mich schon deutlich genervt. Ich hatte eigentlich keine Lust, das zu fixen. Schon gar nicht, wenn ich weiß, dass es andere Programme gibt – zum Beispiel Newsbeuter –, die für all diese Sonderfälle bereits gewappnet sind. Ich hatte also die Wahl: Entweder ich baue mein Skript ein weiteres Mal aus, bis es irgendwann die Komplexität von Newsbeuter erreicht, oder ich gehe zurück zu Newsbeuter. Von dem weiß ich, dass er funktioniert. Irgendwas musste ich mir nur noch überlegen, um nicht die schöne Feed-To-E-Mail-Funktionalität zu verlieren.

Der neue Ansatz sieht jetzt so aus, dass Newsbeuter bei mir auf dem Server die Feeds überwacht. Interaktiv starte ich das Programm aber nie. Stattdessen habe ich folgendes kleines Skript drumherum gebaut, was einmal pro Stunde von Cron aufgerufen wird:

#!/bin/bash

myfeedfrom='blabla@domain.tld'
myfeedto='blublu@domain.tld'
urls="$HOME"/.newsbeuter/urls
config="$HOME"/.newsbeuter/config
db="$HOME"/.newsbeuter/cache.db

[[ -f ~/.newsbeuter/to-mail.rc ]] && . ~/.newsbeuter/to-mail.rc

newsbeuter -u "$urls" -c "$db" -C "$config" -x reload

markread=no
for i in $(sqlite3 "$db" 'SELECT id FROM rss_item WHERE unread = "1";')
do
	title=$(sqlite3 "$db" "SELECT title FROM rss_item WHERE id = \"$i\";")
	content=$(sqlite3 "$db" "SELECT content FROM rss_item WHERE id = \"$i\";")
	itemurl=$(sqlite3 "$db" "SELECT url FROM rss_item WHERE id = \"$i\";")
	enclurl=$(sqlite3 "$db" "SELECT enclosure_url FROM rss_item WHERE id = \"$i\";")
	feedurl=$(sqlite3 "$db" "SELECT feedurl FROM rss_item WHERE id = \"$i\";")
	feedtitle=$(sqlite3 "$db" "SELECT rss_feed.title
		FROM rss_item
		LEFT OUTER JOIN rss_feed ON rss_item.feedurl = rss_feed.rssurl
		WHERE rss_item.id = \"$i\";" | sed 's/[^[:alnum:]]/ /g')

	{
		echo "* $itemurl"
		[[ -n "$enclurl" ]] && echo "* $enclurl"
		echo
		echo "$content" | elinks -dump -dump-width 72 -dump-charset utf-8 \
			-force-html -localhost 1 -no-connect 1 -no-home 1
		echo
		echo '--'
		echo "$feedurl"
	} | mail -r "$feedtitle <$myfeedfrom>" -s "$title" "$myfeedto"

	markread=yes
done

if [[ "$markread" == "yes" ]]
then
	sqlite3 "$db" 'UPDATE rss_item SET unread = "0" WHERE unread = "1";'
fi

Was da passiert:

  • Newsbeuter wird über „-x reload“ dazu angehalten, ausschließlich die Feeds neu zu laden und sich dann zu beenden. Dabei wird keine interaktive Oberfläche gestartet.
  • Mit „sqlite3“ greife ich von der Shell aus direkt auf die Newsbeuter-Datenbank zu und lese dort die neuen Items aus. Ich muss auch jedes Feld jedes Items einzeln auslesen, um sie sauber voneinander trennen zu können.
  • ELinks zaubert aus dem Content einen schönen Plain Text für meine Mail.
  • Jedes Feed-Item wird einfach über mail an den lokalen Mailserver weitergereicht.
  • Zuguterletzt werden alle neuen Items als gelesen markiert.

– Nachtrag 25.09.2012: Das ursprüngliche Skript hatte einen schlimmen Bug: Es hat in $feedtitle auch nicht-alphanumerische Zeichen zugelassen. Dieser Fehler ist mir peinlich spät aufgefallen. De facto habe ich dadurch ziemlich viele Elemente meiner Feeds verpasst.

Dinge wie Doppelpunkte und Kommata sind nämlich gar nicht so gesund an dieser Stelle:

$ date | mail -r 'foo: <foo@bar.de>' -s test void
exim: bad -f address "foo: <foo@bar.de>": missing or malformed local part (expected word or "<")

$ date | mail -r 'foo, bar <foo@bar.de>' -s test void
A Sender: field is required with multiple addresses in From: field.
No such file or directory
"/home/void/dead.letter" 1/30
. . . message not sent.

Ärgerlich! Vielleicht ist das aber auch ein Zeichen dafür, dass ich mal meine Feeds ausmisten sollte.

Nun denn, weiter im Text.

Man kann hier diskutieren, ob ein Shellskript ein geeignetes Werkzeug ist, um mit der SQLite-Datenbank zu interagieren. Einen Schönheitspreis gewinnt das sicherlich nicht. Ich bin aber zu dem Schluss gekommen, dass es keine Rolle spielt, ob ich hier ein Shellskript schreibe oder Python, Ruby oder sonstwas verwende. Der Unterschied wäre rein kosmetischer Natur, die Performance ist in meinem Fall nicht so wichtig. Die eigentliche Hässlichkeit an meiner Lösung ist nämlich, dass ich direkt auf die Newsbeuter-Datenbank zugreife. Wenn sich dort etwas an den Tabellen ändert, fliegt mein Skript auseinander. Dieses Problem hätte ich aber in jeder Sprache und es ließe sich nur lösen, wenn der Newsbeuter selbst eine passende API für meinen Zweck anböte.

Folglich kann ich auch ein Shellskript nehmen. Im Endeffekt hat das Skript auch so gut wie keine eigene Logik und bedient im Wesentlichen andere Programme – und genau dafür sind Shellskripte da.

Einen echten Mehrwert gibt es für mich sogar: Ich sehe jetzt auch Enclosures. Die hatte ich bei meinem eigenen Feedreader ignoriert, weil es auch hier wieder sehr viele verschiedene Fälle gibt, wie etwas in einem Feed als Enclosure markiert werden kann. Das übernimmt nun Newsbeuter alles für mich.

Tags: newsbeuter, mail

Kommentare

#3 von: Matthias

06.03.2013, 22:25:18

Ich würde das so gerne auf meinem Webspace installieren. Leider weiß ich nicht wie ich die deps mit compiled bekomme. Wenn jemand weiß, wie das (auf einem uberspace) zu schaffen ist, bitte melden!

#2 von: Vain

15.06.2012, 17:52:34

Servus,

ich habe mehrere Mailboxen auf mehreren Servern, aber insgesamt sind das auch nur eine Hand voll. Die Masse sind Wegwerf-Aliases, die auf die Hauptadressen zeigen (für jede Forenregistrieren und jeden Online-Shop einen Alias und so weiter). Zusammengeführt werden die Boxen erst bei mir auf dem Rechner. Ich hole die Mails ganz klassisch per POP3, da ich es nicht so ganz toll finde, wenn die Mails „ewig“ auf den Servern liegen bleiben. Außerdem mache ich die Synchro und damit auch implizit Backups per Git:

http://www.uninformativ.de/?section=news&ndo=single&newsid=97

Ein Smartphone habe ich nicht, deswegen fällt wohl einiges an Komplexität weg.

Für lokale Mails per Cron oder ähnlichem habe ich einen Exim installiert, aber nicht als Daemon laufen, er nimmt Mails also nur über /usr/sbin/sendmail entgegen:

http://www.uninformativ.de/txt/minimal-exim.conf

Alle Mail landet in Maildirs unterhalb von ~/Mail. Als MUA nehme ich Mutt. MTAs sind mpop und msmtp, Cron stößt mpop alle 30 Minuten an. Ich sehe das dann in der screen-Statusbar oder in einer awesome-Wibox, dass neue Mail da ist.

Insbesondere für die Feeds habe ich eine eigene Mailbox, damit sich das nicht mit normalen Mails vermischt. So kann man das sehr schnell überfliegen.

Für Mailinglisten habe ich auf dem Server nur eine einzige Mailbox (aber pro Mailingliste einen Alias) und die Mails sortiere ich dann lokal mit procmail in ein Maildir pro Mailingliste ein (mpop kann die Mails an procmail weitergeben, anstatt sie selbstständig in ein Maildir zu stecken). Das habe ich so gemacht, weil ich keine Lust hatte, pro Mailingliste extra eine eigene Mailbox anzulegen. Außerdem habe ich so die Möglichkeit, manche Mailinglisten – wenn es mir zu viel wird – vorübergehend automatisch als „gelesen“ zu markieren (das macht procmail).

Meine Maildirs habe ich außerdem so organisiert, dass ein Maildir eingehende und ausgehende Mails enthält. Mutt macht sehr gutes Threading und so kann ich immer die gesamte Diskussion an Ort und Stelle nachvollziehen.

So weit in aller Kürze. Hab’ jetzt bestimmt noch 1000 Sachen vergessen. Vielleicht lohnt sich doch ein eigenes Posting dazu, hmm. Falls es dich nach mehr Informationen gelüstet, sag’ bescheid. wink

Cheers!

#1 von: ji

14.06.2012, 21:48:25

Hi!

Ich bin von deiner Vorgehensweise, so alles mögliche abseits von Nachrichten über E-Mail abzuwickeln, angetan. Alles in einen Kanal rein (E-Mail) und den eben überwachen. Aber ich frage mich, wie handhabst du das? Hast du mehrere Adressen für verschiedene Aufgabenbereiche (zB Admin hier und dort, persönliche Adresse, Wegwerfadressen für Internetmüll, Arbeitsadresse usw)? Leitest du zB externe Adressen irgendwie weiter an die auf deinem Server? Wie siehts mit mobilen Klienten aus, zB ein Androidtelefon und Synchronität. Ich mein, wie gehst du das alles an, so dass es möglichst einfach zu handhaben ist und man nicht ständig mit Sondieren von E-Mails zu tun hat. Und wie und wann gehst du deine Mails so durch? Schaust einmal am Tag nach (wobei das bei Notifications ja selten wäre) und wühlst dich dann durch 50 neue Mails oder wie machst du das?

Würde sowas gerne selbst irgendwie gleich von Anfang an einrichten, wenn ich auf Arch umsteigen will.

Danke für eine Erklärung hier oder vlt in einem neuen Blogeintrag. ^^

Kommentar hinterlassen

Name (optional):
E-Mail (optional):
Webpage (optional):
Follow-Up-Benachrichtigung: Aktivieren
Code bestätigen: 1979 →

Captcha:

Hinweise: