PDA

Archiv verlassen und diese Seite im Standarddesign anzeigen : Mail-Info Backup



mex
17-08-2007, 10:55
Moin zusammen,

ich habe mal eine Frage an Euch. Ich mache hier von unseren Daten und natürlich auch von den E-Mail täglich ein Backup. Das ganze wird ordentlich geloggt damit ich nachschauen kann welche Daten auf dem Backup sind. Das habe ich bis jetzt aber nur für allgemeine Daten gemacht nicht aber für die Mails. Das Backup wird mit einem selbst geschriebenen Script gemacht welches über ein cronjob aufgerufen wird.
Das Problem was ich habe ist Postfix scheibt die Mails an sich ja einfach als Datei(z.B. "154." ) auf die Platte, wenn ich mir davon ne liste ausgeben lasse bringt mich das ja nicht wirklich weiter, wenn ein user eine Speziele Mail wieder haben will. Also muss ich zumindest die Infos "From", "Subject", "Date" und "To" auslesen um überhaupt eine zuordnung machen zu können. Dazu noch die Dateiname und den Pfad.
So die Sache ist ich bräuchte eine recht schlanke Lösung da das Backup an sich schon recht lange braucht. Hat da jemand ne Idee oder Erfahrung mit. Bin für jede Idee Dankbar.

mfg

mex

System:
SuSE 10
Postfix, cyrus und spamd

jan61
18-08-2007, 01:54
Starte vor dem Backup ein Perl-Script, das Dir die gewünschten Daten aus den Mailordnern zieht und in eine separate Liste (am besten pro User eine) schreibt. Damit hast Du zwar ein kleines Zeitloch (es können ja Mails eintrudeln zwischen dem Start des Scripts und dem Start des Backups), aber das sollte zu verschmerzen sein - Perl ist ziemlich fix.

Wenn Du Dich mit Perl nicht auskennst, dann poste hier mal eine anonymisierte Postfix-Datei.

Jan

P.S.: Du kannst sowas natürlich mit fast jeder Programmiersprache machen, aber nach meinen Erfahrungen ist Perl bei Textanalyse immer noch am schnellsten.

tschloss
18-08-2007, 18:29
Das ist nicht Postfix sondern Cyrus, der diese Dateien anlegt.
Ich rate aber davon ab, dem Cyrus auf Dateisystemebene in seine Ablage reinzupfuschen. Suchen kannst du natürlich, aber beim Restore müsstest du schon einen reconstruct machen.

Außerdem werden die Namen auch wiedervergeben, dass heisst ein 154. ist heute vlt. eine andere Mail als gestern.

Als Viewer für diese Dateien eignen sich Konqueror, aber mit etwas Gebastel auch Maildir-fähige Mailclients.

mex
20-08-2007, 10:38
Danke für die Antworten.
Ne von Perl versteh ich nicht all zu viel :). Also hier mal ein Beispiel wie so eine Datei aussieht. Ich hoffe ich habe die richtig verstanden. Nur was du mit einem configfile anfangen wolltest wüsst ich auch nicht :rolleyes:


