Solved

Sending an email with ShellExecute

Posted on 2000-03-01
16
599 Views
Last Modified: 2010-04-04
Hi

I am wanting to allow people to register my ap.  When the fields have been filled out on my registration form I want the user to click a button to send the details to me by email.

I can use ShellExecute to open the user's mail program and set my email address in place, but can I also from my form fill out the rest of the email (subject, body etc), and if so, how?  Also can the email programs "send" function be activated from my ap (assuming I use SW_MINIMIZE or SW_HIDE with ShellExecute)?

I have looked at using an Smtp component instead, but I don't want the user to have to specify a lot of settings like ports and servers.

Thanks in advance for any help

Regards

John
0
Comment
Question by:jdthedj
  • 6
  • 6
  • 2
  • +2
16 Comments
 
LVL 13

Accepted Solution

by:
Epsylon earned 100 total points
Comment Utility
function TForm1.CreateMail( sSubject : string; rgTo, rgCc, rgBcc, rgContent : TStrings ) : Boolean;
var
  sTo, sCc, sBcc, sContent, sURL : string;

  function LinesToStr( rgs : TStrings; const sDelim : string ) : string;
  var
    iIndex          : Integer;
  begin
    Result := '';
    for iIndex := 0 to rgs.Count - 1 do
    begin
      Result := Result + rgs[ iIndex ];
      if ( iIndex < rgs.Count - 1 ) then Result := Result + sDelim;
    end;
  end;

begin
  Result := False;
  if not ( Assigned( rgTo ) and Assigned( rgCc ) and Assigned( rgBcc ) and Assigned( rgContent ) )
    then Exit;
  sTo := LinesToStr( rgTo, '; ' );
  sBcc := LinesToStr( rgBcc, '; ' );
  sCc := LinesToStr( rgCc, '; ' );
  sContent := LinesToStr( rgContent, '%0D%0A' );
  sURL := 'mailto:' + sTo;
  if ( sCc <> '' ) then sURL := sURL + '?cc=' + sCc;
  if ( sBcc <> '' ) then sURL := sURL + '&bcc=' + sBcc;
  if ( sSubject <> '' ) then sURL := sURL + '&subject=' + sSubject;
  if ( sContent <> '' ) then sURL := sURL + '&body=' + sContent;
  Memo2.Text := sURL;
  Result := ShellExecute( 0, 'Open', PChar( sURL ), nil, nil, SW_SHOWNORMAL ) > 32;
end;

procedure TForm1.Button1Click(Sender: TObject);
begin
  CreateMail(Edit1.Text, ListBox1.Items, ListBox2.Items, ListBox3.Items, Memo1.Lines);
end;
0
 

Expert Comment

by:Gurkan
Comment Utility
You can set recipient,subject and body of the message using the following code:

EditBoxes are for Recipient and Subject;
Memo is for the body of the message (U can create a format using the memo)

