webForumDet fria alternativet

skicka massor av mail

9 svar · 508 visningar · startad av MikeEast

MikeEastMedlem sedan sep. 200153 inlägg
#1

Hej på er!

Jag håller på med en grej som ska kunna skicka sjuka mängder mail. Det är ofta över 200.000 och den färdiga applikationen bör kunna skicka minst 10.000 på en timme.

Jag har tidigare löst det med ett jätteenkelt VBScript och aspQmail, men nu har vi alltså fått till stålars för att utveckla en mer sofistikerad applikation.

I specen står det att den måste gå att porta till olika miljöer, utan för mycket besvär. Jag har valt att göra presentationen i PHP och själva mail-skickar-kärnan i Java.

Jag har tittat på javax.mail och undrar nu om det är någon som har använd dess möjligheter att lägga mailen i kö innan man sänder dem.

Jag har även kollat lite på JAMES från Jakarta. Är det någon som har någon erfarenhet av den?

Vad jag vill göra i stort är att jag först vill generera mina 200.000 mail och spara den lokalt på disk. När detta är klart vill jag skicka dem.

Jag var tvungen att göra på det sättet när jag körde vbs, eftersom maskinen ibland hade en tendens att krasha, när jag körde generering av mail samtidigt som smtp:n och det får inte hända. Dock kommer jag att bygga in massor av olika statistikprylar, såsom tracking på vad som exakt har hänt med mailet under hela processen så jag kommer att kunna kolla vilka mail som har gått iväg.

Jag vet inte om detta är en bra lösning att spara dem lokalt först och därför tänkte jag att jag skulle höra mig för lite grann.

Någon som har någon tanke om detta?

::mikeEast

------------------
www.sthlm-mansion.com
www.milano-mansion.com

sgtpepperMedlem sedan apr. 20007 588 inlägg
#2

Är varje mail unikt eller är det samma mail fast till olika mottagare?

------------------
Peer's Law
The solution to a problem changes the problem.

MikeEastMedlem sedan sep. 200153 inlägg
#3

Det är så illa att varje mail innehåller en dynamisk body.

Den måste ändras för varje mail som går iväg. Detta på grund av att nån projektledare tyckte att det vore ballt att skriva "Hej Mario Rossi" i själva mailet.

Dessutom kommer jag att behöva lägga in en del unika id:n i mailen.

::micke

------------------
www.sthlm-mansion.com
www.milano-mansion.com

LimeMedlem sedan sep. 2001961 inlägg
#4

Vi gjorde en sån här sak för ett bolag för ett par år sedan.

Det vi gjorde då var att vi lät själva meddelandet vara XML-drivet, d.v.s. vi satte in taggar i ett meddelande som vi sedan ersatte med en SAX-parser.

Själva Mailet var ett javax.mail.Message där man kombinerade rätt meddelande med rätt användare.

När detta sedan skulle skickas så användes helt enkelt Transport.sendMessage(Message, Message.getRecipients(Message.RecipientsType.TO))

Denna metod kastar SendFailedException och MessagingException om det inte går att sända mailet.

I Transport så lade vi till en TransportListener som returnerar ett "MESSAGE_DELIVERED" eller ett "MESSAGE_NOT_DELIVERED" beroende på vad som hänt med messet. Om mailservern man skickar det till har returnerat _DELIVERED så tar vi nästa. Om det är NOT_DELIVERED så skickas det om efter en stund (sätts sist i listan).

Man får ganska lätt timeingproblem....

/Lime

------------------
Praeterea conseo microsoftenem esse delendam.
- modernt latinskt ordspråk

MikeEastMedlem sedan sep. 200153 inlägg
#5

Hej Lime... och alla andra...

Tack för ditt inlägg Lime.. Det har varit till stor hjälp...

Jag vill bara att ni ska veta att jag har cirka 2 veckor Javaerfarenhet, så det kan nog vara en del tokigheter här... kanske kan vara kul att läsa om inte annat...

Imorgon är sista dagen för mitt projekt och det är nu nästan klart... :)

Jag har dock en liten bugg som jag inte vet hur jag ska hantera...

I min message.setSubject(strSubject); vet jag inte riktigt hur jag ska få message-objektet att tycka om åäö osv... Det kommer inte att bli aktuellt med åäö, men kanske áàèé och lite såna kommer att vara aktuellt och vad jag tror, finns inte de i ascii-127, eller vad det nu är som används som standard... På from name och to name har jag använt InternetAddress() och då satte jag charSet till iso-8859-1 och då funkade det jättebra... Dock har jag inte hittat något sätt att ändra charSet för subject... Kan man ändra charSet för en String eller hur gör man?

