My previous blogpost described how you can use Logic Apps to send emails from a PowerShell script.
While this is a great tool, I want to show you an alternative method that might be more suitable if you have to handle a large volume of email. In this post, I will show you how to send email from PowerShell with SendGrid.
Update 26/07/2020
Below you can still find the function, but I have now extended the functionality and added it to the PowerShell gallery. This new function includes the option to send attachments. Read more about it in my new blogpost.
But why?
As I explained in my previous post, there has been some discussion on the usage of Send-MailMessage. While Send-MailMessage is functional, it is not guaranteed to be secure if you don’t add your own security measures (like -UseSSL). But more so, the system that is behind cmdlet is no longer maintained, so the system is no longer supported.
So a Logic App could provide a nice alternative. There is a challenge with that method though and that is that it doesn’t scale that well. For example an Office 365 account is limited to 30 emails per minute (Thank you Ludwig for the heads up!). If your needs exceed these limits, it’s a good idea to try SendGrid. The other reason this might be a good way to go, is when you are using an email provider that is not available as a connector for a Logic App.
What is SendGrid
SendGrid is a tool that is often used for marketing emails and newsletters. Along some other services it provides an API and SMTP service that you can use to make sending emails pretty straightforward.
You don’t authenticate against the account you use as the From-address. This means you don’t have to store those credentials. Unfortunately this also means that if you don’t prepare your environment, your email will be marked as unsafe, end up in the spam folder or be rejected (depending on the DMARC settings of the receiving party). And it should, because you are not authorized to use that address.
You do need to create an account with SendGrid, so you are not completely anonymous. But you should have control of the SPF records of the domain you are sending from and use Domain Authentication to make sure your email is not marked as spam.
What should you choose
So if you are wondering which method you should choose, I think the scale of your mailing needs and control of your email domain are the most important factors. If you have to send a lot of emails, or want a lot of variation in the from-address that is used, SendGrid might be a better fit.
To use SendGrid though you do need to be able to change the SPF record for the sending domain. So for services like Outlook.com or Gmail, this will be an issue.
If possible, I would personally prefer a logic app. The reason for this is that I think an SPF record should be as clean as possible. If you have the option to not add an external domain to a SPF record, I would take that option.
Here are a few pointers for both methods that you might want to consider when making your choice.
Logic Apps
- Authenticates directly with a sender account
- Limited to the send limit for personal accounts
- Only works with email services that are available as a connector
- Does not work with Exchange server (on-premises)
SendGrid
- Uses a SendGrid Account, no authentication against the sender Address
- Needs SPF changes and Domain Authentication
- If you have no control over SPF, your email will likely be marked as spam or rejected
I encourage you to try out both options and consider your options with that.
SendGrid
So we are going to use the Sendgrid API for our email. You are able to set up Sendgrid on its own, but for this post we are going to get the service through the Azure portal.
Set it up
To set up SendGrid through Azure, follow the steps in this Microsoft Doc. They are pretty clear. You can use the free tier to send up to 25.000 emails per day at the time of writing. Follow this guide to create an account.
Follow the steps until you get an API key.
Use it in PowerShell
To create an email through the API, we first need to create a Body object. This object contains every property about the email. The Object is honestly a big mess of arrays and hash tables. I have tried to break it up, but in my opinion this did not increase readability.
You can of course use variables for all the different settings. More on that later.
When the object is created, we turn it into a JSON.
We will use this body to give to the API. First we create the header with the token we got from SendGrid. After that, we will call the API
Result
So here is the result, an email send from PowerShell with SendGrid.
As you can see, this email mentions that it is send through Sendgrid and that it is not trusted.
To make sure your mail is secure and not considered spam, see the following guides about changing your SPF record and setting up domain authentication.
https://sendgrid.com/docs/glossary/spf/
https://sendgrid.com/docs/ui/account-and-settings/how-to-set-up-domain-authentication/
Put it in a function
Update 26/07/2020
Below you can still find the function, but I have now extended the functionality and added it to the PowerShell gallery. This new function includes the option to send attachments. Read more about it in my new blogpost.
So as I mentioned, the body-object is messy and variables aren’t used at all now. To make it all a little easier, I have put the SendGrid call in a PowerShell Function that tries to mimic Send-MailMessage. This function is very basic, but it does give you something to build on.
Call it by using the following syntax:
$MailParameters = @{ ToAddress = "exa@mp.le" ToName = "Receiving party" FromAddress = "ex@amp.le" FromName = "Sending party" Subject = " example " Body = "Plain Text body (user type text/html for a HTML output)" Token = $Token } Send-SendGridMail @Parameters
Pingback:ICYMI: PowerShell Week of 24-January-2020 | PowerShell.org
Following your article is the closest I’ve got to getting this to work in that I can actually get an email through now, however everywhere I’ve looked never seems to address the adding of an attachment to the email, is this an difficult thing to do with SendGrid?
Hi Gary,
I have not used SendGrid to send attachments myself, but it should be possible according to the documentation.
You would probably add something like this to the PowerShell object
attachments: @(
@{
content: attachmentinBase64,
filename: "example.pdf",
type: "application/pdf",
disposition: "attachment"
}
)
}
Disclaimer: haven’t tried this myself yet.
To create a base64 version of your attachment, you can use PowerShell as well. In this blog are some pointers.
Hope this helps you, let me know if you have more questions!
could you add the attachment functionality, please???
thanks for this!
Hi Spizzy,
I do not have plans to add it to this blog post at this point. Did the code in my comment not work for you?
Hello! thank you for the wonderful post, but I’m not sure where that code goes and how to invoke it?
Can you provide some additional context?
Hi! The code can be used in whatever context your use case is. It could be on a local server, a local computer, Azure Runbooks, Azure Function apps. So a lot of options available. You can invoke it interactively or scheduled. So there is a lot of flexibility with this code.
If you have a question about a specific use case let me know.
Hi Barbara,
Great article on sending email from powershell with sendgrid. I understand there are very few documentation , or none I’d say regarding Sendgrid in powershell. I was wondering if it was possible to manage sendgrid contact list through powershell. Thanks,
Keep up the good work.
Hi Jasmin,
Thank you!
It should be possible to manage that according to their API documentation, by calling the API through PowerShell (which is what is done in the blog post as well).
You can find the documentation on managing contacts here: https://sendgrid.com/docs/API_Reference/Web_API_v3/Marketing_Campaigns/contactdb.html
Hi Barbara,
Great Article! SendGrid’s documentation part on the implementation is not so well. Did you get a chance to try with the attachment ? I am stuck at this, any help would be appreciated.
Hi Manish,
I am working on the attachment part now, I hope to have some answers in the following two weeks :). If I do I will add to this blog post or create a new one.
Hi all,
A new blog post that covers attachments has been released, you can find it here: https://4bes.nl/2020/07/26/pssendgrid-send-email-from-powershell-with-sendgrid/
Hi
I followed this and at the end im getting error as connot able convert to system.string as i have created html using ConvertTo-Html
How can i pass that data ”
$htmlBody = $PreContent + $obj | ConvertTo-Html -Property name,tests, failures, errors -Head $Header -PreContent $PreContent”
i have system.object[] in $obj
Hi Jai,
I am a bit confused on how you are using the cmdlets, would you mind posting an anonymous version of your script?
Hi ,
All works absolutely fine for me nice and easy explanation, but i need to drop emails to multiple users how would i can do it, i tried array of emails but it is going as plain string of all emails to sendgrid like email1@firsts.comemail2@firsts.com and hence it is bounced in the sendgrid
Hi Jairam,
I have created a new blogpost about PowerShell and Sendgrid. I have added an example of how to use PowerShell as a method to send to multiple users. Find it here: https://4bes.nl/2020/07/26/pssendgrid-send-email-from-powershell-with-sendgrid/
Can you tell me how can I send multiple recipients? Should I rewrite code or existing will work?
Hi Ganesh,
I worte a part two for this post. I have written in a PowerShell Module for SendGrid and I mention in the post how you can send to multiple recipients with PowerShell logic. You can find it here: https://4bes.nl/2020/07/26/pssendgrid-send-email-from-powershell-with-sendgrid/
Pingback:[SOLVED] Send-MailMessage : Unable to read data from the transport connection: net_io_connectionclosed – BugsFixing