EmailVersandHack

Aus alt.comp.hsr
Wechseln zu: Navigation, Suche

Diese Konfiguration habe ich für unser SE2P Projekt auf unserem Ubuntu Virtual Server (SE2P Version) vorgenommen. Diese Anleitung dient dazu, dass man dem virtuellen Server, der von der SMTP-Welt ausgeschlossen ist, die Mailfunktionalität beibringt, indem man die Mails von Jenkins und Redmine irgendwo anders in Auftrag gibt. Diese Variante führt bei Erhalt eines Mails ein spezielles Skript aus, welches dann ein Skript auf einem öffentlichen Server über HTTP ankickt und die Daten mitschickt.

Virtueller Server

Annahmen

  • Dir steht ein (PHP-fähiger) Server zur Verfügung, der via HTTP erreichbar ist und Mails verschicken kann
  • sendmail ist (vor)installiert
  • Eingeloggt via ssh als Benutzer root

Vorbereitung

Installiere php (ja sorry, ich kann halt immernoch php am besten ;)

 $ sudo apt-get install php5 php5-cli

Konfiguration

/etc/aliases

Der virtuelle lokale Benutzer "special" wird die E-Mails annehmen und sendmail "pipe"d so den Inhalt an das Skript weiter:

Suche nach:

 # Other aliases

und ergänze mit:

 special:	|/usr/local/scripts/specialmailer/send.php

/etc/mail/sendmail.mc

Sendmail erweitern wir um das Feature, eigendlich externe Adressen intern to "relayen", dazu sind dann auch ein paar Einträge in anderen Files notwendig:

