Was hat es mit all diesen Gleichheitszeichen (=) auf sich?
(lars.ingebrigtsen.no)- Kürzlich verbreiteten sich auf Twitter Zitate aus alten E-Mails, wodurch die Frage aufkam, warum am Satzende Gleichheitszeichen (=) erscheinen
- Diese Zeichen entstehen im Zuge der „quoted-printable“-Kodierung und dienen dazu, beim erzwungenen Umbrechen langer Zeilen anzuzeigen, dass die Zeile fortgesetzt wird
- Beim E-Mail-Transport wird CRLF (Carriage Return + Line Feed) als Zeilenumbruch verwendet; wird dies in Unix-NL umgewandelt, können bei fehlerhaft arbeitenden Dekodieralgorithmen Gleichheitszeichen zurückbleiben oder Zeichen verloren gehen
- Das Gleichheitszeichen wird außer für Zeilenumbrüche auch zur Darstellung von Nicht-ASCII-Zeichen (z. B.
=C2=A0) verwendet; fehlerhafte Decoder ersetzen dies nur simpel und verursachen so Fehler - Die Ursache des Problems liegt in fehlerhafter Dekodierlogik und ungeeigneter Konvertierungsbehandlung, was zeigt, dass die Person, die die E-Mails verarbeitet hat, technisch nicht besonders versiert war
Die Bedeutung der Gleichheitszeichen (=) in E-Mail-Zitaten
-
In den letzten Tagen wurden auf Twitter zahlreiche alte E-Mail-Zitate geteilt, bei denen die Gleichheitszeichen am Satzende auffielen
- Der Autor widerspricht Behauptungen, dies sei ein Code- oder OCR-Fehler (optische Zeichenerkennung)
- Tatsächlich handelt es sich um einen Fehler bei der Kodierungsverarbeitung, der beim Umwandeln in ein besser lesbares Format entstanden ist
-
E-Mails waren früher einfacher Text, doch zur Verarbeitung langer Zeilen und von Sonderzeichen wurde die „quoted-printable“-Kodierung eingeführt
- Beim Aufteilen langer Zeilen wird am Zeilenende ein Gleichheitszeichen (=) angehängt, um zu markieren: „Diese Zeile wird fortgesetzt“
- Auf das Gleichheitszeichen folgt dabei CRLF (Carriage Return + Line Feed)
Fehler bei Zeilenumbruch-Kodierung und -Dekodierung
-
E-Mail-Server verwenden standardmäßig CRLF als Zeilenumbruch, Unix-Systeme dagegen nur NL
- Bei der Umwandlung geht ein Byte verloren; verarbeitet der Decoder dies falsch, bleiben Gleichheitszeichen stehen oder Zeichen verschwinden
- Beispiel: Wenn „non- =CRLF cloven“ falsch verarbeitet wird, kann daraus „non- loven“ werden, wobei das „c“ verschwindet
-
Manche Implementierungen verarbeiten ein Gleichheitszeichen am Zeilenende, indem sie einfach zwei Zeichen löschen
- Dieser Algorithmus funktioniert bei Dateien im Unix-Format fehlerhaft, sodass Gleichheitszeichen unverändert stehen bleiben
Ein weiterer Zweck des Gleichheitszeichens: Nicht-ASCII-Zeichen kodieren
-
Das Gleichheitszeichen wird nicht nur für Zeilenumbrüche, sondern auch zur Kodierung von Nicht-ASCII-Zeichen verwendet
- Beispiel:
=C2=A0steht für ein geschütztes Leerzeichen (non-breaking space) - In E-Mail-Texten taucht dies häufig bei Einrückungen oder zur Darstellung von Sonderzeichen auf
- Beispiel:
-
Der Autor vermutet, dass einige Konvertierungsprogramme
=C2,=A0usw. nur per einfacher Suche-und-Ersetzen-Logik verarbeitet haben, anstatt einen korrekten Decoder zu verwenden
Technischer Hintergrund und Standard
-
Der Standard RFC 2045 definiert die quoted-printable-Kodierung als Transportformat
- Nach dem Empfang sollte sie dekodiert und als sauberer Text gespeichert werden
- In realen Implementierungen wird dieser Schritt jedoch oft ausgelassen, wodurch Fehler bei der Zeilenumbruch-Behandlung häufig auftreten
-
Im Beispielcode wird
(quoted-printable-decode-string "he=\nllo")korrekt zu"hello"rekonstruiert- Der Grund ist die Wiederverwendung eines Algorithmus, der im Kontext von SMTP-Servern von CRLF ausgeht
- Bei Windows-basierten Dateien funktioniert das korrekt, bei Unix-basierten hingegen nicht
Fazit
- Die Gleichheitszeichen in E-Mail-Zitaten sind Überreste der quoted-printable-Kodierung und das Ergebnis einer Kombination aus
fehlerhafter Zeilenumbruch-Behandlung und mangelhafter Dekodierung von Nicht-ASCII-Zeichen - Die eigentliche Ursache des Problems sind ungenaue Decoder-Implementierungen und Fehler bei der Kodierungskonvertierung
- Der Autor fasst dies als „technisches Problem und Ergebnis fehlerhafter Verarbeitung“ zusammen und betont, wie wichtig eine präzise Einhaltung der Standards bei der E-Mail-Konvertierung ist
1 Kommentare
Hacker-News-Kommentare
Der Protagonist dieses Artikels ist Lars Ingebrigtsen, der Autor des Handbuchs für Gnus, das E-Mail-/Usenet-Reader-Paket von Emacs
Sein Handbuch ist geistreich und informativ, und er hat ein viel tieferes Verständnis vom E-Mail-Parsing als die meisten anderen
Das Handbuch ist hier zu finden, eine weitere Version gibt es unter diesem Link
Ich erinnere mich noch an die Zeit, als er Gnus an der Universität Oslo (UiO) zum ersten Mal entwickelte
Unter den Informatikstudierenden bei uns war er so eine Art kleiner Star-Entwickler, und alle nutzten Emacs und Gnus
Dieser Vorfall ist ein typisches Beispiel für jemanden, der "gefährlich viel weiß"
Man wusste zwar, dass E-Mail nicht einfach nur Klartext ist, aber nicht, dass man quoted-printable-Decoding nicht mit einer simplen Ersetzung behandeln darf
Es ist dieselbe Art von Bug wie HTML direkt mit regulären Ausdrücken zu parsen: Erst scheint alles zu funktionieren, und später tauchen in Beweisstücken vor dem Kongress plötzlich massenhaft '='-Zeichen auf
Es gab die Frage: "Warum hassen Mailserver lange Zeilen?"
Der Server muss die Header parsen und kann die Nachricht deshalb nicht einfach als binären Blob behandeln
Bei IMAP muss der Server vollständig parsen, und POP3 ist auf ein einzelnes Gerät ausgelegt und passt heute nicht mehr richtig
RFC 821 begrenzte die Zeilenlänge auf maximal 1000 Byte, und aus Kompatibilitätsgründen war es üblich, bei 80 Zeichen oder weniger umzubrechen
Deshalb fügt auch die Base64-Kodierung nach jeweils 76 Zeichen einen Zeilenumbruch ein
Ein PDP-11 hatte zum Beispiel rund 512 KB, ein VAX-11 etwa 2 MB, und Programmierer rechneten Speicher auf Byte-Ebene
HELO,MAIL FROM,RCPT TO,DATAusw. aufgebaut istRelevante Dokumente finden sich in der offiziellen IBM-Dokumentation und auf Wikipedia
Zunächst dachte man, der Artikel würde von der Bedeutung von Operatoren wie
= == === .=. <== ==> <<== ==>> (==) => =~=handelnIch persönlich habe einmal selbst Software zur E-Mail-Archivierung entwickelt
Am schwierigsten war der Umgang mit Edge Cases in .eml-Dateien, die sich über mehr als 20 Jahre angesammelt hatten
Das Konzept ist einfach, aber E-Mail ist erstaunlich komplex
Selbst die Validierung von E-Mail-Adressen ist praktisch kaum wirklich möglich
Es gab über mehrere Jahre hinweg einige wenige Nutzer, aber die MIME-Verarbeitung war der größte Schmerzpunkt
Was ich interessant fand, war weniger das '='-Zeichen selbst als vielmehr das Phänomen, dass die umliegenden Zeichen verschwinden
Fast wie bei einem Off-by-one-Fehler wurde nicht nur '=' entfernt, sondern offenbar auch ein Teil des eigentlichen Textes
Möglicherweise hängt das mit einer CRLF/LF-Konvertierung zusammen
Man fragte sich, warum dieses Problem gerade jetzt auftaucht
In den letzten Tagen haben Leute alte E-Mails auf Twitter gepostet, und die Frage war, weshalb
Jemand brachte die Möglichkeit ins Spiel, dass die Ursache nicht Gmail, sondern eine Umwandlung auf einem Zwischenserver sein könnte
Neben einer CRLF→LF-Konvertierung können auch bei doppelt angewendetem quoted-printable verbleibende '='-Zeichen auftreten, daher könnten zwei Mailserver beteiligt gewesen sein
In der Praxis sammelt oft ein fachfremder Praktikant die Daten mit simplen Tools, sie werden mehrfach konvertiert, und das Format geht kaputt
Das Original ist bereits vernichtet, und übrig bleiben nur noch fragmentierte Daten mit bloß erhaltener Form
Der Artikel auf archive.today zeigt dieselbe beschädigte quoted-printable-Darstellung
Relevante Links sind pastes.io/correspond und der HN-Thread
Jemand meinte, beim Anzeigen aus Outlook heruntergeladener Mails wäre ein .eml-Viewer hilfreich, der quoted-printable automatisch decodiert