Return-Path: <sender-adresse>
Received: from empfänger-domain.de ([unix socket])
by empfänger-server (Cyrus v2.2.12) with LMTPA;
Mon, 30 Jul 2007 10:41:24 +0200
X-Sieve: CMU Sieve 2.2
Received: from localhost (localhost [127.0.0.1])
by empfänger-domain.de (Postfix) with ESMTP id 19E72114655
for <empfänger-adresse>; Mon, 30 Jul 2007 10:41:24 +0200 (CEST)
Received: from empfänger-domain.de ([127.0.0.1])
by localhost (empfänger-domain.de [127.0.0.1]) (amavisd-new, port 10024) with ESMTP
id 15472-05 for <xxx@localhost.empfänger-domain.de>;
Mon, 30 Jul 2007 10:41:23 +0200 (CEST)
Received: from localhost (localhost [127.0.0.1])
by empfänger-domain.de (Postfix) with ESMTP id CD030114653
for <xxx@localhost>; Mon, 30 Jul 2007 10:41:22 +0200 (CEST)
Delivery-Date: Mon, 30 Jul 2007 10:40:34 +0200
Received-SPF: none (mxeu24: 85.25.139.103 is neither permitted nor denied by domain of sender-domain.de) client-ip=85.
Received: from imap.1und1.com [212.227.15.187]
by localhost with IMAP (fetchmail-6.2.5.2)
for xxx@localhost (single-drop); Mon, 30 Jul 2007 10:41:22 +0200 (CEST)
Received: from [85.25.139.103] (helo=echo636.server4you.de)
by mx.kundenserver.de (node=mxeu24) with ESMTP (Nemesis),
id 0MKtd6-1IFQnp3ATk-0004Gg for xxx@empfänger-domain.de; Mon, 30 Jul 2007 10:40:33 +0200
Received: by echo636.server4you.de (Postfix, from userid 65534)
id 6A4DF434254; Mon, 30 Jul 2007 10:40:34 +0200 (CEST)
Received: from [192.168.1.2] (p57B7B308.dip0.t-ipconnect.de [87.183.179.8])
by echo636.server4you.de (Postfix) with ESMTP id 377C743424E;
Mon, 30 Jul 2007 10:40:22 +0200 (CEST)
Message-ID: <46ADA36B.6000602@sender-domain.de>
Date: Mon, 30 Jul 2007 10:38:03 +0200
From: "Sender." <xxx@sender-domain.de>
User-Agent: Thunderbird 1.5.0.12 (Windows/20070509)
MIME-Version: 1.0
To: empfänger <xxx@empfänger-domain.de>,
"CC-Empfänger" <xxx@CC-empfänger-domain.de>
Subject: <Subject>
Content-Type: text/plain; charset=ISO-8859-15; format=flowed
Content-Transfer-Encoding: 8bit
Envelope-To: xxx@empfänger-domain.de
X-Virus-Scanned: amavisd-new at empfänger-domain.de

moin,

<Mailinhalt>


Interessant sind wie gesagt nur die Vier sachen aus der Mail und der Dateiname:


Date: Mon, 30 Jul 2007 10:38:03 +0200

From: "Sender." <xxx@sender-domain.de>

To: empfänger <xxx@empfänger-domain.de>

Subject: <Subject>
--------------------------------------------------------------------------

aber beim Restore müsstest du schon einen reconstruct machen.

Außerdem werden die Namen auch wiedervergeben, dass heisst ein 154. ist heute vlt. eine andere Mail als gestern.

Das mit dem Restore ist klar, das mach ich ja bei Mails die der Virenscanner oder Spamfilter fälschlicherweise weg sotiert hat.
Ändert sich der Name nicht nur wenn die Mail in ein anderes Verzeichnis gelegt wird? Wenn die Mail immer im gleichen Verzeichnis liegt sollte sich der Name doch nicht änder, hab das zwar noch nie getestet aber wäre für mich ziemlich unlogisch.


mfg

mex

tschloss
20-08-2007, 13:27
Eine Mail-Datei zu finden ist mit egrep sicher nicht besonders schwer, mit einem Perl Progrämmchen (es gibt im CPAN Module, die das Mailformat mit allem drum und dran interpretieren können) kann man das leicht noch etwas aufpeppen.
Schöner wird es, wenn du dir das Verzechnis etwas umbastelst bzw. deinen Backup in eine Maildir-Struktur hinein machst, damit es wie ein echtes Maildir aussieht und dann mit einem Client draufschaust. Das ist für Einzelfälle angenehm, aber um es für einen Regelbetrieb zu nutzen müßtest du den Ansatz noch verfeinern.

Mit den Datenamen miente ich nur, dass wenn der User die 153. abgeholt / gelöscht hat, dass dann eine neue eingehende Mail auch wieder 153. heissen kann. Das heisst man muss beim Zurückspeichern auf Konfliktfreiheit achten.

jan61
20-08-2007, 20:09
Moin,

nein, ich wollte tatsächlich nur ein Beispiel für eine Mail haben, keine Konfig. So könnte ein kleines Perl-Script aussehen, das Dir die benötigten Infos extrahiert:

