Coder Social home page Coder Social logo

atc0005 / go-teams-notify Goto Github PK

View Code? Open in Web Editor NEW

This project forked from dasrick/go-teams-notify

69.0 4.0 13.0 934 KB

A package to send messages to a Microsoft Teams channel

License: MIT License

Go 98.58% Makefile 1.42%
go teams notify golang webhook microsoft-teams

go-teams-notify's Introduction

goteamsnotify

A package to send messages to a Microsoft Teams channel.

Latest release Go Reference License go.mod Go version Lint and Build Project Analysis

Table of contents

Project home

See our GitHub repo for the latest code, to file an issue or submit improvements for review and potential inclusion into the project.

Overview

The goteamsnotify package (aka, go-teams-notify) allows sending messages to a Microsoft Teams channel. These messages can be composed of legacy MessageCard or Adaptive Card card formats.

Simple messages can be created by specifying only a title and a text body. More complex messages may be composed of multiple sections (MessageCard) or containers (Adaptive Card), key/value pairs (aka, Facts) and externally hosted images. See the Features list for more information.

NOTE: Adaptive Card support is currently limited. The goal is to expand this support in future releases to include additional features supported by Microsoft Teams.

Features

  • Submit simple or complex messages to Microsoft Teams
    • simple messages consist of only a title and a text body (one or more strings)
    • complex messages may consist of multiple sections (MessageCard), containers (Adaptive Card) key/value pairs (aka, Facts) and externally hosted images
  • Support for Actions, allowing users to take quick actions within Microsoft Teams
  • Support for user mentions (Adaptive Card format)
  • Configurable validation of webhook URLs
    • enabled by default, attempts to match most common known webhook URL patterns
    • option to disable validation entirely
    • option to use custom validation patterns
  • Configurable validation of MessageCard type
    • default assertion that bare-minimum required fields are present
    • support for providing a custom validation function to override default validation behavior
  • Configurable validation of Adaptive Card type
    • default assertion that bare-minimum required fields are present
    • support for providing a custom validation function to override default validation behavior
  • Configurable timeouts
  • Configurable retry support

Project Status

In short:

  • The upstream project is no longer being actively developed or maintained.
  • This fork is now a standalone project, accepting contributions, bug reports and feature requests.
  • Others have also taken an interest in maintaining their own forks of the original project. See those forks for other ideas/changes that you may find useful.

For more details, see the Releases section or our Changelog.

Supported Releases

Series Example Status
v1.x.x v1.3.1 Not Supported (EOL)
v2.x.x v2.6.0 Supported
v3.x.x v3.0.0-alpha.1 TBD

The current plan is to continue extending the v2 branch with new functionality while retaining backwards compatibility. Any breakage in compatibility for the v2 series is considered a bug (please report it).

Long-term, the goal is to learn from missteps made in current releases and correct as many as possible for a future v3 series.

Changelog

See the CHANGELOG.md file for the changes associated with each release of this application. Changes that have been merged to master, but not yet an official release may also be noted in the file under the Unreleased section. A helpful link to the Git commit history since the last official release is also provided for further review.

Usage

Add this project as a dependency

See the Examples section for more details.

Webhook URLs

Expected format

Valid webhook URLs for Microsoft Teams use one of several (confirmed) FQDNs patterns:

  • outlook.office.com
  • outlook.office365.com
  • *.webhook.office.com
    • e.g., example.webhook.office.com

Using a webhook URL with any of these FQDN patterns appears to give identical results.

Here are complete, equivalent example webhook URLs from Microsoft's documentation using the FQDNs above:

All of these patterns when provided to this library should pass the default validation applied. See the example further down for the option of disabling webhook URL validation entirely.

How to create a webhook URL (Connector)

  1. Open Microsoft Teams
  2. Navigate to the channel where you wish to receive incoming messages from this application
  3. Select โ‹ฏ next to the channel name and then choose Connectors.
  4. Scroll through the list of Connectors to Incoming Webhook, and choose Add.
  5. Enter a name for the webhook, upload an image to associate with data from the webhook, and choose Create.
  6. Copy the webhook URL to the clipboard and save it. You'll need the webhook URL for sending information to Microsoft Teams.
    • NOTE: While you can create another easily enough, you should treat this webhook URL as sensitive information as anyone with this unique URL is able to send messages (without authentication) into the associated channel.
  7. Choose Done.

