Files
remark42/backend/vendor/github.com/go-pkgz/notify
3f5b3cdd98 feat: add configurable SMTP HELO hostname (#2146)
* 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>
2026-08-19 02:52:39 -05:00
..
2025-12-03 19:47:01 -06:00

Notify

Build Status Coverage Status Go Reference

This library provides ability to send notifications using multiple services:

  • Email
  • 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.

Email

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:channel
  • telegram:channelID // channel ID is a number, like -1001480738202: use that instruction to obtain it
  • telegram: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 &amp;, &lt;, &gt;).

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:

  1. you run the Run goroutine
  2. call AddToken and provide user with that token
  3. user clicks on the link https://t.me/<BOT_USERNAME>/?start=<TOKEN>
  4. you call CheckToken to 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:channel
  • slack:channelID
  • slack:userID
  • slack: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.