Link to home
Start Free TrialLog in
Avatar of cyberman05
cyberman05

asked on

Sending emails

Hi!

I'm still trying to fix this "address book" application:

http://users.volja.net/cyberman05/slike/imenik2.jpg
http://users.volja.net/cyberman05/slike/imenik1.jpg

The problem is again at the mailing part. I'm using TSMTPRelayServer component for sending mails which you can download here:

http://users.volja.net/cyberman05/Tester/absr116.zip

or from official www.legitima.com software site. I'd like to send personalized email to all of my friends one by one, one after another and invite them to my birthday (attachment invitation.doc is included). This SMTPRelayServer component promises just this. It has OnGetData event which triggers before the mail is send and where you can design body part of an email. After the mail has been successfully sent the onFinished event triggers. The onProcessEmail event notifies you about successfull delivery of email. Component works ASYNCHRONEOUSLY. Here starts my problem. I can't send multiple emails one after another becouse "component is busy error occurs". If I try to take that into consideration with this piece of code:

  if not SmtpRelayServer1.Busy then    //if compoment is not busy than send mail to George (first on the list)
  begin
    SmtpRelayServer1.Dns:='195.130.224.18';
    SmtpRelayServer1.Connections := 100;  //100 simultaneous connections
    SmtpRelayServer1.TimeOut := 60;
    SmtpRelayServer1.Recipients.Add(strMailTo);
    SmtpRelayServer1.From := strFrom;
    SmtpRelayServer1.HeaderFrom := '"Best friend" <' + strFrom + '>';
    SmtpRelayServer1.Subject := 'Invitation to my birthday';
    SmtpRelayServer1.Attachments.Add(edit1.Text);
    try
      SmtpRelayServer1.Send;
    except
    on e:exception do
     begin end;
    end;
  end
  else     //else if busy (mail is still being send to George, so Jake has to wait) then
    begin
      repeat
      until SmtpRelayServer1.Busy; //repeat until not busy any more
      SendSMTPServerMail(HeaderTo,strMailTo); //and then send mail again to same recipient (Jake)
    end;

the mail is sent only to the first recipient on the list and noone else. Besides it performs some weird loops even if the component is not busy. The HeaderTo and strMailTo is retrieved from address book's Paradox database. I've developed a small testing application which you can download here:

http://users.volja.net/cyberman05/Tester/TesterNet.zip

or just see the source code of the main unit here:

http://users.volja.net/cyberman05/Tester/Unit1.txt

So, how do I send personalized mail one by one, one after another without getting "component is busy" error? Please help!
Avatar of calinutz
calinutz
Flag of Romania image

You should try the components from Delphi FastNet Pallete (D6) or idSMTP from Indy Clients Palette (D7)
 I never had problems with them.
Avatar of cyberman05
cyberman05

ASKER

The advantage of this component is that you don't have to put down any SMTP hosts or passwords, "becouse TSMTPRelayServer acts as a SMTP server". It sends emails through DNS server. No SMTP hosts, no passwords, easy to use, at least what sending only 1 email is concerned.
if not SmtpRelayServer1.Busy then
begin
 ....
 try
    SmtpRelayServer1.Send;
 except
    on e:exception do
    begin end;
 end;    
end
else
    begin
      repeat

      until
        SmtpRelayServer1.Busy; //repeat until not busy any more

      SendSMTPServerMail(HeaderTo,strMailTo);
 end;

I think your problem can be found in the repeat until loop. it loops (doing nothing) until SmtpRelayServer1.Busy. Well...the component is busy so it will exit the loop immediately and will try to send the next mail.

I think it should read :

until
   not  SmtpRelayServer1.Busy ;

that way it will loop until the component is not busy anymore :)




No, this is not the solution.
Come on! I don't have any more points and I'm becoming depressed. Doesn't enyone know the answer to this problem? Than suggest something else. How can I send emails independently of any SMTP server so that I don't have to type in any host names or passwords? Is there any component that doesn't need to type in anything if you want to send an email or finds host or servers by itself?
cyberman05,
  The code below works fine for me.
  You will have to ensure that you provide a proper DNS value. The code only works on my PC only if I provide my office's internal DNS server IP:
  Also, you kept adding things to various properties without clearing them: I corrected those things in the code.
  The code now waits till one message is sent before proceeding to send another.
  Please replace your code with the one below and let me know if you still face problems (Remember to set the proper DNS).
