Send an e-mail with rtf text in delphi - delphi

I would like to perform the following task: converting a TRichEdit content (an rtf text) into a not-plain-text e-mail message body.
MAPI doesn't support rtf, but is there a way to do it maybe with Indy?
The problem is that rtf is rtf and emails are plain text or HTML.
Can someone suggest a trick? Is it possible to convert rtf to text using TWebBrowser?
Basically the scenario is:
1) User writes email in a delphi form,
2) The email is then sent with MAPI to the default mail client (so a new email window is generated, and the message body is the same I had in delphi form)
3) User sends the email from mail client
Anyway MAPI accepts only plain text.
UPDATE:
Trying with Indy I wrote this but still it doesn't work, as I send a mail it to my gmail account I recieve a message with empty body and NONAME fake attachment.
uses IdMessageBuilder;
procedure SendMail;
var
MBuilder: TIdMessageBuilderRtf;
MyMemoryStream: TMemoryStream;
begin
try
MBuilder := TIdMessageBuilderRtf.Create;
MyMemoryStream := TMemoryStream.Create;
MBuilder.RtfType := idMsgBldrRtfRichtext;
// RichEdit1 has PlainText set to False
// at design time I pasted some formatted text onto it
RichEdit1.Lines.SaveToStream(MyMemoryStream);
MBuilder.Rtf.LoadFromStream(MyMemoryStream);
MBuilder.FillMessage(IdMessage1);
IdSMTP1.Connect;
IdSMTP1.Send(IdMessage1);
IdSMTP1.Disconnect;
finally
MyMemoryStream.Free;
MBuilder.Free;
end;
end;

Indy supports sending RTF emails. Send an email the same way you would send an HTML email, just use the "text/rtf", "text/enriched", or "text/richtext" Context-Type, and send the raw RTF codes that are generated by TRichEdit when its PlainText property is set to false. Also, if you are using Indy 10, look at its TIdMessageBuilderRtf class to set up the TIdMessage structure correctly.

Apparently (googled this myself, as I mail some from Delphi, but not in this case), the PR_RTF_COMPRESSED option of (extended) MAPI may help you here. Also look at this.

Is it possible to convert rtf to text using TWebBrowser?
You can convert RTF to Text using TRichEdit - but obviously this loses all formatting:
Using TRichEdit at runtime without defining a parent
2: You can find a number of RTF to HTML converters online - some free, some not. Like these:
http://wiki.delphi-jedi.org/wiki/JVCL_Help:TJvRichEditToHtml
https://www.habarisoft.com/scroogexhtml_delphi.html
http://www.easybyte.com/products/rtf2html.html
http://www.sautinsoft.com/products/rtf-to-html/index.php
3: You can rename the noname attachment as NONAME.MHT and it should then be openable with internet explorer.
However you might want to consider using an HTML edit control, rather than a TRichEdit. Then you have no conversion to worry about. Something like this question:-
WYSIWYG HTML Editor Component for Delphi

Related

How to reliably detect RICHTEXT format on clipboard?

