Mai 19, 2012 registrieren anmelden
 
Durchsuchen minimieren
  
 
 SupportNewsBlog   
Weblogs
Nov 1

Erstellt von: Torsten Weggen
01.11.2005 13:36 

Wir spielen mal Outlook Express…

E-Mails sind in der heutigen Zeit integraler Bestandteil unserer Kommunikation. Dementsprechend kommt heute kaum ein Programm ohne diese Funktionalität aus. Das haben sich auch viele Toolhersteller zunutze gemacht und bieten für diesen Zweck eigene ActiveX- oder COM-Komponenten an, die auch in Foxpro genutzt werden können. Ein typischer Vertreter dieser Gattung findet sich z.B. bei Mabry (Stand November 2009: Firma existiert nicht mehr).

Desweiteren kann man z.B. Outlook automatisieren. Leider ist Outlook kein Bestandteil des Betriebssystems, wir können also nicht immer voraussetzen, das Outlook beim Kunden auch vorhanden ist. Außerdem ist mit den aktuellsten Versionen von Outlook die Automatisierung aus Sicherheitsgründen erschwert, so das dieses Vorgehen zum simplen Versenden und Empfangen von Mails schlicht der Overkill ist.

Dabei geht es so einfach! E-Mails sind ja letzten Endes nichts anderes als Textnachrichten, die zwischen einem Server und dem Client (in diesem Fall ihr Programm) hin- und hergeschoben werden. Der (Mail-) Server hat einen sehr beschränkten, standardisierten Befehlssatz, den wir schnell beherrschen können.

Also: Warum machen wir das Ganze nicht selbst?

Tun wir doch mal so, als wären wir ein E-Mailclient wie Thunderbird oder Outlook Express. Wir melden uns an unserem POP3-Server an und rufen ein paar ausgesuchte Mails ab. Dann löschen wir einige SPAM-Mails direkt auf dem Server und melden uns anschließend wieder ab.

POP3 wird standardmäßig über den Port 110 abgewickelt. Deshalb starten wir jetzt Telnet mit der Adresse unseres Mailservers sowie dem genannten Port:

telnet pop3.meinserver.de 110¬

Wenn alles richtig läuft, antwortet der Server so etwas wie:

+OK POP server ready H mimap9


Jetzt loggen wir uns mal ein. Dazu gibt’s den Befehl USER

USER tweggen¬ 
+OK password required for user "tweggen"

Sowie das Passwort:

PASS needasverraticheuchnich¬ 
+OK tweggen's mailbox has 2 messages (4185 octets) H mimap19

Wenn die Daten OK waren, seid Ihr schon mal an eurer Mailbox angemeldet. Das ist gut ! Als nächstes wollen wir nachschauen, ob auch was drin ist in der Mailbox. Dazu fragen wir die Mailbox mit dem LIST-Befehl:

LIST¬

Und bekommen eine schöne Liste sämtlicher in der Mailbox liegenden Mails. Klasse, oder ?

+OK 2 messages (4185 octets) 
1 1670 
2 2515 
.

Alle Mails in der Mailbox haben eine eindeutige ID, die das Mailserver-Programm vergibt. Anhand dieser ID kann man entscheiden, ob man die Mail bereits abgeholt hat (vorausgesetzt, man merkt sich die ID’s der abgeholten Mails). Mailclients tun dies, da sie sonst jedes Mal wieder alle Mails aus der Mailbox abholen würden.

UIDL¬ 
+OK 
1 0MKpV6-1EOEHp37aN-00086X 
2 0MKsUu-1EOEUA47bl-0002JK 
.

So. Nun wissen wir schon mal was anliegt. Schauen wir uns doch die einzelnen Mails mal etwas genauer an. Schließlich wollen wir ja nicht jeden Mist abholen! Zuerst aber interessiert uns nur der Mailheader. Da steht drin, von wem die Mail ist, der Betreff etc. (mehr dazu später). Wenn wir da feststellen, dass es sich um eine VIA.GR@-Mail handelt, können wir sie gleich dem Orcus übergeben ;-)

TOP 1 0¬
+OK
Return-Path: nixzurueck@spamfritz.com
Delivery-Date: Sat, 08 Oct 2005 14:58:49 +0200
Received: from [212.227.126.187] (helo=moutng.kundenserver.de)
by mxeu1.kundenserver.de with ESMTP (Nemesis),
id 0MKpV6-1EOEHp37aN-00086X for devcon@auktionsbuddy.de; 
Sat, 08 Oct 2005 14:58:49 +0200
Message-ID: 4347C285.5010609@auktionsbuddy.de
Date: Sat, 08 Oct 2005 14:58:45 +0200
From: BöserSpammer boeser@spammer.com
User-Agent: Mozilla Thunderbird 1.0 (Windows/20041206)
X-Accept-Language: de-DE, de, en-us, en
MIME-Version: 1.0
To: devcon@auktionsbuddy.de
Subject: Via.gr@ billich
Content-Type: text/plain
Envelope-To: devcon@auktionsbuddy.de
.

