2016-03-30 5 views
0

Ich versuche, zu extrahieren, eine Nachricht rom mehrteiligen E-Mail Körper zu extrahieren oder aus Befestigung, so dass ich verwendet:Wie E-Mail Körper und Anhang

msgID="" 

#extract message in the attachment if it's plain text 
:0B 
* ^Content-Disposition: *attachment.*(($)[a-z0-9].*)*($)($)\/[a-z0-9+]+=* 
{msgID="$MATCH"} 

#extract message in the body if it's there 
:0EB 
* ^()\/[a-z]+[0-9]+[^\+] 
{msgID = "$MATCH"} 

Aber msgID bekam: 0B jede Option wie folgt zu versuchen, die gleiche Nachricht vom Körper, die Inline-Bild-Code war, was ist falsch daran, wer weiß die bessere Bedingung, um es zu filtern?

Ich muss auch erkennen, ob der Unter Header im Text und base64 ist codiert, dann entschlüsseln, wie man es vor, mit regex:

:0B 
* ^Content-Type:text/html; 
* ^Content-Location:text_0.txt 
* ^Content-Transfer-Encoding:base64 
* ^Content-Disposition: *attachment.*(($)[a-z0-9].*)*($)($)\/[a-z0-9+]+=* 
{ msgID= msgId =`printf '%s' "$MATCH" | base64 -d` } 

Es beschwert sich immer keine Übereinstimmung: ^Content-Type:text/html;

+0

Ihre Frage und Titel besagt, dass Sie einen Körper und Anhang extrahieren möchten, aber der Code, den Sie zeigen, versucht nicht, so etwas zu tun. Sie sollten eine einfache Beispielnachricht einfügen, die sich nicht so verhält, wie Sie es erwarten, und uns auch zeigen, was genau Sie zu extrahieren versuchen. – tripleee

+0

Auch, warum erwarten Sie (fast) die gleiche Regex nicht den gleichen Text? – tripleee

+0

Wie schon wiederholt erwähnt, (der letzte Teil von) meine Antwort auf Ihre vorherige fast identische Frage http://stackoverflow.com/a/32733374/874188 erläutert, wie zu finden, wenn ein Anhang Base64-codiert ist und wie dann dekodiere den extrahierten Text. – tripleee

Antwort

1

Ich bin Raten Sie versuchen zu sagen, gibt es zwei Arten von eingehenden Nachrichten. Man sieht in etwa wie folgt aus:

From: Sender <[email protected]> 
To: You <[email protected]> 
Subject: plain text 

ohmigod0 

Und das andere ist ein komplexes MIME Multipart mit dem gleichen Inhalt:

From: Sender <[email protected]> 
To: Amy X <[email protected]> 
Subject: MIME complexity 
MIME-Version: 1.0 
Content-Type: multipart/related; boundary=12345 

--12345 
Content-type: text/plain; charset="us-ascii" 
Content-transfer-encoding: base64 
Content-disposition: attachment; filename="text_0.txt" 
Content-location: text_0.txt 

b2htaWdvZDA= 
--12345-- 

Wenn dies richtig ist, würden Sie wollen, ein Rezept zu erstellen, die komplexer zu handhaben Fall zuerst, weil es mehr Funktionen hat - wenn Ihre Regex trifft, ist es unwahrscheinlich, dass sie falsch positiv sind. Wenn nicht, greifen Sie auf das einfachere Muster zurück und nehmen Sie an, dass es niemals falsche positive Ergebnisse geben wird (vielleicht, weil dieses Konto nur E-Mails von einem einzigen System erhält).

# extract message in the attachment if this is a MIME message 
:0B 
* ^Content-Disposition: *attachment.*(($)[a-z0-9].*)*($))($)\/[a-z0-9+]+=* 
{ msgID="$MATCH" } # hafta have spaces inside the braces 

:0EB # else, do this: assume the first non-empty body line is msgID 
* ^()\/[a-z]+[0-9]+[^\+] 
{ msgID="$MATCH" } # still need spaces inside braces; 
# ... and, as pointed out many times before, cannot have spaces 
# around the equals sign 

