mirror of
https://github.com/ptarmiganlabs/butler-sos.git
synced 2025-12-19 17:58:18 -05:00
273 lines
9.8 KiB
PowerShell
273 lines
9.8 KiB
PowerShell
# Send-Email-Modern.ps1
|
|
# Modern PowerShell (7+) version with enhanced Gmail support and better security
|
|
# Reusable PowerShell script for sending formatted emails
|
|
# Used by various GitHub Actions workflows
|
|
|
|
#Requires -Version 7.0
|
|
|
|
param(
|
|
[Parameter(Mandatory = $true)]
|
|
[string]$SmtpServer,
|
|
|
|
[Parameter(Mandatory = $true)]
|
|
[int]$SmtpPort,
|
|
|
|
[Parameter(Mandatory = $true)]
|
|
[string]$From,
|
|
|
|
[Parameter(Mandatory = $true)]
|
|
[string]$To,
|
|
|
|
[Parameter(Mandatory = $true)]
|
|
[string]$Subject,
|
|
|
|
[Parameter(Mandatory = $true)]
|
|
[string]$Body,
|
|
|
|
[Parameter(Mandatory = $false)]
|
|
[string]$Username,
|
|
|
|
[Parameter(Mandatory = $false)]
|
|
[SecureString]$Password,
|
|
|
|
[Parameter(Mandatory = $false)]
|
|
[PSCredential]$Credential,
|
|
|
|
[Parameter(Mandatory = $false)]
|
|
[switch]$UseSSL,
|
|
|
|
[Parameter(Mandatory = $false)]
|
|
[switch]$IsBodyHtml,
|
|
|
|
[Parameter(Mandatory = $false)]
|
|
[ValidateSet("Normal", "High", "Low")]
|
|
[string]$Priority = "Normal",
|
|
|
|
[Parameter(Mandatory = $false)]
|
|
[int]$TimeoutSeconds = 30
|
|
)
|
|
|
|
Write-Host "=== Send-Email-Modern.ps1 Starting ==="
|
|
Write-Host "PowerShell Version: $($PSVersionTable.PSVersion)"
|
|
Write-Host "SMTP Server: $SmtpServer"
|
|
Write-Host "SMTP Port: $SmtpPort"
|
|
Write-Host "From: $From"
|
|
Write-Host "To: $To"
|
|
Write-Host "Subject: $Subject"
|
|
Write-Host "Body Length: $($Body.Length)"
|
|
Write-Host "Has Username: $([bool]$Username)"
|
|
Write-Host "Has Password: $([bool]$Password)"
|
|
Write-Host "Has Credential: $([bool]$Credential)"
|
|
Write-Host "Use SSL: $UseSSL"
|
|
Write-Host "Is Body HTML: $IsBodyHtml"
|
|
Write-Host "Priority: $Priority"
|
|
Write-Host "Timeout: $TimeoutSeconds seconds"
|
|
|
|
# Modern PowerShell function using Send-MailMessage with enhanced error handling
|
|
function Send-EmailModern {
|
|
param(
|
|
[hashtable]$EmailParams
|
|
)
|
|
|
|
try {
|
|
# Use the modern Send-MailMessage cmdlet if available
|
|
if (Get-Command Send-MailMessage -ErrorAction SilentlyContinue) {
|
|
Write-Host "Using Send-MailMessage cmdlet (modern method)"
|
|
|
|
$sendParams = @{
|
|
SmtpServer = $EmailParams.SmtpServer
|
|
Port = $EmailParams.Port
|
|
From = $EmailParams.From
|
|
To = $EmailParams.To
|
|
Subject = $EmailParams.Subject
|
|
Body = $EmailParams.Body
|
|
BodyAsHtml = $EmailParams.IsBodyHtml
|
|
Priority = $EmailParams.Priority
|
|
UseSsl = $EmailParams.UseSSL
|
|
}
|
|
|
|
if ($EmailParams.Credential) {
|
|
$sendParams.Credential = $EmailParams.Credential
|
|
}
|
|
|
|
Send-MailMessage @sendParams
|
|
return $true
|
|
}
|
|
}
|
|
catch {
|
|
Write-Host "Send-MailMessage failed, falling back to .NET method: $($_.Exception.Message)" -ForegroundColor Yellow
|
|
return $false
|
|
}
|
|
|
|
return $false
|
|
}
|
|
|
|
try {
|
|
Write-Host "Preparing to send email (Modern PowerShell)..."
|
|
Write-Host "PowerShell Version: $($PSVersionTable.PSVersion)"
|
|
Write-Host "SMTP Server: $SmtpServer"
|
|
Write-Host "SMTP Port: $SmtpPort"
|
|
Write-Host "From: $From"
|
|
Write-Host "To: $To"
|
|
Write-Host "Subject: $Subject"
|
|
Write-Host "Use SSL: $($UseSSL.IsPresent)"
|
|
Write-Host "HTML Body: $($IsBodyHtml.IsPresent)"
|
|
Write-Host "Priority: $Priority"
|
|
Write-Host "Timeout: $TimeoutSeconds seconds"
|
|
|
|
# Gmail-specific configuration and validation
|
|
if ($SmtpServer -like "*gmail*" -or $SmtpServer -eq "smtp.gmail.com") {
|
|
Write-Host "Gmail SMTP detected - applying Gmail-specific settings" -ForegroundColor Green
|
|
|
|
# Validate Gmail settings
|
|
if ($SmtpPort -ne 587 -and $SmtpPort -ne 465) {
|
|
Write-Host "Warning: Gmail typically uses port 587 (TLS) or 465 (SSL). Current port: $SmtpPort" -ForegroundColor Yellow
|
|
Write-Host "Recommended: Use port 587 with UseSSL for Gmail" -ForegroundColor Yellow
|
|
}
|
|
|
|
if (-not $UseSSL.IsPresent) {
|
|
Write-Host "Gmail requires SSL/TLS. Enabling SSL automatically." -ForegroundColor Yellow
|
|
$UseSSL = $true
|
|
}
|
|
|
|
# Gmail authentication guidance
|
|
if (-not $Username -and -not $Credential) {
|
|
throw "Gmail requires authentication. Provide either Username/Password or Credential parameter."
|
|
}
|
|
|
|
Write-Host "Gmail setup reminders:" -ForegroundColor Cyan
|
|
Write-Host "- Use an App Password (not your regular Gmail password)" -ForegroundColor Cyan
|
|
Write-Host "- Enable 2-factor authentication" -ForegroundColor Cyan
|
|
Write-Host "- Generate App Password: https://myaccount.google.com/apppasswords" -ForegroundColor Cyan
|
|
}
|
|
|
|
# Prepare credential object
|
|
$emailCredential = $null
|
|
if ($Credential) {
|
|
Write-Host "Using provided PSCredential object"
|
|
$emailCredential = $Credential
|
|
}
|
|
elseif ($Username -and $Password) {
|
|
Write-Host "Creating credential from Username/Password"
|
|
$emailCredential = New-Object System.Management.Automation.PSCredential($Username, $Password)
|
|
}
|
|
|
|
# Prepare parameters for email sending
|
|
$emailParams = @{
|
|
SmtpServer = $SmtpServer
|
|
Port = $SmtpPort
|
|
From = $From
|
|
To = $To
|
|
Subject = $Subject
|
|
Body = $Body
|
|
IsBodyHtml = $IsBodyHtml.IsPresent
|
|
Priority = $Priority
|
|
UseSSL = $UseSSL.IsPresent -or $UseSSL
|
|
Credential = $emailCredential
|
|
TimeoutSeconds = $TimeoutSeconds
|
|
}
|
|
|
|
# Try modern method first
|
|
$modernSuccess = Send-EmailModern -EmailParams $emailParams
|
|
|
|
if (-not $modernSuccess) {
|
|
Write-Host "Falling back to .NET System.Net.Mail method"
|
|
|
|
# Create mail message
|
|
$mailMessage = New-Object System.Net.Mail.MailMessage
|
|
$mailMessage.From = $From
|
|
$mailMessage.To.Add($To)
|
|
$mailMessage.Subject = $Subject
|
|
$mailMessage.Body = $Body
|
|
$mailMessage.IsBodyHtml = $IsBodyHtml.IsPresent
|
|
|
|
# Set UTF-8 encoding for proper character support
|
|
$mailMessage.BodyEncoding = [System.Text.Encoding]::UTF8
|
|
$mailMessage.SubjectEncoding = [System.Text.Encoding]::UTF8
|
|
|
|
# Set priority
|
|
$mailMessage.Priority = switch ($Priority.ToLower()) {
|
|
"high" { [System.Net.Mail.MailPriority]::High }
|
|
"low" { [System.Net.Mail.MailPriority]::Low }
|
|
default { [System.Net.Mail.MailPriority]::Normal }
|
|
}
|
|
|
|
# Create SMTP client with modern settings
|
|
$smtpClient = New-Object System.Net.Mail.SmtpClient($SmtpServer, $SmtpPort)
|
|
$smtpClient.EnableSsl = $emailParams.UseSSL
|
|
$smtpClient.Timeout = $TimeoutSeconds * 1000 # Convert to milliseconds
|
|
|
|
# Gmail-specific settings
|
|
if ($SmtpServer -like "*gmail*" -or $SmtpServer -eq "smtp.gmail.com") {
|
|
$smtpClient.DeliveryMethod = [System.Net.Mail.SmtpDeliveryMethod]::Network
|
|
}
|
|
|
|
# Set credentials
|
|
if ($emailCredential) {
|
|
Write-Host "Using authentication with username: $($emailCredential.UserName)"
|
|
$smtpClient.Credentials = $emailCredential.GetNetworkCredential()
|
|
}
|
|
else {
|
|
Write-Host "No credentials provided - using anonymous authentication"
|
|
}
|
|
|
|
# Send the email
|
|
Write-Host "Sending email via .NET method..."
|
|
$smtpClient.Send($mailMessage)
|
|
|
|
# Clean up
|
|
$mailMessage.Dispose()
|
|
$smtpClient.Dispose()
|
|
}
|
|
|
|
Write-Host "✅ Email sent successfully!" -ForegroundColor Green
|
|
return $true
|
|
|
|
}
|
|
catch [System.Net.Mail.SmtpException] {
|
|
Write-Host "❌ SMTP Error: $($_.Exception.Message)" -ForegroundColor Red
|
|
Write-Host "SMTP Status Code: $($_.Exception.StatusCode)" -ForegroundColor Red
|
|
|
|
# Enhanced Gmail error handling
|
|
if ($SmtpServer -like "*gmail*" -or $SmtpServer -eq "smtp.gmail.com") {
|
|
Write-Host "" -ForegroundColor Red
|
|
Write-Host "📧 Gmail Troubleshooting Guide:" -ForegroundColor Yellow
|
|
Write-Host "1. Verify you're using an App Password (not regular password)" -ForegroundColor Yellow
|
|
Write-Host "2. Enable 2-factor authentication: https://myaccount.google.com/security" -ForegroundColor Yellow
|
|
Write-Host "3. Generate App Password: https://myaccount.google.com/apppasswords" -ForegroundColor Yellow
|
|
Write-Host "4. Use these settings: smtp.gmail.com, port 587, SSL enabled" -ForegroundColor Yellow
|
|
Write-Host "5. Check Gmail account security: https://myaccount.google.com/lesssecureapps" -ForegroundColor Yellow
|
|
|
|
switch -Wildcard ($_.Exception.Message) {
|
|
"*authentication*" { Write-Host "🔐 Authentication issue - check App Password" -ForegroundColor Red }
|
|
"*credential*" { Write-Host "🔐 Credential issue - verify username/password" -ForegroundColor Red }
|
|
"*SSL*" { Write-Host "🔒 SSL/TLS issue - ensure UseSSL is enabled" -ForegroundColor Red }
|
|
"*timeout*" { Write-Host "⏱️ Timeout issue - check network connectivity" -ForegroundColor Red }
|
|
"*5.7.14*" { Write-Host "🚫 Gmail blocked sign-in - check security settings" -ForegroundColor Red }
|
|
}
|
|
}
|
|
|
|
return $false
|
|
|
|
}
|
|
catch {
|
|
Write-Host "❌ Unexpected error: $($_.Exception.Message)" -ForegroundColor Red
|
|
Write-Host "Exception Type: $($_.Exception.GetType().FullName)" -ForegroundColor Red
|
|
|
|
if ($_.Exception.StackTrace) {
|
|
Write-Host "Stack trace:" -ForegroundColor Red
|
|
Write-Host $_.Exception.StackTrace -ForegroundColor Red
|
|
}
|
|
|
|
return $false
|
|
|
|
}
|
|
finally {
|
|
# Ensure cleanup
|
|
if ($mailMessage) {
|
|
try { $mailMessage.Dispose() } catch { }
|
|
}
|
|
if ($smtpClient) {
|
|
try { $smtpClient.Dispose() } catch { }
|
|
}
|
|
} |