Cheers,
...Shu


procedure TTester.SendSMTPServerMail(HeaderTo, strMailTo: string);
begin
  if not SmtpRelayServer1.Busy then    //if compoment is not busy than send mail to George
  begin
    SmtpRelayServer1.Dns:='195.130.224.18';
//    SmtpRelayServer1.Dns:='172.28.84.7';//Shu-My working DNS
    SmtpRelayServer1.Connections := 100;  //100 simultaneous connections
    SmtpRelayServer1.TimeOut := 180;
    SmtpRelayServer1.Recipients.Clear;
    SmtpRelayServer1.Recipients.Add(strMailTo);
    SmtpRelayServer1.From := strFrom;
    SmtpRelayServer1.HeaderFrom := '"Best friend" <' + strFrom + '>';
    SmtpRelayServer1.Subject := 'Invitation to my birthday';
    SmtpRelayServer1.Attachments.Clear;
    SmtpRelayServer1.Attachments.Add(edit1.Text);
    try
      SmtpRelayServer1.Send;
      repeat
        Application.ProcessMessages;
      until Not SmtpRelayServer1.Busy; //repeat until not busy any more (George got his email)
    except
    on e:exception do
     begin
       ShowMessage(e.Message);
     end;
    end;
  end
  else     //else if busy (mail is still being send to George, so Jake has to wait) then
    begin
      repeat
        Application.ProcessMessages;
      until Not SmtpRelayServer1.Busy; //repeat until not busy any more (George got his email)
      SendSMTPServerMail(HeaderTo,strMailTo); //and then send mail again to next recipient (Jake)
    end;
end;


procedure TTester.SmtpRelayServer1EMailProcessed(Sender: TObject;
  RecipientIndex, Err: Integer);
begin
//  if Err <> 0 then //repeat sending until successful
//    begin
//      SendSMTPServerMail(memo1.lines.Strings[0],memo2.lines.Strings[0]);
//    end;

  //this is error handler
    if Err = 0 then
        begin
          //Showmessage( 'Delivered and available to the recipient!');
        end
  else
        begin
          case Err of
                -9: Showmessage( 'Failed: DNS Server not responding');
                -8: Showmessage( 'Failed: Aborted by user');
                -7: Showmessage( 'Failed: Could not perform the DATA command');
                -6: Showmessage( 'Failed: Could not perform the QUIT command');
                -5: Showmessage( 'Failed: Could not perform the MAILFROM command');
                -4: Showmessage( 'Failed: Could not perform the RCPT command');
                -3: Showmessage( 'Failed: Could not perform the OPEN command');
                -2: Showmessage( 'Failed: Time Out - Recipient''s SMTP Server didn''t respond');
                -1: Showmessage( 'Failed: Invalid DNS');
          else
            if Err > 0 then
                  begin
                  case Err of
                    550: Showmessage( 'Failed: Mailbox unavailable');
                    551: Showmessage( 'Failed: User not local');
                    552: Showmessage( 'Failed: Exceeded storage allocation');
                    554: Showmessage( 'Failed: Transaction failed');
              else
                        Showmessage( Format('Failed: Recipient''s  SMTP server returned error %d',[Err]));
            end;
            end
          else
                Showmessage( Format('Failed: Error %d',[Err]));
          end;
      end;
     
end;


procedure TTester.FormCreate(Sender: TObject);
begin
  strFrom:='me@hotmail.com';
end;

procedure TTester.Button1Click(Sender: TObject);
var i: integer;
begin
  for i:=0 to memo1.Lines.Count-1 do
  begin
    SendSMTPServerMail(memo1.lines.strings[i],memo2.lines.strings[i]); //first send mail to George
    //showmessage(memo2.lines.strings[i]);
  end;
  showmessage('Done!!');
end;

