748 lines
22 KiB
Plaintext
748 lines
22 KiB
Plaintext
|
unit IdMessageBuilder;
|
||
|
|
||
|
interface
|
||
|
|
||
|
{$i IdCompilerDefines.inc}
|
||
|
|
||
|
uses
|
||
|
Classes, IdMessage;
|
||
|
|
||
|
type
|
||
|
TIdMessageBuilderAttachment = class(TCollectionItem)
|
||
|
private
|
||
|
FContentID: String;
|
||
|
FContentTransfer: String;
|
||
|
FContentType: String;
|
||
|
FData: TStream;
|
||
|
FFileName: String;
|
||
|
FName: String;
|
||
|
public
|
||
|
procedure Assign(Source: TPersistent); override;
|
||
|
property ContentID: String read FContentID write FContentID;
|
||
|
property ContentTransfer: String read FContentTransfer;
|
||
|
property ContentType: String read FContentType write FContentType;
|
||
|
property Data: TStream read FData write FData;
|
||
|
property FileName: String read FFileName write FFileName;
|
||
|
property Name: String read FName write FName;
|
||
|
end;
|
||
|
|
||
|
TIdMessageBuilderAttachments = class(TCollection)
|
||
|
private
|
||
|
function GetAttachment(Index: Integer): TIdMessageBuilderAttachment;
|
||
|
procedure SetAttachment(Index: Integer; Value: TIdMessageBuilderAttachment);
|
||
|
public
|
||
|
constructor Create; reintroduce;
|
||
|
function Add: TIdMessageBuilderAttachment; reintroduce; overload;
|
||
|
function Add(const AFileName: String; const AContentID: String = ''): TIdMessageBuilderAttachment; overload;
|
||
|
function Add(AData: TStream; const AContentType: String; const AContentID: String = ''): TIdMessageBuilderAttachment; overload;
|
||
|
procedure AddToMessage(AMsg: TIdMessage; ParentPart: Integer);
|
||
|
property Attachment[Index: Integer]: TIdMessageBuilderAttachment
|
||
|
read GetAttachment write SetAttachment; default;
|
||
|
end;
|
||
|
|
||
|
TIdCustomMessageBuilder = class
|
||
|
protected
|
||
|
FAttachments: TIdMessageBuilderAttachments;
|
||
|
FPlainText: TStrings;
|
||
|
FPlainTextCharSet: String;
|
||
|
FPlainTextContentTransfer: String;
|
||
|
procedure AddAttachments(AMsg: TIdMessage);
|
||
|
procedure FillBody(AMsg: TIdMessage); virtual; abstract;
|
||
|
procedure FillHeaders(AMsg: TIdMessage); virtual;
|
||
|
procedure SetPlainText(AValue: TStrings);
|
||
|
procedure SetAttachments(AValue: TIdMessageBuilderAttachments);
|
||
|
public
|
||
|
constructor Create; virtual;
|
||
|
destructor Destroy; override;
|
||
|
//
|
||
|
procedure Clear; virtual;
|
||
|
procedure FillMessage(AMsg: TIdMessage);
|
||
|
function NewMessage(AOwner: TComponent = nil): TIdMessage;
|
||
|
//
|
||
|
property Attachments: TIdMessageBuilderAttachments read FAttachments write SetAttachments;
|
||
|
property PlainText: TStrings read FPlainText write SetPlainText;
|
||
|
property PlainTextCharSet: String read FPlainTextCharSet write FPlainTextCharSet;
|
||
|
property PlainTextContentTransfer: String read FPlainTextContentTransfer write FPlainTextContentTransfer;
|
||
|
end;
|
||
|
|
||
|
TIdMessageBuilderPlain = class(TIdCustomMessageBuilder)
|
||
|
protected
|
||
|
procedure FillBody(AMsg: TIdMessage); override;
|
||
|
procedure FillHeaders(AMsg: TIdMessage); override;
|
||
|
end;
|
||
|
|
||
|
TIdMessageBuilderHtml = class(TIdCustomMessageBuilder)
|
||
|
protected
|
||
|
FHtml: TStrings;
|
||
|
FHtmlCharSet: String;
|
||
|
FHtmlContentTransfer: String;
|
||
|
FHtmlFiles: TIdMessageBuilderAttachments;
|
||
|
FHtmlViewerNeededMsg: String;
|
||
|
procedure FillBody(AMsg: TIdMessage); override;
|
||
|
procedure FillHeaders(AMsg: TIdMessage); override;
|
||
|
procedure SetHtml(AValue: TStrings);
|
||
|
procedure SetHtmlFiles(AValue: TIdMessageBuilderAttachments);
|
||
|
public
|
||
|
constructor Create; override;
|
||
|
destructor Destroy; override;
|
||
|
//
|
||
|
procedure Clear; override;
|
||
|
//
|
||
|
property Html: TStrings read FHtml write SetHtml;
|
||
|
property HtmlCharSet: String read FHtmlCharSet write FHtmlCharSet;
|
||
|
property HtmlContentTransfer: String read FHtmlContentTransfer write FHtmlContentTransfer;
|
||
|
property HtmlFiles: TIdMessageBuilderAttachments read FHtmlFiles write SetHtmlFiles;
|
||
|
property HtmlViewerNeededMsg: String read FHtmlViewerNeededMsg write FHtmlViewerNeededMsg;
|
||
|
end;
|
||
|
|
||
|
TIdMessageBuilderRtfType = (idMsgBldrRtfMS, idMsgBldrRtfEnriched, idMsgBldrRtfRichtext);
|
||
|
|
||
|
TIdMessageBuilderRtf = class(TIdCustomMessageBuilder)
|
||
|
protected
|
||
|
FRtf: TStrings;
|
||
|
FRtfType: TIdMessageBuilderRtfType;
|
||
|
FRtfViewerNeededMsg: String;
|
||
|
procedure FillBody(AMsg: TIdMessage); override;
|
||
|
procedure FillHeaders(AMsg: TIdMessage); override;
|
||
|
procedure SetRtf(AValue: TStrings);
|
||
|
public
|
||
|
constructor Create; override;
|
||
|
destructor Destroy; override;
|
||
|
//
|
||
|
procedure Clear; override;
|
||
|
//
|
||
|
property Rtf: TStrings read FRtf write SetRtf;
|
||
|
property RtfType: TIdMessageBuilderRtfType read FRtfType write FRtfType;
|
||
|
property RtfViewerNeededMsg: String read FRtfViewerNeededMsg write FRtfViewerNeededMsg;
|
||
|
end;
|
||
|
|
||
|
implementation
|
||
|
|
||
|
uses
|
||
|
IdGlobal, IdGlobalProtocols, IdMessageParts, IdAttachment, IdAttachmentFile,
|
||
|
IdAttachmentMemory, IdResourceStringsProtocols, IdText, SysUtils;
|
||
|
|
||
|
const
|
||
|
cTextPlain = 'text/plain'; {do not localize}
|
||
|
cTextHtml = 'text/html'; {do not localize}
|
||
|
cTextRtf: array[TIdMessageBuilderRtfType] of String = ('text/rtf', 'text/enriched', 'text/richtext'); {do not localize}
|
||
|
cMultipartAlternative = 'multipart/alternative'; {do not localize}
|
||
|
cMultipartMixed = 'multipart/mixed'; {do not localize}
|
||
|
cMultipartRelatedHtml = 'multipart/related; type="text/html"'; {do not localize}
|
||
|
|
||
|
{ TIdMessageBuilderAttachment }
|
||
|
|
||
|
procedure TIdMessageBuilderAttachment.Assign(Source: TPersistent);
|
||
|
var
|
||
|
LSource: TIdMessageBuilderAttachment;
|
||
|
begin
|
||
|
if Source is TIdMessageBuilderAttachment then
|
||
|
begin
|
||
|
LSource := TIdMessageBuilderAttachment(Source);
|
||
|
FContentID := LSource.FContentID;
|
||
|
FContentTransfer := LSource.FContentTransfer;
|
||
|
FContentType := LSource.FContentType;
|
||
|
FData := LSource.FData;
|
||
|
FFileName := LSource.FFileName;
|
||
|
FName := LSource.FName;
|
||
|
end else begin
|
||
|
inherited Assign(Source);
|
||
|
end;
|
||
|
end;
|
||
|
|
||
|
{ TIdMessageBuilderAttachments }
|
||
|
|
||
|
constructor TIdMessageBuilderAttachments.Create;
|
||
|
begin
|
||
|
inherited Create(TIdMessageBuilderAttachment);
|
||
|
end;
|
||
|
|
||
|
function TIdMessageBuilderAttachments.Add: TIdMessageBuilderAttachment;
|
||
|
begin
|
||
|
// This helps prevent unsupported TIdMessageBuilderAttachment from being added
|
||
|
Result := nil;
|
||
|
end;
|
||
|
|
||
|
function TIdMessageBuilderAttachments.Add(const AFileName: String;
|
||
|
const AContentID: String = ''): TIdMessageBuilderAttachment;
|
||
|
begin
|
||
|
Result := TIdMessageBuilderAttachment(inherited Add);
|
||
|
Result.FContentID := AContentID;
|
||
|
Result.FFileName := AFileName;
|
||
|
end;
|
||
|
|
||
|
function TIdMessageBuilderAttachments.Add(AData: TStream; const AContentType: String;
|
||
|
const AContentID: String = ''): TIdMessageBuilderAttachment;
|
||
|
begin
|
||
|
Assert(AData <> nil);
|
||
|
Result := TIdMessageBuilderAttachment(inherited Add);
|
||
|
Result.FContentID := AContentID;
|
||
|
Result.FContentType := AContentType;
|
||
|
Result.FData := AData;
|
||
|
end;
|
||
|
|
||
|
procedure TIdMessageBuilderAttachments.AddToMessage(AMsg: TIdMessage; ParentPart: Integer);
|
||
|
var
|
||
|
I: Integer;
|
||
|
LMsgBldrAttachment: TIdMessageBuilderAttachment;
|
||
|
LMsgAttachment: TIdAttachment;
|
||
|
LStream: TStream;
|
||
|
|
||
|
function FormatContentId(Item: TIdMessageBuilderAttachment): String;
|
||
|
begin
|
||
|
if Item.ContentID <> '' then begin
|
||
|
Result := EnsureMsgIDBrackets(Item.ContentID);
|
||
|
end else begin
|
||
|
Result := '';
|
||
|
end;
|
||
|
end;
|
||
|
|
||
|
function FormatContentType(Item: TIdMessageBuilderAttachment): String;
|
||
|
begin
|
||
|
if Item.ContentType <> '' then begin
|
||
|
Result := Item.ContentType;
|
||
|
end else begin
|
||
|
Result := GetMIMETypeFromFile(Item.FileName);
|
||
|
end;
|
||
|
end;
|
||
|
|
||
|
function FormatName(Item: TIdMessageBuilderAttachment): String;
|
||
|
begin
|
||
|
if Item.Name <> '' then begin
|
||
|
Result := Item.Name;
|
||
|
end
|
||
|
else if Item.FileName <> '' then begin
|
||
|
Result := ExtractFileName(Item.FileName);
|
||
|
end else begin
|
||
|
Result := '';
|
||
|
end;
|
||
|
end;
|
||
|
|
||
|
begin
|
||
|
for I := 0 to Count-1 do
|
||
|
begin
|
||
|
LMsgBldrAttachment := Attachment[I];
|
||
|
if Assigned(LMsgBldrAttachment.Data) then
|
||
|
begin
|
||
|
LMsgAttachment := TIdAttachmentMemory.Create(AMsg.MessageParts);
|
||
|
try
|
||
|
LMsgAttachment.FileName := ExtractFileName(LMsgBldrAttachment.FileName);
|
||
|
LStream := LMsgAttachment.PrepareTempStream;
|
||
|
try
|
||
|
LStream.CopyFrom(LMsgBldrAttachment.Data, 0);
|
||
|
finally
|
||
|
LMsgAttachment.FinishTempStream;
|
||
|
end;
|
||
|
except
|
||
|
LMsgAttachment.Free;
|
||
|
raise;
|
||
|
end;
|
||
|
end else
|
||
|
begin
|
||
|
LMsgAttachment := TIdAttachmentFile.Create(AMsg.MessageParts, LMsgBldrAttachment.FileName);
|
||
|
end;
|
||
|
LMsgAttachment.Name := FormatName(LMsgBldrAttachment);
|
||
|
LMsgAttachment.ContentId := FormatContentId(LMsgBldrAttachment);
|
||
|
LMsgAttachment.ContentType := FormatContentType(LMsgBldrAttachment);
|
||
|
LMsgAttachment.ContentTransfer := LMsgBldrAttachment.ContentTransfer;
|
||
|
if ParentPart > -1 then
|
||
|
begin
|
||
|
if IsHeaderMediaType(LMsgAttachment.ContentType, 'image') then begin {do not localize}
|
||
|
LMsgAttachment.ContentDisposition := 'inline'; {do not localize}
|
||
|
end;
|
||
|
LMsgAttachment.ParentPart := ParentPart;
|
||
|
end;
|
||
|
end;
|
||
|
end;
|
||
|
|
||
|
function TIdMessageBuilderAttachments.GetAttachment(Index: Integer): TIdMessageBuilderAttachment;
|
||
|
begin
|
||
|
Result := TIdMessageBuilderAttachment(inherited GetItem(Index));
|
||
|
end;
|
||
|
|
||
|
procedure TIdMessageBuilderAttachments.SetAttachment(Index: Integer; Value: TIdMessageBuilderAttachment);
|
||
|
begin
|
||
|
inherited SetItem(Index, Value);
|
||
|
end;
|
||
|
|
||
|
{ TIdCustomMessageBuilder }
|
||
|
|
||
|
constructor TIdCustomMessageBuilder.Create;
|
||
|
begin
|
||
|
inherited Create;
|
||
|
FPlainText := TStringList.Create;
|
||
|
FAttachments := TIdMessageBuilderAttachments.Create;
|
||
|
end;
|
||
|
|
||
|
destructor TIdCustomMessageBuilder.Destroy;
|
||
|
begin
|
||
|
FPlainText.Free;
|
||
|
FAttachments.Free;
|
||
|
inherited Destroy;
|
||
|
end;
|
||
|
|
||
|
procedure TIdCustomMessageBuilder.AddAttachments(AMsg: TIdMessage);
|
||
|
begin
|
||
|
FAttachments.AddToMessage(AMsg, -1);
|
||
|
end;
|
||
|
|
||
|
procedure TIdCustomMessageBuilder.Clear;
|
||
|
begin
|
||
|
FAttachments.Clear;
|
||
|
FPlainText.Clear;
|
||
|
FPlainTextCharSet := '';
|
||
|
FPlainTextContentTransfer := '';
|
||
|
end;
|
||
|
|
||
|
procedure TIdCustomMessageBuilder.FillMessage(AMsg: TIdMessage);
|
||
|
begin
|
||
|
if not Assigned(AMsg) then begin
|
||
|
Exit;
|
||
|
end;
|
||
|
|
||
|
// Clear only the body, ContentType, CharSet, and ContentTransferEncoding here...
|
||
|
//
|
||
|
AMsg.ClearBody;
|
||
|
AMsg.ContentType := '';
|
||
|
AMsg.CharSet := '';
|
||
|
AMsg.ContentTransferEncoding := '';
|
||
|
|
||
|
// let the message decide how to encode itself
|
||
|
// based on what parts are added in InternalFill()
|
||
|
//
|
||
|
AMsg.Encoding := meDefault;
|
||
|
|
||
|
// fill in type-specific content first
|
||
|
//
|
||
|
FillBody(AMsg);
|
||
|
|
||
|
// Are non-related attachments present?
|
||
|
//
|
||
|
AddAttachments(AMsg);
|
||
|
|
||
|
// Determine the top-level ContentType and
|
||
|
// ContentTransferEncoding for the message now
|
||
|
//
|
||
|
FillHeaders(AMsg);
|
||
|
end;
|
||
|
|
||
|
function TIdCustomMessageBuilder.NewMessage(AOwner: TComponent = nil): TIdMessage;
|
||
|
begin
|
||
|
Result := TIdMessage.Create(AOwner);
|
||
|
try
|
||
|
FillMessage(Result);
|
||
|
except
|
||
|
FreeAndNil(Result);
|
||
|
raise;
|
||
|
end;
|
||
|
end;
|
||
|
|
||
|
procedure TIdCustomMessageBuilder.SetAttachments(AValue: TIdMessageBuilderAttachments);
|
||
|
begin
|
||
|
FAttachments.Assign(AValue);
|
||
|
end;
|
||
|
|
||
|
procedure TIdCustomMessageBuilder.FillHeaders(AMsg: TIdMessage);
|
||
|
var
|
||
|
LPart: TIdMessagePart;
|
||
|
begin
|
||
|
if FAttachments.Count > 0 then
|
||
|
begin
|
||
|
if AMsg.MessageParts.Count > 1 then
|
||
|
begin
|
||
|
// plain text and/or formatting, and at least 1 non-related attachment
|
||
|
//
|
||
|
AMsg.ContentType := cMultipartMixed;
|
||
|
AMsg.CharSet := '';
|
||
|
AMsg.ContentTransferEncoding := '';
|
||
|
end else
|
||
|
begin
|
||
|
// no plain text or formatting, only 1 non-related attachment
|
||
|
//
|
||
|
LPart := AMsg.MessageParts[0];
|
||
|
AMsg.ContentType := LPart.ContentType;
|
||
|
AMsg.CharSet := LPart.CharSet;
|
||
|
AMsg.ContentTransferEncoding := LPart.ContentTransfer;
|
||
|
end;
|
||
|
end else
|
||
|
begin
|
||
|
AMsg.ContentType := '';
|
||
|
AMsg.CharSet := '';
|
||
|
AMsg.ContentTransferEncoding := '';
|
||
|
end;
|
||
|
end;
|
||
|
|
||
|
procedure TIdCustomMessageBuilder.SetPlainText(AValue: TStrings);
|
||
|
begin
|
||
|
FPlainText.Assign(AValue);
|
||
|
end;
|
||
|
|
||
|
{ TIdMessageBuilderPlain }
|
||
|
|
||
|
procedure TIdMessageBuilderPlain.FillBody(AMsg: TIdMessage);
|
||
|
var
|
||
|
LTextPart: TIdText;
|
||
|
begin
|
||
|
// Is plain text present?
|
||
|
//
|
||
|
if FPlainText.Count > 0 then
|
||
|
begin
|
||
|
// Should the message contain only plain text?
|
||
|
//
|
||
|
if FAttachments.Count = 0 then
|
||
|
begin
|
||
|
AMsg.Body.Assign(FPlainText);
|
||
|
end else
|
||
|
begin
|
||
|
// At this point, multiple pieces will be present in the message
|
||
|
// body, so everything must be stored in the MessageParts collection...
|
||
|
//
|
||
|
LTextPart := TIdText.Create(AMsg.MessageParts, FPlainText);
|
||
|
LTextPart.ContentType := cTextPlain;
|
||
|
LTextPart.CharSet := FPlainTextCharSet;
|
||
|
LTextPart.ContentTransfer := FPlainTextContentTransfer;
|
||
|
end;
|
||
|
end;
|
||
|
end;
|
||
|
|
||
|
procedure TIdMessageBuilderPlain.FillHeaders(AMsg: TIdMessage);
|
||
|
begin
|
||
|
if (FPlainText.Count > 0) and (FAttachments.Count = 0) then
|
||
|
begin
|
||
|
// plain text only
|
||
|
//
|
||
|
AMsg.ContentType := cTextPlain;
|
||
|
AMsg.CharSet := FPlainTextCharSet;
|
||
|
AMsg.ContentTransferEncoding := FPlainTextContentTransfer;
|
||
|
end else
|
||
|
begin
|
||
|
inherited FillHeaders(AMsg);
|
||
|
end;
|
||
|
end;
|
||
|
|
||
|
{ TIdMessageBuilderHtml }
|
||
|
|
||
|
constructor TIdMessageBuilderHtml.Create;
|
||
|
begin
|
||
|
inherited Create;
|
||
|
FHtml := TStringList.Create;
|
||
|
FHtmlFiles := TIdMessageBuilderAttachments.Create;
|
||
|
FHtmlViewerNeededMsg := rsHtmlViewerNeeded;
|
||
|
end;
|
||
|
|
||
|
destructor TIdMessageBuilderHtml.Destroy;
|
||
|
begin
|
||
|
FHtml.Free;
|
||
|
FHtmlFiles.Free;
|
||
|
inherited Destroy;
|
||
|
end;
|
||
|
|
||
|
procedure TIdMessageBuilderHtml.Clear;
|
||
|
begin
|
||
|
FHtml.Clear;
|
||
|
FHtmlCharSet := '';
|
||
|
FHtmlContentTransfer := '';
|
||
|
FHtmlFiles.Clear;
|
||
|
inherited Clear;
|
||
|
end;
|
||
|
|
||
|
procedure TIdMessageBuilderHtml.FillBody(AMsg: TIdMessage);
|
||
|
var
|
||
|
LUsePlain, LUseHtml, LUseHtmlFiles, LUseAttachments: Boolean;
|
||
|
LAlternativeIndex, LRelatedIndex: Integer;
|
||
|
LTextPart: TIdText;
|
||
|
begin
|
||
|
// Cache these for better performance
|
||
|
//
|
||
|
LUsePlain := FPlainText.Count > 0;
|
||
|
LUseHtml := FHtml.Count > 0;
|
||
|
LUseHtmlFiles := LUseHtml and (FHtmlFiles.Count > 0);
|
||
|
LUseAttachments := FAttachments.Count > 0;
|
||
|
|
||
|
LAlternativeIndex := -1;
|
||
|
LRelatedIndex := -1;
|
||
|
|
||
|
// Is any body data present at all?
|
||
|
//
|
||
|
if not (LUsePlain or LUseHtml or LUseHtmlFiles or LUseAttachments) then begin
|
||
|
Exit;
|
||
|
end;
|
||
|
|
||
|
// Should the message contain only plain text?
|
||
|
//
|
||
|
if LUsePlain and not (LUseHtml or LUseAttachments) then
|
||
|
begin
|
||
|
AMsg.Body.Assign(FPlainText);
|
||
|
Exit;
|
||
|
end;
|
||
|
|
||
|
// Should the message contain only HTML?
|
||
|
//
|
||
|
if LUseHtml and not (LUsePlain or LUseHtmlFiles or LUseAttachments) then
|
||
|
begin
|
||
|
// TODO: create "multipart/alternative" pieces if FHtmlViewerNeededMsg is not empty...
|
||
|
AMsg.Body.Assign(FHtml);
|
||
|
Exit;
|
||
|
end;
|
||
|
|
||
|
// At this point, multiple pieces will be present in the message
|
||
|
// body, so everything must be stored in the MessageParts collection...
|
||
|
|
||
|
// If the message should contain both plain text and HTML, a
|
||
|
// "multipart/alternative" piece is needed to wrap them if
|
||
|
// non-related attachments are also present...
|
||
|
//
|
||
|
// RLebeau 5/23/2011: need to output the Alternative piece if
|
||
|
// the "HTML Viewer is needed" text is going to be used...
|
||
|
//
|
||
|
if {LUsePlain and} LUseHtml and LUseAttachments then
|
||
|
begin
|
||
|
LTextPart := TIdText.Create(AMsg.MessageParts, nil);
|
||
|
LTextPart.ContentType := cMultipartAlternative;
|
||
|
LAlternativeIndex := LTextPart.Index;
|
||
|
end;
|
||
|
|
||
|
// Is plain text present?
|
||
|
//
|
||
|
if LUsePlain or LUseHtml then
|
||
|
begin
|
||
|
LTextPart := TIdText.Create(AMsg.MessageParts, FPlainText);
|
||
|
begin
|
||
|
if LUseHtml and (not LUsePlain) then
|
||
|
begin
|
||
|
LTextPart.Body.Text := FHtmlViewerNeededMsg;
|
||
|
end;
|
||
|
LTextPart.ContentType := cTextPlain;
|
||
|
LTextPart.CharSet := FPlainTextCharSet;
|
||
|
LTextPart.ContentTransfer := FPlainTextContentTransfer;
|
||
|
LTextPart.ParentPart := LAlternativeIndex;
|
||
|
end;
|
||
|
end;
|
||
|
|
||
|
// Is HTML present?
|
||
|
//
|
||
|
if LUseHtml then
|
||
|
begin
|
||
|
// related attachments can't be referenced by, or used inside
|
||
|
// of, plain text, so there is no point in wrapping the plain
|
||
|
// text inside the same "multipart/related" part with the HTML
|
||
|
// and attachments. Some email programs don't do that as well.
|
||
|
// This logic is newer and more accurate than what is described
|
||
|
// in the "HTML Messages" article found on Indy's website.
|
||
|
//
|
||
|
if LUseHtmlFiles then
|
||
|
begin
|
||
|
LTextPart := TIdText.Create(AMsg.MessageParts, nil);
|
||
|
LTextPart.ContentType := cMultipartRelatedHtml;
|
||
|
LTextPart.ParentPart := LAlternativeIndex;
|
||
|
LRelatedIndex := LTextPart.Index;
|
||
|
end;
|
||
|
|
||
|
// Add HTML
|
||
|
//
|
||
|
LTextPart := TIdText.Create(AMsg.MessageParts, FHtml);
|
||
|
LTextPart.ContentType := cTextHtml;
|
||
|
LTextPart.CharSet := FHtmlCharSet;
|
||
|
LTextPart.ContentTransfer := FHtmlContentTransfer;
|
||
|
if LRelatedIndex <> -1 then begin
|
||
|
LTextPart.ParentPart := LRelatedIndex; // plain text and related attachments
|
||
|
end else begin
|
||
|
LTextPart.ParentPart := LAlternativeIndex; // plain text and optional non-related attachments
|
||
|
end;
|
||
|
|
||
|
// Are related attachments present?
|
||
|
//
|
||
|
if LUseHtmlFiles then begin
|
||
|
FHtmlFiles.AddToMessage(AMsg, LRelatedIndex);
|
||
|
end;
|
||
|
end;
|
||
|
end;
|
||
|
|
||
|
procedure TIdMessageBuilderHtml.FillHeaders(AMsg: TIdMessage);
|
||
|
begin
|
||
|
if FAttachments.Count = 0 then
|
||
|
begin
|
||
|
if (FPlainText.Count > 0) and (FHtml.Count = 0) then
|
||
|
begin
|
||
|
// plain text only
|
||
|
//
|
||
|
AMsg.ContentType := cTextPlain;
|
||
|
AMsg.CharSet := FPlainTextCharSet;
|
||
|
AMsg.ContentTransferEncoding := FPlainTextContentTransfer;
|
||
|
end
|
||
|
else if FHtml.Count > 0 then
|
||
|
begin
|
||
|
if (FPlainText.Count = 0) and (FHtmlFiles.Count = 0) then
|
||
|
begin
|
||
|
// HTML only
|
||
|
//
|
||
|
AMsg.ContentType := cTextHtml;
|
||
|
AMsg.CharSet := FHtmlCharSet;
|
||
|
AMsg.ContentTransferEncoding := FHtmlContentTransfer;
|
||
|
end else
|
||
|
begin
|
||
|
// plain text and HTML and no related attachments
|
||
|
//
|
||
|
AMsg.ContentType := cMultipartAlternative;
|
||
|
AMsg.CharSet := '';
|
||
|
AMsg.ContentTransferEncoding := '';
|
||
|
end;
|
||
|
end;
|
||
|
end else
|
||
|
begin
|
||
|
inherited FillHeaders(AMsg);
|
||
|
end;
|
||
|
end;
|
||
|
|
||
|
procedure TIdMessageBuilderHtml.SetHtml(AValue: TStrings);
|
||
|
begin
|
||
|
FHtml.Assign(AValue);
|
||
|
end;
|
||
|
|
||
|
procedure TIdMessageBuilderHtml.SetHtmlFiles(AValue: TIdMessageBuilderAttachments);
|
||
|
begin
|
||
|
FHtmlFiles.Assign(AValue);
|
||
|
end;
|
||
|
|
||
|
{ TIdMessageBuilderRTF }
|
||
|
|
||
|
constructor TIdMessageBuilderRtf.Create;
|
||
|
begin
|
||
|
inherited Create;
|
||
|
FRtf := TStringList.Create;
|
||
|
FRtfType := idMsgBldrRtfMS;
|
||
|
FRtfViewerNeededMsg := rsRtfViewerNeeded;
|
||
|
end;
|
||
|
|
||
|
destructor TIdMessageBuilderRtf.Destroy;
|
||
|
begin
|
||
|
FRtf.Free;
|
||
|
inherited Destroy;
|
||
|
end;
|
||
|
|
||
|
procedure TIdMessageBuilderRtf.Clear;
|
||
|
begin
|
||
|
FRtf.Clear;
|
||
|
inherited Clear;
|
||
|
end;
|
||
|
|
||
|
procedure TIdMessageBuilderRtf.FillBody(AMsg: TIdMessage);
|
||
|
var
|
||
|
LUsePlain, LUseRtf, LUseAttachments: Boolean;
|
||
|
LAlternativeIndex: Integer;
|
||
|
LTextPart: TIdText;
|
||
|
begin
|
||
|
// Cache these for better performance
|
||
|
//
|
||
|
LUsePlain := FPlainText.Count > 0;
|
||
|
LUseRtf := FRtf.Count > 0;
|
||
|
LUseAttachments := FAttachments.Count > 0;
|
||
|
LAlternativeIndex := -1;
|
||
|
|
||
|
// Is any body data present at all?
|
||
|
//
|
||
|
if not (LUsePlain or LUseRtf or LUseAttachments) then begin
|
||
|
Exit;
|
||
|
end;
|
||
|
|
||
|
// Should the message contain only plain text?
|
||
|
//
|
||
|
if LUsePlain and not (LUseRtf or LUseAttachments) then
|
||
|
begin
|
||
|
AMsg.Body.Assign(FPlainText);
|
||
|
Exit;
|
||
|
end;
|
||
|
|
||
|
// Should the message contain only RTF?
|
||
|
//
|
||
|
if LUseRtf and not (LUsePlain or LUseAttachments) then
|
||
|
begin
|
||
|
// TODO: create "multipart/alternative" pieces if FRtfViewerNeededMsg is not empty...
|
||
|
AMsg.Body.Assign(FRtf);
|
||
|
Exit;
|
||
|
end;
|
||
|
|
||
|
// At this point, multiple pieces will be present in the message
|
||
|
// body, so everything must be stored in the MessageParts collection...
|
||
|
|
||
|
// If the message should contain both plain text and RTF, a
|
||
|
// "multipart/alternative" piece is needed to wrap them if
|
||
|
// attachments are also present...
|
||
|
//
|
||
|
// RLebeau 11/11/2013: need to output the Alternative piece if
|
||
|
// the "RTF Viewer is needed" text is going to be used...
|
||
|
//
|
||
|
if {LUsePlain and} LUseRtf and LUseAttachments then
|
||
|
begin
|
||
|
LTextPart := TIdText.Create(AMsg.MessageParts, nil);
|
||
|
LTextPart.ContentType := cMultipartAlternative;
|
||
|
LAlternativeIndex := LTextPart.Index;
|
||
|
end;
|
||
|
|
||
|
// Is plain text present?
|
||
|
//
|
||
|
if LUsePlain or LUseRtf then
|
||
|
begin
|
||
|
LTextPart := TIdText.Create(AMsg.MessageParts, FPlainText);
|
||
|
if LUseRtf and (not LUsePlain) then
|
||
|
begin
|
||
|
LTextPart.Body.Text := FRtfViewerNeededMsg;
|
||
|
end;
|
||
|
LTextPart.ContentType := cTextPlain;
|
||
|
LTextPart.CharSet := FPlainTextCharSet;
|
||
|
LTextPart.ContentTransfer := FPlainTextContentTransfer;
|
||
|
LTextPart.ParentPart := LAlternativeIndex;
|
||
|
end;
|
||
|
|
||
|
// Is RTF present?
|
||
|
//
|
||
|
if LUseRtf then
|
||
|
begin
|
||
|
// Add RTF
|
||
|
//
|
||
|
LTextPart := TIdText.Create(AMsg.MessageParts, FRtf);
|
||
|
LTextPart.ContentType := cTextRtf[FRtfType];
|
||
|
LTextPart.ParentPart := LAlternativeIndex; // plain text and optional non-related attachments
|
||
|
end;
|
||
|
end;
|
||
|
|
||
|
procedure TIdMessageBuilderRtf.FillHeaders(AMsg: TIdMessage);
|
||
|
begin
|
||
|
if FAttachments.Count = 0 then
|
||
|
begin
|
||
|
if (FPlainText.Count > 0) and (FRtf.Count = 0) then
|
||
|
begin
|
||
|
// plain text only
|
||
|
//
|
||
|
AMsg.ContentType := cTextPlain;
|
||
|
AMsg.CharSet := FPlainTextCharSet;
|
||
|
AMsg.ContentTransferEncoding := FPlainTextContentTransfer;
|
||
|
end
|
||
|
else if (FRtf.Count > 0) and (FPlainText.Count = 0) then
|
||
|
begin
|
||
|
// RTF only
|
||
|
//
|
||
|
AMsg.ContentType := cTextRtf[FRtfType];
|
||
|
AMsg.CharSet := '';
|
||
|
AMsg.ContentTransferEncoding := '';
|
||
|
end else
|
||
|
begin
|
||
|
// plain text and RTF and no non-related attachments
|
||
|
//
|
||
|
AMsg.ContentType := cMultipartAlternative;
|
||
|
AMsg.CharSet := '';
|
||
|
AMsg.ContentTransferEncoding := '';
|
||
|
end;
|
||
|
end else
|
||
|
begin
|
||
|
inherited FillHeaders(AMsg);
|
||
|
end;
|
||
|
end;
|
||
|
|
||
|
procedure TIdMessageBuilderRtf.SetRtf(AValue: TStrings);
|
||
|
begin
|
||
|
FRtf.Assign(AValue);
|
||
|
end;
|
||
|
|
||
|
end.
|