Based on some great samples that I found on the web, specially those from Mike Gagnon, I've created my own class to send emails. I chose to use CDOSYS (Microsoft Collaboration Data Objects for Windows 2000)because it comes with Win2000 / XP / Vista and 2003, and it allows to send messages in various ways, specially embedding images that are used in the HTML content of the message.
MAPI was my first choice, but unfortunately it does not allow to embed pictures, only attachments are allowed. MS Outlook automation would work too, but I don`t have it too.
Below is a simple code that generates an HTML page that contains some images that is to be sent. The images are embedded to the message, not as common attachments ! This allows us to show the pictures in the place and characteristics we desire.
Apart from the most common features, it also allows you to embed pictures, add attachments, set priority, ask for a read receipt and send HTML.
The "Body" property of the class accepts 3 different kinds of parameters: 1- An HTML code, 2- an URL (CDOSYS will embed the entire page in the message) or 3- A .htm file that will be embedded. For this last option, my tests failed when I used spaces in either the directory name of the filename, so avoid spaces in filenames !
The pictures below show some screenshots of some samples that I generated and received using the code below, opened with Outlook Express. This was tested in some webmails too, eg. Hotmail, and the result is similar.


Save the code below as a prg, not forgetting to replace the information in Red for your own, and run it.
It will ask you to choose some pictures. When finished, click "cancel"at the GETPICT() dialog, then choose any 2 other files that will be attached. Wait for some seconds, enough time for sending the email, and check your inbox.
LOCAL lcHeader, lcBody, lcClose, lcMsgBody, lnIndex, lcIndex, lcPictFile, lcJustFnamePictFile, lcHTML
TEXT TO lcHeader
<HTML><HEAD>
<BODY bgColor=#ffffff>
<DIV><FONT face=Verdana size=4><STRONG>EMBED PICTURES SAMPLE WITH CDOSYS</STRONG></FONT></DIV>
<P></P><P></P>
ENDTEXT
TEXT TO lcBody
<DIV><IMG src="<<lcPictFile>>"></DIV>
<DIV><FONT face=Verdana size=2>Image <<lcIndex>> - <<lcJustFnamePictFile>></FONT></DIV>
<P></P><P></P><div></div><div></div>
ENDTEXT
TEXT TO lcClose
</BODY></HTML>
ENDTEXT
lcMsgBody = ""
lnIndex = 1
DO WHILE .T.
lcPictFile = GETPICT()
IF EMPTY(lcPictFile)
EXIT
ENDIF
lcIndex = TRANSFORM(lnIndex)
lcJustFnamePictFile = JUSTFNAME(lcPictFile)
lcMsgBody = lcMsgBody + TEXTMERGE(lcBody)
lnIndex = lnIndex + 1
ENDDO
lcHTML = lcHeader + lcMsgBody + lcClose
* STRTOFILE(lcHtml,"c:\myHtmFile.htm")
LOCAL loMail as CDOSYSMAIL
loMail = CREATEOBJECT("CDOSYSMAIL")
WITH loMail
.SMTPServer = "smtp.yourdomain.com" && place your smtp here
.UserName = "yourusername" && Username
.Password = "yourpassword" && Password
.From = "Your Name <you@yourserver.com>"
.To = "destination@server.com"
.Subject = "Testing CDOSYSMail"
.HTMLFormat = .T. && Default = .T.
.Priority = 1 && Default = 0 -1=Low, 0=Normal, 1=High
.ReadReceipt = .T. && Default = .F.
.ReceiptTo = "you@yourserver.com"
.Body = lcHTML
* .Body = "http://www.microsoft.com"
* .Body = "c:/myHtmFile.htm"
.AddAttachment(GETFILE()) && FullPath of attachment
.AddAttachment(GETFILE())
.Send()
ENDWITH
RETURN
DEFINE CLASS CDOSYSMAIL AS Custom
SMTPServer = ""
UserName = ""
Password = ""
From = ""
To = ""
Body = ""
Subject = ""
CC = ""
BCC = ""
HTMLFormat = .T.
Priority = 0
ReadReceipt = .F.
ReceiptTo = ""
DIMENSION aFiles(1)
PROCEDURE AddAttachment(tcFile)
IF VARTYPE(tcFile) = "C" AND FILE(tcFile)
lnFiles = ALEN(This.aFiles)
DIMENSION This.aFiles(lnFiles + 1)
This.aFiles(lnFiles+1) = tcFile
ENDIF
ENDPROC
PROCEDURE Send
#DEFINE CdoReferenceTypeName 1
#DEFINE CdoReferenceTypeId 0
LOCAL lcSchema, loConfig, loMsg
lcSchema = "http://schemas.microsoft.com/cdo/configuration/"
LOCAL loConfig as "CDO.Configuration"
loConfig = CREATEOBJECT("CDO.Configuration")
WITH loConfig.FIELDS
.Item(lcSchema + "smtpserver") = This.SMTPServer && host of smtp server
.Item(lcSchema + "smtpserverport") = "25" && SMTP Port
.Item(lcSchema + "sendusing") = 2 && Send it using port
.Item(lcSchema + "smtpauthenticate") = .T. && Authenticate
.Item(lcSchema + "smtpusessl") = .F.
.Item(lcSchema + "sendusername") = This.UserName && login
.Item(lcSchema + "sendpassword") = This.Password && your password
.Item(lcSchema + "smtpconnectiontimeout") = 10 && Assign timeout in seconds
.Update()
ENDWITH
LOCAL loMsg as "CDO.Message"
loMsg = CREATEOBJECT ("CDO.Message")
WITH loMsg
.Configuration = loConfig
.Subject = This.Subject
.FROM = This.From
.TO = This.To
IF VARTYPE(This.CC) = "C"
.CC = This.CC
ENDIF
IF VARTYPE(This.BCC) = "C"
.BCC = This.BCC
ENDIF
DO CASE
CASE FILE(This.Body)
loMsg.CreateMHTMLBody("file://" + This.Body)
CASE LOWER(LEFT(This.Body,7)) = "http://"
loMsg.CreateMHTMLBody(This.Body) && This.Body
CASE This.HTMLFormat = .T.
LOCAL n, lcFile, lcPictRef, lcHTML, lcImgTag
lcHTML = This.Body
n = 1
DO WHILE .T.
lcImgTag = STREXTRACT(lcHTML, "<IMG", ">", n, 1)
lcFile = STREXTRACT(lcImgTag, ["], ["])
IF EMPTY(lcImgTag)
EXIT
ENDIF
IF "http:" $ LOWER(lcFile) && reference to a picture stored on the web, so skip !
n = n + 1
LOOP
ENDIF
lcPictRef = "cid:" + JUSTFNAME(lcFile)
lcHTML = STRTRAN(lcHTML, lcFile, lcPictRef, 1, 1)
loMsg.AddRelatedBodyPart(lcFile, JUSTFNAME(lcFile), CdoReferenceTypeId)
loMsg.Fields.Item("urn:schemas:mailheader:Content-ID") = "<" + (JUSTFNAME(lcFile)) + ">"
loMsg.Fields.Update()
n = n + 1
ENDDO
.HTMLBody = lcHTML
OTHERWISE
.TextBody = This.Body
ENDCASE
IF ALEN(This.aFiles) > 1
LOCAL lnCount
FOR lnCount = 2 TO ALEN(This.aFiles)
.AddAttachment(This.aFiles(lnCount))
.Fields.Update()
ENDFOR
ENDIF
* Set priority if needed
IF This.Priority <> 0
.Fields.Item("urn:schemas:mailheader:X-Priority") = This.Priority && -1=Low, 0=Normal, 1=High
.Fields.Item("urn:schemas:httpmail:importance") = This.Priority
.Fields.Update()
ENDIF
* Ask for Reading Receipt if needed
IF This.ReadReceipt = .T.
IF EMPTY(This.ReceiptTo)
This.ReceiptTo = This.To
ENDIF
.Fields("urn:schemas:mailheader:disposition-notification-to") = This.ReceiptTo
.Fields("urn:schemas:mailheader:return-receipt-to") = This.ReceiptTo
.Fields.Update()
ENDIF
* Set DSN options. This still needs some checking. For some SMTP servers this makes CDOSYS not to send the msg.
* Name Value Description
* cdoDSNDefault 0 No DSN commands are issued.
* cdoDSNNever 1 No DSN commands are issued.
* cdoDSNFailure 2 Return a DSN if delivery fails.
* cdoDSNSuccess 4 Return a DSN if delivery succeeds.
* cdoDSNDelay 8 Return a DSN if delivery is delayed.
* cdoDSNSuccessFailOrDelay 14 Return a DSN if delivery succeeds, fails, or is delayed.
.MDNRequested = .T.
* .DSNOptions = 2
.Fields.Update()
.Send()
ENDWITH
ENDPROC
ENDDEFINE
Related links:
Mike Gagnon Étude sur l'utilisation de CDO et MAPI avec Visual Foxpro
http://fox.wikis.com/wc.dll?Wiki~CdoEmail~VFP
Craig Boyd article
How do I alter the priority / importance of an e-mail message?
Email, POP3, SMTP Scripts, Components and Articles
Lots of samples here
How to use the Cdosys.dll library to embed a message in a new message by using Visual C#