Jump to content
Lars Fosdal

How-to: Post a message to Teams using WebHooks

Recommended Posts

Nice.

I've been using the following to post the status of our Bamboo build jobs (it's a PowerShell script) but I've been thinking about adding Teams notification to some of our automated test tools and your example will come in handy there.

$uri = 'https://outlook.office.com/webhook/yadayadayada/IncomingWebhook/yadayadayada/yadayadayada-yada-yada-yada-yadayadayada'

if("${bamboo_buildFailed}" -eq "true"){
  $status = 'Failure'
}else {
  $status = 'Success'
}

$body = ConvertTo-Json -Depth 4 @{
    title = 'FooBar Build Notification'
    text = "Build of FooBar version ${bamboo.fileVersion} completed with status $status"
    sections = @(
        @{
            activityTitle = 'FooBar Build'
            activitySubtitle = '${bamboo.buildKey}'
            activityText = 'The build of ${bamboo.planRepository.branchName} ${bamboo.planRepository.revision} completed.'
            activityImage = 'https://pbs.twimg.com/profile_images/1128664840233525248/T3YNFtIt_400x400.png'
        },
        @{
            title = 'Details'
            facts = @(
                @{
                name = 'Branch'
                value = '${bamboo.planRepository.branchName}'
                },
                @{
                name = 'Revision'
                value = '${bamboo.planRepository.revision}'
                }
            )
        }
    )
    potentialAction = @(@{
            '@context' = 'http://schema.org'
            '@type' = 'ViewAction'
            name = 'Click here for details'
            target = @('${bamboo.buildResultsUrl}')
        })
}

Invoke-RestMethod -uri $uri -Method Post -body $body -ContentType 'application/json'

image.thumb.png.779ee232e75b6bd02ef55f930e9872cc.png

Share this post


Link to post

Nice!

 

Any reason why you didn't make use of TRestClient instead of the Indy component? That would not only avoid the dependence on the OpenSSL libraries, but make it also work on other target platforms.

unit O365WebHook;

// Lars Fosdal, 2020 OCT 16
// Simple example without error handling

interface
uses
  System.Classes, System.SysUtils,
  REST.Json, REST.Client, REST.Types;

type
  TWebHookMessage = class
  end;

/// <summary> See https://docs.microsoft.com/en-us/microsoftteams/platform/webhooks-and-connectors/how-to/connectors-using
/// for examples of how to structure the json for creating advanced formats</summary>
  TSimpleText = class(TWebHookMessage)
  private
    FText: String;
  public
    property Text: String read FText write FText;
    constructor Create(const aText: string);
  end;

type
  TWebHook = class
  private
    FClient: TRESTClient;
    FRequest: TCustomRESTRequest;
    FURL: string;
  protected
    property Client: TRESTClient read FClient;
    property Request: TCustomRESTRequest read FRequest;
  public
    constructor Create(const aURL: string = '');
    destructor Destroy; override;
    function PostMessage(const aMsg: TWebhookMessage; aOwnsMsg: Boolean = False): Boolean;
    property URL: string read FURL write FURL;
  end;

implementation

{ TWebHook }

constructor TWebHook.Create(const aURL: string);
begin
  inherited Create;
  FURL := aURL;

  FClient := TRESTClient.Create(nil);
  FRequest := TCustomRESTRequest.Create(nil);
  FRequest.Client := FClient;
end;

destructor TWebHook.Destroy;
begin
  FRequest.Free;
  FClient.Free;
  inherited;
end;

function TWebHook.PostMessage(const aMsg: TWebhookMessage; aOwnsMsg: Boolean = False): Boolean;
begin
  try
    Request.Client.BaseURL := URL;
    Request.Method := rmPOST;
    Request.AddBody(aMsg);
    Request.Execute;
    Result := Request.Response.Status.Success;
  finally
    if aOwnsMsg then
      aMsg.Free;
  end;
end;

{ TSimpleText }

constructor TSimpleText.Create(const aText: string);
begin
  inherited Create;
  FText := aText;
end;

end.

 

  • Like 2

Share this post


Link to post

@Anders Melander - We use Continua CI and FinalBuilder, and Continua has Teams support built in.  
My PS scripts also posts to Teams, but I use the PSTeams module.  I still need to master how do PS Secure Vault secret keys across multiple users to avoid having the URLs in the PS script, though.


Love your example of how simple it is to do Json in PowerShell!

 

@Uwe Raabe Ignorance, I guess :classic_blush: I've never used TRESTClient and I already was using Indy for JsonRPC.
Thanks for sharing the modified version!  I added it to the article.  

 

How TLS capable is the TRESTClient?

Share this post


Link to post

Spotted one challenge with TRESTClient.  No easy way to override the flags to ObjectToJsonString.

Share this post


Link to post
2 hours ago, Lars Fosdal said:

Spotted one challenge with TRESTClient.  No easy way to override the flags to ObjectToJsonString.

Thanks to the overloads for AddBody that is not a big challenge:

