Click here to Skip to main content
11,500,413 members (70,334 online)
Click here to Skip to main content

Programmatically adding attachments to emails

, 18 Jan 2006 CPOL 239.1K 2.7K 48
Rate this:
Please Sign up or sign in to vote.
A technique for programmatically adding attachments to emails.

Introduction

Having read Stephane Rodriguez's excellent and rather clever solution to programmatically adding attachments to Outlook emails, I realized how subtly useful this functionality was. Many was the time I have needed a way to send an application's document to another user. Obviously, it could be done by writing your own dialogs that mimic the mail client dialogs, but you have to hook up the address book and so on. It's far better to exploit the existing mail client software installed on the PC. I needed exactly this for an application so it could have File->Send To functionality - obviously, it needs attachments to work.

SendTo or MailTo

Stephane's article makes the perfectly valid point that using the SendTo approach is functionally better than using the mailto trick. Another compelling reason for not using mailto is it doesn't support attachments. The RFC mailto protocol is simple and doesn't specify attachments.

However, you commonly see code trying to use mailto like this:

mailto:shiver@metimbers.com?Subject=Ahoy there 
  shipmate&Body=Here's the shipping 
  manifest&Attach="D:\manifest.doc"

It probably won't attach the document because you are at the liberty of the email client to implement the mailto protocol and include parsing for the attachment clause. You may not know what mail client is installed on the PC, so it may not always work - Outlook certainly doesn't support attachments using mailto.

So what's the best (and easiest) way to do it

Stephane's solution is neat. It simulates a drag 'n drop into Outlook by using an unpublished mail helper COM object. However, by using unpublished functionality, you are at the mercy of the vendor (in this case Microsoft) changing things! And this is what has happened. The drag drop code works with no problem at all when using Outlook 2002/2003 on Win2K, but throws a 'Privileged exception' when running on XP. The presumption is there are permission issues with this combination of OS and the version of Outlook.

I needed a mail client version independent solution that supported attachments, so I chose to investigate MAPI. As it turns out, the answer is pretty simple, which is wrapped up in the CSendFileTo class.

#ifndef __SENDFILETO_H__
#define __SENDFILETO_H__

#include <mapi.h>

class CSendFileTo
{
public:
    bool SendMail(HWND hWndParent, 
         CString const &strAttachmentFileName, 
         CString const &strSubject=_T(""))
    {
        // The attachment must exist as a file on the system
        // or MAPISendMail will fail, so......
        if (strAttachmentFileName.IsEmpty())
            return false;

        // You may want to remove this check, but if a valid
        // HWND is passed in, the mail dialog will be made
        // modal to it's parent.
        if (!hWndParent || !::IsWindow(hWndParent))
            return false;

        HINSTANCE hMAPI = ::LoadLibraryA(_T("MAPI32.DLL"));
        if (!hMAPI)
            return false;

        // Grab the exported entry point for the MAPISendMail function
        ULONG (PASCAL *SendMail)(ULONG, ULONG_PTR, 
                      MapiMessage*, FLAGS, ULONG);
        (FARPROC&)SendMail = GetProcAddress(hMAPI, 
                              _T("MAPISendMail"));

        if (!SendMail)
            return false;

        TCHAR szFileName[_MAX_PATH];
        TCHAR szPath[_MAX_PATH];
        TCHAR szSubject[_MAX_PATH];
        ::StrCpy(szFileName, strAttachmentFileName.GetString());
        ::StrCpy(szPath, strAttachmentFileName.GetString());
        ::StrCpy(szSubject, strSubject.GetString());

        MapiFileDesc fileDesc;
        ::ZeroMemory(&fileDesc, sizeof(fileDesc));
        fileDesc.nPosition = (ULONG)-1;
        fileDesc.lpszPathName = szPath;
        fileDesc.lpszFileName = szFileName;

        MapiMessage message;
        ::ZeroMemory(&message, sizeof(message));
        message.lpszSubject = szSubject;
        message.nFileCount = 1;
        message.lpFiles = &fileDesc;

        // Ok to send
        int nError = SendMail(0, (ULONG_PTR)hWndParent, 
               &message, MAPI_LOGON_UI|MAPI_DIALOG, 0);

        if (nError != SUCCESS_SUCCESS && 
            nError != MAPI_USER_ABORT && 
            nError != MAPI_E_LOGIN_FAILURE)
              return false;

        return true;
    }
};

#endif

Example use

This nugatory code fragment shows how easy it is to use.

#include "SendFileTo.h"
...
...

CSendFileTo sendTo;
sendTo.(m_hWnd, _T("c://documents//menu.doc"), 
                _T("Here's the lunch menu"));

...
...

