multithreadingdelphimail-sender

Multithread with several email account sending to a list of recipients?


My goal is speed up process of send emails, because send only with 1 email account will delay a long time when have a big list of recipients.

Then i have a txt file with several email account each line is equal to this:

Then i want create a quantity of threads equals to number of lines of this txt file ( with clarity if is greater than it, will cause errors :-) ) passing each info between "|" delimiter as parameter to each thread.

All emails recipients will be present in a unique Memo (line by line) and my app not must send same message to the same recipient once already sent.

I have a example about how create several threads, but i not know how pass these parameters to each thread created:

type 
   TMyThread = class(TThread) 
   private 
   protected 
      procedure Execute; override; 
   public 
      constructor Create; 
   end; 

constructor TMyThread.Create; 
begin 
   inherited True; 
   FreeOnTerminate := True; 
   Priority := tpNormal; 
end; 

//=================================================================

var 
   I: Integer; 
   MyThreadList: array [0..2] of TMyThread; // creates two threads
begin 
   for I := 0 to High(MyThreadList) do 
   begin 
      MyThreadList[I] := TMyThread.Create(True); 
      MyThreadList[I].FreeOnTerminate := True; 
      MyThreadList[I].Priority := tpNormal; 
      MyThreadList[I].Resume; 
   end; 
end; 

Also if exist some better idea to speed up process of send emails using only 1 email account, will be welcome.


Solution

  • To pass parameters to a thread, simply add input parameters to TMyThread's constructor. Either as individual string values (Host, Port, Username, Password, etc), or as a TStringList, or a record, whatever you are comfortable passing. The constructor can then save the data in members of the class for Execute() to use as needed. In this regard, threads don't work any differently than any other class. Only that Execute() runs in a different context than the constructor does.

    I suggest you use a thread pool with a couple of thread-safe lists. One list of SMTP providers, and one list of recipients. Create a thread pool with only as many threads as there are installed CPUs (if more than the number of recipients being sent to).

    Each thread can then do the following:

    1. extract a recipient from the recipients list. Or a handful, since a single email can be sent to multiple recipients at a time, especially if multiple recipients are on the same email domain. If no recipient(s) are available, exit.

    2. then, extract an idle SMTP provider from the providers list. If not already connected to it, connect and login as needed.

    3. then, send an email to the recipient(s).

    4. then, put the SMTP provider back in the providers list (or, leave it in the list the whole time and just mark it as idle). Leave the connection open, so another thread (or even the same thread) can use the same connection on its next iteration.

    5. Go back to #1.

    Once all threads have finished, cleanup as needed.

    Now, with that said, note that SMTP providers thwart spammers in many ways, including:

    No amount of threading will get you past these kind of limitations. If anything, you usually have to pay extra to remove them.

    The best way to handle this kind of situation is to setup an online mailing list (such as with Yahoo Groups), and then you can send 1 email to 1 address and let the mailing list provider distribute the email to subscribed members for you.