Ja, die kann eindeutig weg!

DELE 1¬
+OK message deleted

Diese wiederum scheint ganz interessant zu sein:

Return-Path: torsten@auktionsbuddy.de
...
To: devcon@auktionsbuddy.de
Subject: Sehr wichtige Mitteilung
Content-Type: text/plain
Envelope-To: devcon@auktionsbuddy.de

 

Die wollen wir uns mal komplett ansehen:

RETR 2¬
+OK 2515 octets
Return-Path: torsten@auktionsbuddy.de
Delivery-Date: Sat, 08 Oct 2005 15:11:36 +0200
Received: from [212.227.126.186] (helo=moutng.kundenserver.de)
by mxeu6.kundenserver.de with ESMTP (Nemesis),
id 0MKsUu-1EOEUA47bl-0002JK for devcon@auktionsbuddy.de; 
 Sat, 08 Oct 2005 15:11:34 +0200
Received: from a2125949139.net-htp.de [212.59.49.139] (helo=[192.168.111.3])
by mrelayeu.kundenserver.de with ESMTP (Nemesis),id 0ML21M-1EOEU91zR9-0002Q1;
 Sat, 08 Oct 2005 15:11:33 +0200
Message-ID: 4347C583.5070705@auktionsbuddy.de
Date: Sat, 08 Oct 2005 15:11:31 +0200
From: Auktionsbuddy torsten@auktionsbuddy.de
User-Agent: Mozilla Thunderbird 1.0 (Windows/20041206)
X-Accept-Language: de-DE, de, en-us, en
MIME-Version: 1.0
To: devcon@auktionsbuddy.de
Subject: Sehr wichtige Mitteilung
Content-Type: text/plain
Envelope-To: devcon@auktionsbuddy.de
Content-Transfer-Encoding: 8bit

Hallo,
sehr sehr wichtig
Freundliche Grüsse

Torsten Weggen
=============================================
|\/| indisoftware gmbh
(..) Torsten Weggen
 \/ Lister Str. 10
 ○ 30163 Hannover
EMail: torsten@auktionsbuddy.de
Internet: http://www.auktionsbuddy.de
=============================================

Nachdem wir alle durchgearbeitet haben, können wir uns wieder abmelden:

QUIT¬

Wenn ihr euch jetzt etwas enttäuscht zurücklehnt, und euch fragt, ob das alles sein soll und warum ihr letzte Woche so horrend viel Geld für dieses Mail-OCX ausgegeben habt, muss ich euch leider sagen:

NÄNÄNÄNÄNÄ

Hier gibt’s noch mal zusammengefasst die wichtigsten POP3-Befehle:

