tags:

views:

409

answers:

3

Hello!

Using the latest snapshot of Indy tiburon on D2010. A very simple project like:

var
  stream: TFileStream; (s is TidSMTP and m is TidMessage)
begin
  s.Connect;
  Stream := TFileStream.Create('c:\Test.zip', fmOpenRead or fmShareExclusive);
  try
    with TIdAttachmentMemory.Create(m.MessageParts, Stream) do
    begin
      ContentType := 'application/x-zip-compressed';
      Name := ExtractFilePath('C:\'); //'
      FileName := 'Test.zip';
    end;
  finally
    FreeAndNil(Stream);
  end;
  s.Send(m);
  s.Disconnect();
end;

Everything works Ok in Outlook, The bat!, OE, yahoo, etc... but in Thunderbird the attachment is not shown. Looking at the source of the message in Thunderbird, the attachment is there. The only difference I can find between messages send by indy and other clients is that Indy messages have this order:

Content-Type: multipart/mixed; boundary="Z\=_7oeC98yIhktvxiwiDTVyhv9R9gwkwT1"
MIME-Version: 1.0

while any other clients have the order:

MIME-Version: 1.0
Content-Type: multipart/mixed; boundary="Z\=_7oeC98yIhktvxiwiDTVyhv9R9gwkwT1"

Don't know if THAT is the source of the problem, but if so: is this a bug on Thunderbird or is this a problem with indy which "malforms" the headers of the messages? Is this order a problem? Does that matter anyway?

A: 

RFC 1521 explicitly states:

Messages composed in accordance with this document MUST include such a header field, with the following verbatim text:

MIME-Version: 1.0

And note it is an header field:

Header fields are lines composed of a field name, followed by a colon (":"), followed by a field body, and terminated by CRLF. (rfc 2822)

Thereby if Indy does not set it as an header field it's an Indy bug, IMHO its syntax is invalid, it can't be set in the content-type line (maybe just a missing CRLF?) - and TB just follows the RFC verbatim, while the other know the RFC are often not followed completely and process the document anyay.

ldsandon
Don't know why Stack overflow messed the layout but Indy does include the CRLF: One line: Content-Type: multipart/mixed; boundary="Z\=_7oeC98yIhktvxiwiDTVyhv9R9gwkwT1" Next line: MIME-Version: 1.0 But in that order while other programs have it the other way around. Could that be the cause of the problem
Lobuno
Welcome to Stack Overflow, Lobuno. What you posted was correct, but poorly formatted. Rruz tried to format it, but didn't get the line break right. Stack Overflow is not to blame. Please look at the preview before posting next time. If you notice an error later, please edit to fix it, as Rruz and I have done.
Rob Kennedy
Mmh, I was deceived :). Well, it makes sense for the MIME-version header field to come before the content-type, because it returns the MIME version and what follows could depend from it (although until now there were no need of it). The RFC introduces MIME-version before Content-type, although AFAIK it does not specify the order. It could be that TB is pretty strict in its parsing. Try to export the message, change the header position and reopen it. If it shows the attachment it's the TB parser, although Indy should change the order as well.
ldsandon
A: 

You should try something like this: (Note: The code doesn't show you how to send the message, just how to create it. There is another service that sends the emails).

Msg := TIdMessage.Create(nil);
try
  {create the message}
  Msg.Subject := Subject;
  with Msg.Recipients.Add do
  begin
    Text := EMailAddress;
  end;
  Msg.From.Address := From;
  Msg.From.Name := Copy(From, 1, pos('@', From) - 1);
  with Msg.ReplyTo.Add do
  begin
    Text := From;
  end;
  with TIdMessageBuilderHtml.Create do
  try
    {plain text}
    PlainText.Text := 'body text'
    {html body}
    Html.Text := '<html><body><p>' + 'body text' + '</p></body></html>';
    {attachments}
    for i := 0 to AttachFiles.Count - 1 do
        Attachments.Add(AttachFiles.Strings[i]);
    FillMessage(Msg);
  finally
    Free;
  end;
  {save the message for sending}
  Msg.NoEncode := False;
  Msg.NoDecode := False;
  Msg.SaveToFile(locfilename + TempExt);
finally
  Msg.Free;
end;

Answer to Rob Kennedy's comment bellow: I posted this code because for me, this code works with all major mail clients. The code is self explanatory, creates the message with attachments, saves it. I posted a solution that works. I don't have time (I'm at work) to compare the headers or message source of the original code the and the one posted by me to see why mine works. The original poster is free to do it and report back.

ioan
Can you please describe what makes this code right and the other code wrong? What part of this code is what makes it "something like this"? Don't just post some code to blindly copy and paste. Help us learn.
Rob Kennedy
+1  A: 

The latest version (as today) of Indy has a problem in the headers:

The problem seems to be around the line in the mail header with:

Content-Type: multipart/mixed; boundary="oIROJ8Yu4KsL8BbjOo0fc\=_O7oAqLVq97i"

The "=" inside the boundary identifier is prepended with a "\" (probably to escape it), but in the body of the mail the boundary looks like this:

--oIROJ8Yu4KsL8BbjOo0fc=_O7oAqLVq97i

If you look at the source of Indy, in the file idGlobalProtocols, ReplaceHeaderSubItem calls QuoteString, which is the one that adds the backslash. You could carefully change the logic here and recompile Indy.

cobian
THANKKKKKKKKSSSS. THAT IS!!!!
Lobuno
That has aleady been fixed in the latest snapshot.
Remy Lebeau - TeamB