#! /usr/bin/perl

use strict;
use warnings;
use File::Basename;

# Basis-Mailverzeichnis
my $BASE_DIR = "/home/jan/tmp/mail_info";

# Daten aus einer Mail ziehen
# Parameter: Dateiname mit absolutem Pfad
sub extract_maildata {
my ($fname) = @_;
# Dateinamen und Verzeichnis trennen
my ($dir, $file) = $fname =~ m#^(.+)/([^/]+)$#;
if (open MFILE, $fname) {
# benoetigte Daten initialisieren
my $date = "";
my $from = "";
my $to = "";
my $subj = "";
# Datei zeilenweise lesen
foreach my $line (<MFILE>) {
# Zeilenende \n entfernen
chomp $line;
# 1. Leerzeile in einer Mail ist Header-Ende
last if $line =~ /^$/;
# nach den Daten suchen, extrahieren
($date) = $line =~ m/^Date: (.+)$/ if $line =~ /^Date: /;
($from) = $line =~ m/^From: (.+)$/ if $line =~ /^From: /;
($to) = $line =~ m/^To: (.+)$/ if $line =~ /^To: /;
($subj) = $line =~ m/^Subject: (.+)$/ if $line =~ /^Subject: /;
}
close MFILE;
# CSV-Zeile nach STDOUT schreiben
print "$dir|$file|$date|$from|$to|$subj\n";
}
}

# rekursiv Verzeichnisse einlesen
# Parameter: Verzeichnis (absoluter Pfad)
sub read_dir {
my ($dname) = @_;
# Verzeichnis oeffnen und Inhalt in Array lesen
if (opendir FDIR, $dname) {
my @dlist = readdir FDIR;
closedir FDIR;
# Array durchlaufen
foreach my $d (@dlist) {
# . und .. interessieren nicht
next if $d =~ /^\.{1,2}$/;
# absoluter Pfad des Verzeichniseintrags
my $p = $dname . "/" . $d;
# wieder Verzeichnis? rekursiv read_dir aufrufen
if (-d $p) {
read_dir($p);
}
# Datei gefunden: Parsen
elsif (-f $p) {
extract_maildata($p);
}
}
}
}

# MAIN
# Header nach STDOUT schreiben
print "Pfad|Dateiname|Datum|Absender|Empfaenger|Betreff\n";
# Basisverzeichnis durchackern
read_dir $BASE_DIR;
exit 0;
Das Script durchforstet ab dem mit $BASE_DIR definierten Verzeichnis rekursiv den ganzen Baum und parst jede gefundene Datei nach den angegebenen Daten. Die Erebnisse schreibt es im CSV-Format auf STDOUT (Feldtrenner ist |), die Datei kannst Du dann z. B. in OpenOffice Calc importieren, suchen, sortieren, ...

Aufrufen kannst Du das Script z. B. so:
jan@jack:~/tmp> ./get_mailinfo.pl >mail_info.txt
jan@jack:~/tmp> cat mail_info.txt
Pfad|Dateiname|Datum|Absender|Empfaenger|Betreff
/home/jan/tmp/mail_info|135|Mon, 30 Jul 2007 10:38:03 +0200|"Sender." <xxx@sender-domain.de>|empfänger <xxx@empfänger-domain.de>,|<Subject>
/home/jan/tmp/mail_info/jan|144|Mon, 30 Jul 2007 10:38:03 +0200|"Sender." <xxx@sender-domain.de>|empfänger <xxx@empfänger-domain.de>,|<Subject>
/home/jan/tmp/mail_info/jan61|222|Mon, 30 Jul 2007 10:38:03 +0200|"Sender." <xxx@sender-domain.de>|empfänger <xxx@empfänger-domain.de>,|<Subject>
Das ist nat. nur ein grobes Beispiel. Wenn Du z. B. noch Dateien im Tree hast, die keine Mails sind, dann müssten diese noch abgefangen werden, Fehlerhandling ist auch eher rudimentär.

HTH
Jan

mex
21-08-2007, 08:39
Super Danke euch Beiden :D ich werde das ganze heute gleich mal testen.

mfg

mex

