Messaging mit Ruby on Rails: Auf E-Mails direkt antworten

Nachrichtenfunktion in Webanwendungen

Wenn Nutzer einer Software anderen Nutzern Nachrichten schreiben können, spricht man von Messaging. Das kann primär der Kommunikation dienen wie in Chats, Foren oder Dating-Plattformen, aber auch der Koordination wie bei Kleinanzeigen-, Buchungs- oder Verkaufsportalen.

Häufig findet sich das folgende Muster: Nachrichten werden innerhalb der Anwendung in einem Postfach verwaltet, jedoch zusätzlich per E-Mail versendet, um den Empfänger auf neue Post hinzuweisen. Nutzer lesen dann zunächst die E-Mail, da das einfach schneller geht.

Beim Antworten wird es dann schwieriger. In der Vergangenheit entstand hier meist ein Bruch. Nutzer mussten sich zunächst auf die Softwareplattform begeben, um hier die Antwort zu schreiben. Wenn dann noch ein Login erforderlich ist, zog sich der Antwortprozess in die Länge.

Wie es besser geht, zeigen Plattformen wie eBay-Kleinanzeigen oder Airbnb. Hier besteht die Möglichkeit, direkt per E-Mail zu antworten. Die E-Mail geht dabei nicht an den Empfänger direkt, sondern an das System. Das schützt zum einen die Privatsphäre, indem E-Mail-Adressen versteckt bleiben, zum anderen werden auch solche Nachrichten im Postfach der Software verwaltet. So kann eine Kommunikation nachvollzogen werden, egal ob Nachrichten per E-Mail oder der Anwendungsoberfläche geschrieben wurden.

Beispielanwendung "postdog"

Mit der Beispielanwendung postdog zeige ich, wie das mit Ruby on Rails funktioniert. Die Anwendung nutzt Rails 5.1.2 sowie die Alpha-Version von Bootstrap 4.

Die Anwendung habe ich auf https://github.com/bjoerne2/postdog bereitgestellt. Eine Anleitung, wie man sie in wenigen Minuten selbst auf Heroku installiert, folgt unten. Eine Instanz läuft aktuell auf https://postdog.herokuapp.com.

Authentifizierung mit Devise

Um das Messaging zu demonstrieren, bedarf es mindestens zwei unterschiedlicher Nutzer. Damit es überhaupt Nutzer gibt, setze ich Devise ein. Devise ist die State-of-the-Art-Lösung für die Behandlung von Usern und deren Authentifizierung.

Ich folge der Installationsanleitung und bekomme in wenigen Minuten:

  • User-Model
  • Registrierung
  • Login-Seite
  • Remember-Me-Funktion
  • Passwort-vergessen-Funktion
  • Logout

Mit rails generate devise:views kann ich mir die Devise-Views in mein Projekt kopieren. Ich passe jedoch nur die Eingabefelder und Buttons an Bootstrap an.

Messaging mit Ruby on Rails

Für das Messaging nutze ich Mailboxer. Neben der Dokumentation setze ich auf dem Code einer anderen Beispielanwendung auf, die hier beschrieben ist: http://josephndungu.com/tutorials/private-inbox-system-in-rails-with-mailboxer.

Mailboxer arbeitet wie E-Mail-Clients mit den Ordnern Inbox, Sent und Trash. In diesen Postfächern gibt es Konversationen. Eine Konversation besteht aus der originären Nachricht und allen Antworten. Nachrichten haben Flags, z.B. ob sie gelesen wurden (unread).

So sieht ein Postfach aus:

Postfächer und Postfachinhalt

Klickt man auf eine Nachricht, gelangt man in die Konversationssicht, in der man direkt antworten kann.

Konversationssicht

Standardmäßig werden neue Nachrichten zusätzlich per E-Mail an den Empfänger gesendet. In meiner Anwendung habe ich dazu ein SMTP-Konto eingerichtet.

Mailboxer Advanced: Validierung der Eingaben

Die Models, die Mailboxer verwendet (Mailbox, Conversation, Message, Notification, Receipt), liegen in der Mailboxer-Bibliothek und können nicht so einfach angepasst werden. Außerdem startet der Controller nur den Erstellungsprozess und hat nur Zugriff auf das Endergebnis. Falls aber Daten invalide sind, z.B. durch leere Eingabefelder, kann dies nicht behandelt werden und fehlerhafte Daten gelangen in die Datenbank.

Meine Lösung besteht in der Verwendung eines transienten Models, das nur zur Eingabe und Validierung dient:

Im Controller wird zunächst dieses Modell mit den Parametern gefüllt. Erst wenn das transiente Modell valide ist, wird die eigentliche Nachricht erstellt.

Das Ergebnis ist eine Prüfung aller Felder auf gültige Eingaben:

E-Mails mit Token versehen

Um zu ermöglichen, dass Nutzer auf die von Mailboxer versendeten E-Mails antworten können, muss die Absenderadresse ein Token enthalten, das die ursprüngliche Nachricht identifiziert. Denn beim Schreiben der Antwort-E-Mail wird der Sender nicht authentifiziert. Das Token in der E-Mail-Adresse ist der Ersatz.

