Azure DevOps SendMail Rest API returns 204 but doesn't send an email - azure

I am trying to use the following SendMail Azure DevOps Rest API route to send out e-mails in PowerShell:
https://learn.microsoft.com/en-us/rest/api/azure/devops/wit/send-mail/send-mail?view=azure-devops-rest-7.1#emailrecipients
This is the JSON body I am using for this request:
{
"message" : {
"body": "<p>Test Email</p>",
"to" : {
"tfIds" : ["mytfsid here"]
},
"cc" : {},
"replyTo" : {},
"inReplyTo" : "",
"subject" : "test"
},
"projectId" : "my project id here"
}
Postman shows me my request passes with 204; however, I am not receiving any e-mails. I'm at a loss. Can anyone tell me what I'm doing wrong, or why the e-mail would fail to deliver?
Thanks in advance.
What I've tried:
- Tried using the tfId of a colleague; still no e-mail received
- Tried using emailAddresses instead within the "to" block; still does not work.
- Tried using emailAddresses AND tfIds within the "to" block; still does not work.

Please make sure the notification works well, otherwise you have to troubleshoot the notification issue first. See Why am I not receiving notification emails?
If the notification works well, then please try below PowerShell script to send email for the selected work items: (works for me)
Param(
[string]$orgname = "{org-name}",
[string]$project = "{project-name}",
[string]$sendmailto = "xxx#xxx.com",
[string]$mysubject = "Test-Subject",
[string]$mailbody = "Body test",
[string]$witids = "1536,1537",
[string]$user = "",
[string]$token = "PAT"
)
# Base64-encodes the Personal Access Token (PAT) appropriately
$base64AuthInfo = [Convert]::ToBase64String([Text.Encoding]::ASCII.GetBytes(("{0}:{1}" -f $user,$token)))
#Get the tfsid
$userentitlementurl = "https://vsaex.dev.azure.com/$orgname/_apis/userentitlements?api-version=7.1-preview.1"
$response = Invoke-RestMethod -Uri $userentitlementurl -Method Get -Headers #{Authorization=("Basic {0}" -f $base64AuthInfo)}
#Filter by sendmailto
$tfsid = ($response.value| where {$_.user.mailAddress -eq $sendmailto}).id
#Create Jason body
function CreateJsonBody
{
$value = #"
{
"message": "{\"to\":{\"tfIds\":[\"$tfsid\"],\"emailAddresses\":[],\"unresolvedEntityIds\":[]},\"subject\":\"$mysubject\",\"body\":\"$mailbody\",\"cc\":{\"tfids\":[\"$tfsid\"]},\"replyTo\":{\"tfids\":[\"$tfsid\"]}}",
"ids": [
$witids
],
"fields": [
"System.Id",
"System.Title",
"System.AssignedTo",
"System.State",
"System.AreaPath",
"System.Tags",
"System.CommentCount"
],
"format": 1
}
"#
return $value
}
$json = CreateJsonBody
$baseurl = "https://dev.azure.com/$orgname/$project/_api/_wit/sendMail?api-version=7.1-preview.1"
#Send mail
Invoke-RestMethod -Uri $baseurl -Method POST -Body $json -ContentType "application/json" -Headers #{Authorization=("Basic {0}" -f $base64AuthInfo)}

Related

Azure Devops REST API SendMail

