Link to home
Create AccountLog in
Avatar of Kent Dyer
Kent DyerFlag for United States of America

asked on

Powershell - send to multiple recipients

I have been playing with PowerShell's Send-MailMessage and seems to work fine with one person to send to..  I have previously used Blat.exe with VBScript and it works fine.  I even tried to convert the Blat Script over to PowerShell..

I have also seen this, but does not seem to work either..
http://powershell.com/cs/blogs/tips/archive/2012/04/23/sending-email-to-multiple-recipients.aspx

I have read that you need to setup multiple recipients in the following manner:
$To = ("recipient1@company.com","recipient2@company.com")

If I convert the blat Script..
function blat-Mail
{
	param(
		[Parameter(Mandatory = $true)]
		[String[]]
		$To,
		[Parameter(Mandatory = $true)]
		$Subject, 
		[Parameter(Mandatory = $true)]
		$Body, 
		[Parameter(Mandatory = $true)]
		$Attachment, 
		$From = "CustomerCare@somecompany.com",
		$SmtpServer="RELAY.COMPANY.COM"
		)
			
	try {
		$strCommand = """D:\WORK\Scripts\Blat.exe"
		$strCommand = $strCommand + " -log $MailResult"
		$strCommand = $strCommand + " -f ""$from"""
		$strCommand = $strCommand + " -to ""$To"""
		$strCommand = $strCommand + " -server ""$smtpserver"""
		$strCommand = $strCommand + " -subject ""$subject"""
		$strCommand = $strCommand + " -body ""$body"""
		$strCommand = $strCommand + " -attach ""$Attachment"""
		$strCommand = $strCommand + " -q"""

 & $strCommand
##write-host $strCommand
		Write-Host "Email successfully sent." -ForegroundColor Green
	}
	catch {
		Write-Host "Email did not go through: $_" -ForegroundColor Red
	}
	}

$FullDate = Get-Date -format "yyyyMMdd000000"
$applog = "D:\WORK\Scripts\p1\AppLog\"
$mailresult = "$applog"+$FullDate+"_MailResult.txt"

blat-Mail "recipient1@company.com" "Daily Reports" "Attached are reports.  If there are any issues or concerns please contact your Customer Service Representative immediately." "D:\WORK\Scripts\p1\ReportDownload\Temp\20130713_foo.zip"

Open in new window


Results are (have tried to pass individual parameters and the whole thing as one parameter):
D:\WORK\ps\Reports\kt.ps1
Email did not go through: The term '"D:\WORK\Scripts\Blat.exe -log D:\WORK\Scripts\p1\AppLog\20130715000000_MailResult.txt -f "Cust
omerCare@somecompany.com" -to "recipient@fcompany.com" -server "RELAY.company.COM" -subject "Daily Reports" -body "Attached are
 reports.  If there are any issues or concerns please contact your Customer Service Representative immediately." -attach "D:\W
ORK\Scripts\p1\ReportDownload\Temp\20130713_foo.zip" -q"' is not recognized as the name of a cmdlet, function, script fil
e, or operable program. Check the spelling of the name, or if a path was included, verify that the path is correct and try again.

Multiple recipients using Send-MailMessage:

I am reading in a "mapping" (settings) file as well.

Mapping Construct is:

COMPANY1,recipient1@somecompany.com;recipient2@somecompany.com
COMPANY2,recipient1@anothercompany.com;recipient2@anothercompany.com;recipient3@anothercompany.com;recipient4@anothercompany.com
COMPANY3,recipien1@yetanothercompany.com

And here is the code..
#7 Email the resulting Zip files to companies
## to do: work on event log
$ScriptDir = Split-Path $MyInvocation.MyCommand.Path
#$applog = "$ScriptDir\AppLog\"
$applog = "D:\WORK\Scripts\p1\AppLog\"
#$bkup = "$ScriptDir\ReportDownload\BkUp\"
$bkup = "D:\WORK\Scripts\p1\ReportDownload\BkUp\"
#$temp = "$ScriptDir\ReportDownload\Temp\"
$temp = "D:\WORK\Scripts\p1\ReportDownload\Temp\"
#$Settings = "$ScriptDir\Settings.Txt"
$Settings = "D:\WORK\Scripts\Settings.Txt"

#READ IN SETTINGS FROM TEXT FILE
$setting = Get-Content $Settings -encoding String
foreach ( $set in $setting )
{
If ($set.split("=")[0] -eq "AdminRecipient")
{
$AdminRecipient = $set.split("=")[1]
}
If ($set.split("=")[0] -eq "smtpserver")
{
$smtpserver = $set.split("=")[1]
}
}