procedure TTester.SmtpRelayServer1Finished(Sender: TObject;
  Aborted: Boolean);
begin
//  memo1.lines.Delete(0);  //deleting George from mailing list becouse mail has
//  memo2.lines.Delete(0);  //already been send to him
//  if memo1.lines.Count <> 0 then   //and start sending second mail to Jake who is now first on the list
//    SendSMTPServerMail(memo1.lines.Strings[0],memo2.lines.Strings[0]);
end;


procedure TTester.SmtpRelayServer1GetData(Sender: TObject;
  RecipientIndex: Integer; var HeaderTo, Subject: String;
  var Body: TStrings);
begin
   Body.Clear;
//   SmtpRelayServer1.Body.Insert(0, 'Dear ' + HeaderTo);
   Body.Add('Dear ' + HeaderTo); //personalized body, HeaderTo will be taken from database
end;
U could send mail through DNS server using TIdDNSResolver (Indy). Use that component to find out what mailservers are available for a paticular e-mail adress.
Connect to that server using TIdSMTP and TIdMessage. Not tested fully but it just might work.

procedure TForm1.BtnZoekExClick(Sender: TObject);
var
  I : Integer ;
  LDomeinDeel : String;
  LMXRecord : TMXRecord;
begin
  if not assigned(fmailServers) then
     fMailServers := TStringList.Create;
  fmailServers.clear ;
  LDomeinDeel := copy(inEmail.text,pos('@',inEmail.text)+1,length(inEmail.text));
  SNaam := copy (inEmail.text , 1 , pred(pos('@',inEmail.text)) );
  DNSr.QueryRecords :=[qtMX] ;   // find mailexchangers


  try
   DNSr.resolve(LDomeinDeel) ;

   if DNSr.QueryResult.Count > 0 then
   begin
     for i := 0 to  DNSr.QueryResult.Count - 1 do
     begin
       case DNSr.QueryResult[i].RecType of
        qtMX :
         begin
           LMXRecord := TMXRecord(DNSr.QueryResult.Items[i]);
           fMailServers.Duplicates := dupIgnore;
           fMailServers.Append(LMXRecord.ExchangeServer) ;
           fMailServers.Sorted := true;
         end ;
       end ;
      end ;
      memo1.lines.AddStrings(fMailServers) ;
   end
   else
   begin
     ShowMessage('No servers found');
   end;
  except
     //errorhandling here
  end;

DNSr = TIdDNSresolver
inEmail = TEdit
DNSr.host should be an ipnumber of a DNS-server .. never mind which one. Try and connect to any of the emailexchangers found and send your mail.
Thanks! I'll test that over the following days. I'll let you know if it works next week. I'm using an Italian DNS server and as you know Italians aren't very reliable people :)))
snehanshu!

It works almost fine. I've noticed what I have done wrong. No error occurs within the program, but I've tried every possible Italian public DNS server IP's, but none works. I get the following error:

Recipient's server returned error: 10060 or 11001, but I don't know what it means and what to do. I can't send a single mail.

Ratje!

Your code freezes my computer.
I have just discovered Indy's SMTPRelay demo that works just the same as TSMTPRelayServer. But I haven't looked at the code yet. I'll try to solve the problem with Indy and let you know how it works. Any suggestions are still welcome.
Suggestions about how to resolve DNS server mainly, becouse Indy example has a lot of errors. I've found some code on groups.google.com on how to get DNS server from registry but I don't know if that's reliable?
cyberman05,
  I tried it again just now and it worked from my home with a dial-up connection also.
  How are you connecting to the internet? Are there proxies, some policies etc. that block things?
  I got the DNS by checking the TCP/IP properties of my Dialup connection after connecting.


  Please replace all the cdode in your pas file by this and try again and let me know:
(The DNS here may work here for you too)


unit Unit1;

interface

uses
  Windows, Messages, SysUtils, Classes, Graphics, Controls, Forms, Dialogs,
  StdCtrls, ExtCtrls, USmtpRelayServer, Registry;