Hmm..

En annan grej som jag har problem med är att jag aldrig får någon response från min listener... Jag hittade några exempel 'där ute' och tog det bästa från alla... Min connection listener funkar bra, men känns onödig... Däremot ger min transport listener ingenting...
Det skulle vara mycket intressant att få den feedback som den ger och verkligen få veta om ett mail har gått iväg eller ej, eftersom jag för statistik över alla mail... Som det är nu tror man ju att alla mail har gått iväg i och med att jag får positiv response från SMTPn även om de inte går iväg... Jag tror väl att det är positivt response från SMTPn i form av att den säger att den har mottagit ett mail för behandling, men sedan lägger det mailet i BADMAIL eller nånstans...

Det jag gör är i alla fall detta (sorry för den massiva kodpejstningen):

Properties props = System.getProperties();
			
String host = "localhost";
props.put("mail.smtp.host", host);
			
Session session = Session.getInstance(props, null);
session.setDebug(false);
			
InternetAddress fromAddress = new InternetAddress(senderEmail, senderName);
Transport transport = session.getTransport("smtp");
transport.addTransportListener(new TransportHandler());
transport.connect();
// query och params har jag klippt ut här... men frågan returerar recipients iaf... massor.. 
ResultSet rs = dbstmt.executeQuery(query, param);
			
while(rs.next()) {
	String strFullName = rs.getString("strName") + " " + rs.getString("strSurName");
	String strEmail = rs.getString("strEmail");
	MimeMessage message = new MimeMessage(session);
	message.setSubject(strSubject);
	message.setFrom(fromAddress);
	message.addRecipient(Message.RecipientType.TO, new InternetAddress(strEmail, strFullName, "iso-8859-1"));
				
	message.setContent(strMailBody, "text/html" );
	message.saveChanges();
	
	transport.sendMessage(message, message.getRecipients(Message.RecipientType.TO));
				
}
transport.close();

Ser ni något brutalt fel där?

Jag har en klass, TransportHandler(), som har tre olika metoder som då skulle vara den som tar hand om de event som TransportListernern skulle ge:
public void messageTransferred(TransportEvent te)
public void messagePartiallyTransferred(TransportEvent te)
public void messageNotTransferred(TransportEvent te)

Vad jag trodde var att det skulle funka lika bra som min ConnectionHandler och köra dessa events, men det gör det inte och jag förstår inte varför... Jag saknar dock fundametal kännedom om listeners i allmänhet, så jag har egentligen ingen aning...

Ett sista problem som jag har är att jag får MessagingException med en nested IOException med följande kommentar "Socket Write Error"... Det är ju lite störande... Men i och med att jag inte riktigt förstog mig på hur jag skulle bära mig åt för att få bukt på det problemet har jag gjort en workaround... Jag fångar Exception:en och startar om min sändning och eftersom jag har koll på vilka jag redan har skickat till kan jag inte skicka till samma person igen... Men det sticker ändå lite i min ögon att applikationen skall tilllåtas krasha under kontrollerade former för att sedan fortsätta och krasha på nytt... Det MÅSTE ju gå att komma undan med det... En idé jag hade var att jag kör det i en tråd som jag pausar lite då och då, så jag inte steker Socket:en...

Hmm..

Hoppas jag inte har rört till allt för mycket nu... Men om någon har en liten kommentar på detta, vad som helst, är det jättevälkommet...

Tackar..

::mikeEast

LimeMedlem sedan sep. 2001961 inlägg
#6

String-encoding

Vi tar den lätta först...

Sträng kodad enligt ISO-8859-1 ....

new String("Jag kan skriva åäö!!", "ISO-8859-1").

Så var det med de.

/Lime

MikeEastMedlem sedan sep. 200153 inlägg
#7

Yo...

Hehe...

Den var ju inte så klurig... Nu har jag pillat klart med allt utom Listenern...

För jag väntar på ett genialiskt svar från Lime... :)

Owella.. Det är inte så bråttom... Den funkar nu, men sakar alltså bara feedback till statistiken... vilket inte är så otroligt viktigt just nu...

Men jag är dock fortfarande otroligt nyfiken på hur man kommer åt det som Listenern har snappat upp..

