none
Zeitüberschreitung beim E-Mail-Versand RRS feed

  • Frage

  • Hallo,

    ich habe mal wieder ein Problem.
    Mein Programm versendet u.A. E-Mails mit Anlagen via SMTP udn gibt nach dem Versenden eine Rückmeldung ob erfolgreich oder nicht.
    Wenn ich nur kleine Anhänge versende oder eizelne Anhänge funktioniert das.
    Ab 2 MB Anhanggröße bekomme ich meine Fehlermeldung die bislang nur auftrat, wenn i.d.R. etwas an der Kontoeinstellung nicht stimmte.
    Kann ich herausbekommen, ob das ggf. an einer Zeitüberschreitung liegt? Wenn ja, wie und dann natürlich die Frage, wie kann ich den Wert verändern?
    Danke für eure Tipps.

    LG
    Stef@n
    Liebe Grüße Stefan
    Mittwoch, 17. März 2010 22:55

Antworten

  • Hallo Stefan,

    einfach der Timeout Eigenschaft der SmtpClient Klasse zuweisen:

    Dim myClient As New Net.Mail.SmtpClient(Form12.TextBox2.Text) ''Dim myClient As NewNet.Mail.SmtpClient("smtp.web.de")
    
    myClient.Timeout = 5 * 60 * 1000 ' 5 Minuten (* Sek * ms)
    oben als Ausdruck damit es klarer wird (300000 ginge auch ;-)

    Dabei einen zuverlässigen Wert zu ermitteln, wie lange es denn dauert wird i. a. schwierig.

    Zum einen muß man immer bedenken, dass die Upload Geschwindigkeit bei DSL deutlich unter der Download Geschwindigkeit liegt.

    So rückt mein DSL 6000 weniger als ein Zehntel beim Upload raus (könnte aber technisch lt. Router mehr als das doppelte - grummel).

    Zudem sind Mailserver manchmal launisch und verarbeiten in Stoßzeiten die Daten nur tröpfelweise.

    Sinnvoll ist es, das Volumen an sich zu verkleinern: Komprimiere Anhänge, sofern es sich nicht bereits um komprimierte Daten handelt. Zip-Archive kannst Du z. B. mit http://www.codeplex.com/DotNetZip erstellen.

    Und alternativ bei größeren Mails auf einen asynchronen Versand zu wechseln (SendAsync - VB Beispiel unter http://www.systemnetmail.com/faq/4.6.aspx . Dabei mußt Du darauf achten, dass der Anwender nicht vorzeitig das Programm beendet und solltest ihn am Ende (im SendCompletedEventHandler ) über das Ende des Versands benachrichtigen.

    Gruß Elmar
    • Als Antwort markiert Giftzwockel Samstag, 20. März 2010 19:13
    Freitag, 19. März 2010 23:07
  • Hallo Stefan,

    gegen Virenscanner hat man kaum eine Chance (ausser sie abzustellen);
    denn sie klinken sich direkt in die Verbindung ein.

    Wobei das Kern-Problem häufig ist, dass sie sich schlicht und einfach
    zuviel Zeit nehmen, um ihre Prüfung durchzuführen (und G-Data gehört
    zudem wohl zu den gemächlicheren).

    Da man von einem Kunden kaum verlangen kann, auf seinen Virenscanner
    zu verzichten (und dies bei vielen auch temporär nicht ratsam ist),
    wirst Du in solchen Fällen die Größe begrenzen müssen und mehrere E-Mails
    daraus machen müssen.

    Gruß Elmar

    • Als Antwort markiert Giftzwockel Sonntag, 21. März 2010 00:36
    Samstag, 20. März 2010 20:30
  • Hallo Stefan,

    die Zeit wird über die Timeout Eigenschaft gesteuert (Standard 100 Sekunden).

    Gruß Elmar
    Donnerstag, 18. März 2010 09:11
  • Hallo Elmar,

    danke -  wieder ein Stück weiter.
    Liebe Grüße Stefan
    • Als Antwort markiert Giftzwockel Sonntag, 21. März 2010 00:37
    Donnerstag, 18. März 2010 17:08

Alle Antworten

  • Hallo Stefan,

    die Zeit wird über die Timeout Eigenschaft gesteuert (Standard 100 Sekunden).

    Gruß Elmar
    Donnerstag, 18. März 2010 09:11
  • Hallo Elmar,

    danke -  wieder ein Stück weiter.
    Liebe Grüße Stefan
    • Als Antwort markiert Giftzwockel Sonntag, 21. März 2010 00:37
    Donnerstag, 18. März 2010 17:08
  • Hallo Elmar,

    ich habe mir den Link nun mal angesehen und komme dabei nicht wirklich weiter. Ein Grund ist wohl auch der, dass ausgerechnet für VB.Net kein Beispiel vorhanden ist.

    Ich weiß aber auch nichts mit der Deklaration "Public Proberty" anzufangen. Das was ich dazu gefunden habe, habe ich mal integriert. Es wäre aber sicher Zufall, wenn ich das an die richtige Stelle gepackt hätte.

    Das habe ich:

    Public Class EMAIL
        Dim instance As SmtpClient
        Public Property Timeout() As Integer
            Get
                value = instance.Timeout
                instance.Timeout = value
            End Get
            Private Set(ByVal wert As Integer)
                instance.Timeout = wert
            End Set
    
        End Property
    
        Private Sub EMAIL_Load(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles MyBase.Load
    

     Wenn ich nun meine Mails mit Anhängen abschicke, dann hänge ich momentan an diesem Teilstück:

    Private Sub Button7_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles Button7.Click
    
            'Erst wird geprüft, ob ein Empfänger angegeben ist, wenn nicht wird so lange abgefragt, bis man auf- oder eingibt
            If TextBox1.Text = Nothing Then 'Es wurde kein E-Mail-Empfänger angegeben
                MsgBox("Adressfehler! Sie haben keine E-Mail-Adresse für den Empänger angegeben.", MsgBoxStyle.Exclamation)
                Me.TextBox1.Focus()
                Me.TextBox1.SelectionLength = TextBox1.TextLength
                Me.Text = " Direktmailing ... "
            Else    'Mail-Empfänger wurde angegeben
                'Prüfe, ob mind. 8 Zeichen als Mail-Adresse eingegeben sind.
                Dim eingabe As String
                eingabe = TextBox1.Text
                Dim numAnzahl As String
                numAnzahl = eingabe.Length
                If numAnzahl < 8 Then
                    MsgBox("Adressfehler! Sie haben keine gültige E-Mail-Adresse für den Empänger angegeben." & vbCrLf & vbCrLf & "Eine gültige E-Mail-Adresse besteht mind. aus 8 Zeichen und ist nach folgendem Muster: " & vbCrLf & vbCrLf & """1@abc.de""" & vbCrLf & vbCrLf & "aufgebaut. Ihre Eingabe besteht aus " & numAnzahl & " Zeichen." & vbCrLf & "Bitte korrigieren Sie Ihre Eingabe.", MsgBoxStyle.Exclamation)
                    Me.TextBox1.SelectionLength = TextBox1.TextLength
                    Me.TextBox1.Focus()
                    Me.TextBox1.SelectionLength = TextBox1.TextLength
                Else
                    'Ende Prüfung auf korrekte Mailadresse
    
                    'Im zweiten Schritt wird geprüft, ob ein Betreff angegeben ist, das kann man auch mit "Nein" ignorieren
                    If TextBox2.Text = Nothing Then
    
                        'Prüfe auf Betreff
                        If TextBox2.Text = Nothing And OhneBetreff = 1 Then  'Kein Betreff und auf Nachfrage Betreff unerwünscht
                            Dim FrageObBetreff As MsgBoxResult = MessageBox.Show(text:="Es wurde kein ""Betreff"" für die Mail angegeben." & vbCrLf & vbCrLf & "Es wird empfohlen, der Nachricht einen Betreff zu geben. Sie teilen so dem Empfänger Ihrer Mail mit um was es sich handelt und werden nicht so schnell als SPAM-Nachricht eingestuft." & vbCrLf & vbCrLf & "Um zur Betreffzeile zu gelangen und einen Betreff einzugeben, drücken Sie die ""JA""-Schaltfläche. " & vbCrLf & vbCrLf & "Wenn Sie die Mail ohne Betreff versenden möchten, drücken Sie die ""NEIN""-Schaltfläche.", caption:="Mail ohne Betreff ...", icon:=MessageBoxIcon.Question, buttons:=MessageBoxButtons.YesNo)
                            If FrageObBetreff = MsgBoxResult.No Then    'Mitteilung erhält keinen Betreff, wir gehen sofort zur Texteingabe.
                                OhneBetreff = 0
                                Me.TabPage1.Focus()
    
                                Try
                                    MessageBox.Show("Der Auftrag wurde gestartet." & vbCrLf & vbCrLf & "Der Versandt kann in Abhängigkeit der:" & vbCrLf & vbCrLf & "- Dateigröße" & vbCrLf & "- Datenstream für Upload und des" & vbCrLf & "- Datenstreams für Download " & vbCrLf & vbCrLf & "einige Zeit in Anspruch nehmen. Sie können in der Zwischenzeit mit dem Programm weiterarbeiten.", "E-Mail-Versandt vorbereitet ...", MessageBoxButtons.OK, MessageBoxIcon.Information)
                                    Dim Betreff As String = Me.TextBox2.Text 'Text aus eigenem Formular TB2
                                    'MsgBox("Betreff: " & Me.TextBox2.Text)
                                    Dim SendFrom As String = Form12.TextBox1.Text   'Holt sich Mail-Adresse auf Form 12
                                    'MsgBox("Absender: " & Form12.TextBox1.Text)
                                    Dim ShipTo As String = Me.TextBox1.Text
                                    'MsgBox("Empfänger: " & Me.TextBox1.Text)
    
                                    Dim Text As String = RichTextBox1.Text
                                    Dim myClient As New Net.Mail.SmtpClient(Form12.TextBox2.Text) ''Dim myClient As NewNet.Mail.SmtpClient("smtp.web.de")
                                    Text = RichTextBox1.Text
                                    myClient.Credentials = New NetworkCredential(Form12.TextBox1.Text, Form12.TextBox3.Text) 'myClient.Credentials = New NetworkCredential("name@domain.de", "Passwort")
                                    Dim mail As New System.Net.Mail.MailMessage
                                    mail.From = New System.Net.Mail.MailAddress(SendFrom)
                                    mail.To.Add(ShipTo)
                                    mail.Subject = Betreff
                                    mail.Body = Text
    
                                    'Lese ListBox mit Anhängen aus und erzeuge pro Anhang ein neues Attachment //Versuch
                                    Dim lbx As ListBox = Me.TabControl1.TabPages(1).Controls(0)
                                    Dim AnzahlAnhänge As Integer = lbx.Items.Count
                                    For i = 0 To lbx.Items.Count - 1
                                        mail.Attachments.Add(New System.Net.Mail.Attachment(lbx.Items(i)))
                                    Next
    
    // und hier wird es vermutlich kritisch? Hier soll doch irgendwie der Wert für die Timeout-Instanz stehen, oder?



    'Wenn PRG das Senden beginnt, wird die ProgressBar sichtbar ToolStripProgressBar1.Visible = True myClient.Send(mail) MessageBox.Show("Die Mail wurde am: " & vbCrLf & Today & vbCrLf & "um: " & vbCrLf & TimeOfDay & vbCrLf & "an: " & vbCrLf & Me.TextBox1.Text & vbCrLf & "mit dem Betreff: " & vbCrLf & """" & Me.TextBox2.Text & """" & " verschickt." & vbCrLf & "Die Mitteilung lautete: " & vbCrLf & Me.RichTextBox1.Text & vbCrLf & vbCrLf & "Die Nachricht enthielt " & AnzahlAnhänge & " Anlage/n. ", ProgrammName & " Mail-Report", MessageBoxButtons.OK, MessageBoxIcon.Information) OhneBetreff = 1 'Mail ohne Betreff reklamieren 'Nach Beenden des Sendevorgangs, wird Prograssbar unsichtbar ToolStripProgressBar1.Visible = False ' Catch ex As Exception 'MessageBox.Show("Beim Senden trat ein Fehler auf." & vbCrLf & vbCrLf & "Wiederholen Sie den Vorgang. Sollte der Fehler weiterhin auftreten, überprüfen Sie bitte folgende Punkte: " & vbCrLf & vbCrLf & "1. Überprüfen Sie die Einstellung für den SMTP-Server" & vbCrLf & "2. Überpüfen Sie Ihr Passwort" & vbCrLf & "3. Stellen Sie sicher, dass Sie aktuell eine bestehende Internetverbindung haben." & vbCrLf & vbCrLf & "Sollte der Fehler dauerhaft vorliegen, wenden Sie sich an Ihren Systemadministrator.", "Mailversandt fehlgeschlagen ... ", MessageBoxButtons.OK, MessageBoxIcon.Stop) MsgBox("Fehler " & ex.Message) End Try End If If FrageObBetreff = MsgBoxResult.Yes Then 'Wir möchten einen Betreff eingeben und bleibem im Betreff-Eingabefeld Me.TextBox2.Focus() OhneBetreff = 1 End If

    Wenn ich mir verschiedene Codschnipsel ansehe, dann bestehen die immer aus einem Tei, der meinem ersten Teil entspricht und dann bekommt das Programm kurz vor dem eigentlichen Absenden den Timeout-Wert "mitgeteilt".
    Das bekomme ich eben nicht hin.

    In diesem Zusammenhang stellt sich aber auch die Frage, wie man mit solchen großen Datenmengen bei langsamen Datenübertragungsraten am besten umgeht.
    Macht es Sinn, sich:

    1. Aufzuaddieren, wie groß die Summe aller zu versendenden Anlagen ist und ggf. ein Limit zu geben? oder
    2. Man prüft schon, wie groß das Paket werden soll, prüft die Geschwindigkeit der Leitung, berechnet die voraussichtliche Sendedauer und setzt in Abhängigkeit dieser Parameter den Wert für Timeout? oder
    3. Gibt man dem Nutzer die Möglichkeit den Timeout-Wert irgendwo einzustellen?

    Mal davon abgesehen, dass bei Nr. eine Menge weiterer Probleme auf mich zukämen, bleibt mein Hauptproblem zunächst bestehen, nämlich überhaupt einmal auf den Wert erfolgreich Einfluß zu nehmen.

    So, das war wieder eine Mammutfrage für ein Mammut-Programm-Bastelwochenende.

    ...wäre schön, wenn du es mir schonend beibringen könntest :-)

    Danke im Voraus auch an alle für eure Tipps und Anregungen.

     


    Liebe Grüße Stefan
    Freitag, 19. März 2010 20:35
  • Hallo Stefan,

    einfach der Timeout Eigenschaft der SmtpClient Klasse zuweisen:

    Dim myClient As New Net.Mail.SmtpClient(Form12.TextBox2.Text) ''Dim myClient As NewNet.Mail.SmtpClient("smtp.web.de")
    
    myClient.Timeout = 5 * 60 * 1000 ' 5 Minuten (* Sek * ms)
    oben als Ausdruck damit es klarer wird (300000 ginge auch ;-)

    Dabei einen zuverlässigen Wert zu ermitteln, wie lange es denn dauert wird i. a. schwierig.

    Zum einen muß man immer bedenken, dass die Upload Geschwindigkeit bei DSL deutlich unter der Download Geschwindigkeit liegt.

    So rückt mein DSL 6000 weniger als ein Zehntel beim Upload raus (könnte aber technisch lt. Router mehr als das doppelte - grummel).

    Zudem sind Mailserver manchmal launisch und verarbeiten in Stoßzeiten die Daten nur tröpfelweise.

    Sinnvoll ist es, das Volumen an sich zu verkleinern: Komprimiere Anhänge, sofern es sich nicht bereits um komprimierte Daten handelt. Zip-Archive kannst Du z. B. mit http://www.codeplex.com/DotNetZip erstellen.

    Und alternativ bei größeren Mails auf einen asynchronen Versand zu wechseln (SendAsync - VB Beispiel unter http://www.systemnetmail.com/faq/4.6.aspx . Dabei mußt Du darauf achten, dass der Anwender nicht vorzeitig das Programm beendet und solltest ihn am Ende (im SendCompletedEventHandler ) über das Ende des Versands benachrichtigen.

    Gruß Elmar
    • Als Antwort markiert Giftzwockel Samstag, 20. März 2010 19:13
    Freitag, 19. März 2010 23:07
  • Hallo Elmar,

    danke. Zunächst habe ich aber bei großen Anlagen nach wie vor keinen Erfolg verzeichnen können.
    Ich habe dann mal das mit Try und Catch auskommentiert und bin bei der auftretenden Meldung auf folgende Nachricht gestoßen:

           bei System.Threading.ExecutionContext.Run(ExecutionContext executionContext, ContextCallback callback, Object state)

           bei System.Threading.ThreadHelper.ThreadStart()

      InnerException: System.IO.IOException

           Message="In die Übertragungsverbindung können keine Daten geschrieben werden: Eine bestehende Verbindung wurde softwaregesteuert durch den Hostcomputer abgebrochen."

           Source="System"

           StackTrace:

                bei System.Net.Sockets.NetworkStream.Write(Byte[] buffer, Int32 offset, Int32 size)

                bei System.Net.DelegatedStream.Write(Byte[] buffer, Int32 offset, Int32 count)

                bei System.Net.DelegatedStream.Write(Byte[] buffer, Int32 offset, Int32 count)

                bei System.Net.Mime.SevenBitStream.Write(Byte[] buffer, Int32 offset, Int32 count)

                bei System.Net.DelegatedStream.Write(Byte[] buffer, Int32 offset, Int32 count)

                bei System.Net.DelegatedStream.Write(Byte[] buffer, Int32 offset, Int32 count)

                bei System.Net.Mime.SevenBitStream.Write(Byte[] buffer, Int32 offset, Int32 count)

                bei System.Net.DelegatedStream.Write(Byte[] buffer, Int32 offset, Int32 count)

                bei System.Net.DelegatedStream.Write(Byte[] buffer, Int32 offset, Int32 count)

                bei System.Net.Base64Stream.FlushInternal()

                bei System.Net.Base64Stream.Write(Byte[] buffer, Int32 offset, Int32 count)

                bei System.Net.Mime.MimePart.Send(BaseWriter writer)

                bei System.Net.Mime.MimeMultiPart.Send(BaseWriter writer)

                bei System.Net.Mail.Message.Send(BaseWriter writer, Boolean sendEnvelope)

                bei System.Net.Mail.MailMessage.Send(BaseWriter writer, Boolean sendEnvelope)

                bei System.Net.Mail.SmtpClient.Send(MailMessage message)

           InnerException: System.Net.Sockets.SocketException

                ErrorCode=10053

                Message="Eine bestehende Verbindung wurde softwaregesteuert durch den Hostcomputer abgebrochen"

                NativeErrorCode=10053

                Source="System"

                StackTrace:

                     bei System.Net.Sockets.Socket.Send(Byte[] buffer, Int32 offset, Int32 size, SocketFlags socketFlags)

                     bei System.Net.Sockets.NetworkStream.Write(Byte[] buffer, Int32 offset, Int32 size)

                InnerException:

    Ja wer macht denn so was? Ich habe dann den Virenscanner (G_Data) versuchsweise vor dem Versenden abgeschaltet und plötzlich konnten auch große Anhänge gemailt werden. Ich kenne somit meine nächste Herausforderung. Feststellen ob und welche Einstellung bei einem Virenscanner oder sogar Firewall die Verbindung unterbricht.

    Eines habe ich aber noch nicht verstanden und vielleicht hängt das ja auch zusammen, nachdem ich den Code:

    myClient.Timeout = 5 * 60 * 1000 ' 5 Minuten (* Sek * ms)

    platziert hatte, habe ich den untensrtehenden Teil ebenfalls zunächst einmal rauskommentiert. Geht das oder ist das sogar ggf. die Ursache dafür, dass GDATA mich so einfach rausschmeißt?

    Public Class EMAIL
        Dim instance As SmtpClient
        Public Property Timeout() As Integer
            Get
                value = instance.Timeout
                instance.Timeout = value
            End Get
            Private Set(ByVal wert As Integer)
                instance.Timeout = wert
            End Set

        End Property

    Zu guterletzt, wie kann man es denn vermeiden, dass ein anderes Programm wie Virenscanner etc. einen rauskickt?

     


    Liebe Grüße Stefan
    • Bearbeitet Giftzwockel Samstag, 20. März 2010 19:25 bessere Transparenz
    Samstag, 20. März 2010 19:25
  • Hallo Stefan,

    gegen Virenscanner hat man kaum eine Chance (ausser sie abzustellen);
    denn sie klinken sich direkt in die Verbindung ein.

    Wobei das Kern-Problem häufig ist, dass sie sich schlicht und einfach
    zuviel Zeit nehmen, um ihre Prüfung durchzuführen (und G-Data gehört
    zudem wohl zu den gemächlicheren).

    Da man von einem Kunden kaum verlangen kann, auf seinen Virenscanner
    zu verzichten (und dies bei vielen auch temporär nicht ratsam ist),
    wirst Du in solchen Fällen die Größe begrenzen müssen und mehrere E-Mails
    daraus machen müssen.

    Gruß Elmar

    • Als Antwort markiert Giftzwockel Sonntag, 21. März 2010 00:36
    Samstag, 20. März 2010 20:30
  • Hallo Elmar,

    das war zu befürchten. Naja, es macht ja auch nicht unbedingt Sinn allzugroße Anlagen zu verschicken.
    Bei meinem Programm kommt noch erschwerend hinzu, dass die Analgen, die verschickt werden sollen gar nicht auf dem lockalen PC sind, sondern auf einem Server.

    Ich melde mich also mit meinem Programm am Server an, suche mir dort meine Anlagen, packe die in meine "Versandiste" und "jage" die dann los. Der Virenscanner prüft die somit sicherlich beim Kommen und beim gehen und bei beiden Vorgängen habe ich es mit langsamen Uploadgeschwindigkeiten zu tun. Da ist vielleicht im Einzelfall eine Brieftaube schnelle ;-).

    Ich mache das nun aber tatsächlich so, dass ich die Größe der ausgwählten Anlagen schon jetzt ermittle und anzeige. Ich packe einfach noch eine Routine vors Versenden und gebe eine Warung raus. Ob es Sinn macht, sich den Kopf darüber zu zerbrechen das Programm dahingegend zu erweitern selbst kleinere Packete zu erstellen ist fraglich. Genauso fraglich ob ich das überhaupt hinbekomme.

    Danke


    Liebe Grüße Stefan
    Sonntag, 21. März 2010 00:36