Eine Beispiel für eine E-Mail-Adresse mit einem Token ist reply-SGxERr8n1sgebqtQL35tJXkM@example.com. Damit eine solche E-Mail empfangen werden kann, muss ein Catchall beim Hoster eingerichtet sein. Das bedeutet, dass E-Mails zu denen kein Postfach existiert, nicht zurückgewiesen werden, sondern an ein bestimmtes Postfach geleitet werden.

Das Token muss so sicher sein, dass es nicht erraten werden kann. In Rails gibt es für die Generierung von solchen Token das Feature has_secure_token. Dieser Einzeiler reicht, damit ein Model bei der Erstellung ein Token bekommt. Voraussetzung is ein Feld token in der Datenbank.

Da die Modelle von Mailboxer nicht konfiguriert werden können, ist ein Monkey Patch notwendig, den ich einfach in den Initializer mailboxer.rb eingefügt habe:

Damit das Token angehängt wird, passe ich die Mailer an, die Mailboxer verwendet:

Die Mailer überschreiben lediglich die mail-Methode. Das passende Receipt und damit auch das passende Token wird gesucht und vor dem @-Zeichen der from-Adresse eingefügt.

Im E-Mail-Postfach sieht das dann so aus:

Erhaltene E-Mail

Antwort

Nachrichtenempfang mit Ruby on Rails

Wenn die Antwort erfolgt ist, liegt diese nun in einem E-Mail-Postfach und wartet auf die Verarbeitung. Damit das passieren kann, muss sie zunächst abgerufen werden.

Dazu habe ich ein Rake-Task postdog:receive_mails geschrieben, der zeitgesteuert aufgerufen wird. Das Abrufen habe ich mit dem Ruby-Gem mail und dem POP3-Protokoll realisiert.

Bei der Verarbeitung habe ich Folgendes berücksichtigt:

  • Nach -- beginnt die Signatur. Diese wird ignoriert.
  • Alle Zeilen, die mit > beginnen zitieren die vorherige E-Mail. Sie werden ignoriert, sofern sie am Ende der Nachricht stehen.
  • Enthält eine Zeile die E-Mail-Adresse mit dem Token (wie gesagt, ist der Token eine Authentifizierung für die Antwort, die nur vom ursprünglichen Empfänger genutzt werden soll), wird die Zeile ignoriert.

Ob diese Regeln praxistauglich sind, muss sich erst noch in einem Feldtest zeigen.

Deployment auf Heroku

Voraussetzung ist ein einfacher Heroku-Account. Um den Scheduler zu nutzen und damit die oben genannte zeitgesteuerte Verarbeitung, muss leider eine Kreditkarte hinterlegt werden, auch wenn voraussichtlich keine Kosten anfallen.

Zunächst muss die Anwendung erstellt werden. Anschließend muss das Deployment konfiguriert werden. Hier stehen die Möglichkeiten Heroku CLI, Github und Dropbox zur Auswahl. Die Datenbank und der Scheduler werden als sogenannte Dynos hinzugefügt:

Die folgenden Umgebungsvariablen müssen gesetzt sein:

  • DATABASE_URL (wird von Heroku gesetzt)
  • MAILBOXER_DEFAULT_FROM (z.B. reply@example.com. Beim Senden wird vor dem @-Zeichen "-<token>" eingefügt)
  • MAILER_DEFAULT_URL_HOST (z.B. https://postdog.herokuapp.com)
  • MAILER_SMTP_ADDRESS
  • MAILER_SMTP_PASSWORD
  • MAILER_SMTP_PORT
  • MAILER_SMTP_USER_NAME
  • MAIL_POP3_ADDRESS
  • MAIL_POP3_PASSWORD
  • MAIL_POP3_PORT
  • MAIL_POP3_USER_NAME

Die Umgebungsvariablen können per Weboberfläche oder CLI gesetzt werden.

Anschließend is der folgenden Aufruf per Heroku CLI notwendig: heroku run -a postdog rake db:migrate.

Damit regelmäßig die Verarbeitung der E-Mail-Antworten durchgeführt wird, muss ein Job zum Scheduler hinzugefügt werden, der den Rake-Task ausführt:

Anschließend kann die Anwendung aufgerufen werden. Damit sich zwei Testnutzer gleichzeitig unterhalten können, nutze ich meist zwei verschiedene Browser, auf denen jeweils ein Nutzer angemeldet ist.

Eine Instanz der Anwendung läuft aktuell auf https://postdog.herokuapp.com.

 

 

bjoerne_com_bjoern_weinbrenner_softwareentwickler_icon_leistungen_02

Lust auf mehr? Als Experte für Individualentwicklung mit Ruby on Rails kann ich Sie in Ihren Projekten unterstützen. Melden Sie sich gerne bei mir.

2017-07-16T09:58:40+00:00 16.07.2017|Tags: , , , , , |0 Kommentare

Hinterlassen Sie einen Kommentar