functions/Send-MForgeMail.ps1
|
function Send-MForgeMail { <# .SYNOPSIS Sends mass emails based on input data (pipeline or Excel file) and a mail template. .DESCRIPTION Send-MForgeMail processes input data provided either via the InputData parameter (including pipeline input) or from an Excel file. For each data row, an email is sent using a template. Recipients and subject can be provided from a specified column in the input data or as a fixed parameter. Data rows can be filtered using a filter scriptblock, and the number of emails sent can be limited (e.g., for testing). All columns of the input data row are available as placeholders in the template and can be used with the Unicode character þ (ALT+0254), e.g. þNameþ. The template can be specified by name (registered beforehand) or as a file. Additional settings like CC/BCC, subject, etc. are optional. .PARAMETER Credential Optional credential for SMTP authentication. Default values can be set with Initialize-MForgeMailDefault. .PARAMETER SMTPServer SMTP server address. Default values can be set with Initialize-MForgeMailDefault. .PARAMETER Port SMTP port. Default values can be set with Initialize-MForgeMailDefault. .PARAMETER From Sender address. Default values can be set with Initialize-MForgeMailDefault. .PARAMETER RecipientList List of recipient addresses. Default values can be set with Initialize-MForgeMailDefault. Overrides attribute mapping. .PARAMETER CCList List of CC addresses. Default values can be set with Initialize-MForgeMailDefault. .PARAMETER BCCList List of BCC addresses. Default values can be set with Initialize-MForgeMailDefault. .PARAMETER UseSecureConnectionIfAvailable Uses a secure connection if available. Default values can be set with Initialize-MForgeMailDefault. .PARAMETER Subject Subject of the email. Can be provided from a column in the Excel file or as a fixed value. .PARAMETER TemplateName Name of the template to use. Must be registered beforehand with Register-MForgeTemplate. .PARAMETER TemplateFile Path to the template file (.html or .md). .PARAMETER DataFile Excel file containing recipient data. .PARAMETER Filter Scriptblock for filtering data rows. Default: all rows. .PARAMETER WorksheetName Name of the Excel worksheet. .PARAMETER ParameterMapping Hashtable mapping parameter names to attribute names, e.g. @{Subject='Subject';RecipientList='MailTo'}. .PARAMETER Limit Maximum number of emails to send (e.g., for testing). .EXAMPLE Send-MForgeMail -TemplateName "Newsletter" -DataFile "data.xlsx" -WorksheetName "Recipients" -ParameterMapping @{RecipientList='Email'} Sends emails based on the "Newsletter" template to all recipients in the "Email" column. .EXAMPLE Send-MForgeMail -TemplateFile "template.html" -DataFile "data.xlsx" -WorksheetName "Sheet1" -ParameterMapping @{RecipientList='Email';Subject='Subject'} -Limit 10 -Filter { $_.Status -eq 'Active' } Sends up to 10 emails to all active recipients, with subject and recipient taken from the respective columns in the Excel file. All columns are available as placeholders in the template. .NOTES If -WhatIf is specified, the mail information (recipient, subject, content) will be displayed on the console, but no mails will be sent. #> [CmdletBinding(SupportsShouldProcess = $true, ConfirmImpact = 'High')] param ( # Optional parameters from Initialize-MForgeMail [pscredential]$Credential, [string]$SMTPServer, [int]$Port, $From, # MailboxAddress $RecipientList, # InternetAddressList $CCList, # InternetAddressList $BCCList, # InternetAddressList [boolean]$UseSecureConnectionIfAvailable, [string]$Subject, # Template selection [string]$TemplateName, [PSFFile]$TemplateFile, # Data input from Excel [Parameter(ParameterSetName = 'dataFromExcel', Mandatory = $true)] [PsfFile]$DataFile, [Parameter(ParameterSetName = 'dataFromExcel', Mandatory = $true)] [string]$WorksheetName, # Data input from pipeline [Parameter(ParameterSetName = 'dataFromPipeline', ValueFromPipeline = $true)] [object[]]$InputData, # Common parameters [scriptblock]$Filter = { $true }, [hashtable]$ParameterMapping, [int]$Limit = 0 ) begin { $singleMailParams = $PSBoundParameters | ConvertTo-PSFHashtable -ReferenceCommand "Send-MForgeSingleMail" -Exclude TemplateFile | Remove-MForgeValuesFromHashtable Write-PSFMessage "Single Mail Params: $($singleMailParams|ConvertTo-Json -Compress)" if ($PSBoundParameters.ContainsKey('TemplateFile')) { $templateName = Register-MForgeTemplate -TemplateFile $TemplateFile -Temporary $singleMailParams.TemplateName = $templateName } if (-not $TemplateName){ Stop-PSFFunction -Level Warning -Message "TemplateName is required either via -TemplateName or -TemplateFile" -EnableException $true } $rawData = @() if ($PSBoundParameters.ContainsKey('DataFile') -and $PSBoundParameters.ContainsKey('WorksheetName')) { $rawData = Import-Excel -Path $DataFile -WorksheetName $WorksheetName } # By default, map standard parameter names to attribute names # This mapping is used to provide the named parameters from the data attributes # ParameterMapping: Key=Value means ParameterName=AttributeName in the data. # Data can be provided either via InputData (including pipeline) or from an Excel file. $ParameterMappingTable = @{ From = 'From' RecipientList = 'RecipientList' CCList = 'CCList' BCCList = 'BCCList' Subject = 'Subject' } # The user-provided mapping overrides the default mapping if ($ParameterMapping) { foreach ($key in $ParameterMapping.Keys) { $ParameterMappingTable.$key = $ParameterMapping.$key } } # The following Property array is later used by Select-PSFObject to select and rename the attributes of the provided $InputData # and provide them as parameters to Send-MForgeSingleMail $possibleParameterKeys = $singleMailParams.Keys + $ParameterMappingTable.keys | Select-Object -Unique # $psfSelectParam = $ParameterMappingTable.Keys | ForEach-Object { $psfSelectParam = $possibleParameterKeys | ForEach-Object { if ($singleMailParams.ContainsKey($_)) { "`$$_ as $_" } else { "$($ParameterMappingTable.$_) as $_" } } $psfSelectParam += '$_ as templateParameters' Write-PSFMessage "Parameter Mapping resulting Select-PSFObject parameters: $($psfSelectParam | Join-String -Separator ', ')" Write-PSFMessage "`$ConfirmPreference=$($ConfirmPreference)" if ($WhatIfPreference) { # WhatIf was specified, do nothing here } $rawDataSelectParam = @{ Property = $psfSelectParam } if ($Limit -gt 0) { $rawDataSelectParam.First = $Limit } } process { $rawData += $InputData } end { $TemplateData = [array]($rawData | Where-Object $Filter | Select-PSFObject @rawDataSelectParam | ConvertTo-PSFHashtable | Remove-MForgeValuesFromHashtable) $uniqueRecipients = ($TemplateData | Select-Object -ExpandProperty RecipientList -ErrorAction SilentlyContinue -Unique | Measure-Object).count $ConfirmMessage = "Sending $($TemplateData.Count) mails to $($uniqueRecipients.Count) recipients" Write-PSFMessage "Data imported, $(($templateData|Measure-Object).Count) entries after filtering original $($rawData.Count)" Save-ContextCache -Name "murks" -CurrentVariables (Get-Variable -Scope local) if ([string]::IsNullOrEmpty($TemplateData)) { Stop-PSFFunction -Level Warning -Message "No data found" -EnableException $true } # TODO: Eine Überprüfung auf notwendige Parameter einbauen # Check if Subject is provided from parameter and contains the Placeholder delimiter if ($PSBoundParameters.ContainsKey('Subject') -and $Subject -like "*þ*") { $subjectTemplateName = Register-MForgeTemplate -TemplateString $Subject -TemplateType 'TXT' -Temporary } $TemplateData | ForEach-Object { if ($_.Subject -match 'þ') { Write-PSFMessage "Generating subject from template $subjectTemplateName" $_.Subject = Invoke-MForgeTemplate -TemplateName $subjectTemplateName -TemplateParameters $_.templateParameters } } Invoke-PSFProtectedCommand -Action $ConfirmMessage -ScriptBlock { foreach ($mailParam in $TemplateData) { Write-PSFMessage "Sending mail to $($mailParam.RecipientList) with subject '$($mailParam.Subject)'" -FunctionName Send-MForgeMail Write-PSFMessage "Mail Parameters: $($mailParam | ConvertTo-Json -Compress)" -FunctionName Send-MForgeMail Send-MForgeSingleMail @mailParam -WhatIf:$WhatIfPreference } } -WhatIf:$false -Confirm:$ConfirmPreference if ($PSBoundParameters.ContainsKey('TemplateFile')) { Write-PSFMessage "Removing temporary template $templateName" Remove-PSMDTemplate -TemplateName $TemplateName -Confirm:$false -ErrorAction SilentlyContinue } if ($subjectTemplateName) { Write-PSFMessage "Removing temporary subject template $subjectTemplateName" Remove-PSMDTemplate -TemplateName $subjectTemplateName -Confirm:$false -ErrorAction SilentlyContinue } } } |