Credit: docs.microsoft.com, gist comment from shadabacc3934

Examples

Basic

This is an example of a simple client application which uses this library.

  • Adaptive Card
  • MessageCard

Specify proxy server

This is an example of a simple client application which uses this library to route a generated message through a specified proxy server.

  • Adaptive Card
  • MessageCard

User Mention

These examples illustrates the use of one or more user mentions. This feature is not available in the legacy MessageCard card format.

Tables

These examples illustrates the use of a Table. This feature is not available in the legacy MessageCard card format.

Set custom user agent

This example illustrates setting a custom user agent.

Add an Action

This example illustrates adding an OpenUri (MessageCard) or OpenUrl Action. When used, this action triggers opening a URL in a separate browser or application.

Disable webhook URL prefix validation

This example disables the validation webhook URLs, including the validation of known prefixes so that custom/private webhook URL endpoints can be used (e.g., testing purposes).

Enable custom patterns' validation

This example demonstrates how to enable custom validation patterns for webhook URLs.

Used by

See the Known importers lists below for a dynamically updated list of projects using either this library or the original project.

References

go-teams-notify's People

Contributors

atc0005 avatar dasrick avatar dependabot[bot] avatar nmaupu avatar odise avatar pcanilho avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar  avatar

go-teams-notify's Issues

Sync this repo against upstream, squash prototype branches, merge

I need to start the work to prepare this repo to be a complete fork.

I've tried multiple times to reach the original developer in recent months (GitHub repo, Twitter, direct email), all to no avail. It appears that if I wish to develop this code further I'll need to maintain my own fork separate from upstream.

Hopefully I'll hear back at some point and this repo can go back to being a PR-fork only, but until then I can move forward with queued changes.

Allow setting user agent, fallback to project-specific default value

Overview

Instead of submitting HTTP requests with the Go default user agent of Go-http-client/1.1, set a project-specific default value. Ideally it would reflect the specific release version of the project (e.g., v2.6.0), but for simplicity it is probably worth specifying a major version instead.

For example, perhaps use the major.minor version number to indicate when this fork first diverged from the upstream project: go-teams-notify/2.2

Additionally, add support for changing this project-specific default value from client code.

References

Microsoft Teams Webhook Connector "200 OK" status insufficient indication of success

From rveachkc/pymsteams#75:

I did use a script to verify the size constraints, and I'll detail it below if it's interesting, but I talked with the Teams team and believe I found a better way.

It seems the reason for the 200 status in cases where the message doesn't send is due to 3rd party connectors, incorrectly, handling errors by deleting the configuration.

tl;dr

The team let me know that the content of the response will be '1' when the message is sent successfully. So I propose updating the check before returning in send from if r.status_code == requests.codes.ok: to if r.status_code == requests.codes.ok and r.text == '1'

Needs further research/testing. Further notes from that GH issue:

It's seemingly the combined data size sent that effects it
Without a summary, I get an exception so I'm using a single char for that (more characters would then mean removing others from the cardsection text or title, but it's not 1-for-1 i.e. a summary of '00' won't work if a "bare text message" is sent w\ 20826 characters
With a title that was the count of characters sent, the limit is 20,811 chars
W\o a title the limit bumps up to 20,827

So 20k+ characters is enough to hit a limit, but probably worth implementing the check as noted previously instead of trying to check for a specific hard-coded message size limit.

Test failure | Object expected to be of type *url.Error, but was *errors.errorString

This test failure was surfaced from running go test ./... locally:

2020/08/24 04:26:11 RoundTripper returned a response & error; ignoring response
2020/08/24 04:26:11 RoundTripper returned a response & error; ignoring response
--- FAIL: TestTeamsClientSend (0.00s)
    send_test.go:106:
                Error Trace:    send_test.go:106
                Error:          Object expected to be of type *url.Error, but was *errors.errorString
                Test:           TestTeamsClientSend
FAIL
FAIL    github.com/atc0005/go-teams-notify/v2   0.010s
FAIL

Report: bug in TestTeamsClientSend re handling of response error

Bug report

Dave Cheney's response to a golang/go GH issue I filed:

There is a bug in your test

2020/08/27 09:18:25 RoundTripper returned a response & error; ignoring response

This is the fix

