Einzelnen Beitrag anzeigen

idefix2

Registriert seit: 17. Mär 2010
Ort: Wien
1.027 Beiträge
 
RAD-Studio 2009 Pro
 
#9

Re: Indy SMTP Mailversand, Fehler bei Umlauten äöü,ß usw.

  Alt 8. Apr 2010, 02:09
So, nachdem zu dem Thema nirgends eine Information zu finden war, habe ich mich durch den Indy-Code durchgebissen und die Ursache gefunden.

Die Indy Routinen sind derart undurchsichtig programmiert, dass es einem die Haare aufstellt, ich habe letztlich an vier Stellen den Code geändert, und jetzt versenden die Komponenten meine Mails sowohl mit als auch ohne Anhang unter Beibehaltung der Umlaute. Nachdem ich aber nicht wirklich ganz durchblicke, ist leider nicht sichergestellt, dass die Änderungen, die in meinem Programm funktionieren, nicht in anderen Programmen unerwünschte Nebeneffekte haben, wenn die Mails anders aufgebaut sind. Trotzdem poste ich hier diese Änderungen, wenn jemand Mails mit Umlauten oder Sonderzeichen mit den aktuellen Indy Komponenten versenden will, kann er ja versuchen, ob die Anpassungen auch für ihn tun, was er braucht.

Für den Normalfall eines Mails mit einem Messagebody und keinem, einem oder mehreren Anhängen sollte es, glaube ich, einwandfrei funktionieren, wobei ich, offenbar entgegen den Vorstellungen der Indy Entwickler, den Mailtext auch dann im Message.body übergebe, wenn es Dateianhänge gibt (beim Studium des Indy Codes habe ich festgestellt, dass eigentlich, wenn ein Mailanhang existiert, auch der Mailbodytext als Messagepart übergeben werden sollte; nur, wenn man das so macht, bin ich nicht sicher, ob mit den Umlauten im Bodytext wieder irgend ein Unfug passiert, ich habe es gar nicht erst versucht). Was das Ding mit Bildern im Mailbody oder mit mehr als einem textpart macht (gibt es solche Mails überhaupt?), weiss ich nicht.

Im den auskommentierten Codezeilen steht jeweils die ursprüngliche, von mir geänderte Quelltextversion

Viel Erfolg!

Delphi-Quellcode:

procedure TIdMessageClient.SendHeader(AMsg: TIdMessage);
begin // notwendig für Umlaute im Betreff oder Absender
  AMsg.GenerateHeader;
// IOHandler.Write(AMsg.LastGeneratedHeaders);
// geändert:
  IOHandler.Write(AMsg.LastGeneratedHeaders, false, en8bit);
// Ende der Änderung
end;


in procedure TIdMessageClient.SendBody(AMsg: TIdMessage);
// Umlaute in einem Mailtext ohne Anhang handhaben
    ....
    else if AMsg.Encoding = mePlainText then begin
      IOHandler.WriteLn; //This is the blank line after the headers
      //CC2: It is NOT Mime. It is a body followed by optional attachments
      DoStatus(hsStatusText, [RSMsgClientEncodingText]);
      // Write out Body first
      LHeaderCoder := HeaderCoderByCharSet(ISOCharSet);
      if LHeaderCoder <> nil then begin
        for i := 0 to AMsg.Body.Count - 1 do begin
          LBodyLine := LHeaderCoder.Encode(ISOCharSet, AMsg.Body[i]);
// IOHandler.WriteLnRFC(LBodyLine); {do not localize}
// geändert:
          IOHandler.WriteLnRFC(LBodyLine,en8bit); {do not localize}
// Ende der Änderung
        end;
      end else begin
        EncodeAndWriteText(AMsg.Body);
      end;
      ....


procedure TIdMessageClient.EncodeAndWriteText(const ABody: TStrings);
begin
  Assert(ABody<>nil);
  Assert(IOHandler<>nil);
// IOHandler.WriteRFCStrings(ABody);
// geändert:
  IOHandler.WriteRFCStrings(ABody, False, en8bit);
// Ende der Änderung
end;



