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;