IOException.de

Icon

Ausgewählter Nerdkram von Informatikstudenten der Uni Ulm

Einfacher SMTP-Server zur Aufgabenverarbeitung

Häufig ärgere ich mich über Webanwendungen, die ihren Nutzern Mails schicken, wenn irgendein Ereignis eingetreten ist oder eine Aktion des Users benötigt wird, eine einfache Antwort auf die Mail aber nicht möglich ist. Ein typisches Szenario ist etwa das Bestätigen der Mailadresse, wenn man sich bei einem neuen Dienst registriert: Man gibt seine Mailadresse in ein Online-Formular ein, bekommt eine Aktivierungsmail zugeschickt und muss darin einen Link anklicken, der wiederum zum Webdienst führt und meine Mailadresse bestätigt. Wäre es nicht einfacher, die Mail so wie sie ist an den Absender zurückzuschicken um sie zu bestätigen?

Dies sei nur als ein Beispiel genannt. Beim nicht mehr gepflegten node.js-Modul smtpevent sind auch noch weitere Szenarien aufgeführt: Viele Mailinglists bieten etwa die Möglichkeit, sich über eine Mail an unsubscribe@mailinglist.de davon abzumelden. Bei Github kann man auf einen Issue direkt antworten, indem man die Benachrichtigungsmail einfach beantwortet. Weitere Szenarien sind leicht vorstellbar: Warum soll ich von unterwegs mit dem Handy eine Weboberfläche bemühen, um remote meine Heizung zu steuern, wenn ich schneller eine Mail mit dem Betreff “On” an heating@meinserver.de schicken kann?

Um eine solche Anwendung zu realisieren wird ein SMTP-Server benötigt. Node.js versteht sich sehr gut auf solche Protokolle und der eventbasierte Ansatz ist bei eingehenden Mails sicher auch nicht verkehrt. Und so gibt es bereits eine kleine Zahl an guter SMTP-Server-Implementierungen. Mir ist vor allem der estländische Programmierer Andris Reiman aufgefallen, der für node.js viele Module geschrieben hat, die sich mit dem Versand und Empfang von Mails beschäftigen. So reichen seine beiden Projekte simplesmtp und mailparser, um einen einfachen SMTP-Server aufzusetzen und die Mails und Anhänge zu parsen.

Zuerst bauen wir den SMTP-Server auf:

var simplesmtp = require('simplesmtp');
var MailParser = require('mailparser').MailParser;

var server = simplesmtp.createServer({
  validateSenders: false,
  validateRecipients: false
});

server.on('startData', function(envelope) {
  envelope.mailparser = new MailParser();
  envelope.mailparser.on('end', takeMail);
});

server.on('data', function(envelope, chunk){
  envelope.mailparser.write(chunk);
});

server.on('dataReady', function(envelope, callback){
  envelope.mailparser.end();
  callback();
});

server.listen(25);

Der Code ist relativ selbsterklärend: Bei Eingang einer Mail wird das startData-Event gefeuert, einzelne Datenchunks werden durch den data-Listener bearbeitet, und wenn die Mail vollständig übertragen wurde, feuert dataReady. Der Rahmen envelope wird dabei allen Funktionen übergeben, sodass envelope.mailparser auch in allen Funktionsaufrufen für eine Mail der gleiche ist. So werden bei zwei gleichzeitig eingehenden Mails diese nicht versehentlich vermischt.

Sobald die Mail vollständig übertragen wurde (dataReady), lösen wir mailparser.end() aus, was das Parsen der Mail beginnt. Fehlt noch die Definition, was mit unserer geparsten Mail denn passieren soll:

function takeMail(mail_object) {
    console.log('From:', mail_object.from); //[{address:'sender@example.com',name:'Sender Name'}]
    console.log('Subject:', mail_object.subject); // Hello world!
    console.log('Text body:', mail_object.text); // How are you today?

    // Irgendein Datenbankaufruf o.ä.
}

Hier kann die Mail nun also ausgewertet und so die gewünschte Aktion ausgelöst werden. Das tolle am Mailparser ist die Tatsache, dass Dateianhänge ebenfalls soweit wie möglich geparst werden. So enthält das mail_object auch einen Eintrag attachments, der etwa so aussehen könnte:

attachments = [{
    contentType: 'image/png',
    fileName: 'image.png',
    contentDisposition: 'attachment',
    contentId: '5.1321281380971@localhost',
    transferEncoding: 'base64',
    length: 126,
    generatedFileName: 'image.png',
    checksum: 'e4cef4c6e26037bcf8166905207ea09b',
    content: <Buffer ...>
}];

Attachments-Beispiel von mailparser

So könnte man leicht einen Service wie den von Twitpic einrichten, dass man durch das Senden an eine userspezifische Mailadresse ein Bild hochladen kann.

Wem das ganze zu unsicher scheint, weil ja sonst jeder, der die Mailadresse kennt, Dummheiten anstellen könnte, der sei auf die Serverkonfiguration ganz oben hingewiesen: Werden validateSenders und validateRecipients auf true gesetzt, können Sender und Empfänger in einer eigenen Funktion überprüft und ggf. zurückgewiesen werden. Die simplesmtp-Bibliothek bietet daneben auch noch andere Authorisierungsmechanismen.

ioexception.de

Benjamin Erb [] studiert seit 2006 Medieninformatik und interessiert sich insbesondere für Java, Web-Technologien, Ubiquitous Computing, Cloud Computing, verteilte Systeme und Informationsdesign.


Raimar Wagner studiert seit 2005 Informatik mit Anwendungsfach Medizin und interessiert sich für C++ stl, boost & Qt Programmierung, Scientific Visualization, Computer Vision und parallele Rechenkonzepte.


David Langer studiert seit 2006 Medieninformatik und interessiert sich für Web-Entwicklung, jQuery, Business Process Management und Java.


Sebastian Schimmel studiert seit 2006 Informatik mit Anwendungsfach Medizin und interessiert sich für hardwarenahe Aspekte, Robotik, webOs, C/C++ und UNIX/Linux.


Timo Müller studiert seit 2006 Medieninformatik. Er interessiert sich allen voran für Mobile and Ubiquitous Computing, systemnahe Enwticklung und verteilte Systeme, sowie Computer Vision.


Achim Strauß studiert seit 2006 Medieninformatik. Seine Interessen liegen in Themen der Mensch-Computer Interaktion sowie Webentwicklung und UNIX/Linux.


Tobias Schlecht studiert seit 2006 Medieninformatik und interessiert sich vor allem für Software Engineering, Model Driven Architecture, Requirements Engineering, Usability Engineering, Web-Technologien, UML2 und Java.


Fabian Groh studiert seit 2006 Medieninformatik. Seine Interessengebiete sind Computer Graphics, Computer Vision, Computational Photography sowie Ubiquitos Computing.


Matthias Matousek studiert seit 2007 Medieninformatik und interessiert sich besonders für Skriptsprachen, Echtzeitsysteme und Kommunikation.


Michael Müller [] studiert seit 2009 Medieninformatik. Er interessiert sich vor allem für Web-Technologien, Ubiquitous Computing, User-Interfaces, UNIX und Creative Coding.


Falco Nogatz [] studiert seit 2010 Informatik mit Anwendungsfach Mathematik. Er interessiert sich für Web-Technologien, Programmierparadigmen und theoretische Grundlagen.

Archiv

Februar 2015
M D M D F S S
« Mrz    
 1
2345678
9101112131415
16171819202122
232425262728