Sachin Tayade
Sachin Tayade

Reputation: 3

Using Microsoft Graph API to send mail from Windows PowerShell - getting 400 : Bad request

hope you are doing good.

I'm trying to use Graph API - Mail module, to send mail Windows PowerShell(not wanted to use SMTP). But I'm stuck, getting Error 400 - Bad Request Error for the following script.

Able to fetch the access token, getting error at Invoke-RestMethod.

API permission is given, - Mail.Send, Mail.ReadWrite (Delegated). Using Administrator Account - Azure Running Script from Local Windows PowerShell.

Glad of any help, Thank you.

Import-Module Microsoft.Graph.Users.Actions
Import-Module Microsoft.Graph.Mail

# Define variables
$tenantId = "tenant_id"
$clientId = "client_id/app_id"
$clientSecret = "client_value"
$senderEmail = "{object_id/user_mail_id}"  # Verified UPN of the user sending the email
$recipientEmail = "recipient_mail"
$subject = "Mail sent using MS Graph API"
$bodyContent = "Hi there, successfully sent mail using Graph API"

# Get an access token
$body = @{
    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 -ContentType "application/x-www-form-urlencoded" -Body $body

$accessToken = $tokenResponse.access_token

# Print the access token
Write-Output "Access Token: $accessToken"

# Create the email message
$emailMessage = @{
    message = @{
        body            = @{
            content     = $bodyContent
            contentType = 'Text'
        }
        subject         = $subject
        toRecipients    = @(
            @{
                emailAddress = @{
                    address = 'recipient_mail_id'
                }
            }
        )
        hasAttachments  = $false
        importance      = 'Normal'
        saveToSentItems = 'true'
    }
}

# Convert the email message to JSON
$emailMessageJson = $emailMessage | ConvertTo-Json

# Print the email message JSON
Write-Output "Email Message JSON: $emailMessageJson"

# Send the email using the /users/{user-id}/sendMail endpoint
$response = Invoke-RestMethod -Uri "https://graph.microsoft.com/v1.0/users/{ObjectID/user_mail_id}/sendMail" -Method Post -Headers @{Authorization = "Bearer $accessToken"; "Content-Type" = "application/json"} -Body $emailMessageJson

# Output the response
$response

I wanted to remove the 400 - Bad Request Error, to make script more secure, as credentials are given in script.

Upvotes: 0

Views: 224

Answers (2)

Sachin Tayade
Sachin Tayade

Reputation: 3

Hi @SantiagoSquarzon and All,

Above code works, the problem was with Subscriptions(for me at least).

We require to have a Subscription(Azure or Office 365) in which Office 365 Exchange Online should be active and working(unfortunately, its was not enabled for me). After enabling, the above code was working fine, I was getting response 202, and mail is not being delivered as it was considered as Spam.

Let me know if there is any other solution working.

Thank you.

Upvotes: 0

Santiago Squarzon
Santiago Squarzon

Reputation: 60873

This is likely to be caused by a typo in the Body of the request. I don't see other issues with your code that could cause a 400 response from the API.

If you look at the body used in Example 1: Send a new email using JSON format from the docs, the saveToSentItems key-value pair is outside message not inside. Moreover, saveToSentItems is not a property listed in message resource type properties.

{
  "message": {
    "subject": "Meet for lunch?",
    "body": {
      "contentType": "Text",
      "content": "The new cafeteria is open."
    },
    "toRecipients": [
      {
        "emailAddress": {
          "address": "[email protected]"
        }
      }
    ],
    "ccRecipients": [
      {
        "emailAddress": {
          "address": "[email protected]"
        }
      }
    ]
  },
  "saveToSentItems": "false"
}

Whereas you have it inside message, so solution might be:

$emailMessage = @{
    message = @{
        body            = @{
            content     = $bodyContent
            contentType = 'Text'
        }
        subject         = $subject
        toRecipients    = @(
            @{
                emailAddress = @{
                    address = 'recipient_mail_id'
                }
            }
        )
        hasAttachments  = $false
        importance      = 'Normal'
    }
    saveToSentItems = 'true' # <-- Moving this outside the `message` kv pair
}

Also, as noted in comments, you will need -Depth 4 or more in your ConvertTo-Json to properly convert this object and not get it truncated.

Upvotes: 0

Related Questions