I'm trying to send mail after the successful stage on my release definition.
Following the docs
OAuth box is checked in my stage
Project Collection Service Account is added to Build Administrators and Release Administrators.
But the response from REST API is "Azure DevOps Login Page"
Here is my script:
$OrganizationName = "myorg"
$ProjectName = "myproj"
$sendmailto = "example#mail.com"
$mysubject = "Test Mail Subjcet"
$mailbody = "Mail body to test it works with azure rest api"
$PAT="MYPAT"
$Token = "$(System.AccessToken)"
$encodedCreds = [System.Convert]::ToBase64String([System.Text.Encoding]::ASCII.GetBytes(":$Token"))
$HeaderMail = #{
Authorization = "Bearer $encodedCreds"
}
##send mail
$urimail = "https://${OrganizationName}.vsrm.visualstudio.com/${ProjectName}/_apis/Release/sendmail/$($env:RELEASE_RELEASEID)?api-version=3.2-preview.1"
$requestBody =
#"
{
"senderType":1,
"to":{"tfsIds":[$sendmailto]},
"body":"${mailbody}",
"subject":"${mysubject}"
}
"#
Try {
Invoke-RestMethod -Uri $urimail -Body $requestBody -Method POST -ContentType "application/json" -Headers $HeaderMail
}
Catch {
$_.Exception
}
Tested with:
Tried with 3.2 version and 7.1
PAT Token and authorization to Basic return 400 with Bearer return 401.
Switch $(System.AccessToken) to $($env:System_AccessToken) trygin to convert to base64 and without.
What I'm missing?
Response from
ConsoleLog
It's caused by the $requestBody. The request body requires valid Azure DevOps users referenced by their tfsIds.
Below PS script works for me, if your are running it in pipeline, then please use the $(System.AccessToken) instead of $PAT.
Running locally and authenticate with PAT:
$OrganizationName = "organization"
$ProjectName = "Project"
$sendmailto = "xxx#microsoft.com"
$mysubject = "Test Mail Subjcet"
$PAT="xxx"
$encodedCreds = [System.Convert]::ToBase64String([System.Text.Encoding]::ASCII.GetBytes(":$PAT"))
$HeaderMail = #{
Authorization = "Basic $encodedCreds"
}
#Get the tfsid
$userentitlementurl = "https://vsaex.dev.azure.com/${OrganizationName}/_apis/userentitlements?api-version=7.1-preview.1"
$response = Invoke-RestMethod -Uri $userentitlementurl -Method Get -Headers $HeaderMail
#Filter by sendmailto
$tfsid = ($response.value| where {$_.user.mailAddress -eq $sendmailto}).id
Write-Host $tfsid
##send mail
$urimail = "https://vsrm.dev.azure.com/${OrganizationName}/${ProjectName}/_apis/Release/sendmail/168?api-version=7.1-preview.1"
$requestBody =
#"
{
"senderType": 1,
"to": {
"tfsIds": [
"$tfsid"
],
"emailAddresses": []
},
"subject": "$mysubject",
"sections": [
5,
0,
1,
2,
4
]
}
"#
Try {
Invoke-RestMethod -Uri $urimail -Body $requestBody -Method POST -ContentType "application/json" -Headers $HeaderMail
}
Catch {
$_.Exception
}
Running in release pipeline and authenticate with $(System.AccessToken): (Please note that, because this script is being run during the release, the summary email will show the environment as IN PROGRESS even if it is run as the last step in the Release.)
$OrganizationName = "organization"
$ProjectName = "project"
$sendmailto = "xxx#microsoft.com"
$mysubject = "Test Mail Subjcet"
$HeaderMail = #{
Authorization = "Bearer $env:SYSTEM_ACCESSTOKEN"
}
#Get the tfsid
$userentitlementurl = "https://vsaex.dev.azure.com/${OrganizationName}/_apis/userentitlements?api-version=7.1-preview.1"
$response = Invoke-RestMethod -Uri $userentitlementurl -Method Get -Headers $HeaderMail
#Filter by sendmailto
$tfsid = ($response.value| where {$_.user.mailAddress -eq $sendmailto}).id
Write-Host $tfsid
##send mail
$urimail = "$env:SYSTEM_TEAMFOUNDATIONSERVERURI$env:SYSTEM_TEAMPROJECT/_apis/Release/sendmail/$($env:RELEASE_RELEASEID)?api-version=7.1-preview.1"
$requestBody =
#"
{
"senderType": 1,
"to": {
"tfsIds": [
"$tfsid"
],
"emailAddresses": []
},
"subject": "$mysubject",
"sections": [
5,
0,
1,
2,
4
]
}
"#
Try {
Invoke-RestMethod -Uri $urimail -Body $requestBody -Method POST -ContentType "application/json" -Headers $HeaderMail
}
Catch {
$_.Exception
}

What causes "invalid query definition, dataset is invalid or not supplied" querying the Azure REST API with powershell?