Embarcadero RAD Studio VCL has the TClipboard.HasFormat Method, with a usage e.g. Clipboard.HasFormat(CF_TEXT) or Clipboard.HasFormat(CF_BITMAP) etc..
But I did not find any supported CF_RTF or CF_RICHTEXT format-descriptor which indicates a rich-text format in the clipboard.
So I created some formatted text in Microsoft WordPad and copied it to the clipboard. Then I used a clipboard-spy program to inspect the formats on the clipboard:
This lists 3 RichText formats with the format-descriptors C078, C16B and C1A5.
Are these format-descriptors universal or dependent from the individual system or from the current situation? I.e., can I generally use Clipboard.HasFormat($C078) to detect any RichText format on the clipboard? Or is there another method?
Can I generally use Clipboard.HasFormat($C078) to detect any
RichText format on the clipboard?
No, You need to register the RTF clipboard format via RegisterClipboardFormat function. The returned value is generated by the system and may vary.
Registers a new clipboard format. This format can then be used as a
valid clipboard format.
If a registered format with the specified name already exists, a new
format is not registered and the return value identifies the existing
format. This enables more than one application to copy and paste data
using the same registered clipboard format.
var
CF_RTF: UINT;
...
initialization
CF_RTF := RegisterClipboardFormat('Rich Text Format');
Then check for:
if Clipboard.HasFormat(CF_RTF) then ...
{ or // if Windows.IsClipboardFormatAvailable(CF_RTF) then ... }
Edit: After reading the documentation: How to Use Rich Edit Clipboard Operations
The constant CF_RTF is already declared in RichEdit unit as:
CF_RTF = 'Rich Text Format';
CF_RTFNOOBJS = 'Rich Text Format Without Objects';
CF_RETEXTOBJ = 'RichEdit Text and Objects';
So it might be a better idea to use other naming for the returned value of RegisterClipboardFormat. e.g.
uses RichEdit;
...
var
CF_RICHTEXT: UINT;
...
initialization
CF_RICHTEXT := RegisterClipboardFormat(RichEdit.CF_RTF);
And:
if Clipboard.HasFormat(CF_RICHTEXT) then ...
Note: There are already a few reserved system clipboard formats such as CF_TEXT (=1), CF_BITMAP(=2) etc ... but the "CF_RTF" or "CF_RICHTEXT" is not one of them. it is a custom format used by the RICHEDIT common control, and registered via RegisterClipboardFormat as already mentioned.

Delphi XE7,Unicode display problems with PageProducer on WebBroker

I'm writing a multilanguage WebBroker application (for Apache 2.2) which display unicode encoded data from an oracle database. The same data with the same data-aware components (Devart's ODAC) in a test program written in Delphi XE7, are displaying correctly.
My problem occured in the WebBroker where I'm facing with a strange behavior when I'm using a PageProducer to prepare the content for the response
When I'm using the follow code in the action :
Response.ContentType := 'text/html; charset=UTF-8';
PageProducer1.HTMLFile:= htmltemplate
Response.Content :=
PageProducer1.Content+
'Label 1 ='+Label1fromDB+
' Label 2='+Label2fromDB+
'</body></html>';
Response.SendResponse;
the result in the webbrowser is that all the non-latin chars that was not inserted by the PageProducer but already existed in the htmltemplate file (which has declared as utf-8 with ) replaced by other not correct chars, the text that was inserted by the PageProducer and was retrived from the database also not displayed correctly but the extra labels, Label1fromDB and Label2fromDB which are added to the content response as showing in the code above are displayed correctly having also the same chars which are inside the htmltemplate.
Now, when I omit the declaration
Response.ContentType := 'text/html; charset=UTF-8'
the content of the htmltemplate are diplaying correctly but all the other texts , the text filled by PageProducer and the two labels Label1fromDB and Label2fromDB not correctly
Can you please help me identify where the problem is and what have I do in order to be able to serve unicode multilanguage content via web broker?
You are having issues with different Unicode encodings.
Both PageProducer.Content and Response.Content are UTF16 encoded strings. Your htmltemplate is encoded in UTF8 and is not correctly interpreted by PageProducer.
Most likely cause is that htmltemplate file does not have UTF8 BOM at beginning and PageProducer will interpret that file encoding as default ANSI. If that is so, adding UTF8 BOM should solve your problem.

Indy message with Unicode Subject

I need to create a IdMessage with Unicode subject (eg "本語 - test")
I have tried setting it using
Msg.Subject := UTF8Encode(subject);
where subject is a WideString containing the text above
but when I look at the encoded subject (by saving the Message to file) it looks like this:
Subject: =?UTF-8?Q?=C3=A6=C5=93=C2=AC=C3=A8=C2=AA=C5=BE?= - test
instead of
Subject: =?UTF-8?Q?=E6=0C=AC=E8=AA=9E?= - test
and Outlook displays it as "本語 - test"
Any pointers as to where I am going wrong?
Delphi 2006 (pre-unicode), Indy 10 (fairly recent from source)
In pre-Unicode versions of Delphi, where everything is based on AnsiString, the value you assign to the TIdMessage.Subject property (and any other AnsiString property of TIdMessage, for that matter) MUST be encoded using the OS default character encoding. You are encoding it to UTF-8 instead, which will not work. This is because TIdMessage will first decode the Subject value to Unicode using the OS default encoding, then MIME-encode the Unicode data using the encoding parameters provided by the TIdMessage.OnInitializeISO event, or defaults if no event handler is assigned (in this case, those parameters are CharSet=UTF-8 and HeaderEncoding=QuotedPrintable). TIdMessage has no mechanism to allow you to specify the encoding used for any AnsiString data you assign to it. So the only possibility to send a value of '本語 - test' with the Subject property is to assign your source WideString as-is to the property and let the RTL convert the data to AnsiString using the OS default encoding:
Msg.Subject := subject;
However, if the OS does not support the Unicode characters being used, there will be data lost. There is no avoiding that in this scenario.
The alternative is to set the Subject property to a blank string and then use the TIdMessage.ExtraHeaders property instead so that you can provide your own header value that will be put into the email as-is. Using this approach, you can call Indy's EncodeHeader() function directly. In pre-Unicode versions of Delphi, it has an optional ASrcEncoding parameter that defaults to the OS default encoding (TIdMessage does not currently provide a value for that parameter when encoding headers):
uses
..., IdCoderHeader;
Msg.Subject := '';
Msg.ExtraHeaders.Values['Subject'] := EncodeHeader(UTF8Encode(subject), '', 'Q', 'UTF-8', IndyTextEncoding_UTF8);
This way, EncodeHeader() will be able to avoid a redundant conversion because it can detect that the source and target character encodings are both UTF-8, and thus just MIME-encode the source UTF-8 data as-is. Worse case, even if it did not detect the character encodings were the same, it would simply decode the source data to Unicode using UTF-8 and then re-encode it back to UTF-8. Those are lossless conversions, so no data is lost.
And FYI, the correct encoding for the Unicode characters you have shown would be:
Subject: =?UTF-8?Q?=E6=9C=AC=E8=AA=9E?= - test
Not
Subject: =?UTF-8?Q?=E6=0C=AC=E8=AA=9E?= - test
As you have shown. Notice the second encoded octet is 9C instead of 0C.