Der reguläre Ausdruck für die Befestigung ist eine grobe Vereinfachung, aber ich Ihnen bereits gezeigt, wie man mit einer komplexen MIME-Nachricht in a previous question of yours fertig zu werden - wenn Sie mehrere Fälle haben (beispielsweise Base64-codierte Anlage, oder einfach nur ein Klartext-Anhang, oder kein MIME), würde ich sie von komplexerem anordnen (was mehr Funktionen in der Regex bedeutet) und sukzessive auf einfachere Regexes zurückgreifen, mit einer höheren Wahrscheinlichkeit von falsch-positiven Ergebnissen. Sie können :0E ("else") Fälle so lange verketten, wie Sie möchten - wenn eine Regex erfolgreich ist und die folgenden Rezepte :0E Rezepte sind, werden sie alle übersprungen.


Als Antwort auf Ihr Update gibt es zwei Probleme mit Ihrem Versuch. Die erste, wie Sie bemerken, ist, dass die erste Regex nicht übereinstimmt. Sie haben nach dem Doppelpunkt keinen Platz mehr, und ich vermute, dass es in der Nachricht, gegen die Sie einen Treffer erhalten, einen gibt. Sie müssen verstehen, dass jedes Zeichen in einer Regex exakt übereinstimmen muss, mit Ausnahme von Regex-Metazeichen, die eine besondere Bedeutung haben. Sie würde in der Regel so etwas wie dies in vielen Procmail Rezepte sehen:

* ^Content-Type:[ ]*text/html; 

wo die Abstände zwischen den eckigen Klammern ein Raum und ein Register sind. Die Zeichenklasse (das Zeug in den eckigen Klammern) stimmt mit jedem Zeichen einmal überein, und das Sternchen * sagt, um dieses Muster Null oder mehrere Male zu wiederholen. Dies ermöglicht einen willkürlichen Abstand nach dem Doppelpunkt. Die eckigen Klammern und der Stern sind Metazeichen. (Dies ist eine sehr einfache Sache, die in jeder Procmail-Einführung enthalten sein sollte, die Sie gelesen haben.)

Ihr anderes Problem ist, dass jeder Regex isoliert angewendet wird. Also Ihr Rezept sagt, wenn die Content-Type Header erscheint überall in den Körper, und die Content-Location Header erscheint überall sonst (in der Regel in einem anderen MIME-Header irgendwo) usw.Mit anderen Worten, Ihr Rezept ist sehr anfällig für Fehlalarme. Deshalb ist die Regel, die ich zuvor vorgeschlagen habe, so komplex: Sie sucht diese Header nacheinander in einem einzigen Block, dh in einem einzelnen MIME-Header (obwohl es nichts gibt, um sicherzustellen, dass der Kontext ein MIME ist Körperteil Header; mehr dazu in einem Bit).

Weil wir sicherstellen wollen, dass es vier verschiedene Header sind, in beliebiger Reihenfolge, die Regex dafür wird riesig sein: ABCD|ACDB|ACDB|ABDC|ADCB|BACD|... wobei A die Content-Type Header regex, B ist die Content-Location regex, etc. Sie betrügen könnte eine kleine Bit und Fertigkeit eine einzige Regex, die eine Sequenz von vier Übereinstimmungen der gleichen Header-Identifizierung Regex - dies ist unwahrscheinlich, dass keine falschen positiven (es gibt keinen Grund, zwei Kopien der gleichen Header haben) und vereinfacht den Code erheblich, obwohl es immer noch komplex ist. Beachten Sie hier: Wir möchten einen einzelnen Regex erstellen, der mit einem dieser vier Header übereinstimmt.

^Content-(Type:[ ]text/plain;|\ 
      Location:[ ]*text_0\.txt|\ 
      Transfer-Encoding:[ ]*base64|\ 
      Disposition:[  ]*attachment) 

... von jedem Kopfball, viermal wiederholt, mit dem MIME-Körperteil gefolgt (die Sie nach dem Content-Disposition Kopf hatten, etwas aus dem Zusammenhang gerissen, aber nicht per se falsch).

(Ihr Code hat text/html aber wenn die Anlage nicht HTML ist, wie durch das Format und die Dateinamen vorgeschlagen, soll es text/plain sein, so dass ich mit, dass stattdessen werde.)

