Grundstruktur
Dieser Abschnitt befasst sich mit dem Grundgerüst unseres Packages. Am Ende dieser Seite wird das Programm - zumindest theoretisch - bereits lauffähig sein.
Als ersten Schritt erstellen wir unser Package, binden externe Standard-Module ein
und deklarieren eine Subroutine sendMail
. An diese Subroutine sollen
über das Hash %mail
sämtliche relevanten Daten vom Hauptprogramm
übergeben werden.
package mail; ### # Module aufrufen ### use CGI::Carp qw(fatalsToBrowser); ### # Variablen exportieren ### require Exporter; @ISA = qw(Exporter); @EXPORT = qw($mail_error); @EXPORT_OK = qw(); ### # Standard-Variablen ### my $mailprog = "/usr/lib/sendmail"; $mail_error = undef; ################################### ################################### #### Send Mail ##### ################################### sub sendMail { my %mail = @_; # Hier folgen alle weiteren Anweisungen # [...] }
Hinweise:
- Es empfiehlt sich, sämtliche Daten über ein Hash zu übergeben (
my %mail = @_;
), ansatt beispielweise mehrere Skalare zu verwenden. Wie wir später noch sehen werden, sollen nicht alle möglichen Variablen Pflicht-Werte darstellen, und auf diese Weise können auch wirklich nur die Werte übergeben werden, die tatsächlich benötigt werden. - Die globale Variable
$mail_error
gibt uns eine Möglichkeit, Fehlermeldungen an das aufrufende Programm zurückzugeben. Die Variable wird über dasExporter
-Modul an das aufrufende Programm exportiert und kann dort weiter verwendet werden. - Die Variable
$mailprog
beeinhaltet den Pfad zu dem Mail-Programm des Servers, standardmäßig auf UNIX-basierten Servern/usr/lib/sendmail
. Grundsätzlich muss diese Variable nicht gleich zu Programm-Beginn deklariert werden, es is jedoch vorteilhaft, da dieser Wert angepasst werden muss, falls das Mailprogramm an einem anderen Ort liegt.
Was machen wir nun mit diesem Mail-Programm sendmail
? Technisch gesehen übergeben wir unsere
gewünschten Informationen als Daten-Stream an ein File-Handle, das eine Pipe zum
angegebenen Programm geöffnet hat. Das mag jetzt etwas abstrakt klingen, bedeutet aber
konkret nichts anderes, als dass wir die altbekannte print
-Anweisung so "umbiegen",
dass sie ihre Anweisungen eben an unser Mail-Programm anstelle des STDOUT-Streams übergibt -
genauso, wie wir mittels open
auch jede x-beliebige Datei beschreiben können:
#[...] sub sendMail { my %mail = @_; ### # Mail-Programm starten ### if ( open(MAIL,"|$mailprog -t") ) { # Daten an Mail-Programm übergeben print MAIL "To: $mail{'to'}\n"; print MAIL "From: $mail{'from'}"; print MAIL " ($mail{'namefrom'})" if ( exists($mail{'namefrom'}) ); print MAIL "\n"; print MAIL "Cc: $mail{'cc'}\n" if ( exists($mail{'cc'}) ); print MAIL "Bcc: $mail{'bcc'}\n" if ( exists($mail{'bcc'}) ); print MAIL "Subject: $mail{'subject'}\n"; print MAIL "MIME-Version: 1.0\n"; print MAIL "Content-Type: text/plain;\n\tcharset=\"iso-8859-1\"\n\n"; print MAIL "$mail{'text'}\n\n"; close(MAIL); return 1; } # Fehler beim Öffnen else { $mail_error = "Fehler beim Starten des Mail-Programms: $!"; print STDERR $mail_error; return undef; } }
Erklärung:
Mit open(MAIL,"|$mailprog -t")
definieren wir ein Filehandle MAIL
, das auf das
Mail-Programm zeigt. Da open()
bei einem Fehler den Wert false
, ansonsten true
zurückgibt, können wir gleichzeitig mit einer if-Anweisung Fehler abfangen. Bei erfolgreichem Ausführen
des Mail-Programms soll dann an das aufrufende Programm der Wert 1
, ansonsten undef
zurückgegeben werden. Zudem wird im Falle eines Fehlers die Fehlermeldung auf STDERR
geschrieben
und in der globalen Variable $mail_error
gespeichert.
Als nächstes werden die Header-Informationen abgearbeitet. An dieser Stelle wird auch deutlich, wieso sich die
Wert-Übergabe mittels eines Hashs anbietet: Optionale Angaben wie Cc
, Bcc
können durch die
Bedingung if ( exists($mail{'cc'}) )
nur dann angegeben werden, wenn sie wirklich benötigt werden.
Zu guter Letzt geben wir den Content-Type
(momentan lassen wir nur plain-text E-Mails zu) und den
Zeichensatz (charset) an, gefolgt von der eigentlichen Nachricht.
Hinweis:
Das Package ist nun bereits theoretisch lauffähig. Allerdings ist es in dieser Form noch absolut davon abhängig, dass es vom aufrufenden Programm nur korrekte Daten erhält. Im Klartext: Momentan könnte man damit noch jede Menge Unsinn anstellen. Dies werden wir im nächsten Abschnitt ändern.