enigmasolutions
asked on
tOLEContainer CreateOleObject tIDHTMLMessageBuilder and MS WORD as HTML Email Editor with email stored/retrieved from dataset
Hi All,
I am trying to create a delphi application that uses MS Word (preferably within a Delphi form) to create HTML emails (with embedded images) and then use SMTP (or Outlook) to send the emails. I want to use this system to create one-off emails as well as bulk emails (via mail merge) - all integrated into my application.
I have managed to get a lot of it working - which is a good start.
Note: I am using Delphi 2009.
This is a big question, so there is scope for a many correct answers, I plan to award points to all good answers, and increase points if necessary. I have attached a ZIP of the sample application - it is very concise and should help to understand this question.
I have a dataset with the following fields:
* EmailSubject tStringField
* EmailBody tMemoField
* EmailAttachments tBlobField
My plan is to get Delphi to call MS Word to create an HTML email and then store the HTML in EmailBody and the Attachments as multiple memory streams within a single memory stream that is stored in EmailAttachments (Arguably I could go with a second table here).
IMPORTANT - My preferred method for creating and editing my HTML documents is via the InFormEditButton method. Please focus on this.
So the following questions arise (in order of importance):
1) I want the InFormEditButton to open my HTML - but I can't get it to work?
2) In the EmailerWordEditorForm - why is there no Save/Update function in MS Word?
3) How do I retrieve changes as a result of the InFormEditButton?
4) In the EmailerWordEditorForm I want to create a button to drop place holder strings (eg <FirstName> that I can later perform search and replace for Mail Merge Purposes).
5) How can I change the InFromEditButton so I don't have to create a temportary file on the hard drive for teh image?
6) Why does the preview button display <\Div> in the preview screen?
7) Is there a way to get the Preview button to work withotu creatign teh temporary file?
8) Why does Button 4 have a bug?
9) With the NewButton and EditButton - is there a way to wait on teh Word App?
10) With the NewButton and EditButton - is there a way to avoid creating the temporary files?
11) How do I know WordApp has actually made changes?
12) How do I retrieve changes from WordApp?
13) I would like to see if I can get the OutlookButton to send my email via outlook - how?
14) Anyone wanting to have a go at tWordApplication is welcome also.
15) Pros & Cons of various methods appreciated
16) the EmailSMTP works well - enjoy & good luck...
In summary - I am looking for all constructive input that helps me (and the community) to understand OLE.
Below is the critical parts of the source code of the main form. I have also attached the full sample application. When I finally close this question I will upload the final source.
I am trying to create a delphi application that uses MS Word (preferably within a Delphi form) to create HTML emails (with embedded images) and then use SMTP (or Outlook) to send the emails. I want to use this system to create one-off emails as well as bulk emails (via mail merge) - all integrated into my application.
I have managed to get a lot of it working - which is a good start.
Note: I am using Delphi 2009.
This is a big question, so there is scope for a many correct answers, I plan to award points to all good answers, and increase points if necessary. I have attached a ZIP of the sample application - it is very concise and should help to understand this question.
I have a dataset with the following fields:
* EmailSubject tStringField
* EmailBody tMemoField
* EmailAttachments tBlobField
My plan is to get Delphi to call MS Word to create an HTML email and then store the HTML in EmailBody and the Attachments as multiple memory streams within a single memory stream that is stored in EmailAttachments (Arguably I could go with a second table here).
IMPORTANT - My preferred method for creating and editing my HTML documents is via the InFormEditButton method. Please focus on this.
So the following questions arise (in order of importance):
1) I want the InFormEditButton to open my HTML - but I can't get it to work?
2) In the EmailerWordEditorForm - why is there no Save/Update function in MS Word?
3) How do I retrieve changes as a result of the InFormEditButton?
4) In the EmailerWordEditorForm I want to create a button to drop place holder strings (eg <FirstName> that I can later perform search and replace for Mail Merge Purposes).
5) How can I change the InFromEditButton so I don't have to create a temportary file on the hard drive for teh image?
6) Why does the preview button display <\Div> in the preview screen?
7) Is there a way to get the Preview button to work withotu creatign teh temporary file?
8) Why does Button 4 have a bug?
9) With the NewButton and EditButton - is there a way to wait on teh Word App?
10) With the NewButton and EditButton - is there a way to avoid creating the temporary files?
11) How do I know WordApp has actually made changes?
12) How do I retrieve changes from WordApp?
13) I would like to see if I can get the OutlookButton to send my email via outlook - how?
14) Anyone wanting to have a go at tWordApplication is welcome also.
15) Pros & Cons of various methods appreciated
16) the EmailSMTP works well - enjoy & good luck...
In summary - I am looking for all constructive input that helps me (and the community) to understand OLE.
Below is the critical parts of the source code of the main form. I have also attached the full sample application. When I finally close this question I will upload the final source.
unit EmailerFormU;
//form header stuff here
procedure TEmailerForm.EditButtonClick(Sender: TObject);
var
tf:TextFile;
fs:TFileStream;
tempPath:string;
PathLen:DWORD;
s:string;
WordApp:OLEVariant;
begin
SetLength(TempPath,MAX_PATH);
PathLen:=GetTempPath(MAX_PATH, PChar(TempPath));
SetLength(TempPath,PathLen);
s:=ClientDataSet1.FieldByName('EmailBody').AsString;
s:=ReplaceText(s,'TestImage.jpg',TempPath+'TestImage.jpg');
AssignFile(tf, TempPath+'EmailBody.HTML');
ReWrite(tf);
Write(tf,s);
CloseFile(tf);
TBlobField(ClientDataSet1.FieldByName('EmailAttachments')).SaveToFile(TempPath+'TestImage.jpg');
WordApp := CreateOleObject('Word.Application') ;
wordApp.Visible:=true;
WordApp.Documents.Open(TempPath+'EmailBody.HTML');
WordApp:=Unassigned;
end;
procedure TEmailerForm.EmailButtonClick(Sender: TObject);
var
tf:TextFile;
fs:TFileStream;
tempPath:string;
PathLen:DWORD;
HTMLBd:string;
WordApp:OLEVariant;
IdSMTP : TIdSMTP;
IdMsg: TIdMessage;
IdAttachment: TIdAttachmentFile;
IMH:TIdMessageBuilderHtml;
begin
SetLength(TempPath,MAX_PATH);
PathLen:=GetTempPath(MAX_PATH, PChar(TempPath));
SetLength(TempPath,PathLen);
HTMLBd:=ClientDataSet1.FieldByName('EmailBody').AsString;
HTMLBd:=ReplaceText(HTMLBd,'TestImage.jpg',TempPath+'TestImage.jpg');
//AssignFile(tf, TempPath+'EmailBody.HTML');
//ReWrite(tf);
//Write(tf,s);
//CloseFile(tf);
TBlobField(ClientDataSet1.FieldByName('EmailAttachments')).SaveToFile(TempPath+'TestImage.jpg');
IMH:=TIdMessageBuilderHtml.Create;
IdMsg:=TIdMessage.Create(nil);
IdSMTP:=TIdSMTP.Create(nil);
try
//IdAttachment:=TIDAttachmentFile.Create(IdMsg.MessageParts,Attachment);
IdMsg.Date:=Now;
IdMsg.Recipients.EMailAddresses:= uiEmailTo.Text;
IdMsg.Subject:= ClientDataSet1.FieldByName('EmailSubject').AsString;
//IdMsg.Body.Text:= HTMLBd;
IdMsg.From.Name:= 'Test HTML Emailer';
IdMsg.From.Address:= uiEmailTo.Text;
//IdMsg.CCList.EmailAddresses:=GetAddressString(CCAddress);
//IdMsg.BCCList.EmailAddresses:=GetAddressString(BCCAddress);
//IdMsg.ReplyTo.EmailAddresses:=GetAddressString(ReplyToAddress);
//IMH.PlainText.Text:='Plain Text';
IMH.Html.Text:=HTMLBd;
IMH.HtmlFiles.Add(TempPath+'TestImage.jpg');
IMH.FillMessage(IdMsg);
IdSMTP.Host:= uiSMTPServer.Text;
IdSMTP.Username:= uiSMTPUser.Text;
IdSMTP.Password:= uiSMTPPassword.Text;
IdSMTP.AuthType:= satNone;
IdSMTP.Connect;
IdSMTP.Send(IdMsg);
IdSMTP.Disconnect;
finally
IMH.Free;
IdMsg.Free;
IdSMTP.Free;
end;
end;
procedure TEmailerForm.FormCreate(Sender: TObject);
var
BStream:tMemoryStream;
begin
ClientDataSet1.CreateDataSet;
ClientDataSet1.Append;
ClientDataSet1.FieldByName('EmailSubject').AsString:='Test Email';
ClientDataSet1.FieldByName('EmailBody').AsString:=Memo1.Text;
BStream:=tMemoryStream.Create;
try
Image1.Picture.Graphic.SaveToStream(BStream);
TBlobField(ClientDataSet1.FieldByName('EmailAttachments')).LoadFromStream(BStream);
finally
BStream.Free;
end;
ClientDataSet1.Post;
end;
procedure TEmailerForm.InFormEditButtonClick(Sender: TObject);
var
tf:TextFile;
fs:TFileStream;
tempPath:string;
PathLen:DWORD;
s:string;
f:TEmailerWordEditorForm;
CreateInfo: tCreateInfo;
WordApp:OleVariant;
begin
SetLength(TempPath,MAX_PATH);
PathLen:=GetTempPath(MAX_PATH, PChar(TempPath));
SetLength(TempPath,PathLen);
s:=ClientDataSet1.FieldByName('EmailBody').AsString;
s:=ReplaceText(s,'TestImage.jpg',TempPath+'TestImage.jpg');
AssignFile(tf, TempPath+'EmailBody.HTML');
ReWrite(tf);
Write(tf,s);
CloseFile(tf);
TBlobField(ClientDataSet1.FieldByName('EmailAttachments')).SaveToFile(TempPath+'TestImage.jpg');
//This link explains how to load the OleContainer without having to create the file - but I couldn't get it to work
//http://www.experts-exchange.com/Programming/Languages/Pascal/Delphi/Q_21821816.html
f:=TEmailerWordEditorForm.Create(self);
try
//f.OleContainer1.AllowInPlace:=true;
//f.OleContainer1.AutoActivate:=aaManual;
f.OleContainer1.CreateObject('Word.Document',false);
WordApp:=f.OleContainer1.OleObject;
WordApp.Open(TempPath+'EmailBody.HTML');
//WordApp.FileOpen(TempPath+'EmailBody.HTML');
//WordApp.Documents.Open(TempPath+'EmailBody.HTML');
//f.OleContainer1.OleObject.Documents.FileOpen(TempPath+'EmailBody.HTML');
//f.OleContainer1.OleObject.Documents.Open(TempPath+'EmailBody.HTML');
//f.OleContainer1.LoadFromFile(TempPath+'EmailBody.HTML');
//f.OleContainer1.DoVerb(ovShow);
f.ShowModal;
finally
f.Free;
end;
end;
procedure TEmailerForm.NewButtonClick(Sender: TObject);
var
tf:TextFile;
fs:TFileStream;
tempPath:string;
PathLen:DWORD;
s:string;
WordApp:OLEVariant;
begin
SetLength(TempPath,MAX_PATH);
PathLen:=GetTempPath(MAX_PATH, PChar(TempPath));
SetLength(TempPath,PathLen);
AssignFile(tf, TempPath+'EmailBody.HTML');
ReWrite(tf);
Write(tf,'This is a New Email');
CloseFile(tf);
WordApp := CreateOleObject('Word.Application') ;
wordApp.Visible:=true;
WordApp.Documents.Open(TempPath+'EmailBody.HTML');
WordApp:=Unassigned;
//WordApp.wait;
//WordDocument := WordApplication.Documents.Add;
//WordApplication.Selection.TypeText('Hello world') ;
//WordDocument.SaveAs(FileName := 'C:\Doc.Doc',
// AddToRecentFiles := False) ;
//WordApplication.Quit(False)
end;
procedure TEmailerForm.OutlookButtonClick(Sender: TObject);
var
tf:TextFile;
fs:TFileStream;
tempPath:string;
PathLen:DWORD;
s:string;
OutApp:OLEVariant;
begin
SetLength(TempPath,MAX_PATH);
PathLen:=GetTempPath(MAX_PATH, PChar(TempPath));
SetLength(TempPath,PathLen);
s:=ClientDataSet1.FieldByName('EmailBody').AsString;
s:=ReplaceText(s,'TestImage.jpg',TempPath+'TestImage.jpg');
AssignFile(tf, TempPath+'EmailBody.HTML');
ReWrite(tf);
Write(tf,s);
CloseFile(tf);
TBlobField(ClientDataSet1.FieldByName('EmailAttachments')).SaveToFile(TempPath+'TestImage.jpg');
OutApp := CreateOleObject('Outlook.Application') ;
OutApp.Visible:=true;
//OutApp.Documents.Open(TempPath+'EmailBody.HTML');
//OutApp.Documents.Send;
OutApp:=Unassigned;
end;
procedure TEmailerForm.Button4Click(Sender: TObject);
var
BStream:tMemoryStream;
begin
BStream:=tMemoryStream.Create;
try
TBlobField(ClientDataSet1.FieldByName('EmailAttachments')).SaveToStream(BStream);
Image2.Picture.Graphic.LoadFromStream(BStream);
finally
BStream.Free;
end;
end;
procedure TEmailerForm.PreviewButtonClick(Sender: TObject);
var
tf:TextFile;
fs:TFileStream;
tempPath:string;
PathLen:DWORD;
s:string;
sl:tstringlist;
begin
SetLength(TempPath,MAX_PATH);
PathLen:=GetTempPath(MAX_PATH, PChar(TempPath));
SetLength(TempPath,PathLen);
s:=ClientDataSet1.FieldByName('EmailBody').AsString;
s:=ReplaceText(s,'TestImage.jpg',TempPath+'TestImage.jpg');
sl:=tstringlist.Create;
sl.Text:=s;
sl.SaveToFile(TempPath+'EmailBody.HTML');
sl.Free;
//AssignFile(tf, TempPath+'TestBody.HTML');
//ReWrite(tf);
//Write(tf,s);
//CloseFile(tf);
TBlobField(ClientDataSet1.FieldByName('EmailAttachments')).SaveToFile(TempPath+'TestImage.jpg');
WebBrowser1.Navigate(TempPath+'EmailBody.HTML');
end;
end.
EmailerWordApp.zip
ASKER
I just came accross a website with quite a lot of information on the subject (but it is all quite old) - see here:
http://www.djpate.freeserve.co.uk/AutoWord.htm
But, at the very bottom is a link with source code that adds functionality to tOleContainer.
http://www.djpate.freeserve.co.uk/wordcntr.zip
Perhaps this will solves some of the issues.
http://www.djpate.freeserve.co.uk/AutoWord.htm
But, at the very bottom is a link with source code that adds functionality to tOleContainer.
http://www.djpate.freeserve.co.uk/wordcntr.zip
Perhaps this will solves some of the issues.
ASKER
For the record we thought about using a delphi HTML Editor component (the first one below seems the best). But I feel that it might be better to use MS Word if possible (more functionaliity / more widely used).
http://www.profgrid.com/dhtmledit.html
http://delphi2.software.informer.com/download-delphi-component-wysiwyg-html-editor/
http://coding.derkeiler.com/Archive/Delphi/borland.public.delphi.thirdpartytools.general/2004-10/0380.html
http://delphi2.software.informer.com/download-delphi-html-editor-vcl-component/
http://www.profgrid.com/dhtmledit.html
http://delphi2.software.informer.com/download-delphi-component-wysiwyg-html-editor/
http://coding.derkeiler.com/Archive/Delphi/borland.public.delphi.thirdpartytools.general/2004-10/0380.html
http://delphi2.software.informer.com/download-delphi-html-editor-vcl-component/
ASKER
We believe we will have a fix for the EmailSMTP button soon. We were getting an attachment (with extension .dat) instead of having the image embedded. Anyway our research tells us that this was a bug in the version of INDY we have that came with Delphi 2009. We are in the process of upgrading INDY (which is not that easy). My guess is that for anyone running Delphi 10 or later it will work.
ASKER
Woo hoo - We got EmailSMTP button working. Now to get tOLEContainer working which should be easy. We will sort that out on Monday (if everything goes as planned).
FYI - We tried using Report Builder with Pragnaan Exports to create an HTML report. Unfortunately I worked out that I can’t use Report Builder and Pragnaan to send HTML emails because MS Word & Outlook do not support the "position" HTML command. Refer to this article:
http://superuser.com/questions/146453/css-absolute-position-dont-work-in-ms-word
We are going to use Report Builder anyway to send RTF reports (eg for customer statements). When we do this we will use the same technique to send RTF emails. We will attached code for this later.
FYI - We tried using Report Builder with Pragnaan Exports to create an HTML report. Unfortunately I worked out that I can’t use Report Builder and Pragnaan to send HTML emails because MS Word & Outlook do not support the "position" HTML command. Refer to this article:
http://superuser.com/questions/146453/css-absolute-position-dont-work-in-ms-word
We are going to use Report Builder anyway to send RTF reports (eg for customer statements). When we do this we will use the same technique to send RTF emails. We will attached code for this later.
ASKER
OK, I have managed to resolve issues 6 onwards. I will soon attach source code.
I am still struggling with tOLEContainer.
Specifically with the following commands:
f.OleContainer1.CreateObje ct('Word.D ocument',f alse);
f.OleContainer1.LoadFromFi le(TempPat h+'EmailBo dy.HTML');
I get "Invalid Stream Format" on the second command.
Why?
I am still struggling with tOLEContainer.
Specifically with the following commands:
f.OleContainer1.CreateObje
f.OleContainer1.LoadFromFi
I get "Invalid Stream Format" on the second command.
Why?
ASKER CERTIFIED SOLUTION
membership
This solution is only available to members.
To access this solution, you must be a member of Experts Exchange.
SOLUTION
membership
This solution is only available to members.
To access this solution, you must be a member of Experts Exchange.
SOLUTION
membership
This solution is only available to members.
To access this solution, you must be a member of Experts Exchange.
ASKER
I will award points to contributors. But for now my most pressing issue is:
In the EmailerWordEditorForm I want to create a button to drop place holder strings (eg <FirstName> that I can later perform search and replace for Mail Merge Purposes).
The problem is the form behaves strangely - ie the MS Word Ribbon dissapears when you lose focus.
I have posted a separate question on this to see if I get any better response.
See here: https://www.experts-exchange.com/questions/26847218/How-to-stop-MS-Word-Ribbon-disappearing-when-using-tOLEContainer-and-switching-focus.html
As you can see from the above I have a work around. So we are nearing teh finish of this post.
In the EmailerWordEditorForm I want to create a button to drop place holder strings (eg <FirstName> that I can later perform search and replace for Mail Merge Purposes).
The problem is the form behaves strangely - ie the MS Word Ribbon dissapears when you lose focus.
I have posted a separate question on this to see if I get any better response.
See here: https://www.experts-exchange.com/questions/26847218/How-to-stop-MS-Word-Ribbon-disappearing-when-using-tOLEContainer-and-switching-focus.html
As you can see from the above I have a work around. So we are nearing teh finish of this post.
SOLUTION
membership
This solution is only available to members.
To access this solution, you must be a member of Experts Exchange.
ASKER
This question should be added to the knowledgebase - it has some good info. I am prepared to award points. But I am dissappointed with the overall response. Which is why I left it open - hoping for more responses.
ASKER
Points go to ewangoya for the contribution.
Although B grade because I would have liked some of the other parts of the question answered considering the maximum award of 500 points.
I also set some of my own contrinbutions as soltions because they are in-fact the soluution to much of this question.
Although B grade because I would have liked some of the other parts of the question answered considering the maximum award of 500 points.
I also set some of my own contrinbutions as soltions because they are in-fact the soluution to much of this question.
ASKER
The EmailSMTP does not quite work. The problem is that the image that is embedded in the HTML of the email is ONLY visible on my PC. Because it has a link to the image in my Windows Temp directory.
So one more question - how do I get the image to be embedded?