webForumDet fria alternativet

SMTP och BulkEmail

.NETur .NET

7 svar · 328 visningar · startad av PatrikB

PatrikBMedlem sedan mars 20002 836 inlägg
#1

Hello!

har setat och labbat med att connecta direkt mot SMTP-servern för att skicka en hel del mail (email-lista) för en kunds räkning där deras hotell inte erbjuder listserv-funktioner.

När jag körde skicket av alla mail adresser (ca 500 st) från en asp sida med ett enkelt anrop tog det ca 5 minuter att skicka alla dessa.

Alldeles för segt enligt mig och började kika på att skicka allt genom att skapa en ny tråd för detta.

Vips! .... nu flög det iväg. De ca 500 mailen skickades på mindre än 1 minut.

Nu till själva frågan.

Har tråden som aspx-sidan körs i mer "overhead" än om man skapar en ny tråd där enbart skicken av alla mailen körs?

kod 1 som tar ca 5 minuter att köra:

    Public Function SendBulkMail(ByVal email as MailMessage, ByVal recipients As ArrayList) As String

        Try
            If (recipients.Count > -1) Then
                Me.Connect()

                '## -- send helo to server --
                SendCommand("HELO " + System.Net.Dns.GetHostName() + ControlChars.CrLf)

                    '## -- loop through all mail in list .
                    Dim i as Integer
                    For i = 1 TO (recipients.Length - 1)

                        email.ToMail = recipients.Item(i)

                        SendCommand("MAIL " + email.FromMail + ControlChars.CrLf)
                        SendCommand("RCPT " + email.ToMail + ControlChars.CrLf)

                        Dim _mailHeader As String = ""
                        _mailHeader += email.FromMail + ControlChars.CrLf
                        _mailHeader += email.ToMail + ControlChars.CrLf
                        _mailHeader += email.Subject + ControlChars.CrLf
                        _mailHeader += "Content-type: text/html; charset=""ISO-8859-1""" + ControlChars.CrLf

                        SendCommand("DATA" + ControlChars.CrLf + _mailHeader + email.Body + ControlChars.CrLf + "." + ControlChars.CrLf)

                    Next _emailCnt
                Me.Disconnect()
                Return "Mail sent successfully to: " + email.ToMail
            Else
                Return "No recipients given as input"
            End If
        Catch Ex As Exception
            Return "ERROR: " + Ex.Message
        End Try
    End Function

Kod 2, som tar mindre än 1 minut att köra (samma antal mail):

    Public Function Send() As String
        Try
            Dim _sendStart As New ThreadStart(AddressOf SendToAll)
            Dim _sendThread As New Thread(_sendStart)
                _sendThread.Start()

            Return "All mail sent."
        Catch Ex As Exception
            Return "ERROR: Send() - " + Ex.Message
        End Try
    End Function

    Private Sub SendToAll()
        Try
            If (_recipients.Count > -1) Then
                '## -- send mail to all recipients --
                Dim i As Integer
                For i = 0 TO (_recipients.Count - 1)
                    _email.ToMail = _recipients.Item(i)
                    Dim _smtp As New SMTP("xxx.xxx.xxx.xxx",25)
                        _smtp.Send(_email)
                Next
            End If
        Catch Ex As Exception
            Throw Ex
        End Try
    End Sub

Varför är det så?
Bara nyfiken ..... rent allmänt och kanske kan detta hjälpa en del andra ...

cya,
/PatrikB

GladhMedlem sedan maj 20012 812 inlägg
#2
    Public Function Send() As String
        Try
            Dim _sendStart As New ThreadStart(AddressOf SendToAll)
            Dim _sendThread As New Thread(_sendStart)
                _sendThread.Start()

            Return "All mail sent."
        Catch Ex As Exception
            Return "ERROR: Send() - " + Ex.Message
        End Try
    End Function

Tyvärr fungerar inte din kod så som du tror att den gör det. När du gör:

 _sendThread.Start()

Så skapas en ny tråd och din SendToAll() funktion kommer att anropas och köras i din nya tråd.

Din main tråd kommer dock fortsätta att köras och köra nästa rad i funktionen Send()

Return "All mail sent."

Kommer alltså att köras INNAN alla mail är ivägskickade. Vilket betyder att när din ASPX sida är färdig exekverad så ligger din tråd fortfarande i backgrunden och skickar iväg mail...

Du borde kunna göra en Thread.Join() precis efter din _sendThread.Start()

och se hur lång tid sidan tar, eftersom Join() methoden skall vänta tills din nya tråd är färdig innan huvudtråden fortsätter sin exekvering.