Bevor wir dorthin gehen Ich möchte darauf hinweisen, dass das MIME-Parsen in Procmail nicht sehr oft durchgeführt wird, gerade weil es dazu neigt, zu enorm komplexen regulären Ausdrücken zu explodieren. MIME hat viele Optionen, und Sie brauchen jede Regex, um das Auslassen oder Einschließen jedes optionalen Elements zu ermöglichen. Es gibt Optionen zum Codieren von Dingen (base64, oder quoted-printable, oder überhaupt nicht codiert) und Optionen zum Einschließen oder Auslassen von Anführungszeichen um viele Elemente und Optionen zum Verwenden einer mehrteiligen Nachricht mit einem oder mehreren Körperteilen oder einfach zum Einfügen der Daten der Körper, wie in meinem ersten Beispiel Nachricht (die immer noch technisch eine MIME-Nachricht ist, ist die implizierte Inhaltstyp text/plain; charset="us-ascii" und die Standard-Content-Transfer-Codierung ist 7bit, was zufällig passiert, was E-Mail vor MIME immer aussehen musste).

Also, wenn Sie in diese sind, weil (a) Sie wirklich, wirklich die tiefsten Geheimnisse der Procmail lernen wollen oder (b) Sie auf einem sehr eingeschränkten System, wo Sie zu haben, weil es nichts anderes, was Sie verwenden können, würde ich ernsthaft vorschlagen, dass Sie in eine Sprache mit einem richtigen MIME-Parser bewegen. Ein Python-Skript, das dies decodiert, wäre nur ein halbes Dutzend Zeilen oder so, und Sie erhalten alles normalisiert und entschlüsselt für Sie, ohne dass Sie in Anführungszeichen gedruckte Dekodierung oder Zeichensatz-Übersetzung neu erfinden müssen. (Sie können das Python-Skript immer noch von Procmail aus aufrufen.)

Ich werde hier auch darauf hinweisen, dass ein richtiger MIME-Parser den boundary=-Parameter aus den Kopfzeilen der obersten Ebene in einer mehrteiligen Nachricht extrahiert und sicherstellt Alle Übereinstimmungen in Textteil-Headern erfolgen nur unmittelbar nach einem Trennzeichen. Der folgende Procmail-Code tut das nicht, daher könnten wir einen falschen positiven Wert erhalten, wenn eine Nachricht irgendwo anders als in den MIME-Hauptteil-Headern eine Übereinstimmung enthält (z. B. wenn eine Bounce-Nachricht ein Fragment der MIME-Header von enthält) die gebouncte Nachricht; in diesem Fall möchten Sie, dass das Rezept nicht übereinstimmt, aber es wird).

:0B 
* ^(Content-(Type:[  ]text/plain;|\ 
      Location:[ ]*text_0\.txt|\ 
      Transfer-Encoding:[ ]*base64|\ 
      Disposition:[  ]*attachment).*(($)[a-z0-9].*)*)($)\ 
    (Content-(Type:[ ]text/plain;|\ 
      Location:[ ]*text_0\.txt|\ 
      Transfer-Encoding:[ ]*base64|\ 
      Disposition:[  ]*attachment).*(($)[a-z0-9].*)*)($)\ 
    (Content-(Type:[ ]text/plain;|\ 
      Location:[ ]*text_0\.txt|\ 
      Transfer-Encoding:[ ]*base64|\ 
      Disposition:[  ]*attachment).*(($)[a-z0-9].*)*)($)\ 
    (Content-(Type:[ ]text/plain;|\ 
      Location:[ ]*text_0\.txt|\ 
      Transfer-Encoding:[ ]*base64|\ 
      Disposition:[  ]*attachment).*(($)[a-z0-9].*)*)($)\ 
    ($)\/[a-z0-9/+]+=* 
{ msgid=`printf '%s' "$MATCH" | base64 -d` } 

:0BE 
* ^^\/[a-z]+[0-9]*[^\+] 
{ msgid="$MATCH" } 

(Leider hat Procmail die Regex-Engine die {4} Wiederholungsoperator nicht haben, so haben wir die Regex buchstäblich viermal wiederholen!)

Wie bereits erwähnt, Procmail leider nicht weiß, irgendetwas über MIME. Soweit es Procmail betrifft, sind die Kopfzeilen der obersten Ebene Header, und alles andere ist Rumpf. Es gab Versuche, MIME-Bibliotheken oder -Erweiterungen für Procmail zu schreiben, aber sie reduzieren die Komplexität nicht, sondern mischen sie nur herum.

+0

Danke! Wie erkenne ich base64-kodierte Anhänge? SEHE den modifizierten Beitrag. Ich denke, es ist besser, sie nach *^Content-Type zu filtern: text/html, dann weiter *^..., aber ich übergebe nie die erste Bedingung für den Inhaltstyp, noch die Regex, die du mir zuvor mit vier Zeilen gegeben hast. @tripeee –

Verwandte Themen