// Umlaute in einem Mailtext mit Anhängen
  procedure WriteTextPart(ATextPart: TIdText);
  var
    LData: TStringList;
    li, j: Integer;
    LQuotedPrintableEncoder: TIdEncoderQuotedPrintable;
    LHeaderCoder: TIdHeaderCoderClass;
    LFileName: String;
  begin
    if ATextPart.ContentType = 'then begin
      ATextPart.ContentType := 'text/plain'; {do not localize}
    end;
    if ATextPart.ContentTransfer = 'then begin
      ATextPart.ContentTransfer := 'quoted-printable'; {do not localize}
    end
    else if (PosInStrArray(ATextPart.ContentTransfer, ['quoted-printable', 'base64'], False) = -1) {do not localize}
      and ATextPart.IsBodyEncodingRequired then
    begin
// ATextPart.ContentTransfer := '8bit'; {do not localize}
// geändert:
        ATextPart.ContentTransfer := 'quoted-printable'; {do not localize}
// Ende der Änderung - ich bin nicht sicher, ob diese Änderung nötig ist,
// aber so kommen die Umalute jedenfalls richtig an
    end;
    if ATextPart.ContentDisposition = 'then begin
      ATextPart.ContentDisposition := 'inline'; {do not localize}
    end;

    LFileName := EncodeHeader(ExtractFileName(ATextPart.FileName), '', HeaderEncoding, ISOCharSet); {do not localize}

    //ContentType may contain the charset also, but CharSet overrides it if it is present...
    if ATextPart.CharSet <> 'then begin
      IOHandler.Write('Content-Type: ' + RemoveHeaderEntry(ATextPart.ContentType, 'charset') {do not localize}
         + '; charset="' + ATextPart.CharSet + '"'); {do not localize}
    end else begin
      IOHandler.Write('Content-Type: ' + ATextPart.ContentType); {do not localize}
    end;
    if LFileName <> 'then begin
      IOHandler.Write(';' + EOL + ' name="' + LFileName + '"'); {do not localize}
    end;
    IOHandler.WriteLn;

    IOHandler.WriteLn(SContentTransferEncoding + ': ' + ATextPart.ContentTransfer); {do not localize}
    IOHandler.WriteLn('Content-Disposition: ' + ATextPart.ContentDisposition); {do not localize}
    if LFileName <> 'then begin
      IOHandler.Write(';' + EOL + ' filename="' + LFileName + '"'); {do not localize}
    end;
    IOHandler.WriteLn;

    if ATextPart.ContentID <> 'then begin
      IOHandler.WriteLn('Content-ID: ' + ATextPart.ContentID); {do not localize}
    end;

    LX := ATextPart.ExtraHeaders.Count; {Debugging}
    IOHandler.Write(ATextPart.ExtraHeaders);
    IOHandler.WriteLn;

    if TextIsSame(ATextPart.ContentTransfer, 'quoted-printable') then begin {do not localize}
      if ATextPart.Body.Count > 0 then begin
        LQuotedPrintableEncoder := TIdEncoderQuotedPrintable.Create(Self);
        try
          LData := TStringList.Create;
          try
            LHeaderCoder := HeaderCoderByCharSet(ISOCharSet);
            for li := 0 to ATextPart.Body.Count - 1 do begin
// LQuotedPrintableEncoder.Encode(ATextPart.Body[li] + EOL, LData);
// for j := 0 to LData.Count-1 do begin
// if (LData[j] <> '') and (LHeaderCoder <> nil) then begin
// LData[j] := LHeaderCoder.Encode(ISOCharSet, LData[j]);
// end;
// end;
// IOHandler.WriteRFCStrings(LData, False);
// end;
// geändert:
              ldata.add (ATextPart.Body[li]+EOL);
            end;
            IOHandler.WriteRFCStrings(LData, False, en8bit);
// Ende der Änderung
          finally
            FreeAndNil(LData);
          end;
        finally
          FreeAndNil(LQuotedPrintableEncoder);
        end;
      end;
    end
    else if TextIsSame(ATextPart.ContentTransfer, 'base64') then begin {do not localize}
      EncodeStrings(ATextPart.Body, TIdMessageEncoderMIME);
    end else
    begin
      LX := ATextPart.Body.Count;

// IOHandler.WriteRFCStrings(ATextPart.Body, False);
      { No test for last line break necessary because IOHandler.WriteRFCStrings() uses WriteLn(). }
// geändert:
      IOHandler.WriteRFCStrings(ATextPart.Body, False, en8bit);
// Ende der Änderung
    end;
  end;
  Mit Zitat antworten Zitat