mex
28-08-2007, 10:35
Moin hat doch etwas gedauert mit dem testen ist bisschen viel los im moment :). Also ich habe es jetzt mal an einem kleinen Datenbestand getestet. Es funktioniert soweit er liest das aus was er soll und schreib es auch in die Log-Datei. Es gibt nur ein kleines Problem für das ich aber keine Lösung gefunden habe. Die Formatierung in der Log- bzw. CVS-Datei stimmt irgendwie nicht ganz der mach dort ein paar Zeilenumbrüche die nicht seien dürften. Das hat zur folge das man die Daten leider nicht ordentlich in eine Calc-Tabelle importieren kann. Wenn ich von Hand die Zeilenumbrüche raus nehme gehts nur kann ich das bei ca. 800.000 Datensätzen nicht Händisch machen :D


/home/user/tdir/NeuerO|10524.|Wed, 20 Dec 2006 16:11:27 +0100
|Absender <absender@domain.de>
|Empfänger <empfänger@domain.de>
|Re: Subject

genau so ist die Formatierung und Sie Sollte so sein




/home/user/tdir/NeuerO|10524.|Wed, 20 Dec 2006 16:11:27 +0100|Absender <absender@domain.de>|Empfnger <empfnger@domain.de>|Re: Subject

Ich hab schon versucht das zu ändern aber irgendwie find ich da keine Lösung. Wäre sehr dankbar wenn da wär ne Idee hätte. Ein Hinweis oder Schubs in die richtige Richtung wäre mir schon genug :)

mfg

mex

jan61
28-08-2007, 16:53
Moin,

da bleiben offenbar noch ein paar Zeilenumbrüche übrig, allerdings ist mir nicht ganz klar, woher die kommen (in extract_maildata soll chomp $line; eigentlich genau das verhindern). Kann es sein, dass da DOS-Zeilenenden drinstehen? Mach mal
od -cx mail_info.txt | less und schau nach, ob da irgendwo das Zeichen \r auftaucht.

Du solltest sie wegkriegen, wenn Du in der Funktion extract_maildata folgende Zeile einfügst (ungetestet):

...
# Zeilenende \n entfernen
chomp $line;
$line =~ s/[\r\n]//g;
...
Gruß
Jan

mex
29-08-2007, 11:38
Super danke so gehts :).

Also das erstellen geht echt fix, hab das mal mit knapp 68000 mails getestet hat er so ca. eine minute für gebraucht da kann man nicht meckern ;). Nur das importieren nach Clac kann man glaub ich getrost vergessen. 1. sagt Calc bei ca. 64000 Zeilen hier ist meine maximal Grenze erreicht und die Daten die er dann hat irgendwie zu sortieren kann man komplett vergessen. Ich teste das ganze noch mal mit einer DB denke mal wird eine Postgres damit wird es wahrscheinlich besser gehen aber ist zuviel aufwand, das rechnet sich nicht. Dafür geht das öffnen der .txt recht gut mit einem vernüpfitgen Editor, denke auch mal das das mit der jetzt funktionierenden Formatierung übersichtlich genug ist.

Ein kleines Problem gibts allerdings noch, ist aber nichts was mich wirklich stört.
Beim ausführen des Skriptes wird ein Fehler ausgegeben.


Use of uninitialized value in concatenation (.) or string at ./get_mailinfo.pl line 37.


Das liegt aber, so wie ich es sehe, an der neuen Zeile.

line 37 ist die folgende:


print "$dir|$file|$date|$from|$to|$subj \n";

Also das letzte war nur zu Info halt falls noch jemand das Skript benutzt. Daten gehen keine verloren.

mfg

mex

Und nochmals vielen Dank

jan61
29-08-2007, 21:40
...Also das erstellen geht echt fix, hab das mal mit knapp 68000 mails getestet hat er so ca. eine minute für gebraucht da kann man nicht meckern ;). Nur das importieren nach Clac kann man glaub ich getrost vergessen. 1. sagt Calc bei ca. 64000 Zeilen hier ist meine maximal Grenze erreicht und die Daten die er dann hat irgendwie zu sortieren kann man komplett vergessen....