Suche nach:

 dnl DAEMON_OPTIONS(`Family=inet6, Name=MSP-v6, Port=submission, M=Ea, Addr=::1')dnl
 DAEMON_OPTIONS(`Family=inet,  Name=MSP-v4, Port=submission, M=Ea, Addr=127.0.0.1')dnl

und ergänze unterhalb mit:

 dnl # Define virtualusertable
 FEATURE(`virtusertable', `hash /etc/mail/virtusertable')dnl
 VIRTUSER_DOMAIN_FILE(`/etc/mail/virtual-domains')dnl

/etc/mail/virtusertable

Wir definieren eine "catch-all" Regel und leiten diese an unseren speziellen "special" user weiter.

Erstelle Datei mit Inhalt:

 @hsr.ch		special

/etc/mail/virtual-domains

Damit die Regel überhaupt zieht, müssen wir definieren, dass sendmail die gewünschten Domains überhaupt beachtet.

Erstelle Datei mit Inhalt:

 hsr.ch

/usr/local/scripts/specialmailer/send.php

Nun erstellen wir das Skript, welches angekickt wird im Falle, dass "special" eine Mail bekommt. Das kann natürlich auch ein eigenes Skript sein. Diese Variante leitet den ganzen Mail-Content per POST an das gewünschte Skript des öffentlichen Servers weiter.

!WICHTIG! Ändere $url zu der Adresse, wo sich das andere Skript dann befinden wird. !WICHTIG! Denke daran, dieser Datei Ausführberechtigung zu geben, z.B. mit:

 $ chmod +x send.php

Erstelle Datei mit Inhalt:

 #!/usr/bin/php -q
 <?php
 
 stream_set_blocking(STDIN, 0);
 $mail = "";
 while(($line = fgets(STDIN)) !== FALSE) {
 	$mail .= $line;
 }
 
 //file_put_contents("/tmp/send.log", $mail);
 
 $url = 'http://stuff.deinedomain.ch/hsrmail.php';
 $data = array('msg' => $mail);
 
 $options = array(
     'http' => array(
         'header'  => "Content-type: application/x-www-form-urlencoded\r\n",
         'method'  => 'POST',
         'content' => http_build_query($data),
     ),
 );
 $context  = stream_context_create($options);
 $result = file_get_contents($url, false, $context);

Abschluss

Übernehme die neue Konfiguration mit (die Fragen grundsätzlich mit y=Yes beantworten)

 $ newaliases
 $ sendmailconfig

Öffentlicher Server

Skript

Mein Mailversandskript nutzt das "alte" Zend Framework, um einfacher den Mail-Header und -body auseinander zu nehmen und das neue Mail dann zu verschicken. Ihr benötigt also noch das Zend Framework v1.x.x, auspacken, und das "library"-Verzeichnis in die gleiche ebene wie das Skript ablegen.

!WICHTIG! Schütze dein öffentliches Skript vor unbefugten Zugriffen, z.B. Alles blocken ausser der Anfragende hat die zugelassene IP

 <php
 
 if($_SERVER['REMOTE_ADDR'] != "11.22.33.44") {
 	die("You're not permitted to send mails over this script");
 }
 
 @error_reporting(E_ALL^E_NOTICE);
 @ini_set('display_errors','on');
 set_include_path(get_include_path().PATH_SEPARATOR.'./library');
 
 include_once("Zend/Mail.php");
 include_once("Zend/Mail/Message.php");
 //file_put_contents("send.log", $_POST['msg']);
 
 $parsed_mail = new Zend_Mail_Message(array('raw' => $_POST['msg']));
 //file_put_contents("debug.log", print_r($parsed_mail, true));
 //file_put_contents("debug2.log", print_r($parsed_mail->to, true));
 
 $mail = new Zend_Mail('UTF-8');
 $mail->setFrom('special@dein-virtueller-server.edu.hsr.ch', 'DragonSlayer');
 if(preg_match("/hsr\.ch/", $parsed_mail->to)) {
 	foreach(explode(",", $parsed_mail->to) as $recipient) {
 		$mail->addTo(trim($recipient));
 	}
 } else { // der Empfänger war special, welches dann an alle gehen sollte
 	$mail->addTo('mitglied1@hsr.ch', 'mitglied1 name');
 	$mail->addTo('mitglied2@hsr.ch', 'mitglied2 name');
 	$mail->addTo('mitglied3@hsr.ch', 'mitglied3 name');
 	$mail->addTo('mitglied4@hsr.ch', 'mitglied4 name');
 }
 $mail->setSubject($parsed_mail->subject);
 $mail->setBodyText(trim($parsed_mail->getContent()));
 $mail->send();

Konfiguration der Tools

Jenkins

Benutze als Mailserver jeweils "localhost". Soll das Mail an alle gehen, nutze "special" oder "special@localhost" als Empfänger, ich empfehle auch "special@localhost" als Absender zu definieren. Es wird keine Authentifizierung (da lokal) benötigt. Diese Variante ist für Jenkins interessant.

Konfiguration GUI

Schnellanleitung Projekte Jenkins0.jpg

Schnellanleitung Projekte Jenkins1.jpg

Redmine

Sobald ein Mail an eine @hsr.ch -Adresse geschickt wird, wird diese auch automatisch an "special" übermittelt. Das externe Skript erkennt jedoch, dass dieses Mail an einen (oder mehrere) direkt gesendet wird.

/etc/redmine/default/configuration.yml

Erstelle Datei mit Inhalt:

 production:
   email_delivery:
     delivery_method: :sendmail

Konfiguration GUI

Schnellanleitung Projekte Redmine0.jpg

Debugging

Generell ist es schwierig zu debuggen, wenn man sich nicht in das Thema gearbeitet hat oder sich nicht auskennt. Anlaufstellen sind:

  • Manuell ein Mail auslösen:
 $ echo "Testmail" | mail -s "Testmail" mitglied1@hsr.ch
 $ echo "Mastermail" | mail -s "Mastermail" special
  • die file_put_contents der Skripts aktivieren, und schauen was drin steht (in Zusammenhang mit den oberen beiden Befehlen natürlich den Inhalt wechseln)
  • Die sendmail-logs durchsuchen, befinden sich unter /var/log/mail*


Quellen und Anlaufstellen