?
Solved

Sending Emails silently from Delphi

Posted on 2005-03-22
17
Medium Priority
?
813 Views
Last Modified: 2010-04-05
Hi,

I am trying to send an email from within delphi, silently, without using SMTP. I am currently using MAPI calls which work well except that when sending to a client using Outlook Express and a Linux mail server, the attachments come through as garbage or 'winmail.dat' and a wierd MIME type header.
All of the examples I have looked at pass through NIL as the filetype for the attachments sent to MAPI. Does anyone have any alternatives to using MAPI or know how to solve the problem with the attachments.

Any help would be much appreciated.

Thanks
0
Comment
Question by:AndrewNixon
[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
  • 4
  • 3
  • 3
  • +3
17 Comments
 
LVL 11

Expert Comment

by:calinutz
ID: 13609318
Using SMTP you can have it like this:
// the listBox1 contains paths to the files you want to attach to the email
// the Memo1 contains the body of your message
// imeil is the tSMTP component
// I did not understand why not use SMTP?

begin
if imeil.Connected=true then
begin
 imeil.Disconnect;
 imeil.ClearParameters;

 imeil.Host:='yourhost';
 imeil.UserID:='yourUserID'
 imeil.PostMessage.FromAddress:='your from address';
 imeil.PostMessage.FromName:='your name';

 imeil.PostMessage.Subject:='your subject';
 imeil.PostMessage.ToAddress.Clear;
 imeil.PostMessage.ToAddress.Add('your To address');
 imeil.PostMessage.Attachments.Clear;

 imeil.PostMessage.Attachments.AddStrings(ListBox1.Items);
 imeil.PostMessage.Body.Clear;
 imeil.PostMessage.Body.AddStrings(Memo1.Lines);
end
  else
  begin
 imeil.ClearParameters;


 imeil.Host:='yourhost';
 imeil.UserID:='yourUserID'
 imeil.PostMessage.FromAddress:='your from address';
 imeil.PostMessage.FromName:='your name';

 imeil.PostMessage.Subject:='your subject';
 imeil.PostMessage.ToAddress.Clear;
 imeil.PostMessage.ToAddress.Add('your To Address');
 imeil.PostMessage.Attachments.Clear;
 imeil.PostMessage.Attachments.AddStrings(ListBox1.Items);
 imeil.PostMessage.Body.Clear;
 imeil.PostMessage.Body.AddStrings(Memo1.Lines);
 imeil.Connect;
  end;
 imeil.SendMail;
Close;
end;
0
 
LVL 11

Accepted Solution

by:
calinutz earned 400 total points
ID: 13609350
0
 

Author Comment

by:AndrewNixon
ID: 13609357
Thanks for the reply, but SMTP does not help us.  We can already send using either SMTP or MAPI, the problem is that our client wants to have the emails in their 'Sent items' folder on the local machine doing the sending, thus, MAPI must be used unless there is a way to get messages sent via SMTP into 'sent items' ?

Thanks
0
Industry Leaders: 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!

 

Author Comment

by:AndrewNixon
ID: 13610433
calinutz - Thanks for the link, while there is lot of info there, it all involves sending mails by bypassing the local mail program.  I want to use the local mail program (hence the use of MAPI) in order to get it into the client's sent items folder.

Thanks
0
 
LVL 26

Expert Comment

by:EddieShipman
ID: 13611973
If you want to send it silently, why would you also want it in the client's sent folder? LOL!!

I wrote the article on Hotmail and I am working on doing attachments, too.
0
 
LVL 26

Assisted Solution

by:EddieShipman
EddieShipman earned 400 total points
ID: 13611983
[quote]there is a way to get messages sent via SMTP into 'sent items' [/quote]

Well, how about a copy? just BCC the sender.
0
 
LVL 2

Expert Comment

by:SaLz
ID: 13618734
>> If you want to send it silently, why would you also want it in the client's sent folder? LOL!!

I'm with u on that one Eddie! lol
0
 
LVL 13

Assisted Solution

by:Ashok
Ashok earned 400 total points
ID: 13619324
function SendMail(const Subject, Body, FileName,
                  SenderName, SenderEMail,
                  RecipientName, RecipientEMail: string): Integer;
var
  Message: TMapiMessage;
  lpSender, lpRecipient: TMapiRecipDesc;
  FileAttach: TMapiFileDesc;

  SM: TFNMapiSendMail;
  MAPIModule: HModule;
begin
  FillChar(Message, SizeOf(Message), 0);
  with Message do
  begin
    if (Subject <> '') then
      lpszSubject := PChar(Subject);

    if (Body <> '') then
      lpszNoteText := PChar(Body);

    if (SenderEmail <> '') then
    begin
      lpSender.ulRecipClass := MAPI_ORIG;
      if (SenderName = '') then
        lpSender.lpszName := PChar(SenderEMail)
      else
        lpSender.lpszName := PChar(SenderName);
      lpSender.lpszAddress := PChar(SenderEmail);
      lpSender.ulReserved := 0;
      lpSender.ulEIDSize := 0;
      lpSender.lpEntryID := nil;
      lpOriginator := @lpSender;
    end;

    if (RecipientEmail <> '') then
    begin
      lpRecipient.ulRecipClass := MAPI_TO;
      if (RecipientName = '') then
        lpRecipient.lpszName := PChar(RecipientEMail)
      else
        lpRecipient.lpszName := PChar(RecipientName);
      lpRecipient.lpszAddress := PChar(RecipientEmail);
      lpRecipient.ulReserved := 0;
      lpRecipient.ulEIDSize := 0;
      lpRecipient.lpEntryID := nil;
      nRecipCount := 1;
      lpRecips := @lpRecipient;
    end
    else
      lpRecips := nil;

    if (FileName = '') then
    begin
      nFileCount := 0;
      lpFiles := nil;
    end
    else
    begin
      FillChar(FileAttach, SizeOf(FileAttach), 0);
      FileAttach.nPosition := Cardinal($FFFFFFFF);
      FileAttach.lpszPathName := PChar(FileName);

      nFileCount := 1;
      lpFiles := @FileAttach;
    end;
  end;

  MAPIModule := LoadLibrary(PChar(MAPIDLL));
  if MAPIModule = 0 then
    Result := -1
  else
    try
      @SM := GetProcAddress(MAPIModule, 'MAPISendMail');
      if @SM <> nil then
      begin
        Result := SM(0, Application.Handle, Message, MAPI_DIALOG or MAPI_LOGON_UI, 0);
      end
      else
        Result := 1;
    finally
      FreeLibrary(MAPIModule);
    end;

  if Result <> 0 then
    MessageDlg('Error sending mail (' + IntToStr(Result) + ').', mtError,
[mbOK], 0);
end;

PS: you must add the MAPI unit in USES-clause. To execute this procedure:
0
 

Author Comment

by:AndrewNixon
ID: 13619350
ashok111 - Thanks for your code, it looks almost identical to my own (excpet that we can't use the MAPI_DIALOG flag), and works fine for normal situations, just not with the Linux mail server and Outlook express client.  I suspect it has something to do with the 'lpFileType' property of the TMapiFileDesc, but I don't know how to set it's properties correctly and all of the examples I have seen just set it to NIL or ignore it completely.
0
 
LVL 13

Expert Comment

by:Ashok
ID: 13620739
I found this from Microsoft site.  It is in VB.
It has a way to send e-mail to the outbox.
Also, the code is very well commented.
Unfortunately it is not in Delphi.

Sub MapiSendMail()
   Dim objSession As Object
   Dim objMessage As Object
   Dim objRecipient As Object
   Dim sProfile As String
   Dim sSubjPrmpt As String
   Dim sTextPrmpt As String
   Dim sEmailPrmpt As String
   Dim sMsgTitle As String
   ' Leaving sProfile equal to Null will
   ' force the user to select which Mapi
   ' profile to use. To keep from being
   ' prompted, you must supply a valid
   ' user profile.
   sProfile = ""
   sEmailPrmpt = "Enter valid Email Name of message recipient:"
   sSubjPrmpt = "Enter the subject line for this message:"
   sTextPrmpt = "Enter the text for this message:"
   sMsgTitle = "Mapi Macro Example"
   ' Create the Session Object.
   Set objSession = CreateObject("mapi.session")
   ' Log on using the session object.
   ' Specify a valid profile name if you want to
   ' avoid the logon dialog box.
   objSession.Logon profileName:=sProfile
   ' Add a new message object to the OutBox.
   Set objMessage = objSession.Outbox.Messages.Add
   ' Set the properties of the message object.
   objMessage.Subject = InputBox(sSubjPrmpt, sMsgTitle)
   objMessage.Text = InputBox(sTextPrmpt, sMsgTitle)
   ' Add a recipient object to the objMessage.Recipients collection.
   Set objRecipient = objMessage.Recipients.Add
   ' Set the properties of the recipient object.
   objRecipient.Name = InputBox(sEmailPrmpt, sMsgTitle)
   objRecipient.Resolve
   ' Send the message. Setting showDialog to False
   ' sends the message without displaying the message
   ' or requiring user intervention. A setting of True
   ' displays the message and the user must choose
   ' to Send from within the message dialog.
   objMessage.Send showDialog:=False
   MsgBox "Message sent successfully!"
   ' Log off using the session object.
   objSession.Logoff
End Sub

0
 
LVL 13

Expert Comment

by:Ashok
ID: 13620785
' Add an attachment (assumes "myfile.doc" exist in c:\)
 
 objMessage.Attachments.Add("MyFile.doc", 0, 1, "c:\myfile.doc")

was missing from above example
0
 

Author Comment

by:AndrewNixon
ID: 13620814
Thanks,  I'll try and do this in Delphi.
0
 
LVL 26

Expert Comment

by:EddieShipman
ID: 13621959
Why not just use Mike Shkolnik's free SimpleMAPI control:
http://www.scalabium.com
0
 
LVL 2

Assisted Solution

by:SaLz
SaLz earned 400 total points
ID: 13623127
this will send an email with attachments though outlook express.

======
try this little MAPI example:

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;
  i1: integer;
  FileName: string;
  dwRet: Cardinal;
  MAPI_Session: Cardinal;
  WndList: Pointer;
begin
  dwRet := MapiLogon(Handle,
    PChar(''),
    PChar(''),
    MAPI_LOGON_UI or MAPI_NEW_SESSION,
    0, @MAPI_Session);

  if (dwRet <> SUCCESS_SUCCESS) then
  begin
    MessageBox(Handle,
      PChar('Error while trying to send email'),
      PChar('Error'),
      MB_ICONERROR or MB_OK);
  end
  else
  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 i1 := 0 to MaxInt do
    begin
      if Mail.Values['attachment' + IntToStr(i1)] = '' then
        break;
      Inc(AttachCount);
    end;

    if AttachCount > 0 then
    begin
      GetMem(Attachments, SizeOf(TMapiFileDesc) * AttachCount);

      for i1 := 0 to AttachCount - 1 do
      begin
        FileName := Mail.Values['attachment' + IntToStr(i1)];
        Attachments[i1].ulReserved := 0;
        Attachments[i1].flFlags := 0;
        Attachments[i1].nPosition := ULONG($FFFFFFFF);
        Attachments[i1].lpszPathName := StrNew(PChar(FileName));
        Attachments[i1].lpszFileName :=
          StrNew(PChar(ExtractFileName(FileName)));
        Attachments[i1].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']));

    WndList := DisableTaskWindows(0);
    try
    Result := MapiSendMail(MAPI_Session, Handle,
      MapiMessage, MAPI_DIALOG, 0);
    finally
      EnableTaskWindows( WndList );
    end;

    for i1 := 0 to AttachCount - 1 do
    begin
      StrDispose(Attachments[i1].lpszPathName);
      StrDispose(Attachments[i1].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);
    MapiLogOff(MAPI_Session, Handle, 0, 0);
  end;
end;

procedure TForm1.Button1Click(Sender: TObject);
var
  mail: TStringList;
begin
  mail := TStringList.Create;
  try
    mail.values['to'] := 'Receiver-Email@test.xyz';
    mail.values['subject'] := 'Hello';
    mail.values['body'] := 'blah';
    mail.values['body'] := 'blah';
    mail.values['attachment0'] := 'C:\Test.txt';
    // mail.values['attachment1']:='C:\Test2.txt';
    sendEMail(Application.Handle, mail);
  finally
    mail.Free;
  end;
end;
====
0
 
LVL 4

Assisted Solution

by:HillGroover
HillGroover earned 400 total points
ID: 15304084
Hi AndrewNixon,

Dunno if you've already sorted this out yet.

Reading through the problem i see that you mentioned the "winmail.dat" file, the reason you're getting this is the format the mail is being sent in and since you're going through outlook express you might want to change the format within outlook express to plain text.

the winmail.dat file is outlook/outlook express's formatting information for that email and only a small amount of email clients can read it and put the formatting back the way it should be, especially with it going through a linux mail server this will more than likely not come out right on the receiving end. change to plain text (no formatting) and you won't have that problem.

HillGroover
0

Featured Post

Independent Software Vendors: 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!

Question has a verified solution.

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

A lot of questions regard threads in Delphi.   One of the more specific questions is how to show progress of the thread.   Updating a progressbar from inside a thread is a mistake. A solution to this would be to send a synchronized message to the…
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…
This is my first video review of Microsoft Bookings, I will be doing a part two with a bit more information, but wanted to get this out to you folks.
How to fix incompatible JVM issue while installing Eclipse While installing Eclipse in windows, got one error like above and unable to proceed with the installation. This video describes how to successfully install Eclipse. How to solve incompa…
Suggested Courses
Course of the Month12 days, 10 hours left to enroll

777 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