$FullDate = Get-Date -format "yyyyMMdd000000"

$Mapping = "D:\WORK\Scripts\p1\Mapping.Txt"
##$Mapping = "D:\WORK\Scripts\p1\Testing.Txt"
$mailresult = "$applog"+$FullDate+"_MailResult.txt"

# $sw = [Diagnostics.Stopwatch]::StartNew()
% { $i = 1 }
$DateLogged = Get-Date -format u
"Run Start: $DateLogged" | Out-File -append -filepath $MailResult -encoding ASCII
#NEED TO CHECK FOR THE EXISTENCE OF THE Mapping file
If (Test-Path $Mapping) {
$results=''
$count = @(Get-Content $Mapping).Length
$lists = Get-Content $Mapping -encoding String
"Number of COMPANIES: " + $count | Out-File -append -filepath $MailResult -encoding ASCII
foreach ($list in $lists)
{
	$CompanyName = $list.split(",")[0]
	$Email = $list.split(",")[1]
    	#IF  THERE ARE MORE THAN ONE $EMAIL IN THE RECIPIENT LIST AND CONTAIS A ; IT NEEDS TO BE REPLACED
	$files = Get-ChildItem -Path $temp
	# verify if the list of source files is empty
	foreach ($file in $files)
	##if ($file -ne $null)
	{
	   $filename = $file.name
	   $fullname = $file.FullName
	   #Need to check to be sure that the file has not been previously sent
	   $ORGName = $filename.Substring(0, $filename.length-4)
	   $ORGName = $ORGName.Substring(9, $ORGName.length-9)
	   $result = Test-Path $BkUp$ORGName\$filename
	   if (!(Test-Path $BkUp$ORGName\$filename))
	   {
	   $count = $file.count
	   $e = $filename.contains($CompanyName)
	   if ($CompanyName -eq $ORGName)
	   ##if ($e -eq $true)
	   {
        If ($Email.contains(";"))
        {
            $Email=$Email -replace(';',""", """)
        }
        
        #ForEach ($y in $Email) {
	#if($results -ne '') { $results += "','" }
	#$tmpy = $y
	#$results += $tmpy
	#}
	$Email=$Email -replace '([^_]*).*','"$1'
	$Email=($Email)

	##$Email=$Email -replace (';',"','")

	Write-host ($Email)
	$DateLogged = Get-Date -format u
	Send-MailMessage -To ($Email) -From "CustomerCare@company.com" -subject "Daily Reports for $ORGName" -Body "Attached are Daily reports.  If there are any issues or concerns please contact your Customer Service Representative immediately." -Attachment $fullname -smtpServer "$smtpserver"
	#####"$i ,On: "+Get-Date+" ,e-mail was sent for: $ORGName ,To: $EMail ,Attachment: $fullname" | Out-File -append -filepath $MailResult -encoding ASCII
	"$i,On: $DateLogged,e-mail was sent for: $ORGName,To: $EMail,Attachment: $fullname" | Out-File -append -filepath $MailResult -encoding ASCII
	$i++
        }
	}
    }
	}
#$sw.Stop()
##$sw.Elapsed
"" | Out-File -append -filepath $MailResult -encoding ASCII
#"time taken: " + $sw.Elapsed | Out-File -append -filepath $MailResult -encoding ASCII
"Number of Companies: " + $count | Out-File -append -filepath $MailResult -encoding ASCII

#Measure-Command { Get-Process }
#$timetaken = Measure-Command { Get-Process }

#http://social.technet.microsoft.com/Forums/windowsserver/en-US/e172f039-ce88-4c9f-b19a-0dd6dc568fa0/writing-to-different-event-logs-and-sources-registered-to-a-single-event-log
$src = [System.Diagnostics.EventLog]::SourceExists("Daily_reports")
#IF THE EVENTLOG DOES NOT EXIST, WE NEED TO CREATE IT
	if (!$src)
	{
		New-EventLog -source "Daily_Reports" -logname "Application" > $null
	}
	write-eventlog -logname "Application" -source "Daily_Reports" -eventID 3001 -entrytype "Information" -message "Daily Reports have been sent and process is complete." -category 1 -rawdata 10,20
}

Open in new window


Here are the results..
PS C:\Documents and Settings\kent> D:\WORK\ps\Reports\7-b.ps1
"recipient1@anothercompany.com", "recipient2@anothercompany.com", "recipient3@anothercompany.com", "recipient4@anothercompany.com"
Send-MailMessage : The specified string is not in the form required for an e-mail address.
At D:\WORK\ps\Reports\7-b.ps1:160 char:25
+            Send-MailMessage <<<<  -To ($Email) -From "CustomerCare@company.com" -subject "Daily Reports for $ORGName" -Body
 "Attached are Daily reports.  If there are any issues or concerns please contact your Customer Service Representative immediately