Vielleicht wäre eine Variante, das in kleinere Brocken aufzuteilen (z. B. nach Empfänger, das sollte doch Sinn machen?):

jan@jack:~/tmp> cat split_mailinfo.pl
#! /usr/bin/perl

use strict;
use warnings;

my $hdr = "";
my $prev_to = "";

while (<STDIN>) {
if ($hdr eq "") {
$hdr = $_;
next;
}
my @f = split /\|/;
my ($to) = $f[4] =~ m/.*?([\wäöüß.-]+@[\wäöüß.-]+).*/i;
if ($prev_to ne $to) {
close OUT if $prev_to ne "";
open OUT, ">mail_out/${to}.csv" or die "kann Ausgabedatei nicht oeffnen ($!)\n";
print OUT $hdr;
}
print OUT $_;
$prev_to = $to;
}
close OUT;

exit 0;
Das rufst Du dann wie folgt auf:
./get_mailinfo.pl | sort -t '|' -k 5 | ./split_mailinfo.pl und hast im Verzeichnis mail_out je Empfänger 1 CSV-Datei liegen.

Eine andere Variante wäre nach Tagen zu splitten:
jan@jack:~/tmp> cat split_mailinfo2.pl
#! /usr/bin/perl

use strict;
use warnings;

my $hdr = "";
my $prev_dt = "";

while (<STDIN>) {
if ($hdr eq "") {
$hdr = $_;
next;
}
my @f = split /\|/;
my ($dt) = $f[2] =~ m/^[^ ]* (\d+ \w+ \d+) .*/i;
if ($prev_dt ne $dt) {
close OUT if $prev_dt ne "";
open OUT, ">mail_out/${dt}.csv" or die "kann Ausgabedatei nicht oeffnen ($!)\n";
print OUT $hdr;
}
print OUT $_;
$prev_dt = $dt;
}
close OUT;

exit 0;
Aufruf analog:
./get_mailinfo.pl | sort -t '|' -k 3 | ./split_mailinfo2.plDas Prinzip könnte (und muss!) man noch ausbauen, die Regex für die Ermittlung des Empfängers z. B. ist eher rudimentär, da findet man im Netz bessere, das Ganze variabel machen (nach beliebigen Feldern sortieren), leere Felder abfangen, Fehler abfangen, nach Tag+Stunde splitten... Nur so eine Idee, wie man der Datenflut Herr werden könnte.


Ein kleines Problem gibts allerdings noch, ist aber nichts was mich wirklich stört.
Beim ausführen des Skriptes wird ein Fehler ausgegeben.


Use of uninitialized value in concatenation (.) or string at ./get_mailinfo.pl line 37....

Nein, an der neuen Zeile liegt das nicht. Das kann z. B. passieren, wenn das Subject leer ist (ist ja nicht ungewöhnlich). Das kannst Du einfach umgehen:
close MFILE;
$date = "" unless $date;
$from = "" unless $from;
$to = "" unless $to;
$subj = "" unless $subj;
print "$dir|$file|$date|$from|$to|$subj\n";
Damit wird immer dann, wenn ein Wert nicht definiert ist, ein Leerstring gesetzt (kannst natürlich auch irgendeinen Wert wie "--UNBEKANNT--" oder "--LEER--" einsetzen).

Jan

mex
04-09-2007, 14:59
moin,
ich teste das noch mal hab im moment nur leider keine Zeit dafür. Kann also noch ein bisschen dauern bis ich wieder was poste.

Noch mal vielen Dank für deine Mühen

mfg

mex

mex
10-12-2007, 10:55
Da hab ich doch glatt vergessen noch was zu posten...das script ist echt super also zumindest bei den Tests. Hab das ganze mal mit meinem Postfach ausprobiert(ca 66000 mails) ist ech fix das ganze...Probleme gibts nur wenn man die Daten richtung Excel schieben will...da ist irgendwann schluss mit Daten hinzufügen höhö, naja nehm ich dann halt ne postgres für, wenn es mal nötig ist. Aber ansonsten echt schönes Script.

Vielen Dank noch mal.

mfg

mex