This is all straightforward, but there are a few points to note.

  • If the attachment doesn't exist as a file on the file system, the call to MAPISendMail will fail with MAPI_E_ATTACHMENT_NOT_FOUND. Hence the check at the start of the SendMail call.
  • By passing the parent HWND to the MAPISendMail function, the email client is supposed to make the send mail dialog modal to the given HWND. You may want to remove this modalness(?) and simply use HWND_DESKTOP.
  • When the MAPISendMail call is made, it doesn't send the mail, it just pops up the email client dialog with the optional subject line set and the attachment attached.
  • This code was written to compile and work with WTL (it rocks), but will work equally well using MFC.

I've successfully tested this with Outlook 2002 and 2003 on Win2K and XP. I'd be interested in hearing if it works with other mail clients I don't have access to - Eudora etc.

This class could probably do with some more error checking but I'll leave that as an exercise for the reader.

License

This article, along with any associated source code and files, is licensed under The Code Project Open License (CPOL)

Share

About the Author

David M Brooks
Technical Lead
United Kingdom United Kingdom
When Dave isn't trying to play drums, fly helicopters or race cars, he can be found coding hard and herding cats at JoinIn Networks He must try harder!

You can read Dave's ramblings in his blog Aliens Ate My GUI

Or, if you can be bothered, he twitters on BoomerDave

Comments and Discussions

 
QuestionGreat! Pin
Giordano Settimo20-Mar-15 0:05
memberGiordano Settimo20-Mar-15 0:05 
QuestionGeneral comments Pin
MadMalcolmX24-Oct-13 4:34
memberMadMalcolmX24-Oct-13 4:34 
QuestionNice, works now with wxwidgets as well Pin
Member 90858329-Jul-12 8:12
memberMember 90858329-Jul-12 8:12 
Questionsendto with attachment solution Pin
manywebbs9-Sep-11 18:14
membermanywebbs9-Sep-11 18:14 
AnswerRe: sendto with attachment solution Pin
Rocky_Bas26-Sep-13 16:54
memberRocky_Bas26-Sep-13 16:54 
GeneralMy vote of 5 Pin
itz_faraz5-May-11 19:31
memberitz_faraz5-May-11 19:31 
GeneralI hate to nag but this code sample is bad... Pin
dc_200025-Apr-11 17:46
memberdc_200025-Apr-11 17:46 
QuestionCan I use this solution for my problem.... Pin
dkperez21-Jan-10 12:16
memberdkperez21-Jan-10 12:16 
GeneralWARNING = THIS CODE PROBABLY UNSAFE Pin
sashasawchai1-Dec-08 22:21
membersashasawchai1-Dec-08 22:21 
GeneralRe: WARNING = THIS CODE PROBABLY UNSAFE Pin
David M Brooks27-Aug-09 5:14
memberDavid M Brooks27-Aug-09 5:14 
It depends on how you clean things up when you've finished with them.

To counter the argument, I've used a variation of this code in a corporate application with a user base of over 1600. It's been running for over 3 years with no problems yet.