procedure TForm1.Button1Click(Sender: TObject);
Var
Buffer : String;
recip,subj,mess : String;
begin
recip:= Edit1.text;   {message recipients' email address}
subj:=Edit2.Text;     {message subject}
Mess:= Memo1.Text;    {message body}
Buffer:='mailto:'+recip+'?subject='+subj+'&body='+mess;
ShellExecute(Application.Handle,'open',PChar(Buffer),nil,nil,SW_Normal);
end;
0
 
LVL 3

Author Comment

by:jdthedj
Comment Utility
Hi Epsylon and Gurkan - thanks for the replies.  

I have tried both lots of code and have the same problem with each.  My mail program will open when I put in an email address by itself, or add a subject that has no spaces in it.  It will not work at all if I put in anything in the body, or if I have spaces in the Subject.

Any ideas?

John
0
 
LVL 5

Expert Comment

by:TheNeil
Comment Utility
Why not get away from ShellExecute and send the mail via MAPI?

Try this

uses mapi;

FUNCTION SendEMail(Handle : THandle; Mail : TStrings):Cardinal;
TYPE
  TAttachAccessArray = ARRAY [0..0] OF TMapiFileDesc;
  PAttachAccessArray = ^TAttachAccessArray;
VAR
  MapiMessage : TMapiMessage;
  Receip      : TMapiRecipDesc;
  Attachments : PAttachAccessArray;
  AttachCount : INTEGER;
  iCount      : INTEGER;
  FileName    : STRING;
BEGIN
  fillChar(MapiMessage, SizeOf(MapiMessage), #0);
  Attachments := NIL;
  fillChar(Receip,SizeOf(Receip), #0);
  IF Mail.Values['to'] <> ''
  THEN
  BEGIN
    Receip.ulReserved := 0;
    Receip.ulRecipClass := MAPI_TO;
    Receip.lpszName := StrNew(PChar(Mail.Values['to']));
    Receip.lpszAddress := StrNew(PChar('SMTP:' + Mail.Values['to']));
    Receip.ulEIDSize := 0;
    MapiMessage.nRecipCount := 1;
    MapiMessage.lpRecips := @Receip;
  END;

  AttachCount := 0;
  FOR iCount := 0 TO MaxInt
  DO
  BEGIN
    IF Mail.Values['attachment' + IntToStr(iCount)] = ''
    THEN
      BREAK;
    AttachCount := AttachCount + 1;
  END;
 
  IF AttachCount > 0
  THEN
  BEGIN
    GetMem(Attachments,SizeOf(TMapiFileDesc) * AttachCount);
    FOR iCount := 0 TO (AttachCount - 1)
    DO
    BEGIN
      FileName := Mail.Values['attachment' + IntToStr(iCount)];
      Attachments[iCount].ulReserved := 0;
      Attachments[iCount].flFlags := 0;
      Attachments[iCount].nPosition := ULONG($FFFFFFFF);
      Attachments[iCount].lpszPathName := StrNew(PChar(FileName));
      Attachments[iCount].lpszFileName := StrNew(PChar(ExtractFileName(FileName)));
      Attachments[iCount].lpFileType := NIL;
    END;
    MapiMessage.nFileCount := AttachCount;
    MapiMessage.lpFiles := @Attachments^;
  END;

  IF Mail.Values['subject'] <> ''
  THEN
    MapiMessage.lpszSubject := StrNew(PChar(Mail.Values['subject']));
  IF Mail.Values['body'] <> ''
  THEN
    MapiMessage.lpszNoteText := StrNew(PChar(Mail.Values['body']));

  Result := MapiSendMail(0, Handle, MapiMessage,MAPI_DIALOG*Ord(Handle <> 0) OR MAPI_LOGON_UI OR MAPI_NEW_SESSION, 0);

  FOR iCount := 0 TO (AttachCount - 1)
  DO
  BEGIN
    strDispose(Attachments[iCount].lpszPathName);
    strDispose(Attachments[iCount].lpszFileName);
  END;

  IF assigned(MapiMessage.lpszSubject)
  THEN
    strDispose(MapiMessage.lpszSubject);
  IF assigned(MapiMessage.lpszNoteText)
  THEN
    strDispose(MapiMessage.lpszNoteText);
  IF assigned(Receip.lpszAddress)
  THEN
    strDispose(Receip.lpszAddress);
  IF assigned(Receip.lpszName)
  THEN
    strDispose(Receip.lpszName);
END;

procedure TForm1.Button1Click(Sender: TObject);
VAR
  mail : TStringList
BEGIN
  mail := TStringList.Create;
  mail.values['to']      := 'Bloke@Geeza.com';
  mail.values['subject'] := 'A subject';
  mail.values['body']    := 'Some body text (line 1)';
  mail.values['body']    := 'Some more body text (line 2)';
  mail.values['attachment0'] := 'c:\winnt\winnt256.bmp';
  mail.values['attachment1'] := 'c:\winnt\winnt.bmp';
  sendEMail(Application.Handle, mail);
  mail.Free;
END;

The Neil
0
 

Expert Comment

by:Gurkan
Comment Utility
The code I gaved works with spaces (in MS Outlook, U may need re-setup your e-mail prog.
0
 
LVL 13

Expert Comment

by:Epsylon
Comment Utility
Or use the TNMSMTP component....
0
 
LVL 3

Author Comment

by:jdthedj
Comment Utility
Thanks for the replies.

TheNeil: I thought you had to have a MAPI compliant application loaded to be able to use MAPI

Epsylon: I am using D4 Standard, and I don't have TNMSMTP

Gurkan: I want to use your and Epsylon's orginal code, so I will check out my mail program.  I use Pegasus Mail.

John
0
 
LVL 13

Expert Comment

by:Epsylon
Comment Utility
John, it's not possibe to activate the 'Send' button.

If it IS possible then anyone could embed this in html documents and allow sending unautorised email.....
0
How your wiki can always stay up-to-date

Quip doubles as a “living” wiki and a project management tool that evolves with your organization. As you finish projects in Quip, the work remains, easily accessible to all team members, new and old.
- Increase transparency
- Onboard new hires faster
- Access from mobile/offline

 
LVL 3

Author Comment

by:jdthedj
Comment Utility
Thanks Epsylon  - I hadn't thought of that!

I really want your code to work, but I am wondering if I can use DDE once I have opened the mail program with ShellExecute and embedded the email address using your code.  I have been experimenting, but so far no luck.

John
0
 
LVL 13

Expert Comment

by:Epsylon
Comment Utility
I'm not familiar with DDE because I never needed it. Btw, you never know which email client the user is running so I wonder if a DDE solution will work for all available email clients.

Eps.
0
 
LVL 3

Author Comment

by:jdthedj
Comment Utility
I guess you're right, Epsylon.  If I don't get any other ideas from the experts I will give you the points because I know your code should work.  Your code is a bit more complete than Gurkan's and I really wish I could get round the spaces problem.  Maybe I'll replace my mail program and see if that will work - it could just be Pegasus Mail that's the problem.

John
0
 
LVL 13

Expert Comment

by:Epsylon
Comment Utility
About the spaces problem, they should be replaced with a '%20'.

The MailTo protocol and URL coding are decribed in:

ftp://ftp.isi.edu/in-notes/rfc2368.txt
http://support.microsoft.com/support/kb/articles/Q153/5/45.asp
ftp://ftp.isi.edu/in-notes/rfc1738.txt



I wrote something to encode subjects/bodies etc. I did not fully test it and it needs more character in the set.


procedure TForm1.Button1Click(Sender: TObject);
var cset: set of Char;
    s: String;
    c: Char;
    i: Integer;
begin
  cset :=  [' ', '#', '<', '>', '"', '%', '?', '+'];
  s := Edit1.Text;
  for i := length(s) downto 1 do
  begin
    c := s[i];
    if c in cset then
    begin
      delete(s, i, 1);
      insert('%' + IntToHex(ord(c), 2), s, i);
    end;
  end;
  Edit2.Text := s;
end;
0
 

Expert Comment

by:mike_tipping
Comment Utility
Look at Question Q.10225090, It add the 'pressing the send button' and closing the mail application bit to the 'mailto:' solution.

Works fine for me.
0
 
LVL 13

Expert Comment

by:Epsylon
Comment Utility
Mike, It won't work with all email clients I guess and the 500 ms seems a little bit short to me. Good idea though! I didn't think of it.
0
 
LVL 3

Author Comment

by:jdthedj
Comment Utility
Thanks for the continued response.

Mike -

thanks for your tip.  Interestingly, my mail program does actually *send* the mail automatically (though I keep it offline while testing)  I can't see why it does, but that is not a problem.

Epsylon -

your latest comment really helps.  I can now get the subject line to be accepted with spaces in it, BUT I still cannot get anything at all in the body.  If I leave the body blank the mail program opens with the message box showing the address and subject.

If I include a body the mail program opens momentarily and sends the mail!, but when I look at it the body is blank.

So near, yet so far.....

I will leave this open a little longer in the hope that someone can come up with something, then I will give you the points.

John
0
 
LVL 3

Author Comment

by:jdthedj
Comment Utility
Hi again Epsylon

I have made some interesting discoveries.  I downloaded 4 different mail programs and got widely differing results.

Outlook will accept the text in the body.  (I had to wait till I got to work this morning to test it).  Another program would not accept the text in the body (as well as my program Pegasus Mail) but also it did not like the encoding in the subject line and printed it with the hex numbers as well.

Since I cannot rely on each user's program behaving the same way I think I will just have to resort to putting in the email address and leave the user to fill in the rest.  Pity it doesn't generate an error if the results are not what you expect!  (Wonder how the commercial programs cope with this problem?)

Thanks again for all your help

John
0

Featured Post

Highfive Gives IT Their Time Back

Highfive is so simple that setting up every meeting room takes just minutes and every employee will be able to start or join a call from any room with ease. Never be called into a meeting just to get it started again. This is how video conferencing should work!

Join & Write a Comment

The uses clause is one of those things that just tends to grow and grow. Most of the time this is in the main form, as it's from this form that all others are called. If you have a big application (including many forms), the uses clause in the in…
Introduction I have seen many questions in this Delphi topic area where queries in threads are needed or suggested. I know bumped into a similar need. This article will address some of the concepts when dealing with a multithreaded delphi database…
Get a first impression of how PRTG looks and learn how it works.   This video is a short introduction to PRTG, as an initial overview or as a quick start for new PRTG users.
Here's a very brief overview of the methods PRTG Network Monitor (https://www.paessler.com/prtg) offers for monitoring bandwidth, to help you decide which methods you´d like to investigate in more detail.  The methods are covered in more detail in o…

762 members asked questions and received personalized solutions in the past 7 days.

Join the community of 500,000 technology professionals and ask your questions.

Join & Ask a Question

Need Help in Real-Time?

Connect with top rated Experts

15 Experts available now in Live!

Get 1:1 Help Now