I've tried multiple ways to get cost management information from the Azure REST API using Powershell. I'm copy/pasting the data for my $body variable directly from their documentation. I get this error with every example they've posted.
Below is my original attempt.
I've tried to pipe $body to convertto-json.
I've tried saving it as a .json file and then using get-content -raw to get it.
I've tried defining everything in a $params hash table and then using invoke-restmethod #params
No matter what I get the same error.
invalid query definition, dataset is invalid or not supplied
$method = "post"
$URI = "https://management.azure.com//subscriptions/12345678-1234-1234-1234-1234556789123/resourceGroups/HubRG/providers/Microsoft.CostManagement/query?api-version=2019-11-01"
$headers = #{
"authorization" = "Bearer verylongstringofcharacters"
}
$body = #"
{
"type": "ActualCost",
"dataset": {
"granularity": "Daily",
"aggregation": {
"totalcost" : {
"name": "cost",
"function": "Sum"
}
},
"grouping": [
{
"type": "Dimension",
"name": "ResourceGroup"
}
]
}
}
"#
Invoke-RestMethod -Method $method -URI $URI -Headers $headers -Body $body
I had this same issue - drove me crazy for at least an hour. It turned out that even though I was using Invoke-RestMethod, I had to explicitly set 'Content-Type' = 'application/json' in the headers of the request. Without it: 'Dataset is invalid...', with it: success.
$headers = #{
"authorization" = "Bearer verylongstringofcharacters"
"Content-Type" = "application/json"
}

Azure DevOps Rest API to create a branch from a specific branch

I'm looking for an Azure DevOps Rest API to create a new branch from an existing branch.
Azure DevOps Rest API to create a branch from a specific branch
Konteks pointed out the correct REST API.
We could use the Initial commit (Create a new branch) to create a branch, but if you want to create a branch from a specific branch, we need modify the Request Body.
POST https://dev.azure.com/fabrikam/_apis/git/repositories/{repositoryId}/pushes?api-version=5.1
First, we need use the REST API Repositories - List to get the repositoryId.
GET https://dev.azure.com/{organization}/{project}/_apis/git/repositories?api-version=4.1
Then, use the REST API Refs - List with filter=<BranchName> to get the oldObjectId for your specific branch:
GET https://dev.azure.com/{organization}/{project}/_apis/git/repositories/{repositoryId}/refs?filter=heads/master&api-version=5.1
Now, we could use the REST API Repositories - List with following request body to create a new branch from a specific branch:
{
"refUpdates": [
{
"name": "refs/heads/<DefineYourNewBranchName>",
"oldObjectId": "<oldObjectId we get from above REST API>"
}
],
"commits": [
{
"comment": "Initial commit.",
"changes": [
{
"changeType": "add",
"item": {
"path": "/readme111.md"
},
"newContent": {
"content": "My first file!",
"contentType": "rawtext"
}
}
]
}
]
}
Result from postman:
This is my test powershell scripts:
$connectionToken="<PAT Here>"
$base64AuthInfo= [System.Convert]::ToBase64String([System.Text.Encoding]::ASCII.GetBytes(":$($connectionToken)"))
$headers = #{ Authorization = "Bearer $env:SYSTEM_ACCESSTOKEN" }
$url= "https://dev.azure.com/<Organizationname>/<ProjectName>/_apis/git/repositories/<repositoryId>/pushes?api-version=5.1"
$body =#"
{
"refUpdates": [
{
"name": "refs/heads/Test228",
"oldObjectId": "a57f0c34f8ec7330bdc37e7631f7be3cc3ea3956"
}
],
"commits": [
{
"comment": "Initial commit.",
"changes": [
{
"changeType": "add",
"item": {
"path": "/readme111.md"
},
"newContent": {
"content": "My first file!",
"contentType": "rawtext"
}
}
]
}
]
}
"#
Write-Host "$url"
$response= Invoke-RestMethod -Uri $url -ContentType "application/json-patch+json" -Body $body -headers #{authorization = "Basic $base64AuthInfo"} -Method POST
Hope this helps.
I captured the requests created by the AzureDevOps web UI and found out that creating a branch from a specific branch is quite simple task for the REST api.
$repository = "repositoryName"
$newBranch = "newBranchName"
$baseBranch = "baseBranchName"
$organization = "organizationName"
$project = "projectName"
$pat = "personalAccessToken"
$base64AuthInfo = [System.Convert]::ToBase64String([System.Text.Encoding]::ASCII.GetBytes(":$pat"))
$headers = #{ Authorization = "Basic $base64AuthInfo" }
# Get ID of the base branch
$url = "https://dev.azure.com/$organization/$project/_apis/git/repositories/$repository/refs?filter=heads/$baseBranch&api-version=5.1"
$baseBranchResponse = Invoke-RestMethod -Uri $url -ContentType "application/json" -headers $headers -Method GET
# Create a new branch
$url = "https://dev.azure.com/$organization/$project/_apis/git/repositories/$repository/refs?api-version=5.1"
$body = ConvertTo-Json #(
#{
name = "refs/heads/$newBranch"
newObjectId = $baseBranchResponse.value.objectId
oldObjectId = "0000000000000000000000000000000000000000"
})
$response = Invoke-RestMethod -Uri $url -ContentType "application/json" -Body $body -headers $headers -Method POST
This worked for me:
To create/update/delete:
https://learn.microsoft.com/en-us/rest/api/azure/devops/git/refs/update%20refs?view=azure-devops-rest-5.0#create/update/delete-a-ref-by-repositoryid
To get objectId:
https://learn.microsoft.com/en-us/rest/api/azure/devops/git/refs/list?view=azure-devops-rest-5.0#refs
https://learn.microsoft.com/en-us/rest/api/azure/devops/git/pushes/create?view=azure-devops-rest-5.1#initial-commit-(create-a-new-branch)
See section "initial commit"
Sparrow plugin does what you need ( using Rest API ):
s6 --plg-run ado-git-branch-create#project=Backends,repo=Catalog,branch_from=dev,branch=feature
Please pay attention, it does not create any dummy files for that, it only references for an existing branch through it's internal object ID.
Feel free to still the code ;-)).
PS Disclosure. I am the tool author, more details could be found here - https://github.com/melezhik/Spazure