Indy IMAP4 does not display German symbols correctly

I am using TIdIMAP4 component to fill the string grid with the messages of my GMail mailbox.
var IMAPClient: TIdIMAP4;
Some messages have German umlauts. When I call IMAPClient.RetrieveAllHeaders(MyMsgList) the string grid is populated as expected (all umlauts are displayed) but there are no UIDs however (I guess that RetrieveAllHeaders just doesn't fetch UIDs).
When I call IMAPClient.UIDRetrieveAllEnvelopes(MyMsgList) all additional attributes of a Messages are there, but the headers are displayed in abracadabra (=?ISO-8859-1?Q?_Die_Br=FCcke_von_Arnheim?=) // Shall be 'Die Brücke von Arnheim'.
I've read many supportive posts but could not find the answer why IndyIMAP4 treats German symbols incorrectly.
Any ideas?
RetrieveAllHeaders() decodes the raw data it retrieves. UIDRetrieveAllEnvelopes() retrieves the raw data only, it does not decode. You can decode the raw headers manually by calling Indy's DecodeHeader() function in the IdCoderHeader unit.

How do I work with Word Documents without using COM Automation?

I have read multiple posts on the issue, and none seem to come to a decent conclusion to my question. (Perhaps I'm trying to see if anything has popped up lately.)
I have a small charity app that handles pledges. In doing so, it needs to work with and print documents.
Thing is, if Word is open in the background, the app thread will hang and won't respond to the closure of Word, and I have to roll back manually and close word. Sure, that all works fine, but I simply cannot guarantee that the end user will close Word, even if I put the instruction in a user manual.
I'm not too fussed about speed, but I guess that if it can be enhanced, it would be a nice little bonus.
Have any libraries been released for Delphi that will allow me to open, edit, print, and save documents? If not, is there a way to use Word Automation in such a way that it will not conflict with another open handle of Word when opened?
If you use GetActiveOleObject, you will get the running instance of Word.
By using CreateOleObject, you will get a new instance and shouldn't be troubled by other running instances.
In case you use the TWordApplication, wrapper you can set ConnectKind to ckNewInstance to accomplish this. By default, TWordApplication will try to connect with a running instance.
If you want to open edit and print Word documents and you don't mind using RTF format for what you're doing, investigate TRichView.
It will generate rich documents that are in RTF format, which is one of the formats MS word supports. I don't think it directly reads .DOC files but you can convert .DOC and .DOCX into RTF, for most simple files, but certain advanced formatting features would be lost in the conversion.
It has the advantage of working without any need for even any copy of MS Word to be installed on the machine that is going to do the document processing. For production of receipts and other simple documents, this would be the most reliable technique; Don't use Word directly, at all.
procedure PrintViaWord (const filename: string);
const
wdUserTemplatesPath = 2;
var
wrdApp, wrdDoc, wrdSel: variant;
begin
wrdApp:= CreateOleObject ('Word.Application'); // create new instance
sleep (5000); // this fixes a bug in Word 2010 to do with opening templates
wrdDoc:= wrdApp.documents.add (
wrdApp.Options.DefaultFilePath[wdUserTemplatesPath] + '\mytemplate.dot');
wrdDoc.Select;
wrdSel:= wrdApp.selection;
wrdApp.Options.CheckSpellingAsYouType:= 0;
wrdSel.paragraphformat.alignment:= 1;
wrdSel.typetext ('This is a program demonstrating how to open Word in the background'
+ ' and add some text, print it, save it and exit Word');
wrdDoc.SaveAs (filename + '.doc');
wrdApp.ActivePrinter:= 'Konica Minolta 211';
wrdApp.PrintOut;
WrdDoc.SaveAs (filename + '.doc');
wrdApp.quit;
wrdSel:= unassigned;
wrdDoc:= unassigned;
wrdApp:= unassigned
end;

Resources