Professional Documents
Culture Documents
1.1 Requirements
The code samples are provided for Delphi 7 (Indy 9) and Delphi 2006 (Indy 10). You can use Delphi 2006 sample if upgraded to Indy 10 inside Delphi 7.
2. E-Mail formats
If you are familiar with a structure of e-mail messages then you can jump to How to create e-mail part. Usually any e-mail has 3 major parts: Header - contains information about a subject of the e-mail, who and when sent it, what program sent an e-mail, who should receive it, priority of an e-mail and some addition tracking info. Divider - blank line. It separates header and an e-mail body. Message body - contains a text of a message (optional, could be empty) and/or attachment(s). Another thing should be taken in consideration is a format of an e-mail. There are two forms of e-mails: non-MIME encoded emails - generally used to send plain-text, simple emails MIME-encoded emails - more common for e-mails that have attachments and for e-mails with formatted text (HTML/RTF based)). If your e-mail is properly formatted it will be accepted by any modern e-mail client. If it does not follow a guidelines an e-mail client might reject it or show it incorrectly.
02: Received: from ([000.00.00.000]) by smtp.mymail.com with Microsoft SMTPSVC(5.0.2195.6713); Mon, 22 Mar 2004 16:36:25 -0800 03: From: serge@domain.com 04: Subject: TEST 05: To: serge@domain.com 06: Date: Tue, 23 Mar 2004 13:52:41 -0800 07: X-Priority: 3 08: X-Library: Indy 9.00.10 09: Return-Path: serge@domain.com 10: Message-ID: <2KRELAYJwnzsLqIfQdm00000032@smtp.mymail.com> 11: X-OriginalArrivalTime: 23 Mar 2004 00:36:25.0250 (UTC) FILETIME=[DF543020:01C4106E] 12: 13: Hi, this is a test message 14: . Note #1: Code above is formatted to include line number, you will not see it in actual e-mail text. Note #2: The blank line between the header and the body (message) is important. Also if an e-mail includes any attachments then those will follow an e-email body and will be divided with a blank line (see bellow). The '.' in a last line is mandatory. It is a message terminator, denoting the end of an email. Note #3: When this sample is decoded by Indy, the message will be decoded and stored in the TIdMessage.Body. Also TIdMessage.Encoding is set to meUU. This situation is changed as soon as you add an attachment.
16: This is a multi-part message in MIME format 17: 18: --=_NextPart_2rfkindysadvnqw3nerasdf 19: Content-Type: text/plain 20: Content-Transfer-Encoding: 7bit 21: 22: some text 23: 24: --=_NextPart_2rfkindysadvnqw3nerasdf 25: Content-Type: image/jpg; 26: name="htmlbodyIMG0000.JPG" 27: Content-Transfer-Encoding: base64 28: Content-Disposition: attachment; 29: filename="htmlbodyIMG0000.JPG" 30: 31: /9j/4AAQSkZJRgABAQAAAQABAAD/ 2wBDAAMCAgMCAgMDAwMEAwMEBQgFBQQEBQoHBwYIDAoMDAsK <skipped> WW: AKKKKACiiigD/9k= XX: YY: --=_NextPart_2rfkindysadvnqw3nerasdf-ZZ: . When compare this e-mail sample with one for non-MIME encoded emails there are significant differences: Although the headers are the same, in a MIME-encoded emails the additional information about Content-Type and MIME-Version is included (lines 12 and 13). It is followed by "prefix" text (it is called Preamble) and it is used in case if your e-mail client does not recognize MIME blocks or MIME encoding is disabled (line 16). Next are two MIME encoded parts: first contains a text which will be visible in your E-Mail client as a message body; and second is a part with file which is attached to an e-mail. When INDY receives and processes such e-mails, the following parts can be accessed: "prefix" is put in the TIdMessage.Body "part I" and "part II" are stored in a TIdMessage.MessageParts collection: "part I" is presented by object of type TIdText, and "part II" as TIdAttachment. TIdMessage.Encoding is set to meMIME Note #1: In e-mail clients with MIME encoding enabled/available, the "part I" is ignored by MIME encoder and will be not used anywhere in visible text. Still you can specify it as an indication for an e-mail client that e-mail body is stored in MIME blocks. Note #2: Indy 9 does not have an ability to override a Preamble text. This feature is available starting INDY 10: there is a ConvertPreamble property which allows to turn a default text "This is a multi-part message in MIME format" off (ConvertPreamble := False) and allows to use a Message Body to specify a text used by preamble block.
Please follow a next list to see how to create e-mails with different formats and abilities. 3.1 3.2 3.3 3.4 Simple E-Mail Composite E-Mail HTML Formatted E-Mail HTML Formatted E-Mail with objects
Note. In the sample codes below we are going to work with MIME-enabled e-mails.
// ... A code to send a message end; In the case when you have attachments, Indy generates the MIME-encoded email, so the message text has to go in a "text" part rather than the Body. The equivalent code is: var lMessage: TIdMessage; lTextPart: TIdText; begin // ... some code here to initialize your SMTP server. // It could be done somewhere as well lMessage := TIdMessage.Create(Self); lMessage.From.Address := 'myemail@mydomain.com'; lMessage.Subject := 'My test email'; lMessage.Recipients.Add.Address := 'someoneemail@somedomain.com'; lMessage.Body.Clear; lTextPart := TIdText.Create(lMessage.MessageParts); lTextPart.Body.Text := 'some text'; lTextPart.ContentType := 'text/plain'; lTextPart.ContentTransfer := '7bit'; TIdAttachment.Create(lMessage.MessageParts, 'htmlbodyIMG0000.JPG'); // ... A code to send a message end; Note #1: In any attempts to clear lMessage.Body, INDY will automatically set a default "prefix" text to "This is a multi-part message in MIME format" to indicate that an e-mail has MIME parts. lMessage.Body.Text will be ignored and standard preamble text will be used. Note #2: Delphi 7 includes version of INDY which does not work correctly in second situation when message is streamed or saved into a file and a TIdText part created is suppressed. This was corrected in the next releases. Note #3: If your message is not a simple message with an attachment, please refer to the Complex messages section.
lTextPart := TIdText.Create(lMessage.MessageParts); lTextPart.Body.Text := '<html><body><b>This is a HTML message</b></body></html>'; lTextPart.ContentType := 'text/html'; // ... A code to send a message end; Note #1: HTML Formatted E-mail allows to format a text. If you need to include any addition objects into e-mail (for ex. pictures) please read HTML Formatted E-Mail with objects. Note #2: Even if the plain-text part is not required, it is highly recommended to include it as a first part. This will allow clients that does not support multipart/alternative emails to display the plain-text version of the e-mail, so user can get some information about an e-mail. Note #3: You can try to use different ContentTypes (such as "text/rtf"), but it is not common and not many e-mail client might support it.
var lMessage: TIdMessage; lTextPart: TIdText; lImagePart: TIdAttachment; begin // ... some code here to initialize your SMTP server. // It could be done somewhere as well lMessage := TIdMessage.Create(Self); lMessage.From.Address := 'myemail@mydomain.com'; lMessage.Subject := 'My test email'; lMessage.Recipients.Add.Address := 'someoneemail@somedomain.com'; lMessage.Body.Clear; lTextPart := TIdText.Create(lMessage.MessageParts); lTextPart.Body.Text := 'This is a plain text message'; lTextPart.ContentType := 'text/plain'; lTextPart := TIdText.Create(lMessage.MessageParts); lTextPart.Body.Text := '<html><body><b>This is a HTML message with picture</b><img src=" lTextPart.ContentType := 'text/html'; lImagePart := TIdAttachment.Create(lMessage.MessageParts, 'htmlbodyIMG0000.JPG'); lImagePart.ContentType := 'image/jpg'; lImagePart.Headers.Add('Content-ID: <htmlbodyIMG0000.JPG>'); // ... A code to send a message end; When message is received, it will have all required information for you to see an e-mail content.
Note: E-mail with embedded objects will be presented by client in very specific manner: picture files will be still visible as an attachments to a document and can be treated as regular attachments and then used by e-mail formatter. But if attachments are lost, not included or blocked on a way in, then text will have just empty placeholders for missing pictures.
5. Message tuning
5.1 Changing the body encoding
By default a body text (preamble text for MIME encoded messages) is not encoded. It is not recommended to encode Body text of MIME encoded messages (parts 3.2.2, 3.3 and 3.4) because it could cause incorrect representation of the message by e-mail client.
In a case of simple messages (part 3.1) and simple messages with attachments (part 3.2.1) this is acceptable and TIdMessage.ContentTransferEncoding property could be used to specify encoding.
6. Comments
6.1 Message streaming
Working with messages from Delphi sometimes it is useful be able to save a content of e-mail into a file or stream. It is possible to do with INDY but there is some problems in current version of a component implementation available in Delphi 7. 1. In original INDY for Delphi 7, streaming mechanism is broken in some situation. See a "Standard streaming" code from a sample project - streamed composite e-mail will be broken. A solution is implemented in "Fixed Streaming" action or use newer version of INDY from your application. 2. In last stable release of INDY 9 (available from web-site) a stream passed into TIdMessage.SaveToStream is destroyed from inside a method. What this means is you cannot use a stream storage, to have access to a message information. You can pass a TFileStream or TMemoryStream, but do not expect to use it after method is invoked. If you want fix this do it yourself, copy a code of a method in your application and change it by adding next line after LIOHS is created: LIOHS.FreeStreams := False;. You can also use latest dev release which has this issue fixed. 3. Next problem with streaming appears when you using e-mails with attachments. After email is restored from the stream make sure you've got same parts you've saved - there might be an extra part for default message body. Then it should be removed before e-mail could be sent. 4. Standard version of INDY included in Delphi 7 does not support headers in attachments being streamed. Update to a latest version might help in this situation. 5. Similar problem exists for addition information stored in TIdPart.Headers when restored from the stream. In sample project TIdPart.Headers is used to specify "Content-ID" value. Check "Fixed Streaming" portion from sample for details. Some of these issues are addressed in latest releases of INDY 9 and INDY 10. Please check NEVRONA/INDY web-site for more information. Be aware what latest version 10 has some number of introduced issues. Check a bug list before you will decide to update.
7. Links
This article on the web This article on the BDN Delphi 7/2006 sample project
10