Du har helt rätt i att trådning kommer att snabba upp utsändningen av mail, men då skall varje mail skickas i EN EGEN tråd, alltså inte skicka alla mail i en tråd utan du skapar en ny tråd för varje mail. Detta kommer dock ge en massa overhead som inte är så bra, eftersom det kostar prestanda att skapa och släppa en tråd. Det finns därför i .NET en treadpool som man kan använda sig av, och om man gör Asynchronaanrop så använder man sig av denna pool. Så läs på mer om trådar, så kommer du hitta många roligheter och en hel del konstigheter också, eftersom man måste säkra upp sin kod så att endast EN tråd får komma åt delad information åt gången, felhanteringen är också lite speciell, eftersom ett fel i en tråd inte kastas tillbaka till huvudtråden på det sätt som du tror, alltså får du ett fel i en tråd så är det inte säkert att din applikation stoppas, det kan vara så att det endast är tråden som stoppas och du får aldrig reda på det i din huvudtråd :)

- M

PatrikBMedlem sedan mars 20002 836 inlägg
#3

Det med return vet jag .... lite skräp som ligger kvar ... testade bara rent "frankt" att skapa en ny tråd. Det är på inga vis färdigt utan bara testning .... och det var lite av en "bakgrunds process" som jag ville få fram så att inte aspx-sidan gör en timeout.

Dock är det så här att jag har admin på mail-servern och kan där se prestandan (genom loggning) och där visade det sig att det med att skapa en ny tråd som skickar iväg alla mail, inte en tråd per mail, var 500% snabbare ..... har gjort flera olika körningar och alla har visat samma resultat ....

Ska dock läsa på mer om trådar, det var som sagt bara en "vild chansning" med att skapa en ny tråd ... som visade sig ge klart bättre prestanda ...

Lite tips om vart man kan hitta info om "trådar"?

cya,
/PatrikB

GladhMedlem sedan maj 20012 812 inlägg
#4

Varför det blir snabbare att skicka allt i en tråd vet jag inte. Antar väl precis som du att det ligger en massa overhead i ASPX tråden så fall.

Information om trådar finns dels i hjälpen för VS.NET dels på MSDN dels här: http://www.google.dk/search?q=%2B"Thread"+%2B"C%23"&ie=UTF-8&oe=UTF-8&hl=da&meta=

- M

kristofferMedlem sedan juni 20001 257 inlägg
#5

Använd w3JMail Professional istället. Där finns ínbyggda funktioner för att fullkomligt spruta ut mail. Du kan få w3JMail att fungera i ASP.NET också.

PatrikBMedlem sedan mars 20002 836 inlägg
#6

Som sagt, nu finns inte w3JMail installerat på den servern + om det fanns det så tror jag inte att användarna har rätt till pick-up-foldern på servern för att kunna använda den funktionaliteten i w3JMail.
Hade man haft det, en pickupfolder, så går det ju hur lätt som helst att "fixa till" en lista som sprutar ut mailen ... tyvärr är så inte fallet nu.
Endast CDONTS kan användas vilket inte är speciellt lyckat vid "mass-mail"/epost-listor med mellan 500 - 1500 medlemmar

En annan aspekt på det hela.
Vill inte vara beroende av vad som finns installerat på en server, för när nästa kund vill ha något så finns säkerligen inte dessa grejjer installerad på den kundens server eller möjlighet att installera det som behövs.

cya,
/PatrikB

BrimbaMedlem sedan dec. 19995 875 inlägg
#7

Bygg en massmailer-service som du lägger på servern. Den kan sedan exempelvis ligga och läsa av en databastabell emellanåt. När den ser en post i tabellen så itererar den alla poster och för varje post skickar den ett mail, och sedan kör du en delay (för att inte belasta servern).
Du kan ju ställa in att den kollar efter mail i tabellen var 15:e minut eller något...

PatrikBMedlem sedan mars 20002 836 inlägg
#8

Vad menar du med "service"?
En "vanlig" windows-tjänst?
Något sådant tror jag inte ett vanligt webbhotell tillåter.
Koden ska kunna köras UTAN att behöva ha tillgång till servern, dvs koden ska kunna köras på en vanlig webbhotells-server.

Annars, då hade detta redan varit fixat med att starta en enkel SMTP-tjänst och sedan parsa ned mail till PickUp-foldern. TJOFF!!! så var en jädrans massa mail ivägskickade :e

cya,
/PatrikB

138 ms totalt · 3 externa anrop · v20260731065814-full.29ac60f6
0 ms — hämta forumlista (cache)
0 ms — hämta statistik (cache)
135 ms — hämta tråd, inlägg och bilagor (db)