I need to send HTML emails via Microsoft Graph API in Powershell, but I also need to have a table in the email body that is created from a CSV file. I'm able to send an HTML email, but no matter how I try to create the table I get a Invoke-RestMethod : The remote server returned an error: (400) Bad Request.
I need to be able to generate a new table via a for-each as there are several versions of this table with different data in them.
I have tried:
- Joining the body of the email with a variable holding the table in HTML form.
- Creating a text file with the body of the email in it (including the table)and grabbing the body content via Get-Content.
- Creating the table in the script before the variable containing the mail body is called.
Each of these have resulted in the same 400 error. Has anyone had success with this?
My actual script does have all the necessary variables filled in. I've removed the tenant ID etc, etc in this post.
Write-Host "`r`nEnter the name of the file you want to" -NoNewLine; Write-Host " import" -ForegroundColor Yellow -NoNewline; Write-Host " without the file extension:"
Write-Host ""
$InputFileName = Read-Host
Write-Host ""
$Script:Users = import-csv "C:\temp\$InputFileName.csv"
$Script:Users | Sort-Object -Property Manager,Name | Group-Object -Property Manager | ForEach-Object {
$Managername = $_.name
$HTMLBody = "
<!DOCTYPE html>
<html>
<head>
<style>
Table {
border-collapse: collapse;
border: 1px solid black;
}
TH{
border: 1px solid black;
background-color dddddd;
padding: 5px;
}
TD{
border: 1px solid black;
padding: 5px;
}
BODY{
font-family: Calibri;
Font-size: 11pt;
}
</style>
</head>
<p>List of users that have access to PSI:</p>
'<p>Above you will find a list that details your staff members who have access to PSI. The access review is to confirm that access is appropriate for each individual.
<b><h3>The key below describes what actions users can take in the given system.</b></h3>
$($_.group | ConvertTo-Html -Fragment)
</p>
</html>
"
}
$clientID = ""
$Clientsecret = ""
$tenantID = ""
$FromAddress = ""
$MailSubject = "Test Email - Graph API"
$ToAddress = ""
$bodycontent4 = "$HTMLBody"
#Connect to GRAPH API
$tokenBody = @{
Grant_Type = "client_credentials"
Scope = "https://graph.microsoft.com/.default"
Client_Id = $clientId
Client_Secret = $clientSecret
}
$tokenResponse = Invoke-RestMethod -Uri "https://login.microsoftonline.com/$tenantID/oauth2/v2.0/token" -Method POST -Body $tokenBody
$headers = @{
"Authorization" = "Bearer $($tokenResponse.access_token)"
"Content-type" = "application/json"
}
#Send Mail
$URLsend = "https://graph.microsoft.com/v1.0/users/$FromAddress/sendMail"
$Body =
@"
{
"message": {
"subject": "$mailSubject",
"body": {
"contentType": "HTML",
"content": "$bodyContent4"
},
"toRecipients": [
{
"emailAddress": {
"address":, "$ToAddress"
}
}
]
},
"saveToSentItems": "false"
}
"@
Invoke-RestMethod -Headers $headers -Uri $URLsend -Body $Body -Method POST
CodePudding user response:
If you were able to send the e-mail is most of it done.
For converting PSObjects in html tables you can use the ConvertTo-Html cmdlet.
If you use the ConvertTo-Html as is, it will generate the output as if it is a new HTML document.
If you need to insert this table on a already existing HTML, use the -Fragment switch parameter.
Something like this:
$object = Import-Csv -Path 'C:\Path\To\Your\File.csv'
Body = @"
<!DOCTYPE html>
<html>
<head>
<style>
table, th, td {
border-collapse: collapse;
text-align: left;
padding-right: 15px;
}
tr:nth-child(odd) {
background-color: #D6EEEE;
}
th {
background-color: #8fbfbf;
}
tr:last-child {
background-color: #8fbfbf;
font-weight: bold;
}
p {
margin: 0;
font-size: 1.5em;
}
</style>
</head>
Your usual HTML stuff.
The table:
$($object | ConvertTo-Html -Fragment)
</html>
"@
CodePudding user response:
My issue ended up being that there was some small issue with the formatting of my body content (the $body = @"). As far as getting the table into the email, I had to Get-content to pull in a text document with HTML formatting in it and then convert it into HTML.
$importbodycontent = Get-Content "C:\Temp\$bodydocument.txt" -raw
$importbodycontent | ConvertTo-Html | Out-Null
After that I used a text replacement to replace certain text with the contents of the HTML table that I created.
$groupcontents = $_.group | ConvertTo-Html -Fragment
$Currentbodycontent = $importbodycontent.replace('TABLEGOESHERE', $groupcontents)
$bodycontent3 = "$Currentbodycontent"
Then I was able to use that content in the body of the email, and get it to send properly.
$Body =
@"
{
"message": {
"subject": "$mailsubject",
"body": {
"contentType": "HTML",
"content": "$bodycontent3"
},
"toRecipients": [
{
"emailAddress": {
"address": "$toaddress"
}
}
]
},
}
"@
Invoke-RestMethod -Headers $headers -Uri $URLsend -Body $Body -Method POST