'Sending e-mail with Indy doesn't show attachment in Outlook

I have the following problem. I've created a Windows service that sends e-mail with .xls attachments. If I open the e-mail with Windows Live Mail or Web Mail, it works, I can see the attachment. The problem happens when I try to open the e-mail with Microsoft Outlook 2010, the attachment is not present and I have no idea what's wrong with my code.

E-mail header looks like this

Return-Path: <[email protected]>
Delivered-To: [email protected]
Received: (qmail 25352 invoked by uid 500); 15 Jul 2015 14:58:23 -0000
Received: by simscan 1.4.0 ppid: 25345, pid: 25349, t: 0.0443s
         scanners: attach: 1.4.0 clamav: 0.98.5/m:
Received: from unknown (HELO ab-c11) ([email protected]@111.111.111.111)
  by mail.absoft.ro with ESMTPA; 15 Jul 2015 14:58:22 -0000
From: "[email protected]" <[email protected]>
Subject: Test Report
To: "Test test" <[email protected]>
Content-Type: Multipart/Alternative; boundary="wm32hkCMsS=_xUqKLF1OiOMUAOi7ru4ljM"
MIME-Version: 1.0
Date: Wed, 15 Jul 2015 17:58:21 +0300

The code I use for generating the e-mail is

ExecReport;
var
  tMess: TIdMessage;
  q: TADOQuery;
  Attachment: TIdAttachment;
  idtTextPart: TIdText;
  fileAttach: string;
  subiect: string;
  i : Integer;
  fName : string;
begin
  // FEventLogger.LogMessage(  ' Executing ' + IntToStr(FTask.FTaskID) , EVENTLOG_ERROR_TYPE , 0, 2);

  //
  tMess := TIdMessage.Create;
  tMess.Subject := FTask.FDenumire;

  tMess.ContentType := 'text/html';

  try
    q := TADOQuery.Create(nil);
    q.Connection := fConn;
    q.CommandTimeout := FTask.FTimeout;
    q.SQL.Text := FTask.FQueryString;
    q.Open;
    q.First;
  except
    on E: Exception do
    begin
      FEventLogger.LogMessage(' Error! ' + E.Message,
      EVENTLOG_ERROR_TYPE, 0, 2);
      q.Free;
      LogErrorExecution(E.Message);
      Exit;
    end;
  end;

  Subiect := FTask.FDenumire;

  //  dtSource := TDataSource.Create(nil);
  //  dtSource.dataset := q;
  fileAttach := CreateExcelDocument(q,False);

  tMess := TIdMessage.Create;
  tMess.Clear;
  tMess.ContentType := 'Multipart/Alternative';
  tMess.Subject := subiect;

  idtTextPart := TIdText.Create(tMess.MessageParts, nil);
  idtTextPart.ContentType := 'text/plain';
  idtTextPart.Body.Add(' ');

  idtTextPart := TIdText.Create(tMess.MessageParts, nil);
  idtTextPart.ContentType := 'text/html';

  Attachment := TIdAttachmentFile.Create(tMess.MessageParts, fileAttach);

  if q.RecordCount > 0 then
  begin

    idtTextPart.Body.Text := '<html><body bgcolor="#DCEEFC">';
    if (FTask.FHeaderID <> '') then
    begin
      idtTextPart.Body.Text := idtTextPart.Body.Text + BuildTable(q);
    end;   
    idtTextPart.Body.Text := idtTextPart.Body.Text + ' </body></html>';

    self.SendMail(s, tMess);

  end;

  q.Close;
  q.Free;

end;


Solution 1:[1]

How can the content type be "Multipart/Alternative" if you have an attachment? Outlook has no idea what your xls file is, so it picks up the body part that it knows about - plain text or HTML and discards the body flavor that it does not understand (xls).

Have you tried "multipart/mixed" contents type? This way you will signal to Outlook that your xls file is an attachment and has nothing to do with the message body.

UPDATE

If you want both plain text/html parts and an attachment, you message structure should be

multipart/mixed
  multipart/related
    text/plain
    text/html
  attachment

Look at the MIME structure that Outlook creates for various messages - you can see it in OutlookSpy (I am its author) - select a message similar to what you want, click IConverterSession button on the OutlookSpy toolbar, then MAPIToMIMEStm.

Sources

This article follows the attribution requirements of Stack Overflow and is licensed under CC BY-SA 3.0.

Source: Stack Overflow

Solution Source
Solution 1 Dmitry Streblechenko