type
  TTester = class(TForm)
    Button1: TButton;
    SmtpRelayServer1: TSmtpRelayServer;
    Memo1: TMemo;
    Memo2: TMemo;
    Edit1: TEdit;
    procedure FormCreate(Sender: TObject);
    procedure Button1Click(Sender: TObject);
    procedure SmtpRelayServer1EMailProcessed(Sender: TObject;
      RecipientIndex, Err: Integer);
    procedure SmtpRelayServer1Finished(Sender: TObject; Aborted: Boolean);
    procedure SmtpRelayServer1GetData(Sender: TObject;
      RecipientIndex: Integer; var HeaderTo, Subject: String;
      var Body: TStrings);
  private
    { Private declarations }
  public
    { Public declarations }
    strFrom : string;
    procedure SendSMTPServerMail(HeaderTo, strMailTo : string);
  end;

var
  Tester: TTester;

implementation

{$R *.DFM}

procedure TTester.SendSMTPServerMail(HeaderTo, strMailTo: string);
begin
  if not SmtpRelayServer1.Busy then    //if compoment is not busy than send mail to George
  begin
//    SmtpRelayServer1.Dns:='195.130.224.18';
    SmtpRelayServer1.Dns:='202.54.1.30';
    SmtpRelayServer1.Connections := 100;  //100 simultaneous connections
    SmtpRelayServer1.TimeOut := 180;
    SmtpRelayServer1.Recipients.Clear;
    SmtpRelayServer1.Recipients.Add(strMailTo);
    SmtpRelayServer1.From := strFrom;
    SmtpRelayServer1.HeaderFrom := '"Best friend" <' + strFrom + '>';
    SmtpRelayServer1.Subject := 'Invitation to my birthday';
    SmtpRelayServer1.Attachments.Clear;
    SmtpRelayServer1.Attachments.Add(edit1.Text);
    try
      SmtpRelayServer1.Send;
      repeat
        Application.ProcessMessages;
      until Not SmtpRelayServer1.Busy; //repeat until not busy any more (George got his email)
    except
    on e:exception do
     begin
       ShowMessage(e.Message);
     end;
    end;
  end
  else     //else if busy (mail is still being send to George, so Jake has to wait) then
    begin
      repeat
        Application.ProcessMessages;
      until Not SmtpRelayServer1.Busy; //repeat until not busy any more (George got his email)
      SendSMTPServerMail(HeaderTo,strMailTo); //and then send mail again to next recipient (Jake)
    end;
end;


procedure TTester.SmtpRelayServer1EMailProcessed(Sender: TObject;
  RecipientIndex, Err: Integer);
begin
//  if Err <> 0 then //repeat sending until successful
//    begin
//      SendSMTPServerMail(memo1.lines.Strings[0],memo2.lines.Strings[0]);
//    end;

  //this is error handler
    if Err = 0 then
        begin
          //Showmessage( 'Delivered and available to the recipient!');
        end
  else
        begin
          case Err of
                -9: Showmessage( 'Failed: DNS Server not responding');
                -8: Showmessage( 'Failed: Aborted by user');
                -7: Showmessage( 'Failed: Could not perform the DATA command');
                -6: Showmessage( 'Failed: Could not perform the QUIT command');
                -5: Showmessage( 'Failed: Could not perform the MAILFROM command');
                -4: Showmessage( 'Failed: Could not perform the RCPT command');
                -3: Showmessage( 'Failed: Could not perform the OPEN command');
                -2: Showmessage( 'Failed: Time Out - Recipient''s SMTP Server didn''t respond');
                -1: Showmessage( 'Failed: Invalid DNS');
          else
            if Err > 0 then
                  begin
                  case Err of
                    550: Showmessage( 'Failed: Mailbox unavailable');
                    551: Showmessage( 'Failed: User not local');
                    552: Showmessage( 'Failed: Exceeded storage allocation');
                    554: Showmessage( 'Failed: Transaction failed');
              else
                        Showmessage( Format('Failed: Recipient''s  SMTP server returned error %d',[Err]));
            end;
            end
          else
                Showmessage( Format('Failed: Error %d',[Err]));
          end;
      end;
     
end;