Dave
Generalto send more than 1 mail address [modified] Pin
ArielR2-Jul-08 10:08
memberArielR2-Jul-08 10:08 
GeneralRe: to send more than 1 mail address Pin
pine_le11-Apr-10 4:28
memberpine_le11-Apr-10 4:28 
Questionwhat for ? Pin
kilt25-Jun-08 19:59
memberkilt25-Jun-08 19:59 
QuestionLotus Notes ignores lpszFileName Pin
tiggerlily29-Nov-07 23:08
membertiggerlily29-Nov-07 23:08 
Questionwhy it saves the draft into inbox folder? Pin
xuxiaohui7-Nov-07 22:37
memberxuxiaohui7-Nov-07 22:37 
QuestionNewbie problem - can't compile (get errors in mapi.h) Pin
cgalpin1-Nov-07 4:59
membercgalpin1-Nov-07 4:59 
AnswerRe: Newbie problem - can't compile (get errors in mapi.h) Pin
Varchas R S4-Nov-07 23:03
memberVarchas R S4-Nov-07 23:03 
GeneralRe: Newbie problem - can't compile (get errors in mapi.h) Pin
cgalpin6-Nov-07 7:42
membercgalpin6-Nov-07 7:42 
QuestionSending html formatted email Pin
kryzzozz7810-Oct-07 9:09
memberkryzzozz7810-Oct-07 9:09 
GeneralRe: Sending html formatted email Pin
Member 216347031-Mar-08 4:56
memberMember 216347031-Mar-08 4:56 
Generalprofile problem with MAPI Pin
rob010329-Jul-07 23:48
memberrob010329-Jul-07 23:48 
GeneralRe: profile problem with MAPI Pin
BhushanKalse27-Aug-07 20:28
memberBhushanKalse27-Aug-07 20:28 
Generalthanks! Pin
cronky7812-Jul-07 20:17
membercronky7812-Jul-07 20:17 
Generalsending problem Pin
133mmxtr11-Jun-07 2:20
member133mmxtr11-Jun-07 2:20 
QuestionWCHAR version of Mapi32.dll ?? [modified] Pin
ajitatif angajetor24-Jan-07 2:49
memberajitatif angajetor24-Jan-07 2:49 
AnswerRe: WCHAR version of Mapi32.dll ?? Pin
hannahb21-Mar-07 3:22
memberhannahb21-Mar-07 3:22 
GeneralRe: WCHAR version of Mapi32.dll ?? Pin
ajitatif angajetor27-Mar-07 6:21
memberajitatif angajetor27-Mar-07 6:21 
Generalwants demo & source Pin
shital_harode@rediffmail.com17-Nov-06 23:24
membershital_harode@rediffmail.com17-Nov-06 23:24 
GeneralRe: wants demo & source Pin
prathuraj5-Jun-07 23:10
memberprathuraj5-Jun-07 23:10 
GeneralRe: wants demo & source Pin
George Zorba21-Mar-12 21:29
memberGeorge Zorba21-Mar-12 21:29 
GeneralAnyone know how to do this with C# Pin
c-a-b-24-Aug-06 8:49
memberc-a-b-24-Aug-06 8:49 
GeneralRe: Anyone know how to do this with C# [modified] Pin
David Broooks12-Dec-06 4:01
memberDavid Broooks12-Dec-06 4:01 
GeneralRe: Anyone know how to do this with C# Pin
c-a-b-12-Dec-06 10:31
memberc-a-b-12-Dec-06 10:31 
GeneralRe: Anyone know how to do this with C# Pin
Sriharsha R19-Jan-07 1:19
memberSriharsha R19-Jan-07 1:19 
AnswerRe: Anyone know how to do this with C# Pin
goondoo277-Feb-07 10:52
membergoondoo277-Feb-07 10:52 
GeneralRe: Anyone know how to do this with C# Pin
itz_faraz5-May-11 19:32
memberitz_faraz5-May-11 19:32 
GeneralRe: Anyone know how to do this with C# Pin
David Broooks8-Feb-07 4:11
memberDavid Broooks8-Feb-07 4:11 
GeneralAnti Virus issues Pin
David Broooks23-May-06 11:34
memberDavid Broooks23-May-06 11:34 
GeneralRe: Anti Virus issues - there's more.... Pin
David Broooks23-May-06 11:45
memberDavid Broooks23-May-06 11:45 
GeneralAutomatically Send and Multiple Attachments Pin
JeffBilkey21-May-06 14:40
memberJeffBilkey21-May-06 14:40 
GeneralRe: Automatically Send and Multiple Attachments Pin
Rishabh Agrawal18-Sep-06 19:05
memberRishabh Agrawal18-Sep-06 19:05 
GeneralUnicode MFC compatible Multiple Attachment Pin
hannahb21-Mar-07 5:11
memberhannahb21-Mar-07 5:11 
QuestionTwo Questions? Pin
Sstar1-May-06 17:13
memberSstar1-May-06 17:13 
AnswerRe: Two Questions? Pin
xuxiaohui7-Nov-07 22:05
memberxuxiaohui7-Nov-07 22:05 
AnswerRe: Two Questions? Pin
novta20-Nov-07 4:02
membernovta20-Nov-07 4:02 
GeneralC++ Builder Version Pin
JeffBilkey26-Apr-06 14:33
memberJeffBilkey26-Apr-06 14:33 
GeneralRe: C++ Builder Version Pin
JeffBilkey27-Apr-06 11:25
memberJeffBilkey27-Apr-06 11:25 
GeneralRe: C++ Builder Version Pin
JeffBilkey21-May-06 14:23
memberJeffBilkey21-May-06 14:23 
GeneralRe: C++ Builder Version Pin
Oniko1126-May-06 0:24
memberOniko1126-May-06 0:24 
GeneralRe: C++ Builder Version Pin
JeffBilkey29-May-06 16:14
memberJeffBilkey29-May-06 16:14 

General General    News News    Suggestion Suggestion    Question Question    Bug Bug    Answer Answer    Joke Joke    Rant Rant    Admin Admin   

Use Ctrl+Left/Right to switch messages, Ctrl+Up/Down to switch threads, Ctrl+Shift+Left/Right to switch pages.

| Advertise | Privacy | Terms of Use | Mobile
Web03 | 2.8.150520.1 | Last Updated 18 Jan 2006
Article Copyright 2006 by David M Brooks
Everything else Copyright © CodeProject, 1999-2015
Layout: fixed | fluid