2022-09-18

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 link to his presentation on YouTube. By the way, the next release of VirtualFoxFest will be soon, on October 13, 19 and 25 2022.

So, first 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


Before you go:

HOW TO RUN POWERSHELL SCRIPT FILE ON WINDOWS 10

On Windows 10, to run a script file with the PowerShell console, you have to change the execution policy.

To change the execution policy to run PowerShell scripts on Windows 10, use these steps:

  • Open Start.
  • Search for PowerShell, right-click the top result, and select the Run as administrator option.
  • Type the following command to allow scripts to run and press Enter: Set-ExecutionPolicy RemoteSigned
  • Type A and press Enter (if applicable).




Save the script below as SENDPSEMAIL.PRG


* FILE  : SENDPSEMAIL.PRG
* AUTHOR: VFPIMAGING http://vfpimaging.blogspot.com 2022-09-08
* Send e-mails using PowerShell 

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 "<html>" $ 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

	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



Adapt the codes below according to your SMTP server and run!


CLEAR 

* Here is our HTML body
TEXT TO lcHTML NOSHOW
<!DOCTYPE html>
<html><body><font size="3" face="Verdana">
<h1>CONGRATULATIONS!</h1>
<br/><br/><br/>
<p>You successfully managed to send an e-mail using PowerShell and VFP</p>
<br/><br/><br/>
<table><tbody><tr>
<td><img height="65" src="http://www.files.foxypreviewer.com/Logo1.png" width="65" /></td>
<td><table><tbody style="font-family: "Calibri">
<tr><td>CESAR<br/><a href="https://www.FoxyPreviewer.com">FoxyPreviewer</a></td></tr>
<tr><td>+55-44.98765.4321<br/>
<img height="16" src="http://www.files.foxypreviewer.com/Mail.bmp" width="16" />  <a href="mailto:vfpimaging@hotmail.com">vfpimaging@hotmail.com</a></td></tr></tbody></table>
</td></tr></tbody></table>
</body></html>

ENDTEXT 


lcReturn = SendPSEmail("yourdestination@hotmail.com", ;
		"PowerShell E-mail " + TRANSFORM(DATETIME()), ;
		lcHTML, ; && Message body (plain text or HTML)
		GETFILE(), ; && attachment (comma separated)
		"smtp.office365.com", ; && SMTP Server
		"VfpImaging <vfpimaging@hotmail.com>", ; && User
		"yourpassword", ; && pwd
		587) && SMTP port 25, 465, 587
? lcReturn

RETURN 



Running the script above, if you omit the password it will ask you for the credentials:




Below is the video session from Doug Hennig

 


Related links:

POP, IMAP, and SMTP settings for Outlook.com

Send-MailMessage

How to pass credentials to the Send-MailMessage command for sending emails

Powershell tutorials

Send-MailMessage: Sending Emails from PowerShell

How to Send an Email Using Windows PowerShell



No comments:

Post a Comment