Solved

Sending an email with ShellExecute

Posted on 2000-03-01
16
624 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
[X]
Welcome to Experts Exchange

Add your voice to the tech community where 5M+ people just like you are talking about what matters.

  • Help others & share knowledge
  • Earn cash & points
  • Learn & ask questions
  • 6
  • 6
  • 2
  • +2
16 Comments
 
LVL 13

Accepted Solution

by:
Epsylon earned 100 total points
ID: 2575520
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
ID: 2575529
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
ID: 2575717
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
Technology Partners: We Want Your Opinion!

We value your feedback.

Take our survey and automatically be enter to win anyone of the following:
Yeti Cooler, Amazon eGift Card, and Movie eGift Card!

 
LVL 5

Expert Comment

by:TheNeil
ID: 2575822
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
ID: 2575910
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
ID: 2575991
Or use the TNMSMTP component....
0
 
LVL 3

Author Comment

by:jdthedj
ID: 2577000
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
ID: 2578447
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
 
LVL 3

Author Comment

by:jdthedj
ID: 2578593
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
ID: 2579303
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
ID: 2579381
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
ID: 2580149
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
ID: 2580667
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
ID: 2581135
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
ID: 2582215
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
ID: 2585327
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

Enroll in June's Course of the Month

June’s Course of the Month is now available! Experts Exchange’s Premium Members, Team Accounts, and Qualified Experts have access to a complimentary course each month as part of their membership—an extra way to sharpen your skills and increase training.

Question has a verified solution.

If you are experiencing a similar issue, please ask a related question

This article explains how to create forms/units independent of other forms/units object names in a delphi project. Have you ever created a form for user input in a Delphi project and then had the need to have that same form in a other Delphi proj…
In my programming career I have only very rarely run into situations where operator overloading would be of any use in my work.  Normally those situations involved math with either overly large numbers (hundreds of thousands of digits or accuracy re…
If you're a developer or IT admin, you’re probably tasked with managing multiple websites, servers, applications, and levels of security on a daily basis. While this can be extremely time consuming, it can also be frustrating when systems aren't wor…
In this video, viewers are given an introduction to using the Windows 10 Snipping Tool, how to quickly locate it when it's needed and also how make it always available with a single click of a mouse button, by pinning it to the Desktop Task Bar. Int…

729 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