views:

581

answers:

3

I am using this method to send a MAPI email with a PDF attachment from inside a Delphi application.

It brings up an MS Outlook "new message" window with the pdf document already attached, and a blank recipient.

If you type in a normal email contact, then it goes through fine.

However, if you select a fax recipient, it appears in my "Sent Items" folder, but delivery fails silently (no error, no MS Outlook "delivery failed" message, and no delivery of the message).

The "fax recipient" is set up in MS Outlook with nothing but a fax number. No email or anything. We use a faxcore server to route these "faxes" to the outlook inbox.

If you look at this image, the only field I've filled in for this contact is the one labeled "Business Fax".

If I manually (i.e., outside of my application) create a standard MS Outlook email and choose the very same fax recipient, and manually attach the very same PDF, then it goes through fine.

So it seems that something about using MAPI to send to a fax number causes it to fail. This post sounds similar, except they get a "message undeliverable" error and I don't.

Can anyone give me some pointers on this?

Thanks

Update: If I use MAPI to create the email, but then I manually delete the attachment, then it does work. So from within outlook, I can email an attachment to a fax recipient, but using MAPI it fails.

Complete source code follows:

unit Main;

interface

uses
  Windows, Messages, SysUtils, Classes, Graphics, Controls, Forms, Dialogs,
  StdCtrls;

type
  TForm1 = class(TForm)
    Button1: TButton;
    procedure Button1Click(Sender: TObject);
  private
    function SendEMailUsingMAPI(const Subject, Body, FileName, SenderName,
      SenderEMail, RecipientName, RecipientEMail: string): integer;
  public
    { Public declarations }
  end;

var
  Form1: TForm1;

implementation

{$R *.DFM}

uses
  Mapi;

procedure TForm1.Button1Click(Sender: TObject);
begin
  //this will bring up an MS Outlook dialog.
  //inside that dialog, if i choose a normal email recipient, it works.
  //                    if i choose a fax recipient, it fails silently.
  //if i create the email from w/in outlook, it can go to *either* with success.

  SendEmailUsingMAPI(
    'Subject',  //subject of email
    'Body',  //body of email text
    'c:\my_doc.pdf',  //attachment file name
    'My name',  //sender email name
    '[email protected]',  //sender email address
    '',  //recipient email name
    '');  //recipient email address
end;


function TForm1.SendEMailUsingMAPI(const Subject, Body, FileName, SenderName,
  SenderEMail, RecipientName, RecipientEMail: string): Integer;
var
  Message: TMapiMessage;
  lpSender, lpRecipient: TMapiRecipDesc;
  FileAttach: TMapiFileDesc;
  SM: TFNMapiSendMail;
  MAPIModule: HModule;
  FileType: TMapiFileTagExt;
begin
  FillChar(Message,SizeOf(Message),0);

  if (Subject <> '') then begin
    Message.lpszSubject := PChar(Subject);
  end;

  if (Body <> '') then begin
    Message.lpszNoteText := PChar(Body);
  end;

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

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

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

    FileType.ulReserved := 0;
    FileType.cbEncoding := 0;
    FileType.cbTag := 0;
    FileType.lpTag := nil;
    FileType.lpEncoding := nil;

    FileAttach.lpFileType := @FileType;
    Message.nFileCount := 1;
    Message.lpFiles := @FileAttach;
  end;

  MAPIModule := LoadLibrary(PChar(MAPIDLL));

  if MAPIModule = 0 then begin
    Result := -1;
  end
  else begin
    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 begin
        Result := 1;
      end;
    finally
      FreeLibrary(MAPIModule);
    end;
  end;

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

end.
+1  A: 

Could it be the fax addresses are not available in the 0 (temporary) session? In other words, does logging into a session using MAPILogon first, then providing the hSession in the MAPISendMail call help?

Paul-Jan
Great suggestion - I found an example of that here: http://www.swissdelphicenter.ch/torry/showcode.php?id=1246 but it gives me exactly the same results.
JosephStyons
+1  A: 

You could try enabling Outlook Transport Logging, hopefully some (any) error message will turn up there. Make sure to log a manual fax (working situation) first, to check if anything related actually does show up in this log.

Unfortunately, my personal success rate in solving issues through this log is zilch, but trying to get more information never hurts, right?

Paul-Jan
Another great suggestion - comparing a log of a successful email vs a failed one reveals absolutely no differences though (except in the timestamps of course). This is a good tool though, and I'll keep it in mind for the future.
JosephStyons
+1  A: 

Ok, your update points towards the attachment, so I'm going to put in another guess: try setting the filetype of the attachment explicitly to 'application/pdf' (your current code doesn't set the lpFileType field). The fax handling might be dependent on that. You can just leave the encoding parts of the MapiFileTagExt (the type lpFileType points to) blank, simply FillChar the record and set cbTag and lpTag fields.

If you need code (the mapi structures can be a bit dazzling at times) just yell, but it'll take me some time to find a moment to type it up.. And anyway, again, I'm just guessing. I don't have a fax setup in my home environment, otherwise I'd do some proper testing.

EDIT

Illustrating bit of code below. However, I've since then checked with Outlook Spy, and with neither method, nor when attaching a file manually, the PR_ATTACH_MIME_TAG property seems to be set on the sent item, only on the resulting incoming message.

  FillChar(FileAttach,SizeOf(FileAttach),0);
  FileAttach.nPosition := Cardinal($FFFFFFFF);
  FileAttach.lpszPathName := PChar(FileName);
  //
  MimeType := 'application/pdf'; 
  //
  FileType.ulReserved := 0;
  FileType.cbTag := Length( MimeType );
  FileType.lpTag := PByte(MimeType);
  FileType.cbEncoding := 0;
  FileType.lpEncoding := nil;
  //
  FileAttach.lpFileType := @FileType;
  Message.nFileCount := 1;
  Message.lpFiles := @FileAttach;

(code-formatter is not being particularly helpful).

Paul-Jan
Thanks again. I've posted my modified code - I'm not sure I implemented what you are suggesting though. The lpFiletype is not a string type - should I set it to a pointer to a string that contains "application/pdf" ?The current code still gives the same result. Btw it is not only with pdf files, but also if I attach a plain text file.
JosephStyons