Search code examples
delphiemailattachmentshellexecutemailto

How can a Delphi Program send an Email with Attachments via the DEFAULT E-mail Client?


Within my program, I am composing an email to send using the default e-mail client software installed on a user's machine.

I have composed the mailto address, the subject, the multilined body, and I have several attachments to be included.

I almost got this working using mailto and ShellExecute as follows:

  Message := 'mailto:[email protected]'
    + '?subject=This is the subjectBehold Error Report'
    + '&body=This is line 1' + '%0D%0A'
    + 'This is line 2' + '%0D%0A'
    + 'This is line 3'
    + '&Attach=c:\file1.txt';
  RetVal := ShellExecute(Handle, 'open', PChar(Message), nil, nil, SW_SHOWNORMAL);
  if RetVal <= 32 then
    MessageDlg('Cannot find program to send e-mail.', mtWarning, [mbOK], 0);

Using Delphi 2009 on a Windows Vista machine, this will open a Microsoft Mail "Create Mail" window, with the To, Subject and Body filled correctly. However the file does not get attached.

As I researched this, I noticed some commentary stating that this technique does not work with all mail clients. However, most of the commentary is fairly old, as I realize this is a very old technique.

Then I found that Zarko Gajic said that "this approach is ok, but you are unable to send attachments in this way".

I have seen theres also the Windows Simple Mail API (MAPI), but Zarko says that only works if the end-user has MAPI-compliant email software. There are well documented techniques on using MAPI with Delphi (e.g. Sending e-mail using mapi), but they all have the disclaimer that MAPI is not always installed with Windows.

Besides, I really want the message to come up first in the user's default email program, so they will have it as part of their email records and they can edit it and decide if and when they want to send it. I'm not sure how MAPI works and if it will do that.

So my requirements are:

  1. To bring the email up in the user's mail program.

  2. To allow one or more attachments.

  3. To work with (hopefully) all email clients on any Windows machine from XP up (i.e. XP, Vista or 7).

Is there such an animal? Or maybe does someone know how to get attachments to work with the mailto/ShellExecute technique?

What do most people do?


Edit:

There have been a few answers with MAPI solutions and even an Indy solution.

The problem I have with them is that they don't necessarily use the default mail client. On my Vista machine, for example, I have set up Windows Mail as my default client. When I do a MAPI send, it does not bring up Windows Mail, but it brings up and sets up the email in Outlook instead. I don't want that.

Two of my users of my program complained:

Your debug routine fails to send the file, as it tries to start windows mail for some reason known to it's self rather than using the default mail client (in my case thunderbird)

I tried to fill up the exception report but gave up when it asked for this server, that server! I then got really annoyed because it launched Outlook - I never, ever use it or want to use it.

I don't need code for MAPI or Indy. They are readily available. But if you suggest MAPI or Indy, what I really need is a way to find the default client and ensure that it is the one that is passed the email to be sent.

Also, I need to know if MAPI is now universal. 5 years ago, it wasn't guaranteed to work on all machines because it wasn't installed as part of the operating system. Is that still true, or does MAPI now come with Windows XP, Vista and 7 by default?

Same questions go for Indy or any other suggested solutions. Can it work with the default client and will it work on almost all Windows XP and later machines?

The reason why the "mailto" solution is so nice, is that all machines have to support it for the purpose of handling the HTML mailto statement found on webpages. Now if only I could use it to add attachments ...


Likely solution found: mjustin pointed out an alternative that makes use of the Operating System's sendto command. That most likely is the way to go.

The mailto was not limited to 256 characters like the HTML mailto is, but I was devastated to find out it ended up being limited to 2048 characters. Fortunately a few hours later, mjustin gave his answer.

If implementation of that goes okay, his answer will have done it for me. If not, I'll add my comments here.


No. As it turns out, the sendto solution will not always open the default email program. On my machine, it opens Outlook when my default mailer is Windows Mail. Too bad. I've had to go back to the mailto method, despite the 2048 character limit.

I did, however, find in the article: SendTo mail recipient that:

At this point, you could replace ::ShellExecute with a well thought ::WinExec call, using the actual mailto command line declared in the registry and target the current e-mail client (for instance, "%ProgramFiles%\Outlook Express\msimn.exe" /mailurl:%1). But then the limitation is 32 KB. As a conclusion, there is no way to send e-mails larger than 32KB using the mailto protocol.

but then I'd have to determine who the mail client is in each case. I expect that would lead to further complications.

The one other thing I found out is that mailto allows setting of "to", "cc", "bcc", "subject" and "body" but no attachments. Whereas sendto ONLY allows attachments and then sets up a default email with a default message and no way for you to set the various fields and body.


Solution

  • It appears that mailto in a ShellExecute is not capable of sending attachments.

    MAPI and Indy have the unfortunate characteristic of not necessarily selecting the user's email client.

    So the other possibility is to continue using ShellExecute, but find another way to get the attachments into the email client.

    What I decided to do was on my Dialog that creates the email, I now have a FileListBox listing the files the user may want to attach to the email. When the email pops up, they can simply drag and drop them to the email.

    In my case, this is actually a good solution, since this allows the users to select the files they want to include. The other method (automatically attaching them) will require they delete the ones they don't want included. (i.e. Having the "Add Google toolbar" option already checked for you is NOT good)

    For the time being this solution will work.

    Thank you to all those who contributed answers and helped me see my way through this (all +1).