I really like event-driven notifications that can trigger different webhooks and it’s really fun putting them together like pieces of lego to automate workflows.
The most common and simple notification method is via email, but there are scenarios where environments for security reasons and by design have just access to the internet on port 80/443 and this connection is often mediated via a web proxy.
Not having access to SMTP protocol can be a roadblock but, in this article, we will implement a solution to send an email with PowerShell under these limitations without changing Firewall Rules or NSG.
How can we send an email without SMTP (or IMAP)?
SMTP protocol requires TCP port 25 or 587 (with TLS encryption) as the default port for mail submission if those ports are closed my obvious choice is using a web service that will require an API Key as authentication and authorization via web request on HTTPS (using port 443).
In this example, I used Twilio SendGrid (This is not a sponsored article). It’s very popular and the free tier for this application is probably enough for most testing applications or scenarios.
Once you’ve signed up and created your profile you can click on Settings, API KEYS (https://app.sendgrid.com/
My Personal TIP: Remember that API KEYs are free, generate one for each of your apps, so it can be considered as a unique identifier so if it gets compromised it’s possible to identify it and to delete it without causing any interruption for other apps using/sharing the same service or account.
Once created, you’ve got everything you need to start using this script.
Send-MailWithSendGrid
I’ve created a PowerShell function that is a wrapper for Invoke-RestMethod and posts the JSON containing the email message the API Key that SendGrid is expecting to receive.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 |
#Paolo Frigo, https://www.scriptinglibrary.com <# .Synopsis This function sends an email using SendGrid APIs .DESCRIPTION This function sends an email using SendGrid REST API. .EXAMPLE Send-EMailWithSendGrid -from "[email protected]" -to "[email protected]" -ApiKey "MY_SENDGRID_API_KEY" -Body "Test 1..2..3!" -Subject "Sendgrid Test" .NOTES Author Paolo Frigo, https://www.scriptinglibrary.com #> function Send-EmailWithSendGrid { Param ( [Parameter(Mandatory=$true)] [string] $From, [Parameter(Mandatory=$true)] [String] $To, [Parameter(Mandatory=$true)] [string] $ApiKey, [Parameter(Mandatory=$true)] [string] $Subject, [Parameter(Mandatory=$true)] [string] $Body ) $headers = @{} $headers.Add("Authorization","Bearer $apiKey") $headers.Add("Content-Type", "application/json") $jsonRequest = [ordered]@{ personalizations= @(@{to = @(@{email = "$To"}) subject = "$SubJect" }) from = @{email = "$From"} content = @( @{ type = "text/plain" value = "$Body" } )} | ConvertTo-Json -Depth 10 Invoke-RestMethod -Uri "https://api.sendgrid.com/v3/mail/send" -Method Post -Headers $headers -Body $jsonRequest } # $From = "[email protected]" # $To = "[email protected]" # $APIKEY = "MY_API_KEY" # $Subject = "TEST" # $Body ="SENDGRID 123" # Send-EmailWithSendGrid -from $from -to $to -ApiKey $APIKEY -Body $Body -Subject $Subject |
To use this function you can simply import with dot sourcing
1 |
. ./Send-EmailWithSendGrid.ps1 |
Replace these variables with your test values
1 2 3 4 5 |
$APIKEY = "MY_API_KEY" $Subject = "TEST" $Body ="SENDGRID 123" |
And finally, run this one-liner
1 |
Send-EmailWithSendGrid -from $from -to $to -ApiKey $APIKEY -Body $Body -Subject $Subject |
Take advantage of Splatting
Oliver in one of the comments below has pointed out the use of parameter splatting. Indeed, if you have a long list of parameters to pass to a cmd-let or a function in genera is to pack all your variables into a hast table and pass that object to the function.
1 2 3 4 5 6 7 8 9 |
$MailParams = @{ APIKEY = "MY_API_KEY" Subject = "TEST" Body = "SENDGRID 123" } Send-EmailWithSendGrid @MailParams |
There are multiple benefits of splatting, it will not just make your code more readable, but all parameters will be stored into a single object ( hash table), that will be easy to manipulate, count or iterate if needed.
If you require a proxy
As I’ve mentioned this function is a wrapper of Invoke-RestMethod so it’s simple to check the documentation and for instance adding the proxy address to the Invoke-RestMethod cmd-let.
Wrap-Up
I still think that email communication can be still used effectively today and the choice of having other valid alternatives, for instance, Teams/Slack , can help us to make the right decision when it is okay to use it or simply avoid abusing it.
When we decide that the email is the right solution even when SMTP protocol is not available we can replace the cmd-let of Send-MailMessage with this Send-EmailWithSendGrid using the SendGrid RESTAPI.
As usual, you can find this script on my GitHub Repository.
Hello Paolo,
can I suggest the use of splatting to pass the parameters to your function
i.e.
$MailParams = @{
From = “[email protected]”
To = “[email protected]”
APIKEY = “MY_API_KEY”
Subject = “TEST”
Body =”SENDGRID 123″
}
Send-EmailWithSendGrid @MailParams
The commandline is shoter, and more readable and easily customizable.
Regards
Olivier
Hi Oliver,
Thanks for your comment, yes splatting can make the line for the cmd-let shorter, as much as I like hash tables and I wanted to make the code even simpler.
I will edit this post and include your comment, I didn’t think to include splatting in this, but, in general, you’re right and it’s a nice option to have all parameters into a single hash table object if you want for instance iterate or manipulate it.