Wie versende ich E-Mail Attachments mit Sendmail?

Sendmail ist ein recht verbreitetes Programm zum Versenden von E-Mails. Aber wie benutzt man es?

Betrachten wir uns zu Beginn einmal einen gewöhnlichen E-Mail Header, wie er bei einer gewöhnlichen E-Mail (mit den Einträgen From, Date, Subject und To) aussehen würde. Dazu werde ich als Test eine E-Mail an mich selbst schicken (Absender: name@providerxy; Betreff: E-Mail; Empfänger: name2@providerxy).

Schauen wir uns nun den Header der versendeten E-Mail an:


Received: from [127.0.0.1] (helo=server)
  by user with smtp (provider 3.59 #478)
  id 87hjfg-hgFfh5-00
  for name2@providerxy; Sun, 24 Aug 2003 22:19:58 +0200
From: "Erik Bertram"
To: "Erik Bertram"
Subject: E-Mail
Sender: name@providerxy

Versuchen wir doch einmal den Header so weit wie möglich zu zerlegen. In der 1.-3. Zeile steckt die Information über den Absender der E-Mail. Dieser Headerteil trägt beispielsweise die Information, mit welcher IP Adresse und von welchem Server die E-Mail verschickt wurde. Die 4. Zeile zeigt den Empfäger der E-Mail sowie das genaue Datum, an welchem wir die E-Mail versand haben. Zeile 5-7 enthalten den Namen des Absenders, den Namen des Empfängers und den Betreff der E-Mail. Schließlich steht in der letzten Zeile noch, von welcher Adresse man die E-Mail erhalten hat.

So weit so gut. Dies war ein einfaches Beispiel, wie ein normaler E-Mail Header auszusehen hat. Machen wir es nun etwas komplizierter. Das erste Beispiel zeigte eine sogenannte einteilige Nachricht. Der Name kommt daher, da der Header nur einen Inhaltstyp enthält, nämlich die ganz normalen Headereinträge. Mehrteilige Nachrichten dagegen unterscheiden sich gegenüber den einteiligen Nachrichten dadurch, dass sie, wie man schon vorher vermuten kann, mehrere Inahltstypen besitzen. Der andere Inhaltstyp wäre in unserem Falle das Attachment (E-Mail Anhang). Damit das E-Mail Programm des Empfängers unsere E-Mail samt Anhang richtig verarbeiten kann, müssen wir unser obiges Beispiel ein wenig abändern. Es muss wissen, wo das logische Ende eines Inhaltstypes ist. Dieses Ende wird durch gestrichelte Linien und anderen Zeichen gekennzeichnet. Solch eine Kennzeichnung nennt man Boundary (engl. für "Grenze").

Nach den RFC Dokumenten ist es ebenso erforderlich bei mehrteiligen Nachrichten einen MIME Eintrag, der die Version von MIME beschreibt, anzugeben. Außerdem müssen wir den neuen Inhaltstyp (Content-type) explizit angeben, da das E-Mail Programm ansonsten versucht, unseren Dateianhang als gewöhnlichen Text darzustellen.

Der passende Inhaltstyp sieht wie folgt aus:


Content-type: multipart/mixed; boundary="---hierstehendietrennzeichen"

Mit dieser Zeile wird der Inhaltstyp angegeben (mehrteilige Nachricht, also "multipart/mixed") und dahinter die Boundary festgelegt.

Wenn es jedoch so einfach wäre, wären wir jetzt fertig und könnten unser eigenes E-Mail Programm schreiben. Dem ist jedoch nicht so. Eine Kleinigkeit haben wir noch vergessen. In dieser Form können wir leider noch kein Attachment anhägen. Da E-Mail ein textbasierendes Format ist und folglich keine Binärdaten übertragen kann, stellt RFC 2045 eine spezielle MIME-Codierung bereit, mit deren Hilfe man binäre Daten in ein für E-Mails zulässiges Format codieren kann. Diese Codierung nennt man Base64. Base64 nutzt einen eingeschränkten Zeichensatz von 64 Zeichen (daher der Name).

Dieser Zeichensatz besteht aus folgenden Zeichen:


ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/

Diese Auswahl wurde deshalb so getroffen, weil sie in nahezu jedem Computersystem existiert. Perl stellt zur Base64 Codierung das Modul "MIME::Base64" bereit.

Schauen wir uns nun ein fertiges Beispiel zur übertragung von E-Mails mit einem Attachment an:


#!/usr/bin/perl
# Obligatorische Headline

use MIME::Base64;
# Modul zum Codieren wird eingebunden

use strict;
# Erleichterung geht um! ;o)

open(M, "|/usr/lib/sendmail -t") or die "Can't open mailprogram: '/usr/lib/sendmail'!\n$!";
# öffne das Mailprogramm. Falls der Vorgang fehlschlägt, gib eine Fehlermeldung aus.

print M "To: Erik Bertram <name2\@provider.xy>\n";
# Empfäger E-Mail und Name werden angegeben.

print M "From: Erik Bertram <name\@provider.xy>\n";
# Absender E-Mail und Name werden angegeben.

print M "Subject: E-Mail\n";
# Betreff wird angegeben.

print M "MIME-Version: 1.0\n";
# MIME-Version bei mehrteiligen Nachrichten muss angegeben werden.

my $boundary = "----------".substr(pack('u', ('E-Mail'.'Erik Bertram')), 0, 24);
# Logische Grenze zwischen mehrteiligen Nachrichten wird generiert. Generierung kann beliebig erfolgen!

print M "Content-type: multipart/mixed; boundary=\"$boundary\"\n\n";
# Inhaltstype wird angegeben (mehrteilige Nachricht) und logische Grenze wird zugewiesen.

print M "--$boundary\nContent-type: text/plain\n\n";
# Erste logische Grenze wird gesetzt und danach der Inhaltstyp "text/plain"
# (gibt an, dass normaler E-Mail Text folgt).

print M "Hier steht der E-Mail Text...\n";
# E-Mail Nachricht wird geschrieben.

print M "\n--$boundary\n";
# Zweite Logische Grenze wird gesetzt.

print M "Content-type: application/octet-stream; name=\"file.tar.gz\"\n";
# Inhaltstyp für das Attachment wird festgelegt und Dateiname zugeordnet.

print M "Content-Transfer-Encoding: base64\n";
# Codierung wird auf Base64 festgelegt.

print M "Content-Disposition: attachment; filename=\"file.tar.gz\"\n\n";
# Gibt an, dass das E-Mail Programm die Datei als Anhang behandeln soll
# (sprich: der Anhang wird nicht direkt im Text ausgegeben).

open(F, "file.tar.gz") or die "Can't open data: 'file.tar.gz'!\n$!";
# öffnet gewüschte Datei. Falls der Vorgang fehlschlägt, gib eine Fehlermeldung aus.

my $data;
# Da kommen die Daten hinein
{
  binmode F;
  # Datei im Binaermode oeffnen.

  local $/;
  # Zeilentrenner lokal auf undef, damit alles auf einmal gelesen wird.

  my $data = <F>;
  # Datei wird in "$data" eingelesen.
}

close(F);
# Datei wird wieder geschlossen.

my $codiert = MIME::Base64::encode($data);
# Modul "MIME::Base64" codiert die in $data stehende Datei ins Base64 Format.

print M $codiert;
# Codierte Datei wird in die E-Mail geschrieben.

print M "\n--$boundary--\n";
# Letzte Grenze. Besagt, dass der E-Mail Header zu Ende ist.

close(M);
# Schließe E-Mail Programm wieder.

Trotz der Tatsache, dass es funktioniert, ist dieses Programm lang und aufwendig. Es wird daher empfohlen, eines der Mail Module von Perl zu verwenden. Eines davon ist das bekannte Modul "MIME::Lite", mit dem man mit nur wenigen Befehlen den gleichen Effekt erreichen kann, wie es das obige Beispiel tut (MIME::Lite verwendet zum Versenden von E-Mails auch Sendmail). Es gibt noch andere Module, die das Versenden von Nachrichten mit Attachments sehr vereinfachen. Greifen Sie deshalb lieber auf diese zurück, bevor Sie sich mit so komplexen Codes herumschlagen und herumärgern müssen.

So far...

Erik Bertram alias [E|B]

Ergänzungen, Kommentare

Kommentare werden am besten in folgender Form vorgenommen, damit sie im Inhaltsverzeichnis angezeigt werden (natürlich ohne das <verbatim>):
---+++ Main.??? - 14 Jul 2003 - Betreff

-- AlexKoeppe - 27 Aug 2003
-- HaraldBongartz - 28 Aug 2003 - Wiki-Formatierung, kleinere Verbesserungen

UtilFaqSubForm edit

Titel Wie versende ich E-Mail Attachments mit Sendmail?
Autor ErikBertram
Bereich FaqEmail
Topic revision: 2003-08-29, HaraldBongartz
 
Bitte die NutzungsBedingungen beachten.
Bei Vorschlägen, Anfragen oder Problemen mit dem PerlCommunityWiki bitten wir um WebBottomBarExample">Rückmeldung.