." -Attachment $fullname -smtpServer "$smtpserver"
    + CategoryInfo          : InvalidType: (:) [Send-MailMessage], FormatException
    + FullyQualifiedErrorId : FormatException,Microsoft.PowerShell.Commands.SendMailMessage
 
Send-MailMessage : A recipient must be specified.
At D:\WORK\ps\Reports\7-b.ps1:160 char:25
+            Send-MailMessage <<<<  -To ($Email) -From "CustomerCare@company.com" -subject "Daily Reports for $ORGName" -Body
 "Attached are Daily reports.  If there are any issues or concerns please contact your Customer Service Representative immediately
." -Attachment $fullname -smtpServer "$smtpserver"
    + CategoryInfo          : InvalidOperation: (System.Net.Mail.SmtpClient:SmtpClient) [Send-MailMessage], InvalidOperationExceptio
   n
    + FullyQualifiedErrorId : InvalidOperationException,Microsoft.PowerShell.Commands.SendMailMessage

Thanks,

Kent
ASKER CERTIFIED SOLUTION
Avatar of David Carr
David Carr
Flag of United States of America image

Link to home
membership
Create a free account to see this answer
Signing up is free and takes 30 seconds. No credit card required.
See answer
No clue what all the code does, but it looks much too complicated. For sending to multiple targets, you'll need an array of strings.
Line 45 & 46:
	$CompanyName, $EMail = $list.split(',')

Open in new window

