greenavatar
Goto Top

POP3-Client mit Relationaler Datenbank

Hallo zusammen,

ich bin auf der Suche nach einem POP3-Client, der die eingehenden Emails in einer Relationalen Datenbank speichert. Die Email-Attachments sollen nach Möglichkeit in Dateiform separat gespeichert werden. Ebenso eingebettete Bilder. Der Zugriff auf die Dateien muss auf jeden Fall unkompliziert sein.

Ziel:

Ich möchte aus verschiedenen Anwendungen (VB.NET, PHP) heraus auf die Emails zugreifen können, auch auf die Attachments und eingebetteten Bilder (bei RichText- oder HTML-Emails kann man ja Bilder direkt in den Text einbetten), um sie in andere Systeme importieren zu können.

Bedeutet natürlich auch, es muss zumindest einen passenden ODBC-Treiber für die POP3-Client-Datenbank geben.

Hat jemand eine oder mehrere Ideen?

Im ersten Schritt ist es erstmal nicht so wichtig, ob es sich um Freeware oder Lizenzware handelt. Wenn das Programm was taugt, darf es auch was kosten. Wichtig ist, dass der POP3-Client auf einer Relationalen Datenbank basiert.

Der Import in die Zieldatenbanken würde über eine VB.NET-Anwendung oder über einen MS-SQL Server Job erfolgen.

Eine Alternative wäre, einen eigenen Email-Server hochzuziehen (mit einer Relationalen Datenbank als Backend), aber ich denke mal, das ist vom Aufwand mehr ein paar (hundert) Nummern größer face-smile

Nee, ich glaube ein separater Email-Server wäre mir lieber, dann habe ich auch den ganzen Sicherheits-Kladeradatsch separat, die ganze Adress-/IP-/DNS-Geschichte, da bin ich nicht scharf drauf. Das wäre ja wirklich ein Megaprojekt für sich - nee, muss nicht sein. Schon lieber einen vorhandenen POP3-Server nutzen.

Freue mich über Input. Euch schon einmal einen schönen Feiertag!

Gruß

Tommy

Content-ID: 206201

Url: https://administrator.de/contentid/206201

Ausgedruckt am: 04.11.2024 um 18:11 Uhr

knut4linux
knut4linux 10.05.2013 um 11:31:01 Uhr
Goto Top
Nach groben überfliegen deines Anliegens glaube ich zu meinen, dass der GFI-Mailarchiver eine Lösung für dich ist.

In der Version 6 konnte man das Teil noch Standalone betreiben (ohne Anbindung an einem Mail Server).

Mit dazu gab es auch ein Outlook Plugin, was die Mails in die Datenbank geschoben hat.

Effektiver ist es allerdings, wenn du es mit einem Mailserver betreiben würdest.