procedure TTester.FormCreate(Sender: TObject);
begin
  strFrom:='me@hotmail.com';
end;

procedure TTester.Button1Click(Sender: TObject);
var i: integer;
begin
  for i:=0 to memo1.Lines.Count-1 do
  begin
    SendSMTPServerMail(memo1.lines.strings[i],memo2.lines.strings[i]); //first send mail to George
    //showmessage(memo2.lines.strings[i]);
  end;
  showmessage('Done!!');
end;

procedure TTester.SmtpRelayServer1Finished(Sender: TObject;
  Aborted: Boolean);
begin
//  memo1.lines.Delete(0);  //deleting George from mailing list becouse mail has
//  memo2.lines.Delete(0);  //already been send to him
//  if memo1.lines.Count <> 0 then   //and start sending second mail to Jake who is now first on the list
//    SendSMTPServerMail(memo1.lines.Strings[0],memo2.lines.Strings[0]);
end;


procedure TTester.SmtpRelayServer1GetData(Sender: TObject;
  RecipientIndex: Integer; var HeaderTo, Subject: String;
  var Body: TStrings);
begin
   Body.Clear;
//   SmtpRelayServer1.Body.Insert(0, 'Dear ' + HeaderTo);
   Body.Add('Dear ' + HeaderTo); //personalized body, HeaderTo will be taken from database
end;

end.


//------------------------------



HTH,
...Shu
thanks. I'm using dial up connection. The problem is DNS server ip. I've tried Indy components but still the same error occurs:

IdMessage.Clear;
  with IdMessage do
    begin
    From.Text := 'Best friend';
    Sender.Text := strFrom;
    Recipients.EMailAddresses := strTo;
    Subject := 'Invitation';
    //TIdAttachment.Create(IdMessage.MessageParts, 'c:\invitation.doc');
    Body.Text := 'You are invited to my birthday!';
    end;

  with IdSMTP do
  begin       //siol: 193.189.160.170, volja: 217.72.64.30   gov.si: 193.2.236.15
    Host := '217.72.64.30';//'195.130.224.18';
    try
    Connect;
    //Send(IdMessage);
    ProcessMessage(IdMessage,'c:\invitation.doc');
    Disconnect;
    except on E : Exception do
      begin
       if connected then try disconnect; except end;
         ShowMessage(E.Message);
      end;
    end;
  end;

Still the same error if I use Slovene DNS server IP. Ok, I'll try your code now. I don't have any firewalls, nothing. I'm using win2000.
But It's a funny thing. The Indy example works fine with that IP, sending only one mail, as soon as I put same code into my application nothing works anymore:))
I think it's something wrong with my computer. CPU usage is at 100% for no particular reason. I'll try it on another computer on monday.
Shu could you send me your exe file that works to my email

bostjanvalencic@@yahoo.com with only one @ of course. Thanks.
Mailed the exe and code.
Let me know if it works for you.

...Shu
Drop a TIdAntiFreeze component in the project to unfreeze the code :)
Thanks Shu. I've just tried the program in public library and it can't find DNS server error occurs. (-1 under error handler). I'll try it at home but I doubt it will work. Program is probably fine, but something else is wrong, but I don't know what. Any suggestions? Tomorrow you will get your points.
ASKER CERTIFIED SOLUTION
Avatar of snehanshu
snehanshu

Link to home
membership
This solution is only available to members.
To access this solution, you must be a member of Experts Exchange.
Start Free Trial
Shu you are even more obsessed in finding a solution than I am :))). Thanks again. There must be some problem with my computer. Now even Indy SMTPRelay demo doesn't work any more. Sometimes it works sometimes it doesn't like it is bewitched. I think I'll use MAPI if your last solution doesn't work. Points are yours. You deserve them. Thanks again.
cyberman05,
  Thanks for the points, but yes, I'd be happier to see it work for you.
  And thanks to this question, I got to know this interesting email component, which perhaps I shall also use some day
:-)

Cheers!
...Shu
 
Shu it worked on my third click. First two were "DNS server returned error 11001" which means no response from him. So be sure that your third click is on the send button, but first two clicks must be on something else:)))