Tack!

::m

LimeMedlem sedan sep. 2001961 inlägg
#8

Jag gjorde en liten enkel sak som implementerade TransportListener (eller snarare Adaptern) och kodade metoderna:

public void messageTransferred(TransportEvent te)
public void messagePartiallyTransferred(TransportEvent te)
public void messageNotTransferred(TransportEvent te)

så att det skrev ut TransporEventet.

Skapade en metod som alla anropade:

private void logEvent(TransporEvent te) {

switch (te.getType()){
    case TransportEvent. MESSAGE_DELIVERED:
             System.out.println("Message has been successfully delivered to all recipients by the transport firing this event.";
             printAddresses(te.getValidSentAddresses());
             break;
    case TransportEvent.MESSAGE_NOT_DELIVERED: 
          System.out.println("Message was not sent for some reason.");
          printAddresses(te.getValidSentAddresses());
          break;
    case TransportEvent.MESSAGE_PARTIALLY_DELIVERED
         System.out.println("Message was successfully sent to some recipients but not to all."); 
       printAddresses(te.getValidSentAddresses());
          break;

     } // switch
}

private void printAddresses(Addresses[] adresses){
     // Skriver ut arrayen... den får du skriva själv...

}

Detta loggar utskickade mail som den ska...
Det jag upptäckte är dock att man inte får stänga ner transport-objektet innan man har fått alla TransportEvents. Verkar alltså läge att ha den som en statiskt variabel så den inte blev bortstädad. Det kan nämeligen ta en stund innan ackarna kommer tillbaka.

Din ide om att sakta ner utskickande så det blev lite mer kontrollerat var också bra. Jag löste det iofs genom att helt enkelt ha en global räknare som räknades upp när jag skickade ett mail och räknades ner när en TransportEvent kom tillbaka och det var ok.
/Lime

MikeEastMedlem sedan sep. 200153 inlägg
#9

Återigen stort tack för din tid och ditt svar, Lime...

Nu är jag färdig med mitt projekt. Del 1 i alla fall... Det kommer en update senare... men imorrn är det andra grejer på g... VB tyvärr =/

Hur som helst...

Jag fick igång listenern och det visade sig att den inte var helt döv och lam som jag först misstänkte...

men...

Även om jag skickar in en mailadress som är nåt i stil med 'sdfdsfsdfsfdsf' eller nåt annat som inte borde gå att leverera så får jag ändå rapport om att det är leverarat, vilket jag tolkar som att Listenerns rapportering handlar om en bekräftelse att det är levererat till SMTPn och inte att det är levererat till slutmottagaren....

Jag har en hel del sådana poster i de recipientlistor jag får, det är ju trots allt över 200.000 ibland så det är oundvikligt förstås...

Owella... Jag skickar ju HTML-mail och jag har lagt in en bild i dem som egentligen inte är en bild, utan bara ett anrop till min statistikserver om att mailet är läst, så jag kanske ska nöja mig med det...

...om det inte går att ta reda på om mailet är skickat och mottaget på nåt sätt förståss... För det verkar inte som om transportListenern kan ge mig den informationen...? Eller har jag missuppfattat det hela?

Jag tror att jag läste nånstans att man kan kolla mot SMTPn och titta i DROP-foldern och se vilka som var felaktiga osv... Är det kanske så man ska göra?

Det handlar om att jag till slut vill rensa ut de adresser som är helt felaktiga, eller som har uppphört etc.

Det får bli i del två... om inte någon har någon revolutionerande idé om detta...

--------------

Dock upptäckte jag, till min stora glädje, vid ett test i natt att i produktionsmiljön betedde den sig mycket bättre än på min maskin... Jag skickade 5000 mail på 15 minuter på en IBM Netfinity M20(P3-500 med 256Mb RAM). Tyvärr vet jag inte vad vi har för lina eller vad det kan vara för andra parametrar som spelar in.. men man kan väl tuna SMTPn och sätta hur många connections den ska acceptera och lite sånt... men det är verkligen inte mitt område...

Hur som helst är resultatet att den här applikation är dubbelt så snabb som den som vi använde förut och ungefär 1000 gånger lättare att administrera...

Toppen...

Tack för all hjälp!

::mikeEast

LimeMedlem sedan sep. 2001961 inlägg
#10

Ingen orsak... Vart skall räkningen skickas?

:)

/Lime

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