Hoffe der Ansatz bringt dir etwas face-smile
colinardo
colinardo 10.05.2013 aktualisiert um 12:24:11 Uhr
Goto Top
Hallo Tommy,
habe so etwas in der Art schon mal als VB.Net Projekt erstellt, also POP3 Nachrichten runterladen und in eine Access-Datenbank schreiben. Die dazugehörigen Attachments werden alle im Filesystem mit eindeutigen Ordner-IDs abgelegt. Des weiteren werden noch einige Infos zu den Attachments wie (Dateiname,Größe,Extension,Typ(Inline im Body/Normal) gespeichert. Zu erwähnen ist, das du zu dem Projekt die Komponente "Mail.dll" der Firma Limilabs benötigst (149€) - ein Demoversion ist vorhanden. Das Projekt ist als Konsolenanwendung mit Parameterübergabe konzipiert.
Ein Aufruf würde dann wie folgt aussehen:

back-to-topAufruf mit Parametern
pop3download.exe /server:pop.mailserver.de /user:USERNAME /password:PASSWORD /dbpath:"C:\Pfad\database.mdb" /fileroot:"C:\Pfad\Attachments"

back-to-topVB.Net Projekt-Code
Imports System.Text
Imports System.Text.RegularExpressions
Imports Limilabs.Client.POP3
Imports Limilabs.Mail
Imports Limilabs.Mail.MIME
Imports Limilabs.Mail.Headers
Imports System.Data

Module Pop3ToDatabase
    Private _server As String
    Private _user As String
    Private _password As String
    Private _attachmentRootPath As String
    Private _dbPath As String
    Private _dbConn As OleDb.OleDbConnection

    Sub Main()
        Dim cmdArgs() As String = System.Environment.GetCommandLineArgs()
        If cmdArgs.Length = 6 Then
            Dim line As String = [String].Join("|", cmdArgs, 1, 5)  
            _server = New Regex("/server:([^\|]*)", RegexOptions.IgnoreCase).Match(line).Groups(1).Value  
            _user = New Regex("/user:([^\|]*)", RegexOptions.IgnoreCase).Match(line).Groups(1).Value  
            _password = New Regex("/password:([^\|]*)", RegexOptions.IgnoreCase).Match(line).Groups(1).Value  
            _attachmentRootPath = New Regex("/fileroot:([^\|]*)", RegexOptions.IgnoreCase).Match(line).Groups(1).Value  
            _dbPath = New Regex("/dbpath:([^\|]*)", RegexOptions.IgnoreCase).Match(line).Groups(1).Value  
        Else
            Console.WriteLine("Falsche Anzahl an Parametern!")  
            System.Environment.Exit(1)
        End If

        Using pop3 As New Pop3
            Try
                pop3.Connect(_server)                           ' Use overloads or ConnectSSL if you need to specify different port or SSL.  
                pop3.UseBestLogin(_user, _password)
            Catch ex As Exception
                Console.WriteLine("Error connecting to POP3-Server." & vbCrLf & ex.Message)  
                System.Environment.Exit(2)
            End Try

            Dim uids As List(Of String) = pop3.GetAll()             ' Get unique-ids of all messages.  

            If uids.Count > 0 Then
                If ConnectDB() Then
                    For Each uid As String In uids
                        Dim email As IMail = New MailBuilder().CreateFromEml(pop3.GetMessageByUID(uid))      ' Download and parse each message  
                        WriteMessageToDatabase(email)
                        pop3.DeleteMessageByUID(uid)
                    Next
                Else
                    pop3.Close()
                    System.Environment.Exit(3)
                End If
                CloseDB()
                pop3.Close()
            End If
            Console.WriteLine(vbCrLf & "Finished.")  
            System.Environment.Exit(0)
        End Using

    End Sub

    Function ConnectDB() As Boolean
        Try
            Console.WriteLine("Connecting to DB...")  
            _dbConn = New OleDb.OleDbConnection("Provider=Microsoft.ACE.OLEDB.12.0;Data Source=" & _dbPath)  
            _dbConn.Open()
        Catch ex As Exception
            Console.WriteLine("Could not connect for some reason.... is the file on the right location? --> check connectionstring ### " & vbCrLf & ex.Message)  
            Return False
        End Try
        If _dbConn.State = ConnectionState.Open Then
            Return True
        Else
            Return False
        End If
    End Function

    Sub CloseDB()
        _dbConn.Close()
    End Sub

    Sub WriteMessageToDatabase(ByVal email As IMail)

        Try

            Console.WriteLine("Saving Mail to Database: " + email.MessageID)  
            Dim uniqueID As String = tobase36(DateTime.Now.Ticks)
            Dim attSavePath As String = _attachmentRootPath + "\" + uniqueID + "_" + email.MessageID  

            Dim SQL As New OleDb.OleDbCommand("Select * FROM MAILS", _dbConn)  
            Dim da As New OleDb.OleDbDataAdapter(SQL)
            Dim builder As OleDb.OleDbCommandBuilder = New OleDb.OleDbCommandBuilder(da)
            Dim dataSet As DataSet = New DataSet
            da.Fill(dataSet, "MAILS")  
            da.InsertCommand = builder.GetInsertCommand()

            Dim SQL2 As New OleDb.OleDbCommand("Select * FROM ATTACHMENTS", _dbConn)  
            Dim da2 As New OleDb.OleDbDataAdapter(SQL2)
            Dim builder2 As OleDb.OleDbCommandBuilder = New OleDb.OleDbCommandBuilder(da2)
            Dim dataSet2 As DataSet = New DataSet
            da2.Fill(dataSet2, "ATTACHMENTS")  
            da2.InsertCommand = builder2.GetInsertCommand()

            'Add email-content to database  
            Dim new_row As DataRow = dataSet.Tables("MAILS").NewRow()  
            new_row("mailID") = uniqueID & "_" & email.MessageID  
            new_row("mailDate") = email.Date  
            new_row("mailSubject") = email.Subject  
            new_row("mailText") = email.Text  
            new_row("mailHTML") = email.Html  
            new_row("mailFrom") = JoinMailboxes(email.From)  
            new_row("mailTo") = JoinAddresses(email.To)  
            new_row("mailCc") = JoinAddresses(email.Cc)  
            new_row("mailBcc") = JoinAddresses(email.Bcc)  
            dataSet.Tables("MAILS").Rows.Add(new_row)  
            da.Update(dataSet, "MAILS")  

            'Process attachments  
            If email.Attachments.Count > 0 Then
                'Process normal attachments  
                For Each attachment As MimeData In email.NonVisuals
                    Dim new_row_att As DataRow = dataSet2.Tables("ATTACHMENTS").NewRow()  
                    new_row_att("mailID") = uniqueID & "_" & email.MessageID  
                    new_row_att("attPath") = attSavePath  
                    new_row_att("attFilename") = attachment.SafeFileName  
                    new_row_att("attExtension") = Mid(attachment.SafeFileName, InStr(attachment.SafeFileName, ".") + 1)  
                    new_row_att("attFileSize") = attachment.Data.Length  
                    new_row_att("attType") = "normal"  
                    dataSet2.Tables("ATTACHMENTS").Rows.Add(new_row_att)  
                    If Not My.Computer.FileSystem.DirectoryExists(attSavePath) Then
                        My.Computer.FileSystem.CreateDirectory(attSavePath)
                    End If
                    attachment.Save(attSavePath + "\" + attachment.SafeFileName)  
                Next
                'Process inline attachments (in HTML body)  
                For Each attachment As MimeData In email.Visuals
                    Dim new_row_att As DataRow = dataSet2.Tables("ATTACHMENTS").NewRow()  
                    new_row_att("mailID") = uniqueID & "_" & email.MessageID  
                    new_row_att("attPath") = attSavePath  
                    new_row_att("attFilename") = attachment.SafeFileName  
                    new_row_att("attExtension") = Mid(attachment.SafeFileName, InStr(attachment.SafeFileName, ".") + 1)  
                    new_row_att("attFileSize") = attachment.Data.Length  
                    new_row_att("attType") = "inline"  
                    dataSet2.Tables("ATTACHMENTS").Rows.Add(new_row_att)  
                    If Not My.Computer.FileSystem.DirectoryExists(attSavePath) Then
                        My.Computer.FileSystem.CreateDirectory(attSavePath)
                    End If
                    attachment.Save(attSavePath + "\" + attachment.SafeFileName)  
                Next

                da2.Update(dataSet2, "ATTACHMENTS")  
            End If

        Catch ex As Exception
            Console.WriteLine(ex.Message)
        End Try
    End Sub


    Private Function JoinMailboxes(ByVal mailboxes As IList(Of MailBox)) As String
        Return String.Join(",", New List(Of MailBox)(mailboxes).ConvertAll(Function(x As MailBox) String.Format("{0} <{1}>", x.Name, x.Address)).ToArray())  
    End Function

    Private Function JoinAddresses(ByVal addresses As IList(Of MailAddress)) As String
        Dim builder As New StringBuilder

        For Each address As MailAddress In addresses
            If (TypeOf address Is MailGroup) Then
                Dim group As MailGroup = CType(address, MailGroup)
                builder.AppendFormat("{0}: {1};, ", group.Name, JoinAddresses(group.Addresses))  
            End If
            If (TypeOf address Is MailBox) Then
                Dim mailbox As MailBox = CType(address, MailBox)
                builder.AppendFormat("{0} <{1}>, ", mailbox.Name, mailbox.Address)  
            End If
        Next
        Return builder.ToString()
    End Function


    Private Function tobase36(ByVal number As Long) As String
        Dim cList() As Char = ("0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ").ToCharArray  
        Dim finalString As String = ""  

        While Not number = 0
            finalString += cList(CInt(number Mod 36))
            number /= 36
        End While
        Return finalString
    End Function
End Module

Wenn du Interesse daran hast würde ich Dir das Access-Datenbankgerüst oder das ganze VB.Net Projekt das du dafür brauchst per PN schicken...

Grüße Uwe
tschroeder
tschroeder 13.05.2013 um 10:34:30 Uhr
Goto Top
Hallo Uwe,

wow! Nicht übel. Weißt Du, wie groß der Aufwand ist, den Code nach Access VBA zu migrieren? Bekomme ich aber zur Not auch so raus, muss halt ein bissel testen.

Würde mich über weiteres Material freuen (Access-Datenbankgerüst / VB.Net Projekt).

Mein Ziel ist es an sich, die Tabellen in einem SQL Server bereitzustellen und den Import mit Access VBA vorzunehmen.

Freue mich auf Input.

Gruß

Tommy
tschroeder
tschroeder 13.05.2013 um 10:36:03 Uhr
Goto Top
Hallo knut4linux,

werde mir das Teil mal ansehen. Die Produkte von GFI sind an sich alle ganz gut.

Danke Dir für den Tipp.

Gruß

Tommy
colinardo
colinardo 13.05.2013 aktualisiert um 17:55:10 Uhr
Goto Top
Zitat von @tschroeder:
Weißt Du, wie groß der Aufwand ist, den Code nach Access VBA zu migrieren? Bekomme ich aber zur
Not auch so raus, muss halt ein bissel testen.
da muss schon einiges geändert werden...
Mein Ziel ist es an sich, die Tabellen in einem SQL Server bereitzustellen und den Import mit Access VBA vorzunehmen.
Warum machst du den Import in die SQL-Datenbank nicht direkt im VB.Net-Projekt so brauchst du nicht den Umweg über Access VBA nehmen. Mein Code ließe sich einfach an den SQL-Server anpassen, da nur die Datenbank-Verbindung(ConnectionString) und die Tabellennamen geändert werden müssten.
Wenn du dafür Hilfe brauchst melde dich, dann unterstütze ich dich dabei.

face-wink Uwe
greenavatar
greenavatar 14.05.2013 um 07:51:05 Uhr
Goto Top
Hallo Uwe,

es müssen keine Tabellennamen geändert werden, weil es auf unserer Seite noch keine Datenbank gibt.

Können daher Deine Tabellen benutzen.

Klaro bin ich am ganzen Projekt interessiert.

Gruß

Thomas
tschroeder
tschroeder 16.05.2013 um 07:42:45 Uhr
Goto Top
Hallo Uwe,

danke für Dein Projekt. Wie bekomme ich es zum Laufen?

Meine derzeitiges Entwicklungssystem:

- Microsoft Windows XP Professional SP 3
- Microsoft Visual Studio 2008
- Microsoft Visual Studio 2010 Express
- Microsoft Office 2003 Professional

Ich habe gesehen, das ist so eine *.dll, die man nicht registrieren muss. Muss sie in einem bestimmten Verzeichnis liegen?

Oh' mei, habe noch so viele Fragen.

Du hast gesagt, das VB-Programm speichert die Attachments auf Wunsch im Dateisystem. Benötigst Du eine bestimmte Verzeichnisstruktur?

Noch eine Frage: Mein Chef legt Wert auf eingebettete Bilder in RichText- und HTML-Emails. Wie kann ich die im Dateisystem speichern? Im Falle von RichText-Emails sind das OLE-Objekte. Eine harte Nuss!

Aber ich wäre schon froh, wenn das Projekt in der Basisform schon einmal funktionieren würde.

Was muss ich dazu tun?

Noch ein Hinweis: Nicht wundern, wenn ich mal einen halben Tag nicht antworten kann - bin derzeit viel unterwegs.

Freue mich auf Input.

Gruß

Thomas
colinardo
colinardo 16.05.2013 um 10:32:38 Uhr
Goto Top
Hi Thomas,

also, im ZIP-File-Root findest du die Datei Mail.dll diese ist für das Verbinden und Auswerten der Nachrichten des POP3-Servers verantwortlich.
Du öffnest als erstes das Projekt mit der Datei Pop3DownloadToDatabase.vbproj in Visual Studio 2010 Express. Dann überprüfst du in den Eigenschaften des Projekts (Rechtsklick auf den obersten Knoten im Solution-Explorer > Eigenschaften) in den References ob die Referenz zur Mail.dll richtig eingetragen ist; wenn nicht, fügst du den Pfad zu dieser Datei hinzu. Wenn jetzt alles stimmt und du in der Fehlerliste von VS2010Express keine Fehler siehst, solltest du das Projekt kompilieren können. Die fertige *.exe zusammen mit der Mail.dll findest du dann unter "./bin/Debug/". Diese müssen sich beim Aufruf zusammen in einem Verzeichnis befinden.
Wie oben schon erwähnt, ist es als flexibles Konsolenprogramm mit Parameterübergabe konzipiert, d.h. du rufst es folgendermaßen von der Kommandozeile auf:
pop3todatabase.exe /server:pop.mailserver.de /user:USERNAME /password:PASSWORD /dbpath:"C:\Pfad\database.mdb" /fileroot:"C:\Pfad\Attachments"
Dabei gibst du den Pfad zur *.mdb Datei an die mit im Root des ZIP-Files liegt, und ein Verzeichnis in dem die Attachments landen sollen. Das Verzeichnis muss keine Struktur aufweisen, da dies das Programm selber erledigt. Es erstellt für jede E-Mail einen Ordner mit einer eindeutigen Kennung, bestehend aus einem base36-kodierten String der Systemzeit und der eMail-ID. Die Attachments sowohl "normale" Anhänge als auch alle Inline-Objekte werden darin mit deren Namen gespeichert. In der Datenbank ist dann für jedes Attachment der Typ (inline/normal) hinterlegt, so das man diese unterscheiden kann.
Ich denke damit solltest du zurecht kommen.

Noch wichtige Hinweise:
  • .Net-Framework 3.5 muss installiert sein
  • Standardmäßig ist das Programm so eingestellt, dass es die verarbeiteten Mails vom POP-Server löscht sobald sie in die Datenbank eingetragen sind.(Zeile 53 im Code)
  • Die beigefügte Mail.dll befindet sich ja im Demo-Modus d.h. diese ersetzt nach dem Zufallsprinzip Werte wie z.B den Betreff einer Mail mit: Dies ist eine Demoversion,..blabla. Hier ist dann Kohle hinblättern angesagt wenn es dann soweit funktioniert wie Ihr es wollt.

So long...
Uwe
tschroeder
tschroeder 16.05.2013 aktualisiert um 10:53:18 Uhr
Goto Top
Hallo Uwe,

reicht auch das Microsoft Visual Studio 2008?

Mit der Expressversion vom 2010er kann ich nämlich keine *.exe-Dateien erzeugen.

Gruß

Thomas
colinardo
colinardo 16.05.2013 um 10:59:03 Uhr
Goto Top
Da hast du Glück das ich die 2008er auch noch drauf hab. Hab's gerade mal damit geöffnet und kompiliert, sollte funktionieren.
tschroeder
tschroeder 16.05.2013 aktualisiert um 11:08:11 Uhr
Goto Top
Alles klar.

Heute nachmittag bin ich nicht im Büro, hocke mich aber gleich morgen früh dran.

Gruß

Thomas
tschroeder
tschroeder 16.05.2013 um 11:58:28 Uhr
Goto Top
Hallo Uwe,

habe die Parameter korrekt übergeben, die DOS-Box springt auf, dann passiert erst einmal gar nichts, dann schließt sie sich wieder. In der MDB ist in der Tabelle keine Mail drin.

Woran kann es liegen?

Gruß

Thomas
colinardo
colinardo 16.05.2013 aktualisiert um 12:11:48 Uhr
Goto Top
- Sind die Pfade mit Anführungszeichen eingeschlossen (wegen Leerzeichen) ?
- übergibst du die Parameter in Visual Studio ? mach das mal in einer separaten DOS-Box direkt.
- sind überhaupt Mails auf dem POP-Server ?
- eventuell musst du den ODBC-Connection-String ändern da du Office 2003 installiert hast; im Code Zeile 71 das Provider=Microsoft.ACE.OLEDB.12.0 durch Provider=Microsoft.Jet.OLEDB.4.0 ersetzen. Ansonsten lad dir mal die Access 2010 DB-Engine runter: http://www.microsoft.com/de-de/download/details.aspx?id=13255
- Setze halt mal Breakpoints dann siehst du schon wo's bei Dir hakt
tschroeder
tschroeder 17.05.2013 um 07:33:56 Uhr
Goto Top
Hallo Uwe,

habe den Provider in der Pop3ToDatabase.vb angepasst, wie Du gesagt hast:

Provider=Microsoft.Jet.OLEDB.4.0

Ich nehme zum Testen eine *.bat-Datei, die den folgenden Inhalt hat:

"C:\test\pop3_vbnet\bin\Debug\Pop3DownloadToDatabase.exe" /server:"mail.arcor.de:25" /user:"..." /password:"..." /dbpath:"C:\test\pop3_vbnet\bin\Debug\MailDB.mdb" /fileroot:"C:\test\pop3_vbnet\bin\Debug\attachments"

Das müsste doch alles passen - die DOS-Box poppt kurz auf und schließt sich dann wieder. Und zwar in jedem Fall, ob ich nun die *.bat ausführe oder ob ich die *.exe direkt starte. Es müsste doch in letzterem Fall eigentlich so sein, dass ich die Eingaben über die DOS-Box machen kann, oder?

Gruß

Thomas
colinardo
colinardo 17.05.2013 aktualisiert um 08:04:21 Uhr
Goto Top
der POP-Server auf Port 25 ?????? das ist wohl eher SMTP , lass die Portangabe weg ... und der POP-Server bei Arcor lautet pop3.arcor.de !!!
und nur um die Pfade Anführungszeichen nicht um Username und Passwort wenn die keine Leerzeichen haben .mach den Aufruf mal bitte manuell in einer DOS-Box ohne Batchdatei. Bei einer Batch ohne Pause Befehl am Ende, ist es normal das sich das Fenster wieder schließt wenn sich das Programm beendet !
tschroeder
tschroeder 17.05.2013 um 08:26:16 Uhr
Goto Top
Hallo Uwe,

oh Mann, ist das peinlich ... ich wollte über den SMTP-Server Mails abrufen ... ich glaub', ich verkriech mich ... face-smile

Genau das wars. Ich habe den POP3 eingetragen und es geht prima. Sogar die eingebetteten OLE-Bildobjekte in den RichText-Mails werden heruntergeladen - ist ja krass!!!

Ich muss Dir zuerst mal danken für Deine Bemühungen mit einem blutigen Anfänger.
Habe mich - glaube ich - wirklich angestellt wie der erste Mensch face-smile

Eine Frage noch: Wenn wir die *.dll regulär kaufen möchten, an wen müssten wir uns wenden? Den Preis hast Du ja oben schon erwähnt. Muss man das Ding über einen Händler kaufen oder direkt beim Entwickler? Hast Du eine URL?

Gruß

Thomas
colinardo
colinardo 17.05.2013 um 08:32:13 Uhr
Goto Top
steht oben im ersten Link http://www.limilabs.com/mail
Viel Erfolg weiterhin..
Uwe