How to use "Pull Request Query"?

I want to return a pull request based on a commit. I found this > https://learn.microsoft.com/en-us/rest/api/azure/devops/git/pull%20request%20query/get?view=azure-devops-rest-5.1
This API is used to find what pull requests are related to a given commit.
I'm using the following code:
$body = #"
{
"items": [
{
"59c1c31397b266116ff6d735e5638ef5d1b598a0"
}
]
}
"#
$someLink = "https://dev.something.com/embrace/somethingSomething/_apis/git/repositories/****-bf64-47d9-8b10-53f21220d54d/pullrequestquery?api-version=5.1"
Invoke-RestMethod -Uri $someLink -Headers #{Authorization = $pat } -Body $body -Method Post -ContentType 'application/json'
When I run the release I get a:
The remote server returned an error: (400) Bad Request.
Try using the following body:
$body = #"
{
"queries": [{
"items": [
"59c1c31397b266116ff6d735e5638ef5d1b598a0"
],
"type": "commit"
}]
}
"#
This is what worked for me. Powershell doesn't seem to like arrays unless they are wrapped in #().
$body = #{
queries = #(
#{
items = #(
"59c1c31397b266116ff6d735e5638ef5d1b598a0"
)
type = "commit"
}
)
}

How to create a comment in a Pull Request without using thread

I have a script that posts a thread into a pull request:
$createThreadInPRUrl = "https://dev.azure.com/$organization/$project/_apis/git/repositories/$repositoryId/pullRequests/$pullRequestId/threads?api-version=5.0"
Invoke-RestMethod -Uri $createThreadInPRUrl -Headers #{Authorization = $pat } -Body $body -Method Post -ContentType 'application/json'
$body = #"
{
"comments": [
{
"content": "
\nLink to feature release $env:featureReleaseUrl\nOne or more Cypress tests failed.\nLink to Cypress test results $cypressResultatenUrl",
"CommentThreadStatus": "closed"
}
]
}
"#
And this works fine:
But I don't want to use threads. I want to create something like a commit update:
What API call can I use to do that?

Resources