What's Changed
Shoutrrr v0.23.0 adds improved service URL validation and service standardization. TLS, timeout, and logging behavior should be more consistent. Leveled logging is now supported through log/slog. skiptlsverify is also supported for more services that can be self-hosted.
URL Validation
Service URLs that break these rules are now rejected when they are read.
- Discord webhook and thread IDs must be numeric.
- A Twilio account SID must be
ACfollowed by 32 hexadecimal characters. - A Google Chat URL must include its space path.
- A Zulip URL must include an API key.
- A Lark token must be a single path segment.
- MQTT topics can't contain
+,#, or a null character. - MQTT and SMTP ports must be between 1 and 65535.
- Rocket.Chat and Zulip reject unknown query keys.
- A query can't contain a malformed escape or a literal semicolon, except in ntfy.
- A setting can't be given under two spellings, such as
titleandTitle. - A URL can't end in a bare
#.
Send Checks
- Each send checks its config the same way reading its URL does, before any request or connection. A config built in code or changed by send params now fails the send when its URL would be rejected.
- Unknown send params fail the send in Google Chat, Join, Notifiarr, Rocket.Chat, and Zulip, and in Discord sends of raw JSON. The
title,message, andlevelparams are still accepted everywhere. - A Matrix send without configured rooms fails when the account has joined none.
- An IFTTT send fails when its
eventsparam empties the list. - A Discord message that is only whitespace fails.
TLS
- Gotify's
disabletlsno longer skips certificate verification. Addskiptlsverify=yesto keep skipping it. GetURLwrites theskiptlsverifykey for Gotify, ntfy, and MQTT. Releases before v0.23.0 reject that key.
Timeouts
- A send without a deadline is bounded by its service's own time budget.
- A router timeout longer than 10 seconds is now honored.
- The default HTTP clients no longer set a request timeout of their own.
Logging
- Plain loggers receive lines in the form
LEVEL message key=value, so warnings start withWARNinstead ofWarning:. - Success and progress messages log at Debug.
- Errors that a send returns are no longer logged as well.
Deprecations
The following items are deprecated in this release. See the Deprecations documentation page for more information.
URL Settings
| Service | Deprecated | Replacement |
|---|---|---|
| Bark | scheme
| disabletls
|
| Gotify | insecureskipverify
| skiptlsverify
|
| MQTT | disabletlsverification
| skiptlsverify
|
| ntfy | disabletlsverification
| skiptlsverify
|
| ntfy | scheme
| disabletls
|
Go API
| Package | Deprecated | Replacement |
|---|---|---|
| bark | Config.Scheme
| Config.DisableTLS
|
| bark | HTTPClient
| types.HTTPClient
|
| bark | DefaultHTTPClient
| Service.SetHTTPClient
|
| bark | NewDefaultHTTPClient
| Service.SetHTTPClient
|
| bark | Service.HTTPClient
| Service.SetHTTPClient
|
| discord | HTTPClient
| types.HTTPClient
|
| discord | DefaultHTTPClient
| Service.SetHTTPClient
|
| discord | NewDefaultHTTPClient
| Service.SetHTTPClient
|
| discord | Service.HTTPClient
| Service.SetHTTPClient
|
| gotify | Config.InsecureSkipVerify
| Config.SkipTLSVerify
|
| gotify | HTTPClientManager
| Service.SetHTTPClient
|
| gotify | DefaultHTTPClientManager
| Service.SetHTTPClient
|
| gotify | HTTPTimeout
| None. Sends use the Service.ServiceTimeout budget.
|
| lark | ErrMissingHost
| None. No function returns it. |
| matrix | HTTPClient
| types.HTTPClient
|
| matrix | DefaultHTTPClient
| Service.SetHTTPClient
|
| mqtt | Config.DisableTLSVerification
| Config.SkipTLSVerify
|
| ntfy | Config.DisableTLSVerification
| Config.SkipTLSVerify
|
| ntfy | Config.Scheme
| Config.DisableTLS
|
| ntfy | HTTPTimeout
| None. Sends use the Service.ServiceTimeout budget.
|
| pushover | Service.Client
| Service.SetHTTPClient
|
| rocketchat | Service.Client
| Service.SetHTTPClient
|
| rocketchat | ErrInvalidURLScheme
| None. No function returns it. |
| standard | Logger.Log
| Logger.Debug, Logger.Info, or Logger.Warn
|
| standard | Logger.Logf
| Logger.Debug, Logger.Info, or Logger.Warn
|
| teams | HTTPClient
| types.HTTPClient
|
| twilio | HTTPClient
| types.HTTPClient
|
| twilio | DefaultHTTPClient
| Service.SetHTTPClient
|
| twilio | Service.HTTPClient
| Service.SetHTTPClient
|
| zulip | HTTPClient
| types.HTTPClient
|
| zulip | DefaultHTTPClient
| Service.SetHTTPClient
|
| zulip | NewDefaultHTTPClient
| Service.SetHTTPClient
|
| zulip | Service.HTTPClient
| Service.SetHTTPClient
|
Commits
Features
- feat: mask sensitive values in verify output by @nicholas-fedor in #1783
- feat: mask secrets in the URLs that send and generate print by @nicholas-fedor in #1787
- feat: map the message level to ntfy, Pushover, and Discord severity by @nicholas-fedor in #1795
- feat: map the message level to Gotify, Signalgrid, Opsgenie, and PagerDuty severity by @nicholas-fedor in #1799
- feat(telegram): send through a configurable Bot API server by @nicholas-fedor in #1801
- feat(pushover): send a message timestamp by @nicholas-fedor in #1803
- feat(smtp): refresh OAuth2 access tokens from a refresh token by @nicholas-fedor in #1809
- feat(format): support deprecated config keys and fields by @nicholas-fedor in #1827
- feat(gotify): add the skiptlsverify key and follow the service rules by @nicholas-fedor in #1833
- feat(ntfy): add the skiptlsverify key and follow the service rules by @nicholas-fedor in #1835
- feat(mqtt): add SendContext and follow the service rules by @nicholas-fedor in #1837
- feat(services): bring Signal and Home Assistant under the service rules by @nicholas-fedor in #1841
- feat(services): bring SMTP and XMPP under the service rules by @nicholas-fedor in #1843
- feat(services): bring Discord and Zulip under the service rules by @nicholas-fedor in #1851
- feat(bark): bring Bark under the service rules by @nicholas-fedor in #1853
- feat(services): bring Rocket.Chat and Pushover under the service rules by @nicholas-fedor in #1857
- feat(services): bring Twilio and Telegram under the service rules by @nicholas-fedor in #1859
- feat(services): bring the chat services under the service rules by @nicholas-fedor in #1861
- feat(services): bring the remaining services under the service rules by @nicholas-fedor in #1863
- feat(logging): log leveled records through log/slog by @nicholas-fedor in #1921
- feat(logging): log every service message at a level by @nicholas-fedor in #1923
- feat(bark): add skiptlsverify for servers with unverifiable certificates by @nicholas-fedor in #1937
- feat(rocketchat): add disabletls and skiptlsverify for self-hosted servers by @nicholas-fedor in #1941
- feat: add skiptlsverify to Mattermost and Generic by @nicholas-fedor in #1961
- feat(matrix): add skiptlsverify for homeservers with unverifiable certificates by @nicholas-fedor in #1962
- feat(zulip): add skiptlsverify for servers with unverifiable certificates by @nicholas-fedor in #1966
- feat(telegram): add skiptlsverify and warn about http Bot API URLs by @nicholas-fedor in #1968
- feat(matrix): retry rate-limited requests after the homeserver's wait by @nicholas-fedor in #1974
Fixes
- fix(services): keep host credentials exact in ifttt, signalgrid, and pushbullet by @nicholas-fedor in #1733
- fix(format): clear slice and map keys set from an empty value by @nicholas-fedor in #1735
- fix(services): reject service urls with a malformed query by @nicholas-fedor in #1741
- fix(mqtt): reject topics with wildcards or a null character by @nicholas-fedor in #1755
- fix: cap response body reads at 1 MiB by @nicholas-fedor in #1781
- fix: harden scheme lookup, channel ID parsing, and message partitioning by @nicholas-fedor in #1791
- fix(ntfy): let a scheme param override the stored scheme by @nicholas-fedor in #1855
- fix(services): return an error instead of panicking before Initialize by @nicholas-fedor in #1865
- fix(generic): apply only config keys from send params by @nicholas-fedor in #1871
- fix(matrix): apply the disabletls send param to each send by @nicholas-fedor in #1873
- fix(services): check Lark and WeCom messages against the documented size limits by @nicholas-fedor in #1875
- fix(format): stop logging unknown URL parts to the global logger by @nicholas-fedor in #1877
- fix(xmpp): join and leave rooms without mellium's muc client by @nicholas-fedor in #1883
- fix(color): write to standard output when the config or its writer is nil by @nicholas-fedor in #1889
- fix(color): let EnableColor and DisableColor decide every method's output by @nicholas-fedor in #1891
- fix(format): treat fields without a default as defaulting to their zero value by @nicholas-fedor in #1893
- fix(httpclient): fail requests through a nil injected client instead of panicking by @nicholas-fedor in #1895
- fix(router): reject service URLs that end in an empty fragment by @nicholas-fedor in #1899
- fix(xoauth2): authorize through a loopback redirect with PKCE by @nicholas-fedor in #1905
- fix(smtp): stop a send when its context is canceled by @nicholas-fedor in #1927
- fix(services): give each target of a send its share of the time by @nicholas-fedor in #1929
- fix(router): report a service timeout only when its budget runs out by @nicholas-fedor in #1931
- fix(format): reject a config key given in two spellings by @nicholas-fedor in #1943
- fix(services): build Lark, IFTTT, and Join payloads from the send's config by @nicholas-fedor in #1949
- fix(notifiarr): reject send params that are neither config keys nor payload params by @nicholas-fedor in #1955
- fix: read Retry-After the same way in Discord and Matrix by @nicholas-fedor in #1976
- fix(discord): send webhooks to Discord API v10 by @nicholas-fedor in #1982
- fix(discord): fall back to the 429 body's retry_after by @nicholas-fedor in #1984
- fix(discord): check the webhook ID and token when the URL is read by @nicholas-fedor in #1988
- fix: validate the docs placeholder URL like any other service URL by @nicholas-fedor in #1992
- fix(discord): resolve and check each send's config once by @nicholas-fedor in #1994
- fix: reject unknown send params in Google Chat and check every service by @nicholas-fedor in #2011
- fix: check each send's config before any request by @nicholas-fedor in #2013
- fix: check chat service configs before any request by @nicholas-fedor in #2017
- fix: check HTTP service configs before any request by @nicholas-fedor in #2019
- fix: check MQTT and SMTP configs before dialing by @nicholas-fedor in #2021
- fix(matrix): send an access token only to the account that owns it by @nicholas-fedor in #2023
- fix(matrix): reject a login reply without an access token by @nicholas-fedor in #2027
- fix(matrix): fail a send that reaches no joined room by @nicholas-fedor in #2029
- fix: fail IFTTT and Discord sends that deliver nothing by @nicholas-fedor in #2031
- fix: check every config field before a send by @nicholas-fedor in #2035
- fix: keep Twilio and Lark requests on their webhook path by @nicholas-fedor in #2041
Dependency Updates
- chore(deps): update module golang.org/x/net to v0.62.0 by @renovate[bot] in #1902
- chore(deps): update module go.yaml.in/yaml/v3 to v3.0.6 by @renovate[bot] in #2006
Full Changelog: v0.22.1...v0.23.0