Lines 66-79:
        $EMail = @($EMail -replace  '([^_]*).*','"$1' -split ";"

Open in new window

and all you need is provide $EMail to the -To parameter as already done by you (you can remove the surrounding parens - they have no use, but do not harm).
Avatar of Kent Dyer

ASKER

Something still is not right with these results.

It still cannot parse out and use multiple e-mails no matter what I do.

I have reverted back to VBScript for the time being.

Thanks,

Kent
Is this code a translation from VBS?
Do you get an error, or only one receipient, or what?
Have you tried using my method?
The code I placed above, is not a direct translation of the VBS method I am using today.  The reasons are many and varied, but the one thing that I want to get away from is the requirement of having to code-sign the scripts when used in our production servers.  This can be argued in the positive sense you don't have rampant code running that cannot be explained like a Melissa..  The close second reason is that IMHO, PowerShell is much more powerful than VBS.  The multiple e-mail send - or rather send to multiple recipients is something we are doing today and does not work at all right in PowerShell.  I will be the first to admit, it is probably something that I am doing the reading of the text mapping file in comparison to the working folder/file structure to e-mail our customers daily.

Here is the method that I am using on a daily basis to send something on the order of 500 messages a daily using VBS and Blat..

Const ForReading = 1, ForWriting = 2, ForAppending = 8

Set fso = CreateObject("Scripting.FileSystemObject")
Set WshNetwork = CreateObject("Wscript.Network")
Set objWS = CreateObject("WScript.Shell")

strMachineName = WshNetwork.ComputerName 
ScriptDir = Replace(WScript.ScriptFullName, WScript.ScriptName, "")

MappingFile = ScriptDir & "Mapping.Txt"
ReportFileFolder = ScriptDir & "ReportDownload\" ' -- Base Download for latest.zip, temp folder under here is used for processing

YYYY = Year(Date)
MM = Right(100 + Month(Date), 2)
DD = Right(100 + Day(Date), 2)
HH = Right(100 + Hour(Date), 2)
MN = Right(100 + Minute(Date), 2)
SS = Right(100 + Second(Date), 2)
DTSTR = YYYY & MM & DD & HH & MN & SS

'(8) Read the Mapping.txt
	Set f1 = fso.OpenTextFile(MappingFile, ForReading, True)
	Do Until f1.AtEndOfStream
		line = f1.ReadLine
		If Len(line) > 0 Then
			'CompanyName = Mid(Split(line, ",") (0), 13, Len(Split(line, ",") (0))) ' -- Company Name
			SomeCompanyName = Split(line, ",") (0) ' -- Company Name
			Set objFolder = fso.GetFolder(ReportFileFolder & "Temp")
			Set colFiles = objFolder.Files
			For Each objFile In colFiles
				FLPath = objFile.Path
				FLName = objFile.Name
				FITest = Mid(FLName, InStr(FLName, "_") + 1, InStr(FLName, ".zip") - InStr(FLName, "_") - 1)
				If Instr(FLName,CompanyName)>0 Then
					EMail = Split(line, ",") (1)
					If InStr(EMail, ";") Then
						EMail = Replace(EMail, ";", ",")
					End If
					Dest = BkupFolder & CompanyName & "\" & FLName
					If Not fso.fileexists(Dest) Then
						If fso.fileexists(FLPath) Then
							Mailer EMail, Chr(34) & FLPath & Chr(34), CompanyName
							'WScript.sleep 300
						End If
					End If
				End If
			Next
		End If
	Loop
	f1.Close
	Set f1 = Nothing

Sub Mailer(recipient, Attachment, Nm)
	Dim WshShell, server, from, subject, body, strCommand, oExec
	Set objWS = CreateObject("WScript.Shell")
	If Attachment <> "" Then
		If InStr(strMachineName, "ABC") Or InStr(strMachineName, "DEF") Or InStr(strMachineName, "GHI") Then
			server = "1.2.3.4"
		End If
		If InStr(strMachineName, "JKL") Then
			server = "5.6.7.8" '
		End If
		from = "CustomerCare@company.com"
		subject = "Daily Reports for: " & Nm
		body = "Attached are Daily reports.  If there are any issues or concerns please contact your Customer Service Representative immediately."
		strCommand = "%comspec% /c " & ScriptDir & "Blat.exe "
		strCommand = strCommand & " -log " & Chr(34) & ScriptDir & "AppLog\" & DTSTR & "_MailResult.txt" & Chr(34) & ""
		strCommand = strCommand & " -f " & Chr(34) & from & Chr(34) & ""
		strCommand = strCommand & " -to " & Chr(34) & recipient & Chr(34) & ""
		strCommand = strCommand & " -server " & Chr(34) & server & Chr(34) & ""
		strCommand = strCommand & " -subject " & Chr(34) & subject & Chr(34) & ""
		strCommand = strCommand & " -body " & Chr(34) & body & Chr(34) & ""
		strCommand = strCommand & " -attach " & Attachment & ""
		strCommand = strCommand & " -q"
		intReturn = objWS.Run(strCommand, 0, True)
		While Not intReturn = 0
			WScript.Sleep 10
		Wend
		Set objWS = Nothing
	End If
End Sub

Open in new window


Thanks,

Kent
And what is the effect if you use the code?
Do you get an error, or only one receipient, or what?
Do you get an error, or only one receipient, or what?

See the following error:
"recipient@company.com", "recpient@gmail.com"
Send-MailMessage : The specified string is not in the form required for an e-mail address.
At D:\WORK\ps\Reports\7.ps1:122 char:25
+            Send-MailMessage <<<<  -To ($Email) -From "CustomerCare@company.com" -subject "Daily Reports for $ORGName" -Body
 "Attached are Daily Reports.  If there are any issues or concerns please contact your Customer Service Representative immediately
." -Attachment $fullname -smtpServer "$smtpserver"
    + CategoryInfo          : InvalidType: (:) [Send-MailMessage], FormatException
    + FullyQualifiedErrorId : FormatException,Microsoft.PowerShell.Commands.SendMailMessage
 
Send-MailMessage : A recipient must be specified.
At D:\WORK\ps\Reports\7.ps1:122 char:25
+            Send-MailMessage <<<<  -To ($Email) -From "CustomerCare@company.com" -subject "Daily Reports for $ORGName" -Body
 "Attached are Daily Reports.  If there are any issues or concerns please contact your Customer Service Representative immediately
." -Attachment $fullname -smtpServer "$smtpserver"
    + CategoryInfo          : InvalidOperation: (System.Net.Mail.SmtpClient:SmtpClient) [Send-MailMessage], InvalidOperationExceptio
   n
    + FullyQualifiedErrorId : InvalidOperationException,Microsoft.PowerShell.Commands.SendMailMessage

code is..
        If ($Email.contains(";"))
        {
            $Email=$Email -replace(';',""", """)
        }
$Email=$Email -replace '([^_]*).*','"$1'
$Email=($Email)
Write-host ($Email)
	       $DateLogged = Get-Date -format u
	       Send-MailMessage -To ($Email) -From "CustomerCare@company.com" -subject "Daily Reports for $ORGName" -Body "Attached are Daily reports.  If there are any issues or concerns please contact your Customer Service Representative immediately." -Attachment $fullname -smtpServer "$smtpserver"

Open in new window

       
Thanks,

Kent
This is partially correct..

You posted:
$msg.To.Add(”recipient1@yourdomain.com, recipient2@yourdomain.com,”)

It actually needs to be:
$msg.To.Add(”recipient1@yourdomain.com, recipient2@yourdomain.com")