{ as Json string }
    Request.AddBody(TJSON.ObjectToJsonString(aMsg, [joIgnoreEmptyStrings, joIgnoreEmptyArrays, joDateIsUTC, joDateFormatISO8601]));

{ or as TJsonObject }

    Request.AddBody(TJSON.ObjectToJsonObject(aMsg, [joIgnoreEmptyStrings, joIgnoreEmptyArrays, joDateIsUTC, joDateFormatISO8601]), ooREST);

 

  • Like 2

Share this post


Link to post
7 hours ago, Lars Fosdal said:

Continua has Teams support built in.

Yeah, well Bamboo being an Atlassian product relies on paid 3rd party add-ins for even the simplest things :classic_dry:

It does have support for XMPP but that isn't supported by Teams.

Share this post


Link to post
11 hours ago, Anders Melander said:

Yeah, well Bamboo being an Atlassian product relies on paid 3rd party add-ins for even the simplest things

Yes, this is true for all Atlassian products. We're moving away from Confluence because whilst it has support for producing documentation sites, it has no support for versioning.. unless you buy an expensive plugin - which totally takes over and makes a complete mess of things when you install on existing spaces, and and even worse mess (had to restore from backup) when uninstalling it. TBH, I fell out of love with confluence a long time ago.. we'll probably just switch to some sort of static site generator. 

 

They announced yesterday they are moving to cloud only and will retire the server/dc products over the next few years - that's just another reason to stop using their products imho.  

 

  • Like 1

Share this post


Link to post
14 hours ago, Vincent Parrett said:

TBH, I fell out of love with confluence a long time ago.. we'll probably just switch to some sort of static site generator.

I like it for internal documentation. For external use I think it sucks as you can't style it properly. If we were to replace it I would probably just use WordPress.

 

14 hours ago, Vincent Parrett said:

They announced yesterday they are moving to cloud only and will retire the server/dc products over the next few years - that's just another reason to stop using their products imho.

Oh... wow. I just read their announcement.

For Jira, Confluence and Bitbucket this won't affect us much. Our Jira and Confluence are already on cloud. But for Bamboo this definitely means that we'll have to find alternatives and Bitbucket pipelines isn't a viable alternative. I just took their migration quiz. Bamboo isn't listed at all... and for Bitbucket it recommended that I migrate to Bitbucket Data Center - which is also being EOL'd.. Classic Atlassian.

Share this post


Link to post

Lots of unhappy Atlassian customers

 

https://community.atlassian.com/t5/Atlassian-Cloud-Migration/To-all-Atlassian-server-champions-we-want-to-hear-from-you/qaq-p/1500873

 

And yes, it seems like Bamboo is just being quietly shelved, they don't mention it anywhere on their roadmaps or cloud migration pages. My guess is bitbucket piplelines is the intended migration path. 

 

I'll take this opportunity to offer a different migration option - https://www.finalbuilder.com/continua-ci - currently windows only, but we're working towards linux & mac support (agents first, server later). 

 

  • Like 1

Share this post


Link to post

@limelect I removed the other post.

 

I don't have 10.2 so I can't check if I see the same error.

Did you get this error in a bare bone test project, or in a bigger project?

 

 

Share this post


Link to post

@Lars Fosdal just copied O365WebHook.pas

and 

procedure TestExampleToATeamsChannel;
var
  Teams: TWebhook;
begin
  Teams := TWebhook.Create('https://limelect.com');
  try
    Teams.PostMessage(TSimpleText.Create('Hello from Delphi!'));
  finally
    Teams.Free;
  end;
end;

procedure TForm1.Button1Click(Sender: TObject);
begin
  TestExampleToATeamsChannel;
end;

 

Using this post

https://larsfosdal.blog/2020/10/16/post-a-message-to-teams-from-delphi-using-webhooks/

 

Maybe i suppose to add IppeerCommon which i do not have

Edited by limelect

Share this post


Link to post

Is https://limelect.com the URL you tried?

The URL you use, must be the webhook URL you have configured in your Teams channel. 

In your MS Teams team, select the desired channel, and click on Connectors from the ••• menu.
In that channel you must define an Incoming Webhook.

Share this post


Link to post

Yes but the problem is not the URL!! this just to put something.

The problem is much before that  FClient := TRESTClient.Create(nil);

Share this post


Link to post

The Delphi 10.2 implementation of TRESTClient still makes use of the IPPeerAPI. This has been removed later in 10.3.

Share this post


Link to post

@lars this is the first thing I did. GOOGLE GOOGLE GOOGLE!

To the point, I do not have the Delphi version needed.

What I have is a Professional ver.

Never needed above it.

Share this post


Link to post
2 minutes ago, limelect said:

GOOGLE GOOGLE GOOGLE!

<OT>

Have I ever noticed how silly "BING BING BING !" would sound :classic_smile:

</OT>

  • Like 1

Share this post


Link to post

Create an account or sign in to comment

You need to be a member in order to leave a comment

Create an account

Sign up for a new account in our community. It's easy!

Register a new account

Sign in

Already have an account? Sign in here.

Sign In Now

×