(~/devel/go-teams-notify) % git diff
diff --git a/send_test.go b/send_test.go
index 6a1d6d1..8824f67 100644
--- a/send_test.go
+++ b/send_test.go
@@ -116,6 +116,9 @@ func TestTeamsClientSend(t *testing.T) {
                client := NewTestClient(func(req *http.Request) (*http.Response, error) {
                        // Test request parameters
                        assert.Equal(t, req.URL.String(), test.reqURL)
+                       if test.resError != nil {
+                               return nil, test.resError
+                       }
                        return &http.Response{
                                StatusCode: test.resStatus,

@@ -124,7 +127,7 @@ func TestTeamsClientSend(t *testing.T) {

                                // Must be set to non-nil value or it panics
                                Header: make(http.Header),
-                       }, test.resError
+                       }, nil
                })
                c := &teamsClient{httpClient: client}

I confirmed that the RoundTripper returned a response & error; ignoring response test output is present all the way back to v1.2.0.

References

This project (and original)

Guides

Official/upstream

Make URL validation optional

I just wonder why the URL schema for is so strict and limited to outlook.office365.com and outlook.office.com? I'm currently facing a use case with an URL schema like https://<corporate-name>.webhook.office.com which prevents me from using the library. Could give me some background here? Thanks a bunch.

Add CHANGELOG

Probably best to list prior versions as stub entries: they're in the file and can be expanded later if desired.

Update go.mod to reflect this fork

Per #2, this fork will now be a standalone fork instead of a PR-only fork, so we'll need to replace most upstream references with the equivalent reference back to this fork. Updating our module file is one of those steps.

While I feel that a v2 was not needed in order to maintain compatibility with existing client codebases, I think to help prevent any potential confusion that the v2 release series should remain.

I'm not very familiar with maintaining v2+ modules, but my loose understanding is that we can still have the master branch receive changes before tagging new releases. Modern versions of Go should pull the tagged v2.x releases and older versions of Go should pull from master, which (at least for now) should work equally well.

send.go:170:1: cognitive complexity 11 of func `(teamsClient).SendWithRetry` is high (> 10) (gocognit)

GH-54 added the new SendWithRetry method to provide retry support. That first version of the method failed the complexity linting check:

send.go:170:1: cognitive complexity 11 of func `(teamsClient).SendWithRetry` is high (> 10) (gocognit)
func (c teamsClient) SendWithRetry(ctx context.Context, webhookURL string, webhookMessage MessageCard, retries int, retriesDelay int) error {
^

Goal: refactor to pass this linting check and in the process learn a different way to implement the functionality.

Merge changes from atc0005/send2teams/teams package here

Specifics:

  • package-level logging potentially useful as a troubleshooting tool
  • functionality provided by the teams.SendMessage function
    • configurable delay between retries
    • configurable number of retries

The current thinking is that we'll add another function very similar to the teams.SendMessage function which wraps the SendWithContext method.

Research: Newline rendering in Teams messages via Office 365 Connector Cards

While researching whether Markdown tables are supported via webhook requests (spoiler: it does not appear so), I stumbled across this line:

In connector cards, newlines are rendered for \n\n, but not for \n or \r.

This is particularly useful to know, as I ended up going this route to work around the discovered behavior:

I don't recall off the top of my head where I learned that <br> was a good replacement, but it served the use case. Now it sounds like the ConvertEOLToBreak() function can be deprecated and one put in its place to substitute \n\n instead.


Create standalone functions for API methods

As suggested by @nmaupu on GH-93:

I see a possible improvement though: it would be a great idea to have a singleton that one can use directly (other libraries do that as well, see viper for example: https://github.com/spf13/viper/blob/master/viper.go#L63)
So no need to even create a NewClient() if your usage is the default one ๐Ÿ‘ Calls could look like the following:

import teams github.com/atc0005/go-teams-notify
[...]
func main() {
  _ := teams.SendWithContext(context.TODO(), webhook, msg)
}

I agree with the reasoning. Having this available would make getting started with the library even easier.

Extend GoDoc coverage

From GH-24:

messagecard.go:1:1: ST1000: at least one file in a package should have a package comment (stylecheck)

Fix:

Add go.doc project-level file to add an intro/summary for the project.

Add examples folder, migrate examples from README, build examples via CI

While updating an example for #112, I noticed that I had failed to include a needed import. While reviewing the other examples, I noticed that package main was not specified in any of the prior examples.

The goal is to move all examples out of the README and add them to CI so that they're built whenever code changes in this repo. Additionally, we can point to the examples from the README.

Misc linting issues surfaced from CI run

From the most recent CI run:

send_test.go:96:38: Using the variable on range scope `test` in function literal (scopelint)
                        assert.Equal(t, req.URL.String(), test.reqURL)
                                                          ^
send_test.go:98:17: Using the variable on range scope `test` in function literal (scopelint)
                                StatusCode: test.resStatus,
                                            ^
send_test.go:101:7: Using the variable on range scope `test` in function literal (scopelint)
                        }, test.resError
                           ^
send_test.go:162:27: unnecessary conversion (unconvert)
                Transport: RoundTripFunc(fn),
                                        ^
send_test.go:145: unnecessary trailing newline (whitespace)

        }
send_test.go:123: unnecessary leading newline (whitespace)
                if err != nil {

messagecard.go:1:1: ST1000: at least one file in a package should have a package comment (stylecheck)

Allow overriding default `http.Client`

The NewClient() function is currently used to create an opaque API "client". This client is used to send MessageCard values to Microsoft Teams.

Current support for overriding the internal http.Client is minimal. While the vast majority of use cases are handled with the default client, many consumers of this library could benefit by supplying their own customized http.Client values.

Tests fail to assert that any errors which occur are expected, only the types

GH-23 and GH-25 dealt with some unexpected test failures as a result of introducing error wrapping in a validation function. At the time, assert.IsType() was used like so:

for _, test := range tests {
client := NewTestClient(func(req *http.Request) (*http.Response, error) {
// Test request parameters
assert.Equal(t, req.URL.String(), test.reqURL)
return &http.Response{
StatusCode: test.resStatus,
// Must be set to non-nil value or it panics
Header: make(http.Header),
}, test.resError
})
c := &teamsClient{httpClient: client}
err := c.Send(test.reqURL, test.reqMsg)
assert.IsType(t, test.error, err)
}

Commit b021f21 replaced assert.IsType() use with errors.As in an attempt to properly handle the new wrapped error. This approach seems to have worked, but as part of the work I realized that aside from checking error types, no assertion was applied to ensure that any errors which occurred were actually expected.

Update Makefile

Replace with a modified copy that I'm using with my other projects.

Updating an exiting webhook connector in Microsoft Teams switches the URL to unsupported https://*.webhook.office.com/webhookb2/ format

On the heels of yesterday's #68 report, I tested a new build of atc0005/send2teams using v2.4.1 of this package. Aside from discovering #83, when I went to grab the webhook URLs from an existing connector (which is still working) I noticed that it was flagged as Attention required. Once I clicked Manage and Save, I noticed that the existing URL pattern changed from https://outlook.office.com/webhook/ to https://*.webhook.office.com/webhookb2/ where * is the subdomain for our org.

Without knowing for sure, I'd say that these are going to be the legacy webhook URL patterns:

  • https://outlook.office.com/webhook/
  • https://outlook.office365.com/webhook/

and this the current one:

  • https://*.webhook.office.com/webhookb2/

Creating a brand new Incoming Webhook connector resulted in another URL of the same format.

Update project LICENSE file

I need to update the LICENSE file to add my entry, and update the existing entry to update the existing date for Enrico Hoffmann (he performed multiple updates to the project earlier this year).

AFAIK this is the right process to follow when forking/extending an existing MIT licensed project (just append to the existing file).

Required MessageCard fields use "omitempty" json struct tag

For example:

// Title is the title property of a card. is meant to be rendered in a
// prominent way, at the very top of the card. Use it to introduce the
// content of the card in such a way users will immediately know what to
// expect.
Title string `json:"title,omitempty"`
// Text is required if the card does not contain a summary property,
// otherwise optional. The text property is meant to be displayed in a
// normal font below the card's title. Use it to display content, such as
// the description of the entity being referenced, or an abstract of a
// news article.
Text string `json:"text,omitempty"`

Validation functions are used to prevent the field from actually going out empty, but including omitempty here feels like it is misleading?

Doc comments for API interface are too thin

go-teams-notify/send.go

Lines 87 to 95 in eaab5cd

// API - interface of MS Teams notify
type API interface {
Send(webhookURL string, webhookMessage MessageCard) error
SendWithContext(ctx context.Context, webhookURL string, webhookMessage MessageCard) error
SendWithRetry(ctx context.Context, webhookURL string, webhookMessage MessageCard, retries int, retriesDelay int) error
SkipWebhookURLValidationOnSend(skip bool) API
AddWebhookURLValidationPatterns(patterns ...string) API
ValidateWebhook(webhookURL string) error
}

This is functional and was likely fine when the API surface was smaller, but should be extended to cover existing functionality.

Accept a context to allow cancellation of c.httpClient.Do(req)

The content below was originally from dasrick#19.


There is already a reasonable timeout set:

go-teams-notify/send.go

Lines 29 to 37 in a6412ec

// NewClient - create a brand new client for MS Teams notify
func NewClient() API {
client := teamsClient{
httpClient: &http.Client{
Timeout: 5 * time.Second,
},
}
return &client
}

As part of some local application changes I'm learning/implementing contexts for cancellation. I figured it was worth asking here if it would be useful to modify teamsClient.Send() to accept a context for cancellation:

go-teams-notify/send.go

Lines 39 to 40 in a6412ec

// Send - will post a notification to MS Teams webhook URL
func (c teamsClient) Send(webhookURL string, webhookMessage MessageCard) error {

If backwards compatibility is a concern (as I imagine it would be), perhaps we could essentially extend the existing function, rename it to communicate that it accepts a context and then have teamsClient.Send() be a wrapper around this modified method.

The wrapper could accept the same arguments the teamsClient.Send() function does now, but within create a new context that it passes to the modified method. If client code calls the new function directly, they would have direct control of the context cancellation/timeout. If the client code calls the current name, existing functionality would apply.

In this scenario, would this timeout still be set, or rely entirely on a context?

go-teams-notify/send.go

Lines 32 to 34 in a6412ec

httpClient: &http.Client{
Timeout: 5 * time.Second,
},

This doc (https://golang.org/pkg/net/http/#Client) has this to say:

type Client struct {

    // ...

    // Timeout specifies a time limit for requests made by this
    // Client. The timeout includes connection time, any
    // redirects, and reading the response body. The timer remains
    // running after Get, Head, Post, or Do return and will
    // interrupt reading of the Response.Body.
    //
    // A Timeout of zero means no timeout.
    //
    // The Client cancels requests to the underlying Transport
    // as if the Request's Context ended.
    //
    // For compatibility, the Client will also use the deprecated
    // CancelRequest method on Transport if found. New
    // RoundTripper implementations should use the Request's Context
    // for cancellation instead of implementing CancelRequest.
    Timeout time.Duration // Go 1.3
}

which I take to mean that http.NewRequestWithContext() will do the job without needing to specify a Client.Timeout value.

The end result would be to have this call be controlled via a context:

go-teams-notify/send.go

Lines 54 to 58 in a6412ec

// do the request
res, err := c.httpClient.Do(req)
if err != nil {
return err
}

How to use @mention

Hello,

I'm trying to mention someone in the cards like I do manually with @user .

Is there a way to do that with this lib ?

Review tests, add additional documentation to emphasize intentions

Currently I find the tests to be both to be brittle and not as clear as they could be. This is probably from a lack of an "ah ha!" moment.

I've made attempts to refactor with recent releases, but further work is needed to document exactly what is happening and why.

For example, one thing I spent an embarrassing amount of time on this AM was "remembering" the relationship between resError and error in the table test entries:

var tests = []struct {
reqURL string
reqMsg MessageCard
resStatus int // httpClient response status
resBody string // httpClient response body text
resError error // httpClient error
error error // method error
skipURLVal bool // whether webhook URL validation is applied (e.g., GH-68)
}{

If I recall correctly, you're specifying what client error is expected (e.g., connectivity issue) and what error is expected from invoking library functions/methods using provided table test data.

This table test entry is an example of where there is no client error, but there is an error returned from validating the target endpoint or request URL:

// invalid webhookURL - missing prefix in webhook URL
{
reqURL: "",
reqMsg: simpleMsgCard,
resStatus: 0,
resBody: "invalid",
resError: nil,
error: ErrWebhookURLUnexpectedPrefix,
skipURLVal: false,
},

Add package-level logger that is disabled by default

The content below is duplicated from upstream issue dasrick#10.


Overview

Continuation of the discussion from dasrick#4.

Speaking as someone without a lot of experience writing packages/libraries, it seems like it could free the package to more liberally log useful troubleshooting details, while not emitting it into the usual stdout/stderr streams by default.

I'm testing this functionality from a fork of this project and one of the items I'm emitting is the JSON that is being sent to Teams via the webhook URL. I'm finding that this is useful troubleshooting information as I develop client app changes. I understand that specific JSON logging use-case might not extend to all users of the library, so perhaps wrapping it in some further call might be necessary (were it to be included at all).

Example

// logger is a package logger that can be enabled from client code to allow
// logging output from this package when desired/needed for troubleshooting
var logger *log.Logger

func init() {

	// Disable logging output by default unless client code explicitly
	// requests it
	logger = log.New(os.Stderr, "[goteamsnotify] ", 0)
	logger.SetOutput(ioutil.Discard)

}

// EnableLogging enables logging output from this package. Output is muted by
// default unless explicitly requested (by calling this function).
func EnableLogging() {
	logger.SetFlags(log.Ldate | log.Ltime | log.Lshortfile)
	logger.SetOutput(os.Stderr)
}

Remote API error handling: expose response string

The content below was originally from dasrick#15.


Summary

Extend error handling by retrieving and providing the response string from the remote API as part of the error message returned to the caller if the status code indicates an error condition.

Based on testing, the response string contains useful troubleshooting information which can help identify missing information in the submitted MessageCard payload.

Note

This Pull Request contains example logger object calls to illustrate the proposed changes mentioned in dasrick#10. These logger calls are included in this PR only for discussion purposes.

Before this PR would be merged, those logger calls would be removed, the associated branch rebased, and those changes set aside for potential implementation as part of a separate PR specific to dasrick#10.

refs dasrick#10, dasrick#6 (loosely)

SendWithRetry method does not honor setting to disable webhook URL prefix validation

Work for #68 and related issues was incomplete, but only due to a bug in how SendWithRetry was written. Instead of using the receiver (as it should have), this method instantiates a new client which doesn't retain any potential field change to disable prefix validation. This is likely due to how I brought over the vendored changes from the atc0005/send2teams project last Fall.

Proposal: Add formatting functions useful for text conversion

The content below was originally submitted as dasrick#16.


Summary

  • Convert Windows/Mac/Linux EOL to Markdown break statements

    • used to provide equivalent Teams-compatible formatting
  • Format text as code snippet

    • this inserts leading and trailing ` character to provide Markdown string formatting
  • Format text as code block

    • this inserts three leading and trailing ` characters to provide Markdown code block formatting
  • Try variants of code formatting functions

    • return formatted string if no errors, otherwise return the original string

Concerns

FormatAsCode variants

I've implemented most of these functions primarily for use with several projects that submit code-heavy content to Microsoft Teams. These functions might be too project-specific for inclusion here, but I thought it would be best to get a clear yes/no verdict instead of not offering them for inclusion. Worst case they're rejected, but I figured it might be possible to rework (if necessary) so that they're available for everyone to use when needed.

ConvertEOLToBreak

The ConvertEOLToBreak() function was written specifically for taking in text input from a variety of sources and converting to Markdown break statements in order to have equivalent formatting when displayed in Microsoft Teams.

For my use case, I used the ConvertEOLToBreak() function to take text output from Nagios plugins and convert the newlines inserted by those plugins. This allowed the converted text to display with the intended line formatting instead of having the output jumbled together as one big paragraph. This optional conversion could be called by other client code as-needed for similar use cases.

refs dasrick#6 (loosely)

Follow-up: Have the older webhook URL prefixes been deprecated?

This text:

Important: Your connector is running on old configuration. Navigate to connector configuration window to update to new configuration.

has begun to appear at the bottom of messages sent via webhooks using the form https://outlook.office.com/webhook/. Generating a replacement webhook URL results in the new URL having a prefix of https://example.webhook.office.com/webhookb2/ (where example is whatever the O365 Org "slug" happens to be).

I spot checked https://docs.microsoft.com/en-us/outlook/actionable-messages/send-via-connectors, but that example is still using the https://outlook.office365.com/webhook/ prefix.

How much longer will the older prefixes remain viable?

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    ๐Ÿ–– Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. ๐Ÿ“Š๐Ÿ“ˆ๐ŸŽ‰

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google โค๏ธ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.