* feat: add configurable SMTP HELO hostname Allow the SMTP HELO/EHLO hostname to be configured separately from the SMTP server hostname. This is useful when the SMTP server requires clients to identify themselves with a fully qualified hostname different from the server address. * chore: remove vendored dependency changes * Bump go-pkgz/notify to v1.4.0 and document SMTP_HELO_HOST The HELOHost field lands in go-pkgz/notify v1.4.0, so the branch needs the bump to compile; v1.3.0 in master has no such field. The example module is tidied alongside, as any change to backend/go.mod requires. Documents the parameter in the parameters table and, separately, in the email setup page: what it does, that leaving it unset keeps the previous `localhost` greeting, and the case it exists for, a relay refusing the greeting under Postfix `reject_non_fqdn_helo_hostname`. Also records the current limit: verification emails for email authentication go through go-pkgz/auth's own sender, which has no equivalent setting, so the greeting there is unchanged. * Bump go-pkgz/auth to v2.2.0 and apply SMTP_HELO_HOST to verification email The verification email sender had no way to set the greeting, so a relay that refuses the HELO would accept notifications and still reject sign-in emails. EmailParams gains HELOHost in go-pkgz/auth v2.2.0, so the same SMTP_HELO_HOST now drives both paths. The example module is tidied alongside, as any change to backend/go.mod requires. --------- Co-authored-by: oli <someone@somewhere.tld> Co-authored-by: Dmitry Verkhoturov <paskal.07@gmail.com>
Notify
This library provides ability to send notifications using multiple services:
- Telegram
- Slack
- Webhook
Install
go get -u github.com/go-pkgz/notify
Usage
All supported notification methods could adhere to the following interface. Example on how to use it:
package main
import (
"context"
"fmt"
"github.com/go-pkgz/notify"
)
func main() {
// create notifiers
notifiers := []notify.Notifier{
notify.NewWebhook(notify.WebhookParams{}),
notify.NewEmail(notify.SMTPParams{}),
notify.NewSlack("token"),
}
tg, err := notify.NewTelegram(notify.TelegramParams{Token: "token"})
if err == nil {
notifiers = append(notifiers, tg)
}
err = notify.Send(context.Background(), notifiers, "https://example.com/webhook", "Hello, world!")
if err != nil {
fmt.Printf("Sent message error: %s", err)
}
}
A runnable version of the same flow, sending to a local test server instead of a real webhook, is in example_test.go.
mailto: scheme is supported. Only subject and from query params are used.
Note: Query parameter values must be URL-encoded. In particular, email addresses containing + (e.g. noreply+tag@example.com) must use %2B, otherwise + is interpreted as a space. Use url.QueryEscape for all parameter values.
Examples:
mailto:"John Wayne"<john@example.org>?subject=test-subj&from="Notifier"<notify@example.org>mailto:addr1@example.org,addr2@example.org?&subject=test-subj&from=notify@example.org
package main
import (
"context"
"log"
"time"
"github.com/go-pkgz/notify"
)
func main() {
wh := notify.NewEmail(notify.SMTPParams{
Host: "localhost", // the only required field, others are optional
Port: 25,
TLS: false, // TLS, but not STARTTLS
HELOHost: "mail.example.org", // hostname sent in the SMTP greeting, "localhost" by default
ContentType: "text/html",
Charset: "UTF-8",
Username: "username",
Password: "password",
TimeOut: time.Second * 10, // default is 30 seconds
})
err := wh.Send(
context.Background(),
`mailto:"John Wayne"<john@example.org>?subject=test-subj&from="Notifier"<notify@example.org>`,
"Hello, World!",
)
if err != nil {
log.Fatalf("problem sending message using email, %v", err)
}
}
Telegram
telegram: scheme akin to mailto: is supported. Query params parseMode (doc, legacy Markdown by default, preferable use MarkdownV2 or HTML instead). Examples:
telegram:channeltelegram:channelID// channel ID is a number, like-1001480738202: use that instruction to obtain ittelegram:userID
Here is an instruction on obtaining token for your notification bot.
package main
import (
"context"
"log"
"time"
"github.com/go-pkgz/notify"
)
func main() {
tg, err := notify.NewTelegram(notify.TelegramParams{
Token: "token", // required
Timeout: time.Second * 10, // default is 5 seconds
SuccessMsg: "Success", // optional, for auth, set by default
ErrorMsg: "Error", // optional, for auth, unset by default
})
if err != nil {
log.Fatalf("problem creating telegram notifier, %v", err)
}
err = tg.Send(context.Background(), "telegram:-1001480738202", "Hello, World!")
if err != nil {
log.Fatalf("problem sending message using telegram, %v", err)
}
}
HTML Formatting
parseMode HTML supports limited set of tags, so Telegram provides TelegramSupportedHTML method which strips all unsupported tags and replaces h1-h3 with <b> and h4-h6 with <i><b> to preserve formatting.
If you want to post text into HTML tag like text, you can use EscapeTelegramText method to escape it (by replacing symbols &, <, > with &, <, >).
Authorisation
You can use Telegram notifications as described above, just to send messages. But also, you can use Telegram to authorise users as a login method or to sign them up for notifications. Functions used for processing updates from users are GetBotUsername, AddToken, CheckToken, Request, and Run or ProcessUpdate (only one of two can be used at a time).
Normal flow is following:
- you run the
Rungoroutine - call
AddTokenand provide user with that token - user clicks on the link
https://t.me/<BOT_USERNAME>/?start=<TOKEN> - you call
CheckTokento verify that the user clicked the link, and if so you will receive user's UserID
Alternative flow is the same, but instead of running the Run goroutine, you set up process update flow separately (to use with auth as well, for example) and run ProcessUpdate when update is received. Example of such a setup can be seen in Remark42.
Slack
slack: scheme akin to mailto: is supported. title, titleLink, attachmentText and query params are used: if they are defined, message would be sent with a text attachment. Examples:
slack:channelslack:channelIDslack:userIDslack:channel?title=title&attachmentText=test%20text&titleLink=https://example.org
package main
import (
"context"
"log"
"github.com/go-pkgz/notify"
"github.com/slack-go/slack"
)
func main() {
wh := notify.NewSlack(
"token",
slack.OptionDebug(true), // optional, you can pass any slack.Options
)
err := wh.Send(context.Background(), "slack:general", "Hello, World!")
if err != nil {
log.Fatalf("problem sending message using slack, %v", err)
}
}
Webhook
http:// and https:// schemas are supported.
package main
import (
"context"
"log"
"time"
"github.com/go-pkgz/notify"
)
func main() {
wh := notify.NewWebhook(notify.WebhookParams{
Timeout: time.Second, // optional, default is 5 seconds
Headers: []string{"Content-Type:application/json,text/plain"}, // optional
})
err := wh.Send(context.Background(), "https://example.org/webhook", "Hello, World!")
if err != nil {
log.Fatalf("problem sending message using webhook, %v", err)
}
}
Status
The library extracted from remark42 project. The original code in production use on multiple sites and seems to work fine.
go-pkgz/notify library still in development and until version 1 released some breaking changes possible.