Menu

Sending e-mails with Microsoft Powerscript and VFP, inspired by Doug Hennig

After finally releasing FoxyPreviewer3, I started receiving several requests for sending e-mails. FP3 currently supports the use of CDOSYS - the good and old way Windows used to allow us to send e-mails. The usage was really simple, but it's not compatible with TLS - evolved from the good and old SSL protocol, providing more security to the process.

Unfortunately, there is no simple way for Foxers to send messages using TLS, unless if we use some bridges to access other platforms. So, this was the right time to make tests, inspired by Doug Hennig's session on the last VFF - Virtual Fox Fest - the new online VFP conference, when he presented the amazing session Windows PowerShell: Batch Files on SteroidsThe organizers of VFF were very kind offering a recorded version of all sessions for free for the community in YouTube. At the end of this post you'll find the links to his presentation on YouTube, generously shared by the conference organizers.

So, fist of all I just googled about sending e-mails with PowerScript, and found tons of posts all over, in all languages. And here is my first script to send e-mails. This is raw code, no error handling, very few parameter checking. Needs development, but looks promising, and very effective!

  • create a script in Powershell, and test it
  • since we can't send parameters directly, we need to change the script to adapt it to our needs. One easy way is to store the Script in a "TEXT / ENDTEXT", and using TEXTMERGE make the needed replacements
  • Save the script using the ".PS1" file extension
  • Use the WScript.Shell.Run to run the PS1 file script in invisible mode. Powershell allows us to save the outputs in a text file. This file will be used for us to store the returning values we need
  • Delete the temporary PS1 and Output files



FUNCTION SendPSEmail(tcDest, tcSubject, tcBody, tcAttachment, tcServer, tcUser, tcPwd, tcPort)

	LOCAL lcBodyAsHtml, lcCredentials, lcPSScript, lcSender
	m.lcSender = m.tcUser
	IF "<" $ m.tcUser
		m.tcUser   = STREXTRACT(m.tcUser, "<", ">")
	ENDIF

	m.tcPort = TRANSFORM(m.tcPort)
	m.tcDest = [@('] + STRTRAN(m.tcDest, [,], [';']) + [')] && Adjust for multiple recipients
	IF EMPTY(m.tcAttachment)
		m.tcAttachment = ""
	ELSE
		m.tcAttachment = [Attachment = ] + [@('] + STRTRAN(m.tcAttachment, [,], [', ']) + [')]
	ENDIF

	IF "" $ LOWER(m.tcBody)
		m.lcBodyAsHtml = "BodyAsHtml = $true"
	ELSE
		m.lcBodyAsHtml = ""
	ENDIF

	IF EMPTY(m.tcPwd)
		m.lcCredentials = "$cred = Get-Credential"
	ELSE
		m.lcCredentials = "$pass = ConvertTo-SecureString -String $pass -AsPlainText -Force" + CHR(13) + ;
			"$cred = New-Object System.Management.Automation.PSCredential $user, $pass"
	ENDIF


	* Here starts the Powershell script
	TEXT TO m.lcPSScript NOSHOW TEXTMERGE
$to = <<tcDest>>
$user = '<<tcUser>>'
$pass = '<<tcPwd>>'

<<lcCredentials>>
$mailParam = @{
    To = $to.Split(';')
    From = '<<lcSender>>'
    Subject = '<<tcSubject>>'
    Body = '<<tcBody>>'
    SmtpServer = '<<tcServer>>'
    Port = <<tcPort>> #587 or 465
    Credential = $cred
    UseSsl = $true
    <<tcAttachment>>
	<<lcBodyAsHtml>>
}

try
{
	# Send Email
	Send-MailMessage @mailParam 
}
catch
{
	$_.Exception.Message
	# $_.Exception.Message | out-file C:\Temp\<font color="Blue">error.log && #=Comment
	Write-Output 'Message send failed.'
}
	ENDTEXT
	* End of script

SET STEP ON 

	lcReturn = RunPowerShell(m.lcPSScript)
	IF EMPTY(ALLTRIM(m.lcReturn))
		m.lcReturn = "Message Sent successfully"
	ENDIF
	RETURN m.lcReturn	
	


*************************************************************
* Run PowerShell script hidden
* by VFPImaging - Adapted from Antonio Lopez FUNCTION PS_ExecScript(tcScript)
FUNCTION RunPowerShell(tcScript)
*************************************************************
	LOCAL loWShell AS "WScript.Shell"
	LOCAL lcCmd, lcEcho, lcFile, lcSetEscape, lcText, loPS
	IF EMPTY(m.tcScript)
		RETURN .F.
	ENDIF

	m.lcFile = ADDBS(SYS(2023)) + SYS(2015) + ".ps1"
	m.lcEcho = FORCEEXT(m.lcFile, "log")

	STRTOFILE(m.tcScript, m.lcFile)
	m.lcCmd = "cmd /c powershell.exe -ExecutionPolicy RemoteSigned " + ;
		"-File " + IIF(" " $ m.lcFile, '"' + m.lcFile + '"', m.lcFile) + ;
		" > " + IIF(" "$ m.lcEcho, '"' + m.lcEcho + '"', m.lcEcho)

	m.lcSetEscape = SET("Escape")
	SET ESCAPE ON
	m.loWShell = CREATEOBJECT("WScript.Shell")

	m.lcCmd = "cmd /c powershell -ExecutionPolicy RemoteSigned " + ;
		"-File " + IIF(" " $ m.lcFile, '"' + m.lcFile + '"', m.lcFile) + ;
		" > " + IIF(" "$ m.lcEcho, '"' + m.lcEcho + '"', m.lcEcho)
	m.loPS = m.loWShell.RUN(m.lcCmd, .F., .T.)

	DOEVENTS
	SET ESCAPE &lcSetEscape.

	TRY
		m.lcText = FILETOSTR(m.lcEcho)
	CATCH
		m.lcText = ""
	ENDTRY
	ERASE (m.lcFile)

	TRY
		ERASE (m.lcEcho)
	CATCH
	ENDTRY

	RETURN m.lcText
ENDFUNC