Empfang per POP3 (Port 110) RFC 1939 (http://www.ietf.org/rfc/rfc1939.txt)

USER

Usernamen eingeben

PASS

Passwort eingeben

LIST

Liste der E-Mails abrufen

UIDL

Liste der Unique ID’s der E-Mails abrufen

TOP

Zeile 1 – Y der Mail X abrufen

RETR

Mail X komplett abrufen

DELE

Mail X löschen

QUIT

Abmelden von der Mailbox

RSET

Löschen rückgängig machen

Die Windows-Socken

Also, wenn ich ganz ehrlich sein soll, war das doch noch nicht alles… Ich muss euch jetzt doch noch erklären, wie ihr die DOS-Box mit Foxpro öffnet, den Bildschirminhalt abfotografiert, das ganze dann per OCR auswertet, damit ihr letztendlich die Mails als Text vorliegen habt…

Nicht ?

Naja, Ihr habt ja Recht. Das geht viel besser. Nämlich mit den Windows-Sockets! Dazu brauchen wir aber ein bisschen API-Zugriff auf Windows-interne Funktionen:

DECLARE INTEGER WSAStartup IN ws2_32 INTEGER wVerRq, STRING lpWSAData 
DECLARE INTEGER WSACleanup IN ws2_32 
DECLARE INTEGER WSACreateEvent IN ws2_32 
DECLARE INTEGER WSACloseEvent IN ws2_32 INTEGER hEvent 
DECLARE INTEGER WSASetEvent IN ws2_32 INTEGER hEvent 
DECLARE INTEGER WSAEventSelect IN ws2_32 INTEGER s, INTEGER hEventObject,;
    INTEGER lNetworkEvents 
DECLARE INTEGER WSAWaitForMultipleEvents IN ws2_32 INTEGER cEvents,;
    INTEGER @lphEvents, INTEGER fWaitAll, ;
    INTEGER dwTimeout, INTEGER fAlertable 
DECLARE INTEGER socket IN ws2_32 INTEGER af, INTEGER tp, INTEGER pt 
DECLARE INTEGER closesocket IN ws2_32 INTEGER s 
DECLARE INTEGER inet_addr IN ws2_32 STRING cp 
DECLARE INTEGER htons IN ws2_32 INTEGER hostshort 
DECLARE INTEGER send IN ws2_32 INTEGER s, STRING @buf,;
    INTEGER buflen, INTEGER flags 
DECLARE INTEGER recv IN ws2_32 INTEGER s, STRING @buf,;
    INTEGER buflen, INTEGER flags 
DECLARE INTEGER connect IN ws2_32 AS ws_connect INTEGER s,;
    STRING @sname, INTEGER namelen

Wenn wir den Mailserver ansprechen wollen, brauchen wir seine IP-Adresse. Die können wir so ermitteln:

PROCEDURE GetHostIP
LPARAMETERS tcHost
LOCAL lnStruct, lnSize, lcBuffer, lnAddr, lcIP 

DECLARE STRING  inet_ntoa IN ws2_32 INTEGER in_addr 
DECLARE INTEGER gethostbyname IN ws2_32 STRING host
DECLARE RtlMoveMemory IN kernel32 As CopyMemory STRING @Dest,;
 INTEGER Src, INTEGER nLength 

lnStruct = gethostbyname(tcHost) 
IF lnStruct = 0 
   RETURN "" 
ENDIF 
lcBuffer = REPLICATE(CHR(0), 16)  
lcIP = REPLICATE(CHR(0), 4) 
= CopyMemory(@lcBuffer, lnStruct, LEN(lcBuffer)) 
= CopyMemory(@lcIP, buf2dword(SUBSTR(lcBuffer,13,4)),4) 
= CopyMemory(@lcIP, buf2dword(lcIP),4) 
RETURN inet_ntoa(buf2dword(lcIP))

Das ist relativ harter Stoff. Von der Sorte kommt gleich noch ein bisschen mehr. Aber wen es beruhigt: Ich kenne mich mit Strukturen + API-Calls auch nicht so aus. Hauptsache, es funktioniert! Genau für den Umgang mit den Strukturen brauchen wir übrigens noch ein paar Hilfs-Funktionen:

FUNCTION buf2dword(lcBuffer) 
RETURN Asc(SUBSTR(lcBuffer, 1,1)) + ; 
    BitLShift(Asc(SUBSTR(lcBuffer, 2,1)),  8) +; 
    BitLShift(Asc(SUBSTR(lcBuffer, 3,1)), 16) +; 
    BitLShift(Asc(SUBSTR(lcBuffer, 4,1)), 24) 

FUNCTION num2dword(lnValue) 
#DEFINE m0  256 
#DEFINE m1  65536 
#DEFINE m2  16777216 
    IF lnValue < 0 
        lnValue = 0x100000000 + lnValue 
    ENDIF 
    LOCAL b0, b1, b2, b3 
    b3 = Int(lnValue/m2) 
    b2 = Int((lnValue - b3*m2)/m1) 
    b1 = Int((lnValue - b3*m2 - b2*m1)/m0) 
    b0 = Mod(lnValue, m0) 
RETURN Chr(b0)+Chr(b1)+Chr(b2)+Chr(b3) 

FUNCTION num2word(lnValue) 
RETURN Chr(MOD(m.lnValue,256)) + CHR(INT(m.lnValue/256))

So, nachdem wir jetzt unser Handwerkszeug zusammen haben, wollen wir doch mal eine Verbindung zu unserem Mailserver aufbauen:

#DEFINE AF_INET        2
#DEFINE SOCK_STREAM    1
#DEFINE IPPROTOCOL_TCP 6
#DEFINE SOCKET_ERROR  -1

lnResult = WSAStartup(0x202, REPLICATE(CHR(0),512))
IF lnResult <> 0 
    *-- Winsock kann auf diesem Rechner nicht initialisiert werden
    RETURN .F. 
ENDIF 

lcHostIP = GetHostIP("pop.kundenserver.de")
IF EMPTY(lcHostIP)
    RETURN .F.
ENDIF

lnPort = 110
lhSocket = socket(AF_INET, SOCK_STREAM, IPPROTOCOL_TCP) 

lcBuffer = num2word(AF_INET) +; 
           num2word(htons(lnPort)) +; 
           num2dword(inet_addr(lcHostIP)) + ;
           REPLICATE(CHR(0),8) 
           
lnResult = ws_connect(lhSocket, @lcBuffer, LEN(lcBuffer))
IF lnResult = 0
    *-- Jetzt sind wir verbunden!
ELSE
    = closesocket(lhSocket) 
ENDIF

Jetzt brauchen wir noch 2 Methoden, und zwar zum Senden der Befehle und zum Empfangen der Antworten:

PROCEDURE SendCmd
LPARAMETERS tcCmd
LOCAL lcBuffer, lnResult, lcResponse 
lcBuffer = tcCmd + CRLF 
lnResult = send(lhSocket, @lcBuffer, LEN(lcBuffer), 0) 
    RETURN (lnResult <> SOCKET_ERROR)
ENDPROC

PROCEDURE ReceiveBlock
LPARAMETERS tnWait
LOCAL lhEventRead, lcRead, lnBytesRead 
lhEventRead = WSACreateEvent() 
= WSAEventSelect(lhSocket, lhEventRead, 1) 
lnEventResult = WSAWaitForMultipleEvents(1, @lhEventRead, 0, tnWait, 0) 
= WSACloseEvent(lhEventRead) 
IF lnEventResult = 0 
    lnBlockSize = 16384
    lcRead = REPLICATE(CHR(0), lnBlockSize) 
    lnBytesRead = recv(lhSocket, @lcRead, lnBlockSize, 0) 
    lcRead = LEFT(lcRead, lnBytesRead) 
ELSE 
    lcRead = "" 
ENDIF 
RETURN lcRead

Damit haben wir jetzt eigentlich alles zusammen, um uns eine schöne kleine POP3-Funktionsbibliothek zusammenzuschrauben.

Und was ist mit SMTeeP ?

Jaja Jungs und Deerns. Das geht natürlich auch. Genauso! Klasse, oder ?

Senden per SMTP (Port 25) RFC 821

HELO

Anmeldung an den SMTP-Server ohne Userverifikation

EHLO

Anmeldung an den Mailserver mit Userverifikation, dann folgt

PASS

Nennung des Passwortes

MAIL FROM:

Den Absender angeben

RCPT TO: </EMPFÄNGERMAIL>

Den Empfänger angeben

DATA

Leitet die Übergabe der eigentlichen Mail ein

.

Schließt die Übergabe der Mail ab

QUIT

Beendet die Kommunikation mit dem Server

Hier ein Beispiel für eine komplette Mail-Sende-Session:

220 post.webmailer.de ESMTP Sendmail 8.9.3/8.8.7; Sat, 2 Nov 2002 16:10:45 +0100 (MET)
HELO weggen
250 post.webmailer.de Hello a81-14-145-12.net-htp.de [81.14.145.12], pleased to meet you
RCPT TO: devcon@weggen.de
250 devcon@weggen.de... Recipient ok
DATA
354 Enter mail, end with "." on a line by itself
Date: Sat, 11 Nov 2005 13:01:22 +0100
Subject: Devcon TestMail
To: "Torsten Weggen" 
From: "Auktionsbuddy" 
Content-Type: text/plain

Hallo liebe Sessionteilnehmer in Frankfurt
.
250 QAA26416 Message accepted for delivery
QUIT
221 post.webmailer.de closing connection</INFO@AUKTIONSBUDDY.DE></DEVCON@WEGGEN.DE>

Was ist eigentlich eine E-Mail ?

Eine E-Mail ist zunächst mal nichts anderes als blanker Text. Allerdings gibt es schon ein paar Vorgaben, wie eine Mail auszusehen hat. So muß die E-Mail zB. ausschließlich aus den ersten 128 Zeichen des ASCII-Zeichensatzes bestehen. Ebenso sollte eine Zeile der E-Mail nicht länger als 76 Zeichen sein. Den zugrunde liegende Standard gibt es schon seit 1982. In diesem Jahr wurde der „Request For Comments (RFC) 822: Standard for the format of ARPA Internet Text Messages“ veröffentlicht. Im Laufe der Jahre wurde dieser Standard aktualisiert durch den „RFC 2822: Internet Message Format“, wobei aber keine fundamentalen Änderungen vorgenommen wurden.

Die Struktur einer Mail ist festgelegt. Jede Mail besteht aus einigen Meta-Datenfeldern (dem Header) sowie der eigentlichen Nachricht (dem Body). Der Body selbst kann wieder aus mehreren Teilen bestehen, den so genannten Parts ( z.B. Mailanhänge, Bilder etc.). Eine Nachricht mit mehreren Parts nennen wir eine „MultiPart“-Nachricht.

Wir schreiben uns jetzt mal eine einfache Mail mit dem Texteditor:

From: "Auktionsbuddy" 
To: "torsten@weggen.de"
Subject: Devcon TestMail
Date: Wed, 11 Nov 2005 11:37:45 +0200
MIME-Version: 1.0
Content-Type: text/plain;
    charset="iso-8859-1"
Content-Transfer-Encoding : 8bit

Hallo liebe Sessionteilnehmer in Frankfurt.</INFO@AUKTIONSBUDDY.DE>

Wenn man diese Textdatei nun mit der Endung .eml abspeichert, und diese dann im Windows-Explorer doppelt anklickt, stellen wir fest, das wir es tatsächlich mit einem waschechten Vertreter der Gattung E-Mail zu tun haben:

E-Mail manuell erstellt

Betrachten wir den Header mal ein wenig genauer:

From: "Auktionsbuddy" 
To: "torsten@weggen.de"
Subject: Devcon TestMail
Date: Wed, 9 Oct 2002 11:37:45 +0200</INFO@AUKTIONSBUDDY.DE>

Hier haben wir erst einmal alle Informationen über Sender, Empfänger, Betreff, sowie das Erstellungsdatum.

MIME-Version: 1.0

Dieses Tag bedeutet, das die Nachricht dem MIME-Standard 1.0 entspricht. MIME wurde eingeführt, um den Einschränkungen der RFC822 Nachrichten auf 7bit ASCII zu entkommen und auch binäre Daten wie z.B. Bilder in die Nachricht zu integrieren. Der MIME-Standard definiert dabei, wie solche Dateien zu kodieren sind .

Content-Type: text/plain;
    charset="iso-8859-1"

Das Content-Type-Tag ist sehr wichtig. Er spezifiziert den so genannten „media-type“ (MIME-Standard) oder einfacher gesagt die Art der Daten. In unserem Fall handelt es sich um einen „text“ mit einem Subtype „plain“, d.h. ein Text ohne besondere Formatierungen. Außerdem liefert der Content-Type über einen weiteren Parameter die Information mit, welcher Characterset hierfür benutzt wird. Dies ist wichtig für den Client, damit die Daten auf die richtige Weise angezeigt werden können (so was wie eine Codepage). Andere Content-Types wären zB. text/html oder image/jpeg

Content-Transfer-Encoding : 8bit

Der zweite Header-Wert gibt Auskunft darüber, auf welche Weise der nachfolgende Text kodiert worden ist, um die Forderung zu erfüllen, das Mails nur die ersten 128 bit des ASCII-Zeichensatzes verwenden dürfen. Hier gibt es hauptsächlich zwei Codierungsmethoden: „quoted-printable“, welches für Text verwendet wird, sowie „base64“ für Binärdaten. Weiteres hierzu gibt’s im nächsten Kapitel.

Handelsübliche Mailclients (hier: Outlook Express) fügen beim Erzeugen noch weitere Header hinzu:

X-Priority: 3
X-MSMail-Priority: Normal
X-Unsent: 1
X-MimeOLE: Produced By Microsoft MimeOLE V6.00.2600.0000

Diese 4 Header fangen alle mit einem “X“ an. Jeder Header, der so anfängt, gehört nicht zu den Standardheadern, die im MIME-Standard definiert sind. Manche von diesen Headern sind aber sehr weit verbreitet und werden allgemein von allen Mailclients akzeptiert.

So finden wir zum Beispiel die Mail-Priorität einmal als allgemeinen Tag, einmal in der MS-Variante hier. Einige Mailclients werten die 1.te, andere wiederum die 2.te Variante aus.

An dem Header X-Unsent können wir sehen, dass die Nachricht bisher noch nicht versendet wurde.

Wenn wir diese Nachricht jetzt versenden, werden von den Mailservern, über die die Nachricht läuft, einige Informationen hinzugefügt.

X-Envelope-From: 
X-Envelope-To: 
X-Delivery-Time: 1034158252
Received: from moutvdom.kundenserver.de (moutvdom.kundenserver.de [195.20.224.130])
    by mailin.webmailer.de (8.9.3/8.8.7) with ESMTP id MAA20402
    for ; Wed, 11 Nov 2005 12:10:52 +0200 (MET DST)
Received: from [195.20.224.214] (helo=mrvdomng.kundenserver.de)
by moutvdom.kundenserver.de with esmtp (Exim 3.35 #1)
id 17zDnn-0004xM-00
for torsten@weggen.de; Wed, 11 Nov 2005 12:10:51 +0200
Received: from [80.134.38.17] (helo=entw001)
by mrvdomng.kundenserver.de with smtp (Exim 3.35 #1)
id 17zDnn-0002ov-00
for torsten@weggen.de; Wed, 11 Nov 2005 12:10:51 +0200
Message-ID: <002a01c26f7c$2688c2c0$016fa8c0@entw001></TORSTEN@WEGGEN.DE></TORSTEN@WEGGEN.DE></INFO@AUKTIONSBUDDY.DE>

Wir können also in einer empfangenen Mail zusätzlich erkennen, wann und über welche Server die Mail versendet wurde.

Die X-Delivery-Time zeigt uns in diesem Fall den Zustellzeitpunkt in vergangenen Sekunden seit dem 1.1.1970, in diesem Fall also: {^1970-1-1 0:00:00} + 1034158252 à {^2002-10-09 10:10:52}

Wir können im übrigen eigene X-Tags selbst einfügen. So ist zB: folgendes durchaus zulässig:

X-Mailer: Mein völlig abgefahrener Privat-Mailer V.1.3.3

Merke: Der Header der Mail endet immer mit einer kompletten Leerzeile.

Die Kodierungen in E-Mails

Zunächst einmal gibt’s hier zwei Kodierungen, die relativ simpel sind

7bit

Der komplette Mailtext besteht nur aus Zeichen der ASCII-Codes 1-128

8bit

Der komplette Mailtext besteht aus den ASCII-Zeichen 1 – 256, also auch mit Umlauten.

Hier brauchen wir zum Lesen nichts extra dekodieren. Das ist recht praktisch ;-) Die Kodierung 8bit entspricht aber eigentlich nicht dem Standard.

Um trotzdem die ASCII-Zeichen 128 – 256 benutzen zu können, wurde die Kodierung quoted-printable geschaffen.

quoted-printable

Alle Zeichen oberhalb von 127 werden hier durch das Gleich-Zeichen und der Ordnungszahl im Hex-Format ersetzt. So wird aus ß die Zeichenkette =DF. Außerdem wird eine Zeile, die länger als 74 Zeichen ist, nach 75 Zeichen mit einem =-Zeichen beendet und in der nächsten Zeile fortgesetzt.

Ein Beispiel:

Heute wollen wir Ihnen in Frankfurt lieber nur Käsebrötchen servieren, 
da durch die extreme Gewichtszunahme der Teilnehmer leider die Statik 
des Hotels gefährdet ist

wird zu:

Heute wollen wir Ihnen in Frankfurt lieber nur K=E4sebr=F6tchen =
servieren, da durch die extreme Gewichtszunahme der Teilnehmer leider =
die Statik des Hotels gef=E4hrdet ist

Aus Gründen der Lesbarkeit hat Outlook Express die Zeilenumbrüche hier an die Wortgrenzen gesetzt und nicht die vollen 76 Zeichen Zeilenlänge ausgeschöpft

Als letzte der häufig in E-Mails verwendeten Kodierungen haben wir die base64 – Kodierung, die immer dann verwendet wird, wenn wir Binärdaten per E-Mail verschicken wollen:

Base64

Die komplette Datei wird base64-Kodiert. Die Zeilenlänge von 76 Zeichen wird eingehalten.

Das sieht dann irgendwie so aus:

R0lGODlhlgCCANUAAIdZMP7o9vTLqf/0+5FiOax4SbaIYGY5FJZsR3RJJtCnjfnU59CYa2lDI9Ky
pv7e8lo1GXJDGScPB//w2H1VM7KNe2ZTUFs6IKJsP0YqFuXDyH1RKwkCAuvG1f/96YhNGvzcwZF3
dEoiBMCchmM+IEEUAOG4mVclA+7U1zkgEd28vfTU3+3Pual+YFAyHGxIK+/M2fXQ43ROLe7Iy1At
E+XBqTgqLIZfPVZANHk8Bm9SOWUwBJlgMAcwXP////7W7yH5BAAAAAAALAAAAACWAIIAAAb/QJ9w
6Av8jsikcslsOp/QqHRKrS6JQqN1y+16v+AjVhsum8/oKHHwSLvf8C+RHK/b78khG8/vv/V+gYJg
usw.
Foxpro kann das auch

Base64 enkodieren und dekodieren kann Foxpro sogar nativ, und zwar so:

STRCONV(tcSourceText,13) zum Enkodieren 
STRCONV(tcSourceText,14) zum Dekodieren

Für Quoted-Printable-Kodierung müssen wir leider selber etwas Code schreiben, aber allzu kompliziert ist das auch nicht:

PROCEDURE DecodeQuotedPrintable
    lcDecText = tcEncText
    *-- Erst mal alle "="+CHR(13)+CHR(10) durch "" ersetzen 
    lcDecText = STRTRAN(lcDecText,"="+CHR(13)+CHR(10),"")
    *-- alle restlichen „=“ ersetzen durch |
    lcDecText = STRTRAN(lcDecText,"=","|")
    *-- Jetzt alle ASCII-Zeichen (=HexHex) wandeln
    DO WHILE ATC("|",lcDecText) > 0
        lcConv = SUBSTR(lcDecText,ATC("|",lcDecText)+1,2)
        TRY        
            lcDecText = STRTRAN(lcDecText,"|" + lcConv,CHR(EVALUATE("0x"+lcConv)))
        CATCH
            lnAtc = ATC("|",lcDecText)
            lcDecText = LEFT(lcDecText,lnAtc-1) + SUBSTR(lcDecText,lnAtc + 1)
        ENDTRY
    ENDDO
    RETURN lcDecText
ENDPROC

PROCEDURE EncodeQuotedPrintable
    lcText = ""
    *-- Zunächst einmal laufen wir durch alle Zeichen durch und ersetzen alle 
    *-- ASCII-Zeichen größer 128
    FOR lnLoop = 1 TO LEN(tcDecText)
        lcChar = SUBSTR(tcDecText,lnLoop,1)
        IF ASC(lcChar) < 129
            lcText = lcText + lcChar
        ELSE
            lcText = lcText + "=" + RIGHT(TRANSFORM(ASC(lcChar),"@0"),2)
        ENDIF
    ENDFOR
    *-- Jetzt müssen wir noch Zeilen länger als 76 Zeichen splitten
    lcEncText = ""
    lnZeilen = ALINES(laZeilen,lcText)
    FOR lnLoop = 1 TO lnZeilen
        lcZeile = laZeilen[lnLoop]
        DO WHILE LEN(lcZeile) > 76
            lnWordCount = GETWORDCOUNT(LEFT(lcZeile,76))
            lnAtPos = ATC(" ",lnWordCount-1)
            lcEncText = lcEncText + LEFT(lcZeile,lnAtPos) + ”=” + CHR(13)+CHR(10)
            lcZeile = SUBSTR(lcZeile,lnAtPos + 1)
        ENDDO
        lcEncText = lcEncText + lcZeile + CHR(13)+CHR(10)
    ENDFOR
    RETURN lcEncText
ENDPROC

Gemein ist leider, dass der Betreff einer Mail genauso wie der Mailtext kodiert sein kann. Da der Betreff aber immer in einer Zeile steht, hat man sich da eine ganz besondere Syntax ausgedacht:

=?iso-8859-1?Q?M=E4chtige_Schlemmerei_bei_Devcon_05?=

Das =-Zeichen, gefolgt vom Fragezeichen, leitet ein kodiertes Fragment ein. Es folgt (kann aber auch weggelassen werden) die Bezeichnung des Zeichensatzes. Nach dem nächsten Fragezeichen finden wir die Kodierungs-Methode. „Q“ steht hier für Quoted-Printable und „B“ für base64. Zwischen den beiden folgenden „?=“ befindet sich der kodierte Bereich.

Es ist übrigens möglich, das ein Betreff mehrere kodierte + unkodierte Bereiche hat, wobei die kodierten Bereiche prinzipiell auch noch mit unterschiedlichen Verfahren kodiert sein können.

Unser obenstehendes Beispiel bedeutet also nichts anderes als folgendes:

Mächtige Schlemmerei bei Devcon 05

Das können wir natürlich auch! So geht’s mit Foxpro:

PROCEDURE DecodeSubject
    LPARAMETERS tcText
    lcReturn = ""
    lcText = tcText
    lnStartPos = ATC("=?",tcText)
    lnEndPos   = ATC("?=",tcText)
    IF ATC("?Q?",lcText)+2 = lnEndpos OR ATC("?B?",lcText)+2 = lnEndpos
        lnEndPos = ATC("?=",lcText,2)
    ENDIF
    IF lnStartPos > 0 AND lnEndPos > 0
        *-- Jetzt ermitteln wir die unkodierten Teile
        lcPre = LEFT(lcText,lnStartPos - 1)
        lcPost = SUBSTR(lcText,lnEndPos + 2)
        *-- und den codierten
        lcEncoded = SUBSTR(lcText,lnStartPos+2,lnEndPos-lnStartPos-2)
        *-- mit welcher Methode wurde codiert ?
        lnQuotedPos = ATC("?Q?",UPPER(lcEncoded))
        lnBase64Pos = ATC("?B?",UPPER(lcEncoded))
        DO CASE
            CASE lnQuotedPos > 0 && Quoted_printable
                lcEncodedText = SUBSTR(lcEncoded,lnQuotedPos + 3)
                lcEncodedText = STRTRAN(lcEncodedText,"_"," ")
                lcDecodedText = DecodeQuotedPrintable(lcEncodedText)
            CASE lnBase64Pos > 0 && Base64
                lcEncodedText = SUBSTR(lcEncoded,lnBase64Pos + 3)
                lcDecodedText = STRCONV(lcEncodedText,14)
            OTHERWISE
                *-- Wir konnten das Verfahren nicht feststellen
                RETURN lcText
        ENDCASE
        lcReturn = lcPre + lcDecodedText + lcPost
        IF ATC("=?",lcReturn) > 0 AND ATC("?=",lcText) > 0
            lcReturn = THIS.DecodeSubject(lcReturn)
        ENDIF
    ELSE
        lcReturn = lcText
    ENDIF
    *-- Jetzt werfen wir,falls vorhanden, noch CR,LF,TAB und CHR(0) raus
    lcReturn = ALLTRIM(CHRTRAN(lcReturn,CHR(13)+CHR(10)+CHR(9)+CHR(0),""))
RETURN lcReturn
ENDPROC

Noch ein wichtiges Codefragment: Wie bestimme ich, ob eine E-Mailadresse gültig ist ? Das geht am besten mit regulären Ausdrücken. Welches allerdings das optimale ist, darüber streiten sich die Geister im Internet. Als in der Praxis relativ gut geeignet hat sich folgender Ausdruck herausgestellt:

PROCEDURE IsValidEmail
    LPARAMETERS tcEmail

    TEXT TO lcPattern NOSHOW 
    ^((([\t\x20]*[!#-'\*\+\-/-9=\?A-Z\^-~]+[\t\x20]*|
""[\x01-\x09\x0B\x0C\x0E-\x21\x23-\x5B\x5D-\x7F]*"")+
)?[\t\x20]*<([\t\x20]*[!#-'
\*\+\-/-9=\?A-Z\^-~]+ (\.[!#-'\*\+\-/-9=\?A-Z\^-~]+)*|""[\x01-\x09\x0B\x0C
\x0E-\x21\x23-\x5B\x5D-\x7F]*"")@(([a-zA-Z0-9][-a-zA-Z0-9]*
[a-zA-Z0-9]\.)+[a-zA-Z]{2,}|\[(([0-9]?[0-9]|1[0-9][0-9]|
2[0-4][0-9]|25[0-5])\.){3}([0-9]?[0-9]|1[0-9][0-9]|
2[0-4][0-9]|25[0-5])\])>[\t\x20]*|([\t\x20]*
[!#-'
\*\+\-/-9=\?A-Z\^-~]+(\.[!#-'\*\+\-/-9=\?A-Z\^-~]+)*| ""[\x01-\x09\x0B\x0C\x0E-\x21\x23-\x5B\x5D-\x7F]*"")@ (([a-zA-Z0-9][-a-zA-Z0-9]*[a-zA-Z0-9]\.)+[a-zA-Z]{2,}| \[(([0-9]?[0-9]|1[0-9][0-9]|2[0-4][0-9]|25[0-5])\.){3} ([0-9]?[0-9]|1[0-9][0-9]|2[0-4][0-9]|25[0-5])\]))$ ENDTEXT lcPattern = STRTRAN(lcPattern,CHR(13)+CHR(10),"") loRegEx = CreateObject("VBScript.RegExp") loRegEx.pattern = lcPattern loRegEx.ignoreCase = .T. RETURN loRegEx.test(tcEmail) ENDPROC


Ihr Name:
Gravatar Preview
Ihre E-Mail-Adresse:
(Optional) Geben Sie Ihre E-Mail-Adresse an, um ein Gravatar-Bild festzulegen.
Ihre Web-Site:
Überschrift:
Kommentar:
Sicherheitscode
CAPTCHA image
Geben Sie die angegebenen Zeichen darunter ein.
Kommentar hinzufügen   abbrechen 
 
 Copyright 2010 by indisoftware GmbH   Nutzungsbedingungen  Datenschutzerklärung  Impressum